nameme_core 0.2.3

Library to find the actual type of files based on their magic number.
#[path = "src/sig.rs"]
mod sigs;

use std::{
    collections::{hash_map::DefaultHasher, HashMap},
    fs,
    hash::{Hash, Hasher},
};

use anyhow;
use serde_json;
use sigs::Signature;

fn main() -> anyhow::Result<()> {
    let json = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/data/sigs.json"));
    let sigs: Vec<Signature> = serde_json::from_str(json)?;

    let sigs_rs = make_sigs(sigs.clone())?;
    let head_rs = make_head(sigs.clone())?;
    let _prex_rs = make_prex(sigs)?;

    fs::write(
        concat!(env!("CARGO_MANIFEST_DIR"), "/src/data/sigs.rs"),
        sigs_rs,
    )?;
    fs::write(
        concat!(env!("CARGO_MANIFEST_DIR"), "/src/data/head.rs"),
        head_rs,
    )?;
    //    fs::write(
    //        concat!(env!("CARGO_MANIFEST_DIR"), "/src/data/prex.rs"),
    //        prex_rs,
    //    )?;

    Ok(())
}

fn make_prex(sigs: Vec<Signature>) -> anyhow::Result<String> {
    let mut prefixes: HashMap<u64, Vec<usize>> = HashMap::new();

    for (i, sig) in sigs.iter().enumerate() {
        let mut s = DefaultHasher::new();
        let mut header = vec![];
        for byte in &sig.header {
            header.push(byte);
            header.hash(&mut s);
            let hash = s.finish();
            if prefixes.contains_key(&hash) {
                prefixes.get_mut(&hash).unwrap().push(i);
            } else {
                prefixes.insert(hash, vec![i]);
            }
        }
    }

    let mut ret = String::from(
        "// Automatically generated with build.rs. Edit with care.\nuse std::collections::HashMap;\n",
    );
    ret.push_str("thread_local!(pub static PREFIXES: HashMap<u64, Vec<usize>> = HashMap::from([\n");

    for (k, v) in prefixes {
        ret.push_str(format!("\t({}, vec![\n", k).as_str());
        for i in v {
            ret.push_str(format!("\t\t{i},\n").as_str());
        }
        ret.push_str("\t]),\n");
    }

    ret.push_str("]));");
    Ok(ret)
}

fn make_head(sigs: Vec<Signature>) -> anyhow::Result<String> {
    let mut ret = String::from(
        "// Automatically generated with build.rs. Edit with care.\nuse std::collections::HashMap;\n",
    );
    ret.push_str("thread_local!(pub static HEADERS: HashMap<u64, usize> = HashMap::from([\n");

    let mut max_header_len_bytes = 0;
    for (i, sig) in sigs.iter().enumerate() {
        if sig.exts.len() > max_header_len_bytes {
            max_header_len_bytes = sig.exts.len();
        }

        let mut s = DefaultHasher::new();
        sig.header.hash(&mut s);
        let hash = s.finish();
        ret.push_str(
            format!(
                "\t//d: {} -> hash({:?}) = {}\n",
                sig.description, sig.header, hash
            )
            .as_str(),
        );
        ret.push_str(format!("\t({}, {}),\n", hash, i).as_str())
    }

    ret.push_str("]));\n");
    ret.push_str(
        format!(
            "pub const MAX_HEADER_BYTES: usize = {};",
            max_header_len_bytes
        )
        .as_str(),
    );
    Ok(ret)
}

fn make_sigs(sigs: Vec<Signature>) -> anyhow::Result<String> {
    let mut ret = String::from(
        "// Automatically generated with build.rs. Edit with care.\nuse crate::sig::Signature;\n",
    );

    ret.push_str("thread_local!(pub static SIGNATURES: Vec<Signature<'static>> = vec![\n");
    for sig in sigs {
        ret.push_str("\tSignature {\n");
        ret.push_str(format!("\t\tdescription: \"{}\",\n", sig.description).as_str());
        ret.push_str(format!("\t\tclass: \"{}\",\n", sig.class).as_str());
        ret.push_str("\t\texts: vec![\n");
        for ext in &sig.exts {
            ret.push_str(format!("\t\t\t\"{}\",\n", ext).as_str());
        }
        ret.push_str("\t\t],\n");
        ret.push_str(format!("\t\toffset: {},\n", sig.offset).as_str());
        ret.push_str("\t\theader: vec![\n");
        for b in sig.header {
            ret.push_str(format!("\t\t\t{},\n", b).as_str());
        }
        ret.push_str("\t\t],\n");
        ret.push_str("\t\ttrailer: vec![\n");
        for b in sig.trailer {
            ret.push_str(format!("\t\t\t{},\n", b).as_str());
        }
        ret.push_str("\t\t],\n");
        ret.push_str("\t},\n");
    }
    ret.push_str("]);");

    Ok(ret)
}