| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- //------------------------------------------------------------------------------
- // <copyright file="DbBuffer.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.ProviderBase
- {
- using System;
- using System.Data.Common;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Permissions;
- using System.Threading;
- // DbBuffer is abstract to require derived class to exist
- // so that when debugging, we can tell the difference between one DbBuffer and another
- internal abstract class DbBuffer : SafeHandle {
- internal const int LMEM_FIXED = 0x0000;
- internal const int LMEM_MOVEABLE = 0x0002;
- internal const int LMEM_ZEROINIT = 0x0040;
- private readonly int _bufferLength;
-
- private DbBuffer(int initialSize, bool zeroBuffer) : base(IntPtr.Zero, true) {
- if (0 < initialSize) {
- int flags = ((zeroBuffer) ? LMEM_ZEROINIT : LMEM_FIXED);
- _bufferLength = initialSize;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {} finally {
- base.handle = SafeNativeMethods.LocalAlloc(flags, (IntPtr)initialSize);
- }
- if (IntPtr.Zero == base.handle) {
- throw new OutOfMemoryException();
- }
- }
- }
- protected DbBuffer(int initialSize) : this(initialSize, true) {
- }
- protected DbBuffer(IntPtr invalidHandleValue, bool ownsHandle) : base(invalidHandleValue, ownsHandle) {
- }
- private int BaseOffset { get { return 0; } }
- public override bool IsInvalid {
- get {
- return (IntPtr.Zero == base.handle);
- }
- }
- internal int Length {
- get {
- return _bufferLength;
- }
- }
- internal string PtrToStringUni(int offset) {
- offset += BaseOffset;
- Validate(offset, 2);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
-
- string value = null;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
-
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- int length = UnsafeNativeMethods.lstrlenW(ptr);
- Validate(offset, (2*(length+1)));
- value = Marshal.PtrToStringUni(ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
-
- return value;
- }
- internal String PtrToStringUni(int offset, int length) {
- offset += BaseOffset;
- Validate(offset, 2*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- string value = null;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- value = Marshal.PtrToStringUni(ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal byte ReadByte(int offset) {
- offset += BaseOffset;
- ValidateCheck(offset, 1);
- Debug.Assert(0 == offset%4, "invalid alignment");
- byte value;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- value = Marshal.ReadByte(ptr, offset);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal byte[] ReadBytes(int offset, int length) {
- byte[] value = new byte[length];
- return ReadBytes(offset, value, 0, length);
- }
- internal byte[] ReadBytes(int offset, byte[] destination, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != destination, "null destination");
- Debug.Assert(startIndex + length <= destination.Length, "destination too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(ptr, destination, startIndex, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return destination;
- }
- internal Char ReadChar(int offset) {
- short value = ReadInt16(offset);
- return unchecked((char)value);
- }
- internal char[] ReadChars(int offset, char[] destination, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 2*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != destination, "null destination");
- Debug.Assert(startIndex + length <= destination.Length, "destination too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(ptr, destination, startIndex, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return destination;
- }
- internal Double ReadDouble(int offset) {
- Int64 value = ReadInt64(offset);
- return BitConverter.Int64BitsToDouble(value);
- }
- internal Int16 ReadInt16(int offset) {
- offset += BaseOffset;
- ValidateCheck(offset, 2);
- Debug.Assert(0 == offset%2, "invalid alignment");
- short value;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- value = Marshal.ReadInt16(ptr, offset);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal void ReadInt16Array(int offset, short[] destination, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 2*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != destination, "null destination");
- Debug.Assert(startIndex + length <= destination.Length, "destination too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(ptr, destination, startIndex, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal Int32 ReadInt32(int offset) {
- offset += BaseOffset;
- ValidateCheck(offset, 4);
- Debug.Assert(0 == offset%4, "invalid alignment");
- int value;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- value = Marshal.ReadInt32(ptr, offset);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal void ReadInt32Array(int offset, int[] destination, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 4*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != destination, "null destination");
- Debug.Assert(startIndex + length <= destination.Length, "destination too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(ptr, destination, startIndex, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal Int64 ReadInt64(int offset) {
- offset += BaseOffset;
- ValidateCheck(offset, 8);
- Debug.Assert(0 == offset%IntPtr.Size, "invalid alignment");
- long value;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- value = Marshal.ReadInt64(ptr, offset);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal IntPtr ReadIntPtr(int offset) {
- offset += BaseOffset;
- ValidateCheck(offset, IntPtr.Size);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- IntPtr value;
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- value = Marshal.ReadIntPtr(ptr, offset);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- return value;
- }
- internal unsafe Single ReadSingle(int offset) {
- Int32 value = ReadInt32(offset);
- return *(Single*)&value;
- }
- override protected bool ReleaseHandle() {
- // NOTE: The SafeHandle class guarantees this will be called exactly once.
- IntPtr ptr = base.handle;
- base.handle = IntPtr.Zero;
- if (IntPtr.Zero != ptr) {
- SafeNativeMethods.LocalFree(ptr);
- }
- return true;
- }
- private void StructureToPtr(int offset, object structure) {
- Debug.Assert(null != structure, "null structure");
- offset += BaseOffset;
- ValidateCheck(offset, Marshal.SizeOf(structure.GetType()));
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.StructureToPtr(structure, ptr, false/*fDeleteOld*/);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteByte(int offset, byte value) {
- offset += BaseOffset;
- ValidateCheck(offset, 1);
- Debug.Assert(0 == offset%4, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- Marshal.WriteByte(ptr, offset, value);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteBytes(int offset, byte[] source, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != source, "null source");
- Debug.Assert(startIndex + length <= source.Length, "source too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(source, startIndex, ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteCharArray(int offset, char[] source, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 2*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != source, "null source");
- Debug.Assert(startIndex + length <= source.Length, "source too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(source, startIndex, ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteDouble(int offset, Double value) {
- WriteInt64(offset, BitConverter.DoubleToInt64Bits(value));
- }
- internal void WriteInt16(int offset, short value) {
- offset += BaseOffset;
- ValidateCheck(offset, 2);
- Debug.Assert(0 == offset%2, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- Marshal.WriteInt16(ptr, offset, value);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteInt16Array(int offset, short[] source, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 2*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != source, "null source");
- Debug.Assert(startIndex + length <= source.Length, "source too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(source, startIndex, ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteInt32(int offset, int value) {
- offset += BaseOffset;
- ValidateCheck(offset, 4);
- Debug.Assert(0 == offset%4, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- Marshal.WriteInt32(ptr, offset, value);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteInt32Array(int offset, int[] source, int startIndex, int length) {
- offset += BaseOffset;
- Validate(offset, 4*length);
- Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
- Debug.Assert(null != source, "null source");
- Debug.Assert(startIndex + length <= source.Length, "source too small");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
- Marshal.Copy(source, startIndex, ptr, length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteInt64(int offset, long value) {
- offset += BaseOffset;
- ValidateCheck(offset, 8);
- Debug.Assert(0 == offset%IntPtr.Size, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- Marshal.WriteInt64(ptr, offset, value);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal void WriteIntPtr(int offset, IntPtr value) {
- offset += BaseOffset;
- ValidateCheck(offset, IntPtr.Size);
- Debug.Assert(0 == offset%IntPtr.Size, "invalid alignment");
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- Marshal.WriteIntPtr(ptr, offset, value);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal unsafe void WriteSingle(int offset, Single value) {
- WriteInt32(offset, *(Int32*)&value);
- }
- internal void ZeroMemory() {
- bool mustRelease = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref mustRelease);
- IntPtr ptr = DangerousGetHandle();
- SafeNativeMethods.ZeroMemory(ptr, (IntPtr)Length);
- }
- finally {
- if (mustRelease) {
- DangerousRelease();
- }
- }
- }
- internal Guid ReadGuid(int offset) {
- // faster than Marshal.PtrToStructure(offset, typeof(Guid))
- byte[] buffer = new byte[16];
- ReadBytes(offset, buffer, 0, 16);
- return new Guid(buffer);
- }
- internal void WriteGuid(int offset, Guid value) {
- // faster than Marshal.Copy(value.GetByteArray()
- StructureToPtr(offset, value);
- }
- internal DateTime ReadDate(int offset) {
- short[] buffer = new short[3];
- ReadInt16Array(offset, buffer, 0, 3);
- return new DateTime(
- unchecked((ushort)buffer[0]), // Year
- unchecked((ushort)buffer[1]), // Month
- unchecked((ushort)buffer[2])); // Day
- }
- internal void WriteDate(int offset, DateTime value) {
- short[] buffer = new short[3] {
- unchecked((short)value.Year),
- unchecked((short)value.Month),
- unchecked((short)value.Day),
- };
- WriteInt16Array(offset, buffer, 0, 3);
- }
- internal TimeSpan ReadTime(int offset) {
- short[] buffer = new short[3];
- ReadInt16Array(offset, buffer, 0, 3);
- return new TimeSpan(
- unchecked((ushort)buffer[0]), // Hours
- unchecked((ushort)buffer[1]), // Minutes
- unchecked((ushort)buffer[2])); // Seconds
- }
- internal void WriteTime(int offset, TimeSpan value) {
- short[] buffer = new short[3] {
- unchecked((short)value.Hours),
- unchecked((short)value.Minutes),
- unchecked((short)value.Seconds),
- };
- WriteInt16Array(offset, buffer, 0, 3);
- }
- internal DateTime ReadDateTime(int offset) {
- short[] buffer = new short[6];
- ReadInt16Array(offset, buffer, 0, 6);
- int ticks = ReadInt32(offset + 12);
- DateTime value = new DateTime(
- unchecked((ushort)buffer[0]), // Year
- unchecked((ushort)buffer[1]), // Month
- unchecked((ushort)buffer[2]), // Day
- unchecked((ushort)buffer[3]), // Hours
- unchecked((ushort)buffer[4]), // Minutes
- unchecked((ushort)buffer[5])); // Seconds
- return value.AddTicks(ticks / 100);
- }
- internal void WriteDateTime(int offset, DateTime value) {
- int ticks = (int)(value.Ticks % 10000000L)*100;
- short[] buffer = new short[6] {
- unchecked((short)value.Year),
- unchecked((short)value.Month),
- unchecked((short)value.Day),
- unchecked((short)value.Hour),
- unchecked((short)value.Minute),
- unchecked((short)value.Second),
- };
- WriteInt16Array(offset, buffer, 0, 6);
- WriteInt32(offset + 12, ticks);
- }
- internal Decimal ReadNumeric(int offset) {
- byte[] bits = new byte[20];
- ReadBytes(offset, bits, 1, 19);
- int[] buffer = new int[4];
- buffer[3] = ((int) bits[2]) << 16; // scale
- if (0 == bits[3]) {
- buffer[3] |= unchecked((int)0x80000000); //sign
- }
- buffer[0] = BitConverter.ToInt32(bits, 4); // low
- buffer[1] = BitConverter.ToInt32(bits, 8); // mid
- buffer[2] = BitConverter.ToInt32(bits, 12); // high
- if (0 != BitConverter.ToInt32(bits, 16)) {
- throw ADP.NumericToDecimalOverflow();
- }
- return new Decimal(buffer);
- }
- internal void WriteNumeric(int offset, Decimal value, byte precision) {
- int[] tmp = Decimal.GetBits(value);
- byte[] buffer = new byte[20];
- buffer[1] = precision;
- Buffer.BlockCopy(tmp, 14, buffer, 2, 2); // copy sign and scale
- buffer[3] = (Byte) ((0 == buffer[3]) ? 1 : 0); // flip sign for native
- Buffer.BlockCopy(tmp, 0, buffer, 4, 12);
- buffer[16] = 0;
- buffer[17] = 0;
- buffer[18] = 0;
- buffer[19] = 0;
- WriteBytes(offset, buffer, 1, 19);
- }
- [ConditionalAttribute("DEBUG")]
- protected void ValidateCheck(int offset, int count) {
- Validate(offset, count);
- }
- protected void Validate(int offset, int count) {
- if ((offset < 0) || (count < 0) || (Length < checked(offset + count))) {
- throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer);
- }
- }
- }
- }
|