Add symbols support, string support, more performance optimization. Better syntax highlighting and more
^^ do these please

Fix fn display_disassembly
As SectionFlags::EXECUTE does not exist
SectionKind::Text has executable code support but it is not in the `section struct`

Keep everything in a main.rs file for now


use eframe::{
    egui::{
        self, menu, CentralPanel, Color32, Context, FontId, Layout, RichText, ScrollArea, SidePanel,
        TextEdit, TextStyle, TopBottomPanel,
    },
    emath::Align,
    epaint::Vec2,
    App, CreationContext, Frame, NativeOptions,
};
use object::{Object, ObjectSection, ObjectSymbol, SectionFlags, SectionKind, SymbolKind};
use rfd::FileDialog;
use std::{borrow::Cow, fs::File, io::Read, path::PathBuf};

fn main() {
    let app = BinaryAnalyzerApp::default();
    let native_options = NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([1024.0, 768.0]),
        ..Default::default()
    };
    eframe::run_native(
        "Rust Binary Analyzer",
        native_options,
        Box::new(|cc| Ok(Box::new(app.setup(cc)))),
    )
    .expect("Failed to start eframe");
}

struct BinaryAnalyzerApp {
    binary_path: String,
    analysis_result: AnalysisResult,
    error_message: Option<String>,
    selected_section: Option<SectionInfo>,
    selected_symbol: Option<SymbolInfo>,
    dark_mode: bool,
    recent_files: Vec<String>,
    disassembly_cache: std::collections::HashMap<u64, String>,
    search_query: String,
    tab_index: usize,
}

impl Default for BinaryAnalyzerApp {
    fn default() -> Self {
        Self {
            binary_path: String::new(),
            analysis_result: AnalysisResult::default(),
            error_message: None,
            selected_section: None,
            selected_symbol: None,
            dark_mode: true,
            recent_files: Vec::new(),
            disassembly_cache: std::collections::HashMap::new(),
            search_query: String::new(),
            tab_index: 0,
        }
    }
}

impl BinaryAnalyzerApp {
    fn setup(self, cc: &CreationContext<'_>) -> Self {
        // Set initial dark mode
        if self.dark_mode {
            cc.egui_ctx.set_visuals(egui::Visuals::dark());
        } else {
            cc.egui_ctx.set_visuals(egui::Visuals::light());
        }
        self
    }
}

impl App for BinaryAnalyzerApp {
    fn update(&mut self, ctx: &Context, _: &mut Frame) {
        self.top_panel(ctx);
        self.side_panel(ctx);
        self.central_panel(ctx);
        self.status_bar(ctx);
        self.handle_file_drop(ctx);
    }
}

