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
use std::io::{Read, Write};
use {Error, Header, SectionContent};
use std::collections::hash_map::{Entry, HashMap};

#[derive(Debug, Default, Clone)]
pub struct Strtab {
    hash: Option<HashMap<Vec<u8>, usize>>,
    data: Vec<u8>,
}

impl Strtab {
    pub fn len(&self, _: &Header) -> usize {
        self.data.len()
    }
    pub fn entsize(_: &Header) -> usize {
        1
    }
    pub fn from_reader<R>(
        mut io: R,
        _: Option<&SectionContent>,
        _: &Header,
    ) -> Result<SectionContent, Error>
    where
        R: Read,
    {
        let mut data = Vec::new();
        io.read_to_end(&mut data)?;
        Ok(SectionContent::Strtab(Strtab{
            hash: None,
            data: data,
        }))
    }

    pub fn to_writer<W>(
        &self,
        mut io: W,
        _: &Header,
    ) -> Result<(usize), Error>
    where
        W: Write,
    {
        io.write(&self.data)?;
        Ok(self.data.len())
    }

    pub fn get(&self, i: usize) -> Vec<u8> {
        if i >= self.data.len() {
            println!("pointer {} into strtab extends beyond section size", i);
            return b"<corrupt>".to_vec();
        }
        self.data[i..].split(|c| *c == 0).next().unwrap_or(&[0; 0]).to_vec()
    }

    pub fn insert(&mut self, ns: &[u8]) -> usize {

        //special handling for null. for some reason rusts hashmap doesn't do that correctly
        if self.data.len() < 1 {
            self.data.push(0)
        }
        if ns.len() == 0 {
            return 0;
        }

        //TODO this is less efficient than just scanning data, so it's kinda pointless
        if self.hash == None {
            let mut hash = HashMap::new();

            let mut n = Vec::new();
            let mut start = 0;
            for i in 0..self.data.len() {
                let c = self.data[i];
                if c == 0 {
                    for x in 0..self.data.len() {
                        hash.insert(n[x..].to_vec(), start + x);
                    }
                    start = i + 1;
                    n = Vec::new()
                } else {
                    n.push(c);
                }
            }
            self.hash = Some(hash);
        }

        match self.hash.as_mut().unwrap().entry(ns.to_vec()) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let i = self.data.len();
                self.data.extend(ns);
                self.data.extend(&[0; 1]);
                entry.insert(i);
                i
            }
        }
    }
}