/// <summary> /// 指针的操作 /// </summary> internal class PointerHelper { private byte* _pBuffer; private bool _disposed; private GCHandle _pinnedGCHandle; private bool _needToFreeGCHandle; private int _capacity; /// <summary> /// /// </summary> public byte[] Data { get; private set; } /// <summary> /// Attach a view to a byte[] for providing direct access /// </summary> /// <param name="buffer">buffer to which the view is attached.</param> public PointerHelper(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("buffer"); this.Data = buffer; // pin the buffer so it does not get moved around by GC, this is required since we use pointers _pinnedGCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); _needToFreeGCHandle = true; _pBuffer = (byte*)_pinnedGCHandle.AddrOfPinnedObject().ToPointer(); _capacity = buffer.Length; } /// <summary> /// Capacity of the underlying buffer /// </summary> public int Capacity { get { return _capacity; } } /// <summary> /// Gets the <see cref="byte"/> value at a given index. /// </summary> /// <param name="index">index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public char CharGet(int index) { return (char)*(_pBuffer + index); } /// <summary> /// Writes a <see cref="byte"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void CharPut(int index, char value) { *(_pBuffer + index) = (byte)value; } /// <summary> /// Gets the <see cref="sbyte"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public sbyte Int8Get(int index) { return *(sbyte*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="sbyte"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void Int8Put(int index, sbyte value) { *(sbyte*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="byte"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public byte UInt8Get(int index) { return *(_pBuffer + index); } /// <summary> /// Writes a <see cref="byte"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void UInt8Put(int index, byte value) { *(_pBuffer + index) = value; } /// <summary> /// /// </summary> /// <param name="index"></param> /// <returns></returns> public bool BoolGet(int index) { return *(_pBuffer + index) == 1; } /// <summary> /// /// </summary> /// <param name="index"></param> /// <param name="value"></param> public void BoolPut(int index, bool value) { *(_pBuffer + index) = (byte)(value ? 1 : 0); } /// <summary> /// Gets the <see cref="short"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public short Int16Get(int index) { return *(short*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="short"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void Int16Put(int index, short value) { *(short*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="int"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public int Int32Get(int index) { return *(int*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="int"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void Int32Put(int index, int value) { *(int*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="long"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public long Int64Get(int index) { return *(long*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="long"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void Int64Put(int index, long value) { *(long*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="ushort"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public ushort UInt16Get(int index) { return *(ushort*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="ushort"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void UInt16Put(int index, ushort value) { *(ushort*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="uint"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public uint UInt32Get(int index) { return *(uint*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="uint"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void UInt32Put(int index, uint value) { *(uint*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="ulong"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public ulong UInt64Get(int index) { return *(ulong*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="ulong"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void UInt64Put(int index, ulong value) { *(ulong*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="float"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public float FloatGet(int index) { return *(float*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="float"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void FloatPut(int index, float value) { *(float*)(_pBuffer + index) = value; } /// <summary> /// Gets the <see cref="double"/> value at a given index. /// </summary> /// <param name="index"> index in bytes from which to get.</param> /// <returns>the value at a given index.</returns> public double DoubleGet(int index) { return *(double*)(_pBuffer + index); } /// <summary> /// Writes a <see cref="double"/> value to a given index. /// </summary> /// <param name="index">index in bytes for where to put.</param> /// <param name="value">value to be written</param> public void DoublePut(int index, double value) { *(double*)(_pBuffer + index) = value; } /// <summary> /// 字符串存储为两位数字=字符串长度 + 字符串(每个字符占两个字节) /// </summary> /// <param name="index"></param> /// <param name="length">chars</param> /// <returns></returns> public string StringGet(int index, int length) { int len = UInt16Get(index); if (len <= 0) return string.Empty; return new string((char*)(_pBuffer + index + 2), 0, len); } /// <summary> /// 字符串存储为两位数字=字符串长度 + 字符串(每个字符占两个字节) /// </summary> /// <param name="index"></param> /// <param name="length">chars</param> /// <param name="value"></param> public void StringPut(int index, int length, string value) { if (string.IsNullOrWhiteSpace(value)) { UInt16Put(index, 0); } else { char[] chars = value.ToCharArray(); int len = Math.Min(length, chars.Length); UInt16Put(index, (UInt16)len); Marshal.Copy(chars, 0, (IntPtr)(_pBuffer + index + 2), len); } } /// <summary> /// /// </summary> /// <param name="index"></param> /// <param name="length"></param> /// <returns></returns> public byte[] BinaryGet(int index, int length) { byte[] dest = new byte[length]; GetBytes(index, dest, 0, length); return dest; } /// <summary> /// /// </summary> /// <param name="index"></param> /// <param name="length"></param> /// <param name="src"></param> /// <returns></returns> public void BinaryPut(int index, int length, byte[] src) { SetBytes(index, src, 0, Math.Min(src.Length, length)); } /// <summary> /// /// </summary> /// <param name="index"></param> /// <param name="length"></param> /// <param name="dest"></param> /// <returns></returns> public int GetBytes(int index, int length, ref byte[] dest) { if (dest == null) return 0; return GetBytes(index, dest, 0, Math.Min(length, dest.Length)); } /// <summary> /// Copies a range of bytes from the underlying into a supplied byte array. /// </summary> /// <param name="index">index in the underlying buffer to start from.</param> /// <param name="destination">array into which the bytes will be copied.</param> /// <param name="offsetDestination">offset in the supplied buffer to start the copy</param> /// <param name="length">length of the supplied buffer to use.</param> /// <returns>count of bytes copied.</returns> public int GetBytes(int index, byte[] destination, int offsetDestination, int length) { int count = Math.Min(length, _capacity - index); Marshal.Copy((IntPtr)(_pBuffer + index), destination, offsetDestination, count); return count; } /// <summary> /// Writes a byte array into the underlying buffer. /// </summary> /// <param name="index">index in the underlying buffer to start from.</param> /// <param name="src">source byte array to be copied to the underlying buffer.</param> /// <param name="offset">offset in the supplied buffer to begin the copy.</param> /// <param name="length">length of the supplied buffer to copy.</param> /// <returns>count of bytes copied.</returns> public int SetBytes(int index, byte[] src, int offset, int length) { int count = Math.Min(length, _capacity - index); Marshal.Copy(src, offset, (IntPtr)(_pBuffer + index), count); return count; } /// <summary> /// /// </summary> public void Reset() { Array.Clear(this.Data, 0, this.Data.Length); } /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public override void Dispose() { Dispose(true); GC.SuppressFinalize(this); base.Dispose(); } /// <summary> /// Destructor for <see cref="DirectBuffer"/> /// </summary> ~PointerHelper() { Dispose(false); } private void Dispose(bool disposing) { if (_disposed) return; FreeGCHandle(); _disposed = true; } private void FreeGCHandle() { if (_needToFreeGCHandle) { _pinnedGCHandle.Free(); _needToFreeGCHandle = false; } } }