BitConverter.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. using Internal.Runtime.CompilerServices;
  7. namespace System
  8. {
  9. // The BitConverter class contains methods for
  10. // converting an array of bytes to one of the base data
  11. // types, as well as for converting a base data type to an
  12. // array of bytes.
  13. public static class BitConverter
  14. {
  15. // This field indicates the "endianess" of the architecture.
  16. // The value is set to true if the architecture is
  17. // little endian; false if it is big endian.
  18. #if BIGENDIAN
  19. [Intrinsic]
  20. public static readonly bool IsLittleEndian /* = false */;
  21. #else
  22. [Intrinsic]
  23. public static readonly bool IsLittleEndian = true;
  24. #endif
  25. // Converts a Boolean into an array of bytes with length one.
  26. public static byte[] GetBytes(bool value)
  27. {
  28. byte[] r = new byte[1];
  29. r[0] = (value ? (byte)1 : (byte)0);
  30. return r;
  31. }
  32. // Converts a Boolean into a Span of bytes with length one.
  33. public static bool TryWriteBytes(Span<byte> destination, bool value)
  34. {
  35. if (destination.Length < sizeof(byte))
  36. return false;
  37. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value ? (byte)1 : (byte)0);
  38. return true;
  39. }
  40. // Converts a char into an array of bytes with length two.
  41. public static byte[] GetBytes(char value)
  42. {
  43. byte[] bytes = new byte[sizeof(char)];
  44. Unsafe.As<byte, char>(ref bytes[0]) = value;
  45. return bytes;
  46. }
  47. // Converts a char into a Span
  48. public static bool TryWriteBytes(Span<byte> destination, char value)
  49. {
  50. if (destination.Length < sizeof(char))
  51. return false;
  52. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  53. return true;
  54. }
  55. // Converts a short into an array of bytes with length
  56. // two.
  57. public static byte[] GetBytes(short value)
  58. {
  59. byte[] bytes = new byte[sizeof(short)];
  60. Unsafe.As<byte, short>(ref bytes[0]) = value;
  61. return bytes;
  62. }
  63. // Converts a short into a Span
  64. public static bool TryWriteBytes(Span<byte> destination, short value)
  65. {
  66. if (destination.Length < sizeof(short))
  67. return false;
  68. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  69. return true;
  70. }
  71. // Converts an int into an array of bytes with length
  72. // four.
  73. public static byte[] GetBytes(int value)
  74. {
  75. byte[] bytes = new byte[sizeof(int)];
  76. Unsafe.As<byte, int>(ref bytes[0]) = value;
  77. return bytes;
  78. }
  79. // Converts an int into a Span
  80. public static bool TryWriteBytes(Span<byte> destination, int value)
  81. {
  82. if (destination.Length < sizeof(int))
  83. return false;
  84. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  85. return true;
  86. }
  87. // Converts a long into an array of bytes with length
  88. // eight.
  89. public static byte[] GetBytes(long value)
  90. {
  91. byte[] bytes = new byte[sizeof(long)];
  92. Unsafe.As<byte, long>(ref bytes[0]) = value;
  93. return bytes;
  94. }
  95. // Converts a long into a Span
  96. public static bool TryWriteBytes(Span<byte> destination, long value)
  97. {
  98. if (destination.Length < sizeof(long))
  99. return false;
  100. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  101. return true;
  102. }
  103. // Converts an ushort into an array of bytes with
  104. // length two.
  105. [CLSCompliant(false)]
  106. public static byte[] GetBytes(ushort value)
  107. {
  108. byte[] bytes = new byte[sizeof(ushort)];
  109. Unsafe.As<byte, ushort>(ref bytes[0]) = value;
  110. return bytes;
  111. }
  112. // Converts a ushort into a Span
  113. [CLSCompliant(false)]
  114. public static bool TryWriteBytes(Span<byte> destination, ushort value)
  115. {
  116. if (destination.Length < sizeof(ushort))
  117. return false;
  118. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  119. return true;
  120. }
  121. // Converts an uint into an array of bytes with
  122. // length four.
  123. [CLSCompliant(false)]
  124. public static byte[] GetBytes(uint value)
  125. {
  126. byte[] bytes = new byte[sizeof(uint)];
  127. Unsafe.As<byte, uint>(ref bytes[0]) = value;
  128. return bytes;
  129. }
  130. // Converts a uint into a Span
  131. [CLSCompliant(false)]
  132. public static bool TryWriteBytes(Span<byte> destination, uint value)
  133. {
  134. if (destination.Length < sizeof(uint))
  135. return false;
  136. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  137. return true;
  138. }
  139. // Converts an unsigned long into an array of bytes with
  140. // length eight.
  141. [CLSCompliant(false)]
  142. public static byte[] GetBytes(ulong value)
  143. {
  144. byte[] bytes = new byte[sizeof(ulong)];
  145. Unsafe.As<byte, ulong>(ref bytes[0]) = value;
  146. return bytes;
  147. }
  148. // Converts a ulong into a Span
  149. [CLSCompliant(false)]
  150. public static bool TryWriteBytes(Span<byte> destination, ulong value)
  151. {
  152. if (destination.Length < sizeof(ulong))
  153. return false;
  154. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  155. return true;
  156. }
  157. // Converts a float into an array of bytes with length
  158. // four.
  159. public static byte[] GetBytes(float value)
  160. {
  161. byte[] bytes = new byte[sizeof(float)];
  162. Unsafe.As<byte, float>(ref bytes[0]) = value;
  163. return bytes;
  164. }
  165. // Converts a float into a Span
  166. public static bool TryWriteBytes(Span<byte> destination, float value)
  167. {
  168. if (destination.Length < sizeof(float))
  169. return false;
  170. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  171. return true;
  172. }
  173. // Converts a double into an array of bytes with length
  174. // eight.
  175. public static byte[] GetBytes(double value)
  176. {
  177. byte[] bytes = new byte[sizeof(double)];
  178. Unsafe.As<byte, double>(ref bytes[0]) = value;
  179. return bytes;
  180. }
  181. // Converts a double into a Span
  182. public static bool TryWriteBytes(Span<byte> destination, double value)
  183. {
  184. if (destination.Length < sizeof(double))
  185. return false;
  186. Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
  187. return true;
  188. }
  189. // Converts an array of bytes into a char.
  190. public static char ToChar(byte[] value, int startIndex) => unchecked((char)ToInt16(value, startIndex));
  191. // Converts a Span into a char
  192. public static char ToChar(ReadOnlySpan<byte> value)
  193. {
  194. if (value.Length < sizeof(char))
  195. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  196. return Unsafe.ReadUnaligned<char>(ref MemoryMarshal.GetReference(value));
  197. }
  198. // Converts an array of bytes into a short.
  199. public static short ToInt16(byte[] value, int startIndex)
  200. {
  201. if (value == null)
  202. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  203. if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
  204. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
  205. if (startIndex > value.Length - sizeof(short))
  206. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
  207. return Unsafe.ReadUnaligned<short>(ref value[startIndex]);
  208. }
  209. // Converts a Span into a short
  210. public static short ToInt16(ReadOnlySpan<byte> value)
  211. {
  212. if (value.Length < sizeof(short))
  213. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  214. return Unsafe.ReadUnaligned<short>(ref MemoryMarshal.GetReference(value));
  215. }
  216. // Converts an array of bytes into an int.
  217. public static int ToInt32(byte[] value, int startIndex)
  218. {
  219. if (value == null)
  220. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  221. if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
  222. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
  223. if (startIndex > value.Length - sizeof(int))
  224. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
  225. return Unsafe.ReadUnaligned<int>(ref value[startIndex]);
  226. }
  227. // Converts a Span into an int
  228. public static int ToInt32(ReadOnlySpan<byte> value)
  229. {
  230. if (value.Length < sizeof(int))
  231. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  232. return Unsafe.ReadUnaligned<int>(ref MemoryMarshal.GetReference(value));
  233. }
  234. // Converts an array of bytes into a long.
  235. public static long ToInt64(byte[] value, int startIndex)
  236. {
  237. if (value == null)
  238. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  239. if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
  240. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
  241. if (startIndex > value.Length - sizeof(long))
  242. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
  243. return Unsafe.ReadUnaligned<long>(ref value[startIndex]);
  244. }
  245. // Converts a Span into a long
  246. public static long ToInt64(ReadOnlySpan<byte> value)
  247. {
  248. if (value.Length < sizeof(long))
  249. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  250. return Unsafe.ReadUnaligned<long>(ref MemoryMarshal.GetReference(value));
  251. }
  252. // Converts an array of bytes into an ushort.
  253. //
  254. [CLSCompliant(false)]
  255. public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ToInt16(value, startIndex));
  256. // Converts a Span into a ushort
  257. [CLSCompliant(false)]
  258. public static ushort ToUInt16(ReadOnlySpan<byte> value)
  259. {
  260. if (value.Length < sizeof(ushort))
  261. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  262. return Unsafe.ReadUnaligned<ushort>(ref MemoryMarshal.GetReference(value));
  263. }
  264. // Converts an array of bytes into an uint.
  265. //
  266. [CLSCompliant(false)]
  267. public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ToInt32(value, startIndex));
  268. // Convert a Span into a uint
  269. [CLSCompliant(false)]
  270. public static uint ToUInt32(ReadOnlySpan<byte> value)
  271. {
  272. if (value.Length < sizeof(uint))
  273. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  274. return Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(value));
  275. }
  276. // Converts an array of bytes into an unsigned long.
  277. //
  278. [CLSCompliant(false)]
  279. public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ToInt64(value, startIndex));
  280. // Converts a Span into an unsigned long
  281. [CLSCompliant(false)]
  282. public static ulong ToUInt64(ReadOnlySpan<byte> value)
  283. {
  284. if (value.Length < sizeof(ulong))
  285. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  286. return Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(value));
  287. }
  288. // Converts an array of bytes into a float.
  289. public static float ToSingle(byte[] value, int startIndex) => Int32BitsToSingle(ToInt32(value, startIndex));
  290. // Converts a Span into a float
  291. public static float ToSingle(ReadOnlySpan<byte> value)
  292. {
  293. if (value.Length < sizeof(float))
  294. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  295. return Unsafe.ReadUnaligned<float>(ref MemoryMarshal.GetReference(value));
  296. }
  297. // Converts an array of bytes into a double.
  298. public static double ToDouble(byte[] value, int startIndex) => Int64BitsToDouble(ToInt64(value, startIndex));
  299. // Converts a Span into a double
  300. public static double ToDouble(ReadOnlySpan<byte> value)
  301. {
  302. if (value.Length < sizeof(double))
  303. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  304. return Unsafe.ReadUnaligned<double>(ref MemoryMarshal.GetReference(value));
  305. }
  306. // Converts an array of bytes into a String.
  307. public static string ToString(byte[] value, int startIndex, int length)
  308. {
  309. if (value == null)
  310. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  311. if (startIndex < 0 || startIndex >= value.Length && startIndex > 0)
  312. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
  313. if (length < 0)
  314. throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_GenericPositive);
  315. if (startIndex > value.Length - length)
  316. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
  317. if (length == 0)
  318. {
  319. return string.Empty;
  320. }
  321. if (length > (int.MaxValue / 3))
  322. {
  323. // (int.MaxValue / 3) == 715,827,882 Bytes == 699 MB
  324. throw new ArgumentOutOfRangeException(nameof(length), SR.Format(SR.ArgumentOutOfRange_LengthTooLarge, (int.MaxValue / 3)));
  325. }
  326. return string.Create(length * 3 - 1, (value, startIndex, length), (dst, state) =>
  327. {
  328. const string HexValues = "0123456789ABCDEF";
  329. var src = new ReadOnlySpan<byte>(state.value, state.startIndex, state.length);
  330. int i = 0;
  331. int j = 0;
  332. byte b = src[i++];
  333. dst[j++] = HexValues[b >> 4];
  334. dst[j++] = HexValues[b & 0xF];
  335. while (i < src.Length)
  336. {
  337. b = src[i++];
  338. dst[j++] = '-';
  339. dst[j++] = HexValues[b >> 4];
  340. dst[j++] = HexValues[b & 0xF];
  341. }
  342. });
  343. }
  344. // Converts an array of bytes into a String.
  345. public static string ToString(byte[] value)
  346. {
  347. if (value == null)
  348. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  349. return ToString(value, 0, value.Length);
  350. }
  351. // Converts an array of bytes into a String.
  352. public static string ToString(byte[] value, int startIndex)
  353. {
  354. if (value == null)
  355. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  356. return ToString(value, startIndex, value.Length - startIndex);
  357. }
  358. /*==================================ToBoolean===================================
  359. **Action: Convert an array of bytes to a boolean value. We treat this array
  360. ** as if the first 4 bytes were an Int4 an operate on this value.
  361. **Returns: True if the Int4 value of the first 4 bytes is non-zero.
  362. **Arguments: value -- The byte array
  363. ** startIndex -- The position within the array.
  364. **Exceptions: See ToInt4.
  365. ==============================================================================*/
  366. // Converts an array of bytes into a boolean.
  367. public static bool ToBoolean(byte[] value, int startIndex)
  368. {
  369. if (value == null)
  370. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
  371. if (startIndex < 0)
  372. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
  373. if (startIndex > value.Length - 1)
  374. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); // differs from other overloads, which throw base ArgumentException
  375. return value[startIndex] != 0;
  376. }
  377. public static bool ToBoolean(ReadOnlySpan<byte> value)
  378. {
  379. if (value.Length < sizeof(byte))
  380. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
  381. return Unsafe.ReadUnaligned<byte>(ref MemoryMarshal.GetReference(value)) != 0;
  382. }
  383. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  384. public static unsafe long DoubleToInt64Bits(double value)
  385. {
  386. return *((long*)&value);
  387. }
  388. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  389. public static unsafe double Int64BitsToDouble(long value)
  390. {
  391. return *((double*)&value);
  392. }
  393. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  394. public static unsafe int SingleToInt32Bits(float value)
  395. {
  396. return *((int*)&value);
  397. }
  398. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  399. public static unsafe float Int32BitsToSingle(int value)
  400. {
  401. return *((float*)&value);
  402. }
  403. }
  404. }