Skip to main content

i8051_disassembler/
pattern.rs

1use std::range::Range;
2
3#[derive(Debug, Clone)]
4pub struct BytePattern {
5    regex: regex::bytes::Regex,
6}
7
8impl BytePattern {
9    /// Parses a byte pattern.
10    ///
11    ///  - `00 11 22` -> matches `0x00 0x11 0x22`
12    ///  - `?? ?? ??` -> matches any three bytes
13    pub fn new(pattern: &str) -> Result<Self, String> {
14        Ok(Self {
15            regex: compile_pattern(pattern)?,
16        })
17    }
18
19    pub fn find(&self, data: &[u8]) -> Option<usize> {
20        self.regex.find(data).map(|m| m.start())
21    }
22
23    pub fn find_all(&self, data: &[u8]) -> impl Iterator<Item = Range<usize>> {
24        self.regex
25            .find_iter(data)
26            .map(|m| (m.start()..m.end()).into())
27    }
28}
29
30fn compile_pattern(pattern: &str) -> Result<regex::bytes::Regex, String> {
31    let mut regex = String::with_capacity(pattern.len());
32    regex.push_str("(?s-u)");
33    for part in pattern.split_whitespace() {
34        if part == "??" {
35            regex.push_str(".");
36        } else if let Ok(byte) = u8::from_str_radix(part, 16) {
37            regex.push_str(&format!(r#"\x{:02X}"#, byte));
38        } else {
39            return Err(format!("invalid byte pattern: {}", part));
40        }
41    }
42
43    regex::bytes::Regex::new(&regex).map_err(|e| e.to_string())
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use hex_literal::hex;
50
51    #[test]
52    fn test_byte_pattern_short() {
53        let pattern = BytePattern::new("11 22 33").unwrap();
54        assert_eq!(pattern.find(&hex!("11 22 33")), Some(0));
55        assert_eq!(pattern.find(&hex!("00 11 22 33")), Some(1));
56        assert_eq!(pattern.find(&hex!("01 02 03 44")), None);
57    }
58
59    #[test]
60    fn test_byte_pattern_long() {
61        let pattern = BytePattern::new("12 ?? ?? e4 93 fa a3 e4 93 f5 83 8a 82 e4 73").unwrap();
62        assert_eq!(
63            pattern.find(&hex!("12 01 02 e4 93 fa a3 e4 93 f5 83 8a 82 e4 73")),
64            Some(0)
65        );
66        assert_eq!(
67            pattern.find(&hex!("00 12 01 02 e4 93 fa a3 e4 93 f5 83 8a 82 e4 73")),
68            Some(1)
69        );
70        assert_eq!(
71            pattern.find(&hex!("01 02 e4 93 fa a3 e4 93 f5 83 8a 82 e4 73")),
72            None
73        );
74    }
75}