impl BinaryAnalyzerApp {
    /// Draws the top menu bar
    fn top_panel(&mut self, ctx: &Context) {
        TopBottomPanel::top("menu_bar").show(ctx, |ui| {
            menu::bar(ui, |ui| {
                // File Menu
                ui.menu_button("File", |ui| {
                    if ui.button("Open...").clicked() {
                        self.open_file_dialog();
                        ui.close_menu();
                    }
                    if ui.button("Exit").clicked() {
                        std::process::exit(0);
                    }
                });

                // View Menu
                ui.menu_button("View", |ui| {
                    if ui
                        .checkbox(&mut self.dark_mode, "Dark Mode")
                        .clicked()
                    {
                        if self.dark_mode {
                            ctx.set_visuals(egui::Visuals::dark());
                        } else {
                            ctx.set_visuals(egui::Visuals::light());
                        }
                    }
                    ui.separator();
                    if ui.button("Refresh").clicked() {
                        self.perform_analysis();
                        ui.close_menu();
                    }
                });

                // Help Menu
                ui.menu_button("Help", |ui| {
                    if ui.button("About").clicked() {
                        ui.close_menu();
                        self.show_about(ctx);
                    }
                });

                ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
                    ui.label(RichText::new("🔍 Rust Binary Analyzer").font(FontId::proportional(24.0)));
                });
            });
        });
    }

    /// Draws the side panel for navigation
    fn side_panel(&mut self, ctx: &Context) {
        SidePanel::left("side_panel")
            .min_width(250.0)
            .resizable(true)
            .show(ctx, |ui| {
                ui.heading("Explorer");
                ui.separator();

                if !self.analysis_result.is_empty() {
                    ui.vertical(|ui| {
                        ui.spacing_mut().item_spacing.y = 10.0;
                        ui.collapsing("📁 Sections", |ui| {
                            ScrollArea::vertical().show(ui, |ui| {
                                for section in &self.analysis_result.sections {
                                    if ui
                                        .selectable_label(
                                            self.selected_section
                                                .as_ref()
                                                .map_or(false, |s| s.name == section.name),
                                            &section.name,
                                        )
                                        .clicked()
                                    {
                                        self.selected_section = Some(section.clone());
                                        self.tab_index = 0;
                                    }
                                }
                            });
                        });

                        ui.collapsing("🔖 Symbols", |ui| {
                            ScrollArea::vertical().show(ui, |ui| {
                                for symbol in &self.analysis_result.symbols {
                                    if ui
                                        .selectable_label(
                                            self.selected_symbol
                                                .as_ref()
                                                .map_or(false, |s| s.name == symbol.name),
                                            &symbol.name,
                                        )
                                        .clicked()
                                    {
                                        self.selected_symbol = Some(symbol.clone());
                                        self.tab_index = 1;
                                    }
                                }
                            });
                        });
                    });
                } else {
                    ui.label("No file loaded.");
                }
            });
    }

    /// Draws the central panel displaying analysis results
    fn central_panel(&mut self, ctx: &Context) {
        CentralPanel::default().show(ctx, |ui| {
            if self.analysis_result.is_empty() {
                ui.centered_and_justified(|ui| {
                    ui.label(RichText::new("Drag and drop a binary file here or use File > Open to start.").italics());
                });
            } else {
                egui::TopBottomPanel::top("info_panel").show_inside(ui, |ui| {
                    ui.horizontal_wrapped(|ui| {
                        ui.label("Format:");
                        ui.monospace(format!("{:?}", self.analysis_result.format));
                        ui.separator();
                        ui.label("Arch:");
                        ui.monospace(format!("{:?}", self.analysis_result.architecture));
                        ui.separator();
                        ui.label("Endianness:");
                        ui.monospace(format!("{:?}", self.analysis_result.endianness));
                        ui.separator();
                        ui.label("File Size:");
                        ui.monospace(format!("{:.2} KB", self.analysis_result.file_size as f64 / 1024.0));
                    });
                });

                ui.add_space(5.0);

                let tabs = ["Section Details", "Symbol Details", "Disassembly"];
                ui.horizontal(|ui| {
                    for (i, tab) in tabs.iter().enumerate() {
                        let selected = self.tab_index == i;
                        if ui
                            .selectable_label(selected, *tab)
                            .clicked()
                        {
                            self.tab_index = i;
                        }
                    }
                });
                ui.separator();
                ui.add_space(5.0);

                match self.tab_index {
                    0 => self.display_section_details(ui),
                    1 => self.display_symbol_details(ui),
                    2 => self.display_disassembly(ui),
                    _ => {}
                }
            }
        });
    }

    /// Displays the status bar at the bottom
    fn status_bar(&self, ctx: &Context) {
        TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
            ui.horizontal(|ui| {
                if let Some(path) = &Some(self.binary_path.clone()) {
                    ui.label(format!("📄 File: {}", path));
                }
                ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
                    ui.label("Ready");
                });
            });
        });
    }

    /// Displays section details in the central panel
    fn display_section_details(&mut self, ui: &mut egui::Ui) {
        if let Some(section) = &self.selected_section {
            ui.heading(format!("📄 Section: {}", section.name));
            ui.separator();
            ui.monospace(format!("Address: 0x{:X}", section.address));
            ui.monospace(format!("Size: {}", section.size));
            ui.monospace(format!("Flags: {:?}", section.flags));
            ui.add_space(10.0);

            if !section.data.is_empty() {
                ui.collapsing("🔎 Hex View", |ui| {
                    self.display_hex_view(ui, &section.data);
                });
            }
        } else {
            ui.label("Select a section from the left panel to view details.");
        }
    }

    /// Displays symbol details in the central panel
    fn display_symbol_details(&mut self, ui: &mut egui::Ui) {
        if let Some(symbol) = &self.selected_symbol {
            ui.heading(format!("🔖 Symbol: {}", symbol.name));
            ui.separator();
            ui.monospace(format!("Address: 0x{:X}", symbol.address));
            ui.monospace(format!("Size: {}", symbol.size));
            ui.monospace(format!("Kind: {:?}", symbol.kind));
            ui.monospace(format!("Scope: {:?}", symbol.scope));
            ui.add_space(10.0);
        } else {
            ui.label("Select a symbol from the left panel to view details.");
        }
    }

    /// Displays disassembly of code sections
    fn display_disassembly(&mut self, ui: &mut egui::Ui) {
        if let Some(section) = &self.selected_section {
            if 1 == 1{
                ui.heading(format!("🧩 Disassembly of {}", section.name));
                ui.separator();
                if let Some(disassembly) = self.disassembly_cache.get(&section.address) {
                    ScrollArea::vertical().show(ui, |ui| {
                        ui.monospace(disassembly);
                    });
                } else {
                    ui.label("Disassembling...");
                    if let Ok(disassembly) = self.perform_disassembly(section) {
                        self.disassembly_cache.insert(section.address, disassembly);
                    } else {
                        ui.label("Failed to disassemble section.");
                    }
                }
            } else {
                ui.label("Selected section is not executable.");
            }
        } else {
            ui.label("Select an executable section to disassemble.");
        }
    }

    /// Performs the binary analysis
    fn perform_analysis(&mut self) {
        match analyze_binary(&self.binary_path) {
            Ok(result) => {
                self.analysis_result = result;
                self.error_message = None;
                self.selected_section = None;
                self.selected_symbol = None;
                self.disassembly_cache.clear();
            }
            Err(e) => {
                self.analysis_result = AnalysisResult::default();
                self.error_message = Some(e);
                self.selected_section = None;
                self.selected_symbol = None;
                self.disassembly_cache.clear();
            }
        }
    }

    /// Opens the file dialog to select a binary file
    fn open_file_dialog(&mut self) {
        if let Some(path) = FileDialog::new().add_filter("Binary files", &[""]).pick_file() {
            self.binary_path = path.display().to_string();
            self.perform_analysis();
            self.recent_files.push(self.binary_path.clone());
        }
    }

    /// Displays the hex view of the data
    fn display_hex_view(&self, ui: &mut egui::Ui, data: &[u8]) {
        let bytes_per_row = 16;
        let mut offset = 0;
        while offset < data.len() {
            let end = usize::min(offset + bytes_per_row, data.len());
            let row = &data[offset..end];

            let hex_row: String = row.iter().map(|b| format!("{:02X} ", b)).collect();
            let ascii_row: String = row
                .iter()
                .map(|b| {
                    if b.is_ascii_graphic() {
                        *b as char
                    } else {
                        '.'
                    }
                })
                .collect();

            ui.horizontal_wrapped(|ui| {
                ui.label(format!("{:08X}: ", offset));
                ui.monospace(&hex_row);
                ui.add_space(10.0);
                ui.monospace(&ascii_row);
            });

            offset += bytes_per_row;
        }
    }

    /// Performs disassembly on the given section
    fn perform_disassembly(&self, section: &SectionInfo) -> Result<String, String> {
        // Placeholder for disassembly logic.
        // In real implementation, use a crate like 'capstone' for disassembly.
        Ok(format!(
            "Disassembly of section '{}' at address 0x{:X} is not yet implemented.",
            section.name, section.address
        ))
    }

    /// Shows the About dialog
    fn show_about(&self, ctx: &Context) {
        egui::Window::new("About Rust Binary Analyzer")
            .resizable(false)
            .show(ctx, |ui| {
                ui.label("Rust Binary Analyzer");
                ui.label("Version 1.0.0");
                ui.label("Developed with 💖 in Rust and egui");
            });
    }

    /// Handles file drop events
    fn handle_file_drop(&mut self, ctx: &egui::Context) {
        let dropped_file = ctx.input(|i| i.raw.dropped_files.first().cloned());
        if let Some(file) = dropped_file {
            if let Some(path) = file.path {
                self.binary_path = path.display().to_string();
                self.perform_analysis();
            }
        }
    }
}

