diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/download.rs | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/src/download.rs b/src/download.rs index 75bea57..dfce2fc 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,10 +1,12 @@ use std::{ + fs, io::{Cursor, Read}, str::FromStr, }; use tempdir::TempDir; use url::Url; +use uuid::Uuid; use zip::ZipArchive; use super::{ @@ -103,18 +105,30 @@ impl Downloader { let data = Cursor::new(data); let mut archive = ZipArchive::new(data)?; - // Here we assume that the zipfile contains only one directory, so we just take the first - // name we find and extract the leading directory name. - let name = archive - .file_names() - .next() - .and_then(|name| name.split('/').next()) - .ok_or(Error::EmptyArchive)? - .to_string(); + let dir = self + .temp_dir + .path() + .join(&Uuid::new_v4().to_hyphenated().to_string()); + fs::create_dir(&dir)?; - archive.extract(self.temp_dir.path())?; + archive.extract(&dir)?; - let extracted_path = self.temp_dir.path().join(name); - minemod::open_mod_or_pack(&extracted_path) + // Some archives contain the mod files directly, so try to open it: + if let Ok(pack) = minemod::open_mod_or_pack(&dir) { + return Ok(pack); + } + + // If the archive does not contain the mod directly, we instead try the subdirectories that + // we've extracted. + for entry in fs::read_dir(&dir)? { + let entry = entry?; + let metadata = fs::metadata(&entry.path())?; + if metadata.is_dir() { + if let Ok(pack) = minemod::open_mod_or_pack(&entry.path()) { + return Ok(pack); + } + } + } + Err(Error::InvalidModDir(dir)) } } |