BitConverter.cs 18 KB

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