diff --git a/.vscode/settings.json b/.vscode/settings.json index a647584..3248b76 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.cargo.features": ["default", "lzma", "deflate64", "bzip2"] + "rust-analyzer.cargo.features": ["default", "lzma", "deflate64", "bzip2", "zstd"] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e18c672..e1d4035 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -367,6 +368,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.67" @@ -652,6 +662,7 @@ dependencies = [ "tracing-subscriber", "tracing-test", "winnow", + "zstd", ] [[package]] @@ -1098,3 +1109,31 @@ checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" dependencies = [ "memchr", ] + +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index ae6b417..64d6860 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ cfg-if = "1.0.0" lzma-rs = { version = "0.3.0", features = ["stream"], optional = true } deflate64 = { version = "0.1.7", optional = true } bzip2 = { version = "0.4.4", optional = true } +zstd = { version = "0.13.0", optional = true } [features] default = ["sync", "file", "deflate"] @@ -47,6 +48,7 @@ deflate = ["dep:flate2"] deflate64 = ["dep:deflate64"] lzma = ["dep:lzma-rs"] bzip2 = ["dep:bzip2"] +zstd = ["dep:zstd"] [dev-dependencies] clap = { version = "4.4.18", features = ["derive"] } diff --git a/src/reader/sync/entry_reader/mod.rs b/src/reader/sync/entry_reader/mod.rs index a12495d..e8bd373 100644 --- a/src/reader/sync/entry_reader/mod.rs +++ b/src/reader/sync/entry_reader/mod.rs @@ -19,6 +19,9 @@ mod deflate64_dec; #[cfg(feature = "bzip2")] mod bzip2_dec; +#[cfg(feature = "zstd")] +mod zstd_dec; + use cfg_if::cfg_if; use oval::Buffer; use std::io; @@ -309,6 +312,15 @@ where } } } + Method::Zstd => { + cfg_if! { + if #[cfg(feature = "zstd")] { + Box::new(zstd_dec::mk_decoder(limited_reader)?) + } else { + return Err(Error::method_not_enabled(self.method)); + } + } + } method => { return Err(Error::method_not_supported(method)); } diff --git a/src/reader/sync/entry_reader/zstd_dec.rs b/src/reader/sync/entry_reader/zstd_dec.rs new file mode 100644 index 0000000..4fce919 --- /dev/null +++ b/src/reader/sync/entry_reader/zstd_dec.rs @@ -0,0 +1,23 @@ +use std::io::{BufReader, Read}; + +use zstd::stream::Decoder as ZstdDecoder; + +use crate::reader::sync::{Decoder, LimitedReader}; + +impl Decoder for ZstdDecoder<'static, BufReader> +where + R: Read, +{ + fn into_inner(self: Box) -> R { + Self::finish(*self).into_inner() + } + + fn get_mut(&mut self) -> &mut R { + Self::get_mut(self).get_mut() + } +} + +pub(crate) fn mk_decoder(r: LimitedReader) -> std::io::Result> { + // TODO: have LimitedReader (and Buffer) implement BufRead, cf. https://github.com/fasterthanlime/rc-zip/issues/55 + ZstdDecoder::with_buffer(BufReader::new(r)) +} diff --git a/tests/data/found-me-zstd.zip b/tests/data/found-me-zstd.zip new file mode 100644 index 0000000..659da75 Binary files /dev/null and b/tests/data/found-me-zstd.zip differ diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 5cde2a8..a8657ab 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -308,6 +308,19 @@ fn test_cases() -> Vec { }], ..Default::default() }, + // same with zstd + #[cfg(feature = "zstd")] + ZipTest { + source: ZipSource::File("found-me-zstd.zip"), + expected_encoding: Some(Encoding::Utf8), + files: vec![ZipTestFile { + name: "found-me.txt", + content: FileContent::Bytes("Oh no, you found me\n".repeat(5000).into()), + modified: Some(date((2024, 1, 31), (6, 10, 25), 800491400, time_zone(0)).unwrap()), + ..Default::default() + }], + ..Default::default() + }, ] }