using System.Runtime.InteropServices;
using WhiteMagic.Native;
namespace WhiteMagic;
///
/// Shared ReadProcessMemory / WriteProcessMemory wrappers used by both
/// and . Kept in a single
/// location to keep the two readers byte-for-byte consistent on partial-read handling,
/// write-return semantics, and failure modes.
///
internal static class RpmHelper
{
///
/// Reads up to bytes from in
/// the process identified by . Returns:
///
/// - An empty array if fails and
/// reports zero bytes read.
/// - A truncated array of exactly bytesRead bytes when the call returns
/// but the OS has placed a partial copy in the buffer
/// (for example, ERROR_PARTIAL_COPY).
/// - The full buffer on success.
///
///
public static byte[] ReadBytes(SafeMemoryHandle handle, IntPtr address, int count)
{
byte[] buffer = new byte[count];
bool ok = NativeMethods.ReadProcessMemory(handle, address, buffer, count, out nint bytesRead);
if (!ok && bytesRead == 0)
{
return [];
}
if ((int)bytesRead < count)
{
// Either a successful short read, or a failed-but-partial RPM. In both
// cases honor the bytes the OS actually produced rather than padding.
byte[] partial = new byte[(int)bytesRead];
Buffer.BlockCopy(buffer, 0, partial, 0, (int)bytesRead);
return partial;
}
return buffer;
}
///
/// Writes to in the process
/// identified by . Returns the number of bytes actually
/// written, or 0 on total failure.
///
public static int WriteBytes(SafeMemoryHandle handle, IntPtr address, ReadOnlySpan bytes)
{
if (!NativeMethods.WriteProcessMemory(handle, address, bytes, bytes.Length, out nint written))
{
return 0;
}
return (int)written;
}
}