#if DEBUG
#define CHECK_ACCESS_VIOLATION
#endif
using TUIntPtr = System.UInt32; //Change this to UInt64 for 64-bit platform
using System;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.IO;
using System.Reflection;
namespace Helper
{
/// <summary>Any marshalable object should implement this interface.</summary>
public interface IMarshalable { void MarshalFrom(BufferWithSize buffer); void MarshalTo(BufferWithSize buffer); int MarshaledSize { get; } }
#region Marshaler
//[DebuggerStepThrough]
public static class Marshaler
{
private static OffsetOfHelperDelegate __OffsetOfHelper = ((OffsetOfHelperDelegate)Delegate.CreateDelegate(typeof(OffsetOfHelperDelegate), typeof(Marshal), "OffsetOfHelper", true, true));
private static OffsetOfHelperDelegate __OffsetOfHelperDelegate;
private static PtrToStructureHelperDelegate __PtrToStructureHelperDelegate;
private static SetLastWin32ErrorDelegate __SetLastWin32ErrorDelegate;
#region Different Types of Marshalers
private abstract class AbstractMarshaler<T>
{
private static AbstractMarshaler<T> __Default;
private static int __Size = -1;
private static int __IsBlittable = -1;
protected AbstractMarshaler() { if (typeof(T) == typeof(object)) { throw new InvalidOperationException("Cannot marshal the Object data type. Did you mean to call the dynamic overload?"); } }
public static IntPtr OffsetOf(string fieldName) { return Marshal.OffsetOf(typeof(T), fieldName); }
public abstract void PtrToStructure(BufferWithSize buffer, ref T @object);
public abstract int SizeOf(T @object);
public abstract void StructureToPtr(T @object, BufferWithSize buffer);
public static bool IsBlittable
{
get
{
if (__IsBlittable == -1)
{
bool isBlittable = false;
var blittable = (BlittableAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(BlittableAttribute), false);
if (blittable != null) { isBlittable = blittable.Blittable; }
else
{
try
{
GCHandle.Alloc(Objects.CreateInstance<T>(), GCHandleType.Pinned).Free();
isBlittable = true;
}
catch { isBlittable = false; }
}
Interlocked.CompareExchange(ref __IsBlittable, isBlittable ? 1 : 0, -1);
}
return __IsBlittable != 0;
}
}
public static AbstractMarshaler<T> Default
{
get
{
if (__Default == null)
{
AbstractMarshaler<T> marshaler;
Type c = typeof(T);
if (typeof(IMarshalable).IsAssignableFrom(c))
{ marshaler = (AbstractMarshaler<T>)Activator.CreateInstance(typeof(MarshalableMarshaler<>).MakeGenericType(new Type[] { c })); }
else { marshaler = new DefaultObjectMarshaler<T>(); }
Interlocked.CompareExchange<AbstractMarshaler<T>>(ref __Default, marshaler, null);
}
return __Default;
}
}
public static int Size { get { if (__Size == -1) { Interlocked.CompareExchange(ref __Size, Marshal.SizeOf(typeof(T)), -1); } return __Size; } }
}
private sealed class DefaultObjectMarshaler<T> : AbstractMarshaler<T>
{
public override void PtrToStructure(BufferWithSize buffer, ref T @object) { Marshaler.DefaultPtrToStructure<T>(buffer, ref @object); }
public override int SizeOf(T @object) { return Size; }
public override void StructureToPtr(T @object, BufferWithSize buffer) { Marshaler.DefaultPtrToStructure<T>(buffer, ref @object); }
}
private sealed class MarshalableMarshaler<T> : AbstractMarshaler<T> where T : IMarshalable
{
public override void PtrToStructure(BufferWithSize buffer, ref T @object) { @object.MarshalFrom(buffer); }
public override int SizeOf(T @object) { return @object.MarshaledSize; }
public override void StructureToPtr(T @object, BufferWithSize buffer) { @object.MarshalTo(buffer); }
}
#endregion
public static T DefaultPtrToStructure<T>(BufferWithSize buffer) { T obj = Objects.CreateInstance<T>(); DefaultPtrToStructure<T>(buffer, ref obj); return obj; }
public static void DefaultPtrToStructure<T>(BufferWithSize buffer, ref T @object)
{
buffer = buffer.ExtractSegment(0, AbstractMarshaler<T>.Size);
if (AbstractMarshaler<T>.IsBlittable)
{
if (@object is ValueType) { @object = Objects.Read<T>(buffer.Address); }
else
{
GCHandle handle = GCHandle.Alloc((T)@object, GCHandleType.Pinned);
try { BufferWithSize.Copy(buffer, UIntPtr.Zero, new BufferWithSize(handle.AddrOfPinnedObject(), buffer.Length), UIntPtr.Zero, buffer.Length); }
finally { handle.Free(); }
}
}
else if (@object is ValueType) { @object = (T)Marshal.PtrToStructure(buffer.Address, typeof(T)); }
else { Marshal.PtrToStructure(buffer.Address, (T)@object); }
}
public static void DefaultPtrToStructure(BufferWithSize buffer, object @object)
{
buffer = buffer.ExtractSegment(0, Marshal.SizeOf(@object));
Marshal.PtrToStructure(buffer.Address, @object);
}
public static int DefaultSizeOf<T>() { return AbstractMarshaler<T>.Size; }
public static void DefaultStructureToPtr(object @object, BufferWithSize buffer)
{
buffer = buffer.ExtractSegment(0, Marshal.SizeOf(@object));
Marshal.StructureToPtr(@object, buffer.Address, false);
}
public static void DefaultStructureToPtr<T>(T @object, BufferWithSize buffer)
{
buffer = buffer.ExtractSegment(0, AbstractMarshaler<T>.Size);
if (AbstractMarshaler<T>.IsBlittable)
{
if (@object is ValueType) { Objects.Write(buffer.Address, @object); }
else
{
GCHandle handle = GCHandle.Alloc(@object, GCHandleType.Pinned);
try { BufferWithSize.Copy(new BufferWithSize(handle.AddrOfPinnedObject(), buffer.Length), UIntPtr.Zero, buffer, UIntPtr.Zero, buffer.Length); }
finally { handle.Free(); }
}
}
else { Marshal.StructureToPtr(@object, buffer.Address, false); }
}
[SuppressUnmanagedCodeSecurity, DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int FormatMessage(int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr va_list_arguments);
[SuppressUnmanagedCodeSecurity, DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr FreeLibrary(IntPtr hModule);
public static Exception GetException(int errorCode, string message)
{
if (message == null) { message = GetMessage(errorCode); }
Exception exception = null;
switch (errorCode)
{
case 38:
exception = new EndOfStreamException(message);
break;
case 50:
exception = new NotSupportedException(message);
break;
case 120:
exception = new NotImplementedException(message);
break;
case 2:
exception = new FileNotFoundException(message);
break;
case 3:
exception = new DirectoryNotFoundException(message);
break;
case 5:
exception = new UnauthorizedAccessException(message);
break;
case 14:
exception = new OutOfMemoryException(message);
break;
case 15:
exception = new DriveNotFoundException(message);
break;
case 32:
exception = new IOException(message, errorCode | unchecked((int)0x80070000));
break;
case 206:
exception = new PathTooLongException(message);
break;
case 599:
case 1001:
exception = new StackOverflowException(message);
break;
case 995:
exception = new OperationCanceledException(message);
break;
case 1450:
exception = new InsufficientMemoryException(message);
break;
case 1460:
exception = new TimeoutException(message);
break;
case 998:
exception = new AccessViolationException(message);
break;
}
if (exception == null) { exception = Marshal.GetExceptionForHR(errorCode | unchecked((int)0x8007000)); }
return exception;
}
public static Exception GetExceptionForLastWin32Error() { return Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); }
public static string GetMessage(int errorCode) { string msg = TryGetMessage(errorCode); if (msg == null) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } return msg; }
[SuppressUnmanagedCodeSecurity, DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[SuppressUnmanagedCodeSecurity, DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libFilename);
public static IntPtr OffsetOf(RuntimeFieldHandle fieldHandle) { return __OffsetOfHelper(fieldHandle.Value); }
public static IntPtr OffsetOfHelper(RuntimeFieldHandle fieldHandle)
{
if (__OffsetOfHelperDelegate == null)
{
OffsetOfHelperDelegate @delegate = (OffsetOfHelperDelegate)Delegate.CreateDelegate(typeof(OffsetOfHelperDelegate), typeof(Marshal).GetMethod("OffsetOfHelper", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static), true);
Interlocked.CompareExchange<OffsetOfHelperDelegate>(ref __OffsetOfHelperDelegate, @delegate, null);
}
return __OffsetOfHelperDelegate(fieldHandle.Value);
}
[DebuggerHidden]
public static T PtrToStructure<T>(BufferWithSize buffer) { var obj = Objects.CreateInstance<T>(); PtrToStructure(buffer, ref obj); return obj; }
public static void PtrToStructure<T>(BufferWithSize buffer, ref T @object)
{
//Trace.WriteLine(string.Format(@"Unmanaged -> Managed ({0})", typeof(T)), "Marshaler");
AbstractMarshaler<T>.Default.PtrToStructure(buffer, ref @object);
}
public static unsafe T PtrToStructure<T>(byte[] buffer, int bufferOffset) { fixed (byte* pBuffer = &buffer[bufferOffset]) { return PtrToStructure<T>(new BufferWithSize((IntPtr)pBuffer, buffer.Length - bufferOffset)); } }
public static unsafe void PtrToStructure<T>(byte[] buffer, int bufferOffset, ref T @object) { fixed (byte* pBuffer = &buffer[bufferOffset]) { PtrToStructure<T>(new BufferWithSize((IntPtr)pBuffer, buffer.Length - bufferOffset), ref @object); return; } }
public static void PtrToStructureHelper(IntPtr ptr, object structure, bool allowValueClasses)
{
if (__PtrToStructureHelperDelegate == null)
{
PtrToStructureHelperDelegate @delegate = (PtrToStructureHelperDelegate)Delegate.CreateDelegate(typeof(PtrToStructureHelperDelegate), typeof(Marshal).GetMethod("PtrToStructureHelper", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static), true);
Interlocked.CompareExchange<PtrToStructureHelperDelegate>(ref __PtrToStructureHelperDelegate, @delegate, null);
}
__PtrToStructureHelperDelegate(ptr, structure, allowValueClasses);
}
public static void SetLastWin32Error(int error)
{
if (__SetLastWin32ErrorDelegate == null)
{
SetLastWin32ErrorDelegate @delegate = (SetLastWin32ErrorDelegate)Delegate.CreateDelegate(typeof(SetLastWin32ErrorDelegate), typeof(Marshal).GetMethod("SetLastWin32Error", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static), true);
Interlocked.CompareExchange<SetLastWin32ErrorDelegate>(ref __SetLastWin32ErrorDelegate, @delegate, null);
}
__SetLastWin32ErrorDelegate(error);
}
public static bool ShouldStackAlloc(int size) { return (size < 0x800); }
public static bool ShouldStackAlloc(IntPtr size) { return ((int)size < 0x800); }
[CLSCompliant(false)]
public static bool ShouldStackAlloc(uint size) { return (size < 0x800); }
public static int SizeOf<T>(T @object) { return AbstractMarshaler<T>.Default.SizeOf(@object); }
[CLSCompliant(false)]
public static unsafe void StringToPtrUni(string @string, char* ptr) { fixed (char* pString = @string) { for (int i = 0; i < @string.Length; i++) { ptr[i] = pString[i]; } } }
public static unsafe void StringToPtrUni(string @string, IntPtr ptr) { StringToPtrUni(@string, (char*)ptr); }
public static void StructureToPtr<T>(T @object, BufferWithSize buffer)
{
//Trace.WriteLine(string.Format(@"Managed -> Unmanaged ({0})", @object), "Marshaler");
AbstractMarshaler<T>.Default.StructureToPtr(@object, buffer);
}
public static void StructureToPtr<T>(T @object, byte[] buffer, int bufferOffset) { unsafe { fixed (byte* pBuffer = &buffer[bufferOffset]) { StructureToPtr<T>(@object, new BufferWithSize((IntPtr)pBuffer, buffer.Length - bufferOffset)); return; } } }
public static byte[] StructureToPtr<T>(T @object) { var bytes = new byte[SizeOf(@object)]; StructureToPtr(@object, bytes, 0); return bytes; }
public static void ThrowException(int errorCode) { ThrowException(errorCode, null); }
public static void ThrowException(int errorCode, string message) { throw GetException(errorCode, message); }
public static void ThrowLastWin32Error() { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); }
public static string TryGetMessage(int errorCode) { StringBuilder lpBuffer = new StringBuilder(0x200); if (FormatMessage(0x1200, IntPtr.Zero, errorCode, 0, lpBuffer, lpBuffer.Capacity, IntPtr.Zero) != 0) { return lpBuffer.ToString(); } return null; }
public static string TryGetMessage(int errorCode, IntPtr hModule)
{
StringBuilder lpBuffer = new StringBuilder(0x200);
if (FormatMessage(((hModule != IntPtr.Zero) ? 0x800 : 0x1000) | 0x200, hModule, errorCode, 0, lpBuffer, lpBuffer.Capacity, IntPtr.Zero) != 0)
{ return lpBuffer.ToString(); }
return null;
}
public static string TryGetMessage(int errorCode, string moduleName, bool assumeModuleLoaded)
{
var lpBuffer = new StringBuilder(0x200);
IntPtr hModule = assumeModuleLoaded ? GetModuleHandle(moduleName) : LoadLibrary(moduleName);
try { if (FormatMessage(0xa00, hModule, errorCode, 0, lpBuffer, lpBuffer.Capacity, IntPtr.Zero) != 0) { return lpBuffer.ToString(); } }
finally { if (!assumeModuleLoaded) { FreeLibrary(hModule); } }
return null;
}
private delegate IntPtr OffsetOfHelperDelegate(IntPtr fieldHandleValue);
private delegate void PtrToStructureHelperDelegate(IntPtr ptr, object structure, bool allowValueClasses);
private delegate void SetLastWin32ErrorDelegate(int error);
#if false
public delegate void MarshalDelegate<T>(BufferWithSize buffer, ref T @object);
/// <param name="includeGiven">Whether to include or exclude the fields given.</param>
public static MarshalDelegate<T> CreateDefaultMarshaler<T>(bool includeGiven, params string[] fieldNames)
{ return (MarshalDelegate<T>)CreateDefaultMarshaler(typeof(T), includeGiven, fieldNames); }
/// <param name="includeGiven">Whether to include or exclude the fields given.</param>
private static Delegate CreateDefaultMarshaler(Type type, bool includeGiven, params string[] fieldNames)
{
if (fieldNames == null) { throw new ArgumentNullException("fieldNames"); }
Array.Sort(fieldNames);
var method = new DynamicMethod(type.Name + "__Marshaler", null, new Type[] { typeof(BufferWithSize), type.MakeByRefType() }, type);
var gen = method.GetILGenerator();
foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
if (includeGiven == (Array.BinarySearch(fieldNames, field.Name) >= 0))
{
//Pushes address of field onto stack
gen.Emit(OpCodes.Ldarg_1);
if (!type.IsValueType)
{ gen.Emit(OpCodes.Ldind_Ref); }
else { }
gen.Emit(OpCodes.Ldflda, field);
//Pushes address of buffer onto stack
gen.Emit(OpCodes.Ldarga_S, 0);
gen.Emit(OpCodes.Call, typeof(BufferWithSize).GetProperty("Address").GetGetMethod());
//*
//Pushes field offset onto stack
gen.Emit(OpCodes.Ldc_I4, (int)Marshaler.OffsetOf(field.FieldHandle));
gen.Emit(OpCodes.Conv_Ovf_U);
//Gets the pointer to the field
gen.Emit(OpCodes.Add_Ovf_Un);
gen.Emit(OpCodes.Cpobj, field.FieldType);
//*/
}
}
gen.Emit(OpCodes.Ret);
var del = method.CreateDelegate(typeof(MarshalDelegate<>).MakeGenericType(type));
return del;
}
#endif
}
#endregion
#region BufferWithSize
/// <summary>Represents a buffer in memory that can be accessed safely. If you receive any <see cref="OverflowException"/> while using this class, it signals an access violation.</summary>
[DebuggerStepThrough]
[DebuggerDisplay("{Address} - {(global::System.IntPtr)((byte*)Address + unchecked((ulong)Length))} (Length = {Length})"), DebuggerTypeProxy(typeof(BufferWithSizeDebugView))]
public struct BufferWithSize
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static BufferWithSize Zero;
public readonly IntPtr Address;
[CLSCompliant(false)]
public readonly UIntPtr Length;
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, int count) { this.Address = (IntPtr)address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, long count) { this.Address = (IntPtr)address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, IntPtr count) { this.Address = (IntPtr)address; unsafe { this.Length = ToUIntPtr(count); } }
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, uint count) { this.Address = (IntPtr)address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, ulong count) { this.Address = (IntPtr)address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public unsafe BufferWithSize(byte* address, UIntPtr count) { this.Address = (IntPtr)address; this.Length = count; }
public BufferWithSize(IntPtr address, int count) { this.Address = address; this.Length = (UIntPtr)count; }
public BufferWithSize(IntPtr address, long count) { this.Address = address; this.Length = (UIntPtr)count; }
public BufferWithSize(IntPtr address, IntPtr count) { this.Address = address; unsafe { this.Length = ToUIntPtr(count); } }
[CLSCompliant(false)]
public BufferWithSize(IntPtr address, uint count) { this.Address = address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public BufferWithSize(IntPtr address, ulong count) { this.Address = address; this.Length = (UIntPtr)count; }
[CLSCompliant(false)]
public BufferWithSize(IntPtr address, UIntPtr count) { this.Address = address; this.Length = count; }
public static BufferWithSize AllocHGlobal(int length) { return new BufferWithSize(Marshal.AllocHGlobal((IntPtr)length), (UIntPtr)length); }
[CLSCompliant(false)]
public static BufferWithSize AllocHGlobal(uint length) { return new BufferWithSize(Marshal.AllocHGlobal((IntPtr)length), (UIntPtr)length); }
public static BufferWithSize AllocHGlobal(long length) { return new BufferWithSize(Marshal.AllocHGlobal((IntPtr)length), (UIntPtr)length); }
[CLSCompliant(false)]
public static BufferWithSize AllocHGlobal(ulong length) { return new BufferWithSize(Marshal.AllocHGlobal((IntPtr)length), (UIntPtr)length); }
public static BufferWithSize AllocHGlobal(IntPtr length) { unsafe { return new BufferWithSize(Marshal.AllocHGlobal(length), ToUIntPtr(length)); } }
[CLSCompliant(false)]
public static BufferWithSize AllocHGlobal(UIntPtr length) { unsafe { return new BufferWithSize(Marshal.AllocHGlobal((IntPtr)(void*)length), length); } }
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, int newSize) { return ReAllocHGlobal(buffer, (IntPtr)newSize); }
[CLSCompliant(false)]
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, uint newSize) { return ReAllocHGlobal(buffer, (IntPtr)newSize); }
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, long newSize) { return ReAllocHGlobal(buffer, (IntPtr)newSize); }
[CLSCompliant(false)]
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, ulong newSize) { return ReAllocHGlobal(buffer, (IntPtr)newSize); }
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, IntPtr newSize) { return new BufferWithSize(Marshal.ReAllocHGlobal(buffer.Address, newSize), ToUIntPtr(newSize)); }
[CLSCompliant(false)]
public static BufferWithSize ReAllocHGlobal(BufferWithSize buffer, UIntPtr newSize) { unsafe { return ReAllocHGlobal(buffer, (IntPtr)(void*)newSize); } }
public static void FreeHGlobal(BufferWithSize buffer) { Marshal.FreeHGlobal(buffer.Address); }
public static void Copy(BufferWithSize source, int sourceIndex, BufferWithSize destination, int destinationIndex, int count) { Copy(source, (UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public static void Copy(BufferWithSize source, uint sourceIndex, BufferWithSize destination, uint destinationIndex, uint count) { Copy(source, (UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
public static void Copy(BufferWithSize source, long sourceIndex, BufferWithSize destination, long destinationIndex, long count) { Copy(source, (UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public static void Copy(BufferWithSize source, ulong sourceIndex, BufferWithSize destination, ulong destinationIndex, ulong count) { Copy(source, (UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public static void Copy(BufferWithSize source, UIntPtr sourceIndex, BufferWithSize destination, UIntPtr destinationIndex, UIntPtr count)
{
#if CHECK_ACCESS_VIOLATION
if ((TUIntPtr)sourceIndex + (TUIntPtr)count > (TUIntPtr)source.Length) { ThrowAccessViolation(); }
if ((TUIntPtr)destinationIndex + (TUIntPtr)count > (TUIntPtr)destination.Length) { ThrowAccessViolation(); }
#endif
unsafe { Native.memcpyimpl((byte*)source.Address + (TUIntPtr)sourceIndex, (byte*)destination.Address + (TUIntPtr)destinationIndex, (int)count); }
}
public void CopyFrom(int destinationIndex, byte[] source, int sourceIndex, int count) { this.CopyFrom((UIntPtr)destinationIndex, source, (UIntPtr)sourceIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public void CopyFrom(uint destinationIndex, byte[] source, uint sourceIndex, uint count) { this.CopyFrom((UIntPtr)destinationIndex, source, (UIntPtr)sourceIndex, (UIntPtr)count); }
public void CopyFrom(long destinationIndex, byte[] source, long sourceIndex, long count) { this.CopyFrom((UIntPtr)destinationIndex, source, (UIntPtr)sourceIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public void CopyFrom(ulong destinationIndex, byte[] source, ulong sourceIndex, ulong count) { this.CopyFrom((UIntPtr)destinationIndex, source, (UIntPtr)sourceIndex, (UIntPtr)count); }
public void CopyFrom(IntPtr destinationIndex, byte[] source, IntPtr sourceIndex, IntPtr count) { unsafe { this.CopyFrom(ToUIntPtr(destinationIndex), source, ToUIntPtr(sourceIndex), ToUIntPtr(count)); } }
[CLSCompliant(false)]
public void CopyFrom(UIntPtr destinationIndex, byte[] source, UIntPtr sourceIndex, UIntPtr count) { unsafe { fixed (byte* pFrom = source) { Copy(new BufferWithSize(pFrom, source.Length), sourceIndex, this, destinationIndex, count); } } }
public void CopyTo(int sourceIndex, byte[] destination, int destinationIndex, int count) { this.CopyTo((UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public void CopyTo(uint sourceIndex, byte[] destination, uint destinationIndex, uint count) { this.CopyTo((UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
public void CopyTo(long sourceIndex, byte[] destination, long destinationIndex, long count) { this.CopyTo((UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public void CopyTo(ulong sourceIndex, byte[] destination, ulong destinationIndex, ulong count) { this.CopyTo((UIntPtr)sourceIndex, destination, (UIntPtr)destinationIndex, (UIntPtr)count); }
public void CopyTo(IntPtr sourceIndex, byte[] destination, IntPtr destinationIndex, IntPtr count) { this.CopyTo(ToUIntPtr(sourceIndex), destination, ToUIntPtr(destinationIndex), ToUIntPtr(count)); }
[CLSCompliant(false)]
public void CopyTo(UIntPtr sourceIndex, byte[] destination, UIntPtr destinationIndex, UIntPtr count) { unsafe { fixed (byte* pTo = destination) { Copy(this, sourceIndex, new BufferWithSize(pTo, destination.Length), destinationIndex, count); } } }
public bool Equals(BufferWithSize other) { return ((this.Address == other.Address) & (this.Length == other.Length)); }
public override bool Equals(object obj) { return ((obj is BufferWithSize) && this.Equals((BufferWithSize)obj)); }
public BufferWithSize ExtractSegment(int startIndex) { return this.ExtractSegment((UIntPtr)startIndex); }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(uint startIndex) { return this.ExtractSegment((UIntPtr)startIndex); }
public BufferWithSize ExtractSegment(long startIndex) { return this.ExtractSegment((UIntPtr)startIndex); }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(ulong startIndex) { return this.ExtractSegment((UIntPtr)startIndex); }
public BufferWithSize ExtractSegment(IntPtr startIndex) { unsafe { return this.ExtractSegment(ToUIntPtr(startIndex)); } }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(UIntPtr startIndex) { return this.ExtractSegment(startIndex, (UIntPtr)((TUIntPtr)this.Length - (TUIntPtr)startIndex)); }
public BufferWithSize ExtractSegment(int startIndex, int count) { return this.ExtractSegment((UIntPtr)startIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(uint startIndex, uint count) { return this.ExtractSegment((UIntPtr)startIndex, (UIntPtr)count); }
public BufferWithSize ExtractSegment(long startIndex, long count) { return this.ExtractSegment((UIntPtr)startIndex, (UIntPtr)count); }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(ulong startIndex, ulong count) { return this.ExtractSegment((UIntPtr)startIndex, (UIntPtr)count); }
public BufferWithSize ExtractSegment(IntPtr startIndex, IntPtr count) { unsafe { return this.ExtractSegment(ToUIntPtr(startIndex), ToUIntPtr(count)); } }
[CLSCompliant(false)]
public BufferWithSize ExtractSegment(UIntPtr startIndex, UIntPtr count)
{
#if CHECK_ACCESS_VIOLATION
if ((TUIntPtr)startIndex + (TUIntPtr)count > (TUIntPtr)this.Length)
{ ThrowAccessViolation(); }
#endif
unsafe { return new BufferWithSize((byte*)this.Address + (TUIntPtr)startIndex, count); }
}
public override int GetHashCode() { return this.Address.GetHashCode() ^ this.Length.GetHashCode(); }
public void Initialize() { unsafe { Native.ZeroMemory((byte*)this.Address, this.Length64); } }
public void Initialize(int startIndex) { this.Initialize((UIntPtr)startIndex); }
[CLSCompliant(false)]
public void Initialize(uint startIndex) { this.Initialize((UIntPtr)startIndex); }
public void Initialize(long startIndex) { this.Initialize((UIntPtr)startIndex); }
[CLSCompliant(false)]
public void Initialize(ulong startIndex) { this.Initialize((UIntPtr)startIndex); }
[CLSCompliant(false)]
public void Initialize(UIntPtr startIndex) { this.ExtractSegment(startIndex).Initialize(); }
public void Initialize(int startIndex, int length) { this.Initialize((UIntPtr)startIndex, length); }
[CLSCompliant(false)]
public void Initialize(uint startIndex, uint length) { this.Initialize((UIntPtr)startIndex, length); }
public void Initialize(long startIndex, int length) { this.Initialize((UIntPtr)startIndex, length); }
[CLSCompliant(false)]
public void Initialize(ulong startIndex, uint length) { this.Initialize((UIntPtr)startIndex, length); }
[CLSCompliant(false)]
public void Initialize(UIntPtr startIndex, int length) { this.Initialize(startIndex, length); }
[CLSCompliant(false)]
public void Initialize(UIntPtr startIndex, uint length) { this.ExtractSegment(startIndex, (UIntPtr)length).Initialize(); }
public static bool operator ==(BufferWithSize a, BufferWithSize b) { return a.Equals(b); }
public static bool operator !=(BufferWithSize a, BufferWithSize b) { return !a.Equals(b); }
public byte[] ToArray() { return this.ToArray(UIntPtr.Zero); }
public byte[] ToArray(int index) { return this.ToArray((UIntPtr)index); }
[CLSCompliant(false)]
public byte[] ToArray(uint index) { return this.ToArray((UIntPtr)index); }
public byte[] ToArray(long index) { return this.ToArray((UIntPtr)index); }
[CLSCompliant(false)]
public byte[] ToArray(ulong index) { return this.ToArray((UIntPtr)index); }
[CLSCompliant(false)]
public byte[] ToArray(UIntPtr index) { return this.ToArray(index, (UIntPtr)((TUIntPtr)this.Length - (TUIntPtr)index)); }
public byte[] ToArray(int index, int count) { return this.ToArray((UIntPtr)index, (UIntPtr)count); }
[CLSCompliant(false)]
public byte[] ToArray(uint index, uint count) { return this.ToArray((UIntPtr)index, (UIntPtr)count); }
public byte[] ToArray(long index, long count) { return this.ToArray((UIntPtr)index, (UIntPtr)count); }
[CLSCompliant(false)]
public byte[] ToArray(ulong index, ulong count) { return this.ToArray((UIntPtr)index, (UIntPtr)count); }
[CLSCompliant(false)]
public byte[] ToArray(UIntPtr index, UIntPtr count) { var arr = new byte[(TUIntPtr)count]; this.CopyTo(index, arr, UIntPtr.Zero, count); return arr; }
public override string ToString() { return string.Format("Address = 0x{0:X}, Length = 0x{1:X})", (TUIntPtr)this.Address, (TUIntPtr)this.Length); }
public string ToStringAnsi(int offset, int byteLength) { return this.ToStringAnsi((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringAnsi(uint offset, uint byteLength) { return this.ToStringAnsi((UIntPtr)offset, (UIntPtr)byteLength); }
public string ToStringAnsi(long offset, long byteLength) { return this.ToStringAnsi((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringAnsi(ulong offset, ulong byteLength) { return this.ToStringAnsi((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringAnsi(UIntPtr offset, UIntPtr byteLength) { return this.ExtractSegment(offset, byteLength).ToStringAnsi(); }
public string ToStringAnsi() { return Marshal.PtrToStringAnsi(this.Address, this.Length32); }
public string ToStringUni(int offset, int byteLength) { return this.ToStringUni((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringUni(uint offset, uint byteLength) { return this.ToStringUni((UIntPtr)offset, (UIntPtr)byteLength); }
public string ToStringUni(long offset, long byteLength) { return this.ToStringUni((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringUni(ulong offset, ulong byteLength) { return this.ToStringUni((UIntPtr)offset, (UIntPtr)byteLength); }
[CLSCompliant(false)]
public string ToStringUni(UIntPtr offset, UIntPtr byteLength) { return this.ExtractSegment(offset, byteLength).ToStringUni(); }
public string ToStringUni() { return Marshal.PtrToStringUni(this.Address, this.Length32 >> 1); }
public byte this[int index] { get { return this[(UIntPtr)index]; } set { this[(UIntPtr)index] = value; } }
[CLSCompliant(false)]
public byte this[uint index] { get { return this[(UIntPtr)index]; } set { this[(UIntPtr)index] = value; } }
public byte this[long index] { get { return this[(UIntPtr)index]; } set { this[(UIntPtr)index] = value; } }
[CLSCompliant(false)]
public byte this[ulong index] { get { return this[(UIntPtr)index]; } set { this[(UIntPtr)index] = value; } }
[CLSCompliant(false)]
public byte this[UIntPtr index]
{
get
{
#if CHECK_ACCESS_VIOLATION
if ((TUIntPtr)index >= (TUIntPtr)this.Length) { ThrowAccessViolation(); }
#endif
unsafe { return ((byte*)this.Address)[(TUIntPtr)index]; }
}
set
{
#if CHECK_ACCESS_VIOLATION
if ((TUIntPtr)index >= (TUIntPtr)this.Length) { ThrowAccessViolation(); }
#endif
unsafe { ((byte*)this.Address)[(TUIntPtr)index] = value; }
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int Length32 { get { return (int)this.Length; } }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public long Length64 { get { return (long)this.Length; } }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CLSCompliant(false)]
public uint LengthU32 { get { return (uint)this.Length; } }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CLSCompliant(false)]
public ulong LengthU64 { get { return (TUIntPtr)this.Length; } }
public T Read<T>() where T : struct { return this.Read<T>(UIntPtr.Zero); }
public T Read<T>(int byteOffset) where T : struct { return this.Read<T>((UIntPtr)byteOffset); }
[CLSCompliant(false)]
public T Read<T>(uint byteOffset) where T : struct { return this.Read<T>((UIntPtr)byteOffset); }
public T Read<T>(long byteOffset) where T : struct { return this.Read<T>((UIntPtr)byteOffset); }
[CLSCompliant(false)]
public T Read<T>(ulong byteOffset) where T : struct { return this.Read<T>((UIntPtr)byteOffset); }
public T Read<T>(IntPtr byteOffset) where T : struct { unsafe { return this.Read<T>(ToUIntPtr(byteOffset)); } }
[CLSCompliant(false)]
public unsafe T Read<T>(UIntPtr byteOffset) where T : struct
{
#if CHECK_ACCESS_VIOLATION
var size = (UIntPtr)Objects.SizeOf<T>();
checked
{
if ((TUIntPtr)this.Length - (TUIntPtr)byteOffset < (TUIntPtr)size)
{ ThrowAccessViolation(); }
}
#endif
return Objects.Read<T>((IntPtr)((byte*)this.Address + (TUIntPtr)byteOffset));
}
public void Write<T>(T value) where T : struct { this.Write<T>(value, UIntPtr.Zero); }
public void Write<T>(T value, int byteOffset) where T : struct { this.Write<T>(value, (UIntPtr)byteOffset); }
[CLSCompliant(false)]
public void Write<T>(T value, uint byteOffset) where T : struct { this.Write<T>(value, (UIntPtr)byteOffset); }
public void Write<T>(T value, long byteOffset) where T : struct { this.Write<T>(value, (UIntPtr)byteOffset); }
[CLSCompliant(false)]
public void Write<T>(T value, ulong byteOffset) where T : struct { this.Write<T>(value, (UIntPtr)byteOffset); }
public void Write<T>(T value, IntPtr byteOffset) where T : struct { unsafe { this.Write<T>(value, ToUIntPtr(byteOffset)); } }
[CLSCompliant(false)]
public unsafe void Write<T>(T value, UIntPtr byteOffset) where T : struct
{
#if CHECK_ACCESS_VIOLATION
var size = (UIntPtr)Objects.SizeOf<T>();
checked
{
if ((TUIntPtr)this.Length - (TUIntPtr)byteOffset < (TUIntPtr)size)
{ ThrowAccessViolation(); }
}
#endif
Objects.Write((IntPtr)((byte*)this.Address + (TUIntPtr)byteOffset), value);
}
private static UIntPtr ToUIntPtr(IntPtr value)
{
#if DEBUG
if ((long)value < 0) { throw new OverflowException(); }
#endif
unsafe { return *(UIntPtr*)(&value); }
}
#if CHECK_ACCESS_VIOLATION
[DebuggerStepThrough, DebuggerHidden]
private static void ThrowAccessViolation(Exception inner) { throw new AccessViolationException(Marshaler.GetMessage(998), inner); }
[DebuggerStepThrough, DebuggerHidden]
private static void ThrowAccessViolation() { throw new AccessViolationException(Marshaler.GetMessage(998)); }
#endif
private sealed class BufferWithSizeDebugView { private BufferWithSize buffer; public BufferWithSizeDebugView(BufferWithSize buffer) { this.buffer = buffer; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public byte[] Data { get { return this.buffer.ToArray(); } } }
}
#endregion
#region Objects
public static class Objects //Important: DO NOT RENAME THIS CLASS OR ITS METHOD OR THE NAMESPACE; optimizations are hardcoded in my merger library and won't work otherwise
{
public static T CreateInstance<T>() { return Object<T>.Construct(); }
private static class Array<T> { public static readonly T[] ArrayOfTwoElements = new T[2];}
//These are all hacks but they work!! :D
[CLSCompliant(false)]
public static uint SizeOf<T>()
{
#if !METHOD_1
TypedReference elem1 = __makeref(Array<T>.ArrayOfTwoElements[0] ), elem2 = __makeref(Array<T>.ArrayOfTwoElements[1] );unsafe { return (uint)((byte*)*(IntPtr*)(&elem2) - (byte*)*(IntPtr*)(&elem1)); }
#else
var o = default(ComboObject<T>); unsafe { return (uint)(&o.NextByte - &o.Byte0) - sizeof(byte); }
#endif
}
public static T Read<T>(IntPtr address)
{
var obj = default(T);
var tr = __makeref(obj );
unsafe { *(IntPtr*)(&tr) = address; }
return __refvalue( tr,T );
}
public static void Write<T>(IntPtr address, T value)
{
var obj = default(T);
var tr = __makeref(obj );
unsafe { *(IntPtr*)(&tr) = address; }
__refvalue( tr, T ) = value;
}
public static RuntimeTypeHandle TypeOf<T>() { var obj = default(T); var r = __makeref(obj );unsafe { return *(RuntimeTypeHandle*)&((IntPtr*)(&r))[1]; } }
public static TTo ConvertNoCast<TFrom, TTo>(TFrom value) { var r = __makeref(value); unsafe { *(RuntimeTypeHandle*)&((IntPtr*)(&r))[1] = TypeOf<TTo>(); } return __refvalue(r, TTo); }
public static T ShiftLeft<T>(T value, IntPtr shift) { return Object<T>.ShiftLeft(value, shift); }
public static T ShiftRightUnsigned<T>(T value, IntPtr shift) { return Object<T>.ShiftRightUnsigned(value, shift); }
//private static class Array<T> { public static readonly T[] ArrayOfTwoElements = new T[2]; }
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct ComboObject<T> { public byte Byte0; public T Value; public byte NextByte; }
private static class Object<T>
{
private static readonly bool IsValueType = typeof(T).IsValueType;
private static ConstructorDelegate __Constructor;
private static ShiftDelegate __ShiftLeft;
private static ShiftDelegate __ShiftRightUnsigned;
public static T ShiftLeft(T value, IntPtr shift)
{
if (__ShiftLeft == null)
{
var dyn = new DynamicMethod(@"ShiftLeft", typeof(T), new Type[] { typeof(T), typeof(IntPtr) });
var gen = dyn.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Shl);
gen.Emit(OpCodes.Ret);
Interlocked.CompareExchange(ref __ShiftLeft, (ShiftDelegate)dyn.CreateDelegate(typeof(ShiftDelegate)), null);
}
return __ShiftLeft(value, shift);
}
public static T ShiftRightUnsigned(T value, IntPtr shift)
{
if (__ShiftRightUnsigned == null)
{
var dyn = new DynamicMethod(@"ShiftRightUnsigned", typeof(T), new Type[] { typeof(T), typeof(IntPtr) });
var gen = dyn.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Shr_Un);
gen.Emit(OpCodes.Ret);
Interlocked.CompareExchange(ref __ShiftRightUnsigned, (ShiftDelegate)dyn.CreateDelegate(typeof(ShiftDelegate)), null);
}
return __ShiftRightUnsigned(value, shift);
}
public static T Construct()
{
if (IsValueType) { return default(T); }
else
{
if (__Constructor == null)
{
Type type = typeof(T);
var dyn = new DynamicMethod("Constructor", type, null, type);
var gen = dyn.GetILGenerator();
if (type.IsValueType)
{
LocalBuilder instance = gen.DeclareLocal(type);
gen.Emit(OpCodes.Ldloca_S, (byte)0);
gen.Emit(OpCodes.Initobj, type);
gen.Emit(OpCodes.Ldloc_0);
}
else
{
ConstructorInfo ctor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
gen.Emit(OpCodes.Newobj, ctor);
}
gen.Emit(OpCodes.Ret);
Interlocked.CompareExchange(ref __Constructor, (ConstructorDelegate)dyn.CreateDelegate(typeof(ConstructorDelegate)), null);
}
return __Constructor();
}
}
public delegate T ConstructorDelegate();
public delegate T ShiftDelegate(T value, IntPtr shift);
}
}
#endregion
#region Native
internal static class Native
{
public static readonly unsafe memcpyimplDelegate memcpyimpl = (memcpyimplDelegate)Delegate.CreateDelegate(typeof(memcpyimplDelegate), typeof(Buffer).GetMethod("memcpyimpl", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
public static readonly unsafe ZeroMemoryDelegate ZeroMemory = (ZeroMemoryDelegate)Delegate.CreateDelegate(typeof(ZeroMemoryDelegate), typeof(Buffer).GetMethod("ZeroMemory", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
public unsafe delegate void memcpyimplDelegate(byte* src, byte* dest, int len);
public unsafe delegate void ZeroMemoryDelegate(byte* src, long len);
}
#endregion
/// <summary>Specifies whether a class or structure is blittable, preventing the need destination perform a slow check during runtime.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class BlittableAttribute : Attribute { private bool blittable; public BlittableAttribute(bool blittable) { this.blittable = blittable; } public bool Blittable { get { return this.blittable; } } }
#region Bits
public static class Bits
{
public static T BigEndian<T>(T value) { return BitConverter.IsLittleEndian ? ReverseBytes(value) : value; }
public static T LittleEndian<T>(T value) { return BitConverter.IsLittleEndian ? value : ReverseBytes(value); }
public static T GetValueMask<T>(T source, int valueLeftShift, T mask)
{
unsafe
{
var size = Objects.SizeOf<T>();
var tr = __makeref(source);
var sourceBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], size);
tr = __makeref(mask);
var maskBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], size);
for (uint i = 0; i < size; i++)
{ sourceBuffer[i] &= maskBuffer[i]; }
return Objects.ShiftRightUnsigned<T>(source, (IntPtr)valueLeftShift);
}
//return (source & mask) >> valueLeftShift;
}
public static T PutValueMask<T>(T target, T value, int valueLeftShift, T mask)
{
unsafe
{
value = Objects.ShiftLeft(value, (IntPtr)valueLeftShift);
var size = Objects.SizeOf<T>();
var tr = __makeref(target);
var targetBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], size);
tr = __makeref(value);
var valueBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], size);
tr = __makeref(mask);
var maskBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], size);
for (uint i = 0; i < size; i++)
{
targetBuffer[i] &= unchecked((byte)~maskBuffer[i]);
valueBuffer[i] &= maskBuffer[i];
targetBuffer[i] |= valueBuffer[i];
}
return target;
}
}
public static T ReverseBytes<T>(T value)
{
unsafe
{
var tr = __makeref(value);
var valueBuffer = new BufferWithSize(((IntPtr*)(&tr))[0], Objects.SizeOf<T>());
for (uint i = 0; i < valueBuffer.LengthU32 >> 1; i++)
{
byte b = valueBuffer[i];
valueBuffer[i] = valueBuffer[valueBuffer.LengthU32 - i - 1];
valueBuffer[valueBuffer.LengthU32 - i - 1] = b;
}
return value;
}
}
}
#endregion
}