545 lines
22 KiB
C#
545 lines
22 KiB
C#
// ==++==
|
|
//
|
|
// 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.
|
|
//
|
|
//| <include path='docs/doc[@for="BitConverter"]/*' />
|
|
|
|
[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.
|
|
//| <include path='docs/doc[@for="BitConverter.IsLittleEndian"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes1"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes2"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes3"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes4"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes5"]/*' />
|
|
[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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes6"]/*' />
|
|
[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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes7"]/*' />
|
|
[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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes8"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.GetBytes9"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToChar"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToInt16"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToInt32"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToInt64"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="BitConverter.ToUInt16"]/*' />
|
|
[CLSCompliant(false)]
|
|
public static ushort ToUInt16(byte[] value, int startIndex)
|
|
{
|
|
unchecked {
|
|
return (ushort)ToInt16(value, startIndex);
|
|
}
|
|
}
|
|
|
|
// Converts an array of bytes into an uint.
|
|
//
|
|
//| <include path='docs/doc[@for="BitConverter.ToUInt32"]/*' />
|
|
[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.
|
|
//
|
|
//| <include path='docs/doc[@for="BitConverter.ToUInt64"]/*' />
|
|
[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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToSingle"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToDouble"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="BitConverter.ToBoolean"]/*' />
|
|
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;
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.DoubleToInt64Bits"]/*' />
|
|
[Inline]
|
|
public static unsafe long DoubleToInt64Bits(double value) {
|
|
return *((long *)&value);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.Int64BitsToDouble"]/*' />
|
|
[Inline]
|
|
public static unsafe double Int64BitsToDouble(long value) {
|
|
return *((double *)&value);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.DoubleToUInt64Bits"]/*' />
|
|
[Inline]
|
|
[CLSCompliant(false)]
|
|
public static unsafe ulong DoubleToUInt64Bits(double value) {
|
|
return *((ulong *)&value);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.UInt64BitsToDouble"]/*' />
|
|
[Inline]
|
|
[CLSCompliant(false)]
|
|
public static unsafe double UInt64BitsToDouble(ulong value) {
|
|
return *((double *)&value);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.SingleToUInt32Bits"]/*' />
|
|
[Inline]
|
|
[CLSCompliant(false)]
|
|
public static unsafe uint SingleToUInt32Bits(float value) {
|
|
return *((uint *)&value);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="BitConverter.UInt32BitsToSingle"]/*' />
|
|
[Inline]
|
|
[CLSCompliant(false)]
|
|
public static unsafe float UInt32BitsToSingle(uint value) {
|
|
return *((float *)&value);
|
|
}
|
|
}
|
|
}
|