Skip to content

Commit

Permalink
Add next_header() to ArchiveIterator
Browse files Browse the repository at this point in the history
This allows for skipping files without allocating the contents.
  • Loading branch information
Morganamilo authored and otavio committed Jul 1, 2024
1 parent ca9c246 commit 4450899
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
34 changes: 32 additions & 2 deletions src/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<R: Read + Seek> Iterator for ArchiveIterator<R> {
let next = if self.in_file {
unsafe { self.next_data_chunk() }
} else {
unsafe { self.next_header() }
unsafe { self.unsafe_next_header() }
};

match &next {
Expand Down Expand Up @@ -108,6 +108,36 @@ impl<R: Read + Seek> Iterator for ArchiveIterator<R> {
}
}

impl<R: Read + Seek> ArchiveIterator<R> {
pub fn next_header(&mut self) -> Option<ArchiveContents> {
debug_assert!(!self.closed);

if self.error {
return None;
}

let next = unsafe { self.unsafe_next_header() };

match &next {
ArchiveContents::StartOfEntry(name, stat) => {
if let Some(filter) = &self.filter {
if !filter(name, stat) {
return None;
}
}

self.in_file = true;
Some(next)
}
ArchiveContents::Err(_) => {
self.error = true;
Some(next)
}
_ => None,
}
}
}

impl<R: Read + Seek> Drop for ArchiveIterator<R> {
fn drop(&mut self) {
drop(self.free());
Expand Down Expand Up @@ -299,7 +329,7 @@ impl<R: Read + Seek> ArchiveIterator<R> {
Ok(())
}

unsafe fn next_header(&mut self) -> ArchiveContents {
unsafe fn unsafe_next_header(&mut self) -> ArchiveContents {
match ffi::archive_read_next_header(self.archive_reader, &mut self.archive_entry) {
ffi::ARCHIVE_EOF => ArchiveContents::EndOfEntry,
ffi::ARCHIVE_OK | ffi::ARCHIVE_WARN => {
Expand Down
49 changes: 49 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,55 @@ fn iterate_tar() {
assert_eq!(contents, expected);
}

fn collect_iterate_names_with_encoding(
source: std::fs::File,
decode: DecodeCallback,
) -> Vec<String> {
let mut results = Vec::new();

let mut iter =
ArchiveIterator::from_read_with_encoding(source, decode).expect("Failed to get the file");

while let Some(content) = iter.next_header() {
match content {
ArchiveContents::StartOfEntry(file_name, _) => {
results.push(file_name);
}
ArchiveContents::DataChunk(_) => {
panic!("expected StartOfntry got DataChunk")
}
ArchiveContents::EndOfEntry => {
panic!("expected StartOfntry got EndOfEntry")
}
ArchiveContents::Err(e) => panic!("{:?}", e),
}
}

iter.close().unwrap();

results
}

#[test]
fn iterate_tar_names() {
let source = std::fs::File::open("tests/fixtures/tree.tar").unwrap();

let contents = collect_iterate_names_with_encoding(source, decode_utf8);

let expected: Vec<String> = vec![
"tree/",
"tree/branch1/",
"tree/branch1/leaf",
"tree/branch2/",
"tree/branch2/leaf",
]
.into_iter()
.map(|a| a.into())
.collect();

assert_eq!(contents, expected);
}

#[test]
fn iterate_7z() {
let source = std::fs::File::open("tests/fixtures/tree.7z").unwrap();
Expand Down

0 comments on commit 4450899

Please sign in to comment.