#![warn(clippy::nursery, clippy::pedantic)]
use crate::constants::{
HEARTGOLD, HEARTGOLD_BYTES, PLATINUM, PLATINUM_BYTES, SOULSILVER, SOULSILVER_BYTES,
};
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};
use std::path::PathBuf;
use std::{fs, io};
pub fn determine_game_version(project_path: &str) -> io::Result<&str> {
let header_path = PathBuf::from(project_path).join("header.bin");
fs::File::open(&header_path).map_or_else(|_| {
eprintln!("header.bin not found at path: {}", header_path.display());
Err(io::Error::new(io::ErrorKind::NotFound, "header.bin not found"))
}, |mut file| {
let mut buf = [0u8; 4];
file.seek(SeekFrom::Start(0xC))
.expect("Failed to seek in header.bin");
file.read_exact(&mut buf)
.expect("Failed to read from header.bin");
match buf {
PLATINUM_BYTES => Ok(PLATINUM),
HEARTGOLD_BYTES => Ok(HEARTGOLD),
SOULSILVER_BYTES => Ok(SOULSILVER),
_ => {
eprintln!("Unknown game version in header.bin at path: {}\nBytes found:{:02X} {:02X} {:02X} {:02X}",
header_path.display(), buf[0], buf[1], buf[2], buf[3]);
Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown game version in header.bin"))
}
}
})
}
pub fn is_patch_compatible(patch_path: &str, project_path: &str) -> bool {
match determine_game_version(project_path).unwrap() {
PLATINUM if patch_path.contains("_PLAT") => true,
HEARTGOLD if patch_path.contains("_HG") => true,
SOULSILVER if patch_path.contains("_SS") => true,
_ => false,
}
}
pub fn needs_synthoverlay(asm_path: &str) -> bool {
let input = BufReader::new(
fs::File::open(asm_path).unwrap_or_else(|_| panic!("Failed to open {asm_path}")),
);
let mut lines: Vec<String> = Vec::new();
for line in input.lines() {
let line = line.expect("Failed to read line");
if line.contains(".open \"unpacked/synthOverlay/") {
return true;
}
lines.push(line);
}
false
}
pub fn is_arm9_expanded(project_path: &str, game_version: &str) -> io::Result<bool> {
let arm9_path = PathBuf::from(project_path).join("arm9.bin");
let mut buf = [0u8; 4];
match game_version {
HEARTGOLD | SOULSILVER => fs::File::open(&arm9_path).map_or_else(
|_| {
eprintln!("arm9.bin not found at path: {}", arm9_path.display());
Err(io::Error::new(
io::ErrorKind::NotFound,
"arm9.bin not found",
))
},
|mut file| {
if file.seek(SeekFrom::Start(0xCD0)).is_ok()
&& file.read_exact(&mut buf).is_ok()
&& buf == [0x0F, 0xF1, 0x30, 0xFB]
{
Ok(true)
} else {
Ok(false)
}
},
),
PLATINUM => fs::File::open(&arm9_path).map_or_else(
|_| {
eprintln!("arm9.bin not found at path: {}", arm9_path.display());
Err(io::Error::new(
io::ErrorKind::NotFound,
"arm9.bin not found",
))
},
|mut file| {
if file.seek(SeekFrom::Start(0xCB4)).is_ok()
&& file.read_exact(&mut buf).is_ok()
&& buf == [0x00, 0xF1, 0xB4, 0xF8]
{
Ok(true)
} else {
Ok(false)
}
},
),
_ => {
eprintln!("Unknown game version: {game_version}");
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Unknown game version",
))
}
}
}