#![no_std]
extern crate alloc;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use alloc::vec::Vec;
use core::num::Wrapping;
use hex_literal::hex;
use sha1::{Digest, Sha1};
pub mod types;
pub use types::{CsActive, RomType};
include!(concat!(env!("OUT_DIR"), "/roms.rs"));
pub fn checksum<T>(data: &[u8]) -> T
where
T: Default + From<u8> + Copy,
Wrapping<T>: core::ops::Add<Output = Wrapping<T>>,
{
let mut checksum = Wrapping(T::default());
for &byte in data {
checksum = checksum + Wrapping(T::from(byte));
}
checksum.0
}
pub fn sha1_digest(data: &[u8]) -> [u8; 20] {
let mut hasher = Sha1::new();
hasher.update(data);
let result = hasher.finalize();
let mut sha1 = [0u8; 20];
sha1.copy_from_slice(&result);
sha1
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RomEntry {
name: &'static str,
part: &'static str,
sum: u32,
sha1: [u8; 20],
rom_type: RomType,
}
impl RomEntry {
const fn new(
name: &'static str,
part: &'static str,
sum: u32,
sha1: [u8; 20],
rom_type: RomType,
) -> Self {
Self {
name,
part,
sum,
sha1,
rom_type,
}
}
pub fn matches_checksum(&self, sum: u32) -> bool {
self.sum == sum
}
pub fn matches_sha1(&self, sha1: &[u8; 20]) -> bool {
self.sha1 == *sha1
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn part(&self) -> &'static str {
self.part
}
pub fn sum8(&self) -> u8 {
(self.sum & 0xFF) as u8
}
pub fn sum16(&self) -> u16 {
(self.sum & 0xFFFF) as u16
}
pub fn sum(&self) -> u32 {
self.sum
}
pub fn sha1(&self) -> &[u8; 20] {
&self.sha1
}
pub fn rom_type(&self) -> RomType {
self.rom_type
}
}
#[allow(dead_code)]
fn identify_rom_checksum(sum: u32) -> impl Iterator<Item = &'static RomEntry> {
ROMS.iter().filter(move |rom| rom.matches_checksum(sum))
}
fn identify_rom_sha1(sha1: &[u8; 20]) -> impl Iterator<Item = &'static RomEntry> {
ROMS.iter().filter(move |rom| rom.matches_sha1(sha1))
}
pub fn identify_rom(
rom_type: &RomType,
_sum: u32,
sha1: [u8; 20],
) -> (Vec<&'static RomEntry>, Vec<(&'static RomEntry, RomType)>) {
let candidates = identify_rom_sha1(&sha1).collect::<Vec<_>>();
let mut matches = Vec::new();
let mut wrong_type_matches = Vec::new();
for entry in candidates {
if entry.rom_type == *rom_type {
matches.push(entry);
} else {
wrong_type_matches.push((entry, *rom_type));
}
}
(matches, wrong_type_matches)
}
pub enum Error {
ParseError,
}