use crate::Matcher;
use core::{ops::RangeInclusive, slice::from_raw_parts};
#[inline]
pub unsafe fn terminated_array<'a, T: PartialEq>(mut first: *const T, last: T) -> &'a [T] {
assert!(!first.is_null());
let mut len = 0;
while *first != last {
len += 1;
first = first.add(1);
}
core::slice::from_raw_parts(first.sub(len), len)
}
#[inline]
pub unsafe fn terminated_array_mut<'a, T: PartialEq>(mut first: *mut T, last: T) -> &'a mut [T] {
assert!(!first.is_null());
let mut len = 0;
while *first != last {
len += 1;
first = first.add(1);
}
core::slice::from_raw_parts_mut(first.sub(len), len)
}
#[inline]
pub unsafe fn resolve_multilevel<T>(mut base: *const u8, offsets: &[usize]) -> *const T {
offsets.iter().enumerate().for_each(|(i, &o)| {
if i != offsets.len() - 1 {
base = base.add(o).cast::<*const u8>().read();
} else {
base = base.add(o);
}
});
base.cast()
}
#[inline]
pub unsafe fn resolve_multilevel_mut<T>(mut base: *mut u8, offsets: &[usize]) -> *mut T {
offsets.iter().enumerate().for_each(|(i, &o)| {
if i != offsets.len() - 1 {
base = base.add(o).cast::<*mut u8>().read();
} else {
base = base.add(o);
}
});
base.cast()
}
#[inline]
pub unsafe fn find_pattern(
pat: impl Matcher,
start: *const u8,
len: usize,
) -> impl Iterator<Item = *const u8> {
assert!(!start.is_null());
from_raw_parts::<u8>(start, len)
.windows(pat.len())
.enumerate()
.filter_map(move |(i, bytes)| {
if pat.matches(bytes) {
Some(start.add(i))
} else {
None
}
})
}
#[inline]
pub unsafe fn find_pattern_range(
pat: impl Matcher,
range: RangeInclusive<usize>,
) -> impl Iterator<Item = *const u8> {
find_pattern(pat, *range.start() as _, *range.end() - *range.start())
}
#[cfg(test)]
mod tests {
use crate::resolve_multilevel;
use core::{mem::zeroed, ptr::addr_of};
#[test]
fn test_multilevel() {
#[repr(C)]
struct S1 {
pad: [u8; 0x10],
next: Box<S2>,
}
#[repr(C)]
struct S2 {
pad: [u8; 0x20],
next: Box<S3>,
}
#[repr(C)]
struct S3 {
pad: [u8; 0x30],
value: usize,
}
let s1 = unsafe {
S1 {
next: S2 {
next: S3 {
value: 1337,
pad: zeroed(),
}
.into(),
pad: zeroed(),
}
.into(),
pad: zeroed(),
}
};
unsafe {
let ptr = resolve_multilevel::<usize>(addr_of!(s1).cast(), &[0x10, 0x20, 0x30]);
assert_eq!(*ptr, 1337);
}
}
}