feat: support deflate64 compression with deflate64 crate

This commit is contained in:
anatawa12 2023-08-04 21:50:42 +09:00
parent 21a20584bc
commit 065058d30d
No known key found for this signature in database
GPG key ID: 9CA909848B8E4EA6
7 changed files with 99 additions and 0 deletions

View file

@ -23,6 +23,7 @@ pbkdf2 = {version = "0.11.0", optional = true }
sha1 = {version = "0.10.1", optional = true }
time = { version = "0.3.7", optional = true, default-features = false, features = ["std"] }
zstd = { version = "0.11.2", optional = true }
deflate64 = { version = "0.1.3", optional = true }
[target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies]
crossbeam-utils = "0.8.8"

View file

@ -17,6 +17,7 @@ Supported compression formats:
* stored (i.e. none)
* deflate
* deflate64 (decompression only)
* bzip2
* zstd
@ -46,6 +47,7 @@ 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.
* `deflate64`: Enables the deflate64 compression algorithm. Decompression is only supported.
* `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.

View file

@ -22,6 +22,10 @@ pub enum CompressionMethod {
feature = "deflate-zlib"
))]
Deflated,
/// Compress the file using Deflate64.
/// Decoding deflate64 is supported but encoding deflate64 is not supported.
#[cfg(feature = "deflate64")]
Deflate64,
/// Compress the file using BZIP2
#[cfg(feature = "bzip2")]
Bzip2,
@ -60,6 +64,9 @@ impl CompressionMethod {
feature = "deflate-zlib"
)))]
pub const DEFLATE: Self = CompressionMethod::Unsupported(8);
#[cfg(feature = "deflate64")]
pub const DEFLATE64: Self = CompressionMethod::Deflate64;
#[cfg(not(feature = "deflate64"))]
pub const DEFLATE64: Self = CompressionMethod::Unsupported(9);
pub const PKWARE_IMPLODE: Self = CompressionMethod::Unsupported(10);
#[cfg(feature = "bzip2")]
@ -100,6 +107,8 @@ impl CompressionMethod {
feature = "deflate-zlib"
))]
8 => CompressionMethod::Deflated,
#[cfg(feature = "deflate64")]
9 => CompressionMethod::Deflate64,
#[cfg(feature = "bzip2")]
12 => CompressionMethod::Bzip2,
#[cfg(feature = "zstd")]
@ -126,6 +135,8 @@ impl CompressionMethod {
feature = "deflate-zlib"
))]
CompressionMethod::Deflated => 8,
#[cfg(feature = "deflate64")]
CompressionMethod::Deflate64 => 9,
#[cfg(feature = "bzip2")]
CompressionMethod::Bzip2 => 12,
#[cfg(feature = "aes-crypto")]
@ -154,6 +165,8 @@ pub const SUPPORTED_COMPRESSION_METHODS: &[CompressionMethod] = &[
feature = "deflate-zlib"
))]
CompressionMethod::Deflated,
#[cfg(feature = "deflate64")]
CompressionMethod::Deflate64,
#[cfg(feature = "bzip2")]
CompressionMethod::Bzip2,
#[cfg(feature = "zstd")]

61
src/deflate64.rs Normal file
View file

@ -0,0 +1,61 @@
// TODO: move this module to deflate64 crate
use deflate64::InflaterManaged;
use std::io;
use std::io::{BufRead, BufReader, Read};
const IN_BUFFER_MAX_SIZE: usize = 8192;
pub(crate) struct BufferedDeflate64Decoder<R> {
inner: R,
inflator: Box<InflaterManaged>,
}
impl<R: Read> BufferedDeflate64Decoder<BufReader<R>> {
pub(crate) fn new(inner: R) -> Self {
Self {
inner: BufReader::new(inner),
inflator: Box::new(InflaterManaged::new()),
}
}
}
impl<R> BufferedDeflate64Decoder<R> {
pub(crate) fn into_inner(self) -> R {
self.inner
}
}
struct State {
inflater: InflaterManaged,
in_buffer_size: u16,
in_buffer: [u8; IN_BUFFER_MAX_SIZE],
}
impl<R: BufRead> Read for BufferedDeflate64Decoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
loop {
let input = self.inner.fill_buf()?;
let eof = input.is_empty();
let result = self.inflator.inflate(input, buf);
self.inner.consume(result.bytes_consumed);
if result.data_error {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"invalid deflate64",
));
}
if result.bytes_written == 0 && !eof && !self.inflator.finished() {
// if we haven't ready any data and we haven't hit EOF yet,
// ask again. We must not return 0 in such case
continue;
}
Ok(result.bytes_written)
}
}
}

View file

@ -36,6 +36,8 @@ mod aes_ctr;
mod compression;
mod cp437;
mod crc32;
#[cfg(feature = "deflate64")]
mod deflate64;
pub mod read;
pub mod result;
mod spec;

View file

@ -23,6 +23,9 @@ use std::sync::Arc;
))]
use flate2::read::DeflateDecoder;
#[cfg(feature = "deflate64")]
use crate::deflate64::BufferedDeflate64Decoder;
#[cfg(feature = "bzip2")]
use bzip2::read::BzDecoder;
@ -129,6 +132,8 @@ enum ZipFileReader<'a> {
feature = "deflate-zlib"
))]
Deflated(Crc32Reader<flate2::read::DeflateDecoder<CryptoReader<'a>>>),
#[cfg(feature = "deflate64")]
Deflate64(Crc32Reader<BufferedDeflate64Decoder<io::BufReader<CryptoReader<'a>>>>),
#[cfg(feature = "bzip2")]
Bzip2(Crc32Reader<BzDecoder<CryptoReader<'a>>>),
#[cfg(feature = "zstd")]
@ -147,6 +152,8 @@ impl<'a> Read for ZipFileReader<'a> {
feature = "deflate-zlib"
))]
ZipFileReader::Deflated(r) => r.read(buf),
#[cfg(feature = "deflate64")]
ZipFileReader::Deflate64(r) => r.read(buf),
#[cfg(feature = "bzip2")]
ZipFileReader::Bzip2(r) => r.read(buf),
#[cfg(feature = "zstd")]
@ -168,6 +175,8 @@ impl<'a> ZipFileReader<'a> {
feature = "deflate-zlib"
))]
ZipFileReader::Deflated(r) => r.into_inner().into_inner().into_inner(),
#[cfg(feature = "deflate64")]
ZipFileReader::Deflate64(r) => r.into_inner().into_inner().into_inner().into_inner(),
#[cfg(feature = "bzip2")]
ZipFileReader::Bzip2(r) => r.into_inner().into_inner().into_inner(),
#[cfg(feature = "zstd")]
@ -277,6 +286,11 @@ fn make_reader(
let deflate_reader = DeflateDecoder::new(reader);
ZipFileReader::Deflated(Crc32Reader::new(deflate_reader, crc32, ae2_encrypted))
}
#[cfg(feature = "deflate64")]
CompressionMethod::Deflate64 => {
let deflate64_reader = BufferedDeflate64Decoder::new(reader);
ZipFileReader::Deflate64(Crc32Reader::new(deflate64_reader, crc32, ae2_encrypted))
}
#[cfg(feature = "bzip2")]
CompressionMethod::Bzip2 => {
let bzip2_reader = BzDecoder::new(reader);

View file

@ -958,6 +958,12 @@ impl<W: Write + io::Seek> GenericZipWriter<W> {
))? as u32,
),
)),
#[cfg(feature = "deflate64")]
CompressionMethod::Deflate64 => {
return Err(ZipError::UnsupportedArchive(
"Compressing Deflate64 is not supported",
));
}
#[cfg(feature = "bzip2")]
CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzEncoder::new(
bare,