use std::{fs, io, path::Path};
use crate::emu::Emu;
use crate::maps::mem64::Permission;
impl Emu {
pub fn set_maps_folder(&mut self, folder: &str) {
self.cfg.maps_folder = folder.to_string();
if !self.maps_folder_is_valid(folder) {
log::trace!(
"Maps folder '{}' not found or incomplete, attempting to download...",
folder
);
if let Err(e) = self.download_and_extract_maps(folder) {
log::error!("Failed to download maps folder '{}': {}", folder, e);
panic!("Cannot proceed without maps folder. Please download manually or check your internet connection.");
}
}
}
fn maps_folder_is_valid(&self, folder: &str) -> bool {
let folder_path = Path::new(folder);
if !folder_path.exists() {
println!("folder doesnt exist");
return false;
}
let essential_files = if folder.contains("32") {
println!("self.cfg.emulate_winapi: {}", self.cfg.emulate_winapi);
if self.cfg.emulate_winapi {
vec!["ntdll.dll", "kernel32.dll"]
} else {
vec!["ntdll.dll", "kernel32.dll", "banzai.csv"]
}
} else {
vec!["ntdll.dll", "kernel32.dll"]
};
for file in essential_files {
let file_path = folder_path.join(file);
if !file_path.exists() {
println!("essential file missing: {}", file_path.display());
log::trace!(
"Essential file '{}' missing from maps folder",
file_path.display()
);
return false;
}
}
true
}
fn download_and_extract_maps(&self, folder: &str) -> Result<(), Box<dyn std::error::Error>> {
let url = match folder {
"maps32" | "maps32/" | "maps/maps32" | "maps/maps32/" => {
"https://github.com/sha0coder/mwemu/releases/download/maps/maps32.zip"
}
"maps64" | "maps64/" | "maps/maps64" | "maps/maps64/" => {
"https://github.com/sha0coder/mwemu/releases/download/maps/maps64.zip"
}
_ => return Err(format!("Unknown maps folder: {}", folder).into()),
};
log::trace!(
"Downloading {} from GitHub releases... (this may take a moment)",
folder
);
let response = ureq::get(url)
.timeout(std::time::Duration::from_secs(30))
.call()?;
if response.status() != 200 {
return Err(format!("Failed to download: HTTP {}", response.status()).into());
}
let mut bytes = Vec::new();
response.into_reader().read_to_end(&mut bytes)?;
log::trace!("Downloaded {} MB", bytes.len() / 1024 / 1024);
let cursor = std::io::Cursor::new(bytes);
let mut archive = zip::ZipArchive::new(cursor)?;
log::trace!("Extracting {} files...", archive.len());
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let outpath = Path::new(file.name());
if file.name().ends_with('/') {
fs::create_dir_all(&outpath)?;
} else {
if let Some(p) = outpath.parent() {
if !p.exists() {
fs::create_dir_all(p)?;
}
}
let mut outfile = fs::File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
}
}
log::trace!("Successfully extracted maps folder: {}", folder);
Ok(())
}
pub fn get_base_addr(&self) -> Option<u64> {
let map = match self.maps.get_map_by_name("code") {
Some(m) => m,
None => return None,
};
Some(map.get_base())
}
pub fn filename_to_mapname(&self, filename: &str) -> String {
filename
.split('/')
.last()
.map(|x| x.split('.'))
.and_then(|x| x.peekable().next())
.unwrap()
.to_string()
}
pub fn free(&mut self, name: &str) {
self.maps.free(name);
}
pub fn alloc(&mut self, name: &str, size: u64, permission: Permission) -> u64 {
let addr = match self.maps.alloc(size) {
Some(a) => a,
None => {
log::trace!("low memory");
return 0;
}
};
self.maps
.create_map(name, addr, size, permission)
.expect("cannot create map from alloc api");
addr
}
}