1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Data.Common;
6 using System.Diagnostics;
7 using System.Runtime.CompilerServices;
8 using System.Runtime.InteropServices;
9 
10 namespace System.Data.ProviderBase
11 {
12     // DbBuffer is abstract to require derived class to exist
13     // so that when debugging, we can tell the difference between one DbBuffer and another
14     internal abstract class DbBuffer : SafeHandle
15     {
16         private readonly int _bufferLength;
17 
DbBuffer(int initialSize)18         protected DbBuffer(int initialSize) : base(IntPtr.Zero, true)
19         {
20             if (0 < initialSize)
21             {
22                 _bufferLength = initialSize;
23                 RuntimeHelpers.PrepareConstrainedRegions();
24                 try { }
25                 finally
26                 {
27                     base.handle = SafeNativeMethods.LocalAlloc((IntPtr)initialSize);
28                 }
29                 if (IntPtr.Zero == base.handle)
30                 {
31                     throw new OutOfMemoryException();
32                 }
33             }
34         }
35 
DbBuffer(IntPtr invalidHandleValue, bool ownsHandle)36         protected DbBuffer(IntPtr invalidHandleValue, bool ownsHandle) : base(invalidHandleValue, ownsHandle)
37         {
38         }
39 
40         private int BaseOffset { get { return 0; } }
41 
42         public override bool IsInvalid
43         {
44             get
45             {
46                 return (IntPtr.Zero == base.handle);
47             }
48         }
49 
50         internal int Length
51         {
52             get
53             {
54                 return _bufferLength;
55             }
56         }
57 
PtrToStringUni(int offset)58         internal string PtrToStringUni(int offset)
59         {
60             offset += BaseOffset;
61             Validate(offset, 2);
62             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
63 
64             string value = null;
65             bool mustRelease = false;
66             RuntimeHelpers.PrepareConstrainedRegions();
67             try
68             {
69                 DangerousAddRef(ref mustRelease);
70 
71                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
72                 value = Marshal.PtrToStringUni(ptr);
73                 Validate(offset, (2 * (value.Length + 1)));
74             }
75             finally
76             {
77                 if (mustRelease)
78                 {
79                     DangerousRelease();
80                 }
81             }
82 
83             return value;
84         }
85 
PtrToStringUni(int offset, int length)86         internal String PtrToStringUni(int offset, int length)
87         {
88             offset += BaseOffset;
89             Validate(offset, 2 * length);
90             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
91 
92             string value = null;
93             bool mustRelease = false;
94             RuntimeHelpers.PrepareConstrainedRegions();
95             try
96             {
97                 DangerousAddRef(ref mustRelease);
98 
99                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
100                 value = Marshal.PtrToStringUni(ptr, length);
101             }
102             finally
103             {
104                 if (mustRelease)
105                 {
106                     DangerousRelease();
107                 }
108             }
109             return value;
110         }
111 
ReadByte(int offset)112         internal byte ReadByte(int offset)
113         {
114             offset += BaseOffset;
115             ValidateCheck(offset, 1);
116             Debug.Assert(0 == offset % 4, "invalid alignment");
117 
118             byte value;
119             bool mustRelease = false;
120             RuntimeHelpers.PrepareConstrainedRegions();
121             try
122             {
123                 DangerousAddRef(ref mustRelease);
124 
125                 IntPtr ptr = DangerousGetHandle();
126                 value = Marshal.ReadByte(ptr, offset);
127             }
128             finally
129             {
130                 if (mustRelease)
131                 {
132                     DangerousRelease();
133                 }
134             }
135             return value;
136         }
137 
ReadBytes(int offset, int length)138         internal byte[] ReadBytes(int offset, int length)
139         {
140             byte[] value = new byte[length];
141             return ReadBytes(offset, value, 0, length);
142         }
143 
ReadBytes(int offset, byte[] destination, int startIndex, int length)144         internal byte[] ReadBytes(int offset, byte[] destination, int startIndex, int length)
145         {
146             offset += BaseOffset;
147             Validate(offset, length);
148             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
149             Debug.Assert(null != destination, "null destination");
150             Debug.Assert(startIndex + length <= destination.Length, "destination too small");
151 
152             bool mustRelease = false;
153             RuntimeHelpers.PrepareConstrainedRegions();
154             try
155             {
156                 DangerousAddRef(ref mustRelease);
157 
158                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
159                 Marshal.Copy(ptr, destination, startIndex, length);
160             }
161             finally
162             {
163                 if (mustRelease)
164                 {
165                     DangerousRelease();
166                 }
167             }
168             return destination;
169         }
170 
ReadChar(int offset)171         internal Char ReadChar(int offset)
172         {
173             short value = ReadInt16(offset);
174             return unchecked((char)value);
175         }
176 
ReadChars(int offset, char[] destination, int startIndex, int length)177         internal char[] ReadChars(int offset, char[] destination, int startIndex, int length)
178         {
179             offset += BaseOffset;
180             Validate(offset, 2 * length);
181             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
182             Debug.Assert(null != destination, "null destination");
183             Debug.Assert(startIndex + length <= destination.Length, "destination too small");
184 
185             bool mustRelease = false;
186             RuntimeHelpers.PrepareConstrainedRegions();
187             try
188             {
189                 DangerousAddRef(ref mustRelease);
190 
191                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
192                 Marshal.Copy(ptr, destination, startIndex, length);
193             }
194             finally
195             {
196                 if (mustRelease)
197                 {
198                     DangerousRelease();
199                 }
200             }
201             return destination;
202         }
203 
ReadDouble(int offset)204         internal Double ReadDouble(int offset)
205         {
206             Int64 value = ReadInt64(offset);
207             return BitConverter.Int64BitsToDouble(value);
208         }
209 
ReadInt16(int offset)210         internal Int16 ReadInt16(int offset)
211         {
212             offset += BaseOffset;
213             ValidateCheck(offset, 2);
214             Debug.Assert(0 == offset % 2, "invalid alignment");
215 
216             short value;
217             bool mustRelease = false;
218             RuntimeHelpers.PrepareConstrainedRegions();
219             try
220             {
221                 DangerousAddRef(ref mustRelease);
222 
223                 IntPtr ptr = DangerousGetHandle();
224                 value = Marshal.ReadInt16(ptr, offset);
225             }
226             finally
227             {
228                 if (mustRelease)
229                 {
230                     DangerousRelease();
231                 }
232             }
233             return value;
234         }
235 
ReadInt16Array(int offset, short[] destination, int startIndex, int length)236         internal void ReadInt16Array(int offset, short[] destination, int startIndex, int length)
237         {
238             offset += BaseOffset;
239             Validate(offset, 2 * length);
240             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
241             Debug.Assert(null != destination, "null destination");
242             Debug.Assert(startIndex + length <= destination.Length, "destination too small");
243 
244             bool mustRelease = false;
245             RuntimeHelpers.PrepareConstrainedRegions();
246             try
247             {
248                 DangerousAddRef(ref mustRelease);
249 
250                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
251                 Marshal.Copy(ptr, destination, startIndex, length);
252             }
253             finally
254             {
255                 if (mustRelease)
256                 {
257                     DangerousRelease();
258                 }
259             }
260         }
261 
ReadInt32(int offset)262         internal Int32 ReadInt32(int offset)
263         {
264             offset += BaseOffset;
265             ValidateCheck(offset, 4);
266             Debug.Assert(0 == offset % 4, "invalid alignment");
267 
268             int value;
269             bool mustRelease = false;
270             RuntimeHelpers.PrepareConstrainedRegions();
271             try
272             {
273                 DangerousAddRef(ref mustRelease);
274 
275                 IntPtr ptr = DangerousGetHandle();
276                 value = Marshal.ReadInt32(ptr, offset);
277             }
278             finally
279             {
280                 if (mustRelease)
281                 {
282                     DangerousRelease();
283                 }
284             }
285             return value;
286         }
287 
ReadInt32Array(int offset, int[] destination, int startIndex, int length)288         internal void ReadInt32Array(int offset, int[] destination, int startIndex, int length)
289         {
290             offset += BaseOffset;
291             Validate(offset, 4 * length);
292             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
293             Debug.Assert(null != destination, "null destination");
294             Debug.Assert(startIndex + length <= destination.Length, "destination too small");
295 
296             bool mustRelease = false;
297             RuntimeHelpers.PrepareConstrainedRegions();
298             try
299             {
300                 DangerousAddRef(ref mustRelease);
301 
302                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
303                 Marshal.Copy(ptr, destination, startIndex, length);
304             }
305             finally
306             {
307                 if (mustRelease)
308                 {
309                     DangerousRelease();
310                 }
311             }
312         }
313 
ReadInt64(int offset)314         internal Int64 ReadInt64(int offset)
315         {
316             offset += BaseOffset;
317             ValidateCheck(offset, 8);
318             Debug.Assert(0 == offset % IntPtr.Size, "invalid alignment");
319 
320             long value;
321             bool mustRelease = false;
322             RuntimeHelpers.PrepareConstrainedRegions();
323             try
324             {
325                 DangerousAddRef(ref mustRelease);
326 
327                 IntPtr ptr = DangerousGetHandle();
328                 value = Marshal.ReadInt64(ptr, offset);
329             }
330             finally
331             {
332                 if (mustRelease)
333                 {
334                     DangerousRelease();
335                 }
336             }
337             return value;
338         }
339 
ReadIntPtr(int offset)340         internal IntPtr ReadIntPtr(int offset)
341         {
342             offset += BaseOffset;
343             ValidateCheck(offset, IntPtr.Size);
344             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
345 
346             IntPtr value;
347             bool mustRelease = false;
348             RuntimeHelpers.PrepareConstrainedRegions();
349             try
350             {
351                 DangerousAddRef(ref mustRelease);
352 
353                 IntPtr ptr = DangerousGetHandle();
354                 value = Marshal.ReadIntPtr(ptr, offset);
355             }
356             finally
357             {
358                 if (mustRelease)
359                 {
360                     DangerousRelease();
361                 }
362             }
363             return value;
364         }
365 
ReadSingle(int offset)366         internal unsafe Single ReadSingle(int offset)
367         {
368             Int32 value = ReadInt32(offset);
369             return *(Single*)&value;
370         }
371 
ReleaseHandle()372         protected override bool ReleaseHandle()
373         {
374             // NOTE: The SafeHandle class guarantees this will be called exactly once.
375             IntPtr ptr = base.handle;
376             base.handle = IntPtr.Zero;
377             if (IntPtr.Zero != ptr)
378             {
379                 SafeNativeMethods.LocalFree(ptr);
380             }
381             return true;
382         }
383 
StructureToPtr(int offset, object structure)384         private void StructureToPtr(int offset, object structure)
385         {
386             Debug.Assert(null != structure, "null structure");
387             offset += BaseOffset;
388             ValidateCheck(offset, Marshal.SizeOf(structure.GetType()));
389             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
390 
391             bool mustRelease = false;
392             RuntimeHelpers.PrepareConstrainedRegions();
393             try
394             {
395                 DangerousAddRef(ref mustRelease);
396 
397                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
398                 Marshal.StructureToPtr(structure, ptr, false/*fDeleteOld*/);
399             }
400             finally
401             {
402                 if (mustRelease)
403                 {
404                     DangerousRelease();
405                 }
406             }
407         }
408 
WriteByte(int offset, byte value)409         internal void WriteByte(int offset, byte value)
410         {
411             offset += BaseOffset;
412             ValidateCheck(offset, 1);
413             Debug.Assert(0 == offset % 4, "invalid alignment");
414 
415             bool mustRelease = false;
416             RuntimeHelpers.PrepareConstrainedRegions();
417             try
418             {
419                 DangerousAddRef(ref mustRelease);
420 
421                 IntPtr ptr = DangerousGetHandle();
422                 Marshal.WriteByte(ptr, offset, value);
423             }
424             finally
425             {
426                 if (mustRelease)
427                 {
428                     DangerousRelease();
429                 }
430             }
431         }
432 
WriteBytes(int offset, byte[] source, int startIndex, int length)433         internal void WriteBytes(int offset, byte[] source, int startIndex, int length)
434         {
435             offset += BaseOffset;
436             Validate(offset, length);
437             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
438             Debug.Assert(null != source, "null source");
439             Debug.Assert(startIndex + length <= source.Length, "source too small");
440 
441             bool mustRelease = false;
442             RuntimeHelpers.PrepareConstrainedRegions();
443             try
444             {
445                 DangerousAddRef(ref mustRelease);
446 
447                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
448                 Marshal.Copy(source, startIndex, ptr, length);
449             }
450             finally
451             {
452                 if (mustRelease)
453                 {
454                     DangerousRelease();
455                 }
456             }
457         }
458 
WriteCharArray(int offset, char[] source, int startIndex, int length)459         internal void WriteCharArray(int offset, char[] source, int startIndex, int length)
460         {
461             offset += BaseOffset;
462             Validate(offset, 2 * length);
463             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
464             Debug.Assert(null != source, "null source");
465             Debug.Assert(startIndex + length <= source.Length, "source too small");
466 
467             bool mustRelease = false;
468             RuntimeHelpers.PrepareConstrainedRegions();
469             try
470             {
471                 DangerousAddRef(ref mustRelease);
472 
473                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
474                 Marshal.Copy(source, startIndex, ptr, length);
475             }
476             finally
477             {
478                 if (mustRelease)
479                 {
480                     DangerousRelease();
481                 }
482             }
483         }
484 
WriteDouble(int offset, Double value)485         internal void WriteDouble(int offset, Double value)
486         {
487             WriteInt64(offset, BitConverter.DoubleToInt64Bits(value));
488         }
489 
WriteInt16(int offset, short value)490         internal void WriteInt16(int offset, short value)
491         {
492             offset += BaseOffset;
493             ValidateCheck(offset, 2);
494             Debug.Assert(0 == offset % 2, "invalid alignment");
495 
496             bool mustRelease = false;
497             RuntimeHelpers.PrepareConstrainedRegions();
498             try
499             {
500                 DangerousAddRef(ref mustRelease);
501 
502                 IntPtr ptr = DangerousGetHandle();
503                 Marshal.WriteInt16(ptr, offset, value);
504             }
505             finally
506             {
507                 if (mustRelease)
508                 {
509                     DangerousRelease();
510                 }
511             }
512         }
513 
WriteInt16Array(int offset, short[] source, int startIndex, int length)514         internal void WriteInt16Array(int offset, short[] source, int startIndex, int length)
515         {
516             offset += BaseOffset;
517             Validate(offset, 2 * length);
518             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
519             Debug.Assert(null != source, "null source");
520             Debug.Assert(startIndex + length <= source.Length, "source too small");
521 
522             bool mustRelease = false;
523             RuntimeHelpers.PrepareConstrainedRegions();
524             try
525             {
526                 DangerousAddRef(ref mustRelease);
527 
528                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
529                 Marshal.Copy(source, startIndex, ptr, length);
530             }
531             finally
532             {
533                 if (mustRelease)
534                 {
535                     DangerousRelease();
536                 }
537             }
538         }
539 
WriteInt32(int offset, int value)540         internal void WriteInt32(int offset, int value)
541         {
542             offset += BaseOffset;
543             ValidateCheck(offset, 4);
544             Debug.Assert(0 == offset % 4, "invalid alignment");
545 
546             bool mustRelease = false;
547             RuntimeHelpers.PrepareConstrainedRegions();
548             try
549             {
550                 DangerousAddRef(ref mustRelease);
551 
552                 IntPtr ptr = DangerousGetHandle();
553                 Marshal.WriteInt32(ptr, offset, value);
554             }
555             finally
556             {
557                 if (mustRelease)
558                 {
559                     DangerousRelease();
560                 }
561             }
562         }
563 
WriteInt32Array(int offset, int[] source, int startIndex, int length)564         internal void WriteInt32Array(int offset, int[] source, int startIndex, int length)
565         {
566             offset += BaseOffset;
567             Validate(offset, 4 * length);
568             Debug.Assert(0 == offset % ADP.PtrSize, "invalid alignment");
569             Debug.Assert(null != source, "null source");
570             Debug.Assert(startIndex + length <= source.Length, "source too small");
571 
572             bool mustRelease = false;
573             RuntimeHelpers.PrepareConstrainedRegions();
574             try
575             {
576                 DangerousAddRef(ref mustRelease);
577 
578                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
579                 Marshal.Copy(source, startIndex, ptr, length);
580             }
581             finally
582             {
583                 if (mustRelease)
584                 {
585                     DangerousRelease();
586                 }
587             }
588         }
589 
WriteInt64(int offset, long value)590         internal void WriteInt64(int offset, long value)
591         {
592             offset += BaseOffset;
593             ValidateCheck(offset, 8);
594             Debug.Assert(0 == offset % IntPtr.Size, "invalid alignment");
595 
596             bool mustRelease = false;
597             RuntimeHelpers.PrepareConstrainedRegions();
598             try
599             {
600                 DangerousAddRef(ref mustRelease);
601 
602                 IntPtr ptr = DangerousGetHandle();
603                 Marshal.WriteInt64(ptr, offset, value);
604             }
605             finally
606             {
607                 if (mustRelease)
608                 {
609                     DangerousRelease();
610                 }
611             }
612         }
613 
WriteIntPtr(int offset, IntPtr value)614         internal void WriteIntPtr(int offset, IntPtr value)
615         {
616             offset += BaseOffset;
617             ValidateCheck(offset, IntPtr.Size);
618             Debug.Assert(0 == offset % IntPtr.Size, "invalid alignment");
619 
620             bool mustRelease = false;
621             RuntimeHelpers.PrepareConstrainedRegions();
622             try
623             {
624                 DangerousAddRef(ref mustRelease);
625 
626                 IntPtr ptr = DangerousGetHandle();
627                 Marshal.WriteIntPtr(ptr, offset, value);
628             }
629             finally
630             {
631                 if (mustRelease)
632                 {
633                     DangerousRelease();
634                 }
635             }
636         }
637 
WriteSingle(int offset, Single value)638         internal unsafe void WriteSingle(int offset, Single value)
639         {
640             WriteInt32(offset, *(Int32*)&value);
641         }
642 
ZeroMemory()643         internal void ZeroMemory()
644         {
645             bool mustRelease = false;
646             RuntimeHelpers.PrepareConstrainedRegions();
647             try
648             {
649                 DangerousAddRef(ref mustRelease);
650 
651                 IntPtr ptr = DangerousGetHandle();
652                 SafeNativeMethods.ZeroMemory(ptr, Length);
653             }
654             finally
655             {
656                 if (mustRelease)
657                 {
658                     DangerousRelease();
659                 }
660             }
661         }
662 
ReadGuid(int offset)663         internal Guid ReadGuid(int offset)
664         {
665             // faster than Marshal.PtrToStructure(offset, typeof(Guid))
666             byte[] buffer = new byte[16];
667             ReadBytes(offset, buffer, 0, 16);
668             return new Guid(buffer);
669         }
WriteGuid(int offset, Guid value)670         internal void WriteGuid(int offset, Guid value)
671         {
672             // faster than Marshal.Copy(value.GetByteArray()
673             StructureToPtr(offset, value);
674         }
675 
ReadDate(int offset)676         internal DateTime ReadDate(int offset)
677         {
678             short[] buffer = new short[3];
679             ReadInt16Array(offset, buffer, 0, 3);
680             return new DateTime(
681                 unchecked((ushort)buffer[0]),   // Year
682                 unchecked((ushort)buffer[1]),   // Month
683                 unchecked((ushort)buffer[2]));  // Day
684         }
WriteDate(int offset, DateTime value)685         internal void WriteDate(int offset, DateTime value)
686         {
687             short[] buffer = new short[3] {
688                 unchecked((short)value.Year),
689                 unchecked((short)value.Month),
690                 unchecked((short)value.Day),
691             };
692             WriteInt16Array(offset, buffer, 0, 3);
693         }
694 
ReadTime(int offset)695         internal TimeSpan ReadTime(int offset)
696         {
697             short[] buffer = new short[3];
698             ReadInt16Array(offset, buffer, 0, 3);
699             return new TimeSpan(
700                 unchecked((ushort)buffer[0]),   // Hours
701                 unchecked((ushort)buffer[1]),   // Minutes
702                 unchecked((ushort)buffer[2]));  // Seconds
703         }
WriteTime(int offset, TimeSpan value)704         internal void WriteTime(int offset, TimeSpan value)
705         {
706             short[] buffer = new short[3] {
707                 unchecked((short)value.Hours),
708                 unchecked((short)value.Minutes),
709                 unchecked((short)value.Seconds),
710             };
711             WriteInt16Array(offset, buffer, 0, 3);
712         }
713 
ReadDateTime(int offset)714         internal DateTime ReadDateTime(int offset)
715         {
716             short[] buffer = new short[6];
717             ReadInt16Array(offset, buffer, 0, 6);
718             int ticks = ReadInt32(offset + 12);
719             DateTime value = new DateTime(
720                 unchecked((ushort)buffer[0]),  // Year
721                 unchecked((ushort)buffer[1]),  // Month
722                 unchecked((ushort)buffer[2]),  // Day
723                 unchecked((ushort)buffer[3]),  // Hours
724                 unchecked((ushort)buffer[4]),  // Minutes
725                 unchecked((ushort)buffer[5])); // Seconds
726             return value.AddTicks(ticks / 100);
727         }
WriteDateTime(int offset, DateTime value)728         internal void WriteDateTime(int offset, DateTime value)
729         {
730             int ticks = (int)(value.Ticks % 10000000L) * 100;
731             short[] buffer = new short[6] {
732                 unchecked((short)value.Year),
733                 unchecked((short)value.Month),
734                 unchecked((short)value.Day),
735                 unchecked((short)value.Hour),
736                 unchecked((short)value.Minute),
737                 unchecked((short)value.Second),
738             };
739             WriteInt16Array(offset, buffer, 0, 6);
740             WriteInt32(offset + 12, ticks);
741         }
742 
ReadNumeric(int offset)743         internal Decimal ReadNumeric(int offset)
744         {
745             byte[] bits = new byte[20];
746             ReadBytes(offset, bits, 1, 19);
747 
748             int[] buffer = new int[4];
749             buffer[3] = ((int)bits[2]) << 16; // scale
750             if (0 == bits[3])
751             {
752                 buffer[3] |= unchecked((int)0x80000000); //sign
753             }
754             buffer[0] = BitConverter.ToInt32(bits, 4);     // low
755             buffer[1] = BitConverter.ToInt32(bits, 8);     // mid
756             buffer[2] = BitConverter.ToInt32(bits, 12);     // high
757             if (0 != BitConverter.ToInt32(bits, 16))
758             {
759                 throw ADP.NumericToDecimalOverflow();
760             }
761             return new Decimal(buffer);
762         }
763 
WriteNumeric(int offset, Decimal value, byte precision)764         internal void WriteNumeric(int offset, Decimal value, byte precision)
765         {
766             int[] tmp = Decimal.GetBits(value);
767             byte[] buffer = new byte[20];
768 
769             buffer[1] = precision;
770             Buffer.BlockCopy(tmp, 14, buffer, 2, 2); // copy sign and scale
771             buffer[3] = (Byte)((0 == buffer[3]) ? 1 : 0); // flip sign for native
772             Buffer.BlockCopy(tmp, 0, buffer, 4, 12);
773             buffer[16] = 0;
774             buffer[17] = 0;
775             buffer[18] = 0;
776             buffer[19] = 0;
777             WriteBytes(offset, buffer, 1, 19);
778         }
779 
780         [ConditionalAttribute("DEBUG")]
ValidateCheck(int offset, int count)781         protected void ValidateCheck(int offset, int count)
782         {
783             Validate(offset, count);
784         }
785 
Validate(int offset, int count)786         protected void Validate(int offset, int count)
787         {
788             if ((offset < 0) || (count < 0) || (Length < checked(offset + count)))
789             {
790                 throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer);
791             }
792         }
793     }
794 }