Skip to content

Commit 2640a11

Browse files
committed
feat: allowing the match target to suggest a match hint to no longer require the whole length being exposed via the subrange
1 parent 56647f2 commit 2640a11

File tree

2 files changed

+28
-28
lines changed

2 files changed

+28
-28
lines changed

bmatcher-core/src/matcher.rs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
};
1010

1111
/// Hinting where the pattern might be matching the target
12-
enum MatchHint {
12+
pub enum MatchHint {
1313
/// A match hint could not be generated
1414
Unsupported,
1515

@@ -316,33 +316,8 @@ impl<'a, S: Stack<u32>, C: Stack<usize>> BinaryMatcher<'a, S, C> {
316316
return MatchHint::Unsupported;
317317
}
318318

319-
let Some(target_buffer) = self
320-
.target
321-
.subrange(self.current_offset, self.match_length - self.current_offset)
322-
else {
323-
/* memory is not continuous */
324-
return MatchHint::Unsupported;
325-
};
326-
327-
Self::fuzzy_search(&fs_buffer[0..fs_buffer_len], target_buffer)
328-
.map_or(MatchHint::NoMatches, |offset| {
329-
MatchHint::MaybeMatch(self.current_offset + offset)
330-
})
331-
}
332-
333-
fn fuzzy_search(needle: &[u8], haystack: &[u8]) -> Option<usize> {
334-
for offset in 0..(haystack.len() - needle.len()) {
335-
let is_match = needle
336-
.iter()
337-
.zip(&haystack[offset..offset + needle.len()])
338-
.all(|(a, b)| *a == *b);
339-
340-
if is_match {
341-
return Some(offset);
342-
}
343-
}
344-
345-
None
319+
self.target
320+
.match_hint(self.current_offset, &fs_buffer[0..fs_buffer_len])
346321
}
347322

348323
fn next_match_looped(&mut self) -> Option<&[u32]> {

bmatcher-core/src/target.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::matcher::MatchHint;
2+
13
/// A trait for targets that can be matched against a binary pattern.
24
///
35
/// Implementing this trait allows matching against data sources that may not be
@@ -9,6 +11,10 @@ pub trait MatchTarget {
911
/// Returns the total length of the data which will be scaned when matching a binary pattern.
1012
fn match_length(&self) -> usize;
1113

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+
1218
/// Retrieves a subrange of the data, starting at the specified offset and spanning the given number of bytes.
1319
///
1420
/// # Parameters
@@ -34,6 +40,25 @@ impl MatchTarget for &[u8] {
3440
self.len()
3541
}
3642

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+
3762
fn subrange(&self, offset: usize, byte_count: usize) -> Option<&[u8]> {
3863
if offset + byte_count > self.len() {
3964
return None;

0 commit comments

Comments
 (0)