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}