// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; namespace System { // 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. public static class BitConverter { // This field indicates the "endianess" of the architecture. // The value is set to true if the architecture is // little endian; false if it is big endian. #if BIGENDIAN public static readonly bool IsLittleEndian /* = false */; #else public static readonly bool IsLittleEndian = true; #endif // Converts a Boolean into an array of bytes with length one. public static byte[] GetBytes(bool value) { byte[] r = new byte[1]; r[0] = (value ? (byte)1 : (byte)0); return r; } // Converts a Boolean into a Span of bytes with length one. public static bool TryWriteBytes(Span destination, bool value) { if (destination.Length < sizeof(byte)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value ? (byte)1 : (byte)0); return true; } // Converts a char into an array of bytes with length two. public static byte[] GetBytes(char value) { byte[] bytes = new byte[sizeof(char)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a char into a Span public static bool TryWriteBytes(Span destination, char value) { if (destination.Length < sizeof(char)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts a short into an array of bytes with length // two. public static byte[] GetBytes(short value) { byte[] bytes = new byte[sizeof(short)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a short into a Span public static bool TryWriteBytes(Span destination, short value) { if (destination.Length < sizeof(short)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts an int into an array of bytes with length // four. public static byte[] GetBytes(int value) { byte[] bytes = new byte[sizeof(int)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts an int into a Span public static bool TryWriteBytes(Span destination, int value) { if (destination.Length < sizeof(int)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts a long into an array of bytes with length // eight. public static byte[] GetBytes(long value) { byte[] bytes = new byte[sizeof(long)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a long into a Span public static bool TryWriteBytes(Span destination, long value) { if (destination.Length < sizeof(long)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts an ushort into an array of bytes with // length two. [CLSCompliant(false)] public static byte[] GetBytes(ushort value) { byte[] bytes = new byte[sizeof(ushort)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a ushort into a Span [CLSCompliant(false)] public static bool TryWriteBytes(Span destination, ushort value) { if (destination.Length < sizeof(ushort)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts an uint into an array of bytes with // length four. [CLSCompliant(false)] public static byte[] GetBytes(uint value) { byte[] bytes = new byte[sizeof(uint)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a uint into a Span [CLSCompliant(false)] public static bool TryWriteBytes(Span destination, uint value) { if (destination.Length < sizeof(uint)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts an unsigned long into an array of bytes with // length eight. [CLSCompliant(false)] public static byte[] GetBytes(ulong value) { byte[] bytes = new byte[sizeof(ulong)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a ulong into a Span [CLSCompliant(false)] public static bool TryWriteBytes(Span destination, ulong value) { if (destination.Length < sizeof(ulong)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts a float into an array of bytes with length // four. public static byte[] GetBytes(float value) { byte[] bytes = new byte[sizeof(float)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a float into a Span public static bool TryWriteBytes(Span destination, float value) { if (destination.Length < sizeof(float)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts a double into an array of bytes with length // eight. public static byte[] GetBytes(double value) { byte[] bytes = new byte[sizeof(double)]; Unsafe.As(ref bytes[0]) = value; return bytes; } // Converts a double into a Span public static bool TryWriteBytes(Span destination, double value) { if (destination.Length < sizeof(double)) return false; Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); return true; } // Converts an array of bytes into a char. public static char ToChar(byte[] value, int startIndex) => unchecked((char)ToInt16(value, startIndex)); // Converts a Span into a char public static char ToChar(ReadOnlySpan value) { if (value.Length < sizeof(char)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into a short. public static short ToInt16(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(short)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); return Unsafe.ReadUnaligned(ref value[startIndex]); } // Converts a Span into a short public static short ToInt16(ReadOnlySpan value) { if (value.Length < sizeof(short)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into an int. public static int ToInt32(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(int)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); return Unsafe.ReadUnaligned(ref value[startIndex]); } // Converts a Span into an int public static int ToInt32(ReadOnlySpan value) { if (value.Length < sizeof(int)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into a long. public static long ToInt64(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(long)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); return Unsafe.ReadUnaligned(ref value[startIndex]); } // Converts a Span into a long public static long ToInt64(ReadOnlySpan value) { if (value.Length < sizeof(long)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into an ushort. // [CLSCompliant(false)] public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ToInt16(value, startIndex)); // Converts a Span into a ushort [CLSCompliant(false)] public static ushort ToUInt16(ReadOnlySpan value) { if (value.Length < sizeof(ushort)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into an uint. // [CLSCompliant(false)] public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ToInt32(value, startIndex)); // Convert a Span into a uint [CLSCompliant(false)] public static uint ToUInt32(ReadOnlySpan value) { if (value.Length < sizeof(uint)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into an unsigned long. // [CLSCompliant(false)] public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ToInt64(value, startIndex)); // Converts a Span into an unsigned long [CLSCompliant(false)] public static ulong ToUInt64(ReadOnlySpan value) { if (value.Length < sizeof(ulong)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into a float. public static float ToSingle(byte[] value, int startIndex) => Int32BitsToSingle(ToInt32(value, startIndex)); // Converts a Span into a float public static float ToSingle(ReadOnlySpan value) { if (value.Length < sizeof(float)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into a double. public static double ToDouble(byte[] value, int startIndex) => Int64BitsToDouble(ToInt64(value, startIndex)); // Converts a Span into a double public static double ToDouble(ReadOnlySpan value) { if (value.Length < sizeof(double)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)); } // Converts an array of bytes into a String. public static string ToString(byte[] value, int startIndex, int length) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (startIndex < 0 || startIndex >= value.Length && startIndex > 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_GenericPositive); if (startIndex > value.Length - length) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); if (length == 0) { return string.Empty; } if (length > (int.MaxValue / 3)) { // (Int32.MaxValue / 3) == 715,827,882 Bytes == 699 MB throw new ArgumentOutOfRangeException(nameof(length), SR.Format(SR.ArgumentOutOfRange_LengthTooLarge, (int.MaxValue / 3))); } return string.Create(length * 3 - 1, (value, startIndex, length), (dst, state) => { const string HexValues = "0123456789ABCDEF"; var src = new ReadOnlySpan(state.value, state.startIndex, state.length); int i = 0; int j = 0; byte b = src[i++]; dst[j++] = HexValues[b >> 4]; dst[j++] = HexValues[b & 0xF]; while (i < src.Length) { b = src[i++]; dst[j++] = '-'; dst[j++] = HexValues[b >> 4]; dst[j++] = HexValues[b & 0xF]; } }); } // Converts an array of bytes into a String. public static string ToString(byte[] value) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); return ToString(value, 0, value.Length); } // Converts an array of bytes into a String. public static string ToString(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); return ToString(value, startIndex, value.Length - startIndex); } /*==================================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) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (startIndex < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - 1) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); // differs from other overloads, which throw base ArgumentException return value[startIndex] != 0; } public static bool ToBoolean(ReadOnlySpan value) { if (value.Length < sizeof(byte)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); return Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(value)) != 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe long DoubleToInt64Bits(double value) { return *((long*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe double Int64BitsToDouble(long value) { return *((double*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int SingleToInt32Bits(float value) { return *((int*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float Int32BitsToSingle(int value) { return *((float*)&value); } } }