1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use crate::{Result, Endian, Header, ResourceSizeTable, DIGEST};
use crc::Hasher32;
use indexmap::IndexMap;
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
static WIIU_DATA: &str = include_str!("../data/wiiu.json");
static SWITCH_DATA: &str = include_str!("../data/switch.json");
lazy_static::lazy_static! {
pub static ref STOCK_NAMES: HashMap<u32, String> = {
let wiiu: Value = serde_json::from_str(WIIU_DATA).unwrap();
let switch: Value = serde_json::from_str(SWITCH_DATA).unwrap();
wiiu.as_object()
.unwrap()
.get("hash_map")
.unwrap()
.as_object()
.unwrap()
.keys()
.map(|k| k.to_owned())
.chain(
switch.as_object()
.unwrap()
.get("hash_map")
.unwrap()
.as_object()
.unwrap()
.keys()
.map(|k| k.to_owned())
)
.map(|f| (crate::hash(&f), f))
.collect()
};
}
pub fn string_from_hash(crc: u32) -> String {
match STOCK_NAMES.get(&crc) {
Some(s) => s.to_owned(),
None => crc.to_string(),
}
}
#[derive(Debug, Serialize, Deserialize)]
struct JsonRstb {
hash_map: IndexMap<String, u32>,
name_map: IndexMap<String, u32>,
}
impl From<&ResourceSizeTable> for JsonRstb {
fn from(rstb: &ResourceSizeTable) -> JsonRstb {
JsonRstb {
hash_map: rstb
.crc_entries
.iter()
.map(|(k, v)| (string_from_hash(*k), *v))
.collect(),
name_map: rstb.name_entries.clone(),
}
}
}
impl Into<ResourceSizeTable> for JsonRstb {
fn into(self) -> ResourceSizeTable {
let mut digest = DIGEST.lock().unwrap();
ResourceSizeTable {
header: Some(Header {
crc_table_size: self.hash_map.len() as u32,
name_table_size: self.name_map.len() as u32,
}),
crc_entries: self
.hash_map
.iter()
.map(|(k, v)| {
let hash = match k.parse::<u32>() {
Ok(crc) => crc,
Err(_) => {
digest.write(k.as_bytes());
let h = digest.sum32();
digest.reset();
h
}
};
(hash, *v)
})
.collect(),
name_entries: self.name_map,
}
}
}
impl ResourceSizeTable {
pub fn new() -> ResourceSizeTable {
ResourceSizeTable {
header: Some(crate::Header {
crc_table_size: 0,
name_table_size: 0,
}),
crc_entries: IndexMap::new(),
name_entries: IndexMap::new(),
}
}
pub fn new_from_stock(endian: Endian) -> ResourceSizeTable {
let json_rstb: JsonRstb = match endian {
Endian::Big => serde_json::from_str(WIIU_DATA).unwrap(),
Endian::Little => serde_json::from_str(SWITCH_DATA).unwrap(),
};
json_rstb.into()
}
pub fn to_text(&self) -> Result<String> {
let table = JsonRstb::from(self);
Ok(serde_json::to_string_pretty(&table)?)
}
pub fn from_text(text: &str) -> Result<ResourceSizeTable> {
let table: JsonRstb = serde_json::from_str(text)?;
Ok(table.into())
}
}