use std::collections::HashMap;
use std::hash::Hasher;
use std::io::Cursor;
use twox_hash::XxHash64;
static HASHES_U: &'static str = include_str!("../data/wiiu_hashes.json");
static HASHES_NX: &'static str = include_str!("../data/switch_hashes.json");
type HashTable = HashMap<&'static str, Vec<u64>>;
#[derive(Debug, Eq, PartialEq)]
pub enum Platform {
WiiU,
Switch,
}
pub fn get_hash_table(platform: &Platform) -> HashTable {
match platform {
Platform::WiiU => serde_json::from_str(HASHES_U).unwrap(),
Platform::Switch => serde_json::from_str(HASHES_NX).unwrap(),
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct StockHashTable {
table: HashTable,
}
impl StockHashTable {
pub fn new(platform: &Platform) -> StockHashTable {
StockHashTable {
table: get_hash_table(platform),
}
}
pub fn get_stock_files(&self) -> impl Iterator<Item = &&str> {
self.table.keys()
}
pub fn list_stock_files(&self) -> Vec<String> {
self.table.keys().map(|x| x.to_string()).collect()
}
pub fn is_file_modded<S: AsRef<str>, D: AsRef<[u8]>>(
&self,
file_name: S,
data: D,
flag_new: bool,
) -> bool {
match self.table.contains_key(file_name.as_ref()) {
true => {
let data = data.as_ref();
let mut hasher = XxHash64::with_seed(0);
if &data[0..4] == b"Yaz0" {
hasher.write(
&yaz0::Yaz0Archive::new(Cursor::new(data))
.unwrap()
.decompress()
.unwrap(),
);
} else {
hasher.write(data);
}
let hash: u64 = hasher.finish();
!self.table[file_name.as_ref()].contains(&hash)
}
false => flag_new,
}
}
pub fn is_file_new<S: AsRef<str>>(&self, file_name: S) -> bool {
!self.table.contains_key(file_name.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cst_hash_table() {
get_hash_table(&Platform::WiiU);
get_hash_table(&Platform::Switch);
}
#[test]
fn check_val() {
let table = get_hash_table(&Platform::WiiU);
assert_eq!(
table
.get("Actor/ModelList/DgnMrgPrt_Dungeon023.bmodellist")
.unwrap(),
&vec![3305211212481695363u64, 6042644272755124234u64]
)
}
#[test]
fn is_file_modded() {
let tbl = StockHashTable::new(&Platform::Switch);
assert_eq!(
tbl.is_file_modded(
"Actor/Physics/FldObj_MountainSheikerWall_A_06.bphysics",
b"Random data",
true
),
true
)
}
#[test]
fn print_files() {
let tbl = StockHashTable::new(&Platform::WiiU);
for file in tbl.get_stock_files() {
println!("{}", file)
}
}
}