Skip to main content

pacenotes_installer\zip/
archive.rs

1/// A package whose central directory has been read once. Finding each file
2/// by walking the directory again cost an install of n files n² entry
3/// parses: 8.5 s of a 12 s install at 3 000 files.
4pub struct Archive<'a> {
5    zip: &'a [u8],
6    /// Files only, by folded path, because a ledger may hold a path folded.
7    entries: std::collections::BTreeMap<String, super::central_directory::Entry>,
8}
9
10impl<'a> Archive<'a> {
11    pub fn open(zip: &'a [u8]) -> Result<Archive<'a>, super::ZipError> {
12        let mut entries = std::collections::BTreeMap::new();
13        for entry in super::central_directory::read(zip)? {
14            // The first of two names that fold alike wins, as a walk would find it.
15            if !entry.is_dir {
16                entries.entry(entry.path.to_lowercase()).or_insert(entry);
17            }
18        }
19        Ok(Archive { zip, entries })
20    }
21
22    /// One file's bytes, by a path `entries` reported, matched case-insensitively.
23    pub fn read(&self, path: &str) -> Result<Vec<u8>, super::ZipError> {
24        let entry = self
25            .entries
26            .get(&path.to_lowercase())
27            .ok_or_else(|| super::ZipError::new(format!("{path} is not in this package")))?;
28        super::entry_data::read(self.zip, entry)
29    }
30}