// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: BitConverter
**
**
** Purpose: Allows developers to view the base data types as
** an arbitrary array of bits.
**
** Date: August 9, 1998
**
===========================================================*/
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.
// ======================================================================
// 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.
// ======================================================================
// 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: 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) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToI2
short result;
fixed (byte *ptr = value) {
result = *((short *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into an int.
//|
public static unsafe int ToInt32(byte[]value, int startIndex) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToI4
int result;
fixed (byte *ptr = value) {
result = *((int *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into a long.
//|
public static unsafe long ToInt64(byte[] value, int startIndex) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToI8
long result;
fixed (byte *ptr = value) {
result = *((long *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into an ushort.
//
//|
[CLSCompliant(false)] //
public static unsafe ushort ToUInt16(byte[] value, int startIndex) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToU2
ushort result;
fixed (byte *ptr = value) {
result = *((ushort *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into an uint.
//
//|
[CLSCompliant(false)] //
public static unsafe uint ToUInt32(byte[] value, int startIndex) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToU4
uint result;
fixed (byte *ptr = value) {
result = *((uint *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into an unsigned long.
//
//|
[CLSCompliant(false)] //
public static unsafe ulong ToUInt64(byte[] value, int startIndex) {
// rusa: see also Lightning\Src\VM\COMUtilNative.cpp::BytesToU8
ulong result;
fixed (byte *ptr = value) {
result = *((ulong *) (ptr + startIndex));
}
return result;
}
// Converts an array of bytes into a float.
//|
public static unsafe float ToSingle(byte[]value, int startIndex) {
// rusa: 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) {
// rusa: 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);
}
}
}