oxyromon 0.23.0

Rusty ROM OrgaNizer
use anyhow::{Context, Result};
use infer::{Infer, Type};
use std::path::Path;
use std::sync::LazyLock;

pub const BIN_EXTENSION: &str = "bin";
pub const BPS_EXTENSION: &str = "bps";
pub const CHD_EXTENSION: &str = "chd";
pub const CIA_EXTENSION: &str = "cia";
pub const CSO_EXTENSION: &str = "cso";
pub const CUE_EXTENSION: &str = "cue";
pub const DAT_EXTENSION: &str = "dat";
pub const GDI_EXTENSION: &str = "gdi";
pub const GZ_EXTENSION: &str = "gz";
pub const IPS_EXTENSION: &str = "ips";
pub const IRD_EXTENSION: &str = "ird";
pub const ISO_EXTENSION: &str = "iso";
pub const M3U_EXTENSION: &str = "m3u";
pub const NSP_EXTENSION: &str = "nsp";
pub const NSZ_EXTENSION: &str = "nsz";
pub const PKG_EXTENSION: &str = "pkg";
pub const PUP_EXTENSION: &str = "pup";
pub const RAP_EXTENSION: &str = "rap";
pub const RAW_EXTENSION: &str = "raw";
pub const RDSK_EXTENSION: &str = "rdsk";
pub const RIFF_EXTENSION: &str = "riff";
pub const RVZ_EXTENSION: &str = "rvz";
pub const SEVENZIP_EXTENSION: &str = "7z";
pub const WBFS_EXTENSION: &str = "wbfs";
pub const XDELTA_EXTENSION: &str = "xdelta";
pub const ZIP_EXTENSION: &str = "zip";
pub const ZSO_EXTENSION: &str = "zso";

pub static ARCHIVE_EXTENSIONS: [&str; 2] = [SEVENZIP_EXTENSION, ZIP_EXTENSION];
pub static PS3_EXTENSIONS: [&str; 3] = [PKG_EXTENSION, PUP_EXTENSION, RAP_EXTENSION];

pub static NON_ORIGINAL_EXTENSIONS: &[&str] = &[
    CHD_EXTENSION,
    CSO_EXTENSION,
    NSZ_EXTENSION,
    RVZ_EXTENSION,
    ZSO_EXTENSION,
    SEVENZIP_EXTENSION,
    ZIP_EXTENSION,
];

fn bps_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x42 && buf[1] == 0x50 && buf[2] == 0x53 && buf[3] == 0x31
}

fn chd_matcher(buf: &[u8]) -> bool {
    buf.len() >= 8
        && buf[0] == 0x4D
        && buf[1] == 0x43
        && buf[2] == 0x6F
        && buf[3] == 0x6D
        && buf[4] == 0x70
        && buf[5] == 0x72
        && buf[6] == 0x48
        && buf[7] == 0x44
}

fn cso_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x43 && buf[1] == 0x49 && buf[2] == 0x53 && buf[3] == 0x4F
}

fn ips_matcher(buf: &[u8]) -> bool {
    buf.len() >= 5
        && buf[0] == 0x50
        && buf[1] == 0x41
        && buf[2] == 0x54
        && buf[3] == 0x43
        && buf[4] == 0x48
}

fn ird_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x33 && buf[1] == 0x49 && buf[2] == 0x52 && buf[3] == 0x44
}

fn rdsk_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x44 && buf[2] == 0x53 && buf[3] == 0x4B
}

fn riff_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x46
}

fn rvz_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x52 && buf[1] == 0x56 && buf[2] == 0x5A && buf[3] == 0x01
}

fn xdelta_matcher(buf: &[u8]) -> bool {
    buf.len() >= 3 && buf[0] == 0xD6 && buf[1] == 0xC3 && buf[2] == 0xC4
}

fn zso_matcher(buf: &[u8]) -> bool {
    buf.len() >= 4 && buf[0] == 0x5A && buf[1] == 0x49 && buf[2] == 0x53 && buf[3] == 0x4F
}

static MATCHER: LazyLock<Infer> = LazyLock::new(init_matcher);

fn init_matcher() -> Infer {
    let mut matcher = Infer::new();
    matcher.add("application/x-bps", BPS_EXTENSION, bps_matcher);
    matcher.add("application/x-chd", CHD_EXTENSION, chd_matcher);
    matcher.add("application/x-cso", CSO_EXTENSION, cso_matcher);
    matcher.add("application/x-ips", IPS_EXTENSION, ips_matcher);
    matcher.add("application/x-ird", IRD_EXTENSION, ird_matcher);
    matcher.add("application/x-rdsk", RDSK_EXTENSION, rdsk_matcher);
    matcher.add("application/x-riff", RIFF_EXTENSION, riff_matcher);
    matcher.add("application/x-rvz", RVZ_EXTENSION, rvz_matcher);
    matcher.add("application/x-xdelta", XDELTA_EXTENSION, xdelta_matcher);
    matcher.add("application/x-zso", ZSO_EXTENSION, zso_matcher);
    matcher
}

pub async fn get_mimetype<P: AsRef<Path>>(path: &P) -> Result<Option<Type>> {
    let matcher = &*MATCHER;
    matcher
        .get_from_path(path)
        .context("Failed to infer MIME type")
}

#[cfg(test)]
mod test_bps_matcher;
#[cfg(test)]
mod test_chd_matcher;
#[cfg(test)]
mod test_cso_matcher;
#[cfg(test)]
mod test_ips_matcher;
#[cfg(test)]
mod test_ird_matcher;
#[cfg(test)]
mod test_rdsk_matcher;
#[cfg(test)]
mod test_riff_matcher;
#[cfg(test)]
mod test_rvz_matcher;
#[cfg(test)]
mod test_xdelta_matcher;
#[cfg(test)]
mod test_zso_matcher;