Merge pull request #210 from a1phyr/multiple_refactors
Multiple refactors
This commit is contained in:
commit
a60bd79826
5 changed files with 154 additions and 266 deletions
|
@ -1,6 +1,6 @@
|
||||||
//! Possible ZIP compression methods.
|
//! Possible ZIP compression methods.
|
||||||
|
|
||||||
use std::fmt;
|
use std::{fmt, io};
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
/// Identifies the storage format used to compress a file within a ZIP archive.
|
/// Identifies the storage format used to compress a file within a ZIP archive.
|
||||||
|
@ -189,6 +189,92 @@ pub const SUPPORTED_COMPRESSION_METHODS: &[CompressionMethod] = &[
|
||||||
CompressionMethod::Zstd,
|
CompressionMethod::Zstd,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub(crate) enum Decompressor<R: io::BufRead> {
|
||||||
|
Stored(R),
|
||||||
|
#[cfg(feature = "_deflate-any")]
|
||||||
|
Deflated(flate2::bufread::DeflateDecoder<R>),
|
||||||
|
#[cfg(feature = "deflate64")]
|
||||||
|
Deflate64(deflate64::Deflate64Decoder<R>),
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
Bzip2(bzip2::bufread::BzDecoder<R>),
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
Zstd(zstd::Decoder<'static, R>),
|
||||||
|
#[cfg(feature = "lzma")]
|
||||||
|
Lzma(Box<crate::read::lzma::LzmaDecoder<R>>),
|
||||||
|
#[cfg(feature = "xz")]
|
||||||
|
Xz(crate::read::xz::XzDecoder<R>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: io::BufRead> io::Read for Decompressor<R> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
match self {
|
||||||
|
Decompressor::Stored(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "_deflate-any")]
|
||||||
|
Decompressor::Deflated(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "deflate64")]
|
||||||
|
Decompressor::Deflate64(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
Decompressor::Bzip2(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
Decompressor::Zstd(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "lzma")]
|
||||||
|
Decompressor::Lzma(r) => r.read(buf),
|
||||||
|
#[cfg(feature = "xz")]
|
||||||
|
Decompressor::Xz(r) => r.read(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: io::BufRead> Decompressor<R> {
|
||||||
|
pub fn new(reader: R, compression_method: CompressionMethod) -> crate::result::ZipResult<Self> {
|
||||||
|
Ok(match compression_method {
|
||||||
|
CompressionMethod::Stored => Decompressor::Stored(reader),
|
||||||
|
#[cfg(feature = "_deflate-any")]
|
||||||
|
CompressionMethod::Deflated => {
|
||||||
|
Decompressor::Deflated(flate2::bufread::DeflateDecoder::new(reader))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "deflate64")]
|
||||||
|
CompressionMethod::Deflate64 => {
|
||||||
|
Decompressor::Deflate64(deflate64::Deflate64Decoder::with_buffer(reader))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
CompressionMethod::Bzip2 => Decompressor::Bzip2(bzip2::bufread::BzDecoder::new(reader)),
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
CompressionMethod::Zstd => Decompressor::Zstd(zstd::Decoder::with_buffer(reader)?),
|
||||||
|
#[cfg(feature = "lzma")]
|
||||||
|
CompressionMethod::Lzma => {
|
||||||
|
Decompressor::Lzma(Box::new(crate::read::lzma::LzmaDecoder::new(reader)))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "xz")]
|
||||||
|
CompressionMethod::Xz => Decompressor::Xz(crate::read::xz::XzDecoder::new(reader)),
|
||||||
|
_ => {
|
||||||
|
return Err(crate::result::ZipError::UnsupportedArchive(
|
||||||
|
"Compression method not supported",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes this decoder, returning the underlying reader.
|
||||||
|
pub fn into_inner(self) -> R {
|
||||||
|
match self {
|
||||||
|
Decompressor::Stored(r) => r,
|
||||||
|
#[cfg(feature = "_deflate-any")]
|
||||||
|
Decompressor::Deflated(r) => r.into_inner(),
|
||||||
|
#[cfg(feature = "deflate64")]
|
||||||
|
Decompressor::Deflate64(r) => r.into_inner(),
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
Decompressor::Bzip2(r) => r.into_inner(),
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
Decompressor::Zstd(r) => r.finish(),
|
||||||
|
#[cfg(feature = "lzma")]
|
||||||
|
Decompressor::Lzma(r) => r.into_inner(),
|
||||||
|
#[cfg(feature = "xz")]
|
||||||
|
Decompressor::Xz(r) => r.into_inner(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS};
|
use super::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS};
|
||||||
|
|
293
src/read.rs
293
src/read.rs
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#[cfg(feature = "aes-crypto")]
|
#[cfg(feature = "aes-crypto")]
|
||||||
use crate::aes::{AesReader, AesReaderValid};
|
use crate::aes::{AesReader, AesReaderValid};
|
||||||
use crate::compression::CompressionMethod;
|
use crate::compression::{CompressionMethod, Decompressor};
|
||||||
use crate::cp437::FromCp437;
|
use crate::cp437::FromCp437;
|
||||||
use crate::crc32::Crc32Reader;
|
use crate::crc32::Crc32Reader;
|
||||||
use crate::extra_fields::{ExtendedTimestamp, ExtraField};
|
use crate::extra_fields::{ExtendedTimestamp, ExtraField};
|
||||||
|
@ -26,18 +26,6 @@ use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
#[cfg(feature = "deflate-flate2")]
|
|
||||||
use flate2::read::DeflateDecoder;
|
|
||||||
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
use deflate64::Deflate64Decoder;
|
|
||||||
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
use bzip2::read::BzDecoder;
|
|
||||||
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
use zstd::stream::read::Decoder as ZstdDecoder;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
|
@ -124,11 +112,7 @@ pub(crate) mod zip_archive {
|
||||||
#[cfg(feature = "aes-crypto")]
|
#[cfg(feature = "aes-crypto")]
|
||||||
use crate::aes::PWD_VERIFY_LENGTH;
|
use crate::aes::PWD_VERIFY_LENGTH;
|
||||||
use crate::extra_fields::UnicodeExtraField;
|
use crate::extra_fields::UnicodeExtraField;
|
||||||
#[cfg(feature = "lzma")]
|
use crate::result::ZipError::{InvalidArchive, InvalidPassword};
|
||||||
use crate::read::lzma::LzmaDecoder;
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
use crate::read::xz::XzDecoder;
|
|
||||||
use crate::result::ZipError::{InvalidArchive, InvalidPassword, UnsupportedArchive};
|
|
||||||
use crate::spec::is_dir;
|
use crate::spec::is_dir;
|
||||||
use crate::types::ffi::S_IFLNK;
|
use crate::types::ffi::S_IFLNK;
|
||||||
use crate::unstable::{path_to_string, LittleEndianReadExt};
|
use crate::unstable::{path_to_string, LittleEndianReadExt};
|
||||||
|
@ -200,141 +184,69 @@ impl<'a> CryptoReader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
fn invalid_state<T>() -> io::Result<T> {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"ZipFileReader was in an invalid state",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) enum ZipFileReader<'a> {
|
pub(crate) enum ZipFileReader<'a> {
|
||||||
NoReader,
|
NoReader,
|
||||||
Raw(io::Take<&'a mut dyn Read>),
|
Raw(io::Take<&'a mut dyn Read>),
|
||||||
Stored(Crc32Reader<CryptoReader<'a>>),
|
Compressed(Box<Crc32Reader<Decompressor<io::BufReader<CryptoReader<'a>>>>>),
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
Deflated(Crc32Reader<DeflateDecoder<CryptoReader<'a>>>),
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
Deflate64(Crc32Reader<Deflate64Decoder<io::BufReader<CryptoReader<'a>>>>),
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
Bzip2(Crc32Reader<BzDecoder<CryptoReader<'a>>>),
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
Zstd(Crc32Reader<ZstdDecoder<'a, io::BufReader<CryptoReader<'a>>>>),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
Lzma(Crc32Reader<Box<LzmaDecoder<CryptoReader<'a>>>>),
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
Xz(Crc32Reader<XzDecoder<CryptoReader<'a>>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Read for ZipFileReader<'a> {
|
impl<'a> Read for ZipFileReader<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::NoReader => invalid_state(),
|
||||||
ZipFileReader::Raw(r) => r.read(buf),
|
ZipFileReader::Raw(r) => r.read(buf),
|
||||||
ZipFileReader::Stored(r) => r.read(buf),
|
ZipFileReader::Compressed(r) => r.read(buf),
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
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")]
|
|
||||||
ZipFileReader::Zstd(r) => r.read(buf),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
ZipFileReader::Lzma(r) => r.read(buf),
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
ZipFileReader::Xz(r) => r.read(buf),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::NoReader => invalid_state(),
|
||||||
ZipFileReader::Raw(r) => r.read_exact(buf),
|
ZipFileReader::Raw(r) => r.read_exact(buf),
|
||||||
ZipFileReader::Stored(r) => r.read_exact(buf),
|
ZipFileReader::Compressed(r) => r.read_exact(buf),
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
ZipFileReader::Deflated(r) => r.read_exact(buf),
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
ZipFileReader::Deflate64(r) => r.read_exact(buf),
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
ZipFileReader::Bzip2(r) => r.read_exact(buf),
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
ZipFileReader::Zstd(r) => r.read_exact(buf),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
ZipFileReader::Lzma(r) => r.read_exact(buf),
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
ZipFileReader::Xz(r) => r.read_exact(buf),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::NoReader => invalid_state(),
|
||||||
ZipFileReader::Raw(r) => r.read_to_end(buf),
|
ZipFileReader::Raw(r) => r.read_to_end(buf),
|
||||||
ZipFileReader::Stored(r) => r.read_to_end(buf),
|
ZipFileReader::Compressed(r) => r.read_to_end(buf),
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
ZipFileReader::Deflated(r) => r.read_to_end(buf),
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
ZipFileReader::Deflate64(r) => r.read_to_end(buf),
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
ZipFileReader::Bzip2(r) => r.read_to_end(buf),
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
ZipFileReader::Zstd(r) => r.read_to_end(buf),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
ZipFileReader::Lzma(r) => r.read_to_end(buf),
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
ZipFileReader::Xz(r) => r.read_to_end(buf),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::NoReader => invalid_state(),
|
||||||
ZipFileReader::Raw(r) => r.read_to_string(buf),
|
ZipFileReader::Raw(r) => r.read_to_string(buf),
|
||||||
ZipFileReader::Stored(r) => r.read_to_string(buf),
|
ZipFileReader::Compressed(r) => r.read_to_string(buf),
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
ZipFileReader::Deflated(r) => r.read_to_string(buf),
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
ZipFileReader::Deflate64(r) => r.read_to_string(buf),
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
ZipFileReader::Bzip2(r) => r.read_to_string(buf),
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
ZipFileReader::Zstd(r) => r.read_to_string(buf),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
ZipFileReader::Lzma(r) => r.read_to_string(buf),
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
ZipFileReader::Xz(r) => r.read_to_string(buf),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ZipFileReader<'a> {
|
impl<'a> ZipFileReader<'a> {
|
||||||
/// Consumes this decoder, returning the underlying reader.
|
fn into_inner(self) -> io::Result<io::Take<&'a mut dyn Read>> {
|
||||||
pub fn drain(self) {
|
match self {
|
||||||
let mut inner = match self {
|
ZipFileReader::NoReader => invalid_state(),
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::Raw(r) => Ok(r),
|
||||||
ZipFileReader::Raw(r) => r,
|
ZipFileReader::Compressed(r) => {
|
||||||
ZipFileReader::Stored(r) => r.into_inner().into_inner(),
|
Ok(r.into_inner().into_inner().into_inner().into_inner())
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
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")]
|
|
||||||
ZipFileReader::Zstd(r) => r.into_inner().finish().into_inner().into_inner(),
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
ZipFileReader::Lzma(r) => {
|
|
||||||
// Lzma reader owns its buffer rather than mutably borrowing it, so we have to drop
|
|
||||||
// it separately
|
|
||||||
if let Ok(mut remaining) = r.into_inner().finish() {
|
|
||||||
let _ = copy(&mut remaining, &mut sink());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "xz")]
|
}
|
||||||
ZipFileReader::Xz(r) => r.into_inner().into_inner().into_inner(),
|
|
||||||
};
|
|
||||||
let _ = copy(&mut inner, &mut sink());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct for reading a zip file
|
/// A struct for reading a zip file
|
||||||
pub struct ZipFile<'a> {
|
pub struct ZipFile<'a> {
|
||||||
pub(crate) data: Cow<'a, ZipFileData>,
|
pub(crate) data: Cow<'a, ZipFileData>,
|
||||||
pub(crate) crypto_reader: Option<CryptoReader<'a>>,
|
|
||||||
pub(crate) reader: ZipFileReader<'a>,
|
pub(crate) reader: ZipFileReader<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,18 +371,14 @@ fn find_data_start(
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn make_crypto_reader<'a>(
|
pub(crate) fn make_crypto_reader<'a>(
|
||||||
compression_method: CompressionMethod,
|
data: &ZipFileData,
|
||||||
crc32: u32,
|
|
||||||
mut last_modified_time: Option<DateTime>,
|
|
||||||
using_data_descriptor: bool,
|
|
||||||
reader: io::Take<&'a mut dyn Read>,
|
reader: io::Take<&'a mut dyn Read>,
|
||||||
password: Option<&[u8]>,
|
password: Option<&[u8]>,
|
||||||
aes_info: Option<(AesMode, AesVendorVersion, CompressionMethod)>,
|
aes_info: Option<(AesMode, AesVendorVersion, CompressionMethod)>,
|
||||||
#[cfg(feature = "aes-crypto")] compressed_size: u64,
|
|
||||||
) -> ZipResult<CryptoReader<'a>> {
|
) -> ZipResult<CryptoReader<'a>> {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
{
|
{
|
||||||
if let CompressionMethod::Unsupported(_) = compression_method {
|
if let CompressionMethod::Unsupported(_) = data.compression_method {
|
||||||
return unsupported_zip_error("Compression method not supported");
|
return unsupported_zip_error("Compression method not supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,17 +392,18 @@ pub(crate) fn make_crypto_reader<'a>(
|
||||||
}
|
}
|
||||||
#[cfg(feature = "aes-crypto")]
|
#[cfg(feature = "aes-crypto")]
|
||||||
(Some(password), Some((aes_mode, vendor_version, _))) => CryptoReader::Aes {
|
(Some(password), Some((aes_mode, vendor_version, _))) => CryptoReader::Aes {
|
||||||
reader: AesReader::new(reader, aes_mode, compressed_size).validate(password)?,
|
reader: AesReader::new(reader, aes_mode, data.compressed_size).validate(password)?,
|
||||||
vendor_version,
|
vendor_version,
|
||||||
},
|
},
|
||||||
(Some(password), None) => {
|
(Some(password), None) => {
|
||||||
if !using_data_descriptor {
|
let mut last_modified_time = data.last_modified_time;
|
||||||
|
if !data.using_data_descriptor {
|
||||||
last_modified_time = None;
|
last_modified_time = None;
|
||||||
}
|
}
|
||||||
let validator = if let Some(last_modified_time) = last_modified_time {
|
let validator = if let Some(last_modified_time) = last_modified_time {
|
||||||
ZipCryptoValidator::InfoZipMsdosTime(last_modified_time.timepart())
|
ZipCryptoValidator::InfoZipMsdosTime(last_modified_time.timepart())
|
||||||
} else {
|
} else {
|
||||||
ZipCryptoValidator::PkzipCrc32(crc32)
|
ZipCryptoValidator::PkzipCrc32(data.crc32)
|
||||||
};
|
};
|
||||||
CryptoReader::ZipCrypto(ZipCryptoReader::new(reader, password).validate(validator)?)
|
CryptoReader::ZipCrypto(ZipCryptoReader::new(reader, password).validate(validator)?)
|
||||||
}
|
}
|
||||||
|
@ -511,68 +420,11 @@ pub(crate) fn make_reader(
|
||||||
) -> ZipResult<ZipFileReader> {
|
) -> ZipResult<ZipFileReader> {
|
||||||
let ae2_encrypted = reader.is_ae2_encrypted();
|
let ae2_encrypted = reader.is_ae2_encrypted();
|
||||||
|
|
||||||
match compression_method {
|
Ok(ZipFileReader::Compressed(Box::new(Crc32Reader::new(
|
||||||
CompressionMethod::Stored => Ok(ZipFileReader::Stored(Crc32Reader::new(
|
Decompressor::new(io::BufReader::new(reader), compression_method)?,
|
||||||
reader,
|
crc32,
|
||||||
crc32,
|
ae2_encrypted,
|
||||||
ae2_encrypted,
|
))))
|
||||||
))),
|
|
||||||
#[cfg(feature = "_deflate-any")]
|
|
||||||
CompressionMethod::Deflated => {
|
|
||||||
let deflate_reader = DeflateDecoder::new(reader);
|
|
||||||
Ok(ZipFileReader::Deflated(Crc32Reader::new(
|
|
||||||
deflate_reader,
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "deflate64")]
|
|
||||||
CompressionMethod::Deflate64 => {
|
|
||||||
let deflate64_reader = Deflate64Decoder::new(reader);
|
|
||||||
Ok(ZipFileReader::Deflate64(Crc32Reader::new(
|
|
||||||
deflate64_reader,
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
CompressionMethod::Bzip2 => {
|
|
||||||
let bzip2_reader = BzDecoder::new(reader);
|
|
||||||
Ok(ZipFileReader::Bzip2(Crc32Reader::new(
|
|
||||||
bzip2_reader,
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
CompressionMethod::Zstd => {
|
|
||||||
let zstd_reader = ZstdDecoder::new(reader).unwrap();
|
|
||||||
Ok(ZipFileReader::Zstd(Crc32Reader::new(
|
|
||||||
zstd_reader,
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "lzma")]
|
|
||||||
CompressionMethod::Lzma => {
|
|
||||||
let reader = LzmaDecoder::new(reader);
|
|
||||||
Ok(ZipFileReader::Lzma(Crc32Reader::new(
|
|
||||||
Box::new(reader),
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "xz")]
|
|
||||||
CompressionMethod::Xz => {
|
|
||||||
let reader = XzDecoder::new(reader);
|
|
||||||
Ok(ZipFileReader::Xz(Crc32Reader::new(
|
|
||||||
reader,
|
|
||||||
crc32,
|
|
||||||
ae2_encrypted,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
_ => Err(UnsupportedArchive("Compression method not supported")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1313,7 +1165,6 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
.get_index(file_number)
|
.get_index(file_number)
|
||||||
.ok_or(ZipError::FileNotFound)?;
|
.ok_or(ZipError::FileNotFound)?;
|
||||||
Ok(ZipFile {
|
Ok(ZipFile {
|
||||||
crypto_reader: None,
|
|
||||||
reader: ZipFileReader::Raw(find_content(data, reader)?),
|
reader: ZipFileReader::Raw(find_content(data, reader)?),
|
||||||
data: Cow::Borrowed(data),
|
data: Cow::Borrowed(data),
|
||||||
})
|
})
|
||||||
|
@ -1337,21 +1188,11 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
}
|
}
|
||||||
let limit_reader = find_content(data, &mut self.reader)?;
|
let limit_reader = find_content(data, &mut self.reader)?;
|
||||||
|
|
||||||
let crypto_reader = make_crypto_reader(
|
let crypto_reader = make_crypto_reader(data, limit_reader, password, data.aes_mode)?;
|
||||||
data.compression_method,
|
|
||||||
data.crc32,
|
|
||||||
data.last_modified_time,
|
|
||||||
data.using_data_descriptor,
|
|
||||||
limit_reader,
|
|
||||||
password,
|
|
||||||
data.aes_mode,
|
|
||||||
#[cfg(feature = "aes-crypto")]
|
|
||||||
data.compressed_size,
|
|
||||||
)?;
|
|
||||||
Ok(ZipFile {
|
Ok(ZipFile {
|
||||||
crypto_reader: Some(crypto_reader),
|
|
||||||
reader: ZipFileReader::NoReader,
|
|
||||||
data: Cow::Borrowed(data),
|
data: Cow::Borrowed(data),
|
||||||
|
reader: make_reader(data.compression_method, data.crc32, crypto_reader)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1646,21 +1487,8 @@ pub trait HasZipMetadata {
|
||||||
|
|
||||||
/// Methods for retrieving information on zip files
|
/// Methods for retrieving information on zip files
|
||||||
impl<'a> ZipFile<'a> {
|
impl<'a> ZipFile<'a> {
|
||||||
fn get_reader(&mut self) -> ZipResult<&mut ZipFileReader<'a>> {
|
pub(crate) fn take_raw_reader(&mut self) -> io::Result<io::Take<&'a mut dyn Read>> {
|
||||||
if let ZipFileReader::NoReader = self.reader {
|
std::mem::replace(&mut self.reader, ZipFileReader::NoReader).into_inner()
|
||||||
let data = &self.data;
|
|
||||||
let crypto_reader = self.crypto_reader.take().expect("Invalid reader state");
|
|
||||||
self.reader = make_reader(data.compression_method, data.crc32, crypto_reader)?;
|
|
||||||
}
|
|
||||||
Ok(&mut self.reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_raw_reader(&mut self) -> &mut dyn Read {
|
|
||||||
if let ZipFileReader::NoReader = self.reader {
|
|
||||||
let crypto_reader = self.crypto_reader.take().expect("Invalid reader state");
|
|
||||||
self.reader = ZipFileReader::Raw(crypto_reader.into_inner())
|
|
||||||
}
|
|
||||||
&mut self.reader
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the version of the file
|
/// Get the version of the file
|
||||||
|
@ -1829,19 +1657,19 @@ impl<'a> HasZipMetadata for ZipFile<'a> {
|
||||||
|
|
||||||
impl<'a> Read for ZipFile<'a> {
|
impl<'a> Read for ZipFile<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
self.get_reader()?.read(buf)
|
self.reader.read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||||
self.get_reader()?.read_exact(buf)
|
self.reader.read_exact(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
self.get_reader()?.read_to_end(buf)
|
self.reader.read_to_end(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||||
self.get_reader()?.read_to_string(buf)
|
self.reader.read_to_string(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1873,19 +1701,9 @@ impl<'a> Drop for ZipFile<'a> {
|
||||||
// In this case, we want to exhaust the reader so that the next file is accessible.
|
// In this case, we want to exhaust the reader so that the next file is accessible.
|
||||||
if let Cow::Owned(_) = self.data {
|
if let Cow::Owned(_) = self.data {
|
||||||
// Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped.
|
// Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped.
|
||||||
match &mut self.reader {
|
if let Ok(mut inner) = self.take_raw_reader() {
|
||||||
ZipFileReader::NoReader => {
|
let _ = copy(&mut inner, &mut sink());
|
||||||
let innerreader = self.crypto_reader.take();
|
}
|
||||||
let _ = copy(
|
|
||||||
&mut innerreader.expect("Invalid reader state").into_inner(),
|
|
||||||
&mut sink(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
reader => {
|
|
||||||
let innerreader = std::mem::replace(reader, ZipFileReader::NoReader);
|
|
||||||
innerreader.drain();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1934,21 +1752,10 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult<Opt
|
||||||
|
|
||||||
let result_crc32 = result.crc32;
|
let result_crc32 = result.crc32;
|
||||||
let result_compression_method = result.compression_method;
|
let result_compression_method = result.compression_method;
|
||||||
let crypto_reader = make_crypto_reader(
|
let crypto_reader = make_crypto_reader(&result, limit_reader, None, None)?;
|
||||||
result_compression_method,
|
|
||||||
result_crc32,
|
|
||||||
result.last_modified_time,
|
|
||||||
result.using_data_descriptor,
|
|
||||||
limit_reader,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
#[cfg(feature = "aes-crypto")]
|
|
||||||
result.compressed_size,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Some(ZipFile {
|
Ok(Some(ZipFile {
|
||||||
data: Cow::Owned(result),
|
data: Cow::Owned(result),
|
||||||
crypto_reader: None,
|
|
||||||
reader: make_reader(result_compression_method, result_crc32, crypto_reader)?,
|
reader: make_reader(result_compression_method, result_crc32, crypto_reader)?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use lzma_rs::decompress::{Options, Stream, UnpackedSize};
|
use lzma_rs::decompress::{Options, Stream, UnpackedSize};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::{copy, Error, Read, Result, Write};
|
use std::io::{BufRead, Read, Result, Write};
|
||||||
|
|
||||||
const COMPRESSED_BYTES_TO_BUFFER: usize = 4096;
|
|
||||||
|
|
||||||
const OPTIONS: Options = Options {
|
const OPTIONS: Options = Options {
|
||||||
unpacked_size: UnpackedSize::ReadFromHeader,
|
unpacked_size: UnpackedSize::ReadFromHeader,
|
||||||
|
@ -24,23 +22,20 @@ impl<R: Read> LzmaDecoder<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(mut self) -> Result<VecDeque<u8>> {
|
pub fn into_inner(self) -> R {
|
||||||
copy(&mut self.compressed_reader, &mut self.stream)?;
|
self.compressed_reader
|
||||||
self.stream.finish().map_err(Error::from)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> Read for LzmaDecoder<R> {
|
impl<R: BufRead> Read for LzmaDecoder<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
let mut bytes_read = self.stream.get_output_mut().unwrap().read(buf)?;
|
let mut bytes_read = self.stream.get_output_mut().unwrap().read(buf)?;
|
||||||
while bytes_read < buf.len() {
|
while bytes_read < buf.len() {
|
||||||
let mut next_compressed = [0u8; COMPRESSED_BYTES_TO_BUFFER];
|
let compressed_bytes = self.compressed_reader.fill_buf()?;
|
||||||
let compressed_bytes_read = self.compressed_reader.read(&mut next_compressed)?;
|
if compressed_bytes.is_empty() {
|
||||||
if compressed_bytes_read == 0 {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.stream
|
self.stream.write_all(compressed_bytes)?;
|
||||||
.write_all(&next_compressed[..compressed_bytes_read])?;
|
|
||||||
bytes_read += self
|
bytes_read += self
|
||||||
.stream
|
.stream
|
||||||
.get_output_mut()
|
.get_output_mut()
|
||||||
|
|
|
@ -2,12 +2,12 @@ use crc32fast::Hasher;
|
||||||
use lzma_rs::decompress::raw::Lzma2Decoder;
|
use lzma_rs::decompress::raw::Lzma2Decoder;
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
io::{BufRead, BufReader, Error, Read, Result, Write},
|
io::{BufRead, Error, Read, Result, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct XzDecoder<R> {
|
pub struct XzDecoder<R: BufRead> {
|
||||||
compressed_reader: BufReader<R>,
|
compressed_reader: R,
|
||||||
stream_size: usize,
|
stream_size: usize,
|
||||||
buf: VecDeque<u8>,
|
buf: VecDeque<u8>,
|
||||||
check_size: usize,
|
check_size: usize,
|
||||||
|
@ -15,10 +15,10 @@ pub struct XzDecoder<R> {
|
||||||
flags: [u8; 2],
|
flags: [u8; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> XzDecoder<R> {
|
impl<R: BufRead> XzDecoder<R> {
|
||||||
pub fn new(inner: R) -> Self {
|
pub fn new(inner: R) -> Self {
|
||||||
XzDecoder {
|
XzDecoder {
|
||||||
compressed_reader: BufReader::new(inner),
|
compressed_reader: inner,
|
||||||
stream_size: 0,
|
stream_size: 0,
|
||||||
buf: VecDeque::new(),
|
buf: VecDeque::new(),
|
||||||
check_size: 0,
|
check_size: 0,
|
||||||
|
@ -83,7 +83,7 @@ fn error<T>(s: &'static str) -> Result<T> {
|
||||||
Err(Error::new(std::io::ErrorKind::InvalidData, s))
|
Err(Error::new(std::io::ErrorKind::InvalidData, s))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_multibyte<R: Read>(input: &mut R, hasher: &mut Hasher) -> Result<u64> {
|
fn get_multibyte<R: BufRead>(input: &mut R, hasher: &mut Hasher) -> Result<u64> {
|
||||||
let mut result = 0;
|
let mut result = 0;
|
||||||
for i in 0..9 {
|
for i in 0..9 {
|
||||||
let mut b = [0u8; 1];
|
let mut b = [0u8; 1];
|
||||||
|
@ -98,7 +98,7 @@ fn get_multibyte<R: Read>(input: &mut R, hasher: &mut Hasher) -> Result<u64> {
|
||||||
error("Invalid multi-byte encoding")
|
error("Invalid multi-byte encoding")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> Read for XzDecoder<R> {
|
impl<R: BufRead> Read for XzDecoder<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
if !self.buf.is_empty() {
|
if !self.buf.is_empty() {
|
||||||
let len = std::cmp::min(buf.len(), self.buf.len());
|
let len = std::cmp::min(buf.len(), self.buf.len());
|
||||||
|
@ -263,8 +263,8 @@ impl<R: Read> Read for XzDecoder<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> XzDecoder<R> {
|
impl<R: BufRead> XzDecoder<R> {
|
||||||
pub fn into_inner(self) -> R {
|
pub fn into_inner(self) -> R {
|
||||||
self.compressed_reader.into_inner()
|
self.compressed_reader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1315,7 +1315,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
||||||
self.writing_to_file = true;
|
self.writing_to_file = true;
|
||||||
self.writing_raw = true;
|
self.writing_raw = true;
|
||||||
|
|
||||||
io::copy(file.get_raw_reader(), self)?;
|
io::copy(&mut file.take_raw_reader()?, self)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue