pub type Pattern<'l> = &'l[Atom]; /// Pattern atoms. /// /// The scanner will silently ignore nonsensical arguments. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Atom { /// Matches a single byte. Byte(u8), /// Captures the cursor in the save array at the specified index. Save(u8), /// After a Pop later continue matching at the current cursor plus the argument. Push(u8), /// Pops the cursor from the stack and continues matching. Pop, /// Sets a mask to apply on next byte match. Fuzzy(u8), /// Skips a fixed number of bytes. Skip(u8), /// Rewinds the cursor a fixed number of bytes. Back(u8), /// Extends the push, skip, back and many range by `argument * 256`. Rangext(u8), /// Looks for the next pattern at most a certain number of bytes ahead. Many(u8), /// Follows a signed 1 byte jump. /// /// Reads the byte under the cursor, sign extends it, adds it plus 1 to the cursor and continues matching. Jump1, /// Follows a signed 4 byte jump. /// /// Reads the dword under the cursor and adds it plus 4 to the cursor and continues matching. Jump4, /// Follows an absolute pointer. /// /// Reads the pointer under the cursor, translates it to an RVA, assigns it to the cursor and continues matching. /// /// Matching fails immediately when translation to an RVA fails. Ptr, /// Follows a position independent reference. /// /// Reads the dword under the cursor and adds it to the saved cursor for the given slot and continues matching. Pir(u8), /// Compares the cursor with the value in the given save slot and fails if they're not equal. Check(u8), /// Checks if the cursor is aligned to `(1 << value)`. Aligned(u8), /// Reads and sign-extends the byte under the cursor, writes to the given slot and advances the cursor by 1. ReadI8(u8), /// Reads and zero-extends the byte under the cursor, writes to the given slot and advances the cursor by 1. ReadU8(u8), /// Reads and sign-extends the word under the cursor, writes to the given slot and advances the cursor by 2. ReadI16(u8), /// Reads and zero-extends the word under the cursor, writes to the given slot and advances the cursor by 2. ReadU16(u8), /// Reads the dword under the cursor, writes to the given slot and advances the cursor by 4. ReadI32(u8), /// Reads the dword under the cursor, writes to the given slot and advances the cursor by 4. ReadU32(u8), /// Writes zero to the given save slot. Zero(u8), /// Sets a retry point when matching fails. /// /// When matching fails the cursor is restored and matching begins again skipping _N_ atoms. Case(u8), /// Continues matching after a case atom, skipping the next _N_ atoms. Break(u8), /// Null instruction, used to make the parser easier to write. Nop, } impl Atom { pub fn save_len(pat: &[Atom]) -> usize { pat.iter().filter_map(|&atom| { match atom { Atom::Save(slot) | Atom::Pir(slot) | Atom::Check(slot) | Atom::Zero(slot) | Atom::ReadI8(slot) | Atom::ReadI16(slot) | Atom::ReadI32(slot) | Atom::ReadU8(slot) | Atom::ReadU16(slot)| Atom::ReadU32(slot) => Some(slot as usize + 1), _ => None, } }).max().unwrap_or(0) } }