Skip to main content

jagged/
util.rs

1use bytes::Bytes;
2use bzip2::read::BzDecoder;
3use std::io::prelude::*;
4
5pub(crate) fn decompress(data: Bytes) -> Option<Bytes> {
6    // The required header, "BZh1", that is missing in jag archives
7    // must be appended
8    let mut concatenated = vec![66u8, 90, 104, 49];
9    concatenated.extend(data.into_iter());
10
11    let mut decompressor = BzDecoder::new(concatenated.as_slice());
12    let mut decompressed_data = Vec::new();
13
14    // we don't need to know the specific error, just that decompression
15    // failed, hence why this func returns an Option rather than Result.
16    match decompressor.read_to_end(&mut decompressed_data) {
17        Ok(_) => Some(Bytes::from(decompressed_data)),
18        Err(_) => None,
19    }
20}
21
22pub(crate) fn entry_hash(entry: String) -> u32 {
23    use std::num::Wrapping;
24
25    let mut hash = Wrapping(0);
26    let multiplier = Wrapping(61);
27
28    for ch in entry.to_ascii_uppercase().as_bytes().iter() {
29        hash *= multiplier;
30        hash += Wrapping(*ch as u32 - 32);
31    }
32
33    hash.0
34}
35
36#[cfg(test)]
37mod util_tests {
38    #[test]
39    fn test_known_entry_hashes() {
40        use std::collections::HashMap;
41
42        let mut map = HashMap::new();
43
44        map.insert("jagex.jag", 1827744299);
45        map.insert("testing", 903262442);
46        map.insert("hello.world", 241581634);
47        map.insert("1234567890", 2318125913);
48        map.insert("AbCdEfGhIJkLmNoPqRsTuVwXyZ", 4115466251);
49
50        for (k, v) in map.into_iter() {
51            assert_eq!(super::entry_hash(k.into()), v);
52        }
53    }
54}