openjlc 2.23.7

Ultra-fast Gerber conversion tool.
Documentation
/* src/identifier.rs */

use crate::error::report_error;
use crate::log;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};

#[derive(Debug, Clone, Copy)]
pub enum EDATool {
    Altium,
    KiCad,
    LCEDA,
    Unknown,
}

fn check_file_signature(path: &Path, keyword: &str) -> bool {
    if let Ok(file) = File::open(path) {
        let reader = io::BufReader::new(file);
        return reader
            .lines()
            .take(100)
            .filter_map(|line| line.ok())
            .any(|line| line.to_lowercase().contains(&keyword.to_lowercase()));
    }
    false
}

fn has_no_exclusion(path: &Path, excludes: &[&str]) -> bool {
    if let Ok(file) = File::open(path) {
        let reader = io::BufReader::new(file);
        return !reader
            .lines()
            .take(100)
            .filter_map(|line| line.ok())
            .any(|line| {
                let line_lower = line.to_lowercase();
                excludes
                    .iter()
                    .any(|&ex| line_lower.contains(&ex.to_lowercase()))
            });
    }
    true
}

pub fn identify_eda_files(temp_dir: &Path) -> io::Result<(PathBuf, EDATool)> {
    let candidates = ["gto", "gtl", "gbl"];
    let kicad_names = ["Edge_Cuts", "F_Cu", "F_Mask"];
    let keywords = ["Altium", "KiCad", "EasyEDA", "OpenJLC"];

    for entry in temp_dir.read_dir()? {
        if let Ok(entry) = entry {
            let path = entry.path();
            let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
            if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
                let ext_lower = ext.to_lowercase();
                if candidates.contains(&ext_lower.as_str())
                    || kicad_names.iter().any(|&name| file_name.contains(name))
                {
                    if check_file_signature(&path, "Altium")
                        && has_no_exclusion(&path, &["EasyEDA", "OpenJLC"])
                    {
                        return Ok((path, EDATool::Altium));
                    }
                    if check_file_signature(&path, "KiCad")
                        && has_no_exclusion(&path, &["EasyEDA", "OpenJLC"])
                    {
                        return Ok((path, EDATool::KiCad));
                    }
                    if check_file_signature(&path, "EasyEDA")
                        && has_no_exclusion(&path, &["KiCad", "Altium", "OpenJLC"])
                    {
                        return Ok((path, EDATool::LCEDA));
                    }
                    if keywords.iter().any(|&kw| check_file_signature(&path, kw)) {
                        log::log("! File appears to have been injected");
                        return Err(io::Error::new(io::ErrorKind::InvalidData, ""));
                    } else {
                        log::log("- No valid EDA signature found");
                        report_error();
                        return Err(io::Error::new(io::ErrorKind::NotFound, ""));
                    }
                }
            }
        }
    }
    log::log("- No valid EDA signature found");
    report_error();
    Err(io::Error::new(io::ErrorKind::NotFound, ""))
}