i8051_disassembler/
pattern.rs1use std::range::Range;
2
3#[derive(Debug, Clone)]
4pub struct BytePattern {
5 regex: regex::bytes::Regex,
6}
7
8impl BytePattern {
9 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(®ex).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}