#[cfg(doc)]
use crate::base::read::seek;
use crate::base::read::io::entry::{WithEntry, WithoutEntry, ZipEntryReader};
use crate::error::{Result, ZipError};
use crate::file::ZipFile;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tokio::fs::File;
use tokio::io::BufReader;
use tokio_util::compat::{Compat, TokioAsyncReadCompatExt};
struct Inner {
path: PathBuf,
file: ZipFile,
}
#[derive(Clone)]
pub struct ZipFileReader {
inner: Arc<Inner>,
}
impl ZipFileReader {
pub async fn new<P>(path: P) -> Result<ZipFileReader>
where
P: AsRef<Path>,
{
let file = crate::base::read::file(File::open(&path).await?.compat()).await?;
Ok(ZipFileReader::from_raw_parts(path, file))
}
pub fn from_raw_parts<P>(path: P, file: ZipFile) -> ZipFileReader
where
P: AsRef<Path>,
{
ZipFileReader { inner: Arc::new(Inner { path: path.as_ref().to_owned(), file }) }
}
pub fn file(&self) -> &ZipFile {
&self.inner.file
}
pub fn path(&self) -> &Path {
&self.inner.path
}
pub async fn reader_without_entry(
&self,
index: usize,
) -> Result<ZipEntryReader<'static, Compat<BufReader<File>>, WithoutEntry>> {
let stored_entry = self.inner.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
let mut fs_file = BufReader::new(File::open(&self.inner.path).await?).compat();
stored_entry.seek_to_data_offset(&mut fs_file).await?;
Ok(ZipEntryReader::new_with_owned(
fs_file,
stored_entry.entry.compression(),
stored_entry.entry.compressed_size(),
))
}
pub async fn reader_with_entry(
&self,
index: usize,
) -> Result<ZipEntryReader<'_, Compat<BufReader<File>>, WithEntry<'_>>> {
let stored_entry = self.inner.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
let mut fs_file = BufReader::new(File::open(&self.inner.path).await?).compat();
stored_entry.seek_to_data_offset(&mut fs_file).await?;
let reader = ZipEntryReader::new_with_owned(
fs_file,
stored_entry.entry.compression(),
stored_entry.entry.compressed_size(),
);
Ok(reader.into_with_entry(stored_entry))
}
}