use crate::debug_logger::create_logger;
use anyhow::{Context, Result};
use std::fs::File;
use std::io::Read;
use std::path::Path;
#[derive(Debug, PartialEq, Eq)]
pub enum ClipboardStrategy {
Image,
File,
Text,
}
const ASSET_EXTS: &[&str] = &[
"dxf", "obj", "stl", "ply", "gcode", "svg", "eps", "ai", "psd", "pdf", "zip", "7z", "tar",
"gz", "rar", "iso", "dll", "bin", "exe", "jar", "class",
];
fn is_asset_extension(p: &Path) -> bool {
if let Some(ext) = p.extension() {
if let Some(s) = ext.to_str() {
return ASSET_EXTS.contains(&s.to_lowercase().as_str());
}
}
false
}
pub fn inspect(path: &Path) -> Result<ClipboardStrategy> {
let log = create_logger("classifier");
if is_asset_extension(path) {
log.debug(&format!(
"Extension override detected (Asset/Binary): {:?}",
path
));
return Ok(ClipboardStrategy::File);
}
let mut file = File::open(path)
.with_context(|| format!("Failed to open file for classification: {:?}", path))?;
let mut buffer = [0u8; 262];
let n = file.read(&mut buffer).unwrap_or(0);
let buffer = &buffer[..n];
if infer::is_image(buffer) {
log.debug(&format!("Detected IMAGE signature: {:?}", path));
return Ok(ClipboardStrategy::Image);
}
if infer::is_archive(buffer) || infer::is_app(buffer) || infer::doc::is_doc(buffer) {
log.debug(&format!("Detected BINARY signature: {:?}", path));
return Ok(ClipboardStrategy::File);
}
if buffer.contains(&0) {
log.debug(&format!(
"Detected NULL bytes (Binary heuristic): {:?}",
path
));
return Ok(ClipboardStrategy::File);
}
log.debug(&format!("Classified as TEXT: {:?}", path));
Ok(ClipboardStrategy::Text)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use std::path::PathBuf;
use tempfile::NamedTempFile;
#[test]
fn test_asset_extension() {
assert_eq!(
inspect(&PathBuf::from("model.dxf")).unwrap(),
ClipboardStrategy::File
);
assert_eq!(
inspect(&PathBuf::from("image.SVG")).unwrap(),
ClipboardStrategy::File
);
}
#[test]
fn test_classify_text() -> Result<()> {
let mut file = NamedTempFile::new()?;
write!(file, "Hello World")?;
assert_eq!(inspect(file.path())?, ClipboardStrategy::Text);
Ok(())
}
#[test]
fn test_classify_binary_nulls() -> Result<()> {
let mut file = NamedTempFile::new()?;
file.write_all(&[0x00, 0x01, 0x02])?;
assert_eq!(inspect(file.path())?, ClipboardStrategy::File);
Ok(())
}
}