diff --git a/source/marathon/defl.rs b/source/marathon/defl.rs new file mode 100644 index 0000000..b07bd3b --- /dev/null +++ b/source/marathon/defl.rs @@ -0,0 +1,62 @@ +//! DEFLATE loader. + +use crate::durandal::err::*; + +/// Loads a GZIP file header. +pub fn load_gzip_header(b: &[u8]) -> ResultS +{ + const FHCRC: u8 = 1 << 1; + const FEXTRA: u8 = 1 << 2; + const FNAME: u8 = 1 << 3; + const FCOMMENT: u8 = 1 << 4; + + read_data! { + 10, LE in b => + id = u16[0]; + cm = u8[2]; + fl = u8[3]; + } + + if id != 0x8B1F || cm != 8 { + bail!("not gzip format"); + } + + let mut p = 10; + + if fl & FEXTRA != 0 { + read_data!(p + 2, LE in b => xlen = u16[p] usize;); + + if p + 2 + xlen > b.len() { + bail!("not enough data"); + } + + p += xlen; + } + + if fl & FNAME != 0 { + p = skip_zero_terminated_item(&b[p..])?; + } + + if fl & FCOMMENT != 0 { + p = skip_zero_terminated_item(&b[p..])?; + } + + if fl & FHCRC != 0 { + read_data!(p + 2, LE in b => _crc = u16[p];); + + p += 2; + } + + Ok(p) +} + +fn skip_zero_terminated_item(b: &[u8]) -> ResultS +{ + if let Some(i) = b.iter().position(|&n| n == 0) { + Ok(i) + } else { + bail!("no end of zero terminated item"); + } +} + +// EOF diff --git a/source/marathon/mod.rs b/source/marathon/mod.rs index 86fc790..f596331 100644 --- a/source/marathon/mod.rs +++ b/source/marathon/mod.rs @@ -1,5 +1,6 @@ //! Library for file format data readers. +pub mod defl; pub mod machdr; pub mod map; pub mod phy; diff --git a/tests/data/gzipbad1.bin b/tests/data/gzipbad1.bin new file mode 100644 index 0000000..d56535e Binary files /dev/null and b/tests/data/gzipbad1.bin differ diff --git a/tests/data/gzipbad2.bin b/tests/data/gzipbad2.bin new file mode 100644 index 0000000..e4e84f5 Binary files /dev/null and b/tests/data/gzipbad2.bin differ diff --git a/tests/data/gzipbad3.bin b/tests/data/gzipbad3.bin new file mode 100644 index 0000000..c8a57dc Binary files /dev/null and b/tests/data/gzipbad3.bin differ diff --git a/tests/data/gzipbad4.bin b/tests/data/gzipbad4.bin new file mode 100644 index 0000000..f5bebda Binary files /dev/null and b/tests/data/gzipbad4.bin differ diff --git a/tests/data/gzipbad5.bin b/tests/data/gzipbad5.bin new file mode 100644 index 0000000..160dab7 Binary files /dev/null and b/tests/data/gzipbad5.bin differ diff --git a/tests/data/gzipbad6.bin b/tests/data/gzipbad6.bin new file mode 100644 index 0000000..8a4fa68 Binary files /dev/null and b/tests/data/gzipbad6.bin differ diff --git a/tests/data/gzipbad7.bin b/tests/data/gzipbad7.bin new file mode 100644 index 0000000..ed51912 Binary files /dev/null and b/tests/data/gzipbad7.bin differ diff --git a/tests/data/gzipok1.bin b/tests/data/gzipok1.bin new file mode 100644 index 0000000..be9e170 Binary files /dev/null and b/tests/data/gzipok1.bin differ diff --git a/tests/data/gzipok2.bin b/tests/data/gzipok2.bin new file mode 100644 index 0000000..cafa27c Binary files /dev/null and b/tests/data/gzipok2.bin differ diff --git a/tests/data/gzipok3.bin b/tests/data/gzipok3.bin new file mode 100644 index 0000000..347a4aa Binary files /dev/null and b/tests/data/gzipok3.bin differ diff --git a/tests/defl.rs b/tests/defl.rs new file mode 100644 index 0000000..58a503b --- /dev/null +++ b/tests/defl.rs @@ -0,0 +1,29 @@ +use maraiah::marathon::defl::{self, load_gzip_header}; + +include!("data/rand.rs"); + +#[test] +fn defl_must_succeed() +{ + assert!(load_gzip_header(include_bytes!("data/gzipok1.bin")).is_ok()); + assert!(load_gzip_header(include_bytes!("data/gzipok2.bin")).is_ok()); + assert!(load_gzip_header(include_bytes!("data/gzipok3.bin")).is_ok()); +} + +#[test] +fn defl_must_not_succeed() +{ + for inp in &RANDOM { + assert!(defl::load_gzip_header(inp).is_err()); + } + + assert!(load_gzip_header(include_bytes!("data/gzipbad1.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad2.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad3.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad4.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad5.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad6.bin")).is_err()); + assert!(load_gzip_header(include_bytes!("data/gzipbad7.bin")).is_err()); +} + +// EOF