use windows::Win32::Foundation::HANDLE;
use crate::memory::MemoryError;
use super::BytesSwitch;
#[derive(Debug)]
pub struct BytesSwitchBuilder {
handle: Option<HANDLE>,
target_address: Option<usize>,
original_bytes: Option<Vec<u8>>,
patch_bytes: Option<Vec<u8>>,
byte_count: Option<usize>,
nop_mode: bool,
}
impl BytesSwitchBuilder {
pub fn new() -> Self {
Self {
handle: None,
target_address: None,
original_bytes: None,
patch_bytes: None,
byte_count: None,
nop_mode: false,
}
}
pub fn handle(mut self, handle: HANDLE) -> Self {
self.handle = Some(handle);
self
}
pub fn target_address(mut self, addr: usize) -> Self {
self.target_address = Some(addr);
self
}
pub fn original_bytes(mut self, bytes: Vec<u8>) -> Self {
self.original_bytes = Some(bytes);
self
}
pub fn patch_bytes(mut self, bytes: Vec<u8>) -> Self {
self.patch_bytes = Some(bytes);
self
}
pub fn byte_count(mut self, count: usize) -> Self {
self.byte_count = Some(count);
self
}
pub fn nop_mode(mut self) -> Self {
self.nop_mode = true;
self
}
pub fn build(self) -> Result<BytesSwitch, MemoryError> {
let handle = self.handle.ok_or_else(|| {
MemoryError::WriteFailed(
"handle must be set. Call .handle(handle) before build().".to_string()
)
})?;
let target_address = self.target_address.ok_or_else(|| {
MemoryError::WriteFailed(
"target_address must be set. Call .target_address(addr) before build().".to_string()
)
})?;
let (original_bytes, patch_bytes) = if self.nop_mode {
let byte_count = self.byte_count.ok_or_else(|| {
MemoryError::WriteFailed(
"byte_count must be set when using nop_mode. Call .byte_count(n) before build().".to_string()
)
})?;
use crate::memory::read_memory_bytes;
let original = read_memory_bytes(handle, target_address, byte_count)?;
let patch = vec![0x90; byte_count];
(original, patch)
} else {
let original = self.original_bytes.ok_or_else(|| {
MemoryError::WriteFailed(
"original_bytes must be set. Call .original_bytes(bytes) or enable .nop_mode().".to_string()
)
})?;
let patch = self.patch_bytes.ok_or_else(|| {
MemoryError::WriteFailed(
"patch_bytes must be set. Call .patch_bytes(bytes) or enable .nop_mode().".to_string()
)
})?;
if original.len() != patch.len() {
return Err(MemoryError::WriteFailed(
format!(
"Original and patch bytes length mismatch: {} vs {}",
original.len(),
patch.len()
)
));
}
(original, patch)
};
Ok(BytesSwitch::new(handle, target_address, original_bytes, patch_bytes))
}
}