chiark / gitweb /
bundles: Scan the zipfile
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 10 May 2021 18:32:12 +0000 (19:32 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 10 May 2021 18:32:12 +0000 (19:32 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.toml
src/bundles.rs
src/prelude.rs
src/shapelib.rs

index 6f88731625b535dbc16149326b699ff3ef33830e..b047e9bc22f6be33cf1587806aa1b01df39e17d2 100644 (file)
@@ -2260,6 +2260,7 @@ dependencies = [
  "toml 0.5.8",
  "typetag",
  "uds",
+ "unicase 2.6.0",
  "url 2.2.1",
  "usvg",
  "vecdeque-stableix",
index 03ca80d74e7ba0b253ae55b5babf38938074908f..24debfe039b8618971ecb8c9ec7b1503ec313cfe 100644 (file)
@@ -74,6 +74,7 @@ tera="0.11"
 toml="0.5"
 typetag="0.1.6"
 uds="0.2"
+unicase="2"
 url="2"
 vecdeque-stableix="1"
 zip="0.5"
index a69b2d05f8c3e36e7c6afdccbe4427281947cb42..e6ff1e0ba5ab4c11e8a0b1fcff4d83ff2144abbc 100644 (file)
@@ -265,6 +265,38 @@ impl From<ZipError> for LoadError {
   }
 }
 
+pub struct IndexedZip<R> where R: Read + io::Seek {
+  za: ZipArchive<BufReader<R>>,
+  members: BTreeMap<UniCase<String>, usize>,
+}
+deref_to_field_mut!{{ R: Read + io::Seek }
+                    IndexedZip<R>, ZipArchive<BufReader<R>>, za }
+
+impl<R> IndexedZip<R> where R: Read + io::Seek {
+  #[throws(LoadError)]
+  fn new(file: R) -> Self {
+    let file = BufReader::new(file);
+    let mut za = ZipArchive::new(file)?;
+    let mut members = BTreeMap::new();
+    for i in 0..za.len() {
+      let entry = za.by_index_raw(i)?;
+      let sname = entry.name().to_owned();
+      let uname = UniCase::new(sname.to_owned());
+      if let Some(previously) = members.insert(uname, i) {
+        let sname = sname.to_owned();
+        drop(entry);
+        let previously = za.by_index_raw(previously)?;
+        let previously = previously.name();
+        throw!(LE::BadBundle(format!(
+          "duplicate files, differing only in case, {:?} vs {:?}",
+          &previously, sname,
+        )));
+      }
+    }
+    IndexedZip { za, members }
+  }
+}
+
 #[ext(pub)]
 impl<R> ZipArchive<R> where R: Read + io::Seek {
   #[throws(LoadError)]
@@ -366,10 +398,9 @@ fn parse_bundle<EH,F>(id: Id, file: &mut F, bpath: &str) -> Parsed
 where EH: BundleParseError,
       F: Read + io::Seek
 {
-  let file = BufReader::new(file);
   match id.kind { Kind::Zip => () }
   let mut za = EH::required(bpath, ||{
-    ZipArchive::new(file)
+    IndexedZip::new(file)
   })?;
 
   let meta = EH::besteffort(bpath, ||{
index 00989747b02558c754fe6710b0bf605697cec90c..221062a3f85bc818181d29d79fe205b70984eed7 100644 (file)
@@ -98,6 +98,7 @@ pub use strum::{IntoEnumIterator, IntoStaticStr};
 pub use subtle::ConstantTimeEq;
 pub use tempfile::NamedTempFile;
 pub use thiserror::Error;
+pub use unicase::UniCase;
 pub use url::Url;
 pub use vecdeque_stableix::Deque as StableIndexVecDeque;
 pub use void::{unreachable, Void, ResultVoidExt, ResultVoidErrExt};
index 8bedfca6677ff2fcc7c6a4a37c70b8561b44b3d0..b55d63d421d5f42a7f1e25bb6853d23033edfd47 100644 (file)
@@ -557,7 +557,7 @@ fn resolve_inherit<'r>(depth: u8, groups: &toml::value::Table,
   Cow::Owned(build)
 }
 
-trait LibrarySource {
+pub trait LibrarySource {
   fn read_catalogue(&self) -> Result<String, LLE>;
   fn svg_dir(&self) -> String;
 }