From 41fdb3a1402dd08f543d46e60b165734ac5d9861 Mon Sep 17 00:00:00 2001 From: nattthebear Date: Mon, 3 Jul 2017 14:44:30 -0400 Subject: [PATCH] Lay down the CR/LF law --- BizHawk.Common/BizInvoke/MemoryBlock.cs | 954 ++++++++++++------------ 1 file changed, 477 insertions(+), 477 deletions(-) diff --git a/BizHawk.Common/BizInvoke/MemoryBlock.cs b/BizHawk.Common/BizInvoke/MemoryBlock.cs index 3407960818..6f353cbc70 100644 --- a/BizHawk.Common/BizInvoke/MemoryBlock.cs +++ b/BizHawk.Common/BizInvoke/MemoryBlock.cs @@ -1,539 +1,539 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using System.IO; - -namespace BizHawk.Common.BizInvoke -{ - public sealed class MemoryBlock : IDisposable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.IO; + +namespace BizHawk.Common.BizInvoke +{ + public sealed class MemoryBlock : IDisposable { - /// - /// starting address of the memory block - /// + /// + /// starting address of the memory block + /// public ulong Start { get; private set; } - /// - /// total size of the memory block - /// + /// + /// total size of the memory block + /// public ulong Size { get; private set; } - /// - /// ending address of the memory block; equal to start + size - /// + /// + /// ending address of the memory block; equal to start + size + /// public ulong End { get; private set; } - /// - /// handle returned by CreateFileMapping - /// + /// + /// handle returned by CreateFileMapping + /// private IntPtr _handle; - /// - /// true if this is currently swapped in - /// + /// + /// true if this is currently swapped in + /// public bool Active { get; private set; } - /// - /// stores last set memory protection value for each page - /// + /// + /// stores last set memory protection value for each page + /// private readonly Protection[] _pageData; - /// - /// snapshot for XOR buffer - /// - private byte[] _snapshot; - + /// + /// snapshot for XOR buffer + /// + private byte[] _snapshot; + public byte[] XorHash { get; private set; } - /// - /// get a page index within the block - /// - private int GetPage(ulong addr) - { - if (addr < Start || addr >= End) - throw new ArgumentOutOfRangeException(); - - return (int)((addr - Start) >> WaterboxUtils.PageShift); + /// + /// get a page index within the block + /// + private int GetPage(ulong addr) + { + if (addr < Start || addr >= End) + throw new ArgumentOutOfRangeException(); + + return (int)((addr - Start) >> WaterboxUtils.PageShift); } - /// - /// get a start address for a page index within the block - /// - private ulong GetStartAddr(int page) - { - return ((ulong)page << WaterboxUtils.PageShift) + Start; + /// + /// get a start address for a page index within the block + /// + private ulong GetStartAddr(int page) + { + return ((ulong)page << WaterboxUtils.PageShift) + Start; } - /// - /// allocate size bytes at any address - /// - /// - public MemoryBlock(ulong size) - : this(0, size) - { + /// + /// allocate size bytes at any address + /// + /// + public MemoryBlock(ulong size) + : this(0, size) + { } - /// - /// allocate size bytes starting at a particular address - /// - /// - /// - public MemoryBlock(ulong start, ulong size) - { - if (!WaterboxUtils.Aligned(start)) - throw new ArgumentOutOfRangeException(); - if (size == 0) - throw new ArgumentOutOfRangeException(); - size = WaterboxUtils.AlignUp(size); - - _handle = Kernel32.CreateFileMapping(Kernel32.INVALID_HANDLE_VALUE, IntPtr.Zero, - Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, (uint)(size >> 32), (uint)size, null); - - if (_handle == IntPtr.Zero) - throw new InvalidOperationException("CreateFileMapping() returned NULL"); - Start = start; - End = start + size; - Size = size; - _pageData = new Protection[GetPage(End - 1) + 1]; + /// + /// allocate size bytes starting at a particular address + /// + /// + /// + public MemoryBlock(ulong start, ulong size) + { + if (!WaterboxUtils.Aligned(start)) + throw new ArgumentOutOfRangeException(); + if (size == 0) + throw new ArgumentOutOfRangeException(); + size = WaterboxUtils.AlignUp(size); + + _handle = Kernel32.CreateFileMapping(Kernel32.INVALID_HANDLE_VALUE, IntPtr.Zero, + Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, (uint)(size >> 32), (uint)size, null); + + if (_handle == IntPtr.Zero) + throw new InvalidOperationException("CreateFileMapping() returned NULL"); + Start = start; + End = start + size; + Size = size; + _pageData = new Protection[GetPage(End - 1) + 1]; } - /// - /// activate the memory block, swapping it in at the specified address - /// - public void Activate() - { - if (Active) - throw new InvalidOperationException("Already active"); - if (Kernel32.MapViewOfFileEx(_handle, Kernel32.FileMapAccessType.Read | Kernel32.FileMapAccessType.Write | Kernel32.FileMapAccessType.Execute, - 0, 0, Z.UU(Size), Z.US(Start)) != Z.US(Start)) - { - throw new InvalidOperationException("MapViewOfFileEx() returned NULL"); - } - ProtectAll(); - Active = true; + /// + /// activate the memory block, swapping it in at the specified address + /// + public void Activate() + { + if (Active) + throw new InvalidOperationException("Already active"); + if (Kernel32.MapViewOfFileEx(_handle, Kernel32.FileMapAccessType.Read | Kernel32.FileMapAccessType.Write | Kernel32.FileMapAccessType.Execute, + 0, 0, Z.UU(Size), Z.US(Start)) != Z.US(Start)) + { + throw new InvalidOperationException("MapViewOfFileEx() returned NULL"); + } + ProtectAll(); + Active = true; } - /// - /// deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in - /// - public void Deactivate() - { - if (!Active) - throw new InvalidOperationException("Not active"); - if (!Kernel32.UnmapViewOfFile(Z.US(Start))) - throw new InvalidOperationException("UnmapViewOfFile() returned NULL"); - Active = false; + /// + /// deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in + /// + public void Deactivate() + { + if (!Active) + throw new InvalidOperationException("Not active"); + if (!Kernel32.UnmapViewOfFile(Z.US(Start))) + throw new InvalidOperationException("UnmapViewOfFile() returned NULL"); + Active = false; } - /// - /// Memory protection constant - /// - public enum Protection : byte - { - None, R, RW, RX + /// + /// Memory protection constant + /// + public enum Protection : byte + { + None, R, RW, RX } - /// - /// Get a stream that can be used to read or write from part of the block. Does not check for or change Protect()! - /// - public Stream GetStream(ulong start, ulong length, bool writer) - { - if (start < Start) - throw new ArgumentOutOfRangeException(nameof(start)); - if (start + length > End) - throw new ArgumentOutOfRangeException(nameof(length)); - - return new MemoryViewStream(!writer, writer, (long)start, (long)length, this); + /// + /// Get a stream that can be used to read or write from part of the block. Does not check for or change Protect()! + /// + public Stream GetStream(ulong start, ulong length, bool writer) + { + if (start < Start) + throw new ArgumentOutOfRangeException(nameof(start)); + if (start + length > End) + throw new ArgumentOutOfRangeException(nameof(length)); + + return new MemoryViewStream(!writer, writer, (long)start, (long)length, this); } - /// - /// get a stream that can be used to read or write from part of the block. - /// both reads and writes will be XORed against an earlier recorded snapshot - /// - public Stream GetXorStream(ulong start, ulong length, bool writer) - { - if (start < Start) - throw new ArgumentOutOfRangeException(nameof(start)); - if (start + length > End) - throw new ArgumentOutOfRangeException(nameof(length)); - if (_snapshot == null) - throw new InvalidOperationException("No snapshot taken!"); - - return new MemoryViewXorStream(!writer, writer, (long)start, (long)length, this, _snapshot, (long)(start - Start)); + /// + /// get a stream that can be used to read or write from part of the block. + /// both reads and writes will be XORed against an earlier recorded snapshot + /// + public Stream GetXorStream(ulong start, ulong length, bool writer) + { + if (start < Start) + throw new ArgumentOutOfRangeException(nameof(start)); + if (start + length > End) + throw new ArgumentOutOfRangeException(nameof(length)); + if (_snapshot == null) + throw new InvalidOperationException("No snapshot taken!"); + + return new MemoryViewXorStream(!writer, writer, (long)start, (long)length, this, _snapshot, (long)(start - Start)); } - /// - /// take a snapshot of the entire memory block's contents, for use in GetXorStream - /// - public void SaveXorSnapshot() - { - if (_snapshot != null) - throw new InvalidOperationException("Snapshot already taken"); - if (!Active) + /// + /// take a snapshot of the entire memory block's contents, for use in GetXorStream + /// + public void SaveXorSnapshot() + { + if (_snapshot != null) + throw new InvalidOperationException("Snapshot already taken"); + if (!Active) throw new InvalidOperationException("Not active"); // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want // that to complicate things - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) - throw new InvalidOperationException("VirtualProtect() returned FALSE!"); - - _snapshot = new byte[Size]; - var ds = new MemoryStream(_snapshot, true); - var ss = GetStream(Start, Size, false); - ss.CopyTo(ds); - XorHash = WaterboxUtils.Hash(_snapshot); - - ProtectAll(); - } - + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) + throw new InvalidOperationException("VirtualProtect() returned FALSE!"); + + _snapshot = new byte[Size]; + var ds = new MemoryStream(_snapshot, true); + var ss = GetStream(Start, Size, false); + ss.CopyTo(ds); + XorHash = WaterboxUtils.Hash(_snapshot); + + ProtectAll(); + } + /// /// take a hash of the current full contents of the block, including unreadable areas /// - /// + /// public byte[] FullHash() { - if (!Active) + if (!Active) throw new InvalidOperationException("Not active"); // temporarily switch the entire block to `R` - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) throw new InvalidOperationException("VirtualProtect() returned FALSE!"); var ret = WaterboxUtils.Hash(GetStream(Start, Size, false)); ProtectAll(); return ret; - } - - private static Kernel32.MemoryProtection GetKernelMemoryProtectionValue(Protection prot) - { - Kernel32.MemoryProtection p; - switch (prot) - { - case Protection.None: p = Kernel32.MemoryProtection.NOACCESS; break; - case Protection.R: p = Kernel32.MemoryProtection.READONLY; break; - case Protection.RW: p = Kernel32.MemoryProtection.READWRITE; break; - case Protection.RX: p = Kernel32.MemoryProtection.EXECUTE_READ; break; - default: throw new ArgumentOutOfRangeException(nameof(prot)); - } - return p; } - /// - /// restore all recorded protections - /// - private void ProtectAll() - { - int ps = 0; - for (int i = 0; i < _pageData.Length; i++) - { - if (i == _pageData.Length - 1 || _pageData[i] != _pageData[i + 1]) - { - var p = GetKernelMemoryProtectionValue(_pageData[i]); - ulong zstart = GetStartAddr(ps); - ulong zend = GetStartAddr(i + 1); - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(zstart), Z.UU(zend - zstart), p, out old)) - throw new InvalidOperationException("VirtualProtect() returned FALSE!"); - ps = i + 1; - } - } + private static Kernel32.MemoryProtection GetKernelMemoryProtectionValue(Protection prot) + { + Kernel32.MemoryProtection p; + switch (prot) + { + case Protection.None: p = Kernel32.MemoryProtection.NOACCESS; break; + case Protection.R: p = Kernel32.MemoryProtection.READONLY; break; + case Protection.RW: p = Kernel32.MemoryProtection.READWRITE; break; + case Protection.RX: p = Kernel32.MemoryProtection.EXECUTE_READ; break; + default: throw new ArgumentOutOfRangeException(nameof(prot)); + } + return p; } - /// - /// set r/w/x protection on a portion of memory. rounded to encompassing pages - /// - public void Protect(ulong start, ulong length, Protection prot) - { - if (length == 0) - return; - int pstart = GetPage(start); - int pend = GetPage(start + length - 1); - - var p = GetKernelMemoryProtectionValue(prot); - for (int i = pstart; i <= pend; i++) + /// + /// restore all recorded protections + /// + private void ProtectAll() + { + int ps = 0; + for (int i = 0; i < _pageData.Length; i++) + { + if (i == _pageData.Length - 1 || _pageData[i] != _pageData[i + 1]) + { + var p = GetKernelMemoryProtectionValue(_pageData[i]); + ulong zstart = GetStartAddr(ps); + ulong zend = GetStartAddr(i + 1); + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(zstart), Z.UU(zend - zstart), p, out old)) + throw new InvalidOperationException("VirtualProtect() returned FALSE!"); + ps = i + 1; + } + } + } + + /// + /// set r/w/x protection on a portion of memory. rounded to encompassing pages + /// + public void Protect(ulong start, ulong length, Protection prot) + { + if (length == 0) + return; + int pstart = GetPage(start); + int pend = GetPage(start + length - 1); + + var p = GetKernelMemoryProtectionValue(prot); + for (int i = pstart; i <= pend; i++) _pageData[i] = prot; // also store the value for later use if (Active) // it's legal to Protect() if we're not active; the information is just saved for the next activation - { - var computedStart = WaterboxUtils.AlignDown(start); - var computedEnd = WaterboxUtils.AlignUp(start + length); - var computedLength = computedEnd - computedStart; - - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(computedStart), - Z.UU(computedLength), p, out old)) - throw new InvalidOperationException("VirtualProtect() returned FALSE!"); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_handle != IntPtr.Zero) - { - if (Active) - Deactivate(); - Kernel32.CloseHandle(_handle); - _handle = IntPtr.Zero; - } - } - - ~MemoryBlock() - { - Dispose(false); - } - - private class MemoryViewStream : Stream - { - public MemoryViewStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner) - { - _readable = readable; - _writable = writable; - _ptr = ptr; - _length = length; - _owner = owner; - _pos = 0; - } - - private void EnsureNotDisposed() - { - if (_owner.Start == 0) - throw new ObjectDisposedException("MemoryBlock"); - } - - private MemoryBlock _owner; - - private readonly bool _readable; - private readonly bool _writable; - - private long _length; - private long _pos; - private readonly long _ptr; - - public override bool CanRead => _readable; - public override bool CanSeek => true; - public override bool CanWrite => _writable; - public override void Flush() { } - public override long Length => _length; - - public override long Position - { - get { return _pos; } - set - { - if (value < 0 || value > _length) - throw new ArgumentOutOfRangeException(); - _pos = value; - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (!_readable) - throw new InvalidOperationException(); - if (count < 0 || count + offset > buffer.Length) - throw new ArgumentOutOfRangeException(); - EnsureNotDisposed(); - count = (int)Math.Min(count, _length - _pos); - Marshal.Copy(Z.SS(_ptr + _pos), buffer, offset, count); - _pos += count; - return count; - } - - public override long Seek(long offset, SeekOrigin origin) - { - long newpos; - switch (origin) - { - default: - case SeekOrigin.Begin: - newpos = offset; - break; - case SeekOrigin.Current: - newpos = _pos + offset; - break; - case SeekOrigin.End: - newpos = _length + offset; - break; - } - Position = newpos; - return newpos; - } - - public override void SetLength(long value) - { - throw new InvalidOperationException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (!_writable) - throw new InvalidOperationException(); - if (count < 0 || count + offset > buffer.Length) - throw new ArgumentOutOfRangeException(); - if (count > _length - _pos) - throw new ArgumentOutOfRangeException(); - EnsureNotDisposed(); - Marshal.Copy(buffer, offset, Z.SS(_ptr + _pos), count); - _pos += count; - } - } - - private class MemoryViewXorStream : MemoryViewStream - { - public MemoryViewXorStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner, - byte[] initial, long offset) - : base(readable, writable, ptr, length, owner) - { - _initial = initial; - _offset = (int)offset; + { + var computedStart = WaterboxUtils.AlignDown(start); + var computedEnd = WaterboxUtils.AlignUp(start + length); + var computedLength = computedEnd - computedStart; + + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(computedStart), + Z.UU(computedLength), p, out old)) + throw new InvalidOperationException("VirtualProtect() returned FALSE!"); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (_handle != IntPtr.Zero) + { + if (Active) + Deactivate(); + Kernel32.CloseHandle(_handle); + _handle = IntPtr.Zero; + } + } + + ~MemoryBlock() + { + Dispose(false); + } + + private class MemoryViewStream : Stream + { + public MemoryViewStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner) + { + _readable = readable; + _writable = writable; + _ptr = ptr; + _length = length; + _owner = owner; + _pos = 0; } - /// - /// the initial data to XOR against for both reading and writing - /// + private void EnsureNotDisposed() + { + if (_owner.Start == 0) + throw new ObjectDisposedException("MemoryBlock"); + } + + private MemoryBlock _owner; + + private readonly bool _readable; + private readonly bool _writable; + + private long _length; + private long _pos; + private readonly long _ptr; + + public override bool CanRead => _readable; + public override bool CanSeek => true; + public override bool CanWrite => _writable; + public override void Flush() { } + public override long Length => _length; + + public override long Position + { + get { return _pos; } + set + { + if (value < 0 || value > _length) + throw new ArgumentOutOfRangeException(); + _pos = value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (!_readable) + throw new InvalidOperationException(); + if (count < 0 || count + offset > buffer.Length) + throw new ArgumentOutOfRangeException(); + EnsureNotDisposed(); + count = (int)Math.Min(count, _length - _pos); + Marshal.Copy(Z.SS(_ptr + _pos), buffer, offset, count); + _pos += count; + return count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + long newpos; + switch (origin) + { + default: + case SeekOrigin.Begin: + newpos = offset; + break; + case SeekOrigin.Current: + newpos = _pos + offset; + break; + case SeekOrigin.End: + newpos = _length + offset; + break; + } + Position = newpos; + return newpos; + } + + public override void SetLength(long value) + { + throw new InvalidOperationException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (!_writable) + throw new InvalidOperationException(); + if (count < 0 || count + offset > buffer.Length) + throw new ArgumentOutOfRangeException(); + if (count > _length - _pos) + throw new ArgumentOutOfRangeException(); + EnsureNotDisposed(); + Marshal.Copy(buffer, offset, Z.SS(_ptr + _pos), count); + _pos += count; + } + } + + private class MemoryViewXorStream : MemoryViewStream + { + public MemoryViewXorStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner, + byte[] initial, long offset) + : base(readable, writable, ptr, length, owner) + { + _initial = initial; + _offset = (int)offset; + } + + /// + /// the initial data to XOR against for both reading and writing + /// private readonly byte[] _initial; - /// - /// offset into the XOR data that this stream is representing - /// - private readonly int _offset; - - public override int Read(byte[] buffer, int offset, int count) - { - int pos = (int)Position; - count = base.Read(buffer, offset, count); - XorTransform(_initial, _offset + pos, buffer, offset, count); - return count; - } - - public override void Write(byte[] buffer, int offset, int count) - { - int pos = (int)Position; - if (count < 0 || count + offset > buffer.Length) - throw new ArgumentOutOfRangeException(); - if (count > Length - pos) + /// + /// offset into the XOR data that this stream is representing + /// + private readonly int _offset; + + public override int Read(byte[] buffer, int offset, int count) + { + int pos = (int)Position; + count = base.Read(buffer, offset, count); + XorTransform(_initial, _offset + pos, buffer, offset, count); + return count; + } + + public override void Write(byte[] buffer, int offset, int count) + { + int pos = (int)Position; + if (count < 0 || count + offset > buffer.Length) + throw new ArgumentOutOfRangeException(); + if (count > Length - pos) throw new ArgumentOutOfRangeException(); // is mutating the buffer passed to Stream.Write kosher? - XorTransform(_initial, _offset + pos, buffer, offset, count); - base.Write(buffer, offset, count); - } - - private static unsafe void XorTransform(byte[] source, int sourceOffset, byte[] dest, int destOffset, int length) + XorTransform(_initial, _offset + pos, buffer, offset, count); + base.Write(buffer, offset, count); + } + + private static unsafe void XorTransform(byte[] source, int sourceOffset, byte[] dest, int destOffset, int length) { // we don't do any bounds check because MemoryViewStream.Read and MemoryViewXorStream.Write already did it // TODO: C compilers can make this pretty snappy, but can the C# jitter? Or do we need intrinsics - fixed (byte* _s = source, _d = dest) - { - byte* s = _s + sourceOffset; - byte* d = _d + destOffset; - byte* sEnd = s + length; - while (s < sEnd) - { - *d++ ^= *s++; - } - } - } - } - - private static class Kernel32 - { - [DllImport("kernel32.dll", SetLastError = true)] - public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize, - AllocationType flAllocationType, MemoryProtection flProtect); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool VirtualFree(UIntPtr lpAddress, UIntPtr dwSize, - FreeType dwFreeType); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, - MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); - - public enum FreeType : uint - { - DECOMMIT = 0x4000, - RELEASE = 0x8000 - } - - [Flags] - public enum AllocationType : uint - { - COMMIT = 0x1000, - RESERVE = 0x2000, - RESET = 0x80000, - RESET_UNDO = 0x1000000, - LARGE_PAGES = 0x20000000, - PHYSICAL = 0x400000, - TOP_DOWN = 0x100000, - WRITE_WATCH = 0x200000 - } - - [Flags] - public enum MemoryProtection : uint - { - EXECUTE = 0x10, - EXECUTE_READ = 0x20, - EXECUTE_READWRITE = 0x40, - EXECUTE_WRITECOPY = 0x80, - NOACCESS = 0x01, - READONLY = 0x02, - READWRITE = 0x04, - WRITECOPY = 0x08, - GUARD_Modifierflag = 0x100, - NOCACHE_Modifierflag = 0x200, - WRITECOMBINE_Modifierflag = 0x400 - } - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr CreateFileMapping( - IntPtr hFile, - IntPtr lpFileMappingAttributes, - FileMapProtection flProtect, - uint dwMaximumSizeHigh, - uint dwMaximumSizeLow, - string lpName); - - [Flags] - public enum FileMapProtection : uint - { - PageReadonly = 0x02, - PageReadWrite = 0x04, - PageWriteCopy = 0x08, - PageExecuteRead = 0x20, - PageExecuteReadWrite = 0x40, - SectionCommit = 0x8000000, - SectionImage = 0x1000000, - SectionNoCache = 0x10000000, - SectionReserve = 0x4000000, - } - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); - - [DllImport("kernel32.dll")] - public static extern IntPtr MapViewOfFileEx(IntPtr hFileMappingObject, - FileMapAccessType dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, - UIntPtr dwNumberOfBytesToMap, IntPtr lpBaseAddress); - - [Flags] - public enum FileMapAccessType : uint - { - Copy = 0x01, - Write = 0x02, - Read = 0x04, - AllAccess = 0x08, - Execute = 0x20, - } - - public static readonly IntPtr INVALID_HANDLE_VALUE = Z.US(0xffffffffffffffff); - } - } -} + fixed (byte* _s = source, _d = dest) + { + byte* s = _s + sourceOffset; + byte* d = _d + destOffset; + byte* sEnd = s + length; + while (s < sEnd) + { + *d++ ^= *s++; + } + } + } + } + + private static class Kernel32 + { + [DllImport("kernel32.dll", SetLastError = true)] + public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize, + AllocationType flAllocationType, MemoryProtection flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool VirtualFree(UIntPtr lpAddress, UIntPtr dwSize, + FreeType dwFreeType); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, + MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); + + public enum FreeType : uint + { + DECOMMIT = 0x4000, + RELEASE = 0x8000 + } + + [Flags] + public enum AllocationType : uint + { + COMMIT = 0x1000, + RESERVE = 0x2000, + RESET = 0x80000, + RESET_UNDO = 0x1000000, + LARGE_PAGES = 0x20000000, + PHYSICAL = 0x400000, + TOP_DOWN = 0x100000, + WRITE_WATCH = 0x200000 + } + + [Flags] + public enum MemoryProtection : uint + { + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + GUARD_Modifierflag = 0x100, + NOCACHE_Modifierflag = 0x200, + WRITECOMBINE_Modifierflag = 0x400 + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateFileMapping( + IntPtr hFile, + IntPtr lpFileMappingAttributes, + FileMapProtection flProtect, + uint dwMaximumSizeHigh, + uint dwMaximumSizeLow, + string lpName); + + [Flags] + public enum FileMapProtection : uint + { + PageReadonly = 0x02, + PageReadWrite = 0x04, + PageWriteCopy = 0x08, + PageExecuteRead = 0x20, + PageExecuteReadWrite = 0x40, + SectionCommit = 0x8000000, + SectionImage = 0x1000000, + SectionNoCache = 0x10000000, + SectionReserve = 0x4000000, + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); + + [DllImport("kernel32.dll")] + public static extern IntPtr MapViewOfFileEx(IntPtr hFileMappingObject, + FileMapAccessType dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, + UIntPtr dwNumberOfBytesToMap, IntPtr lpBaseAddress); + + [Flags] + public enum FileMapAccessType : uint + { + Copy = 0x01, + Write = 0x02, + Read = 0x04, + AllAccess = 0x08, + Execute = 0x20, + } + + public static readonly IntPtr INVALID_HANDLE_VALUE = Z.US(0xffffffffffffffff); + } + } +}