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/zip/file/read.rs | |
| parent | 5d3d32ded672b67471d9d7c85ebbe691129cc51c (diff) | |
| download | archivator-aa0893e63ac90e939c5b119e95f1e305105cd40a.tar.gz archivator-aa0893e63ac90e939c5b119e95f1e305105cd40a.zip | |
Fix lzma decompression
Diffstat (limited to 'src/zip/file/read.rs')
| -rw-r--r-- | src/zip/file/read.rs | 42 |
1 files changed, 33 insertions, 9 deletions
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 | } |
