deflate() error handling

This commit is contained in:
Kornel Lesiński 2018-06-01 15:06:16 +01:00 committed by Kornel Lesiński
parent 84d3ba417b
commit 9a98a31a46
3 changed files with 28 additions and 18 deletions

View file

@ -13,7 +13,7 @@ pub fn inflate(data: &[u8]) -> Result<Vec<u8>, PngError> {
} }
/// Compress a data stream using the DEFLATE algorithm /// Compress a data stream using the DEFLATE algorithm
pub fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8) -> Vec<u8> { pub fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8) -> Result<Vec<u8>, PngError> {
#[cfg(feature = "cfzlib")] #[cfg(feature = "cfzlib")]
{ {
if is_cfzlib_supported() { if is_cfzlib_supported() {
@ -21,7 +21,7 @@ pub fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8) -> Vec<u8> {
} }
} }
miniz_stream::compress_to_vec_oxipng(data, zc, zw.into(), zs.into()) Ok(miniz_stream::compress_to_vec_oxipng(data, zc, zw.into(), zs.into()))
} }
#[cfg(feature = "cfzlib")] #[cfg(feature = "cfzlib")]
@ -40,20 +40,22 @@ fn is_cfzlib_supported() -> bool {
} }
#[cfg(feature = "cfzlib")] #[cfg(feature = "cfzlib")]
pub fn cfzlib_deflate(data: &[u8], level: u8, strategy: u8, window_bits: u8) -> Vec<u8> { pub fn cfzlib_deflate(data: &[u8], level: u8, strategy: u8, window_bits: u8) -> Result<Vec<u8>, PngError> {
use std::mem; use std::mem;
use cloudflare_zlib_sys::*; use cloudflare_zlib_sys::*;
assert!(data.len() < u32::max_value() as usize); assert!(data.len() < u32::max_value() as usize);
unsafe { unsafe {
let mut stream = mem::zeroed(); let mut stream = mem::zeroed();
assert_eq!(Z_OK, deflateInit2( if Z_OK != deflateInit2(
&mut stream, &mut stream,
level.into(), level.into(),
Z_DEFLATED, Z_DEFLATED,
window_bits.into(), window_bits.into(),
MAX_MEM_LEVEL, MAX_MEM_LEVEL,
strategy.into())); strategy.into()) {
return Err(PngError::new("deflateInit2"));
}
let max_size = deflateBound(&mut stream, data.len() as uLong) as usize; let max_size = deflateBound(&mut stream, data.len() as uLong) as usize;
// it's important to have the capacity pre-allocated, // it's important to have the capacity pre-allocated,
@ -65,11 +67,15 @@ pub fn cfzlib_deflate(data: &[u8], level: u8, strategy: u8, window_bits: u8) ->
stream.avail_in = data.len() as uInt; stream.avail_in = data.len() as uInt;
stream.next_out = out.as_mut_ptr(); stream.next_out = out.as_mut_ptr();
stream.avail_out = out.capacity() as uInt; stream.avail_out = out.capacity() as uInt;
assert_eq!(Z_STREAM_END, deflate(&mut stream, Z_FINISH)); if Z_STREAM_END != deflate(&mut stream, Z_FINISH) {
assert_eq!(Z_OK, deflateEnd(&mut stream)); return Err(PngError::new("deflate"));
}
if Z_OK != deflateEnd(&mut stream) {
return Err(PngError::new("deflateEnd"));
}
debug_assert!(stream.total_out as usize <= out.capacity()); debug_assert!(stream.total_out as usize <= out.capacity());
out.set_len(stream.total_out as usize); out.set_len(stream.total_out as usize);
return out; return Ok(out);
} }
} }

View file

@ -501,7 +501,10 @@ fn optimize_png(
let new_idat = if opts.deflate == Deflaters::Zlib { let new_idat = if opts.deflate == Deflaters::Zlib {
deflate::deflate(filtered, trial.compression, trial.strategy, opts.window) deflate::deflate(filtered, trial.compression, trial.strategy, opts.window)
} else { } else {
deflate::zopfli_deflate(filtered).unwrap() deflate::zopfli_deflate(filtered)
};
let new_idat = if let Ok(n) = new_idat {n} else {
return None;
}; };
if opts.verbosity == Some(1) { if opts.verbosity == Some(1) {

View file

@ -603,28 +603,29 @@ impl PngData {
assert!(!alphas.is_empty()); assert!(!alphas.is_empty());
let best = alphas let best = alphas
.iter() .iter()
.map(|alpha| { .filter_map(|alpha| {
let mut image = self.clone(); let mut image = self.clone();
image.reduce_alpha_channel(*alpha); image.reduce_alpha_channel(*alpha);
let size = STD_FILTERS STD_FILTERS
.iter() .iter()
.map(|f| { .filter_map(|f| {
deflate::deflate( deflate::deflate(
&image.filter_image(*f), &image.filter_image(*f),
STD_COMPRESSION, STD_COMPRESSION,
STD_STRATEGY, STD_STRATEGY,
STD_WINDOW, STD_WINDOW,
).len() ).ok()
.as_ref().map(|l| l.len())
}) })
.min() .min()
.unwrap(); .map(|size| (size, image))
(size, image)
}) })
.min_by_key(|&(size, _)| size) .min_by_key(|&(size, _)| size);
.unwrap();
if let Some(best) = best {
self.raw_data = best.1.raw_data; self.raw_data = best.1.raw_data;
} }
}
pub fn reduce_alpha_channel(&mut self, optim: AlphaOptim) -> bool { pub fn reduce_alpha_channel(&mut self, optim: AlphaOptim) -> bool {
let (bpc, bpp) = match self.ihdr_data.color_type { let (bpc, bpp) = match self.ihdr_data.color_type {