bmatcher_core/target.rs
1use crate::matcher::MatchHint;
2
3/// A trait for targets that can be matched against a binary pattern.
4///
5/// Implementing this trait allows matching against data sources that may not be
6/// continuous (e.g., fragmented data or packed representations), offering greater flexibility
7/// compared to directly using a `u8` slice.
8///
9/// By default a `u8` slice does implement this trait.
10pub trait MatchTarget {
11 /// Returns the total length of the data which will be scaned when matching a binary pattern.
12 fn match_length(&self) -> usize;
13
14 /// Return a match hint based of the given `byte_sequence` which will be used to evaluate
15 /// the full pattern at that offset.
16 fn match_hint(&self, offset: usize, byte_sequence: &[u8]) -> MatchHint;
17
18 /// Retrieves a subrange of the data, starting at the specified offset and spanning the given number of bytes.
19 ///
20 /// # Parameters
21 /// - `offset`: The starting position within the data.
22 /// - `byte_count`: The number of bytes to include in the subrange.
23 ///
24 /// # Returns
25 /// An `Option` containing a slice of the data if the range is valid; otherwise, `None`.
26 fn subrange(&self, offset: usize, byte_count: usize) -> Option<&[u8]>;
27
28 /// Translates an absolute address to an index within the matchable data.
29 ///
30 /// # Parameters
31 /// - `address`: The absolute address to translate.
32 ///
33 /// # Returns
34 /// An `Option` containing the translated index if the address is valid; otherwise, `None`.
35 fn translate_absolute_address(&self, address: u64) -> Option<usize>;
36}
37
38impl MatchTarget for &[u8] {
39 fn match_length(&self) -> usize {
40 self.len()
41 }
42
43 fn match_hint(&self, offset: usize, byte_sequence: &[u8]) -> MatchHint {
44 if offset + byte_sequence.len() >= self.len() {
45 return MatchHint::NoMatches;
46 }
47
48 for offset in offset..(self.len() - byte_sequence.len()) {
49 let is_match = byte_sequence
50 .iter()
51 .zip(&self[offset..offset + byte_sequence.len()])
52 .all(|(a, b)| *a == *b);
53
54 if is_match {
55 return MatchHint::MaybeMatch(offset);
56 }
57 }
58
59 MatchHint::NoMatches
60 }
61
62 fn subrange(&self, offset: usize, byte_count: usize) -> Option<&[u8]> {
63 if offset + byte_count > self.len() {
64 return None;
65 }
66
67 Some(&self[offset..offset + byte_count])
68 }
69
70 fn translate_absolute_address(&self, address: u64) -> Option<usize> {
71 let own_address = self.as_ptr() as u64;
72 if own_address < address || address >= own_address + self.len() as u64 {
73 None
74 } else {
75 Some((address - own_address) as usize)
76 }
77 }
78}