From 677167b97a6a466b91496e9c1ccb11142fc32450 Mon Sep 17 00:00:00 2001 From: Intege-rs Date: Tue, 19 Nov 2024 19:55:34 -0500 Subject: [PATCH] fix cases --- sub/xpat/src/scanner.rs | 76 ++++++++++++++++++++++------------------- x/tests/test_xpat.rs | 12 ++++--- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/sub/xpat/src/scanner.rs b/sub/xpat/src/scanner.rs index 18c7c67..7a10c56 100644 --- a/sub/xpat/src/scanner.rs +++ b/sub/xpat/src/scanner.rs @@ -36,7 +36,7 @@ impl<'a, S: Scannable + ?Sized> Scanner<'a, S> { let upper_limit = self.range.end; while let Some(address) = scan_for_aob(self.bin, self.cursor..upper_limit, aob) { self.cursor = address + 1; - if exec(self.bin, address, self.pat, saves, self.range.clone()) { + if exec(self.bin, address, self.pat, saves, self.range.clone()).is_some() { return true; } } @@ -46,7 +46,7 @@ impl<'a, S: Scannable + ?Sized> Scanner<'a, S> { while self.range.contains(&self.cursor) { let current_cursor = self.cursor; self.cursor += 1; - if exec(self.bin, current_cursor, self.pat, saves, self.range.clone()) { + if exec(self.bin, current_cursor, self.pat, saves, self.range.clone()).is_some() { return true; } } @@ -63,7 +63,7 @@ pub fn exec( pattern: Pattern, saves: &mut [usize], range: Range, -) -> bool { +) -> Option { let mut cursor = address; let mut pc = 0; @@ -87,8 +87,8 @@ pub fn exec( // Compare bytes Atom::Byte(pat_byte) => { - let Some(byte) = read::<_, u8>(bin, cursor) else { return false; }; - if byte & mask != pat_byte & mask { return false; } + let Some(byte) = read::<_, u8>(bin, cursor) else { return None; }; + if byte & mask != pat_byte & mask { return None; } cursor += 1; mask = 0xFF; } @@ -105,9 +105,8 @@ pub fn exec( let skip = if skip == 0 { SKIP_VA } else { skip }; // start running the pattern from pc... - if !exec(bin, cursor, &pattern[pc..], saves, range.clone()) { - return false; - } + exec(bin, cursor, &pattern[pc..], saves, range.clone())?; + cursor = cursor.wrapping_add(skip as usize); mask = 0xff; ext_range = 0; @@ -119,7 +118,7 @@ pub fn exec( match pattern.get(pc) { Some(Atom::Push(_)) => counter += 1, Some(Atom::Pop) => counter -= 1, - None => return true, + None => return Some(cursor), _ => (/**/) } pc += 1; @@ -127,7 +126,7 @@ pub fn exec( } Atom::Pop => { - return true; + return Some(cursor); } Atom::Fuzzy(pat_mask) => { @@ -158,60 +157,60 @@ pub fn exec( } Atom::Jump1 => { - let Some(sbyte) = read::<_, i8>(bin, cursor) else { return false }; + let Some(sbyte) = read::<_, i8>(bin, cursor) else { return None }; cursor = cursor.wrapping_add(sbyte as usize).wrapping_add(1); } Atom::Jump4 => { - let Some(sdword) = read::<_, i32>(bin, cursor) else { return false }; + let Some(sdword) = read::<_, i32>(bin, cursor) else { return None }; cursor = cursor.wrapping_add(sdword as usize).wrapping_add(4); } Atom::Ptr => { - let Some(sptr) = read::<_, usize>(bin, cursor) else { return false }; + let Some(sptr) = read::<_, usize>(bin, cursor) else { return None }; cursor = sptr; } Atom::Pir(slot) => { - let Some(sdword) = read::<_, i32>(bin, cursor) else { return false }; + let Some(sdword) = read::<_, i32>(bin, cursor) else { return None }; let base = saves.get(slot as usize).cloned().unwrap_or(cursor); cursor = base.wrapping_add(sdword as usize); } Atom::Check(slot) => { if let Some(&rva) = saves.get(slot as usize) { - if rva != cursor { return false; } + if rva != cursor { return None; } } } Atom::Aligned(align) => { if cursor & ((1 << align) - 1) != 0 { - return false; + return None; } } Atom::ReadU8(slot) => { - let Some(value) = read::<_, u8>(bin, cursor) else { return false }; + let Some(value) = read::<_, u8>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::ReadI8(slot) => { - let Some(value) = read::<_, i8>(bin, cursor) else { return false }; + let Some(value) = read::<_, i8>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::ReadU16(slot) => { - let Some(value) = read::<_, u16>(bin, cursor) else { return false }; + let Some(value) = read::<_, u16>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::ReadI16(slot) => { - let Some(value) = read::<_, i16>(bin, cursor) else { return false }; + let Some(value) = read::<_, i16>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::ReadU32(slot) => { - let Some(value) = read::<_, u32>(bin, cursor) else { return false }; + let Some(value) = read::<_, u32>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::ReadI32(slot) => { - let Some(value) = read::<_, i32>(bin, cursor) else { return false }; + let Some(value) = read::<_, i32>(bin, cursor) else { return None }; if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ } } Atom::Zero(slot) => { @@ -220,35 +219,40 @@ pub fn exec( } } Atom::Case(next) => { - if exec(bin, cursor, pattern, saves, range.clone()) { + if let Some(nc) = exec(bin, cursor, &pattern[pc..], saves, range.clone()) { + cursor = nc; + // same as Push/Pop except we add the next from the break to the pc. let mut counter = 1; loop { - pc += 1; match pattern.get(pc) { Some(Atom::Case(_)) => counter += 1, Some(Atom::Break(next)) => { counter -= 1; if counter == 0 { - pc += *next as usize + pc += *next as usize + 1; + break; } } - None => return true, + None => return Some(cursor), _ => (/**/) } + pc += 1; } + // panic!("{pc}, {:X?} == {:02X}", pattern.get(pc), bin.chunk_at(cursor).unwrap([1])); + } else { // if the case fails go to the location defined by next pc += next as usize; } } Atom::Break(_next) => { - return true; + return Some(cursor); } Atom::Nop => {} } } - true + Some(cursor) } @@ -260,13 +264,13 @@ pub fn exec_many( saves: &mut [usize], range: Range, limit: u32, -) -> bool { +) -> Option { let mut aob = <[u8; 0x10] as Pod>::uninit(); let aob = make_aob(pattern, &mut aob); let Some(chunk) = bin.chunk_at(address) else { // pattern fails before we even try (out of bounds) - return false; + return None; }; match !aob.is_empty() { @@ -275,21 +279,21 @@ pub fn exec_many( let mut cursor = address; while let Some(address) = scan_for_aob(bin, cursor..upper_limit, aob) { cursor = address; - if exec(bin, cursor, pattern, saves, range.clone()) { - return true; + if let Some(cursor) = exec(bin, cursor, pattern, saves, range.clone()) { + return Some(cursor); } cursor += 1; } - false + None } false => { // try to reduce the limit just in-case we can squeeze some perf out of it for i in 0..(limit as usize).min(chunk.len()) { - if exec(bin, address + i, pattern, saves, range.clone()) { - return true; + if let Some(cursor) = exec(bin, address + i, pattern, saves, range.clone()) { + return Some(cursor); } } - false + None } } } diff --git a/x/tests/test_xpat.rs b/x/tests/test_xpat.rs index a875cfd..2b6a1b4 100644 --- a/x/tests/test_xpat.rs +++ b/x/tests/test_xpat.rs @@ -4,14 +4,16 @@ #[test] pub fn test_pattern() { - let pattern = x::pattern!("E8 [0-4] BB "); - let buffer: &[u8] = &[ 0xAA, 0xE8, 0xBB, 0xE8, 0x00, 0xBB, ]; + let pattern = x::pattern!("E8 ( AA | CC | DD ) E8 "); + use x::xpat::Atom::*; + let pattern = &[Save(0), Byte(0xE8), + Case(2), Byte(0xCC), Break(8), + Case(2), Byte(0xAA), Break(5), + Case(2), Byte(0xCC), Break(2), Nop, Byte(0xDD), Byte(0xE8)]; + let buffer: &[u8] = &[ 0xE8, 0xDD, 0xE8 ]; let mut scanner = x::Scanner::new(buffer, pattern, ..); let mut saves = [0usize;8]; assert!(scanner.next(&mut saves)); - assert_eq!(saves[0], 1); - assert!(scanner.next(&mut saves)); - assert_eq!(saves[0], 3); }