Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,111 @@ pub(crate) mod zip_archive {
}
}

/// Iterable version of ZipArchive
pub struct IterableZipArchive<R> {
#[allow(unused)]
pub(crate) config: Config,
pub(crate) iterable_shared: IterableShared<R>,
}
impl<R: Read + Seek> IterableZipArchive<R> {
/// Try to create a new zip archive
pub fn try_new(reader: R) -> ZipResult<IterableZipArchive<R>> {
Self::with_config(Default::default(), reader)
}

/// Read the central header
fn read_central_header(
dir_info: CentralDirectoryInfo,
reader: R,
) -> ZipResult<IterableShared<R>> {
// If the parsed number of files is greater than the offset then
// something fishy is going on and we shouldn't trust number_of_files.
let file_capacity = if dir_info.number_of_files > dir_info.directory_start as usize {
0
} else {
dir_info.number_of_files
};

if dir_info.disk_number != dir_info.disk_with_central_directory {
return unsupported_zip_error("Support for multi-disk files is not implemented");
}

if file_capacity.saturating_mul(size_of::<ZipFileData>()) > isize::MAX as usize {
return unsupported_zip_error("Oversized central directory");
}

IterableShared::try_new(reader, dir_info)
Comment thread
Its-Just-Nans marked this conversation as resolved.
Outdated
}

fn with_config(config: Config, mut reader: R) -> ZipResult<IterableZipArchive<R>> {
let file_len = reader.seek(io::SeekFrom::End(0))?;
let mut end_exclusive = file_len;
let mut last_err = None;

let dir_info = loop {
let cde = match spec::find_central_directory(
&mut reader,
config.archive_offset,
end_exclusive,
file_len,
) {
Ok(cde) => cde,
Err(e) => return Err(last_err.unwrap_or(e)),
};

match CentralDirectoryInfo::try_from(&cde) {
Ok(info) => break info,
Err(e) => {
last_err = Some(e);
end_exclusive = cde.eocd.position;
}
}
};

let iterable_shared = Self::read_central_header(dir_info, reader)?;

Ok(IterableZipArchive {
config,
iterable_shared,
})
}

/// Get the file as an iterator
pub fn files(&mut self) -> &mut IterableShared<R> {
&mut self.iterable_shared
}
}

/// Iterable Files
#[derive(Debug)]
pub struct IterableShared<R> {
reader: R,
dir_info: CentralDirectoryInfo,
}

impl<R: Read + Seek> IterableShared<R> {
/// Try to create an iterable of files
pub(crate) fn try_new(mut reader: R, dir_info: CentralDirectoryInfo) -> ZipResult<Self> {
reader.seek(SeekFrom::Start(dir_info.directory_start))?;
Ok(Self { reader, dir_info })
}
}

impl<R: Read + Seek> Iterator for IterableShared<R> {
// We can refer to this type using Self::Item
type Item = ZipFileData;

// Here, we define the sequence using `.curr` and `.next`.
// The return type is `Option<T>`:
// * When the `Iterator` is finished, `None` is returned.
// * Otherwise, the next value is wrapped in `Some` and returned.
// We use Self::Item in the return type, so we can change
// the type without having to update the function signatures.
fn next(&mut self) -> Option<Self::Item> {
central_header_to_zip_file(&mut self.reader, &self.dir_info).ok()
}
}
Comment thread
Its-Just-Nans marked this conversation as resolved.
Outdated

#[cfg(feature = "aes-crypto")]
use crate::aes::PWD_VERIFY_LENGTH;
use crate::extra_fields::UnicodeExtraField;
Expand Down
Loading