aboutsummaryrefslogtreecommitdiff
path: root/src/zip/file
diff options
context:
space:
mode:
Diffstat (limited to 'src/zip/file')
-rw-r--r--src/zip/file/info.rs47
-rw-r--r--src/zip/file/mod.rs2
-rw-r--r--src/zip/file/read.rs159
3 files changed, 143 insertions, 65 deletions
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}