diff --git a/source/durandal/bin.rs b/source/durandal/bin.rs index 6f15769..6a12bc4 100644 --- a/source/durandal/bin.rs +++ b/source/durandal/bin.rs @@ -156,17 +156,26 @@ macro_rules! _durandal_read_impl { /// # Ok(()) /// # } /// ``` -#[macro_export(local_inner_macros)] +#[macro_export] macro_rules! read_data { ( $sz:expr , $ty:ident in $b:ident => $( $nam:ident = $t:ident [ $n:expr ] $( $ex:ident )* ; )* + ) => { + $crate::check_data!($sz, $b); + $($crate::_durandal_read_impl!($ty $b $nam $($ex)* $t $n);)* + }; +} + +/// Checks if there is enough data in `b`. +#[macro_export] +macro_rules! check_data { + ( + $sz:expr , $b:ident ) => { if $b.len() < $sz { return Err(err_msg("not enough data")); } - - $($crate::_durandal_read_impl!($ty $b $nam $($ex)* $t $n);)* }; } @@ -360,11 +369,7 @@ pub fn rd_ofstable(b: &[u8], for _ in 0..num { let ofs = usize_from_u32(u32b(&b[p..p + 4])); - - if ofs >= b.len() { - bail!("not enough data"); - } - + check_data!(ofs, b); v.push(read(&b[ofs..])?); p += 4; } diff --git a/source/durandal/bit.rs b/source/durandal/bit.rs index 72dea3d..3ca1b5b 100644 --- a/source/durandal/bit.rs +++ b/source/durandal/bit.rs @@ -2,53 +2,49 @@ use crate::durandal::err::*; -/// Reads `width` bits from `b` starting at bit `cr_ptr` into an integer. +/// Reads `width` bits from `b` starting at bit `cr_bit` into an integer. /// /// # Errors /// /// The function will return an error if `width` is 0 or more than 64, or if -/// `(cr_ptr + width - 1) / 8` would overflow an index into `b`. -pub fn read_bits(b: &[u8], cr_ptr: usize, width: u8) -> ResultS<(usize, u64)> +/// `(cr_bit + width - 1) / 8` would overflow an index into `b`. +pub fn read_bits(b: &[u8], cr_bit: usize, width: u8) -> ResultS<(usize, u64)> { if width < 1 || width > 64 { bail!("invalid number of bits"); } - let nx_ptr = cr_ptr + usize::from(width); - let ed_ptr = nx_ptr - 1; + let nx_bit = cr_bit + usize::from(width); + let ed_bit = nx_bit - 1; - let first_byte = cr_ptr / 8; - let last_byte = ed_ptr / 8; + let cr_byte = cr_bit / 8; + let ed_byte = ed_bit / 8; - if b.len() <= last_byte { - bail!("not enough data"); - } + check_data!(ed_byte + 1, b); - let first_bits = cr_ptr as u32 % 8; - let last_bits = nx_ptr as u32 % 8; + let cr_bits = cr_bit as u32 % 8; + let nx_bits = nx_bit as u32 % 8; - let last_mask = ((1_u128 << last_bits) - 1) as u64; + let nx_mask = ((1_u128 << nx_bits) - 1) as u64; - let num_bytes = last_byte - first_byte; + let num_bytes = ed_byte - cr_byte; - let bytes = get_bytes(b, num_bytes, first_byte); + let bytes = get_bytes(b, num_bytes, cr_byte); let bits = u64::from_be_bytes(bytes); - let bits = bits.wrapping_shl(first_bits); + let bits = bits.wrapping_shl(cr_bits); let bits = bits >> (64 - width); // special case for over byte boundary - let bits = if num_bytes == 8 { - let lbyt = u64::from(b[last_byte]); - let lbyt = lbyt >> (8 - last_bits); - let lbyt = lbyt & last_mask; + if num_bytes == 8 { + let lbyt = u64::from(b[ed_byte]); + let lbyt = lbyt >> (8 - nx_bits); + let lbyt = lbyt & nx_mask; - (bits & !last_mask) | lbyt + Ok((nx_bit, bits & !nx_mask | lbyt)) } else { - bits - }; - - Ok((nx_ptr, bits)) + Ok((nx_bit, bits)) + } } fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8] diff --git a/source/marathon/defl.rs b/source/marathon/defl.rs index b07bd3b..ddc8d8c 100644 --- a/source/marathon/defl.rs +++ b/source/marathon/defl.rs @@ -25,10 +25,7 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS 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"); - } + check_data!(p + 2 + xlen, b); p += xlen; } @@ -42,7 +39,7 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS } if fl & FHCRC != 0 { - read_data!(p + 2, LE in b => _crc = u16[p];); + check_data!(p + 2, b); p += 2; } diff --git a/source/marathon/map.rs b/source/marathon/map.rs index 7d4a9d8..81f4724 100644 --- a/source/marathon/map.rs +++ b/source/marathon/map.rs @@ -88,9 +88,7 @@ pub fn read_old_minf(b: &[u8]) -> ResultS /// Reads an `iidx` chunk. pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)> { - if b.len() < 2 { - bail!("not enough data"); - } + check_data!(2, b); Ok((u16b(b), 2)) } diff --git a/source/marathon/shp.rs b/source/marathon/shp.rs index 276ffc1..4df8363 100644 --- a/source/marathon/shp.rs +++ b/source/marathon/shp.rs @@ -88,11 +88,12 @@ pub fn read_bitmap(b: &[u8]) -> ResultS fst = u16[p] usize; lst = u16[p + 2] usize; } + let end = lst - fst; p += 4; - if lst < fst || fst > pitch || lst > pitch || b.len() < p + end { + if lst < fst || fst > pitch || lst > pitch { bail!("invalid compressed scanline"); } @@ -110,10 +111,6 @@ pub fn read_bitmap(b: &[u8]) -> ResultS } } else { // simple copy - if b.len() < p + width * height { - bail!("invalid scanline"); - } - bmp.cr.extend_from_slice(ok!(b.get(p..p + width * height), "not enough data")?); }