lib3mf_core/archive/
zip_archive.rs

1use crate::archive::ArchiveReader;
2use crate::error::{Lib3mfError, Result};
3use std::io::{Read, Seek};
4use zip::ZipArchive;
5
6#[derive(Debug)]
7pub struct ZipArchiver<R> {
8    archive: ZipArchive<R>,
9}
10
11impl<R: Read + Seek> ZipArchiver<R> {
12    pub fn new(reader: R) -> Result<Self> {
13        Ok(Self {
14            archive: ZipArchive::new(reader).map_err(|e| Lib3mfError::Io(e.into()))?,
15        })
16    }
17}
18
19impl<R: Read + Seek> Read for ZipArchiver<R> {
20    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
21        // ZipArchiver itself doesn't implement Read in a meaningful way for the whole archive,
22        // but we need to satisfy the trait bounds if we passed it around.
23        // For now, this is a placeholder or we might remove Read from ArchiveReader if not strictly needed.
24        // However, ArchiveReader inherits Read + Seek to allow flexibility.
25        // A better design might be to separate the "Opener" from the "Reader".
26        // Let's implement dummy Read/Seek for the Archiver wrapper or rethink the trait.
27
28        // Actually, looking at the design, ArchiveReader requires Read+Seek.
29        // This implies the *underlying* reader has it, but the Archiver *is* the manager.
30        // Let's implement pass-through if we have access, or just return 0.
31        Ok(0)
32    }
33}
34
35impl<R: Read + Seek> Seek for ZipArchiver<R> {
36    fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
37        Ok(0)
38    }
39}
40
41impl<R: Read + Seek> ArchiveReader for ZipArchiver<R> {
42    fn read_entry(&mut self, name: &str) -> Result<Vec<u8>> {
43        let name = name.trim_start_matches('/');
44        let mut file = self.archive.by_name(name).map_err(|_| {
45            Lib3mfError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, name))
46        })?;
47
48        let mut buffer = Vec::new();
49        file.read_to_end(&mut buffer)?;
50        Ok(buffer)
51    }
52
53    fn entry_exists(&mut self, name: &str) -> bool {
54        let name = name.trim_start_matches('/');
55        self.archive.by_name(name).is_ok()
56    }
57
58    fn list_entries(&mut self) -> Result<Vec<String>> {
59        Ok(self.archive.file_names().map(|s| s.to_string()).collect())
60    }
61}