use crate::base::read::io::entry::ZipEntryReader;
use crate::error::Result;
use crate::error::ZipError;
use crate::spec::consts::DATA_DESCRIPTOR_LENGTH;
use crate::spec::consts::DATA_DESCRIPTOR_SIGNATURE;
use crate::spec::consts::SIGNATURE_LENGTH;
#[cfg(feature = "tokio")]
use crate::tokio::read::stream::Ready as TokioReady;
use futures_lite::io::AsyncBufRead;
use futures_lite::io::AsyncReadExt;
#[cfg(feature = "tokio")]
use tokio_util::compat::TokioAsyncReadCompatExt;
use super::io::entry::WithEntry;
use super::io::entry::WithoutEntry;
pub struct Ready<R>(R);
pub struct Reading<'a, R, E>(ZipEntryReader<'a, R, E>, bool);
#[derive(Clone)]
pub struct ZipFileReader<S>(S);
impl<'a, R> ZipFileReader<Ready<R>>
where
R: AsyncBufRead + Unpin + 'a,
{
pub fn new(reader: R) -> Self {
Self(Ready(reader))
}
pub async fn next_without_entry(mut self) -> Result<Option<ZipFileReader<Reading<'a, R, WithoutEntry>>>> {
let entry = match crate::base::read::lfh(&mut self.0 .0).await? {
Some(entry) => entry,
None => return Ok(None),
};
let length = if entry.data_descriptor { u64::MAX } else { entry.compressed_size };
let reader = ZipEntryReader::new_with_owned(self.0 .0, entry.compression, length);
Ok(Some(ZipFileReader(Reading(reader, entry.data_descriptor))))
}
pub async fn next_with_entry(mut self) -> Result<Option<ZipFileReader<Reading<'a, R, WithEntry<'a>>>>> {
let entry = match crate::base::read::lfh(&mut self.0 .0).await? {
Some(entry) => entry,
None => return Ok(None),
};
let length = if entry.data_descriptor { u64::MAX } else { entry.compressed_size };
let reader = ZipEntryReader::new_with_owned(self.0 .0, entry.compression, length);
let data_descriptor = entry.data_descriptor;
Ok(Some(ZipFileReader(Reading(reader.into_with_entry_owned(entry), data_descriptor))))
}
pub async fn into_inner(self) -> R {
self.0 .0
}
}
#[cfg(feature = "tokio")]
impl<R> ZipFileReader<TokioReady<R>>
where
R: tokio::io::AsyncBufRead + Unpin,
{
pub fn with_tokio(reader: R) -> ZipFileReader<TokioReady<R>> {
Self(Ready(reader.compat()))
}
}
impl<'a, R, E> ZipFileReader<Reading<'a, R, E>>
where
R: AsyncBufRead + Unpin,
{
pub fn reader(&self) -> &ZipEntryReader<'a, R, E> {
&self.0 .0
}
pub fn reader_mut(&mut self) -> &mut ZipEntryReader<'a, R, E> {
&mut self.0 .0
}
pub async fn done(mut self) -> Result<ZipFileReader<Ready<R>>> {
if self.0 .0.read(&mut [0; 1]).await? != 0 {
return Err(ZipError::EOFNotReached);
}
let mut inner = self.0 .0.into_inner();
if self.0 .1 {
consume_data_descriptor(&mut inner).await?;
}
Ok(ZipFileReader(Ready(inner)))
}
pub async fn skip(mut self) -> Result<ZipFileReader<Ready<R>>> {
while self.0 .0.read(&mut [0; 2048]).await? != 0 {}
let mut inner = self.0 .0.into_inner();
if self.0 .1 {
consume_data_descriptor(&mut inner).await?;
}
Ok(ZipFileReader(Ready(inner)))
}
}
async fn consume_data_descriptor<R: AsyncBufRead + Unpin>(reader: &mut R) -> Result<()> {
let mut descriptor: [u8; DATA_DESCRIPTOR_LENGTH] = [0; DATA_DESCRIPTOR_LENGTH];
reader.read_exact(&mut descriptor).await?;
if descriptor[0..SIGNATURE_LENGTH] == DATA_DESCRIPTOR_SIGNATURE.to_le_bytes() {
let mut tail: [u8; SIGNATURE_LENGTH] = [0; SIGNATURE_LENGTH];
reader.read_exact(&mut tail).await?;
}
Ok(())
}