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.
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
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
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
++) {
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;
152 return GetBytes ((byte *) &value, 8);
156 unsafe static void PutBytes (byte *dst
, byte[] src
, int start_index
, int count
)
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
)
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)
192 unsafe public static char ToChar (byte[] value, int startIndex
)
196 PutBytes ((byte *) &ret
, value, startIndex
, 2);
201 unsafe public static short ToInt16 (byte[] value, int startIndex
)
205 PutBytes ((byte *) &ret
, value, startIndex
, 2);
210 unsafe public static int ToInt32 (byte[] value, int startIndex
)
214 PutBytes ((byte *) &ret
, value, startIndex
, 4);
219 unsafe public static long ToInt64 (byte[] value, int startIndex
)
223 PutBytes ((byte *) &ret
, value, startIndex
, 8);
228 [CLSCompliant (false)]
229 unsafe public static ushort ToUInt16 (byte[] value, int startIndex
)
233 PutBytes ((byte *) &ret
, value, startIndex
, 2);
238 [CLSCompliant (false)]
239 unsafe public static uint ToUInt32 (byte[] value, int startIndex
)
243 PutBytes ((byte *) &ret
, value, startIndex
, 4);
248 [CLSCompliant (false)]
249 unsafe public static ulong ToUInt64 (byte[] value, int startIndex
)
253 PutBytes ((byte *) &ret
, value, startIndex
, 8);
258 unsafe public static float ToSingle (byte[] value, int startIndex
)
262 PutBytes ((byte *) &ret
, value, startIndex
, 4);
267 unsafe public static double ToDouble (byte[] value, int startIndex
)
271 if (SwappedWordsInDouble
) {
272 byte* p
= (byte*)&ret
;
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];
299 PutBytes ((byte *) &ret
, value, startIndex
, 8);
304 unsafe internal static double SwappableToDouble (byte[] value, int startIndex
)
308 if (SwappedWordsInDouble
) {
309 byte* p
= (byte*)&ret
;
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];
334 } else if (!IsLittleEndian
) {
335 byte* p
= (byte*)&ret
;
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];
362 PutBytes ((byte *) &ret
, value, startIndex
, 8);
367 public static string ToString (byte[] value)
370 throw new ArgumentNullException ("value");
372 return ToString (value, 0, value.Length
);
375 public static string ToString (byte[] value, int startIndex
)
378 throw new ArgumentNullException ("value");
380 return ToString (value, startIndex
, value.Length
- startIndex
);
383 public static string ToString (byte[] value, int startIndex
, int length
)
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))
396 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
397 + " out of range. Must be non-negative and less than the"
398 + " size of the collection.");
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");
412 StringBuilder builder
= new StringBuilder(length
* 3 - 1);
413 int end
= startIndex
+ length
;
415 for (int i
= startIndex
; i
< end
; i
++) {
419 char high
= (char)((value[i
] >> 4) & 0x0f);
420 char low
= (char)(value[i
] & 0x0f);
435 builder
.Append(high
);
439 return builder
.ToString ();