wgtk/space/section/
bwst.rs

1use std::io::{Read, Seek, SeekFrom};
2use std::collections::HashMap;
3
4use super::{Section, SectionId};
5use crate::util::io::WgReadExt;
6use crate::util::fnv::fnv1a_64;
7
8
9/// StringTable section, providing a mapping from strings' FNV hashes to strings.
10#[derive(Debug)]
11pub struct BWST {
12    pub strings: HashMap<u32, String>
13}
14
15impl Section for BWST {
16
17    const ID: &'static SectionId = b"BWST";
18
19    fn decode<R: Read + Seek>(read: &mut R) -> std::io::Result<Self> {
20
21        let entries = read.read_vector(|buf| {
22            Ok((buf.read_u32()?, buf.read_u32()? as u64, buf.read_u32()? as usize))
23        })?;
24
25        // Currently useless because entries should be valid.
26        let strings_len = read.read_u32()? as u64;
27        let strings_off = read.stream_position()?;
28
29        let mut strings = HashMap::with_capacity(entries.len());
30
31        for (_key, off, len) in entries {
32            read.seek(SeekFrom::Start(strings_off + off))?;
33            let mut buf = Vec::with_capacity(len);
34            buf.resize(len, 0);
35            read.read_exact(&mut buf[..])?;
36            let fnv = get_hash(&buf[..]);
37            strings.insert(fnv, String::from_utf8(buf).unwrap());
38        }
39
40        read.seek(SeekFrom::Start(strings_off + strings_len))?;
41
42        Ok(BWST { strings })
43
44    }
45
46}
47
48impl BWST {
49
50    /// Try to get a string from its hash.
51    pub fn get_string(&self, hash: u32) -> Option<&str> {
52        Some(self.strings.get(&hash)?.as_str())
53    }
54
55}
56
57
58/// Get compiled space's FNV hash section for given bytes.
59pub fn get_hash(data: &[u8]) -> u32 {
60    (fnv1a_64(data) & 0xFFFFFFFF) as u32
61}
62
63/// Get compiled space's FNV hash section for given string.
64pub fn get_hash_from_str(string: &str) -> u32 {
65    get_hash(string.as_bytes())
66}