move FrameworkName from corlib to System
[mcs.git] / class / corlib / System / BitConverter.cs
blob29db8e6bcb584a0413b4dbc7bfd8a128433f2bce
1 //
2 // System.BitConverter.cs
3 //
4 // Author:
5 // Matt Kimball (matt@kimball.net)
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Text;
32 namespace System
34 public
35 static
36 class BitConverter
38 static readonly bool SwappedWordsInDouble = DoubleWordsAreSwapped ();
39 public static readonly bool IsLittleEndian = AmILittleEndian ();
41 static unsafe bool AmILittleEndian ()
43 // binary representations of 1.0:
44 // big endian: 3f f0 00 00 00 00 00 00
45 // little endian: 00 00 00 00 00 00 f0 3f
46 // arm fpa little endian: 00 00 f0 3f 00 00 00 00
47 double d = 1.0;
48 byte *b = (byte*)&d;
49 return (b [0] == 0);
52 static unsafe bool DoubleWordsAreSwapped ()
54 // binary representations of 1.0:
55 // big endian: 3f f0 00 00 00 00 00 00
56 // little endian: 00 00 00 00 00 00 f0 3f
57 // arm fpa little endian: 00 00 f0 3f 00 00 00 00
58 double d = 1.0;
59 byte *b = (byte*)&d;
60 return b [2] == 0xf0;
63 public static long DoubleToInt64Bits (double value)
65 return ToInt64 (GetBytes (value), 0);
68 public static double Int64BitsToDouble (long value)
70 return ToDouble (GetBytes (value), 0);
73 internal static double InternalInt64BitsToDouble (long value)
75 return SwappableToDouble (GetBytes (value), 0);
78 unsafe static byte[] GetBytes (byte *ptr, int count)
80 byte [] ret = new byte [count];
82 for (int i = 0; i < count; i++) {
83 ret [i] = ptr [i];
86 return ret;
89 unsafe public static byte[] GetBytes (bool value)
91 return GetBytes ((byte *) &value, 1);
94 unsafe public static byte[] GetBytes (char value)
96 return GetBytes ((byte *) &value, 2);
99 unsafe public static byte[] GetBytes (short value)
101 return GetBytes ((byte *) &value, 2);
104 unsafe public static byte[] GetBytes (int value)
106 return GetBytes ((byte *) &value, 4);
109 unsafe public static byte[] GetBytes (long value)
111 return GetBytes ((byte *) &value, 8);
114 [CLSCompliant (false)]
115 unsafe public static byte[] GetBytes (ushort value)
117 return GetBytes ((byte *) &value, 2);
120 [CLSCompliant (false)]
121 unsafe public static byte[] GetBytes (uint value)
123 return GetBytes ((byte *) &value, 4);
126 [CLSCompliant (false)]
127 unsafe public static byte[] GetBytes (ulong value)
129 return GetBytes ((byte *) &value, 8);
132 unsafe public static byte[] GetBytes (float value)
134 return GetBytes ((byte *) &value, 4);
137 unsafe public static byte[] GetBytes (double value)
139 if (SwappedWordsInDouble) {
140 byte[] data = new byte [8];
141 byte *p = (byte*)&value;
142 data [0] = p [4];
143 data [1] = p [5];
144 data [2] = p [6];
145 data [3] = p [7];
146 data [4] = p [0];
147 data [5] = p [1];
148 data [6] = p [2];
149 data [7] = p [3];
150 return data;
151 } else {
152 return GetBytes ((byte *) &value, 8);
156 unsafe static void PutBytes (byte *dst, byte[] src, int start_index, int count)
158 if (src == null)
159 throw new ArgumentNullException ("value");
161 if (start_index < 0 || (start_index > src.Length - 1))
162 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
163 + " out of range. Must be non-negative and less than the"
164 + " size of the collection.");
166 // avoid integer overflow (with large pos/neg start_index values)
167 if (src.Length - count < start_index)
168 throw new ArgumentException ("Destination array is not long"
169 + " enough to copy all the items in the collection."
170 + " Check array index and length.");
172 for (int i = 0; i < count; i++)
173 dst[i] = src[i + start_index];
176 unsafe public static bool ToBoolean (byte[] value, int startIndex)
178 if (value == null)
179 throw new ArgumentNullException ("value");
181 if (startIndex < 0 || (startIndex > value.Length - 1))
182 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
183 + " out of range. Must be non-negative and less than the"
184 + " size of the collection.");
186 if (value [startIndex] != 0)
187 return true;
189 return false;
192 unsafe public static char ToChar (byte[] value, int startIndex)
194 char ret;
196 PutBytes ((byte *) &ret, value, startIndex, 2);
198 return ret;
201 unsafe public static short ToInt16 (byte[] value, int startIndex)
203 short ret;
205 PutBytes ((byte *) &ret, value, startIndex, 2);
207 return ret;
210 unsafe public static int ToInt32 (byte[] value, int startIndex)
212 int ret;
214 PutBytes ((byte *) &ret, value, startIndex, 4);
216 return ret;
219 unsafe public static long ToInt64 (byte[] value, int startIndex)
221 long ret;
223 PutBytes ((byte *) &ret, value, startIndex, 8);
225 return ret;
228 [CLSCompliant (false)]
229 unsafe public static ushort ToUInt16 (byte[] value, int startIndex)
231 ushort ret;
233 PutBytes ((byte *) &ret, value, startIndex, 2);
235 return ret;
238 [CLSCompliant (false)]
239 unsafe public static uint ToUInt32 (byte[] value, int startIndex)
241 uint ret;
243 PutBytes ((byte *) &ret, value, startIndex, 4);
245 return ret;
248 [CLSCompliant (false)]
249 unsafe public static ulong ToUInt64 (byte[] value, int startIndex)
251 ulong ret;
253 PutBytes ((byte *) &ret, value, startIndex, 8);
255 return ret;
258 unsafe public static float ToSingle (byte[] value, int startIndex)
260 float ret;
262 PutBytes ((byte *) &ret, value, startIndex, 4);
264 return ret;
267 unsafe public static double ToDouble (byte[] value, int startIndex)
269 double ret;
271 if (SwappedWordsInDouble) {
272 byte* p = (byte*)&ret;
273 if (value == null)
274 throw new ArgumentNullException ("value");
276 if (startIndex < 0 || (startIndex > value.Length - 1))
277 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
278 + " out of range. Must be non-negative and less than the"
279 + " size of the collection.");
281 // avoid integer overflow (with large pos/neg start_index values)
282 if (value.Length - 8 < startIndex)
283 throw new ArgumentException ("Destination array is not long"
284 + " enough to copy all the items in the collection."
285 + " Check array index and length.");
287 p [0] = value [startIndex + 4];
288 p [1] = value [startIndex + 5];
289 p [2] = value [startIndex + 6];
290 p [3] = value [startIndex + 7];
291 p [4] = value [startIndex + 0];
292 p [5] = value [startIndex + 1];
293 p [6] = value [startIndex + 2];
294 p [7] = value [startIndex + 3];
296 return ret;
299 PutBytes ((byte *) &ret, value, startIndex, 8);
301 return ret;
304 unsafe internal static double SwappableToDouble (byte[] value, int startIndex)
306 double ret;
308 if (SwappedWordsInDouble) {
309 byte* p = (byte*)&ret;
310 if (value == null)
311 throw new ArgumentNullException ("value");
313 if (startIndex < 0 || (startIndex > value.Length - 1))
314 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
315 + " out of range. Must be non-negative and less than the"
316 + " size of the collection.");
318 // avoid integer overflow (with large pos/neg start_index values)
319 if (value.Length - 8 < startIndex)
320 throw new ArgumentException ("Destination array is not long"
321 + " enough to copy all the items in the collection."
322 + " Check array index and length.");
324 p [0] = value [startIndex + 4];
325 p [1] = value [startIndex + 5];
326 p [2] = value [startIndex + 6];
327 p [3] = value [startIndex + 7];
328 p [4] = value [startIndex + 0];
329 p [5] = value [startIndex + 1];
330 p [6] = value [startIndex + 2];
331 p [7] = value [startIndex + 3];
333 return ret;
334 } else if (!IsLittleEndian) {
335 byte* p = (byte*)&ret;
336 if (value == null)
337 throw new ArgumentNullException ("value");
339 if (startIndex < 0 || (startIndex > value.Length - 1))
340 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
341 + " out of range. Must be non-negative and less than the"
342 + " size of the collection.");
344 // avoid integer overflow (with large pos/neg start_index values)
345 if (value.Length - 8 < startIndex)
346 throw new ArgumentException ("Destination array is not long"
347 + " enough to copy all the items in the collection."
348 + " Check array index and length.");
350 p [0] = value [startIndex + 7];
351 p [1] = value [startIndex + 6];
352 p [2] = value [startIndex + 5];
353 p [3] = value [startIndex + 4];
354 p [4] = value [startIndex + 3];
355 p [5] = value [startIndex + 2];
356 p [6] = value [startIndex + 1];
357 p [7] = value [startIndex + 0];
359 return ret;
362 PutBytes ((byte *) &ret, value, startIndex, 8);
364 return ret;
367 public static string ToString (byte[] value)
369 if (value == null)
370 throw new ArgumentNullException ("value");
372 return ToString (value, 0, value.Length);
375 public static string ToString (byte[] value, int startIndex)
377 if (value == null)
378 throw new ArgumentNullException ("value");
380 return ToString (value, startIndex, value.Length - startIndex);
383 public static string ToString (byte[] value, int startIndex, int length)
385 if (value == null)
386 throw new ArgumentNullException ("byteArray");
388 // The 4th and last clause (start_index >= value.Length)
389 // was added as a small fix to a very obscure bug.
390 // It makes a small difference when start_index is
391 // outside the range and length==0.
392 if (startIndex < 0 || startIndex >= value.Length) {
393 // special (but valid) case (e.g. new byte [0])
394 if ((startIndex == 0) && (value.Length == 0))
395 return String.Empty;
396 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
397 + " out of range. Must be non-negative and less than the"
398 + " size of the collection.");
401 if (length < 0)
402 throw new ArgumentOutOfRangeException ("length",
403 "Value must be positive.");
405 // note: re-ordered to avoid possible integer overflow
406 if (startIndex > value.Length - length)
407 throw new ArgumentException ("startIndex + length > value.Length");
409 if (length == 0)
410 return string.Empty;
412 StringBuilder builder = new StringBuilder(length * 3 - 1);
413 int end = startIndex + length;
415 for (int i = startIndex; i < end; i++) {
416 if (i > startIndex)
417 builder.Append('-');
419 char high = (char)((value[i] >> 4) & 0x0f);
420 char low = (char)(value[i] & 0x0f);
422 if (high < 10)
423 high += '0';
424 else {
425 high -= (char) 10;
426 high += 'A';
429 if (low < 10)
430 low += '0';
431 else {
432 low -= (char) 10;
433 low += 'A';
435 builder.Append(high);
436 builder.Append(low);
439 return builder.ToString ();