X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=src%2Fdetect.rs;h=f79d063db8165c2d360cea58b728f34e6d2e308d;hb=HEAD;hp=7dad84259ada8ef5a39756ad91ff9ec99a5a0c3c;hpb=db5cc44ba0982de9addf169510630d5ad033f7ef;p=nihav.git diff --git a/src/detect.rs b/src/detect.rs deleted file mode 100644 index 7dad842..0000000 --- a/src/detect.rs +++ /dev/null @@ -1,268 +0,0 @@ -use std::io::SeekFrom; -use io::byteio::ByteReader; - -#[derive(Debug,Clone,Copy,PartialEq)] -pub enum DetectionScore { - No, - ExtensionMatches, - MagicMatches, -} - -impl DetectionScore { - pub fn less(&self, other: DetectionScore) -> bool { - (*self as i32) < (other as i32) - } -} - -#[allow(dead_code)] -enum Arg { - Byte(u8), - U16BE(u16), - U16LE(u16), - U24BE(u32), - U24LE(u32), - U32BE(u32), - U32LE(u32), - U64BE(u64), - U64LE(u64), -} - -impl Arg { - fn val(&self) -> u64 { - match *self { - Arg::Byte(b) => { b as u64 } - Arg::U16BE(v) => { v as u64 } - Arg::U16LE(v) => { v as u64 } - Arg::U24BE(v) => { v as u64 } - Arg::U24LE(v) => { v as u64 } - Arg::U32BE(v) => { v as u64 } - Arg::U32LE(v) => { v as u64 } - Arg::U64BE(v) => { v } - Arg::U64LE(v) => { v } - } - } - fn read_val(&self, src: &mut ByteReader) -> Option { - match *self { - Arg::Byte(_) => { - let res = src.peek_byte(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U16BE(_) => { - let res = src.peek_u16be(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U16LE(_) => { - let res = src.peek_u16le(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U24BE(_) => { - let res = src.peek_u24be(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U24LE(_) => { - let res = src.peek_u24le(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U32BE(_) => { - let res = src.peek_u32be(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U32LE(_) => { - let res = src.peek_u32le(); - if let Err(_) = res { return None; } - Some(res.unwrap() as u64) - } - Arg::U64BE(_) => { - let res = src.peek_u64be(); - if let Err(_) = res { return None; } - Some(res.unwrap()) - } - Arg::U64LE(_) => { - let res = src.peek_u64le(); - if let Err(_) = res { return None; } - Some(res.unwrap()) - } - } - } - fn eq(&self, src: &mut ByteReader) -> bool { - let val = self.read_val(src); - if let None = val { false } - else { val.unwrap() == self.val() } - } - fn ge(&self, src: &mut ByteReader) -> bool { - let val = self.read_val(src); - if let None = val { false } - else { val.unwrap() >= self.val() } - } - fn gt(&self, src: &mut ByteReader) -> bool { - let val = self.read_val(src); - if let None = val { false } - else { val.unwrap() > self.val() } - } - fn le(&self, src: &mut ByteReader) -> bool { - let val = self.read_val(src); - if let None = val { false } - else { val.unwrap() <= self.val() } - } - fn lt(&self, src: &mut ByteReader) -> bool { - let val = self.read_val(src); - if let None = val { false } - else { val.unwrap() < self.val() } - } -} - -#[allow(dead_code)] -enum CC<'a> { - Or(&'a CC<'a>, &'a CC<'a>), - Eq(Arg), - Str(&'static [u8]), - In(Arg, Arg), - Lt(Arg), - Le(Arg), - Gt(Arg), - Ge(Arg), -} - -impl<'a> CC<'a> { - fn eval(&self, src: &mut ByteReader) -> bool { - match *self { - CC::Or (ref a, ref b) => { a.eval(src) || b.eval(src) }, - CC::Eq(ref arg) => { arg.eq(src) }, - CC::In(ref a, ref b) => { a.le(src) && b.ge(src) }, - CC::Lt(ref arg) => { arg.lt(src) }, - CC::Le(ref arg) => { arg.le(src) }, - CC::Gt(ref arg) => { arg.gt(src) }, - CC::Ge(ref arg) => { arg.ge(src) }, - CC::Str(str) => { - let mut val: Vec = Vec::with_capacity(str.len()); - val.resize(str.len(), 0); - let res = src.peek_buf(val.as_mut_slice()); - if let Err(_) = res { return false; } - val == str - } - } - } -} - -struct CheckItem<'a> { - offs: u32, - cond: &'a CC<'a>, -} - -#[allow(dead_code)] -struct DetectConditions<'a> { - demux_name: &'static str, - extensions: &'static str, - conditions: &'a [CheckItem<'a>], -} - -const DETECTORS: &[DetectConditions] = &[ - DetectConditions { - demux_name: "avi", - extensions: ".avi", - conditions: &[CheckItem{offs: 0, cond: &CC::Or(&CC::Str(b"RIFF"), &CC::Str(b"ON2 ")) }, - CheckItem{offs: 8, cond: &CC::Or(&CC::Or(&CC::Str(b"AVI LIST"), - &CC::Str(b"AVIXLIST")), - &CC::Str(b"ON2fLIST")) }, - ] - }, - DetectConditions { - demux_name: "gdv", - extensions: ".gdv", - conditions: &[CheckItem{offs: 0, cond: &CC::Eq(Arg::U32LE(0x29111994))}], - }, - DetectConditions { - demux_name: "realaudio", - extensions: ".ra,.ram", - conditions: &[CheckItem{offs: 0, cond: &CC::Str(b".ra\xFD")}], - }, - DetectConditions { - demux_name: "realmedia", - extensions: ".rm,.rmvb,.rma,.ra,.ram", - conditions: &[CheckItem{offs: 0, cond: &CC::Or(&CC::Str(b".RMF"), &CC::Str(b".RMP")) }, - CheckItem{offs: 4, cond: &CC::Ge(Arg::U32BE(10))}], - }, - DetectConditions { - demux_name: "real_ivr", - extensions: ".ivr", - conditions: &[CheckItem{offs: 0, cond: &CC::Or(&CC::Str(b".R1M"), &CC::Str(b".REC"))}], - }, -]; - -pub fn detect_format(name: &str, src: &mut ByteReader) -> Option<(&'static str, DetectionScore)> { - let mut result = None; - let lname = name.to_lowercase(); - for detector in DETECTORS { - let mut score = DetectionScore::No; - if name.len() > 0 { - for ext in detector.extensions.split(',') { - if lname.ends_with(ext) { - score = DetectionScore::ExtensionMatches; - break; - } - } - } - let mut passed = detector.conditions.len() > 0; - for ck in detector.conditions { - let ret = src.seek(SeekFrom::Start(ck.offs as u64)); - if let Err(_) = ret { - passed = false; - break; - } - if !ck.cond.eval(src) { - passed = false; - break; - } - } - if passed { - score = DetectionScore::MagicMatches; - } - if score == DetectionScore::MagicMatches { - return Some((detector.demux_name, score)); - } - if let None = result { - result = Some((detector.demux_name, score)); - } else { - let (_, oldsc) = result.unwrap(); - if oldsc.less(score) { - result = Some((detector.demux_name, score)); - } - } - } - result -} - -#[cfg(test)] -mod test { - use super::*; - use std::fs::File; - use io::byteio::*; - - #[test] - fn test_avi_detect() { - let name = "assets/laser05.avi"; - let mut file = File::open(name).unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let (name, score) = detect_format(name, &mut br).unwrap(); - assert_eq!(name, "avi"); - assert_eq!(score, DetectionScore::MagicMatches); - } - - #[test] - fn test_gdv_detect() { - let name = "assets/intro1.gdv"; - let mut file = File::open(name).unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let (name, score) = detect_format(name, &mut br).unwrap(); - assert_eq!(name, "gdv"); - assert_eq!(score, DetectionScore::MagicMatches); - } -}