#if NET20 || NET35
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
namespace System.IO
{
///
/// Provides random access to unmanaged blocks of memory from managed code.
///
public class UnmanagedMemoryAccessor : IDisposable
{
private FileAccess access;
[SecurityCritical]
private SafeBuffer buffer;
private bool canRead;
private bool canWrite;
private long offset;
///
/// Initializes a new instance of the class with a specified buffer, offset, and capacity.
///
/// The buffer to contain the accessor.
/// The byte at which to start the accessor.
/// The size, in bytes, of memory to allocate.
[SecuritySafeCritical]
public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity) => Initialize(buffer, offset, capacity, FileAccess.Read);
///
/// Initializes a new instance of the class with a specified buffer, offset, capacity, and
/// access right.
///
/// The buffer to contain the accessor.
/// The byte at which to start the accessor.
/// The size, in bytes, of memory to allocate.
/// The type of access allowed to the memory. The default is ReadWrite.
[SecuritySafeCritical]
public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity, FileAccess access) => Initialize(buffer, offset, capacity, access);
/// Initializes a new instance of the class.
protected UnmanagedMemoryAccessor() => IsOpen = false;
private unsafe delegate T AlignedPtrReadFunc(byte* ptr) where T : unmanaged;
private unsafe delegate void AlignedPtrWriteFunc(byte* ptr);
/// Determines whether the accessor is readable.
/// if the accessor is readable; otherwise, .
public bool CanRead => IsOpen && canRead;
/// Determines whether the accessory is writable.
/// if the accessor is writable; otherwise, .
public bool CanWrite => IsOpen && canWrite;
/// Gets the capacity of the accessor.
/// The capacity of the accessor.
[field: ContractPublicPropertyName("Capacity")]
public long Capacity { get; private set; }
/// Determines whether the accessor is currently open by a process.
/// if the accessor is open; otherwise, .
protected bool IsOpen { get; private set; }
/// Releases all resources used by the UnmanagedMemoryAccessor.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// Reads a structure of type from the accessor into a provided reference.
/// The type of structure.
/// The position in the accessor at which to begin reading.
/// The structure to contain the read data.
[SecurityCritical]
public void Read(long position, out T structure) where T : struct
{
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.EndContractBlock();
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
if (!CanRead)
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Reading"));
var sizeOfT = (uint)Marshal.SizeOf(typeof(T));
if (position > Capacity - sizeOfT)
{
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
throw new ArgumentException(ResourceHelper.GetString("Argument_NotEnoughBytesToRead", typeof(T).FullName), nameof(position));
}
structure = buffer.Read((ulong)(offset + position));
}
/// Reads structures of type from the accessor into an array of type .
/// The type of structure.
/// The number of bytes in the accessor at which to begin reading.
/// The array to contain the structures read from the accessor.
/// The index in in which to place the first copied structure.
/// The number of structures of type to read from the accessor.
///
/// The number of structures read into . This value can be less than if there are
/// fewer structures available, or zero if the end of the accessor is reached.
///
[SecurityCritical]
public int ReadArray(long position, T[] array, int offset, int count) where T : struct
{
if (array == null)
throw new ArgumentNullException(nameof(array), ResourceHelper.GetString("ArgumentNull_Buffer"));
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - offset < count)
throw new ArgumentException(ResourceHelper.GetString("Argument_OffsetAndLengthOutOfBounds"));
Contract.EndContractBlock();
if (!CanRead)
{
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Reading"));
}
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
var sizeOfT = (uint)Marshal.SizeOf(typeof(T));
// only check position and ask for fewer Ts if count is too big
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
var n = count;
var spaceLeft = Capacity - position;
if (spaceLeft < 0)
{
n = 0;
}
else
{
var spaceNeeded = (ulong)(sizeOfT * count);
if ((ulong)spaceLeft < spaceNeeded)
{
n = (int)(spaceLeft / sizeOfT);
}
}
buffer.ReadArray((ulong)(this.offset + position), array, offset, n);
return n;
}
/// Reads a Boolean value from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// or .
public bool ReadBoolean(long position) => ReadByte(position) != 0;
/// Reads a byte value from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
public byte ReadByte(long position)
{
const int sizeOfType = sizeof(byte);
EnsureSafeToRead(position, sizeOfType);
return InternalReadByte(position);
}
/// Reads a character from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public char ReadChar(long position) { unsafe { return InternalRead(position, pointer => (char)(*pointer | *(pointer + 1) << 8)); } }
/// Reads a decimal value from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public decimal ReadDecimal(long position)
{
const int sizeOfType = sizeof(decimal);
EnsureSafeToRead(position, sizeOfType);
var decimalArray = new int[4];
ReadArray(position, decimalArray, 0, decimalArray.Length);
return new decimal(decimalArray);
}
/// Reads a double-precision floating-point value from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public double ReadDouble(long position)
{
unsafe
{
return InternalRead(position, pointer =>
{
var lo = (uint) (*pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24);
var hi = (uint) (*(pointer + 4) | *(pointer + 5) << 8 | *(pointer + 6) << 16 | *(pointer + 7) << 24);
var tempResult = (ulong)hi << 32 | lo;
return *(double*) &tempResult;
});
}
}
/// Reads a 16-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public short ReadInt16(long position) { unsafe { return InternalRead(position, pointer => (short)(*pointer | *(pointer + 1) << 8)); } }
/// Reads a 32-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public int ReadInt32(long position) { unsafe { return InternalRead(position, pointer => *pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24); } }
/// Reads a 64-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public long ReadInt64(long position)
{
unsafe
{
return InternalRead(position, pointer =>
{
var lo = *pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24;
var hi = *(pointer + 4) | *(pointer + 5) << 8 | *(pointer + 6) << 16 | *(pointer + 7) << 24;
return ((long)hi << 32) | (uint)lo;
});
}
}
/// Reads an 8-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public sbyte ReadSByte(long position) => unchecked((sbyte)ReadByte(position));
/// Reads a single-precision floating-point value from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public float ReadSingle(long position)
{
unsafe
{
return InternalRead(position, pointer =>
{
var tempResult = (uint)(*pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24);
return *(float*)&tempResult;
});
}
}
/// Reads an unsigned 16-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public ushort ReadUInt16(long position) { unsafe { return InternalRead(position, pointer => (ushort)(*pointer | *(pointer + 1) << 8)); } }
/// Reads an unsigned 32-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public uint ReadUInt32(long position) { unsafe { return InternalRead(position, pointer => (uint)(*pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24)); } }
/// Reads an unsigned 64-bit integer from the accessor.
/// The number of bytes into the accessor at which to begin reading.
/// The value that was read.
[SecuritySafeCritical]
public ulong ReadUInt64(long position)
{
unsafe
{
return InternalRead(position, pointer =>
{
var lo = (uint)(*pointer | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24);
var hi = (uint)(*(pointer + 4) | *(pointer + 5) << 8 | *(pointer + 6) << 16 | *(pointer + 7) << 24);
return ((ulong)hi << 32) | lo;
});
}
}
/// Writes a Boolean value into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
public void Write(long position, bool value) => Write(position, (byte)(value ? 1 : 0));
/// Writes a byte value into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
public void Write(long position, byte value)
{
const int sizeOfType = sizeof(byte);
EnsureSafeToWrite(position, sizeOfType);
InternalWriteByte(position, value);
}
/// Writes a character into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, char value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
});
}
}
/// Writes a 16-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, short value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
});
}
}
/// Writes a 32-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, int value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
*(pointer + 2) = (byte)(value >> 16);
*(pointer + 3) = (byte)(value >> 24);
});
}
}
/// Writes a 64-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, long value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
*(pointer + 2) = (byte)(value >> 16);
*(pointer + 3) = (byte)(value >> 24);
*(pointer + 4) = (byte)(value >> 32);
*(pointer + 5) = (byte)(value >> 40);
*(pointer + 6) = (byte)(value >> 48);
*(pointer + 7) = (byte)(value >> 56);
});
}
}
/// Writes a decimal value into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, decimal value)
{
const int sizeOfType = sizeof(decimal);
EnsureSafeToWrite(position, sizeOfType);
var decimalArray = new byte[16];
GetDecimalBytes(value, decimalArray);
var bits = new int[4];
var flags = decimalArray[12] | (decimalArray[13] << 8) | (decimalArray[14] << 16) | (decimalArray[15] << 24);
var lo = decimalArray[0] | (decimalArray[1] << 8) | (decimalArray[2] << 16) | (decimalArray[3] << 24);
var mid = decimalArray[4] | (decimalArray[5] << 8) | (decimalArray[6] << 16) | (decimalArray[7] << 24);
var hi = decimalArray[8] | (decimalArray[9] << 8) | (decimalArray[10] << 16) | (decimalArray[11] << 24);
bits[0] = lo;
bits[1] = mid;
bits[2] = hi;
bits[3] = flags;
WriteArray(position, bits, 0, bits.Length);
}
/// Writes a Single into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, float value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
var lValue = value;
var tmpValue = *(uint*)&lValue;
*pointer = (byte)tmpValue;
*(pointer + 1) = (byte)(tmpValue >> 8);
*(pointer + 2) = (byte)(tmpValue >> 16);
*(pointer + 3) = (byte)(tmpValue >> 24);
});
}
}
/// Writes a Double into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, double value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
var lValue = value;
var tmpValue = *(ulong*)&lValue;
*pointer = (byte)tmpValue;
*(pointer + 1) = (byte)(tmpValue >> 8);
*(pointer + 2) = (byte)(tmpValue >> 16);
*(pointer + 3) = (byte)(tmpValue >> 24);
*(pointer + 4) = (byte)(tmpValue >> 32);
*(pointer + 5) = (byte)(tmpValue >> 40);
*(pointer + 6) = (byte)(tmpValue >> 48);
*(pointer + 7) = (byte)(tmpValue >> 56);
});
}
}
/// Writes an unsigned 8-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, sbyte value) => Write(position, unchecked((byte)value));
/// Writes an unsigned 16-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, ushort value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
});
}
}
/// Writes an unsigned 32-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, uint value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
*(pointer + 2) = (byte)(value >> 16);
*(pointer + 3) = (byte)(value >> 24);
});
}
}
/// Writes an unsigned 64-bit integer into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The value to write.
[SecuritySafeCritical]
public void Write(long position, ulong value)
{
unsafe
{
InternalWrite(position, value, pointer =>
{
*pointer = (byte)value;
*(pointer + 1) = (byte)(value >> 8);
*(pointer + 2) = (byte)(value >> 16);
*(pointer + 3) = (byte)(value >> 24);
*(pointer + 4) = (byte)(value >> 32);
*(pointer + 5) = (byte)(value >> 40);
*(pointer + 6) = (byte)(value >> 48);
*(pointer + 7) = (byte)(value >> 56);
});
}
}
/// Writes a structure into the accessor.
/// The number of bytes into the accessor at which to begin writing.
/// The structure to write.
[SecurityCritical]
public void Write(long position, ref T structure) where T : struct
{
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.EndContractBlock();
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
if (!CanWrite)
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Writing"));
var sizeOfT = (uint)Marshal.SizeOf(typeof(T));
if (position > Capacity - sizeOfT)
{
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
throw new ArgumentException(ResourceHelper.GetString("Argument_NotEnoughBytesToWrite", typeof(T).FullName), nameof(position));
}
buffer.Write((ulong)(offset + position), structure);
}
/// Writes structures from an array of type into the accessor.
/// The type of structure.
/// The number of bytes into the accessor at which to begin writing.
/// The array to write into the accessor.
/// The index in to start writing from.
/// The number of structures in to write.
[SecurityCritical]
public void WriteArray(long position, T[] array, int offset, int count) where T : struct
{
if (array == null)
throw new ArgumentNullException(nameof(array), ResourceHelper.GetString("ArgumentNull_Buffer"));
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - offset < count)
throw new ArgumentException(ResourceHelper.GetString("Argument_OffsetAndLengthOutOfBounds"));
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
Contract.EndContractBlock();
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
if (!CanWrite)
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Writing"));
buffer.WriteArray((ulong)(this.offset + position), array, offset, count);
}
internal static void GetDecimalBytes(decimal d, byte[] buffer)
{
Contract.Requires(buffer != null && buffer.Length >= 16, "[GetBytes]buffer != null && buffer.Length >= 16");
Buffer.BlockCopy(decimal.GetBits(d), 0, buffer, 0, buffer.Length);
}
/// Releases the unmanaged resources used by the UnmanagedMemoryAccessor and optionally releases the managed resources.
///
/// to release both managed and unmanaged resources; to release only unmanaged resources.
///
protected virtual void Dispose(bool disposing) => IsOpen = false;
/// Sets the initial values for the accessor.
/// The buffer to contain the accessor.
/// The byte at which to start the accessor.
/// The size, in bytes, of memory to allocate.
/// The type of access allowed to the memory. The default is ReadWrite.
[SecuritySafeCritical]
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected void Initialize(SafeBuffer buffer, long offset, long capacity, FileAccess access)
{
if (buffer == null)
throw new ArgumentNullException(nameof(buffer));
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
if (buffer.ByteLength < (ulong)(offset + capacity))
throw new ArgumentException(ResourceHelper.GetString("Argument_OffsetAndCapacityOutOfBounds"));
if (access < FileAccess.Read || access > FileAccess.ReadWrite)
throw new ArgumentOutOfRangeException(nameof(access));
Contract.EndContractBlock();
if (IsOpen)
throw new InvalidOperationException(ResourceHelper.GetString("InvalidOperation_CalledTwice"));
unsafe
{
byte* pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
buffer.AcquirePointer(ref pointer);
if ((byte*)((long)pointer + offset + capacity) < pointer)
{
throw new ArgumentException(ResourceHelper.GetString("Argument_UnmanagedMemAccessorWrapAround"));
}
}
finally
{
if (pointer != null)
{
buffer.ReleasePointer();
}
}
}
this.offset = offset;
this.buffer = buffer;
this.Capacity = capacity;
this.access = access;
IsOpen = true;
canRead = (this.access & FileAccess.Read) != 0;
canWrite = (this.access & FileAccess.Write) != 0;
}
private void EnsureSafeToRead(long position, int sizeOfType)
{
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
if (!CanRead)
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Reading"));
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.EndContractBlock();
if (position <= Capacity - sizeOfType) return;
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
throw new ArgumentException(ResourceHelper.GetString("Argument_NotEnoughBytesToRead"), nameof(position));
}
private void EnsureSafeToWrite(long position, int sizeOfType)
{
if (!IsOpen)
throw new ObjectDisposedException("UnmanagedMemoryAccessor", ResourceHelper.GetString("ObjectDisposed_ViewAccessorClosed"));
if (!CanWrite)
throw new NotSupportedException(ResourceHelper.GetString("NotSupported_Writing"));
if (position < 0)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.EndContractBlock();
if (position > Capacity - sizeOfType)
{
if (position >= Capacity)
throw new ArgumentOutOfRangeException(nameof(position), ResourceHelper.GetString("ArgumentOutOfRange_PositionLessThanCapacityRequired"));
throw new ArgumentException(ResourceHelper.GetString("Argument_NotEnoughBytesToWrite", "Byte"), nameof(position));
}
}
private unsafe T InternalRead(long position, AlignedPtrReadFunc func) where T : unmanaged, IConvertible
{
var sizeOfType = sizeof(T);
EnsureSafeToRead(position, sizeOfType);
T result;
byte* pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
buffer.AcquirePointer(ref pointer);
pointer += offset + position;
#if ALIGN_ACCESS
// check if pointer is aligned
if (((int)pointer & (sizeOfType - 1)) == 0)
{
#endif
result = *(T*)pointer;
#if ALIGN_ACCESS
}
else
{
result = func(pointer);
}
#endif
}
finally
{
if (pointer != null)
{
buffer.ReleasePointer();
}
}
return result;
}
[SecuritySafeCritical]
private byte InternalReadByte(long position)
{
Contract.Assert(CanRead, "UMA not readable");
Contract.Assert(position >= 0, "position less than 0");
Contract.Assert(position <= Capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)");
byte result;
unsafe
{
byte* pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
buffer.AcquirePointer(ref pointer);
result = *(pointer + offset + position);
}
finally
{
if (pointer != null)
{
buffer.ReleasePointer();
}
}
}
return result;
}
[SecuritySafeCritical]
private unsafe void InternalWrite(long position, T value, AlignedPtrWriteFunc func) where T : unmanaged, IConvertible
{
var sizeOfType = sizeof(T);
EnsureSafeToWrite(position, sizeOfType);
byte* pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
buffer.AcquirePointer(ref pointer);
pointer += offset + position;
#if ALIGN_ACCESS
// check if pointer is aligned
if (((int)pointer & (sizeOfType - 1)) == 0)
{
#endif
*(T*)pointer = value;
#if ALIGN_ACCESS
}
else
{
func(pointer);
}
#endif
}
finally
{
if (pointer != null)
{
buffer.ReleasePointer();
}
}
}
[SecuritySafeCritical]
private void InternalWriteByte(long position, byte value)
{
Contract.Assert(CanWrite, "UMA not writable");
Contract.Assert(position >= 0, "position less than 0");
Contract.Assert(position <= Capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)");
unsafe
{
byte* pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
buffer.AcquirePointer(ref pointer);
*(pointer + offset + position) = value;
}
finally
{
if (pointer != null)
{
buffer.ReleasePointer();
}
}
}
}
}
}
#endif