// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== //============================================================ // // Class: BitConverter // // Purpose: Allows developers to view the base data types as // an arbitrary array of bits. // //=========================================================== namespace System { using System; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; // The BitConverter class contains methods for // converting an array of bytes to one of the base data // types, as well as for converting a base data type to an // array of bytes. // //| [CCtorIsRunDuringStartup] public sealed class BitConverter { // This field indicates the "endianness" of the architecture. // The value is set to true if the architecture is // little endian; false if it is big endian. //| public static readonly bool IsLittleEndian; static BitConverter() { byte [] ba = GetBytes((short)0xF); if (ba[0] == 0xF) { IsLittleEndian=true; } else { IsLittleEndian=false; } } // This class only contains static methods and may not be instantiated. private BitConverter() { } // ====================================================================== // Convert from primitive types to byte array slices. These functions // do not perform memory allocation and so are suitable for use in // interrupt handlers and other no-allocation-allowed contexts. -- mbj // ====================================================================== // Converts a byte into an existing array slice of bytes with length one. public static void GetBytes(bool value, byte[] array, int startIndex) { const int bytesNeeded = 1; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } array[startIndex] = (value ? (byte)Boolean.True : (byte)Boolean.False ); } // Converts a char into an existing array slice of bytes with length two. public static unsafe void GetBytes(char value, byte[] array, int startIndex) { const int bytesNeeded = 2; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((char *) ptr) = value; } } // Converts a short into an existing array slice of bytes with length two. public static unsafe void GetBytes(short value, byte[] array, int startIndex) { const int bytesNeeded = 2; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((short *) ptr) = value; } } // Converts an int into an existing array slice of bytes with length four. public static unsafe void GetBytes(int value, byte[] array, int startIndex) { const int bytesNeeded = 4; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((int *) ptr) = value; } } // Converts a long into an existing array slice of bytes with length eight. public static unsafe void GetBytes(long value, byte[] array, int startIndex) { const int bytesNeeded = 8; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((long *) ptr) = value; } } // Converts an ushort into an existing array slice of bytes with length two. [CLSCompliant(false)] public static unsafe void GetBytes(ushort value, byte[] array, int startIndex) { const int bytesNeeded = 2; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((ushort *) ptr) = value; } } // Converts an uint into an existing array slice of bytes with length four. [CLSCompliant(false)] public static unsafe void GetBytes(uint value, byte[] array, int startIndex) { const int bytesNeeded = 4; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((uint *) ptr) = value; } } // Converts an unsigned long into an existing array slice of bytes with length eight. [CLSCompliant(false)] public static unsafe void GetBytes(ulong value, byte[] array, int startIndex) { const int bytesNeeded = 8; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) { *((ulong *) ptr) = value; } } // Converts a float into an existing array slice of bytes with length four. public unsafe static void GetBytes(float value, byte[] array, int startIndex) { const int bytesNeeded = 4; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) *((float*) ptr) = value; } // Converts a double into an existing array slice of bytes with length eight. public unsafe static void GetBytes(double value, byte[] array, int startIndex) { const int bytesNeeded = 8; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex is negative"); } if (startIndex + bytesNeeded > array.Length) { throw new ArgumentException("Array is too small"); } fixed (byte *ptr = &array[startIndex]) *((double*) ptr) = value; } // ====================================================================== // Convert from primitive types to new byte arrays. These functions // perform memory allocation and so are unsuitable for use in // interrupt handlers and other no-allocation-allowed contexts. -- mbj // ====================================================================== // Converts a byte into an array of bytes with length one. //| public static byte[] GetBytes(bool value) { byte[] result = new byte[1]; GetBytes(value, result, 0); return result; } // Converts a char into an array of bytes with length two. //| public static unsafe byte[] GetBytes(char value) { // See also Lightning\Src\VM\COMUtilNative.cpp::CharToBytes byte[] result = new byte[2]; GetBytes(value, result, 0); return result; } // Converts a short into an array of bytes with length // two. //| public static unsafe byte[] GetBytes(short value) { // See also Lightning\Src\VM\COMUtilNative.cpp::I2ToBytes byte[] result = new byte[2]; GetBytes(value, result, 0); return result; } // Converts an int into an array of bytes with length // four. //| public static unsafe byte[] GetBytes(int value) { // See also Lightning\Src\VM\COMUtilNative.cpp::I4ToBytes byte[] result = new byte[4]; GetBytes(value, result, 0); return result; } // Converts a long into an array of bytes with length // eight. //| public static unsafe byte[] GetBytes(long value) { // See also Lightning\Src\VM\COMUtilNative.cpp::I8ToBytes byte[] result = new byte[8]; GetBytes(value, result, 0); return result; } // Converts an ushort into an array of bytes with // length two. //| [CLSCompliant(false)] public static unsafe byte[] GetBytes(ushort value) { // See also Lightning\Src\VM\COMUtilNative.cpp::U2ToBytes byte[] result = new byte[2]; GetBytes(value, result, 0); return result; } // Converts an uint into an array of bytes with // length four. //| [CLSCompliant(false)] public static unsafe byte[] GetBytes(uint value) { // See also Lightning\Src\VM\COMUtilNative.cpp::U4ToBytes byte[] result = new byte[4]; GetBytes(value, result, 0); return result; } // Converts an unsigned long into an array of bytes with // length eight. //| [CLSCompliant(false)] public static unsafe byte[] GetBytes(ulong value) { // See also Lightning\Src\VM\COMUtilNative.cpp::U8ToBytes byte[] result = new byte[8]; GetBytes(value, result, 0); return result; } // Converts a float into an array of bytes with length // four. //| public unsafe static byte[] GetBytes(float value) { byte[] result = new byte[4]; GetBytes(value, result, 0); return result; } // Converts a double into an array of bytes with length // eight. //| public unsafe static byte[] GetBytes(double value) { byte[] result = new byte[8]; GetBytes(value, result, 0); return result; } // ============ Convert from byte array slices to primitive types ============ // Converts an array of bytes into a char. //| public static unsafe char ToChar(byte[] value, int startIndex) { // See also Lightning\Src\VM\COMUtilNative.cpp::BytesToChar char result; fixed (byte *ptr = value) { result = *((char *) (ptr + startIndex)); } return result; } // Converts an array of bytes into a short. //| public static unsafe short ToInt16(byte[] value, int startIndex) { if (value == null) { throw new ArgumentNullException("value"); } if (((uint)startIndex) >= (uint)value.Length) { throw new ArgumentOutOfRangeException("startIndex"); } if (startIndex > (value.Length - 2)) { throw new ArgumentException("startIndex"); } fixed (byte* p = &value[startIndex]) { if ((startIndex % 2) == 0) { return *((short*)p); } if (IsLittleEndian) { return (short)(p[0] | (p[1] << 8)); } else { return (short)(p[1] | (p[0] << 8)); } } } // Converts an array of bytes into an int. //| public static unsafe int ToInt32(byte[]value, int startIndex) { if (value == null) { throw new ArgumentNullException("value"); } if (((uint)startIndex) >= (uint)value.Length) { throw new ArgumentOutOfRangeException("startIndex"); } if (startIndex > (value.Length - 4)) { throw new ArgumentException("startIndex"); } fixed (byte* p = &value[startIndex]) { if ((startIndex % 4) == 0) { return *((int*)p); } if (IsLittleEndian) { return ( ((int)p[0]) | (((int)p[1]) << 8) | (((int)p[2]) << 16) | (((int)p[3]) << 24) ); } else { return ( ((int)p[3]) | (((int)p[2]) << 8) | (((int)p[1]) << 16) | (((int)p[0]) << 24) ); } } } // Converts an array of bytes into a long. //| public static unsafe long ToInt64(byte[] value, int startIndex) { if (value == null) { throw new ArgumentNullException("value"); } if (((uint)startIndex) >= (uint)value.Length) { throw new ArgumentOutOfRangeException("startIndex"); } if (startIndex > (value.Length - 8)) { throw new ArgumentException("startIndex"); } fixed (byte* p = &value[startIndex]) { if ((startIndex % 8) == 0) { return *((long*)p); } if (IsLittleEndian) { int lo = (((int)p[0]) | (((int)p[1]) << 8) | (((int)p[2]) << 16) | (((int)p[3]) << 24) ); int hi = (((int)p[4]) | (((int)p[5]) << 8) | (((int)p[6]) << 16) | (((int)p[7]) << 24) ); return (long)(((ulong)lo) | ((ulong)hi) << 32); } else { int hi = (((int)p[3]) | (((int)p[2]) << 8) | (((int)p[1]) << 16) | (((int)p[0]) << 24) ); int lo = (((int)p[7]) | (((int)p[6]) << 8) | (((int)p[5]) << 16) | (((int)p[4]) << 24) ); return (long)(((ulong)lo) | ((ulong)hi) << 32); } } } // Converts an array of bytes into an ushort. // //| [CLSCompliant(false)] public static ushort ToUInt16(byte[] value, int startIndex) { unchecked { return (ushort)ToInt16(value, startIndex); } } // Converts an array of bytes into an uint. // //| [CLSCompliant(false)] public static uint ToUInt32(byte[] value, int startIndex) { unchecked { return (uint)ToInt32(value, startIndex); } } // Converts an array of bytes into an unsigned long. // //| [CLSCompliant(false)] public static unsafe ulong ToUInt64(byte[] value, int startIndex) { unchecked { return (ulong)ToInt64(value, startIndex); } } // Converts an array of bytes into a float. //| public static unsafe float ToSingle(byte[]value, int startIndex) { // See also Lightning\Src\VM\COMUtilNative.cpp::BytesToR4 float result; fixed (byte *ptr = value) { result = *((float *) (ptr + startIndex)); } return result; } // Converts an array of bytes into a double. //| public static unsafe double ToDouble(byte []value, int startIndex) { // See also Lightning\Src\VM\COMUtilNative.cpp::BytesToR8 double result; fixed (byte *ptr = value) { result = *((double *) (ptr + startIndex)); } return result; } //==================================ToBoolean=================================== //Action: Convert an array of bytes to a boolean value. We treat this array // as if the first 4 bytes were an Int4 an operate on this value. //Returns: True if the Int4 value of the first 4 bytes is non-zero. //Arguments: value -- The byte array // startIndex -- The position within the array. //Exceptions: See ToInt4. //============================================================================== // Converts an array of bytes into a boolean. //| public static bool ToBoolean(byte[]value, int startIndex) { if (value == null) throw new ArgumentNullException("value"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "ArgumentOutOfRange_NeedNonNegNum"); if (startIndex > value.Length - 1) throw new ArgumentOutOfRangeException("ArgumentOutOfRange_Index"); return (value[startIndex]==0)?false:true; } //| [Inline] public static unsafe long DoubleToInt64Bits(double value) { return *((long *)&value); } //| [Inline] public static unsafe double Int64BitsToDouble(long value) { return *((double *)&value); } //| [Inline] [CLSCompliant(false)] public static unsafe ulong DoubleToUInt64Bits(double value) { return *((ulong *)&value); } //| [Inline] [CLSCompliant(false)] public static unsafe double UInt64BitsToDouble(ulong value) { return *((double *)&value); } //| [Inline] [CLSCompliant(false)] public static unsafe uint SingleToUInt32Bits(float value) { return *((uint *)&value); } //| [Inline] [CLSCompliant(false)] public static unsafe float UInt32BitsToSingle(uint value) { return *((float *)&value); } } }