use serde::Serialize;
use crate::error::RomAnalyzerError;
use crate::region::{Region, check_region_mismatch};
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct MasterSystemAnalysis {
pub source_name: String,
pub region: Region,
pub region_string: String,
pub region_mismatch: bool,
pub region_byte: u8,
}
impl MasterSystemAnalysis {
pub fn print(&self) -> String {
format!(
"{}\n\
System: Sega Master System\n\
Region Code: 0x{:02X}\n\
Region: {}",
self.source_name, self.region_byte, self.region
)
}
}
pub fn map_region(region_byte: u8) -> (&'static str, Region) {
match region_byte {
0x30 => ("Japan (NTSC)", Region::JAPAN),
0x4C => ("Europe / Overseas (PAL/NTSC)", Region::USA | Region::EUROPE),
_ => ("Unknown", Region::UNKNOWN),
}
}
pub fn analyze_mastersystem_data(
data: &[u8],
source_name: &str,
) -> Result<MasterSystemAnalysis, RomAnalyzerError> {
const REQUIRED_SIZE: usize = 0x7FFD;
if data.len() < REQUIRED_SIZE {
return Err(RomAnalyzerError::DataTooSmall {
file_size: data.len(),
required_size: REQUIRED_SIZE,
details: "Master System region byte".to_string(),
});
}
let sms_region_byte = data[0x7FFC];
let (region_name, region) = map_region(sms_region_byte);
let region_mismatch = check_region_mismatch(source_name, region);
Ok(MasterSystemAnalysis {
source_name: source_name.to_string(),
region,
region_string: region_name.to_string(),
region_mismatch,
region_byte: sms_region_byte,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analyze_mastersystem_data_japan() -> Result<(), RomAnalyzerError> {
let mut data = vec![0; 0x7FFD];
data[0x7FFC] = 0x30; let analysis = analyze_mastersystem_data(&data, "test_rom_jp.sms")?;
assert_eq!(analysis.source_name, "test_rom_jp.sms");
assert_eq!(analysis.region_byte, 0x30);
assert_eq!(analysis.region, Region::JAPAN);
assert_eq!(analysis.region_string, "Japan (NTSC)");
assert_eq!(
analysis.print(),
"test_rom_jp.sms\n\
System: Sega Master System\n\
Region Code: 0x30\n\
Region: Japan"
);
Ok(())
}
#[test]
fn test_analyze_mastersystem_data_europe() -> Result<(), RomAnalyzerError> {
let mut data = vec![0; 0x7FFD];
data[0x7FFC] = 0x4C; let analysis = analyze_mastersystem_data(&data, "test_rom_eur.sms")?;
assert_eq!(analysis.source_name, "test_rom_eur.sms");
assert_eq!(analysis.region_byte, 0x4C);
assert_eq!(analysis.region, Region::USA | Region::EUROPE);
assert_eq!(analysis.region_string, "Europe / Overseas (PAL/NTSC)");
Ok(())
}
#[test]
fn test_analyze_mastersystem_data_unknown() -> Result<(), RomAnalyzerError> {
let mut data = vec![0; 0x7FFD];
data[0x7FFC] = 0x00; let analysis = analyze_mastersystem_data(&data, "test_rom.sms")?;
assert_eq!(analysis.source_name, "test_rom.sms");
assert_eq!(analysis.region_byte, 0x00);
assert_eq!(analysis.region, Region::UNKNOWN);
assert_eq!(analysis.region_string, "Unknown");
Ok(())
}
#[test]
fn test_analyze_mastersystem_data_too_small() {
let data = vec![0; 100]; let result = analyze_mastersystem_data(&data, "too_small.sms");
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("too small"));
}
}