use cfg_if::cfg_if;
use mime::Mime;
pub trait MimeDb {
fn init() -> Self;
fn get_type(&self, data: &[u8]) -> Option<Mime>;
}
cfg_if! {
if #[cfg(any(all(unix, feature = "infer-backend"), all(not(unix), not(feature = "xdg-mime-backend"))))] {
use std::str::FromStr;
pub struct InferDb {
db: infer::Infer,
}
fn open_document_check(buf: &[u8], kind: &str) -> bool {
let mime = format!("application/vnd.oasis.opendocument.{kind}");
let mime = mime.as_bytes();
buf.len() > 38 + mime.len() && buf.starts_with(b"PK\x03\x04") && buf[38..mime.len() + 38] == mime[..]
}
impl MimeDb for InferDb {
fn init() -> Self {
let mut info = infer::Infer::new();
info.add("application/vnd.oasis.opendocument.text", "odt", |buf| {
open_document_check(buf, "text")
});
info.add("application/vnd.oasis.opendocument.spreadsheet", "ods", |buf| {
open_document_check(buf, "spreadsheet")
});
info.add("application/vnd.oasis.opendocument.presentation", "odp", |buf| {
open_document_check(buf, "presentation")
});
info.add("application/x-rpa", "rpa", |buf| {
buf.len() >= 34 && buf.starts_with(b"RPA-") && buf[7] == b' ' && buf[24] ==b' '
});
info.add("application/x-mach-binary", "macho", |buf| {
buf.len() >= 28 && [b"\xFE\xED\xFA\xCF", b"\xFE\xED\xFA\xCE", b"\xCA\xFE\xBA\xBE", b"\xCF\xFA\xED\xFE",
b"\xCE\xFA\xED\xFE", b"\xBE\xBA\xFE\xCA"].iter().any(|magic_numbers| buf.starts_with(&magic_numbers[..]))
});
info.add("image/svg+xml", "svg", |buf| {
for c in buf {
match c {
b'\t' | b'\r' | b'\n' | b'\x20' => continue,
b'<' => break,
_ => return false,
}
}
let identifiers: Vec<&[u8]> = vec![b"svg", b"SVG", b"!DOCTYPE svg", b"!DOCTYPE SVG"];
buf
.split(|c| *c == b'<')
.any(|buf| identifiers.iter().any(|id| buf.starts_with(id)))
});
Self { db: info }
}
fn get_type(&self, data: &[u8]) -> Option<Mime> {
if let Some(mime) = self.db.get(data) {
Mime::from_str(mime.mime_type()).ok()
} else { None }
}
}
} else {
pub struct XdgDb {
db: xdg_mime::SharedMimeInfo,
}
impl MimeDb for XdgDb {
fn init() -> Self {
Self { db: xdg_mime::SharedMimeInfo::new() }
}
fn get_type(&self, data: &[u8]) -> Option<Mime> {
self.db.get_mime_type_for_data(data).map(|m| m.0)
}
}
}
}