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