#![crate_name = "infer"]
mod map;
mod matchers;
use std::fs;
use std::path::Path;
pub use matchers::*;
pub type Matcher = fn(buf: &[u8]) -> bool;
#[derive(Debug, Eq, PartialEq)]
pub struct Type {
pub mime: String,
pub ext: String,
}
pub struct Infer {
mmap: Vec<(map::MatcherType, String, String, Matcher)>,
}
impl Infer {
pub fn new() -> Infer {
let mut v: Vec<(map::MatcherType, String, String, Matcher)> = Vec::new();
map::setup(&mut v);
Infer { mmap: v }
}
pub fn get(&self, buf: &[u8]) -> Option<Type> {
for (_mt, mime, ext, matcher) in self.mmap.iter() {
if matcher(buf) {
return Some(Type {
mime: (*mime).clone(),
ext: (*ext).clone(),
});
}
}
return None;
}
pub fn get_from_path<P: AsRef<Path>>(&self, path: P) -> Result<Option<Type>, std::io::Error> {
let r = fs::read(path);
if r.is_err() {
return Err(r.unwrap_err());
}
let data = r.unwrap();
return Ok(self.get(&data));
}
pub fn is(&self, buf: &[u8], ext: &str) -> bool {
for (_mt, _mi, _e, matcher) in self
.mmap
.iter()
.find(|(_mt, _mime, ex, _matcher)| *ex == ext)
{
if matcher(buf) {
return true;
}
}
return false;
}
pub fn is_mime(&self, buf: &[u8], mime: &str) -> bool {
for (_mt, _mi, _e, matcher) in self
.mmap
.iter()
.find(|(_mt, mi, _ext, _matcher)| *mi == mime)
{
if matcher(buf) {
return true;
}
}
return false;
}
pub fn is_supported(&self, ext: &str) -> bool {
for (_mt, _mime, type_ext, _matcher) in self.mmap.iter() {
if ext == *type_ext {
return true;
}
}
return false;
}
pub fn is_mime_supported(&self, mime: &str) -> bool {
for (_mt, type_mime, _ext, _matcher) in self.mmap.iter() {
if mime == *type_mime {
return true;
}
}
return false;
}
pub fn is_app(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::APP);
}
pub fn is_archive(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::ARCHIVE);
}
pub fn is_audio(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::AUDIO);
}
pub fn is_document(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::DOC);
}
pub fn is_font(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::FONT);
}
pub fn is_image(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::IMAGE);
}
pub fn is_video(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::VIDEO);
}
pub fn is_custom(&self, buf: &[u8]) -> bool {
return self.is_type(buf, map::MatcherType::CUSTOM);
}
pub fn add(&mut self, mime: &str , ext: &str, m: Matcher) {
self.mmap.push((map::MatcherType::CUSTOM, mime.to_string(), ext.to_string(), m));
}
fn is_type(&self, buf: &[u8], typ: map::MatcherType) -> bool {
for (_mt, _mi, _ex, matcher) in self
.mmap
.iter()
.filter(|(mt, _mime, _e, _matcher)| *mt == typ)
{
if matcher(buf) {
return true;
}
}
return false;
}
}
#[cfg(test)]
mod tests {
use super::Infer;
#[test]
fn test_get_unknown() {
let v = Vec::new();
let info = Infer::new();
assert!(info.get(&v).is_none());
}
#[test]
fn test_get_jpeg() {
let v = vec![0xFF, 0xD8, 0xFF, 0xAA];
let info = Infer::new();
match info.get(&v) {
Some(info) => {
assert_eq!(info.ext, "jpg");
assert_eq!(info.mime, "image/jpeg");
}
None => assert!(false, "type info expected"),
}
}
}