struct AnalysisResult {
    format: object::BinaryFormat,
    architecture: object::Architecture,
    endianness: object::Endianness,
    file_size: u64,
    sections: Vec<SectionInfo>,
    symbols: Vec<SymbolInfo>,
}

impl Default for AnalysisResult {
    fn default() -> Self {
        AnalysisResult {
            format: object::BinaryFormat::Pe, // Change default to Unknown
            architecture: object::Architecture::Unknown,
            endianness: object::Endianness::Little,
            file_size: 0,
            sections: Vec::new(),
            symbols: Vec::new(),
        }
    }
}

impl AnalysisResult {
    fn is_empty(&self) -> bool {
        self.sections.is_empty() && self.symbols.is_empty()
    }
}

#[derive(Clone)]
struct SectionInfo {
    name: String,
    address: u64,
    size: u64,
    data: Vec<u8>,
    flags: object::SectionFlags,
}

#[derive(Clone)]
struct SymbolInfo {
    name: String,
    address: u64,
    size: u64,
    kind: SymbolKind,
    scope: object::SymbolScope,
}

fn analyze_binary(path: &str) -> Result<AnalysisResult, String> {
    let mut file = File::open(path).map_err(|e| format!("Failed to open file: {}", e))?;
    let metadata = file.metadata().map_err(|e| format!("Failed to get file metadata: {}", e))?;
    let file_size = metadata.len();

    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)
        .map_err(|e| format!("Failed to read file: {}", e))?;

    let obj_file = object::File::parse(&*buffer).map_err(|e| format!("Failed to parse binary: {}", e))?;

    let mut sections = Vec::new();
    for section in obj_file.sections() {
        let data = section.uncompressed_data().unwrap_or(Cow::Borrowed(&[])).to_vec();
        let section_info = SectionInfo {
            name: section.name().unwrap_or("Unknown").to_string(),
            address: section.address(),
            size: section.size(),
            data,
            flags: section.flags(),
        };
        sections.push(section_info);
    }

    let mut symbols = Vec::new();
    for symbol in obj_file.symbols() {
        let symbol_info = SymbolInfo {
            name: symbol.name().unwrap_or("Unknown").to_string(),
            address: symbol.address(),
            size: symbol.size(),
            kind: symbol.kind(),
            scope: symbol.scope(),
        };
        symbols.push(symbol_info);
    }

    Ok(AnalysisResult {
        format: obj_file.format(),
        architecture: obj_file.architecture(),
        endianness: obj_file.endianness(),
        file_size,
        sections,
        symbols,
    })
}