diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/archive.rs | 42 | ||||
| -rw-r--r-- | src/driver/driver.rs | 5 | ||||
| -rw-r--r-- | src/driver/file.rs | 2 | ||||
| -rw-r--r-- | src/file.rs | 38 | ||||
| -rw-r--r-- | src/lib.rs | 6 | ||||
| -rw-r--r-- | src/zip/archive.rs | 19 | ||||
| -rw-r--r-- | src/zip/driver.rs | 25 | ||||
| -rw-r--r-- | src/zip/encryption.rs | 49 | ||||
| -rw-r--r-- | src/zip/error.rs | 2 | ||||
| -rw-r--r-- | src/zip/file/info.rs | 16 | ||||
| -rw-r--r-- | src/zip/file/read.rs | 88 | ||||
| -rw-r--r-- | src/zip/file/write.rs | 6 | ||||
| -rw-r--r-- | src/zip/structs.rs | 6 |
13 files changed, 137 insertions, 167 deletions
diff --git a/src/archive.rs b/src/archive.rs index 73c515c..d49689d 100644 --- a/src/archive.rs +++ b/src/archive.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; | 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; |
| 2 | use crate::{ArchiveFile, ArchiveResult}; | 2 | use crate::ArchiveResult; |
| 3 | use std::fs::File; | 3 | use std::fs::File; |
| 4 | use std::io::{Read, Write}; | 4 | use std::io::{Read, Write}; |
| 5 | use std::path::Path; | 5 | use std::path::Path; |
| @@ -48,51 +48,19 @@ where | |||
| 48 | self.get_file_info_by_index(self.get_file_index(name)?) | 48 | self.get_file_info_by_index(self.get_file_index(name)?) |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | fn get_file_reader_by_index_with_optional_password<'d>( | ||
| 52 | &'d mut self, | ||
| 53 | index: usize, | ||
| 54 | password: Option<&str>, | ||
| 55 | ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { | ||
| 56 | Ok(ArchiveFile::new( | ||
| 57 | self.driver.get_file_reader(index, password)?, | ||
| 58 | )) | ||
| 59 | } | ||
| 60 | |||
| 61 | #[inline] | ||
| 62 | pub fn get_file_reader_by_index<'d>( | 51 | pub fn get_file_reader_by_index<'d>( |
| 63 | &'d mut self, | 52 | &'d mut self, |
| 64 | index: usize, | 53 | index: usize, |
| 65 | ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { | 54 | ) -> ArchiveResult<D::FileReader<'d>, D::Error> { |
| 66 | self.get_file_reader_by_index_with_optional_password(index, None) | 55 | self.driver.get_file_reader(index) |
| 67 | } | ||
| 68 | |||
| 69 | #[inline] | ||
| 70 | pub fn get_file_reader_by_index_with_password<'d>( | ||
| 71 | &'d mut self, | ||
| 72 | index: usize, | ||
| 73 | password: &str, | ||
| 74 | ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { | ||
| 75 | self.get_file_reader_by_index_with_optional_password(index, Some(password)) | ||
| 76 | } | 56 | } |
| 77 | 57 | ||
| 78 | #[inline] | 58 | #[inline] |
| 79 | pub fn get_file_reader_by_name<'d>( | 59 | pub fn get_file_reader_by_name<'d>( |
| 80 | &'d mut self, | 60 | &'d mut self, |
| 81 | name: &str, | 61 | name: &str, |
| 82 | ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { | 62 | ) -> ArchiveResult<D::FileReader<'d>, D::Error> { |
| 83 | self.get_file_reader_by_index_with_optional_password(self.get_file_index(name)?, None) | 63 | self.get_file_reader_by_index(self.get_file_index(name)?) |
| 84 | } | ||
| 85 | |||
| 86 | #[inline] | ||
| 87 | pub fn get_file_reader_by_name_with_password<'d>( | ||
| 88 | &'d mut self, | ||
| 89 | name: &str, | ||
| 90 | password: &str, | ||
| 91 | ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { | ||
| 92 | self.get_file_reader_by_index_with_optional_password( | ||
| 93 | self.get_file_index(name)?, | ||
| 94 | Some(password), | ||
| 95 | ) | ||
| 96 | } | 64 | } |
| 97 | } | 65 | } |
| 98 | 66 | ||
diff --git a/src/driver/driver.rs b/src/driver/driver.rs index f0f93a9..359793d 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs | |||
| @@ -14,7 +14,7 @@ pub trait ArchiveRead: Driver | |||
| 14 | where | 14 | where |
| 15 | Self::Io: Read, | 15 | Self::Io: Read, |
| 16 | { | 16 | { |
| 17 | type FileReader<'d>: FileDriver | 17 | type FileReader<'d>: FileDriver<Io = Self::Io, FileInfo = Self::FileInfo> |
| 18 | where | 18 | where |
| 19 | Self: 'd; | 19 | Self: 'd; |
| 20 | 20 | ||
| @@ -34,7 +34,6 @@ where | |||
| 34 | fn get_file_reader<'d>( | 34 | fn get_file_reader<'d>( |
| 35 | &'d mut self, | 35 | &'d mut self, |
| 36 | index: usize, | 36 | index: usize, |
| 37 | password: Option<&str>, | ||
| 38 | ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>; | 37 | ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>; |
| 39 | } | 38 | } |
| 40 | 39 | ||
| @@ -42,7 +41,7 @@ pub trait ArchiveWrite: Driver | |||
| 42 | where | 41 | where |
| 43 | Self::Io: Read + Write, | 42 | Self::Io: Read + Write, |
| 44 | { | 43 | { |
| 45 | type FileWriter<'d>: FileDriver | 44 | type FileWriter<'d>: FileDriver<Io = Self::Io, FileInfo = Self::FileInfo> |
| 46 | where | 45 | where |
| 47 | Self: 'd; | 46 | Self: 'd; |
| 48 | } | 47 | } |
diff --git a/src/driver/file.rs b/src/driver/file.rs index 5c6ea43..3d562da 100644 --- a/src/driver/file.rs +++ b/src/driver/file.rs | |||
| @@ -3,6 +3,4 @@ pub trait ArchiveFileInfo: Clone {} | |||
| 3 | pub trait FileDriver { | 3 | pub trait FileDriver { |
| 4 | type Io; | 4 | type Io; |
| 5 | type FileInfo: ArchiveFileInfo; | 5 | type FileInfo: ArchiveFileInfo; |
| 6 | |||
| 7 | fn info(&self) -> &Self::FileInfo; | ||
| 8 | } | 6 | } |
diff --git a/src/file.rs b/src/file.rs deleted file mode 100644 index f284b98..0000000 --- a/src/file.rs +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | use crate::driver::FileDriver; | ||
| 2 | use std::io::{Read, Result as IoResult, Seek, Write}; | ||
| 3 | |||
| 4 | pub struct ArchiveFile<D: FileDriver> { | ||
| 5 | pub(crate) driver: D, | ||
| 6 | } | ||
| 7 | |||
| 8 | impl<D: FileDriver> ArchiveFile<D> { | ||
| 9 | pub fn new(driver: D) -> Self { | ||
| 10 | Self { driver } | ||
| 11 | } | ||
| 12 | |||
| 13 | pub fn info(&self) -> &D::FileInfo { | ||
| 14 | self.driver.info() | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | impl<D: FileDriver + Read> Read for ArchiveFile<D> { | ||
| 19 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { | ||
| 20 | self.driver.read(buf) | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<D: FileDriver + Write> Write for ArchiveFile<D> { | ||
| 25 | fn write(&mut self, buf: &[u8]) -> IoResult<usize> { | ||
| 26 | self.driver.write(buf) | ||
| 27 | } | ||
| 28 | |||
| 29 | fn flush(&mut self) -> IoResult<()> { | ||
| 30 | self.driver.flush() | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl<D: FileDriver + Seek> Seek for ArchiveFile<D> { | ||
| 35 | fn seek(&mut self, pos: std::io::SeekFrom) -> IoResult<u64> { | ||
| 36 | self.driver.seek(pos) | ||
| 37 | } | ||
| 38 | } | ||
| @@ -1,14 +1,12 @@ | |||
| 1 | mod archive; | 1 | mod archive; |
| 2 | mod driver; | ||
| 2 | mod error; | 3 | mod error; |
| 3 | mod file; | 4 | mod structs; |
| 4 | mod utils; | 5 | mod utils; |
| 5 | 6 | ||
| 6 | pub mod driver; | ||
| 7 | pub mod structs; | ||
| 8 | pub mod zip; | 7 | pub mod zip; |
| 9 | 8 | ||
| 10 | pub use archive::Archive; | 9 | pub use archive::Archive; |
| 11 | pub use error::{ArchiveError, ArchiveResult}; | 10 | pub use error::{ArchiveError, ArchiveResult}; |
| 12 | pub use file::ArchiveFile; | ||
| 13 | 11 | ||
| 14 | pub use zip::Zip; | 12 | pub use zip::Zip; |
diff --git a/src/zip/archive.rs b/src/zip/archive.rs index 79e8ca1..569ad87 100644 --- a/src/zip/archive.rs +++ b/src/zip/archive.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | use crate::zip::{ZipFileReader, ZipResult}; | ||
| 1 | use crate::{Archive, Zip}; | 2 | use crate::{Archive, Zip}; |
| 2 | use std::io::{Read, Seek, Write}; | 3 | use std::io::{Read, Seek, Write}; |
| 3 | 4 | ||
| @@ -5,6 +6,24 @@ impl<Io: Read + Seek> Archive<Zip<Io>> { | |||
| 5 | pub fn comment(&self) -> &String { | 6 | pub fn comment(&self) -> &String { |
| 6 | self.driver.comment() | 7 | self.driver.comment() |
| 7 | } | 8 | } |
| 9 | |||
| 10 | pub fn get_file_reader_by_index_with_password<'d>( | ||
| 11 | &'d mut self, | ||
| 12 | index: usize, | ||
| 13 | password: &[u8], | ||
| 14 | ) -> ZipResult<ZipFileReader<'d, Io>> { | ||
| 15 | self.driver | ||
| 16 | .get_file_reader_with_optional_password(index, Some(password)) | ||
| 17 | } | ||
| 18 | |||
| 19 | #[inline] | ||
| 20 | pub fn get_file_reader_by_name_with_password<'d>( | ||
| 21 | &'d mut self, | ||
| 22 | name: &str, | ||
| 23 | password: &[u8], | ||
| 24 | ) -> ZipResult<ZipFileReader<'d, Io>> { | ||
| 25 | self.get_file_reader_by_index_with_password(self.get_file_index(name)?, password) | ||
| 26 | } | ||
| 8 | } | 27 | } |
| 9 | 28 | ||
| 10 | impl<Io: Read + Write + Seek> Archive<Zip<Io>> {} | 29 | impl<Io: Read + Write + Seek> Archive<Zip<Io>> {} |
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 87f9c1a..62da39f 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -221,7 +221,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 221 | indexes.insert(name.clone(), i); | 221 | indexes.insert(name.clone(), i); |
| 222 | files.push(ZipFileInfo::new( | 222 | files.push(ZipFileInfo::new( |
| 223 | CompressionMethod::from_struct_id(cdr.compression_method)?, | 223 | CompressionMethod::from_struct_id(cdr.compression_method)?, |
| 224 | EncryptionMethod::from_bit_flag(bit_flag), | 224 | EncryptionMethod::from_bif_flag(bit_flag, cdr.crc, cdr.dos_time), |
| 225 | bit_flag, | 225 | bit_flag, |
| 226 | mtime, | 226 | mtime, |
| 227 | atime, | 227 | atime, |
| @@ -258,11 +258,22 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 258 | self.files.get(index).ok_or(ZipError::FileNotFound.into()) | 258 | self.files.get(index).ok_or(ZipError::FileNotFound.into()) |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | fn get_file_reader<'d>( | 261 | #[inline] |
| 262 | fn get_file_reader<'d>(&'d mut self, index: usize) -> ZipResult<Self::FileReader<'d>> { | ||
| 263 | self.get_file_reader_with_optional_password(index, None) | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | impl<Io: Read + Seek> Zip<Io> { | ||
| 268 | pub fn comment(&self) -> &String { | ||
| 269 | &self.comment | ||
| 270 | } | ||
| 271 | |||
| 272 | pub fn get_file_reader_with_optional_password<'d>( | ||
| 262 | &'d mut self, | 273 | &'d mut self, |
| 263 | index: usize, | 274 | index: usize, |
| 264 | password: Option<&str>, | 275 | password: Option<&[u8]>, |
| 265 | ) -> ZipResult<Self::FileReader<'d>> { | 276 | ) -> ZipResult<<Self as ArchiveRead>::FileReader<'d>> { |
| 266 | Ok(ZipFileReader::new( | 277 | Ok(ZipFileReader::new( |
| 267 | &mut self.io, | 278 | &mut self.io, |
| 268 | self.files.get(index).ok_or(ZipError::FileNotFound)?, | 279 | self.files.get(index).ok_or(ZipError::FileNotFound)?, |
| @@ -271,12 +282,6 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 271 | } | 282 | } |
| 272 | } | 283 | } |
| 273 | 284 | ||
| 274 | impl<Io: Read + Seek> Zip<Io> { | ||
| 275 | pub fn comment(&self) -> &String { | ||
| 276 | &self.comment | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | impl<Io: Read + Write + Seek> ArchiveWrite for Zip<Io> { | 285 | impl<Io: Read + Write + Seek> ArchiveWrite for Zip<Io> { |
| 281 | type FileWriter<'d> = ZipFileWriter<'d, Io> where Io: 'd; | 286 | type FileWriter<'d> = ZipFileWriter<'d, Io> where Io: 'd; |
| 282 | } | 287 | } |
diff --git a/src/zip/encryption.rs b/src/zip/encryption.rs index 84e30d5..28a6bdb 100644 --- a/src/zip/encryption.rs +++ b/src/zip/encryption.rs | |||
| @@ -1,12 +1,35 @@ | |||
| 1 | use crate::utils::ReadUtils; | 1 | use crate::utils::ReadUtils; |
| 2 | use crate::zip::ZipResult; | 2 | use crate::zip::{ZipError, ZipResult}; |
| 3 | use crc32fast::Hasher; | ||
| 4 | use std::io::{Read, Result as IoResult}; | 3 | use std::io::{Read, Result as IoResult}; |
| 5 | 4 | ||
| 6 | fn crc32(byte: u8, crc32: u32) -> u32 { | 5 | const TABLE: [u32; 256] = generate_table(); |
| 7 | let mut hasher = Hasher::new_with_initial(crc32 ^ 0xFFFFFFFF); | 6 | |
| 8 | hasher.update(&[byte]); | 7 | const fn generate_table() -> [u32; 256] { |
| 9 | hasher.finalize() ^ 0xFFFFFFFF | 8 | let mut table = [0; 256]; |
| 9 | |||
| 10 | let mut b = 0; | ||
| 11 | while b <= 255 { | ||
| 12 | let mut crc = b as u32; | ||
| 13 | |||
| 14 | let mut i = 0; | ||
| 15 | while i < 8 { | ||
| 16 | if (crc & 1) > 0 { | ||
| 17 | crc = (crc >> 1) ^ 0xEDB88320 | ||
| 18 | } else { | ||
| 19 | crc >>= 1 | ||
| 20 | } | ||
| 21 | i += 1; | ||
| 22 | } | ||
| 23 | |||
| 24 | table[b] = crc; | ||
| 25 | b += 1 | ||
| 26 | } | ||
| 27 | |||
| 28 | table | ||
| 29 | } | ||
| 30 | |||
| 31 | fn crc32(byte: u8, crc: u32) -> u32 { | ||
| 32 | (crc >> 8) ^ TABLE[((crc & 0xFF) as u8 ^ byte) as usize] | ||
| 10 | } | 33 | } |
| 11 | 34 | ||
| 12 | pub struct WeakDecoder<Io: Read> { | 35 | pub struct WeakDecoder<Io: Read> { |
| @@ -17,7 +40,7 @@ pub struct WeakDecoder<Io: Read> { | |||
| 17 | } | 40 | } |
| 18 | 41 | ||
| 19 | impl<Io: Read> WeakDecoder<Io> { | 42 | impl<Io: Read> WeakDecoder<Io> { |
| 20 | pub fn new(io: Io, password: &str) -> ZipResult<Self> { | 43 | pub fn new(io: Io, check: u8, password: &[u8]) -> ZipResult<Self> { |
| 21 | let mut decoder = Self { | 44 | let mut decoder = Self { |
| 22 | key0: 305419896, | 45 | key0: 305419896, |
| 23 | key1: 591751049, | 46 | key1: 591751049, |
| @@ -25,11 +48,14 @@ impl<Io: Read> WeakDecoder<Io> { | |||
| 25 | io, | 48 | io, |
| 26 | }; | 49 | }; |
| 27 | 50 | ||
| 28 | for c in password.chars() { | 51 | for c in password { |
| 29 | decoder.update_keys(c as u8) | 52 | decoder.update_keys(*c) |
| 30 | } | 53 | } |
| 31 | 54 | ||
| 32 | let buf = decoder.read_arr::<12>()?; | 55 | let buf = decoder.read_arr::<12>()?; |
| 56 | if check != buf[11] { | ||
| 57 | return Err(ZipError::IncorrectPassword.into()); | ||
| 58 | } | ||
| 33 | 59 | ||
| 34 | Ok(decoder) | 60 | Ok(decoder) |
| 35 | } | 61 | } |
| @@ -46,7 +72,9 @@ impl<Io: Read> WeakDecoder<Io> { | |||
| 46 | 72 | ||
| 47 | fn decode_byte(&mut self, byte: u8) -> u8 { | 73 | fn decode_byte(&mut self, byte: u8) -> u8 { |
| 48 | let key = self.key2 | 2; | 74 | let key = self.key2 | 2; |
| 49 | byte ^ (((key * (key ^ 1)) >> 8) as u8) | 75 | let byte = byte ^ ((key * (key ^ 1)) >> 8) as u8; |
| 76 | self.update_keys(byte); | ||
| 77 | byte | ||
| 50 | } | 78 | } |
| 51 | } | 79 | } |
| 52 | 80 | ||
| @@ -55,7 +83,6 @@ impl<Io: Read> Read for WeakDecoder<Io> { | |||
| 55 | let bytes = self.io.read(buf)?; | 83 | let bytes = self.io.read(buf)?; |
| 56 | for i in 0..bytes { | 84 | for i in 0..bytes { |
| 57 | buf[i] = self.decode_byte(buf[i]); | 85 | buf[i] = self.decode_byte(buf[i]); |
| 58 | self.update_keys(buf[i]) | ||
| 59 | } | 86 | } |
| 60 | Ok(bytes) | 87 | Ok(bytes) |
| 61 | } | 88 | } |
diff --git a/src/zip/error.rs b/src/zip/error.rs index 9ec0956..a4b8c2b 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -20,6 +20,7 @@ pub enum ZipError { | |||
| 20 | InvalidFileComment, | 20 | InvalidFileComment, |
| 21 | 21 | ||
| 22 | FileNotFound, | 22 | FileNotFound, |
| 23 | IncorrectPassword, | ||
| 23 | PasswordIsNotSpecified, | 24 | PasswordIsNotSpecified, |
| 24 | CompressedDataIsUnseekable, | 25 | CompressedDataIsUnseekable, |
| 25 | EncryptedDataIsUnseekable, | 26 | EncryptedDataIsUnseekable, |
| @@ -66,6 +67,7 @@ impl Display for ZipError { | |||
| 66 | Self::InvalidFileComment => write!(f, "Invalid file comment"), | 67 | Self::InvalidFileComment => write!(f, "Invalid file comment"), |
| 67 | 68 | ||
| 68 | Self::FileNotFound => write!(f, "File not found"), | 69 | Self::FileNotFound => write!(f, "File not found"), |
| 70 | Self::IncorrectPassword => write!(f, "Incorrect password"), | ||
| 69 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), | 71 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), |
| 70 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), | 72 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), |
| 71 | Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"), | 73 | Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"), |
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs index f5d4d8a..599dcc3 100644 --- a/src/zip/file/info.rs +++ b/src/zip/file/info.rs | |||
| @@ -2,7 +2,7 @@ use crate::driver::ArchiveFileInfo; | |||
| 2 | use crate::zip::{ZipError, ZipResult}; | 2 | use crate::zip::{ZipError, ZipResult}; |
| 3 | use chrono::{DateTime, Local}; | 3 | use chrono::{DateTime, Local}; |
| 4 | 4 | ||
| 5 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 5 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 6 | pub enum CompressionMethod { | 6 | pub enum CompressionMethod { |
| 7 | Store, | 7 | Store, |
| 8 | Deflate, | 8 | Deflate, |
| @@ -28,18 +28,22 @@ impl CompressionMethod { | |||
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 31 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 32 | pub enum EncryptionMethod { | 32 | pub enum EncryptionMethod { |
| 33 | None, | 33 | None, |
| 34 | Weak, | 34 | Weak(u8), |
| 35 | Unsupported, | 35 | Unsupported, |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | impl EncryptionMethod { | 38 | impl EncryptionMethod { |
| 39 | pub(crate) fn from_bit_flag(bit_flag: BitFlag) -> EncryptionMethod { | 39 | pub(crate) fn from_bif_flag(bit_flag: BitFlag, crc: u32, dos_time: u16) -> EncryptionMethod { |
| 40 | match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) { | 40 | match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) { |
| 41 | (false, false) => EncryptionMethod::None, | 41 | (false, false) => EncryptionMethod::None, |
| 42 | (true, false) => EncryptionMethod::Weak, | 42 | (true, false) => EncryptionMethod::Weak(if bit_flag.is_has_data_descriptor() { |
| 43 | (dos_time >> 8) as u8 // Info-ZIP modification | ||
| 44 | } else { | ||
| 45 | (crc >> 24) as u8 | ||
| 46 | }), | ||
| 43 | (true, true) => EncryptionMethod::Unsupported, | 47 | (true, true) => EncryptionMethod::Unsupported, |
| 44 | _ => panic!("impossible"), | 48 | _ => panic!("impossible"), |
| 45 | } | 49 | } |
| @@ -52,7 +56,7 @@ pub struct BitFlag { | |||
| 52 | } | 56 | } |
| 53 | 57 | ||
| 54 | pub mod bit { | 58 | pub mod bit { |
| 55 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 59 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 56 | pub enum DeflateMode { | 60 | pub enum DeflateMode { |
| 57 | Normal, | 61 | Normal, |
| 58 | Maximum, | 62 | Maximum, |
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs index aa665c3..c26b304 100644 --- a/src/zip/file/read.rs +++ b/src/zip/file/read.rs | |||
| @@ -17,11 +17,12 @@ enum Encryption<Io: Read> { | |||
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | impl<Io: Read> Encryption<Io> { | 19 | impl<Io: Read> Encryption<Io> { |
| 20 | pub fn new(io: Io, method: EncryptionMethod, password: Option<&str>) -> ZipResult<Self> { | 20 | pub fn new(io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult<Self> { |
| 21 | Ok(match method { | 21 | Ok(match info.encryption_method { |
| 22 | EncryptionMethod::None => Self::None(io), | 22 | EncryptionMethod::None => Self::None(io), |
| 23 | EncryptionMethod::Weak => Self::Weak(WeakDecoder::new( | 23 | EncryptionMethod::Weak(check) => Self::Weak(WeakDecoder::new( |
| 24 | io, | 24 | io, |
| 25 | check, | ||
| 25 | password.ok_or(ZipError::PasswordIsNotSpecified)?, | 26 | password.ok_or(ZipError::PasswordIsNotSpecified)?, |
| 26 | )?), | 27 | )?), |
| 27 | EncryptionMethod::Unsupported => { | 28 | EncryptionMethod::Unsupported => { |
| @@ -61,12 +62,29 @@ enum Compression<Io: Read> { | |||
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | impl<Io: Read + Seek> Compression<Io> { | 64 | impl<Io: Read + Seek> Compression<Io> { |
| 64 | pub fn new(io: Io, method: CompressionMethod) -> ZipResult<Self> { | 65 | pub fn new(mut io: Io, info: &ZipFileInfo) -> ZipResult<Self> { |
| 65 | Ok(match method { | 66 | Ok(match info.compression_method { |
| 66 | CompressionMethod::Store => Self::Store(io), | 67 | CompressionMethod::Store => Self::Store(io), |
| 67 | CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)), | 68 | CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)), |
| 68 | CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)), | 69 | CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)), |
| 69 | CompressionMethod::Lzma => panic!(), | 70 | CompressionMethod::Lzma => { |
| 71 | let buf = io.read_arr::<9>()?; | ||
| 72 | Compression::Xz(XzDecoder::new_stream( | ||
| 73 | io, | ||
| 74 | Stream::new_raw_decoder( | ||
| 75 | Filters::new().lzma1( | ||
| 76 | LzmaOptions::new() | ||
| 77 | .literal_context_bits((buf[4] % 9) as u32) | ||
| 78 | .literal_position_bits((buf[4] / 9 % 5) as u32) | ||
| 79 | .position_bits((buf[4] / 45) as u32) | ||
| 80 | .dict_size( | ||
| 81 | u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096), | ||
| 82 | ), | ||
| 83 | ), | ||
| 84 | ) | ||
| 85 | .unwrap(), | ||
| 86 | )) | ||
| 87 | } | ||
| 70 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), | 88 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), |
| 71 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), | 89 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), |
| 72 | CompressionMethod::Unsupported(id) => { | 90 | CompressionMethod::Unsupported(id) => { |
| @@ -108,14 +126,14 @@ pub struct ZipFileReader<'d, Io: Read> { | |||
| 108 | impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { | 126 | impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { |
| 109 | type Io = Io; | 127 | type Io = Io; |
| 110 | type FileInfo = ZipFileInfo; | 128 | type FileInfo = ZipFileInfo; |
| 111 | |||
| 112 | fn info(&self) -> &Self::FileInfo { | ||
| 113 | self.info | ||
| 114 | } | ||
| 115 | } | 129 | } |
| 116 | 130 | ||
| 117 | impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | 131 | impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { |
| 118 | pub fn new(io: &'d mut Io, info: &'d ZipFileInfo, password: Option<&str>) -> ZipResult<Self> { | 132 | pub(crate) fn new( |
| 133 | io: &'d mut Io, | ||
| 134 | info: &'d ZipFileInfo, | ||
| 135 | password: Option<&[u8]>, | ||
| 136 | ) -> ZipResult<Self> { | ||
| 119 | io.seek(SeekFrom::Start(info.header_pointer))?; | 137 | io.seek(SeekFrom::Start(info.header_pointer))?; |
| 120 | 138 | ||
| 121 | let buf = io.read_arr::<30>()?; | 139 | let buf = io.read_arr::<30>()?; |
| @@ -127,49 +145,23 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 127 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 | 145 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 |
| 128 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; | 146 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; |
| 129 | 147 | ||
| 130 | io.seek(SeekFrom::Start(data_pointer))?; | ||
| 131 | |||
| 132 | Ok(Self { | 148 | Ok(Self { |
| 133 | io: match info.compression_method { | 149 | io: Compression::new( |
| 134 | CompressionMethod::Lzma => { | 150 | Encryption::new( |
| 135 | let buf = io.read_arr::<9>()?; | 151 | IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?, |
| 136 | Compression::Xz(XzDecoder::new_stream( | 152 | info, |
| 137 | Encryption::new( | 153 | password, |
| 138 | IoCursor::new( | ||
| 139 | io, | ||
| 140 | data_pointer + 9, | ||
| 141 | data_pointer + info.compressed_size, | ||
| 142 | )?, | ||
| 143 | info.encryption_method, | ||
| 144 | password, | ||
| 145 | )?, | ||
| 146 | Stream::new_raw_decoder( | ||
| 147 | Filters::new().lzma1( | ||
| 148 | LzmaOptions::new() | ||
| 149 | .literal_context_bits((buf[4] % 9) as u32) | ||
| 150 | .literal_position_bits((buf[4] / 9 % 5) as u32) | ||
| 151 | .position_bits((buf[4] / 45) as u32) | ||
| 152 | .dict_size( | ||
| 153 | u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096), | ||
| 154 | ), | ||
| 155 | ), | ||
| 156 | ) | ||
| 157 | .unwrap(), | ||
| 158 | )) | ||
| 159 | } | ||
| 160 | _ => Compression::new( | ||
| 161 | Encryption::new( | ||
| 162 | IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?, | ||
| 163 | info.encryption_method, | ||
| 164 | password, | ||
| 165 | )?, | ||
| 166 | info.compression_method, | ||
| 167 | )?, | 154 | )?, |
| 168 | }, | 155 | info, |
| 156 | )?, | ||
| 169 | info, | 157 | info, |
| 170 | }) | 158 | }) |
| 171 | } | 159 | } |
| 172 | 160 | ||
| 161 | pub fn info(&self) -> &ZipFileInfo { | ||
| 162 | self.info | ||
| 163 | } | ||
| 164 | |||
| 173 | pub fn is_seekable(&self) -> bool { | 165 | pub fn is_seekable(&self) -> bool { |
| 174 | match self.io { | 166 | match self.io { |
| 175 | Compression::Store(Encryption::None(..)) => true, | 167 | Compression::Store(Encryption::None(..)) => true, |
diff --git a/src/zip/file/write.rs b/src/zip/file/write.rs index d5b686c..20e53b3 100644 --- a/src/zip/file/write.rs +++ b/src/zip/file/write.rs | |||
| @@ -2,8 +2,8 @@ use crate::driver::FileDriver; | |||
| 2 | use crate::zip::ZipFileInfo; | 2 | use crate::zip::ZipFileInfo; |
| 3 | use std::io::Write; | 3 | use std::io::Write; |
| 4 | 4 | ||
| 5 | #[allow(dead_code)] | ||
| 5 | pub struct ZipFileWriter<'d, Io: Write> { | 6 | pub struct ZipFileWriter<'d, Io: Write> { |
| 6 | #[allow(dead_code)] | ||
| 7 | io: &'d mut Io, | 7 | io: &'d mut Io, |
| 8 | info: &'d ZipFileInfo, | 8 | info: &'d ZipFileInfo, |
| 9 | } | 9 | } |
| @@ -11,8 +11,4 @@ pub struct ZipFileWriter<'d, Io: Write> { | |||
| 11 | impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> { | 11 | impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> { |
| 12 | type Io = Io; | 12 | type Io = Io; |
| 13 | type FileInfo = ZipFileInfo; | 13 | type FileInfo = ZipFileInfo; |
| 14 | |||
| 15 | fn info(&self) -> &Self::FileInfo { | ||
| 16 | self.info | ||
| 17 | } | ||
| 18 | } | 14 | } |
diff --git a/src/zip/structs.rs b/src/zip/structs.rs index a44659b..9fd1aeb 100644 --- a/src/zip/structs.rs +++ b/src/zip/structs.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use crate::structs::{Settings, StructResult}; | 1 | use crate::structs::{ByteOrder, Settings, StructResult, VariantIndexType}; |
| 2 | use serde::{Deserialize, Serialize}; | 2 | use serde::{Deserialize, Serialize}; |
| 3 | 3 | ||
| 4 | #[derive(Serialize, Deserialize)] | 4 | #[derive(Serialize, Deserialize)] |
| @@ -60,9 +60,9 @@ pub struct ExtraHeader { | |||
| 60 | 60 | ||
| 61 | #[allow(dead_code)] | 61 | #[allow(dead_code)] |
| 62 | pub fn serialize<T: Serialize>(object: &mut T) -> StructResult<Vec<u8>> { | 62 | pub fn serialize<T: Serialize>(object: &mut T) -> StructResult<Vec<u8>> { |
| 63 | Settings::default().serialize(object) | 63 | Settings::new(ByteOrder::Le, VariantIndexType::U8).serialize(object) |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | pub fn deserialize<'de, T: Deserialize<'de>>(object: &'de [u8]) -> StructResult<T> { | 66 | pub fn deserialize<'de, T: Deserialize<'de>>(object: &'de [u8]) -> StructResult<T> { |
| 67 | Settings::default().deserialize(object) | 67 | Settings::new(ByteOrder::Le, VariantIndexType::U8).deserialize(object) |
| 68 | } | 68 | } |
