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(())
/// # }
/// ```
#[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<T, F>(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;
}

View File

@ -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]

View File

@ -25,10 +25,7 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
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<usize>
}
if fl & FHCRC != 0 {
read_data!(p + 2, LE in b => _crc = u16[p];);
check_data!(p + 2, b);
p += 2;
}

View File

@ -88,9 +88,7 @@ pub fn read_old_minf(b: &[u8]) -> ResultS<Minf>
/// 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))
}

View File

@ -88,11 +88,12 @@ pub fn read_bitmap(b: &[u8]) -> ResultS<Bitmap>
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<Bitmap>
}
} 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")?);
}