aboutsummaryrefslogtreecommitdiff
path: root/src/zip/file
diff options
context:
space:
mode:
Diffstat (limited to 'src/zip/file')
-rw-r--r--src/zip/file/info.rs7
-rw-r--r--src/zip/file/read.rs106
-rw-r--r--src/zip/file/write.rs4
3 files changed, 55 insertions, 62 deletions
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs
index bfec0b7..4e1b293 100644
--- a/src/zip/file/info.rs
+++ b/src/zip/file/info.rs
@@ -8,7 +8,9 @@ pub enum CompressionMethod {
8 Deflate, 8 Deflate,
9 BZip2, 9 BZip2,
10 Lzma, 10 Lzma,
11 Zstd,
11 Xz, 12 Xz,
13 Unsupported,
12} 14}
13 15
14impl CompressionMethod { 16impl CompressionMethod {
@@ -18,10 +20,9 @@ impl CompressionMethod {
18 8 => Ok(Self::Deflate), 20 8 => Ok(Self::Deflate),
19 12 => Ok(Self::BZip2), 21 12 => Ok(Self::BZip2),
20 14 => Ok(Self::Lzma), 22 14 => Ok(Self::Lzma),
23 93 => Ok(Self::Zstd),
21 95 => Ok(Self::Xz), 24 95 => Ok(Self::Xz),
22 1..=7 | 9..=11 | 13 | 15..=20 | 93..=94 | 96..=99 => { 25 1..=7 | 9..=11 | 13 | 15..=20 | 94 | 96..=99 => Ok(Self::Unsupported),
23 Err(ZipError::UnsupportedCompressionMethod.into())
24 }
25 21..=92 | 100.. => Err(ZipError::InvalidCompressionMethod.into()), 26 21..=92 | 100.. => Err(ZipError::InvalidCompressionMethod.into()),
26 } 27 }
27 } 28 }
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs
index 7d683db..f5a54f3 100644
--- a/src/zip/file/read.rs
+++ b/src/zip/file/read.rs
@@ -1,27 +1,26 @@
1use crate::driver::FileDriver; 1use crate::driver::FileDriver;
2use crate::utils::ReadUtils; 2use crate::utils::{IoCursor, ReadUtils};
3use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult}; 3use crate::zip::{CompressionMethod, ZipError, ZipFileInfo, ZipResult};
4use bzip2::read::BzDecoder; 4use bzip2::read::BzDecoder;
5use flate2::read::DeflateDecoder; 5use flate2::read::DeflateDecoder;
6use liblzma::read::XzDecoder; 6use liblzma::read::XzDecoder;
7use liblzma::stream::{Filters, LzmaOptions, Stream}; 7use liblzma::stream::{Filters, LzmaOptions, Stream};
8use std::io::{ 8use std::io::{
9 Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, 9 BufReader, Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom,
10}; 10};
11use zstd::stream::Decoder as ZstdDecoder;
11 12
12enum IoProxy<Io: Read> { 13enum Compression<Io: Read> {
13 Store(Io), 14 Store(Io),
14 Deflate(DeflateDecoder<Io>), 15 Deflate(DeflateDecoder<Io>),
15 BZip2(BzDecoder<Io>), 16 BZip2(BzDecoder<Io>),
17 Zstd(ZstdDecoder<'static, BufReader<Io>>),
16 Xz(XzDecoder<Io>), 18 Xz(XzDecoder<Io>),
17} 19}
18 20
19pub struct ZipFileReader<'d, Io: Read> { 21pub struct ZipFileReader<'d, Io: Read> {
20 io: IoProxy<&'d mut Io>, 22 io: Compression<IoCursor<&'d mut Io>>,
21 info: &'d ZipFileInfo, 23 info: &'d ZipFileInfo,
22
23 bounds: (u64, u64),
24 cursor: u64,
25} 24}
26 25
27impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { 26impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> {
@@ -36,8 +35,8 @@ impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> {
36impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { 35impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
37 pub fn new(io: &'d mut Io, info: &'d ZipFileInfo) -> ZipResult<Self> { 36 pub fn new(io: &'d mut Io, info: &'d ZipFileInfo) -> ZipResult<Self> {
38 io.seek(SeekFrom::Start(info.header_pointer))?; 37 io.seek(SeekFrom::Start(info.header_pointer))?;
39 let buf = io.read_arr::<30>()?;
40 38
39 let buf = io.read_arr::<30>()?;
41 if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { 40 if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 {
42 return Err(ZipError::InvalidFileHeaderSignature.into()); 41 return Err(ZipError::InvalidFileHeaderSignature.into());
43 } 42 }
@@ -45,18 +44,28 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
45 + 30 44 + 30
46 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 45 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64
47 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; 46 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64;
48 let mut cursor = io.seek(SeekFrom::Start(data_pointer))?;
49 47
50 Ok(Self { 48 Ok(Self {
51 io: match info.compression_method { 49 io: match info.compression_method {
52 CompressionMethod::Store => IoProxy::Store(io), 50 CompressionMethod::Store => Compression::Store(IoCursor::new(
53 CompressionMethod::Deflate => IoProxy::Deflate(DeflateDecoder::new(io)), 51 io,
54 CompressionMethod::BZip2 => IoProxy::BZip2(BzDecoder::new(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 )?)),
55 CompressionMethod::Lzma => { 63 CompressionMethod::Lzma => {
64 io.seek(SeekFrom::Start(data_pointer))?;
56 let buf = io.read_arr::<9>()?; 65 let buf = io.read_arr::<9>()?;
57 cursor += 9; 66
58 IoProxy::Xz(XzDecoder::new_stream( 67 Compression::Xz(XzDecoder::new_stream(
59 io, 68 IoCursor::new(io, data_pointer + 9, data_pointer + info.compressed_size)?,
60 Stream::new_raw_decoder( 69 Stream::new_raw_decoder(
61 Filters::new().lzma1( 70 Filters::new().lzma1(
62 LzmaOptions::new() 71 LzmaOptions::new()
@@ -71,18 +80,30 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
71 .unwrap(), 80 .unwrap(),
72 )) 81 ))
73 } 82 }
74 CompressionMethod::Xz => IoProxy::Xz(XzDecoder::new(io)), 83 CompressionMethod::Zstd => Compression::Zstd(
84 ZstdDecoder::new(IoCursor::new(
85 io,
86 data_pointer,
87 data_pointer + info.compressed_size,
88 )?)
89 .unwrap(),
90 ),
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 }
75 }, 99 },
76 info, 100 info,
77
78 bounds: (cursor, data_pointer + info.compressed_size),
79 cursor,
80 }) 101 })
81 } 102 }
82 103
83 pub fn seekable(&self) -> bool { 104 pub fn seekable(&self) -> bool {
84 match self.io { 105 match self.io {
85 IoProxy::Store(..) => true, 106 Compression::Store(..) => true,
86 _ => false, 107 _ => false,
87 } 108 }
88 } 109 }
@@ -90,49 +111,20 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
90 111
91impl<'d, Io: Read> Read for ZipFileReader<'d, Io> { 112impl<'d, Io: Read> Read for ZipFileReader<'d, Io> {
92 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { 113 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
93 let upper = buf.len().min((self.bounds.1 - self.cursor) as usize); 114 match &mut self.io {
94 let bytes = match &mut self.io { 115 Compression::Store(io) => io.read(buf),
95 IoProxy::Store(io) => io.read(&mut buf[..upper]), 116 Compression::Deflate(io) => io.read(buf),
96 IoProxy::Deflate(io) => io.read(&mut buf[..upper]), 117 Compression::BZip2(io) => io.read(buf),
97 IoProxy::BZip2(io) => io.read(&mut buf[..upper]), 118 Compression::Zstd(io) => io.read(buf),
98 IoProxy::Xz(io) => io.read(&mut buf[..upper]), 119 Compression::Xz(io) => io.read(buf),
99 }?; 120 }
100 self.cursor += upper as u64;
101 Ok(bytes)
102 } 121 }
103} 122}
104 123
105impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> { 124impl<'d, Io: Read + Seek> Seek for ZipFileReader<'d, Io> {
106 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { 125 fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
107 match &mut self.io { 126 match &mut self.io {
108 IoProxy::Store(io) => { 127 Compression::Store(io) => io.seek(pos),
109 self.cursor = match pos {
110 SeekFrom::Start(offset) => self.bounds.0 + offset,
111 SeekFrom::End(offset) => {
112 let cursor = self.bounds.1.saturating_add_signed(offset);
113 if cursor < self.bounds.0 {
114 return Err(IoError::new(
115 IoErrorKind::InvalidInput,
116 ZipError::NegativeFileOffset,
117 ));
118 }
119 cursor
120 }
121 SeekFrom::Current(offset) => {
122 let cursor = self.cursor.saturating_add_signed(offset);
123 if cursor < self.bounds.0 {
124 return Err(IoError::new(
125 IoErrorKind::InvalidInput,
126 ZipError::NegativeFileOffset,
127 ));
128 }
129 cursor
130 }
131 }
132 .min(self.bounds.1);
133
134 Ok(io.seek(SeekFrom::Start(self.cursor))? - self.bounds.0)
135 }
136 _ => Err(IoError::new( 128 _ => Err(IoError::new(
137 IoErrorKind::Unsupported, 129 IoErrorKind::Unsupported,
138 ZipError::CompressedDataIsUnseekable, 130 ZipError::CompressedDataIsUnseekable,
diff --git a/src/zip/file/write.rs b/src/zip/file/write.rs
index 6f5756a..d20c378 100644
--- a/src/zip/file/write.rs
+++ b/src/zip/file/write.rs
@@ -5,7 +5,7 @@ use flate2::write::DeflateEncoder;
5use liblzma::write::XzEncoder; 5use liblzma::write::XzEncoder;
6use std::io::Write; 6use std::io::Write;
7 7
8enum IoProxy<Io: Write> { 8enum Compression<Io: Write> {
9 Store(Io), 9 Store(Io),
10 Deflate(DeflateEncoder<Io>), 10 Deflate(DeflateEncoder<Io>),
11 BZip2(BzEncoder<Io>), 11 BZip2(BzEncoder<Io>),
@@ -13,7 +13,7 @@ enum IoProxy<Io: Write> {
13} 13}
14 14
15pub struct ZipFileWriter<'d, Io: Write> { 15pub struct ZipFileWriter<'d, Io: Write> {
16 io: IoProxy<&'d mut Io>, 16 io: Compression<&'d mut Io>,
17 info: &'d ZipFileInfo, 17 info: &'d ZipFileInfo,
18 18
19 bounds: (u64, u64), 19 bounds: (u64, u64),