more concise range error handling

png-branch
an 2019-03-09 20:27:19 -05:00
parent 8d504612cb
commit 25488e7faa
5 changed files with 39 additions and 46 deletions

View File

@ -156,17 +156,26 @@ macro_rules! _durandal_read_impl {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[macro_export(local_inner_macros)] #[macro_export]
macro_rules! read_data { macro_rules! read_data {
( (
$sz:expr , $ty:ident in $b:ident => $sz:expr , $ty:ident in $b:ident =>
$( $nam:ident = $t:ident [ $n:expr ] $( $ex: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 { if $b.len() < $sz {
return Err(err_msg("not enough data")); 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<T, F>(b: &[u8],
for _ in 0..num { for _ in 0..num {
let ofs = usize_from_u32(u32b(&b[p..p + 4])); let ofs = usize_from_u32(u32b(&b[p..p + 4]));
check_data!(ofs, b);
if ofs >= b.len() {
bail!("not enough data");
}
v.push(read(&b[ofs..])?); v.push(read(&b[ofs..])?);
p += 4; p += 4;
} }

View File

@ -2,53 +2,49 @@
use crate::durandal::err::*; 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 /// # Errors
/// ///
/// The function will return an error if `width` is 0 or more than 64, or if /// 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`. /// `(cr_bit + width - 1) / 8` would overflow an index into `b`.
pub fn read_bits(b: &[u8], cr_ptr: usize, width: u8) -> ResultS<(usize, u64)> pub fn read_bits(b: &[u8], cr_bit: usize, width: u8) -> ResultS<(usize, u64)>
{ {
if width < 1 || width > 64 { if width < 1 || width > 64 {
bail!("invalid number of bits"); bail!("invalid number of bits");
} }
let nx_ptr = cr_ptr + usize::from(width); let nx_bit = cr_bit + usize::from(width);
let ed_ptr = nx_ptr - 1; let ed_bit = nx_bit - 1;
let first_byte = cr_ptr / 8; let cr_byte = cr_bit / 8;
let last_byte = ed_ptr / 8; let ed_byte = ed_bit / 8;
if b.len() <= last_byte { check_data!(ed_byte + 1, b);
bail!("not enough data");
}
let first_bits = cr_ptr as u32 % 8; let cr_bits = cr_bit as u32 % 8;
let last_bits = nx_ptr 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 = u64::from_be_bytes(bytes);
let bits = bits.wrapping_shl(first_bits); let bits = bits.wrapping_shl(cr_bits);
let bits = bits >> (64 - width); let bits = bits >> (64 - width);
// special case for over byte boundary // special case for over byte boundary
let bits = if num_bytes == 8 { if num_bytes == 8 {
let lbyt = u64::from(b[last_byte]); let lbyt = u64::from(b[ed_byte]);
let lbyt = lbyt >> (8 - last_bits); let lbyt = lbyt >> (8 - nx_bits);
let lbyt = lbyt & last_mask; let lbyt = lbyt & nx_mask;
(bits & !last_mask) | lbyt Ok((nx_bit, bits & !nx_mask | lbyt))
} else { } else {
bits Ok((nx_bit, bits))
}; }
Ok((nx_ptr, bits))
} }
fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8] fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8]

View File

@ -25,10 +25,7 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
if fl & FEXTRA != 0 { if fl & FEXTRA != 0 {
read_data!(p + 2, LE in b => xlen = u16[p] usize;); read_data!(p + 2, LE in b => xlen = u16[p] usize;);
check_data!(p + 2 + xlen, b);
if p + 2 + xlen > b.len() {
bail!("not enough data");
}
p += xlen; p += xlen;
} }
@ -42,7 +39,7 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
} }
if fl & FHCRC != 0 { if fl & FHCRC != 0 {
read_data!(p + 2, LE in b => _crc = u16[p];); check_data!(p + 2, b);
p += 2; p += 2;
} }

View File

@ -88,9 +88,7 @@ pub fn read_old_minf(b: &[u8]) -> ResultS<Minf>
/// Reads an `iidx` chunk. /// Reads an `iidx` chunk.
pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)> pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)>
{ {
if b.len() < 2 { check_data!(2, b);
bail!("not enough data");
}
Ok((u16b(b), 2)) Ok((u16b(b), 2))
} }

View File

@ -88,11 +88,12 @@ pub fn read_bitmap(b: &[u8]) -> ResultS<Bitmap>
fst = u16[p] usize; fst = u16[p] usize;
lst = u16[p + 2] usize; lst = u16[p + 2] usize;
} }
let end = lst - fst; let end = lst - fst;
p += 4; p += 4;
if lst < fst || fst > pitch || lst > pitch || b.len() < p + end { if lst < fst || fst > pitch || lst > pitch {
bail!("invalid compressed scanline"); bail!("invalid compressed scanline");
} }
@ -110,10 +111,6 @@ pub fn read_bitmap(b: &[u8]) -> ResultS<Bitmap>
} }
} else { } else {
// simple copy // simple copy
if b.len() < p + width * height {
bail!("invalid scanline");
}
bmp.cr.extend_from_slice(ok!(b.get(p..p + width * height), bmp.cr.extend_from_slice(ok!(b.get(p..p + width * height),
"not enough data")?); "not enough data")?);
} }