From ea75f6ccc1528270542d172d7bf40f796d36a555 Mon Sep 17 00:00:00 2001 From: Kornel Date: Mon, 12 Jul 2021 04:07:18 +0100 Subject: [PATCH] Handle files with invalid filters (#410) The bad filter case is reachable, and can happen when the PNG file is corrupted. --- src/filters.rs | 13 +++++++++++-- src/png/mod.rs | 8 ++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/filters.rs b/src/filters.rs index 8b85ca17..c0c10b10 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -1,3 +1,5 @@ +use crate::error::PngError; + pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec) { 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) { +pub fn unfilter_line( + filter: u8, + bpp: usize, + data: &[u8], + last_line: &[u8], + buf: &mut Vec, +) -> 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 { diff --git a/src/png/mod.rs b/src/png/mod.rs index 44bfded4..2ae3b116 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -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 { + fn unfilter_image(&self) -> Result, 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 = 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