aboutsummaryrefslogtreecommitdiff
path: root/src/zip/file/read.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/zip/file/read.rs')
-rw-r--r--src/zip/file/read.rs106
1 files changed, 49 insertions, 57 deletions
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,