2 // System.BitConverter.cs
5 // Matt Kimball (matt@kimball.net)
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
43 private BitConverter ()
48 static readonly bool SwappedWordsInDouble = DoubleWordsAreSwapped ();
49 public static readonly bool IsLittleEndian = AmILittleEndian ();
51 static unsafe bool AmILittleEndian ()
53 // binary representations of 1.0:
54 // big endian: 3f f0 00 00 00 00 00 00
55 // little endian: 00 00 00 00 00 00 f0 3f
56 // arm fpa little endian: 00 00 f0 3f 00 00 00 00
62 static unsafe bool DoubleWordsAreSwapped ()
64 // binary representations of 1.0:
65 // big endian: 3f f0 00 00 00 00 00 00
66 // little endian: 00 00 00 00 00 00 f0 3f
67 // arm fpa little endian: 00 00 f0 3f 00 00 00 00
73 public static long DoubleToInt64Bits (double value)
75 return ToInt64 (GetBytes (value), 0);
78 public static double Int64BitsToDouble (long value)
80 return ToDouble (GetBytes (value), 0);
83 internal static double InternalInt64BitsToDouble (long value)
85 return SwappableToDouble (GetBytes (value), 0);
88 unsafe static byte[] GetBytes (byte *ptr, int count)
90 byte [] ret = new byte [count];
92 for (int i = 0; i < count; i++) {
99 unsafe public static byte[] GetBytes (bool value)
101 return GetBytes ((byte *) &value, 1);
104 unsafe public static byte[] GetBytes (char value)
106 return GetBytes ((byte *) &value, 2);
109 unsafe public static byte[] GetBytes (short value)
111 return GetBytes ((byte *) &value, 2);
114 unsafe public static byte[] GetBytes (int value)
116 return GetBytes ((byte *) &value, 4);
119 unsafe public static byte[] GetBytes (long value)
121 return GetBytes ((byte *) &value, 8);
124 [CLSCompliant (false)]
125 unsafe public static byte[] GetBytes (ushort value)
127 return GetBytes ((byte *) &value, 2);
130 [CLSCompliant (false)]
131 unsafe public static byte[] GetBytes (uint value)
133 return GetBytes ((byte *) &value, 4);
136 [CLSCompliant (false)]
137 unsafe public static byte[] GetBytes (ulong value)
139 return GetBytes ((byte *) &value, 8);
142 unsafe public static byte[] GetBytes (float value)
144 return GetBytes ((byte *) &value, 4);
147 unsafe public static byte[] GetBytes (double value)
149 if (SwappedWordsInDouble) {
150 byte[] data = new byte [8];
151 byte *p = (byte*)&value;
162 return GetBytes ((byte *) &value, 8);
166 unsafe static void PutBytes (byte *dst, byte[] src, int start_index, int count)
170 throw new ArgumentNullException ("value");
172 throw new ArgumentNullException ("byteArray");
175 if (start_index < 0 || (start_index > src.Length - 1))
176 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
177 + " out of range. Must be non-negative and less than the"
178 + " size of the collection.");
180 // avoid integer overflow (with large pos/neg start_index values)
181 if (src.Length - count < start_index)
182 throw new ArgumentException ("Destination array is not long"
183 + " enough to copy all the items in the collection."
184 + " Check array index and length.");
186 for (int i = 0; i < count; i++)
187 dst[i] = src[i + start_index];
190 unsafe public static bool ToBoolean (byte[] value, int startIndex)
193 throw new ArgumentNullException ("value");
195 if (startIndex < 0 || (startIndex > value.Length - 1))
196 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
197 + " out of range. Must be non-negative and less than the"
198 + " size of the collection.");
200 if (value [startIndex] != 0)
206 unsafe public static char ToChar (byte[] value, int startIndex)
210 PutBytes ((byte *) &ret, value, startIndex, 2);
215 unsafe public static short ToInt16 (byte[] value, int startIndex)
219 PutBytes ((byte *) &ret, value, startIndex, 2);
224 unsafe public static int ToInt32 (byte[] value, int startIndex)
228 PutBytes ((byte *) &ret, value, startIndex, 4);
233 unsafe public static long ToInt64 (byte[] value, int startIndex)
237 PutBytes ((byte *) &ret, value, startIndex, 8);
242 [CLSCompliant (false)]
243 unsafe public static ushort ToUInt16 (byte[] value, int startIndex)
247 PutBytes ((byte *) &ret, value, startIndex, 2);
252 [CLSCompliant (false)]
253 unsafe public static uint ToUInt32 (byte[] value, int startIndex)
257 PutBytes ((byte *) &ret, value, startIndex, 4);
262 [CLSCompliant (false)]
263 unsafe public static ulong ToUInt64 (byte[] value, int startIndex)
267 PutBytes ((byte *) &ret, value, startIndex, 8);
272 unsafe public static float ToSingle (byte[] value, int startIndex)
276 PutBytes ((byte *) &ret, value, startIndex, 4);
281 unsafe public static double ToDouble (byte[] value, int startIndex)
285 if (SwappedWordsInDouble) {
286 byte* p = (byte*)&ret;
288 throw new ArgumentNullException ("value");
290 if (startIndex < 0 || (startIndex > value.Length - 1))
291 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
292 + " out of range. Must be non-negative and less than the"
293 + " size of the collection.");
295 // avoid integer overflow (with large pos/neg start_index values)
296 if (value.Length - 8 < startIndex)
297 throw new ArgumentException ("Destination array is not long"
298 + " enough to copy all the items in the collection."
299 + " Check array index and length.");
301 p [0] = value [startIndex + 4];
302 p [1] = value [startIndex + 5];
303 p [2] = value [startIndex + 6];
304 p [3] = value [startIndex + 7];
305 p [4] = value [startIndex + 0];
306 p [5] = value [startIndex + 1];
307 p [6] = value [startIndex + 2];
308 p [7] = value [startIndex + 3];
313 PutBytes ((byte *) &ret, value, startIndex, 8);
318 unsafe internal static double SwappableToDouble (byte[] value, int startIndex)
322 if (SwappedWordsInDouble) {
323 byte* p = (byte*)&ret;
325 throw new ArgumentNullException ("value");
327 if (startIndex < 0 || (startIndex > value.Length - 1))
328 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
329 + " out of range. Must be non-negative and less than the"
330 + " size of the collection.");
332 // avoid integer overflow (with large pos/neg start_index values)
333 if (value.Length - 8 < startIndex)
334 throw new ArgumentException ("Destination array is not long"
335 + " enough to copy all the items in the collection."
336 + " Check array index and length.");
338 p [0] = value [startIndex + 4];
339 p [1] = value [startIndex + 5];
340 p [2] = value [startIndex + 6];
341 p [3] = value [startIndex + 7];
342 p [4] = value [startIndex + 0];
343 p [5] = value [startIndex + 1];
344 p [6] = value [startIndex + 2];
345 p [7] = value [startIndex + 3];
348 } else if (!IsLittleEndian) {
349 byte* p = (byte*)&ret;
351 throw new ArgumentNullException ("value");
353 if (startIndex < 0 || (startIndex > value.Length - 1))
354 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
355 + " out of range. Must be non-negative and less than the"
356 + " size of the collection.");
358 // avoid integer overflow (with large pos/neg start_index values)
359 if (value.Length - 8 < startIndex)
360 throw new ArgumentException ("Destination array is not long"
361 + " enough to copy all the items in the collection."
362 + " Check array index and length.");
364 p [0] = value [startIndex + 7];
365 p [1] = value [startIndex + 6];
366 p [2] = value [startIndex + 5];
367 p [3] = value [startIndex + 4];
368 p [4] = value [startIndex + 3];
369 p [5] = value [startIndex + 2];
370 p [6] = value [startIndex + 1];
371 p [7] = value [startIndex + 0];
376 PutBytes ((byte *) &ret, value, startIndex, 8);
381 public static string ToString (byte[] value)
384 throw new ArgumentNullException ("value");
386 return ToString (value, 0, value.Length);
389 public static string ToString (byte[] value, int startIndex)
392 throw new ArgumentNullException ("value");
394 return ToString (value, startIndex, value.Length - startIndex);
397 public static string ToString (byte[] value, int startIndex, int length)
400 throw new ArgumentNullException ("byteArray");
402 // The 4th and last clause (start_index >= value.Length)
403 // was added as a small fix to a very obscure bug.
404 // It makes a small difference when start_index is
405 // outside the range and length==0.
406 if (startIndex < 0 || startIndex >= value.Length) {
408 // special (but valid) case (e.g. new byte [0])
409 if ((startIndex == 0) && (value.Length == 0))
412 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
413 + " out of range. Must be non-negative and less than the"
414 + " size of the collection.");
418 throw new ArgumentOutOfRangeException ("length",
419 "Value must be positive.");
421 // note: re-ordered to avoid possible integer overflow
422 if (startIndex > value.Length - length)
423 throw new ArgumentException ("startIndex + length > value.Length");
428 StringBuilder builder = new StringBuilder(length * 3 - 1);
429 int end = startIndex + length;
431 for (int i = startIndex; i < end; i++) {
435 char high = (char)((value[i] >> 4) & 0x0f);
436 char low = (char)(value[i] & 0x0f);
451 builder.Append(high);
455 return builder.ToString ();