#![cfg(feature = "detection")]
mod cert;
mod mp4;
mod png;
mod xml;
use bladvak::eframe::egui::{self};
use bladvak::errors::ErrorManager;
use std::ops::RangeInclusive;
use crate::panels::FileInfoData;
use crate::windows::detection::cert::{CertData, show_certs};
use crate::windows::detection::mp4::{Mp4Data, ui::show_mp4_ui};
use crate::windows::detection::png::{PngData, show_png_chunks};
use crate::windows::detection::xml::{XmlData, xml_tree_ui};
#[derive(Default, Debug)]
enum DetectionCache {
Png(Option<PngData>),
Xml(Option<XmlData>),
Cert(Option<CertData>),
Mp4(Option<Mp4Data>),
String(String),
#[default]
Empty,
}
impl DetectionCache {
fn show(
&self,
ui: &mut egui::Ui,
_binary_data: &[u8],
file_info: &FileInfoData,
) -> Option<RangeInclusive<usize>> {
match self {
DetectionCache::Png(data) => show_png_chunks(ui, data.as_ref()),
DetectionCache::Xml(xml_str) => xml_tree_ui(ui, xml_str.as_ref()),
DetectionCache::Cert(xml_str) => show_certs(ui, xml_str.as_ref()),
DetectionCache::String(str) => {
ui.label(str);
None
}
DetectionCache::Mp4(mp4_data) => show_mp4_ui(ui, mp4_data.as_ref()),
DetectionCache::Empty => {
ui.label(format!("Kind: {:?}", file_info.kind));
ui.label("No data");
None
}
}
}
fn parse(binary_data: &[u8], file_info: &FileInfoData) -> DetectionCache {
match file_info.extension.as_str() {
"png" => {
let parsed = PngData::parse(binary_data);
DetectionCache::Png(parsed)
}
"xml" | "svg" | "html" => {
let parsed = XmlData::parse(binary_data);
DetectionCache::Xml(Some(parsed))
}
"crt" => {
let parsed = CertData::parse(binary_data, false);
DetectionCache::Cert(parsed)
}
"der" => {
let parsed = CertData::parse(binary_data, true);
DetectionCache::Cert(parsed)
}
"mp4" => {
let parsed = Mp4Data::parse(binary_data);
DetectionCache::Mp4(parsed)
}
"qoi" => DetectionCache::String("A QOI (Quite OK Image) image".to_string()),
_ => {
if binary_data.starts_with("0 HEAD\r\n1 SOUR".as_bytes()) {
DetectionCache::String("Maybe a GED file".to_string())
} else {
DetectionCache::Empty
}
}
}
}
}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub(crate) struct Detection {
pub(crate) is_open: bool,
#[serde(skip)]
cache: DetectionCache,
}
impl Detection {
pub(crate) fn new() -> Self {
Self {
is_open: false,
cache: DetectionCache::Empty,
}
}
pub(crate) fn reset(&mut self) {
self.cache = DetectionCache::Empty;
}
pub(crate) fn ui(
&mut self,
binary_data: &[u8],
file_info: &FileInfoData,
ui: &mut egui::Ui,
_error_manager: &mut ErrorManager,
) -> Option<RangeInclusive<usize>> {
if self.is_open {
let mut is_open = self.is_open;
let mut ret = None;
egui::Window::new("Detection")
.open(&mut is_open)
.vscroll(true)
.show(ui.ctx(), |ui| {
ui.label(format!(
"Name: {} ({}) - {}",
file_info.name, file_info.file_type, file_info.extension
));
ui.separator();
if matches!(self.cache, DetectionCache::Empty) {
self.cache = DetectionCache::parse(binary_data, file_info);
}
ret = self.cache.show(ui, binary_data, file_info);
});
self.is_open = is_open;
return ret;
}
None
}
}