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
pub mod macros;
pub mod errors;
pub mod wad;
pub mod io;
pub mod utility;
pub mod hash {
use std::{collections::HashMap, fs::File, hash::Hasher, io::{self, BufRead, BufReader, BufWriter, Write}, path::Path};
/// Container for unhashed dictionary
pub struct Dict {
unhashed: HashMap<u64, String>,
}
impl Dict {
/// Create an empty hash dictionary
pub fn new() -> Self {
Dict {
unhashed: HashMap::new(),
}
}
/// Create a hash dictionary with a reserved capacity
pub fn with_capacity(capacity: usize) -> Self {
Dict {
unhashed: HashMap::with_capacity(capacity),
}
}
/// Load hash dictionary entries from a file
pub fn load<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut buffer = String::new();
self.unhashed.clear();
while let Ok(size) = reader.read_line(&mut buffer) {
if size == 0 {
break;
}
let mut parts = buffer.trim().splitn(2, ' ');
if let (Some(key), Some(value)) = (parts.next(), parts.next()) {
if let Ok(key) = u64::from_str_radix(key, 16) {
self.unhashed.insert(key, value.to_string());
}
}
buffer.clear();
}
Ok(())
}
/// Save hash dictionary entries to a file
pub fn save<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
for (key, value) in &self.unhashed {
writeln!(writer, "{} {}", key, value)?;
}
writer.flush()?;
Ok(())
}
/// Get the value associated with a key
pub fn get(&self, key: u64) -> Option<&String> {
self.unhashed.get(&key)
}
/// Add a key-value pair to the dictionary
pub fn add(&mut self, key: u64, value: String) {
self.unhashed.insert(key, value);
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Xxh64(pub u64);
impl Xxh64 {
pub fn new(s: &str) -> Self {
let mut hasher = twox_hash::XxHash64::with_seed(0);
for c in s.bytes() {
let lc = if c >= b'A' && c <= b'Z' {
c - b'A' + b'a'
} else {
c
};
hasher.write_u8(lc);
}
let hash = hasher.finish();
Self(hash)
}
pub fn from_path(path: &Path) -> Self {
let binding = path.to_string_lossy().replace('\\', "/");
let mut s = binding.as_str();
while s.starts_with('.') || s.starts_with('/') {
s = &s[1..]
}
if s.contains('.') && s.rsplit_once('.').map(|(b, _)| b).unwrap_or(s).len() == 16 {
if let Ok(v) = u64::from_str_radix(s.rsplit_once('.').map(|(b, _)| b).unwrap_or(s), 16) {
println!("v {:16x}", v);
return Self(v);
}
}
Self::new(s)
}
}
}