aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-16 01:59:53 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-16 01:59:53 +0900
commita83767f9fbd51df654901b52bdba7838f6a10bf9 (patch)
treee9e2fcfb9975a2c2dd6e65c65fd736a035ea6cae /src
parent2fdbec0525bc2a0839ea649106886cb157507a38 (diff)
downloadarchivator-a83767f9fbd51df654901b52bdba7838f6a10bf9.tar.gz
archivator-a83767f9fbd51df654901b52bdba7838f6a10bf9.zip
Add traditional PKWARE decryption.
- Compression and encryption may not work together - Password check is not yet implemented - Unoptimized crc32 function
Diffstat (limited to 'src')
-rw-r--r--src/archive.rs36
-rw-r--r--src/driver/driver.rs1
-rw-r--r--src/utils/cursor.rs1
-rw-r--r--src/zip/driver.rs11
-rw-r--r--src/zip/encryption.rs62
-rw-r--r--src/zip/error.rs20
-rw-r--r--src/zip/file/info.rs47
-rw-r--r--src/zip/file/mod.rs2
-rw-r--r--src/zip/file/read.rs159
-rw-r--r--src/zip/mod.rs5
10 files changed, 269 insertions, 75 deletions
diff --git a/src/archive.rs b/src/archive.rs
index e17db80..73c515c 100644
--- a/src/archive.rs
+++ b/src/archive.rs
@@ -48,11 +48,31 @@ 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]
51 pub fn get_file_reader_by_index<'d>( 62 pub fn get_file_reader_by_index<'d>(
52 &'d mut self, 63 &'d mut self,
53 index: usize, 64 index: usize,
54 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { 65 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> {
55 Ok(ArchiveFile::new(self.driver.get_file_reader(index)?)) 66 self.get_file_reader_by_index_with_optional_password(index, None)
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))
56 } 76 }
57 77
58 #[inline] 78 #[inline]
@@ -60,7 +80,19 @@ where
60 &'d mut self, 80 &'d mut self,
61 name: &str, 81 name: &str,
62 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { 82 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> {
63 self.get_file_reader_by_index(self.get_file_index(name)?) 83 self.get_file_reader_by_index_with_optional_password(self.get_file_index(name)?, None)
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 )
64 } 96 }
65} 97}
66 98
diff --git a/src/driver/driver.rs b/src/driver/driver.rs
index 747345c..f0f93a9 100644
--- a/src/driver/driver.rs
+++ b/src/driver/driver.rs
@@ -34,6 +34,7 @@ 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>,
37 ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>; 38 ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>;
38} 39}
39 40
diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs
index 0c4b77e..91d44f8 100644
--- a/src/utils/cursor.rs
+++ b/src/utils/cursor.rs
@@ -34,7 +34,6 @@ impl<Io: Write> Write for IoCursor<Io> {
34 Ok(bytes) 34 Ok(bytes)
35 } 35 }
36 36
37 #[inline]
38 fn flush(&mut self) -> Result<()> { 37 fn flush(&mut self) -> Result<()> {
39 self.io.flush() 38 self.io.flush()
40 } 39 }
diff --git a/src/zip/driver.rs b/src/zip/driver.rs
index 0905d9a..87f9c1a 100644
--- a/src/zip/driver.rs
+++ b/src/zip/driver.rs
@@ -3,7 +3,8 @@ use crate::utils::ReadUtils;
3use crate::zip::cp437::FromCp437; 3use crate::zip::cp437::FromCp437;
4use crate::zip::structs::{deserialize, Cdr, Eocdr, Eocdr64, Eocdr64Locator, ExtraHeader}; 4use crate::zip::structs::{deserialize, Cdr, Eocdr, Eocdr64, Eocdr64Locator, ExtraHeader};
5use crate::zip::{ 5use crate::zip::{
6 BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult, 6 BitFlag, CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipFileReader,
7 ZipFileWriter, ZipResult,
7}; 8};
8use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime}; 9use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime};
9use std::collections::HashMap as Map; 10use std::collections::HashMap as Map;
@@ -220,6 +221,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
220 indexes.insert(name.clone(), i); 221 indexes.insert(name.clone(), i);
221 files.push(ZipFileInfo::new( 222 files.push(ZipFileInfo::new(
222 CompressionMethod::from_struct_id(cdr.compression_method)?, 223 CompressionMethod::from_struct_id(cdr.compression_method)?,
224 EncryptionMethod::from_bit_flag(bit_flag),
223 bit_flag, 225 bit_flag,
224 mtime, 226 mtime,
225 atime, 227 atime,
@@ -256,10 +258,15 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
256 self.files.get(index).ok_or(ZipError::FileNotFound.into()) 258 self.files.get(index).ok_or(ZipError::FileNotFound.into())
257 } 259 }
258 260
259 fn get_file_reader<'d>(&'d mut self, index: usize) -> ZipResult<Self::FileReader<'d>> { 261 fn get_file_reader<'d>(
262 &'d mut self,
263 index: usize,
264 password: Option<&str>,
265 ) -> ZipResult<Self::FileReader<'d>> {
260 Ok(ZipFileReader::new( 266 Ok(ZipFileReader::new(
261 &mut self.io, 267 &mut self.io,
262 self.files.get(index).ok_or(ZipError::FileNotFound)?, 268 self.files.get(index).ok_or(ZipError::FileNotFound)?,
269 password,
263 )?) 270 )?)
264 } 271 }
265} 272}
diff --git a/src/zip/encryption.rs b/src/zip/encryption.rs
new file mode 100644
index 0000000..84e30d5
--- /dev/null
+++ b/src/zip/encryption.rs
@@ -0,0 +1,62 @@
1use crate::utils::ReadUtils;
2use crate::zip::ZipResult;
3use crc32fast::Hasher;
4use std::io::{Read, Result as IoResult};
5
6fn crc32(byte: u8, crc32: u32) -> u32 {
7 let mut hasher = Hasher::new_with_initial(crc32 ^ 0xFFFFFFFF);
8 hasher.update(&[byte]);
9 hasher.finalize() ^ 0xFFFFFFFF
10}
11
12pub struct WeakDecoder<Io: Read> {
13 key0: u32,
14 key1: u32,
15 key2: u32,
16 io: Io,
17}
18
19impl<Io: Read> WeakDecoder<Io> {
20 pub fn new(io: Io, password: &str) -> ZipResult<Self> {
21 let mut decoder = Self {
22 key0: 305419896,
23 key1: 591751049,
24 key2: 878082192,
25 io,
26 };
27
28 for c in password.chars() {
29 decoder.update_keys(c as u8)
30 }
31
32 let buf = decoder.read_arr::<12>()?;
33
34 Ok(decoder)
35 }
36
37 fn update_keys(&mut self, byte: u8) {
38 self.key0 = crc32(byte, self.key0);
39 self.key1 = self
40 .key1
41 .wrapping_add(self.key0 & 0xFF)
42 .wrapping_mul(134775813)
43 .wrapping_add(1);
44 self.key2 = crc32((self.key1 >> 24) as u8, self.key2);
45 }
46
47 fn decode_byte(&mut self, byte: u8) -> u8 {
48 let key = self.key2 | 2;
49 byte ^ (((key * (key ^ 1)) >> 8) as u8)
50 }
51}
52
53impl<Io: Read> Read for WeakDecoder<Io> {
54 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
55 let bytes = self.io.read(buf)?;
56 for i in 0..bytes {
57 buf[i] = self.decode_byte(buf[i]);
58 self.update_keys(buf[i])
59 }
60 Ok(bytes)
61 }
62}
diff --git a/src/zip/error.rs b/src/zip/error.rs
index 3eb68b8..9ec0956 100644
--- a/src/zip/error.rs
+++ b/src/zip/error.rs
@@ -11,15 +11,18 @@ pub enum ZipError {
11 InvalidFileHeaderSignature, 11 InvalidFileHeaderSignature,
12 InvalidCDRSignature, 12 InvalidCDRSignature,
13 13
14 InvalidCompressionMethod, 14 InvalidCompressionMethod(u16),
15 UnsupportedCompressionMethod, 15 UnsupportedCompressionMethod(u16),
16 UnsupportedEncryptionMethod,
16 InvalidDate, 17 InvalidDate,
17 InvalidTime, 18 InvalidTime,
18 InvalidFileName, 19 InvalidFileName,
19 InvalidFileComment, 20 InvalidFileComment,
20 21
21 FileNotFound, 22 FileNotFound,
23 PasswordIsNotSpecified,
22 CompressedDataIsUnseekable, 24 CompressedDataIsUnseekable,
25 EncryptedDataIsUnseekable,
23} 26}
24 27
25impl From<ZipError> for ArchiveError<ZipError> { 28impl From<ZipError> for ArchiveError<ZipError> {
@@ -48,15 +51,24 @@ impl Display for ZipError {
48 write!(f, "Invalid signature of central directory record") 51 write!(f, "Invalid signature of central directory record")
49 } 52 }
50 53
51 Self::InvalidCompressionMethod => writeln!(f, "Invalid compression method"), 54 Self::InvalidCompressionMethod(id) => {
52 Self::UnsupportedCompressionMethod => writeln!(f, "Unsupported compression method"), 55 writeln!(f, "Invalid compression method {}", id)
56 }
57 Self::UnsupportedCompressionMethod(id) => {
58 writeln!(f, "Unsupported compression method {}", id)
59 }
60 Self::UnsupportedEncryptionMethod => {
61 writeln!(f, "Unsupported encryption method")
62 }
53 Self::InvalidDate => write!(f, "Invalid date"), 63 Self::InvalidDate => write!(f, "Invalid date"),
54 Self::InvalidTime => write!(f, "Invalid time"), 64 Self::InvalidTime => write!(f, "Invalid time"),
55 Self::InvalidFileName => write!(f, "Invalid file name"), 65 Self::InvalidFileName => write!(f, "Invalid file name"),
56 Self::InvalidFileComment => write!(f, "Invalid file comment"), 66 Self::InvalidFileComment => write!(f, "Invalid file comment"),
57 67
58 Self::FileNotFound => write!(f, "File not found"), 68 Self::FileNotFound => write!(f, "File not found"),
69 Self::PasswordIsNotSpecified => write!(f, "Password is not specified"),
59 Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), 70 Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"),
71 Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"),
60 } 72 }
61 } 73 }
62} 74}
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs
index 4e1b293..f5d4d8a 100644
--- a/src/zip/file/info.rs
+++ b/src/zip/file/info.rs
@@ -2,7 +2,7 @@ use crate::driver::ArchiveFileInfo;
2use crate::zip::{ZipError, ZipResult}; 2use crate::zip::{ZipError, ZipResult};
3use chrono::{DateTime, Local}; 3use chrono::{DateTime, Local};
4 4
5#[derive(Debug, Clone)] 5#[derive(Debug, PartialEq, Eq, Clone, Copy)]
6pub enum CompressionMethod { 6pub enum CompressionMethod {
7 Store, 7 Store,
8 Deflate, 8 Deflate,
@@ -10,31 +10,49 @@ pub enum CompressionMethod {
10 Lzma, 10 Lzma,
11 Zstd, 11 Zstd,
12 Xz, 12 Xz,
13 Unsupported, 13 Unsupported(u16),
14} 14}
15 15
16impl CompressionMethod { 16impl CompressionMethod {
17 pub(crate) fn from_struct_id(id: u16) -> ZipResult<Self> { 17 pub(crate) fn from_struct_id(id: u16) -> ZipResult<Self> {
18 match id { 18 Ok(match id {
19 0 => Ok(Self::Store), 19 0 => Self::Store,
20 8 => Ok(Self::Deflate), 20 8 => Self::Deflate,
21 12 => Ok(Self::BZip2), 21 12 => Self::BZip2,
22 14 => Ok(Self::Lzma), 22 14 => Self::Lzma,
23 93 => Ok(Self::Zstd), 23 93 => Self::Zstd,
24 95 => Ok(Self::Xz), 24 95 => Self::Xz,
25 1..=7 | 9..=11 | 13 | 15..=20 | 94 | 96..=99 => Ok(Self::Unsupported), 25 1..=7 | 9..=11 | 13 | 15..=20 | 94 | 96..=99 => Self::Unsupported(id),
26 21..=92 | 100.. => Err(ZipError::InvalidCompressionMethod.into()), 26 21..=92 | 100.. => return Err(ZipError::InvalidCompressionMethod(id).into()),
27 })
28 }
29}
30
31#[derive(Debug, PartialEq, Eq, Clone, Copy)]
32pub enum EncryptionMethod {
33 None,
34 Weak,
35 Unsupported,
36}
37
38impl EncryptionMethod {
39 pub(crate) fn from_bit_flag(bit_flag: BitFlag) -> EncryptionMethod {
40 match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) {
41 (false, false) => EncryptionMethod::None,
42 (true, false) => EncryptionMethod::Weak,
43 (true, true) => EncryptionMethod::Unsupported,
44 _ => panic!("impossible"),
27 } 45 }
28 } 46 }
29} 47}
30 48
31#[derive(Debug, Clone)] 49#[derive(Debug, PartialEq, Eq, Clone, Copy)]
32pub struct BitFlag { 50pub struct BitFlag {
33 flag: u16, 51 flag: u16,
34} 52}
35 53
36pub mod bit { 54pub mod bit {
37 #[derive(Debug, PartialEq, Eq)] 55 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
38 pub enum DeflateMode { 56 pub enum DeflateMode {
39 Normal, 57 Normal,
40 Maximum, 58 Maximum,
@@ -123,6 +141,7 @@ impl BitFlag {
123#[derive(Debug, Clone)] 141#[derive(Debug, Clone)]
124pub struct ZipFileInfo { 142pub struct ZipFileInfo {
125 pub compression_method: CompressionMethod, 143 pub compression_method: CompressionMethod,
144 pub encryption_method: EncryptionMethod,
126 pub bit_flag: BitFlag, 145 pub bit_flag: BitFlag,
127 pub mtime: DateTime<Local>, 146 pub mtime: DateTime<Local>,
128 pub atime: Option<DateTime<Local>>, 147 pub atime: Option<DateTime<Local>>,
@@ -138,6 +157,7 @@ pub struct ZipFileInfo {
138impl ZipFileInfo { 157impl ZipFileInfo {
139 pub fn new( 158 pub fn new(
140 compression_method: CompressionMethod, 159 compression_method: CompressionMethod,
160 encryption_method: EncryptionMethod,
141 bit_flag: BitFlag, 161 bit_flag: BitFlag,
142 mtime: DateTime<Local>, 162 mtime: DateTime<Local>,
143 atime: Option<DateTime<Local>>, 163 atime: Option<DateTime<Local>>,
@@ -151,6 +171,7 @@ impl ZipFileInfo {
151 ) -> Self { 171 ) -> Self {
152 Self { 172 Self {
153 compression_method, 173 compression_method,
174 encryption_method,
154 bit_flag, 175 bit_flag,
155 mtime, 176 mtime,
156 atime, 177 atime,
diff --git a/src/zip/file/mod.rs b/src/zip/file/mod.rs
index 43ccc04..ce3c21d 100644
--- a/src/zip/file/mod.rs
+++ b/src/zip/file/mod.rs
@@ -2,6 +2,6 @@ mod info;
2mod read; 2mod read;
3mod write; 3mod write;
4 4
5pub use info::{bit, BitFlag, CompressionMethod, ZipFileInfo}; 5pub use info::{bit, BitFlag, CompressionMethod, EncryptionMethod, ZipFileInfo};
6pub use read::ZipFileReader; 6pub use read::ZipFileReader;
7pub use write::ZipFileWriter; 7pub use write::ZipFileWriter;
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs
index f5a54f3..aa665c3 100644
--- a/src/zip/file/read.rs
+++ b/src/zip/file/read.rs
@@ -1,6 +1,7 @@
1use crate::driver::FileDriver; 1use crate::driver::FileDriver;
2use crate::utils::{IoCursor, ReadUtils}; 2use crate::utils::{IoCursor, ReadUtils};
3use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult}; 3use crate::zip::encryption::WeakDecoder;
4use crate::zip::{CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipResult};
4use bzip2::read::BzDecoder; 5use bzip2::read::BzDecoder;
5use flate2::read::DeflateDecoder; 6use flate2::read::DeflateDecoder;
6use liblzma::read::XzDecoder; 7use liblzma::read::XzDecoder;
@@ -10,6 +11,47 @@ use std::io::{
10}; 11};
11use zstd::stream::Decoder as ZstdDecoder; 12use zstd::stream::Decoder as ZstdDecoder;
12 13
14enum Encryption<Io: Read> {
15 None(Io),
16 Weak(WeakDecoder<Io>),
17}
18
19impl<Io: Read> Encryption<Io> {
20 pub fn new(io: Io, method: EncryptionMethod, password: Option<&str>) -> ZipResult<Self> {
21 Ok(match method {
22 EncryptionMethod::None => Self::None(io),
23 EncryptionMethod::Weak => Self::Weak(WeakDecoder::new(
24 io,
25 password.ok_or(ZipError::PasswordIsNotSpecified)?,
26 )?),
27 EncryptionMethod::Unsupported => {
28 return Err(ZipError::UnsupportedEncryptionMethod.into())
29 }
30 })
31 }
32}
33
34impl<Io: Read> Read for Encryption<Io> {
35 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
36 match self {
37 Self::None(io) => io.read(buf),
38 Self::Weak(io) => io.read(buf),
39 }
40 }
41}
42
43impl<Io: Read + Seek> Seek for Encryption<Io> {
44 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
45 match self {
46 Self::None(io) => io.seek(pos),
47 _ => Err(IoError::new(
48 IoErrorKind::Unsupported,
49 ZipError::EncryptedDataIsUnseekable,
50 )),
51 }
52 }
53}
54
13enum Compression<Io: Read> { 55enum Compression<Io: Read> {
14 Store(Io), 56 Store(Io),
15 Deflate(DeflateDecoder<Io>), 57 Deflate(DeflateDecoder<Io>),
@@ -18,8 +60,48 @@ enum Compression<Io: Read> {
18 Xz(XzDecoder<Io>), 60 Xz(XzDecoder<Io>),
19} 61}
20 62
63impl<Io: Read + Seek> Compression<Io> {
64 pub fn new(io: Io, method: CompressionMethod) -> ZipResult<Self> {
65 Ok(match method {
66 CompressionMethod::Store => Self::Store(io),
67 CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)),
68 CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)),
69 CompressionMethod::Lzma => panic!(),
70 CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?),
71 CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)),
72 CompressionMethod::Unsupported(id) => {
73 return Err(ZipError::UnsupportedCompressionMethod(id).into())
74 }
75 })
76 }
77}
78
79impl<Io: Read> Read for Compression<Io> {
80 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
81 match self {
82 Compression::Store(io) => io.read(buf),
83 Compression::Deflate(io) => io.read(buf),
84 Compression::BZip2(io) => io.read(buf),
85 Compression::Zstd(io) => io.read(buf),
86 Compression::Xz(io) => io.read(buf),
87 }
88 }
89}
90
91impl<Io: Read + Seek> Seek for Compression<Io> {
92 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
93 match self {
94 Compression::Store(io) => io.seek(pos),
95 _ => Err(IoError::new(
96 IoErrorKind::Unsupported,
97 ZipError::CompressedDataIsUnseekable,
98 )),
99 }
100 }
101}
102
21pub struct ZipFileReader<'d, Io: Read> { 103pub struct ZipFileReader<'d, Io: Read> {
22 io: Compression<IoCursor<&'d mut Io>>, 104 io: Compression<Encryption<IoCursor<&'d mut Io>>>,
23 info: &'d ZipFileInfo, 105 info: &'d ZipFileInfo,
24} 106}
25 107
@@ -33,7 +115,7 @@ impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> {
33} 115}
34 116
35impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { 117impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
36 pub fn new(io: &'d mut Io, info: &'d ZipFileInfo) -> ZipResult<Self> { 118 pub fn new(io: &'d mut Io, info: &'d ZipFileInfo, password: Option<&str>) -> ZipResult<Self> {
37 io.seek(SeekFrom::Start(info.header_pointer))?; 119 io.seek(SeekFrom::Start(info.header_pointer))?;
38 120
39 let buf = io.read_arr::<30>()?; 121 let buf = io.read_arr::<30>()?;
@@ -45,27 +127,22 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
45 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 127 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64
46 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; 128 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64;
47 129
130 io.seek(SeekFrom::Start(data_pointer))?;
131
48 Ok(Self { 132 Ok(Self {
49 io: match info.compression_method { 133 io: match info.compression_method {
50 CompressionMethod::Store => Compression::Store(IoCursor::new(
51 io,
52 data_pointer,
53 data_pointer + info.compressed_size,
54 )?),
55 CompressionMethod::Deflate => Compression::Deflate(DeflateDecoder::new(
56 IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?,
57 )),
58 CompressionMethod::BZip2 => Compression::BZip2(BzDecoder::new(IoCursor::new(
59 io,
60 data_pointer,
61 data_pointer + info.compressed_size,
62 )?)),
63 CompressionMethod::Lzma => { 134 CompressionMethod::Lzma => {
64 io.seek(SeekFrom::Start(data_pointer))?;
65 let buf = io.read_arr::<9>()?; 135 let buf = io.read_arr::<9>()?;
66
67 Compression::Xz(XzDecoder::new_stream( 136 Compression::Xz(XzDecoder::new_stream(
68 IoCursor::new(io, data_pointer + 9, data_pointer + info.compressed_size)?, 137 Encryption::new(
138 IoCursor::new(
139 io,
140 data_pointer + 9,
141 data_pointer + info.compressed_size,
142 )?,
143 info.encryption_method,
144 password,
145 )?,
69 Stream::new_raw_decoder( 146 Stream::new_raw_decoder(
70 Filters::new().lzma1( 147 Filters::new().lzma1(
71 LzmaOptions::new() 148 LzmaOptions::new()
@@ -80,30 +157,22 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
80 .unwrap(), 157 .unwrap(),
81 )) 158 ))
82 } 159 }
83 CompressionMethod::Zstd => Compression::Zstd( 160 _ => Compression::new(
84 ZstdDecoder::new(IoCursor::new( 161 Encryption::new(
85 io, 162 IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?,
86 data_pointer, 163 info.encryption_method,
87 data_pointer + info.compressed_size, 164 password,
88 )?) 165 )?,
89 .unwrap(), 166 info.compression_method,
90 ), 167 )?,
91 CompressionMethod::Xz => Compression::Xz(XzDecoder::new(IoCursor::new(
92 io,
93 data_pointer,
94 data_pointer + info.compressed_size,
95 )?)),
96 CompressionMethod::Unsupported => {
97 return Err(ZipError::UnsupportedCompressionMethod.into())
98 }
99 }, 168 },
100 info, 169 info,
101 }) 170 })
102 } 171 }
103 172
104 pub fn seekable(&self) -> bool { 173 pub fn is_seekable(&self) -> bool {
105 match self.io { 174 match self.io {
106 Compression::Store(..) => true, 175 Compression::Store(Encryption::None(..)) => true,
107 _ => false, 176 _ => false,
108 } 177 }
109 } 178 }
@@ -111,24 +180,12 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
111 180
112impl<'d, Io: Read> Read for ZipFileReader<'d, Io> { 181impl<'d, Io: Read> Read for ZipFileReader<'d, Io> {
113 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { 182 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
114 match &mut self.io { 183 self.io.read(buf)
115 Compression::Store(io) => io.read(buf),
116 Compression::Deflate(io) => io.read(buf),
117 Compression::BZip2(io) => io.read(buf),
118 Compression::Zstd(io) => io.read(buf),
119 Compression::Xz(io) => io.read(buf),
120 }
121 } 184 }
122} 185}
123 186
124impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> { 187impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> {
125 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { 188 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
126 match &mut self.io { 189 self.io.seek(pos)
127 Compression::Store(io) => io.seek(pos),
128 _ => Err(IoError::new(
129 IoErrorKind::Unsupported,
130 ZipError::CompressedDataIsUnseekable,
131 )),
132 }
133 } 190 }
134} 191}
diff --git a/src/zip/mod.rs b/src/zip/mod.rs
index bcc34ed..fcc6161 100644
--- a/src/zip/mod.rs
+++ b/src/zip/mod.rs
@@ -1,13 +1,16 @@
1mod archive; 1mod archive;
2mod cp437; 2mod cp437;
3mod driver; 3mod driver;
4mod encryption;
4mod error; 5mod error;
5mod file; 6mod file;
6mod structs; 7mod structs;
7 8
8pub use driver::Zip; 9pub use driver::Zip;
9pub use error::{ZipError, ZipResult}; 10pub use error::{ZipError, ZipResult};
10pub use file::{bit, BitFlag, CompressionMethod, ZipFileInfo, ZipFileReader, ZipFileWriter}; 11pub use file::{
12 bit, BitFlag, CompressionMethod, EncryptionMethod, ZipFileInfo, ZipFileReader, ZipFileWriter,
13};
11 14
12#[cfg(test)] 15#[cfg(test)]
13mod tests; 16mod tests;