use std::{ collections::HashMap, fs, fs::File, io, path::{Path, PathBuf}, }; use zip::{read::ZipFile, ZipArchive}; use crate::{ errors::McError, minecraft::manifests::{LibraryArtifact, Version}, util::fs::library_allowed, }; pub fn extract_natives( cfg: &crate::config::Config, version: &Version, ) -> Result<(), McError> { let natives_dir = cfg .data_dir .join("minecraft") .join("versions") .join(&version.id) .join("natives"); if natives_dir.exists() { fs::remove_dir_all(&natives_dir)?; } fs::create_dir_all(&natives_dir)?; for lib in &version.libraries { if !library_allowed(lib) { continue; } let natives: &HashMap = match &lib.natives { | Some(n) => n, | None => continue, }; let classifier: &String = match natives.get("linux") { | Some(c) => c, | None => continue, }; let classifiers: &HashMap = match &lib.downloads.classifiers { | Some(c) => c, | None => continue, }; let artifact: &LibraryArtifact = match classifiers.get(classifier) { | Some(a) => a, | None => continue, }; let jar_path: PathBuf = cfg .data_dir .join("minecraft") .join("libraries") .join(&artifact.path); extract_zip(&jar_path, &natives_dir)?; } Ok(()) } fn extract_zip(jar_path: &Path, out_dir: &Path) -> Result<(), McError> { let file: File = File::open(jar_path)?; let mut zip: ZipArchive = ZipArchive::new(file)?; for i in 0..zip.len() { let mut entry: ZipFile = zip.by_index(i)?; let name: &str = entry.name(); if name.starts_with("META-INF/") { continue; } let out_path: PathBuf = out_dir.join(name); if entry.is_dir() { fs::create_dir_all(&out_path)?; continue; } if let Some(parent) = out_path.parent() { fs::create_dir_all(parent)?; } let mut out_file: File = File::create(&out_path)?; io::copy(&mut entry, &mut out_file)?; } Ok(()) }