Handle files with invalid filters (#410)

The bad filter case is reachable, and can happen when the PNG file is corrupted.
This commit is contained in:
Kornel 2021-07-12 04:07:18 +01:00 committed by GitHub
parent 286aaffa31
commit ea75f6ccc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 6 deletions

View file

@ -1,3 +1,5 @@
use crate::error::PngError;
pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) {
assert!(data.len() >= bpp);
assert!(last_line.is_empty() || data.len() == last_line.len());
@ -65,7 +67,13 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &
}
}
pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec<u8>) {
pub fn unfilter_line(
filter: u8,
bpp: usize,
data: &[u8],
last_line: &[u8],
buf: &mut Vec<u8>,
) -> Result<(), PngError> {
buf.clear();
buf.reserve(data.len());
assert!(data.len() >= bpp);
@ -114,8 +122,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf:
);
}
}
_ => unreachable!(),
_ => return Err(PngError::InvalidData),
}
Ok(())
}
fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {

View file

@ -136,7 +136,7 @@ impl PngData {
transparency_pixel,
aux_headers,
};
raw.data = raw.unfilter_image();
raw.data = raw.unfilter_image()?;
// Return the PngData
Ok(Self {
idat_data: idat_headers,
@ -281,7 +281,7 @@ impl PngImage {
}
/// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream
fn unfilter_image(&self) -> Vec<u8> {
fn unfilter_image(&self) -> Result<Vec<u8>, PngError> {
let mut unfiltered = Vec::with_capacity(self.data.len());
let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize;
let mut last_line: Vec<u8> = Vec::new();
@ -293,13 +293,13 @@ impl PngImage {
last_pass = line.pass;
}
last_line.resize(line.data.len(), 0);
unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf);
unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf)?;
unfiltered.push(0);
unfiltered.extend_from_slice(&unfiltered_buf);
std::mem::swap(&mut last_line, &mut unfiltered_buf);
unfiltered_buf.clear();
}
unfiltered
Ok(unfiltered)
}
/// Apply the specified filter type to all rows in the image