async_zip/base/read/
stream.rs1use crate::base::read::counting::Counting;
50use crate::base::read::io::entry::ZipEntryReader;
51use crate::error::Result;
52use crate::error::ZipError;
53use crate::spec::data_descriptor::{CombinedDataDescriptor, DataDescriptor, Zip64DataDescriptor};
54#[cfg(feature = "tokio")]
55use crate::tokio::read::stream::Ready as TokioReady;
56
57use futures_lite::io::AsyncBufRead;
58use futures_lite::io::AsyncReadExt;
59
60use super::io::entry::WithEntry;
61use super::io::entry::WithoutEntry;
62use crate::spec::header::HeaderId;
63#[cfg(feature = "tokio")]
64use tokio_util::compat::TokioAsyncReadCompatExt;
65
66pub struct Ready<R>(R);
68
69pub struct Reading<'a, R, E>(ZipEntryReader<'a, R, E>, Option<Suffix>);
71
72#[derive(Copy, Clone, Debug)]
73enum Suffix {
74 DataDescriptor,
76 Zip64DataDescriptor,
78}
79
80#[derive(Clone)]
84pub struct ZipFileReader<S>(S);
85
86impl<'a, R> ZipFileReader<Ready<Counting<R>>>
87where
88 R: AsyncBufRead + Unpin + 'a,
89{
90 pub fn new(reader: R) -> Self {
92 Self(Ready(Counting::new(reader)))
93 }
94
95 pub async fn next_without_entry(mut self) -> Result<Option<ZipFileReader<Reading<'a, Counting<R>, WithoutEntry>>>> {
97 let file_offset = self.0 .0.bytes_read();
98 let entry = match crate::base::read::lfh(&mut self.0 .0, file_offset).await? {
99 Some(entry) => entry,
100 None => return Ok(None),
101 };
102
103 let length = if entry.data_descriptor { u64::MAX } else { entry.compressed_size };
104 let reader = ZipEntryReader::new_with_owned(self.0 .0, entry.compression, length);
105
106 let suffix = if entry.data_descriptor {
107 if entry.extra_fields.iter().any(|ef| ef.header_id() == HeaderId::ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD) {
108 Some(Suffix::Zip64DataDescriptor)
109 } else {
110 Some(Suffix::DataDescriptor)
111 }
112 } else {
113 None
114 };
115
116 Ok(Some(ZipFileReader(Reading(reader, suffix))))
117 }
118
119 pub async fn next_with_entry(mut self) -> Result<Option<ZipFileReader<Reading<'a, Counting<R>, WithEntry<'a>>>>> {
121 let file_offset = self.0 .0.bytes_read();
122 let entry = match crate::base::read::lfh(&mut self.0 .0, file_offset).await? {
123 Some(entry) => entry,
124 None => return Ok(None),
125 };
126
127 let length = if entry.data_descriptor { u64::MAX } else { entry.compressed_size };
128 let reader = ZipEntryReader::new_with_owned(self.0 .0, entry.compression, length);
129
130 let suffix = if entry.data_descriptor {
131 if entry.extra_fields.iter().any(|ef| ef.header_id() == HeaderId::ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD) {
132 Some(Suffix::Zip64DataDescriptor)
133 } else {
134 Some(Suffix::DataDescriptor)
135 }
136 } else {
137 None
138 };
139
140 Ok(Some(ZipFileReader(Reading(reader.into_with_entry_owned(entry), suffix))))
141 }
142
143 pub async fn into_inner(self) -> R {
145 self.0 .0.into_inner()
146 }
147
148 pub fn offset(&self) -> u64 {
150 self.0 .0.bytes_read()
151 }
152}
153
154#[cfg(feature = "tokio")]
155impl<R> ZipFileReader<TokioReady<R>>
156where
157 R: tokio::io::AsyncBufRead + Unpin,
158{
159 pub fn with_tokio(reader: R) -> ZipFileReader<TokioReady<R>> {
161 Self(Ready(reader.compat()))
162 }
163}
164
165type Next<R> = (Option<CombinedDataDescriptor>, ZipFileReader<Ready<R>>);
166
167impl<'a, R, E> ZipFileReader<Reading<'a, R, E>>
168where
169 R: AsyncBufRead + Unpin,
170{
171 pub fn reader(&self) -> &ZipEntryReader<'a, R, E> {
173 &self.0 .0
174 }
175
176 pub fn reader_mut(&mut self) -> &mut ZipEntryReader<'a, R, E> {
178 &mut self.0 .0
179 }
180
181 pub async fn done(mut self) -> Result<Next<R>> {
183 if self.0 .0.read(&mut [0; 1]).await? != 0 {
184 return Err(ZipError::EOFNotReached);
185 }
186
187 let mut inner = self.0 .0.into_inner();
188
189 let data_descriptor = match self.0 .1 {
190 Some(Suffix::DataDescriptor) => {
191 Some(CombinedDataDescriptor::from(DataDescriptor::from_reader(&mut inner).await?))
192 }
193 Some(Suffix::Zip64DataDescriptor) => {
194 Some(CombinedDataDescriptor::from(Zip64DataDescriptor::from_reader(&mut inner).await?))
195 }
196 None => None,
197 };
198
199 let reader = ZipFileReader(Ready(inner));
200
201 Ok((data_descriptor, reader))
202 }
203
204 pub async fn skip(mut self) -> Result<Next<R>> {
206 while self.0 .0.read(&mut [0; 2048]).await? != 0 {}
207 let mut inner = self.0 .0.into_inner();
208
209 let data_descriptor = match self.0 .1 {
210 Some(Suffix::DataDescriptor) => {
211 Some(CombinedDataDescriptor::from(DataDescriptor::from_reader(&mut inner).await?))
212 }
213 Some(Suffix::Zip64DataDescriptor) => {
214 Some(CombinedDataDescriptor::from(Zip64DataDescriptor::from_reader(&mut inner).await?))
215 }
216 None => None,
217 };
218
219 let reader = ZipFileReader(Ready(inner));
220
221 Ok((data_descriptor, reader))
222 }
223}