From aa0893e63ac90e939c5b119e95f1e305105cd40a Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Fri, 5 Jul 2024 19:52:28 +0900 Subject: Fix lzma decompression --- src/driver/file.rs | 2 +- src/zip/error.rs | 4 ++-- src/zip/file/info.rs | 8 ++++---- src/zip/file/read.rs | 42 +++++++++++++++++++++++++++++++++--------- src/zip/file/write.rs | 4 ++-- 5 files changed, 42 insertions(+), 18 deletions(-) (limited to 'src') 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 @@ -pub trait ArchiveFileInfo {} +pub trait ArchiveFileInfo: Clone {} pub trait FileDriver { 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 { NegativeFileOffset, FileNotFound, - CompressionDataIsUnseekable, + CompressedDataIsUnseekable, } impl From for ArchiveError { @@ -60,7 +60,7 @@ impl Display for ZipError { Self::NegativeFileOffset => write!(f, "Negative file offset"), Self::FileNotFound => write!(f, "File not found"), - Self::CompressionDataIsUnseekable => write!(f, "Compression data is unseekable"), + Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), } } } 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 { Store, Deflate, BZip2, - LZMA, - XZ, + Lzma, + Xz, } impl CompressionMethod { @@ -17,8 +17,8 @@ impl CompressionMethod { 0 => Ok(Self::Store), 8 => Ok(Self::Deflate), 12 => Ok(Self::BZip2), - 14 => Ok(Self::LZMA), - 95 => Ok(Self::XZ), + 14 => Ok(Self::Lzma), + 95 => Ok(Self::Xz), 1..=7 | 9..=11 | 13 | 15..=20 | 93..=94 | 96..=99 => { Err(ZipError::UnsupportedCompressionMethod.into()) } 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; use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult}; use bzip2::read::BzDecoder; use flate2::read::DeflateDecoder; +use liblzma::read::XzDecoder; +use liblzma::stream::{Filters, LzmaOptions, Stream}; use std::io::{ Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, }; -use xz2::read::XzDecoder; enum IoProxy { Store(Io), Deflate(DeflateDecoder), BZip2(BzDecoder), - XZ(XzDecoder), + Xz(XzDecoder), } pub struct ZipFileReader<'d, Io: Read> { @@ -39,6 +40,7 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { io.read(&mut buf)?; buf }; + if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { return Err(ZipError::InvalidFileHeaderSignature.into()); } @@ -46,20 +48,42 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { + 30 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; - io.seek(SeekFrom::Start(data_pointer))?; + let mut cursor = io.seek(SeekFrom::Start(data_pointer))?; Ok(Self { io: match info.compression_method { CompressionMethod::Store => IoProxy::Store(io), CompressionMethod::Deflate => IoProxy::Deflate(DeflateDecoder::new(io)), CompressionMethod::BZip2 => IoProxy::BZip2(BzDecoder::new(io)), - CompressionMethod::LZMA => IoProxy::XZ(XzDecoder::new(io)), - CompressionMethod::XZ => IoProxy::XZ(XzDecoder::new(io)), + CompressionMethod::Lzma => { + let buf = { + let mut buf = [0; 9]; + io.read(&mut buf)?; + cursor += 9; + buf + }; + IoProxy::Xz(XzDecoder::new_stream( + io, + Stream::new_raw_decoder( + Filters::new().lzma1( + LzmaOptions::new() + .literal_context_bits((buf[4] % 9) as u32) + .literal_position_bits((buf[4] / 9 % 5) as u32) + .position_bits((buf[4] / 45) as u32) + .dict_size( + u32::from_le_bytes(buf[5..9].try_into().unwrap()).min(4096), + ), + ), + ) + .unwrap(), + )) + } + CompressionMethod::Xz => IoProxy::Xz(XzDecoder::new(io)), }, info, - bounds: (data_pointer, data_pointer + info.compressed_size), - cursor: data_pointer, + bounds: (cursor, data_pointer + info.compressed_size), + cursor: cursor, }) } @@ -78,7 +102,7 @@ impl<'d, Io: Read> Read for ZipFileReader<'d, Io> { IoProxy::Store(io) => io.read(&mut buf[..upper]), IoProxy::Deflate(io) => io.read(&mut buf[..upper]), IoProxy::BZip2(io) => io.read(&mut buf[..upper]), - IoProxy::XZ(io) => io.read(&mut buf[..upper]), + IoProxy::Xz(io) => io.read(&mut buf[..upper]), }?; self.cursor += upper as u64; Ok(bytes) @@ -118,7 +142,7 @@ impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> { } _ => Err(IoError::new( IoErrorKind::Unsupported, - ZipError::CompressionDataIsUnseekable, + ZipError::CompressedDataIsUnseekable, )), } } 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; use crate::zip::ZipFileInfo; use bzip2::write::BzEncoder; use flate2::write::DeflateEncoder; +use liblzma::write::XzEncoder; use std::io::Write; -use xz2::write::XzEncoder; enum IoProxy { Store(Io), Deflate(DeflateEncoder), BZip2(BzEncoder), - XZ(XzEncoder), + Xz(XzEncoder), } pub struct ZipFileWriter<'d, Io: Write> { -- cgit v1.2.3