use std::path::Path;
use crate::error::Result;
use crate::pak::PakOperations;
use super::types::{ModPhase, ModProgress, ModProgressCallback};
#[derive(Clone, Debug)]
pub struct PakIntegrityResult {
pub valid: bool,
pub file_count: usize,
pub total_size: u64,
pub issues: Vec<String>,
}
pub fn check_pak_integrity(pak_path: &Path) -> Result<PakIntegrityResult> {
check_pak_integrity_with_progress(pak_path, &|_| {})
}
pub fn check_pak_integrity_with_progress(
pak_path: &Path,
progress: ModProgressCallback,
) -> Result<PakIntegrityResult> {
progress(&ModProgress::with_file(
ModPhase::Validating,
0,
1,
"Reading PAK header...",
));
let mut issues = Vec::new();
let valid;
let files = match PakOperations::list(pak_path) {
Ok(f) => f,
Err(e) => {
return Ok(PakIntegrityResult {
valid: false,
file_count: 0,
total_size: 0,
issues: vec![format!("Failed to read PAK: {e}")],
});
}
};
let file_count = files.len();
progress(&ModProgress::with_file(
ModPhase::Validating,
1,
2,
format!("Checking {file_count} files..."),
));
let mut seen_paths = std::collections::HashSet::new();
for file in &files {
if !seen_paths.insert(file) {
issues.push(format!("Duplicate file path: '{file}'"));
}
}
let test_file = files
.iter()
.find(|f| f.ends_with("meta.lsx"))
.or_else(|| files.iter().find(|f| f.ends_with(".lsx")))
.or_else(|| files.iter().find(|f| f.ends_with(".txt")))
.or_else(|| files.first());
if let Some(test_path) = test_file {
match PakOperations::read_file_bytes(pak_path, test_path) {
Ok(_) => {
valid = issues.is_empty();
}
Err(e) => {
issues.push(format!("Failed to read test file '{test_path}': {e}"));
valid = false;
}
}
} else {
valid = issues.is_empty();
}
let total_size = std::fs::metadata(pak_path).map(|m| m.len()).unwrap_or(0);
progress(&ModProgress::new(ModPhase::Complete, 2, 2));
Ok(PakIntegrityResult {
valid,
file_count,
total_size,
issues,
})
}