#[cfg(any(target_os = "linux", target_os = "android"))]
pub use crate::linux::process_reader::*;
#[cfg(target_os = "windows")]
pub use crate::windows::process_reader::*;
#[cfg(target_os = "macos")]
pub use crate::mac::process_reader::*;
use std::{ffi::CString, mem::MaybeUninit};
impl ProcessReader {
#[inline]
pub fn read_to_vec(
&self,
src: usize,
length: std::num::NonZeroUsize,
) -> Result<Vec<u8>, CopyFromProcessError> {
let mut output = vec![0u8; length.into()];
let bytes_read = self.read(src, &mut output)?;
output.truncate(bytes_read);
Ok(output)
}
#[inline]
pub fn read_all(&self, src: usize, dst: &mut [u8]) -> Result<(), CopyFromProcessError> {
let mut offset = 0;
while offset < dst.len() {
offset += self.read(src + offset, &mut dst[offset..])?;
}
Ok(())
}
#[inline]
pub fn read_all_to_vec(
&self,
src: usize,
length: usize,
) -> Result<Vec<u8>, CopyFromProcessError> {
let mut output = vec![0u8; length];
self.read_all(src, &mut output)?;
Ok(output)
}
pub fn copy_nul_terminated_string(
&self,
address: usize,
) -> Result<CString, CopyFromProcessError> {
if let Ok(string) = self.copy_nul_terminated_string_word_by_word(address) {
return Ok(string);
}
let mut string = Vec::<u8>::new();
let mut c = 1u8;
while c != 0 {
self.read(address + string.len(), std::slice::from_mut(&mut c))?;
string.push(c);
}
Ok(unsafe { CString::from_vec_with_nul_unchecked(string) })
}
fn copy_nul_terminated_string_word_by_word(
&self,
address: usize,
) -> Result<CString, CopyFromProcessError> {
const WORD_SIZE: usize = size_of::<usize>();
let mut string = Vec::<u8>::new();
let mut word_bytes = [0u8; WORD_SIZE];
loop {
let read_byte_len = self.read(address + string.len(), &mut word_bytes)?;
let mut read_bytes =
unsafe { word_bytes.get_unchecked(..std::cmp::min(read_byte_len, WORD_SIZE)) };
let nul_terminator = read_bytes.iter().position(|&e| e == 0);
if let Some(nul_terminator) = nul_terminator {
read_bytes = &read_bytes[..nul_terminator + 1];
}
string.extend(read_bytes);
if nul_terminator.is_some() {
break;
}
}
Ok(unsafe { CString::from_vec_with_nul_unchecked(string) })
}
#[inline]
pub fn copy_object_uninit<T>(
&self,
src: usize,
) -> Result<MaybeUninit<T>, CopyFromProcessError> {
let mut object = MaybeUninit::<T>::uninit();
self.read_all(src, uninit_as_bytes_mut(&mut object))?;
Ok(object)
}
#[inline]
pub unsafe fn copy_object<T>(&self, src: usize) -> Result<T, CopyFromProcessError> {
self.copy_object_uninit(src)
.map(|object| unsafe { object.assume_init() })
}
#[inline]
pub fn copy_array_uninit<T>(
&self,
src: usize,
num: usize,
) -> Result<Vec<MaybeUninit<T>>, CopyFromProcessError> {
let mut v = Vec::with_capacity(num);
for _ in 0..num {
v.push(MaybeUninit::<T>::uninit());
}
self.read_all(src, uninit_slice_as_bytes_mut(&mut v))?;
Ok(v)
}
#[inline]
pub unsafe fn copy_array<T>(
&self,
src: usize,
num: usize,
) -> Result<Vec<T>, CopyFromProcessError> {
self.copy_array_uninit(src, num)
.map(|v| unsafe { std::mem::transmute::<Vec<MaybeUninit<T>>, Vec<T>>(v) })
}
}
fn uninit_as_bytes_mut<T>(elem: &mut MaybeUninit<T>) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(elem.as_mut_ptr() as *mut u8, size_of::<T>()) }
}
fn uninit_slice_as_bytes_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, size_of::<T>() * slice.len())
}
}