use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use chd::Chd;
use log::debug;
use crate::error::RomAnalyzerError;
const MAX_HEADER_SIZE: usize = 0x20000;
pub fn analyze_chd_file(filepath: &Path) -> Result<Vec<u8>, RomAnalyzerError> {
let file = File::open(filepath)?;
let mut reader = BufReader::new(file);
let mut chd = Chd::open(&mut reader, None).map_err(RomAnalyzerError::ChdError)?;
let hunk_count = chd.header().hunk_count();
let hunk_size = chd.header().hunk_size();
debug!(
"[+] Analyzing CHD file: {}",
filepath
.file_name()
.unwrap_or_else(|| filepath.as_ref())
.to_string_lossy()
);
let mut decompressed_data = Vec::new();
decompressed_data.reserve_exact(
((hunk_count as u64) * (hunk_size as u64)).min(MAX_HEADER_SIZE as u64) as usize,
);
let mut out_buf = chd.get_hunksized_buffer();
let mut temp_buf = Vec::new();
for hunk_num in 0..hunk_count {
if decompressed_data.len() >= MAX_HEADER_SIZE {
break;
}
let mut hunk = chd.hunk(hunk_num).map_err(RomAnalyzerError::ChdError)?;
hunk.read_hunk_in(&mut temp_buf, &mut out_buf)
.map_err(RomAnalyzerError::ChdError)?;
let remaining_capacity = MAX_HEADER_SIZE - decompressed_data.len();
let data_to_add = out_buf.len().min(remaining_capacity);
decompressed_data.extend_from_slice(&out_buf[..data_to_add]);
}
debug!(
"[+] Decompressed first {} bytes for header analysis.",
decompressed_data.len()
);
Ok(decompressed_data)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::ErrorKind;
#[test]
fn test_analyze_chd_file_non_existent() {
let non_existent_path = Path::new("non_existent_file.chd");
let result = analyze_chd_file(non_existent_path);
assert!(result.is_err());
let error = result.unwrap_err();
match error {
RomAnalyzerError::IoError(io_err) => assert_eq!(io_err.kind(), ErrorKind::NotFound),
_ => panic!("Expected IoError variant"),
}
}
}