diff --git a/CHANGELOG.md b/CHANGELOG.md index b4404d33..ebf0d55f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -190,4 +190,10 @@ ### Added - - Zopfli for aggressive Deflate compression. \ No newline at end of file + - Zopfli for aggressive Deflate compression. + +## [0.9.2] + +### Added + + - `zlib-ng` for fast Deflate compression. This is now the default for compression levels 0-9. \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index fd7d97bc..63b0c17d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zip_next" -version = "0.9.1" +version = "0.9.2" authors = ["Mathijs van de Nes ", "Marli Frost ", "Ryan Levick ", "Chris Hennick "] license = "MIT" @@ -43,9 +43,10 @@ aes-crypto = [ "aes", "constant_time_eq", "hmac", "pbkdf2", "sha1" ] deflate = ["flate2/rust_backend"] deflate-miniz = ["flate2/default"] deflate-zlib = ["flate2/zlib"] +deflate-zlib-ng = ["flate2/zlib-ng"] deflate-zopfli = ["zopfli"] unreserved = [] -default = ["aes-crypto", "bzip2", "deflate", "deflate-zopfli", "time", "zstd"] +default = ["aes-crypto", "bzip2", "deflate", "deflate-zlib-ng", "deflate-zopfli", "time", "zstd"] [[bench]] name = "read_entry" diff --git a/README.md b/README.md index 76e83ad6..9c747911 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ zip_next [![Build Status](https://github.com/Pr0methean/zip-next/actions/workflows/ci.yaml/badge.svg)](https://github.com/Pr0methean/zip-next/actions?query=branch%3Amaster+workflow%3ACI) [![Crates.io version](https://img.shields.io/crates/v/zip_next.svg)](https://crates.io/crates/zip_next) -[Documentation](https://docs.rs/zip_next/0.9.1/zip_next/) +[Documentation](https://docs.rs/zip_next/0.9.2/zip_next/) Info ---- @@ -32,25 +32,31 @@ With all default features: ```toml [dependencies] -zip_next = "0.9.1" +zip_next = "0.9.2" ``` Without the default features: ```toml [dependencies] -zip_next = { version = "0.9.1", default-features = false } +zip_next = { version = "0.9.2", default-features = false } ``` The features available are: * `aes-crypto`: Enables decryption of files which were encrypted with AES. Supports AE-1 and AE-2 methods. -* `deflate`: Enables the deflate compression algorithm, which is the default for zip files. +* `deflate`: Enables decompressing the deflate compression algorithm, which is the default for zip files. +* `deflate-miniz`: Enables deflating files with the `miniz_oxide` library (used when compression quality is 0..=9). +* `deflate-zlib`: Enables deflating files with the `zlib` library (used when compression quality is 0..=9). +* `deflate-zlib-ng`: Enables deflating files with the `zlib-ng` library (used when compression quality is 0..=9). + This is the fastest `deflate` implementation available. +* `deflate-zopfli`: Enables deflating files with the `zopfli` library (used when compression quality is 10..=264). This + is the most effective `deflate` implementation available. * `bzip2`: Enables the BZip2 compression algorithm. * `time`: Enables features using the [time](https://github.com/rust-lang-deprecated/time) crate. * `zstd`: Enables the Zstandard compression algorithm. -All of these are enabled by default. +By default `aes-crypto`, `deflate`, `deflate-zlib-ng`, `deflate-zopfli`, `bzip2`, `time` and `zstd` are enabled. MSRV ---- diff --git a/examples/write_dir.rs b/examples/write_dir.rs index 61535c34..a7f14e35 100644 --- a/examples/write_dir.rs +++ b/examples/write_dir.rs @@ -18,14 +18,17 @@ const METHOD_STORED: Option = #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] const METHOD_DEFLATED: Option = Some(zip_next::CompressionMethod::Deflated); #[cfg(not(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng", + feature = "deflate-zopfli" )))] const METHOD_DEFLATED: Option = None; diff --git a/src/compression.rs b/src/compression.rs index 4d568bf0..e23d743f 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -21,6 +21,7 @@ pub enum CompressionMethod { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] Deflated, @@ -57,6 +58,7 @@ impl CompressionMethod { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] pub const DEFLATE: Self = CompressionMethod::Deflated; @@ -64,6 +66,7 @@ impl CompressionMethod { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" )))] pub const DEFLATE: Self = CompressionMethod::Unsupported(8); @@ -105,6 +108,7 @@ impl CompressionMethod { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] 8 => CompressionMethod::Deflated, @@ -132,6 +136,7 @@ impl CompressionMethod { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] CompressionMethod::Deflated => 8, @@ -161,6 +166,7 @@ pub const SUPPORTED_COMPRESSION_METHODS: &[CompressionMethod] = &[ feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] CompressionMethod::Deflated, diff --git a/src/read.rs b/src/read.rs index 5cbba0ec..f20d4662 100644 --- a/src/read.rs +++ b/src/read.rs @@ -19,7 +19,8 @@ use std::sync::Arc; #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] use flate2::read::DeflateDecoder; @@ -126,7 +127,8 @@ pub(crate) enum ZipFileReader<'a> { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] Deflated(Crc32Reader>>), #[cfg(feature = "bzip2")] @@ -144,7 +146,8 @@ impl<'a> Read for ZipFileReader<'a> { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] ZipFileReader::Deflated(r) => r.read(buf), #[cfg(feature = "bzip2")] @@ -165,7 +168,8 @@ impl<'a> ZipFileReader<'a> { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] ZipFileReader::Deflated(r) => r.into_inner().into_inner().into_inner(), #[cfg(feature = "bzip2")] @@ -271,7 +275,8 @@ pub(crate) fn make_reader( #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] CompressionMethod::Deflated => { let deflate_reader = DeflateDecoder::new(reader); diff --git a/src/write.rs b/src/write.rs index e9eb2a15..5ed7c78a 100644 --- a/src/write.rs +++ b/src/write.rs @@ -21,7 +21,8 @@ use std::sync::Arc; #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] use flate2::write::DeflateEncoder; @@ -60,7 +61,8 @@ enum GenericZipWriter { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] Deflater(DeflateEncoder>), #[cfg(feature = "deflate-zopfli")] @@ -348,13 +350,16 @@ impl Default for FileOptions { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng", + feature = "deflate-zopfli" ))] compression_method: Deflated, #[cfg(not(any( feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" )))] compression_method: Stored, @@ -1157,6 +1162,7 @@ impl GenericZipWriter { { #[allow(deprecated)] + #[allow(unreachable_code)] match compression { Stored => { if compression_level.is_some() { @@ -1171,23 +1177,19 @@ impl GenericZipWriter { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] Deflated => { - #[cfg(all( - not(feature = "deflate"), - not(feature = "deflate-miniz"), - not(feature = "deflate-zlib"), - feature = "deflate-zopfli" - ))] - let default = 24; - - #[cfg(any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib" - ))] - let default = Compression::default().level() as i32; + let default = if cfg!(feature = "deflate") + || cfg!(feature = "deflate-miniz") + || cfg!(feature = "deflate-zlib") + || cfg!(feature = "deflate-zlib-ng") + { + Compression::default().level() as i32 + } else { + 24 + }; let level = clamp_opt( compression_level.unwrap_or(default), @@ -1197,48 +1199,8 @@ impl GenericZipWriter { "Unsupported compression level", ))? as u32; - #[cfg(not(feature = "deflate-zopfli"))] - return Ok(Box::new(move |bare| { - GenericZipWriter::Deflater(DeflateEncoder::new( - bare, - flate2::Compression::new(level), - )) - })); - - #[cfg(all( - not(feature = "deflate"), - not(feature = "deflate-miniz"), - not(feature = "deflate-zlib"), - feature = "deflate-zopfli" - ))] - return Ok(Box::new(move |bare| { - let mut options = Options::default(); - options.iteration_count = - NonZeroU8::try_from((level - best_non_zopfli) as u8).unwrap(); - match deflate_buffer_size { - Some(size) => { - GenericZipWriter::BufferedZopfliDeflater(BufWriter::with_capacity( - size, - zopfli::DeflateEncoder::new(options, Default::default(), bare), - )) - } - None => GenericZipWriter::ZopfliDeflater(zopfli::DeflateEncoder::new( - options, - Default::default(), - bare, - )), - } - })); - - #[cfg(all( - any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib" - ), - feature = "deflate-zopfli" - ))] - Ok(Box::new(move |bare| { + #[cfg(feature = "deflate-zopfli")] + { let best_non_zopfli = Compression::best().level(); if level > best_non_zopfli { let options = Options { @@ -1248,7 +1210,7 @@ impl GenericZipWriter { .unwrap(), ..Default::default() }; - match zopfli_buffer_size { + return Ok(Box::new(move |bare| match zopfli_buffer_size { Some(size) => GenericZipWriter::BufferedZopfliDeflater( BufWriter::with_capacity( size, @@ -1262,14 +1224,25 @@ impl GenericZipWriter { None => GenericZipWriter::ZopfliDeflater( zopfli::DeflateEncoder::new(options, Default::default(), bare), ), - } - } else { + })); + } + } + + #[cfg(any( + feature = "deflate", + feature = "deflate-miniz", + feature = "deflate-zlib", + feature = "deflate-zlib-ng", + ))] + { + return Ok(Box::new(move |bare| { GenericZipWriter::Deflater(DeflateEncoder::new( bare, Compression::new(level), )) - } - })) + })); + } + unreachable!() } #[cfg(feature = "bzip2")] CompressionMethod::Bzip2 => { @@ -1316,7 +1289,8 @@ impl GenericZipWriter { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] GenericZipWriter::Deflater(w) => w.finish()?, #[cfg(feature = "deflate-zopfli")] @@ -1345,7 +1319,8 @@ impl GenericZipWriter { #[cfg(any( feature = "deflate", feature = "deflate-miniz", - feature = "deflate-zlib" + feature = "deflate-zlib", + feature = "deflate-zlib-ng" ))] GenericZipWriter::Deflater(ref mut w) => Some(w as &mut dyn Write), #[cfg(feature = "deflate-zopfli")] @@ -1383,28 +1358,26 @@ impl GenericZipWriter { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli" ))] fn deflate_compression_level_range() -> std::ops::RangeInclusive { - #[cfg(any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib", - ))] - let min = Compression::none().level() as i32; + let min = if cfg!(feature = "deflate") + || cfg!(feature = "deflate-miniz") + || cfg!(feature = "deflate-zlib") + || cfg!(feature = "deflate-zlib-ng") + { + Compression::none().level() as i32 + } else { + Compression::best().level() as i32 + 1 + }; - #[cfg(not(any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib", - )))] - let min = flate2::Compression::best().level() + 1 as i32; - - #[cfg(not(feature = "deflate-zopfli"))] - let max = flate2::Compression::best().level() as i32; - - #[cfg(feature = "deflate-zopfli")] - let max = Compression::best().level() as i32 + u8::MAX as i32; + let max = Compression::best().level() as i32 + + if cfg!(feature = "deflate-zopfli") { + u8::MAX as i32 + } else { + 0 + }; min..=max } @@ -1420,6 +1393,7 @@ fn bzip2_compression_level_range() -> std::ops::RangeInclusive { feature = "deflate", feature = "deflate-miniz", feature = "deflate-zlib", + feature = "deflate-zlib-ng", feature = "deflate-zopfli", feature = "bzip2", feature = "zstd"