diff options
| author | Igor Tolmachev <me@igorek.dev> | 2024-07-05 19:52:28 +0900 |
|---|---|---|
| committer | Igor Tolmachev <me@igorek.dev> | 2024-07-05 19:52:28 +0900 |
| commit | aa0893e63ac90e939c5b119e95f1e305105cd40a (patch) | |
| tree | ba84aa87dea417ff4a63e5b15e46eadccb1d631a /src | |
| parent | 5d3d32ded672b67471d9d7c85ebbe691129cc51c (diff) | |
| download | archivator-aa0893e63ac90e939c5b119e95f1e305105cd40a.tar.gz archivator-aa0893e63ac90e939c5b119e95f1e305105cd40a.zip | |
Fix lzma decompression
Diffstat (limited to 'src')
| -rw-r--r-- | src/driver/file.rs | 2 | ||||
| -rw-r--r-- | src/zip/error.rs | 4 | ||||
| -rw-r--r-- | src/zip/file/info.rs | 8 | ||||
| -rw-r--r-- | src/zip/file/read.rs | 42 | ||||
| -rw-r--r-- | src/zip/file/write.rs | 4 |
5 files changed, 42 insertions, 18 deletions
diff --git a/src/driver/file.rs b/src/driver/file.rs index 125c9c3..5c6ea43 100644 --- a/src/driver/file.rs +++ b/src/driver/file.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | pub trait ArchiveFileInfo {} | 1 | pub trait ArchiveFileInfo: Clone {} |
| 2 | 2 | ||
| 3 | pub trait FileDriver { | 3 | pub trait FileDriver { |
| 4 | type Io; | 4 | type Io; |
diff --git a/src/zip/error.rs b/src/zip/error.rs index 5659f93..963daad 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -21,7 +21,7 @@ pub enum ZipError { | |||
| 21 | 21 | ||
| 22 | NegativeFileOffset, | 22 | NegativeFileOffset, |
| 23 | FileNotFound, | 23 | FileNotFound, |
| 24 | CompressionDataIsUnseekable, | 24 | CompressedDataIsUnseekable, |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | impl From<ZipError> for ArchiveError<ZipError> { | 27 | impl From<ZipError> for ArchiveError<ZipError> { |
| @@ -60,7 +60,7 @@ impl Display for ZipError { | |||
| 60 | 60 | ||
| 61 | Self::NegativeFileOffset => write!(f, "Negative file offset"), | 61 | Self::NegativeFileOffset => write!(f, "Negative file offset"), |
| 62 | Self::FileNotFound => write!(f, "File not found"), | 62 | Self::FileNotFound => write!(f, "File not found"), |
| 63 | Self::CompressionDataIsUnseekable => write!(f, "Compression data is unseekable"), | 63 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), |
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs index 2891b59..ff6e8d2 100644 --- a/src/zip/file/info.rs +++ b/src/zip/file/info.rs | |||
| @@ -7,8 +7,8 @@ pub enum CompressionMethod { | |||
| 7 | Store, | 7 | Store, |
| 8 | Deflate, | 8 | Deflate, |
| 9 | BZip2, | 9 | BZip2, |
| 10 | LZMA, | 10 | Lzma, |
| 11 | XZ, | 11 | Xz, |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | impl CompressionMethod { | 14 | impl CompressionMethod { |
| @@ -17,8 +17,8 @@ impl CompressionMethod { | |||
| 17 | 0 => Ok(Self::Store), | 17 | 0 => Ok(Self::Store), |
| 18 | 8 => Ok(Self::Deflate), | 18 | 8 => Ok(Self::Deflate), |
| 19 | 12 => Ok(Self::BZip2), | 19 | 12 => Ok(Self::BZip2), |
| 20 | 14 => Ok(Self::LZMA), | 20 | 14 => Ok(Self::Lzma), |
| 21 | 95 => Ok(Self::XZ), | 21 | 95 => Ok(Self::Xz), |
| 22 | 1..=7 | 9..=11 | 13 | 15..=20 | 93..=94 | 96..=99 => { | 22 | 1..=7 | 9..=11 | 13 | 15..=20 | 93..=94 | 96..=99 => { |
| 23 | Err(ZipError::UnsupportedCompressionMethod.into()) | 23 | Err(ZipError::UnsupportedCompressionMethod.into()) |
| 24 | } | 24 | } |
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs index 56f42da..c5c7e99 100644 --- a/src/zip/file/read.rs +++ b/src/zip/file/read.rs | |||
| @@ -2,16 +2,17 @@ use crate::driver::FileDriver; | |||
| 2 | use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult}; | 2 | use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult}; |
| 3 | use bzip2::read::BzDecoder; | 3 | use bzip2::read::BzDecoder; |
| 4 | use flate2::read::DeflateDecoder; | 4 | use flate2::read::DeflateDecoder; |
| 5 | use liblzma::read::XzDecoder; | ||
| 6 | use liblzma::stream::{Filters, LzmaOptions, Stream}; | ||
| 5 | use std::io::{ | 7 | use std::io::{ |
| 6 | Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, | 8 | Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, |
| 7 | }; | 9 | }; |
| 8 | use xz2::read::XzDecoder; | ||
| 9 | 10 | ||
| 10 | enum IoProxy<Io: Read> { | 11 | enum IoProxy<Io: Read> { |
| 11 | Store(Io), | 12 | Store(Io), |
| 12 | Deflate(DeflateDecoder<Io>), | 13 | Deflate(DeflateDecoder<Io>), |
| 13 | BZip2(BzDecoder<Io>), | 14 | BZip2(BzDecoder<Io>), |
| 14 | XZ(XzDecoder<Io>), | 15 | Xz(XzDecoder<Io>), |
| 15 | } | 16 | } |
| 16 | 17 | ||
| 17 | pub struct ZipFileReader<'d, Io: Read> { | 18 | pub struct ZipFileReader<'d, Io: Read> { |
| @@ -39,6 +40,7 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 39 | io.read(&mut buf)?; | 40 | io.read(&mut buf)?; |
| 40 | buf | 41 | buf |
| 41 | }; | 42 | }; |
| 43 | |||
| 42 | if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { | 44 | if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { |
| 43 | return Err(ZipError::InvalidFileHeaderSignature.into()); | 45 | return Err(ZipError::InvalidFileHeaderSignature.into()); |
| 44 | } | 46 | } |
| @@ -46,20 +48,42 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 46 | + 30 | 48 | + 30 |
| 47 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 | 49 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 |
| 48 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; | 50 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; |
| 49 | io.seek(SeekFrom::Start(data_pointer))?; | 51 | let mut cursor = io.seek(SeekFrom::Start(data_pointer))?; |
| 50 | 52 | ||
| 51 | Ok(Self { | 53 | Ok(Self { |
| 52 | io: match info.compression_method { | 54 | io: match info.compression_method { |
| 53 | CompressionMethod::Store => IoProxy::Store(io), | 55 | CompressionMethod::Store => IoProxy::Store(io), |
| 54 | CompressionMethod::Deflate => IoProxy::Deflate(DeflateDecoder::new(io)), | 56 | CompressionMethod::Deflate => IoProxy::Deflate(DeflateDecoder::new(io)), |
| 55 | CompressionMethod::BZip2 => IoProxy::BZip2(BzDecoder::new(io)), | 57 | CompressionMethod::BZip2 => IoProxy::BZip2(BzDecoder::new(io)), |
| 56 | CompressionMethod::LZMA => IoProxy::XZ(XzDecoder::new(io)), | 58 | CompressionMethod::Lzma => { |
| 57 | CompressionMethod::XZ => IoProxy::XZ(XzDecoder::new(io)), | 59 | let buf = { |
| 60 | let mut buf = [0; 9]; | ||
| 61 | io.read(&mut buf)?; | ||
| 62 | cursor += 9; | ||
| 63 | buf | ||
| 64 | }; | ||
| 65 | IoProxy::Xz(XzDecoder::new_stream( | ||
| 66 | io, | ||
| 67 | Stream::new_raw_decoder( | ||
| 68 | Filters::new().lzma1( | ||
| 69 | LzmaOptions::new() | ||
| 70 | .literal_context_bits((buf[4] % 9) as u32) | ||
| 71 | .literal_position_bits((buf[4] / 9 % 5) as u32) | ||
| 72 | .position_bits((buf[4] / 45) as u32) | ||
| 73 | .dict_size( | ||
| 74 | u32::from_le_bytes(buf[5..9].try_into().unwrap()).min(4096), | ||
| 75 | ), | ||
| 76 | ), | ||
| 77 | ) | ||
| 78 | .unwrap(), | ||
| 79 | )) | ||
| 80 | } | ||
| 81 | CompressionMethod::Xz => IoProxy::Xz(XzDecoder::new(io)), | ||
| 58 | }, | 82 | }, |
| 59 | info, | 83 | info, |
| 60 | 84 | ||
| 61 | bounds: (data_pointer, data_pointer + info.compressed_size), | 85 | bounds: (cursor, data_pointer + info.compressed_size), |
| 62 | cursor: data_pointer, | 86 | cursor: cursor, |
| 63 | }) | 87 | }) |
| 64 | } | 88 | } |
| 65 | 89 | ||
| @@ -78,7 +102,7 @@ impl<'d, Io: Read> Read for ZipFileReader<'d, Io> { | |||
| 78 | IoProxy::Store(io) => io.read(&mut buf[..upper]), | 102 | IoProxy::Store(io) => io.read(&mut buf[..upper]), |
| 79 | IoProxy::Deflate(io) => io.read(&mut buf[..upper]), | 103 | IoProxy::Deflate(io) => io.read(&mut buf[..upper]), |
| 80 | IoProxy::BZip2(io) => io.read(&mut buf[..upper]), | 104 | IoProxy::BZip2(io) => io.read(&mut buf[..upper]), |
| 81 | IoProxy::XZ(io) => io.read(&mut buf[..upper]), | 105 | IoProxy::Xz(io) => io.read(&mut buf[..upper]), |
| 82 | }?; | 106 | }?; |
| 83 | self.cursor += upper as u64; | 107 | self.cursor += upper as u64; |
| 84 | Ok(bytes) | 108 | Ok(bytes) |
| @@ -118,7 +142,7 @@ impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> { | |||
| 118 | } | 142 | } |
| 119 | _ => Err(IoError::new( | 143 | _ => Err(IoError::new( |
| 120 | IoErrorKind::Unsupported, | 144 | IoErrorKind::Unsupported, |
| 121 | ZipError::CompressionDataIsUnseekable, | 145 | ZipError::CompressedDataIsUnseekable, |
| 122 | )), | 146 | )), |
| 123 | } | 147 | } |
| 124 | } | 148 | } |
diff --git a/src/zip/file/write.rs b/src/zip/file/write.rs index 627db6d..6f5756a 100644 --- a/src/zip/file/write.rs +++ b/src/zip/file/write.rs | |||
| @@ -2,14 +2,14 @@ use crate::driver::FileDriver; | |||
| 2 | use crate::zip::ZipFileInfo; | 2 | use crate::zip::ZipFileInfo; |
| 3 | use bzip2::write::BzEncoder; | 3 | use bzip2::write::BzEncoder; |
| 4 | use flate2::write::DeflateEncoder; | 4 | use flate2::write::DeflateEncoder; |
| 5 | use liblzma::write::XzEncoder; | ||
| 5 | use std::io::Write; | 6 | use std::io::Write; |
| 6 | use xz2::write::XzEncoder; | ||
| 7 | 7 | ||
| 8 | enum IoProxy<Io: Write> { | 8 | enum IoProxy<Io: Write> { |
| 9 | Store(Io), | 9 | Store(Io), |
| 10 | Deflate(DeflateEncoder<Io>), | 10 | Deflate(DeflateEncoder<Io>), |
| 11 | BZip2(BzEncoder<Io>), | 11 | BZip2(BzEncoder<Io>), |
| 12 | XZ(XzEncoder<Io>), | 12 | Xz(XzEncoder<Io>), |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | pub struct ZipFileWriter<'d, Io: Write> { | 15 | pub struct ZipFileWriter<'d, Io: Write> { |
