[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / mscorlib / system / bitconverter.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  BitConverter
9 **
10 **
11 ** Purpose: Allows developers to view the base data types as 
12 **          an arbitrary array of bits.
13 **
14 ** 
15 ===========================================================*/
16 namespace System {
17     
18     using System;
19     using System.Runtime.CompilerServices;
20     using System.Diagnostics.Contracts;
21     using System.Security;
22
23     // The BitConverter class contains methods for
24     // converting an array of bytes to one of the base data 
25     // types, as well as for converting a base data type to an
26     // array of bytes.
27     // 
28     // Only statics, does not need to be marked with the serializable attribute
29     public static class BitConverter {
30 #if MONO
31         public static readonly bool IsLittleEndian = AmILittleEndian ();
32
33         static unsafe bool AmILittleEndian ()
34         {
35             // binary representations of 1.0:
36             // big endian:            3f f0 00 00 00 00 00 00
37             // little endian:         00 00 00 00 00 00 f0 3f
38             double d = 1.0;
39             byte *b = (byte*)&d;
40             return (b [0] == 0);
41         }
42 #else
43         // This field indicates the "endianess" of the architecture.
44         // The value is set to true if the architecture is
45         // little endian; false if it is big endian.
46 #if BIGENDIAN
47         public static readonly bool IsLittleEndian /* = false */;
48 #else
49         public static readonly bool IsLittleEndian = true;
50 #endif
51 #endif
52         // Converts a byte into an array of bytes with length one.
53         public static byte[] GetBytes(bool value) {
54             Contract.Ensures(Contract.Result<byte[]>() != null);
55             Contract.Ensures(Contract.Result<byte[]>().Length == 1);
56
57             byte[] r = new byte[1];
58             r[0] = (value ? (byte)Boolean.True : (byte)Boolean.False );
59             return r;
60         }
61     
62         // Converts a char into an array of bytes with length two.
63         public static byte[] GetBytes(char value)
64         {
65             Contract.Ensures(Contract.Result<byte[]>() != null);
66             Contract.Ensures(Contract.Result<byte[]>().Length == 2);
67
68             return GetBytes((short)value);
69         }
70       
71         // Converts a short into an array of bytes with length
72         // two.
73         [System.Security.SecuritySafeCritical]  // auto-generated
74         public unsafe static byte[] GetBytes(short value)
75         {
76             Contract.Ensures(Contract.Result<byte[]>() != null);
77             Contract.Ensures(Contract.Result<byte[]>().Length == 2);
78
79             byte[] bytes = new byte[2];
80             fixed(byte* b = bytes)
81                 *((short*)b) = value;
82             return bytes;
83         }
84
85         // Converts an int into an array of bytes with length 
86         // four.
87         [System.Security.SecuritySafeCritical]  // auto-generated
88         public unsafe static byte[] GetBytes(int value)
89         {
90             Contract.Ensures(Contract.Result<byte[]>() != null);
91             Contract.Ensures(Contract.Result<byte[]>().Length == 4);
92
93             byte[] bytes = new byte[4];
94             fixed(byte* b = bytes)
95                 *((int*)b) = value;
96             return bytes;
97         }
98       
99         // Converts a long into an array of bytes with length 
100         // eight.
101         [System.Security.SecuritySafeCritical]  // auto-generated
102         public unsafe static byte[] GetBytes(long value)
103         {
104             Contract.Ensures(Contract.Result<byte[]>() != null);
105             Contract.Ensures(Contract.Result<byte[]>().Length == 8);
106
107             byte[] bytes = new byte[8];
108             fixed(byte* b = bytes)
109                 *((long*)b) = value;
110             return bytes;
111         }
112     
113         // Converts an ushort into an array of bytes with
114         // length two.
115         [CLSCompliant(false)]
116         public static byte[] GetBytes(ushort value) {
117             Contract.Ensures(Contract.Result<byte[]>() != null);
118             Contract.Ensures(Contract.Result<byte[]>().Length == 2);
119
120             return GetBytes((short)value);
121         }
122         
123         // Converts an uint into an array of bytes with
124         // length four.
125         [CLSCompliant(false)]
126         public static byte[] GetBytes(uint value) {
127             Contract.Ensures(Contract.Result<byte[]>() != null);
128             Contract.Ensures(Contract.Result<byte[]>().Length == 4);
129
130             return GetBytes((int)value);
131         }
132         
133         // Converts an unsigned long into an array of bytes with
134         // length eight.
135         [CLSCompliant(false)]
136         public static byte[] GetBytes(ulong value) {
137             Contract.Ensures(Contract.Result<byte[]>() != null);
138             Contract.Ensures(Contract.Result<byte[]>().Length == 8);
139
140             return GetBytes((long)value);
141         }
142       
143         // Converts a float into an array of bytes with length 
144         // four.
145         [System.Security.SecuritySafeCritical]  // auto-generated
146         public unsafe static byte[] GetBytes(float value)
147         {
148             Contract.Ensures(Contract.Result<byte[]>() != null);
149             Contract.Ensures(Contract.Result<byte[]>().Length == 4);
150
151             return GetBytes(*(int*)&value);
152         }
153       
154         // Converts a double into an array of bytes with length 
155         // eight.
156         [System.Security.SecuritySafeCritical]  // auto-generated
157         public unsafe static byte[] GetBytes(double value)
158         {
159             Contract.Ensures(Contract.Result<byte[]>() != null);
160             Contract.Ensures(Contract.Result<byte[]>().Length == 8);
161
162             return GetBytes(*(long*)&value);
163         }
164
165         // Converts an array of bytes into a char.  
166         public static char ToChar(byte[] value, int startIndex)
167         {
168             if (value == null) {
169                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
170             }
171
172             if ((uint)startIndex >= value.Length) {
173                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
174             }
175
176             if (startIndex > value.Length - 2) {
177                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
178             }
179             Contract.EndContractBlock();
180
181             return (char)ToInt16(value, startIndex);
182         }
183       
184         // Converts an array of bytes into a short.  
185         [System.Security.SecuritySafeCritical]  // auto-generated
186         public static unsafe short ToInt16(byte[] value, int startIndex) {
187             if( value == null)  {
188                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
189             }
190             
191             if ((uint) startIndex >= value.Length) {
192                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
193             }
194         
195             if (startIndex > value.Length -2) {
196                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
197             }
198             Contract.EndContractBlock();
199
200             fixed( byte * pbyte = &value[startIndex]) {
201                 if( startIndex % 2 == 0) { // data is aligned 
202                     return *((short *) pbyte);
203                 }
204                 else {
205                     if( IsLittleEndian) { 
206                         return (short)((*pbyte) | (*(pbyte + 1) << 8)) ;
207                     }
208                     else {
209                         return (short)((*pbyte << 8) | (*(pbyte + 1)));                        
210                     }
211                 }
212             }
213             
214         }
215       
216         // Converts an array of bytes into an int.  
217         [System.Security.SecuritySafeCritical]  // auto-generated
218         public static unsafe int ToInt32 (byte[] value, int startIndex) {
219             if( value == null)  {
220                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
221             }
222         
223             if ((uint) startIndex >= value.Length) {
224                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
225             }
226         
227             if (startIndex > value.Length -4) {
228                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
229             }
230             Contract.EndContractBlock();
231
232             fixed( byte * pbyte = &value[startIndex]) {
233                 if( startIndex % 4 == 0) { // data is aligned 
234                     return *((int *) pbyte);
235                 }
236                 else {
237                     if( IsLittleEndian) { 
238                         return (*pbyte) | (*(pbyte + 1) << 8)  | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
239                     }
240                     else {
241                         return (*pbyte << 24) | (*(pbyte + 1) << 16)  | (*(pbyte + 2) << 8) | (*(pbyte + 3));                        
242                     }
243                 }
244             }
245         }
246       
247         // Converts an array of bytes into a long.  
248         [System.Security.SecuritySafeCritical]  // auto-generated
249         public static unsafe long ToInt64 (byte[] value, int startIndex) {
250             if (value == null)  {
251                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
252             }
253         
254             if ((uint) startIndex >= value.Length) {
255                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
256             }
257         
258             if (startIndex > value.Length -8) {
259                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
260             }
261             Contract.EndContractBlock();
262
263             fixed( byte * pbyte = &value[startIndex]) {
264                 if( startIndex % 8 == 0) { // data is aligned 
265                     return *((long *) pbyte);
266                 }
267                 else {
268                     if( IsLittleEndian) { 
269                         int i1 = (*pbyte) | (*(pbyte + 1) << 8)  | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);                        
270                         int i2  = (*(pbyte+4)) | (*(pbyte + 5) << 8)  | (*(pbyte + 6) << 16) | (*(pbyte + 7) << 24);
271                         return (uint)i1 | ((long)i2 << 32);
272                     }
273                     else {
274                         int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16)  | (*(pbyte + 2) << 8) | (*(pbyte + 3));                        
275                         int i2  = (*(pbyte+4) << 24) | (*(pbyte + 5) << 16)  | (*(pbyte + 6) << 8) | (*(pbyte + 7));
276                         return (uint)i2 | ((long)i1 << 32);
277                     }
278                 }
279             }        
280         }
281       
282     
283         // Converts an array of bytes into an ushort.
284         // 
285         [CLSCompliant(false)]
286         public static ushort ToUInt16(byte[] value, int startIndex)
287         {
288             if (value == null)
289                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
290             if ((uint)startIndex >= value.Length)
291                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
292             if (startIndex > value.Length - 2)
293                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
294             Contract.EndContractBlock();
295
296             return (ushort)ToInt16(value, startIndex);
297         }
298     
299         // Converts an array of bytes into an uint.
300         // 
301         [CLSCompliant(false)]
302         public static uint ToUInt32(byte[] value, int startIndex)
303         {
304             if (value == null)
305                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
306             if ((uint)startIndex >= value.Length)
307                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
308             if (startIndex > value.Length - 4)
309                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
310             Contract.EndContractBlock();
311
312             return (uint)ToInt32(value, startIndex);
313         }
314     
315         // Converts an array of bytes into an unsigned long.
316         // 
317         [CLSCompliant(false)]
318         public static ulong ToUInt64(byte[] value, int startIndex)
319         {
320             if (value == null)
321                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
322             if ((uint)startIndex >= value.Length)
323                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
324             if (startIndex > value.Length - 8)
325                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
326             Contract.EndContractBlock();
327
328             return (ulong)ToInt64(value, startIndex);
329         }
330     
331         // Converts an array of bytes into a float.  
332         [System.Security.SecuritySafeCritical]  // auto-generated
333         unsafe public static float ToSingle (byte[] value, int startIndex)
334         {
335             if (value == null)
336                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
337             if ((uint)startIndex >= value.Length)
338                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
339             if (startIndex > value.Length - 4)
340                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
341             Contract.EndContractBlock();
342
343             int val = ToInt32(value, startIndex);
344             return *(float*)&val;
345         }
346       
347         // Converts an array of bytes into a double.  
348         [System.Security.SecuritySafeCritical]  // auto-generated
349         unsafe public static double ToDouble (byte[] value, int startIndex)
350         {
351             if (value == null)
352                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
353             if ((uint)startIndex >= value.Length)
354                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
355             if (startIndex > value.Length - 8)
356                 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
357             Contract.EndContractBlock();
358
359             long val = ToInt64(value, startIndex);
360             return *(double*)&val;
361         }
362       
363         private static char GetHexValue(int i) {
364             Contract.Assert( i >=0 && i <16, "i is out of range.");
365             if (i<10) {
366                 return (char)(i + '0');
367             }
368     
369             return (char)(i - 10 + 'A');
370         }
371
372         // Converts an array of bytes into a String.  
373         public static String ToString (byte[] value, int startIndex, int length) {            
374             if (value == null) {
375                 throw new ArgumentNullException("byteArray");
376             }
377
378             if (startIndex < 0 || startIndex >= value.Length && startIndex > 0) {  // Don't throw for a 0 length array.
379                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex")); 
380             }
381
382             if (length < 0) {
383                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
384             }
385
386             if (startIndex > value.Length - length) {
387                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall"));
388             }
389             Contract.EndContractBlock();
390
391             if (length == 0) {
392                 return string.Empty;
393             }
394
395             if (length > (Int32.MaxValue / 3)) {
396                 // (Int32.MaxValue / 3) == 715,827,882 Bytes == 699 MB
397                 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_LengthTooLarge", (Int32.MaxValue / 3)));
398             }
399
400             int chArrayLength = length * 3;
401             
402             char[] chArray = new char[chArrayLength];
403             int i = 0;
404             int index = startIndex;
405             for (i = 0; i < chArrayLength; i += 3) {
406                 byte b = value[index++];
407                 chArray[i]= GetHexValue(b/16);
408                 chArray[i+1] = GetHexValue(b%16);
409                 chArray[i+2] = '-';
410             }
411
412             // We don't need the last '-' character
413             return new String(chArray, 0, chArray.Length - 1);
414         }
415     
416         // Converts an array of bytes into a String.  
417         public static String ToString(byte [] value) {
418             if (value == null)
419                 throw new ArgumentNullException("value");
420             Contract.Ensures(Contract.Result<String>() != null);            
421             Contract.EndContractBlock();
422             return ToString(value, 0, value.Length);
423         }
424     
425         // Converts an array of bytes into a String.  
426         public static String ToString (byte [] value, int startIndex) {
427             if (value == null)
428                 throw new ArgumentNullException("value");
429             Contract.Ensures(Contract.Result<String>() != null);            
430             Contract.EndContractBlock();
431             return ToString(value, startIndex, value.Length - startIndex);
432         }
433       
434         /*==================================ToBoolean===================================
435         **Action:  Convert an array of bytes to a boolean value.  We treat this array 
436         **         as if the first 4 bytes were an Int4 an operate on this value.
437         **Returns: True if the Int4 value of the first 4 bytes is non-zero.
438         **Arguments: value -- The byte array
439         **           startIndex -- The position within the array.
440         **Exceptions: See ToInt4.
441         ==============================================================================*/
442         // Converts an array of bytes into a boolean.  
443         public static bool ToBoolean(byte[] value, int startIndex) {
444             if (value==null)
445                 throw new ArgumentNullException("value");
446             if (startIndex < 0)
447                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
448             if (startIndex > value.Length - 1)
449                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
450             Contract.EndContractBlock();
451     
452             return (value[startIndex]==0)?false:true;
453         }
454
455         [SecuritySafeCritical]
456         public static unsafe long DoubleToInt64Bits(double value) {
457             // If we're on a big endian machine, what should this method do?  You could argue for
458             // either big endian or little endian, depending on whether you are writing to a file that
459             // should be used by other programs on that processor, or for compatibility across multiple
460             // formats.  Because this is ambiguous, we're excluding this from the Portable Library & Win8 Profile.
461             // If we ever run on big endian machines, produce two versions where endianness is specified.
462             Contract.Assert(IsLittleEndian, "This method is implemented assuming little endian with an ambiguous spec.");
463             return *((long *)&value);
464         }
465
466         [SecuritySafeCritical]
467         public static unsafe double Int64BitsToDouble(long value) {
468             // If we're on a big endian machine, what should this method do?  You could argue for
469             // either big endian or little endian, depending on whether you are writing to a file that
470             // should be used by other programs on that processor, or for compatibility across multiple
471             // formats.  Because this is ambiguous, we're excluding this from the Portable Library & Win8 Profile.
472             // If we ever run on big endian machines, produce two versions where endianness is specified.
473             Contract.Assert(IsLittleEndian, "This method is implemented assuming little endian with an ambiguous spec.");
474             return *((double*)&value);
475         }                    
476     }
477
478
479 }