use std::fs::File;
use std::io::{Error, Write};
use std::path::Path;
use log::info;
use crate::lol::io::sys::LOLfile;
use crate::lol::io::sys_type::Lolfileresult;
use crate::lol::wad::archive::Archive;
pub mod lol;
pub mod zstd_compatibility_test;
pub mod wad_diagnostic;
pub fn extract_wad(src: &str, dict_path: &str, dst: &str) -> std::result::Result<(), Error> {
let trace = lol_trace_func!(extract_wad, lol_trace_var!("{}", src), lol_trace_var!("{}", dict_path));
lol_throw_if!(src.is_empty(), trace);
let mut dict = lol::hash::Dict::new();
if dict_path.is_empty() {
let res = dict.load("./hashes.game.txt");
if res.is_err() {
return Err(res.err().unwrap());
}
} else {
let res = dict.load(dict_path);
if res.is_err() {
return Err(res.err().unwrap());
}
}
let path = Path::new(src);
let mut newpath = String::new();
if path.extension().and_then(|s| s.to_str()) ==Some("client") {
if dst.is_empty() {
newpath = path.with_extension("").to_str().unwrap().to_string();
if Path::new(&newpath).is_dir() {
let _= path.to_path_buf();
} else {
std::fs::create_dir(&newpath).unwrap();
}
} else {
let pp = path.with_extension("");
let pa = pp.to_str().unwrap();
let pa = Path::new(pa);
newpath = Path::new(dst).to_string_lossy().to_string() + "/" + pa.file_name().unwrap().to_str().unwrap();
if Path::new(dst).is_dir() {
} else {
std::fs::create_dir_all(dst).unwrap();
}
}
}
let a = Archive::read_from_file(Path::new(src));
for mut entry in a.entries {
let name = entry.0;
let (data, size, tpye_) = entry.1.decompressed_bytes();
let fake_name =format!("{:16x}.bin", name, );
let filename = dict.get(name).unwrap_or(&fake_name );
let mut _file_name = String::new();
if filename.len() > 127 {
_file_name = format!("{:016x}", name) + "." +
Path::new(filename)
.extension().unwrap().to_str().unwrap();
} else {
_file_name = filename.clone();
}
let path = Path::new(&newpath);
let _file_name = path.join(_file_name);
let dir = _file_name.parent().unwrap();
info!("name {:16x} {:?} {:?}", name, _file_name, tpye_);
std::fs::create_dir_all(dir).unwrap();
let mut file = File::create(_file_name).unwrap();
file.write_all(&data).unwrap();
file.set_len(size as _).unwrap();
};
LOLfile::file_munmap(0).unwrap();
Ok(())
}
pub fn make_wad(src: &str, dst: &str) -> std::result::Result<(), Error> {
let src = Path::new(src);
let mut archive = lol::wad::archive::Archive::new();
for entry in walkdir::WalkDir::new(src) {
let entry = entry.expect("walkdir error");
if !entry.file_type().is_file() {
continue;
}
let path = entry.path();
info!("Reading: {}", path.display());
archive.add_from_directory(path, src).unwrap();
}
let mut dst = dst;
if dst.is_empty() {
let tmp = format!("{}.client", src.to_str().unwrap());
dst = &tmp;
archive.write_file(Path::new(dst))?;
} else {
archive.write_file(Path::new(dst))?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use std::path::Path;
use crate::{extract_wad, make_wad};
#[test]
fn test_extract_wad() {
let res = extract_wad("./Irelia.wad.client", "", "");
assert_eq!(true, res.is_ok());
}
#[test]
fn test_make_wad() {
let res = make_wad("./Irelia.wad", "");
assert_eq!(true, res.is_ok())
}
#[test]
fn test_zstd_compatibility() {
crate::zstd_compatibility_test::test_zstd_compatibility();
}
#[test]
fn test_wad_diagnostic() {
use crate::wad_diagnostic::WADDiagnostic;
let rust_wad_path = Path::new("./Irelia.wad.client");
if rust_wad_path.exists() {
println!("诊断Rust生成的WAD文件:");
WADDiagnostic::diagnose_wad_file(rust_wad_path);
} else {
println!("Rust WAD文件不存在,请先运行 test_dict 生成文件");
}
let python_wad_path = Path::new("./python_generated.wad.client");
if rust_wad_path.exists() && python_wad_path.exists() {
println!("\n对比Rust和Python生成的WAD文件:");
WADDiagnostic::compare_wad_files(rust_wad_path, python_wad_path);
}
}
}