2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / corlib / Mono / DataConverter.cs
bloba60337aebe5d3111042f4b90e3433eec0f20698c
1 //
2 // Authors:
3 // Miguel de Icaza (miguel@novell.com)
4 //
5 // See the following url for documentation:
6 // http://www.mono-project.com/Mono_DataConvert
7 //
8 // Compilation Options:
9 // MONO_DATACONVERTER_PUBLIC:
10 // Makes the class public instead of the default internal.
12 // MONO_DATACONVERTER_STATIC_METHODS:
13 // Exposes the public static methods.
15 // TODO:
16 // Support for "DoubleWordsAreSwapped" for ARM devices
18 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
27 //
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
30 //
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System;
40 using System.Collections;
41 using System.Text;
43 #pragma warning disable 3021
45 namespace Mono {
47 #if MONO_DATACONVERTER_PUBLIC
48 unsafe public abstract class DataConverter {
49 #else
50 unsafe internal abstract class DataConverter {
52 // Disables the warning: CLS compliance checking will not be performed on
53 // `XXXX' because it is not visible from outside this assembly
54 #pragma warning disable 3019
55 #endif
56 static DataConverter SwapConv = new SwapConverter ();
57 static DataConverter CopyConv = new CopyConverter ();
59 public static readonly bool IsLittleEndian = BitConverter.IsLittleEndian;
61 public abstract double GetDouble (byte [] data, int index);
62 public abstract float GetFloat (byte [] data, int index);
63 public abstract long GetInt64 (byte [] data, int index);
64 public abstract int GetInt32 (byte [] data, int index);
66 public abstract short GetInt16 (byte [] data, int index);
68 [CLSCompliant (false)]
69 public abstract uint GetUInt32 (byte [] data, int index);
70 [CLSCompliant (false)]
71 public abstract ushort GetUInt16 (byte [] data, int index);
72 [CLSCompliant (false)]
73 public abstract ulong GetUInt64 (byte [] data, int index);
75 public abstract void PutBytes (byte [] dest, int destIdx, double value);
76 public abstract void PutBytes (byte [] dest, int destIdx, float value);
77 public abstract void PutBytes (byte [] dest, int destIdx, int value);
78 public abstract void PutBytes (byte [] dest, int destIdx, long value);
79 public abstract void PutBytes (byte [] dest, int destIdx, short value);
81 [CLSCompliant (false)]
82 public abstract void PutBytes (byte [] dest, int destIdx, ushort value);
83 [CLSCompliant (false)]
84 public abstract void PutBytes (byte [] dest, int destIdx, uint value);
85 [CLSCompliant (false)]
86 public abstract void PutBytes (byte [] dest, int destIdx, ulong value);
88 public byte[] GetBytes (double value)
90 byte [] ret = new byte [8];
91 PutBytes (ret, 0, value);
92 return ret;
95 public byte[] GetBytes (float value)
97 byte [] ret = new byte [4];
98 PutBytes (ret, 0, value);
99 return ret;
102 public byte[] GetBytes (int value)
104 byte [] ret = new byte [4];
105 PutBytes (ret, 0, value);
106 return ret;
109 public byte[] GetBytes (long value)
111 byte [] ret = new byte [8];
112 PutBytes (ret, 0, value);
113 return ret;
116 public byte[] GetBytes (short value)
118 byte [] ret = new byte [2];
119 PutBytes (ret, 0, value);
120 return ret;
123 [CLSCompliant (false)]
124 public byte[] GetBytes (ushort value)
126 byte [] ret = new byte [2];
127 PutBytes (ret, 0, value);
128 return ret;
131 [CLSCompliant (false)]
132 public byte[] GetBytes (uint value)
134 byte [] ret = new byte [4];
135 PutBytes (ret, 0, value);
136 return ret;
139 [CLSCompliant (false)]
140 public byte[] GetBytes (ulong value)
142 byte [] ret = new byte [8];
143 PutBytes (ret, 0, value);
144 return ret;
147 static public DataConverter LittleEndian {
148 get {
149 return BitConverter.IsLittleEndian ? CopyConv : SwapConv;
153 static public DataConverter BigEndian {
154 get {
155 return BitConverter.IsLittleEndian ? SwapConv : CopyConv;
159 static public DataConverter Native {
160 get {
161 return CopyConv;
165 static int Align (int current, int align)
167 return ((current + align - 1) / align) * align;
170 class PackContext {
171 // Buffer
172 public byte [] buffer;
173 int next;
175 public string description;
176 public int i; // position in the description
177 public DataConverter conv;
178 public int repeat;
181 // if align == -1, auto align to the size of the byte array
182 // if align == 0, do not do alignment
183 // Any other values aligns to that particular size
185 public int align;
187 public void Add (byte [] group)
189 //Console.WriteLine ("Adding {0} bytes to {1} (next={2}", group.Length,
190 // buffer == null ? "null" : buffer.Length.ToString (), next);
192 if (buffer == null){
193 buffer = group;
194 next = group.Length;
195 return;
197 if (align != 0){
198 if (align == -1)
199 next = Align (next, group.Length);
200 else
201 next = Align (next, align);
202 align = 0;
205 if (next + group.Length > buffer.Length){
206 byte [] nb = new byte [System.Math.Max (next, 16) * 2 + group.Length];
207 Array.Copy (buffer, nb, buffer.Length);
208 Array.Copy (group, 0, nb, next, group.Length);
209 next = next + group.Length;
210 buffer = nb;
211 } else {
212 Array.Copy (group, 0, buffer, next, group.Length);
213 next += group.Length;
217 public byte [] Get ()
219 if (buffer == null)
220 return new byte [0];
222 if (buffer.Length != next){
223 byte [] b = new byte [next];
224 Array.Copy (buffer, b, next);
225 return b;
227 return buffer;
232 // Format includes:
233 // Control:
234 // ^ Switch to big endian encoding
235 // _ Switch to little endian encoding
236 // % Switch to host (native) encoding
237 // ! aligns the next data type to its natural boundary (for strings this is 4).
239 // Types:
240 // s Int16
241 // S UInt16
242 // i Int32
243 // I UInt32
244 // l Int64
245 // L UInt64
246 // f float
247 // d double
248 // b byte
249 // c 1-byte signed character
250 // C 1-byte unsigned character
251 // z8 string encoded as UTF8 with 1-byte null terminator
252 // z6 string encoded as UTF16 with 2-byte null terminator
253 // z7 string encoded as UTF7 with 1-byte null terminator
254 // zb string encoded as BigEndianUnicode with 2-byte null terminator
255 // z3 string encoded as UTF32 with 4-byte null terminator
256 // z4 string encoded as UTF32 big endian with 4-byte null terminator
257 // $8 string encoded as UTF8
258 // $6 string encoded as UTF16
259 // $7 string encoded as UTF7
260 // $b string encoded as BigEndianUnicode
261 // $3 string encoded as UTF32
262 // $4 string encoded as UTF-32 big endian encoding
263 // x null byte
265 // Repeats, these are prefixes:
266 // N a number between 1 and 9, indicates a repeat count (process N items
267 // with the following datatype
268 // [N] For numbers larger than 9, use brackets, for example [20]
269 // * Repeat the next data type until the arguments are exhausted
271 static public byte [] Pack (string description, params object [] args)
273 int argn = 0;
274 PackContext b = new PackContext ();
275 b.conv = CopyConv;
276 b.description = description;
278 for (b.i = 0; b.i < description.Length; ){
279 object oarg;
281 if (argn < args.Length)
282 oarg = args [argn];
283 else {
284 if (b.repeat != 0)
285 break;
287 oarg = null;
290 int save = b.i;
292 if (PackOne (b, oarg)){
293 argn++;
294 if (b.repeat > 0){
295 if (--b.repeat > 0)
296 b.i = save;
297 else
298 b.i++;
299 } else
300 b.i++;
301 } else
302 b.i++;
304 return b.Get ();
307 static public byte [] PackEnumerable (string description, IEnumerable args)
309 PackContext b = new PackContext ();
310 b.conv = CopyConv;
311 b.description = description;
313 IEnumerator enumerator = args.GetEnumerator ();
314 bool ok = enumerator.MoveNext ();
316 for (b.i = 0; b.i < description.Length; ){
317 object oarg;
319 if (ok)
320 oarg = enumerator.Current;
321 else {
322 if (b.repeat != 0)
323 break;
324 oarg = null;
327 int save = b.i;
329 if (PackOne (b, oarg)){
330 ok = enumerator.MoveNext ();
331 if (b.repeat > 0){
332 if (--b.repeat > 0)
333 b.i = save;
334 else
335 b.i++;
336 } else
337 b.i++;
338 } else
339 b.i++;
341 return b.Get ();
345 // Packs one datum `oarg' into the buffer `b', using the string format
346 // in `description' at position `i'
348 // Returns: true if we must pick the next object from the list
350 static bool PackOne (PackContext b, object oarg)
352 int n;
354 switch (b.description [b.i]){
355 case '^':
356 b.conv = BigEndian;
357 return false;
358 case '_':
359 b.conv = LittleEndian;
360 return false;
361 case '%':
362 b.conv = Native;
363 return false;
365 case '!':
366 b.align = -1;
367 return false;
369 case 'x':
370 b.Add (new byte [] { 0 });
371 return false;
373 // Type Conversions
374 case 'i':
375 b.Add (b.conv.GetBytes (Convert.ToInt32 (oarg)));
376 break;
378 case 'I':
379 b.Add (b.conv.GetBytes (Convert.ToUInt32 (oarg)));
380 break;
382 case 's':
383 b.Add (b.conv.GetBytes (Convert.ToInt16 (oarg)));
384 break;
386 case 'S':
387 b.Add (b.conv.GetBytes (Convert.ToUInt16 (oarg)));
388 break;
390 case 'l':
391 b.Add (b.conv.GetBytes (Convert.ToInt64 (oarg)));
392 break;
394 case 'L':
395 b.Add (b.conv.GetBytes (Convert.ToUInt64 (oarg)));
396 break;
398 case 'f':
399 b.Add (b.conv.GetBytes (Convert.ToSingle (oarg)));
400 break;
402 case 'd':
403 b.Add (b.conv.GetBytes (Convert.ToDouble (oarg)));
404 break;
406 case 'b':
407 b.Add (new byte [] { Convert.ToByte (oarg) });
408 break;
410 case 'c':
411 b.Add (new byte [] { (byte) (Convert.ToSByte (oarg)) });
412 break;
414 case 'C':
415 b.Add (new byte [] { Convert.ToByte (oarg) });
416 break;
418 // Repeat acount;
419 case '1': case '2': case '3': case '4': case '5':
420 case '6': case '7': case '8': case '9':
421 b.repeat = ((short) b.description [b.i]) - ((short) '0');
422 return false;
424 case '*':
425 b.repeat = Int32.MaxValue;
426 return false;
428 case '[':
429 int count = -1, j;
431 for (j = b.i+1; j < b.description.Length; j++){
432 if (b.description [j] == ']')
433 break;
434 n = ((short) b.description [j]) - ((short) '0');
435 if (n >= 0 && n <= 9){
436 if (count == -1)
437 count = n;
438 else
439 count = count * 10 + n;
442 if (count == -1)
443 throw new ArgumentException ("invalid size specification");
444 b.i = j;
445 b.repeat = count;
446 return false;
448 case '$': case 'z':
449 bool add_null = b.description [b.i] == 'z';
450 b.i++;
451 if (b.i >= b.description.Length)
452 throw new ArgumentException ("$ description needs a type specified", "description");
453 char d = b.description [b.i];
454 Encoding e;
456 switch (d){
457 case '8':
458 e = Encoding.UTF8;
459 n = 1;
460 break;
461 case '6':
462 e = Encoding.Unicode;
463 n = 2;
464 break;
465 case '7':
466 e = Encoding.UTF7;
467 n = 1;
468 break;
469 case 'b':
470 e = Encoding.BigEndianUnicode;
471 n = 2;
472 break;
473 case '3':
474 e = Encoding.GetEncoding (12000);
475 n = 4;
476 break;
477 case '4':
478 e = Encoding.GetEncoding (12001);
479 n = 4;
480 break;
482 default:
483 throw new ArgumentException ("Invalid format for $ specifier", "description");
485 if (b.align == -1)
486 b.align = 4;
487 b.Add (e.GetBytes (Convert.ToString (oarg)));
488 if (add_null)
489 b.Add (new byte [n]);
490 break;
491 default:
492 throw new ArgumentException (String.Format ("invalid format specified `{0}'",
493 b.description [b.i]));
495 return true;
498 static bool Prepare (byte [] buffer, ref int idx, int size, ref bool align)
500 if (align){
501 idx = Align (idx, size);
502 align = false;
504 if (idx + size > buffer.Length){
505 idx = buffer.Length;
506 return false;
508 return true;
511 static public IList Unpack (string description, byte [] buffer, int startIndex)
513 DataConverter conv = CopyConv;
514 ArrayList result = new ArrayList ();
515 int idx = startIndex;
516 bool align = false;
517 int repeat = 0, n;
519 for (int i = 0; i < description.Length && idx < buffer.Length; ){
520 int save = i;
522 switch (description [i]){
523 case '^':
524 conv = BigEndian;
525 break;
526 case '_':
527 conv = LittleEndian;
528 break;
529 case '%':
530 conv = Native;
531 break;
532 case 'x':
533 idx++;
534 break;
536 case '!':
537 align = true;
538 break;
540 // Type Conversions
541 case 'i':
542 if (Prepare (buffer, ref idx, 4, ref align)){
543 result.Add (conv.GetInt32 (buffer, idx));
544 idx += 4;
546 break;
548 case 'I':
549 if (Prepare (buffer, ref idx, 4, ref align)){
550 result.Add (conv.GetUInt32 (buffer, idx));
551 idx += 4;
553 break;
555 case 's':
556 if (Prepare (buffer, ref idx, 2, ref align)){
557 result.Add (conv.GetInt16 (buffer, idx));
558 idx += 2;
560 break;
562 case 'S':
563 if (Prepare (buffer, ref idx, 2, ref align)){
564 result.Add (conv.GetUInt16 (buffer, idx));
565 idx += 2;
567 break;
569 case 'l':
570 if (Prepare (buffer, ref idx, 8, ref align)){
571 result.Add (conv.GetInt64 (buffer, idx));
572 idx += 8;
574 break;
576 case 'L':
577 if (Prepare (buffer, ref idx, 8, ref align)){
578 result.Add (conv.GetUInt64 (buffer, idx));
579 idx += 8;
581 break;
583 case 'f':
584 if (Prepare (buffer, ref idx, 4, ref align)){
585 result.Add (conv.GetDouble (buffer, idx));
586 idx += 4;
588 break;
590 case 'd':
591 if (Prepare (buffer, ref idx, 8, ref align)){
592 result.Add (conv.GetDouble (buffer, idx));
593 idx += 8;
595 break;
597 case 'b':
598 if (Prepare (buffer, ref idx, 1, ref align)){
599 result.Add (buffer [idx]);
600 idx++;
602 break;
604 case 'c': case 'C':
605 if (Prepare (buffer, ref idx, 1, ref align)){
606 char c;
608 if (description [i] == 'c')
609 c = ((char) ((sbyte)buffer [idx]));
610 else
611 c = ((char) ((byte)buffer [idx]));
613 result.Add (c);
614 idx++;
616 break;
618 // Repeat acount;
619 case '1': case '2': case '3': case '4': case '5':
620 case '6': case '7': case '8': case '9':
621 repeat = ((short) description [i]) - ((short) '0');
622 save = i + 1;
623 break;
625 case '*':
626 repeat = Int32.MaxValue;
627 break;
629 case '[':
630 int count = -1, j;
632 for (j = i+1; j < description.Length; j++){
633 if (description [j] == ']')
634 break;
635 n = ((short) description [j]) - ((short) '0');
636 if (n >= 0 && n <= 9){
637 if (count == -1)
638 count = n;
639 else
640 count = count * 10 + n;
643 if (count == -1)
644 throw new ArgumentException ("invalid size specification");
645 i = j;
646 save = i + 1;
647 repeat = count;
648 break;
650 case '$': case 'z':
651 // bool with_null = description [i] == 'z';
652 i++;
653 if (i >= description.Length)
654 throw new ArgumentException ("$ description needs a type specified", "description");
655 char d = description [i];
656 Encoding e;
657 if (align){
658 idx = Align (idx, 4);
659 align = false;
661 if (idx >= buffer.Length)
662 break;
664 switch (d){
665 case '8':
666 e = Encoding.UTF8;
667 n = 1;
668 break;
669 case '6':
670 e = Encoding.Unicode;
671 n = 2;
672 break;
673 case '7':
674 e = Encoding.UTF7;
675 n = 1;
676 break;
677 case 'b':
678 e = Encoding.BigEndianUnicode;
679 n = 2;
680 break;
681 case '3':
682 e = Encoding.GetEncoding (12000);
683 n = 4;
684 break;
685 case '4':
686 e = Encoding.GetEncoding (12001);
687 n = 4;
688 break;
690 default:
691 throw new ArgumentException ("Invalid format for $ specifier", "description");
693 int k = idx;
694 switch (n){
695 case 1:
696 for (; k < buffer.Length && buffer [k] != 0; k++)
698 result.Add (e.GetChars (buffer, idx, k-idx));
699 if (k == buffer.Length)
700 idx = k;
701 else
702 idx = k+1;
703 break;
705 case 2:
706 for (; k < buffer.Length; k++){
707 if (k+1 == buffer.Length){
708 k++;
709 break;
711 if (buffer [k] == 0 && buffer [k+1] == 0)
712 break;
714 result.Add (e.GetChars (buffer, idx, k-idx));
715 if (k == buffer.Length)
716 idx = k;
717 else
718 idx = k+2;
719 break;
721 case 4:
722 for (; k < buffer.Length; k++){
723 if (k+3 >= buffer.Length){
724 k = buffer.Length;
725 break;
727 if (buffer[k]==0 && buffer[k+1] == 0 && buffer[k+2] == 0 && buffer[k+3]== 0)
728 break;
730 result.Add (e.GetChars (buffer, idx, k-idx));
731 if (k == buffer.Length)
732 idx = k;
733 else
734 idx = k+4;
735 break;
737 break;
738 default:
739 throw new ArgumentException (String.Format ("invalid format specified `{0}'",
740 description [i]));
743 if (repeat > 0){
744 if (--repeat > 0)
745 i = save;
746 } else
747 i++;
749 return result;
752 internal void Check (byte [] dest, int destIdx, int size)
754 if (dest == null)
755 throw new ArgumentNullException ("dest");
756 if (destIdx < 0 || destIdx > dest.Length - size)
757 throw new ArgumentException ("destIdx");
760 class CopyConverter : DataConverter {
761 public override double GetDouble (byte [] data, int index)
763 if (data == null)
764 throw new ArgumentNullException ("data");
765 if (data.Length - index < 8)
766 throw new ArgumentException ("index");
767 if (index < 0)
768 throw new ArgumentException ("index");
769 double ret;
770 byte *b = (byte *)&ret;
772 for (int i = 0; i < 8; i++)
773 b [i] = data [index+i];
775 return ret;
778 public override ulong GetUInt64 (byte [] data, int index)
780 if (data == null)
781 throw new ArgumentNullException ("data");
782 if (data.Length - index < 8)
783 throw new ArgumentException ("index");
784 if (index < 0)
785 throw new ArgumentException ("index");
787 ulong ret;
788 byte *b = (byte *)&ret;
790 for (int i = 0; i < 8; i++)
791 b [i] = data [index+i];
793 return ret;
796 public override long GetInt64 (byte [] data, int index)
798 if (data == null)
799 throw new ArgumentNullException ("data");
800 if (data.Length - index < 8)
801 throw new ArgumentException ("index");
802 if (index < 0)
803 throw new ArgumentException ("index");
805 long ret;
806 byte *b = (byte *)&ret;
808 for (int i = 0; i < 8; i++)
809 b [i] = data [index+i];
811 return ret;
814 public override float GetFloat (byte [] data, int index)
816 if (data == null)
817 throw new ArgumentNullException ("data");
818 if (data.Length - index < 4)
819 throw new ArgumentException ("index");
820 if (index < 0)
821 throw new ArgumentException ("index");
823 float ret;
824 byte *b = (byte *)&ret;
826 for (int i = 0; i < 4; i++)
827 b [i] = data [index+i];
829 return ret;
832 public override int GetInt32 (byte [] data, int index)
834 if (data == null)
835 throw new ArgumentNullException ("data");
836 if (data.Length - index < 4)
837 throw new ArgumentException ("index");
838 if (index < 0)
839 throw new ArgumentException ("index");
841 int ret;
842 byte *b = (byte *)&ret;
844 for (int i = 0; i < 4; i++)
845 b [i] = data [index+i];
847 return ret;
850 public override uint GetUInt32 (byte [] data, int index)
852 if (data == null)
853 throw new ArgumentNullException ("data");
854 if (data.Length - index < 4)
855 throw new ArgumentException ("index");
856 if (index < 0)
857 throw new ArgumentException ("index");
859 uint ret;
860 byte *b = (byte *)&ret;
862 for (int i = 0; i < 4; i++)
863 b [i] = data [index+i];
865 return ret;
868 public override short GetInt16 (byte [] data, int index)
870 if (data == null)
871 throw new ArgumentNullException ("data");
872 if (data.Length - index < 2)
873 throw new ArgumentException ("index");
874 if (index < 0)
875 throw new ArgumentException ("index");
877 short ret;
878 byte *b = (byte *)&ret;
880 for (int i = 0; i < 2; i++)
881 b [i] = data [index+i];
883 return ret;
886 public override ushort GetUInt16 (byte [] data, int index)
888 if (data == null)
889 throw new ArgumentNullException ("data");
890 if (data.Length - index < 2)
891 throw new ArgumentException ("index");
892 if (index < 0)
893 throw new ArgumentException ("index");
895 ushort ret;
896 byte *b = (byte *)&ret;
898 for (int i = 0; i < 2; i++)
899 b [i] = data [index+i];
901 return ret;
904 public override void PutBytes (byte [] dest, int destIdx, double value)
906 Check (dest, destIdx, 8);
907 fixed (byte *target = &dest [destIdx]){
908 long *source = (long *) &value;
910 *((long *)target) = *source;
914 public override void PutBytes (byte [] dest, int destIdx, float value)
916 Check (dest, destIdx, 4);
917 fixed (byte *target = &dest [destIdx]){
918 uint *source = (uint *) &value;
920 *((uint *)target) = *source;
924 public override void PutBytes (byte [] dest, int destIdx, int value)
926 Check (dest, destIdx, 4);
927 fixed (byte *target = &dest [destIdx]){
928 uint *source = (uint *) &value;
930 *((uint *)target) = *source;
934 public override void PutBytes (byte [] dest, int destIdx, uint value)
936 Check (dest, destIdx, 4);
937 fixed (byte *target = &dest [destIdx]){
938 uint *source = (uint *) &value;
940 *((uint *)target) = *source;
944 public override void PutBytes (byte [] dest, int destIdx, long value)
946 Check (dest, destIdx, 8);
947 fixed (byte *target = &dest [destIdx]){
948 long *source = (long *) &value;
950 *((long*)target) = *source;
954 public override void PutBytes (byte [] dest, int destIdx, ulong value)
956 Check (dest, destIdx, 8);
957 fixed (byte *target = &dest [destIdx]){
958 ulong *source = (ulong *) &value;
960 *((ulong *) target) = *source;
964 public override void PutBytes (byte [] dest, int destIdx, short value)
966 Check (dest, destIdx, 2);
967 fixed (byte *target = &dest [destIdx]){
968 ushort *source = (ushort *) &value;
970 *((ushort *)target) = *source;
974 public override void PutBytes (byte [] dest, int destIdx, ushort value)
976 Check (dest, destIdx, 2);
977 fixed (byte *target = &dest [destIdx]){
978 ushort *source = (ushort *) &value;
980 *((ushort *)target) = *source;
985 class SwapConverter : DataConverter {
986 public override double GetDouble (byte [] data, int index)
988 if (data == null)
989 throw new ArgumentNullException ("data");
990 if (data.Length - index < 8)
991 throw new ArgumentException ("index");
992 if (index < 0)
993 throw new ArgumentException ("index");
995 double ret;
996 byte *b = (byte *)&ret;
998 for (int i = 0; i < 8; i++)
999 b [7-i] = data [index+i];
1001 return ret;
1004 public override ulong GetUInt64 (byte [] data, int index)
1006 if (data == null)
1007 throw new ArgumentNullException ("data");
1008 if (data.Length - index < 8)
1009 throw new ArgumentException ("index");
1010 if (index < 0)
1011 throw new ArgumentException ("index");
1013 ulong ret;
1014 byte *b = (byte *)&ret;
1016 for (int i = 0; i < 8; i++)
1017 b [7-i] = data [index+i];
1019 return ret;
1022 public override long GetInt64 (byte [] data, int index)
1024 if (data == null)
1025 throw new ArgumentNullException ("data");
1026 if (data.Length - index < 8)
1027 throw new ArgumentException ("index");
1028 if (index < 0)
1029 throw new ArgumentException ("index");
1031 long ret;
1032 byte *b = (byte *)&ret;
1034 for (int i = 0; i < 8; i++)
1035 b [7-i] = data [index+i];
1037 return ret;
1040 public override float GetFloat (byte [] data, int index)
1042 if (data == null)
1043 throw new ArgumentNullException ("data");
1044 if (data.Length - index < 4)
1045 throw new ArgumentException ("index");
1046 if (index < 0)
1047 throw new ArgumentException ("index");
1049 float ret;
1050 byte *b = (byte *)&ret;
1052 for (int i = 0; i < 4; i++)
1053 b [3-i] = data [index+i];
1055 return ret;
1058 public override int GetInt32 (byte [] data, int index)
1060 if (data == null)
1061 throw new ArgumentNullException ("data");
1062 if (data.Length - index < 4)
1063 throw new ArgumentException ("index");
1064 if (index < 0)
1065 throw new ArgumentException ("index");
1067 int ret;
1068 byte *b = (byte *)&ret;
1070 for (int i = 0; i < 4; i++)
1071 b [3-i] = data [index+i];
1073 return ret;
1076 public override uint GetUInt32 (byte [] data, int index)
1078 if (data == null)
1079 throw new ArgumentNullException ("data");
1080 if (data.Length - index < 4)
1081 throw new ArgumentException ("index");
1082 if (index < 0)
1083 throw new ArgumentException ("index");
1085 uint ret;
1086 byte *b = (byte *)&ret;
1088 for (int i = 0; i < 4; i++)
1089 b [3-i] = data [index+i];
1091 return ret;
1094 public override short GetInt16 (byte [] data, int index)
1096 if (data == null)
1097 throw new ArgumentNullException ("data");
1098 if (data.Length - index < 2)
1099 throw new ArgumentException ("index");
1100 if (index < 0)
1101 throw new ArgumentException ("index");
1103 short ret;
1104 byte *b = (byte *)&ret;
1106 for (int i = 0; i < 2; i++)
1107 b [1-i] = data [index+i];
1109 return ret;
1112 public override ushort GetUInt16 (byte [] data, int index)
1114 if (data == null)
1115 throw new ArgumentNullException ("data");
1116 if (data.Length - index < 2)
1117 throw new ArgumentException ("index");
1118 if (index < 0)
1119 throw new ArgumentException ("index");
1121 ushort ret;
1122 byte *b = (byte *)&ret;
1124 for (int i = 0; i < 2; i++)
1125 b [1-i] = data [index+i];
1127 return ret;
1130 public override void PutBytes (byte [] dest, int destIdx, double value)
1132 Check (dest, destIdx, 8);
1134 fixed (byte *target = &dest [destIdx]){
1135 byte *source = (byte *) &value;
1137 for (int i = 0; i < 8; i++)
1138 target [i] = source [7-i];
1142 public override void PutBytes (byte [] dest, int destIdx, float value)
1144 Check (dest, destIdx, 4);
1146 fixed (byte *target = &dest [destIdx]){
1147 byte *source = (byte *) &value;
1149 for (int i = 0; i < 4; i++)
1150 target [i] = source [3-i];
1154 public override void PutBytes (byte [] dest, int destIdx, int value)
1156 Check (dest, destIdx, 4);
1158 fixed (byte *target = &dest [destIdx]){
1159 byte *source = (byte *) &value;
1161 for (int i = 0; i < 4; i++)
1162 target [i] = source [3-i];
1166 public override void PutBytes (byte [] dest, int destIdx, uint value)
1168 Check (dest, destIdx, 4);
1170 fixed (byte *target = &dest [destIdx]){
1171 byte *source = (byte *) &value;
1173 for (int i = 0; i < 4; i++)
1174 target [i] = source [3-i];
1178 public override void PutBytes (byte [] dest, int destIdx, long value)
1180 Check (dest, destIdx, 8);
1182 fixed (byte *target = &dest [destIdx]){
1183 byte *source = (byte *) &value;
1185 for (int i = 0; i < 8; i++)
1186 target [i] = source [7-i];
1190 public override void PutBytes (byte [] dest, int destIdx, ulong value)
1192 Check (dest, destIdx, 8);
1194 fixed (byte *target = &dest [destIdx]){
1195 byte *source = (byte *) &value;
1197 for (int i = 0; i < 4; i++)
1198 target [i] = source [7-i];
1202 public override void PutBytes (byte [] dest, int destIdx, short value)
1204 Check (dest, destIdx, 2);
1206 fixed (byte *target = &dest [destIdx]){
1207 byte *source = (byte *) &value;
1209 for (int i = 0; i < 2; i++)
1210 target [i] = source [1-i];
1214 public override void PutBytes (byte [] dest, int destIdx, ushort value)
1216 Check (dest, destIdx, 2);
1218 fixed (byte *target = &dest [destIdx]){
1219 byte *source = (byte *) &value;
1221 for (int i = 0; i < 2; i++)
1222 target [i] = source [1-i];
1227 #if MONO_DATACONVERTER_STATIC_METHODS
1228 static unsafe void PutBytesLE (byte *dest, byte *src, int count)
1230 int i = 0;
1232 if (BitConverter.IsLittleEndian){
1233 for (; i < count; i++)
1234 *dest++ = *src++;
1235 } else {
1236 dest += count;
1237 for (; i < count; i++)
1238 *(--dest) = *src++;
1242 static unsafe void PutBytesBE (byte *dest, byte *src, int count)
1244 int i = 0;
1246 if (BitConverter.IsLittleEndian){
1247 dest += count;
1248 for (; i < count; i++)
1249 *(--dest) = *src++;
1250 } else {
1251 for (; i < count; i++)
1252 *dest++ = *src++;
1256 static unsafe void PutBytesNative (byte *dest, byte *src, int count)
1258 int i = 0;
1260 for (; i < count; i++)
1261 dest [i-count] = *src++;
1264 static public unsafe double DoubleFromLE (byte[] data, int index)
1266 if (data == null)
1267 throw new ArgumentNullException ("data");
1268 if (data.Length - index < 8)
1269 throw new ArgumentException ("index");
1270 if (index < 0)
1271 throw new ArgumentException ("index");
1273 double ret;
1274 fixed (byte *src = &data[index]){
1275 PutBytesLE ((byte *) &ret, src, 8);
1277 return ret;
1280 static public unsafe float FloatFromLE (byte [] data, int index)
1282 if (data == null)
1283 throw new ArgumentNullException ("data");
1284 if (data.Length - index < 4)
1285 throw new ArgumentException ("index");
1286 if (index < 0)
1287 throw new ArgumentException ("index");
1289 float ret;
1290 fixed (byte *src = &data[index]){
1291 PutBytesLE ((byte *) &ret, src, 4);
1293 return ret;
1296 static public unsafe long Int64FromLE (byte [] data, int index)
1298 if (data == null)
1299 throw new ArgumentNullException ("data");
1300 if (data.Length - index < 8)
1301 throw new ArgumentException ("index");
1302 if (index < 0)
1303 throw new ArgumentException ("index");
1305 long ret;
1306 fixed (byte *src = &data[index]){
1307 PutBytesLE ((byte *) &ret, src, 8);
1309 return ret;
1312 static public unsafe ulong UInt64FromLE (byte [] data, int index)
1314 if (data == null)
1315 throw new ArgumentNullException ("data");
1316 if (data.Length - index < 8)
1317 throw new ArgumentException ("index");
1318 if (index < 0)
1319 throw new ArgumentException ("index");
1321 ulong ret;
1322 fixed (byte *src = &data[index]){
1323 PutBytesLE ((byte *) &ret, src, 8);
1325 return ret;
1328 static public unsafe int Int32FromLE (byte [] data, int index)
1330 if (data == null)
1331 throw new ArgumentNullException ("data");
1332 if (data.Length - index < 4)
1333 throw new ArgumentException ("index");
1334 if (index < 0)
1335 throw new ArgumentException ("index");
1337 int ret;
1338 fixed (byte *src = &data[index]){
1339 PutBytesLE ((byte *) &ret, src, 4);
1341 return ret;
1344 static public unsafe uint UInt32FromLE (byte [] data, int index)
1346 if (data == null)
1347 throw new ArgumentNullException ("data");
1348 if (data.Length - index < 4)
1349 throw new ArgumentException ("index");
1350 if (index < 0)
1351 throw new ArgumentException ("index");
1353 uint ret;
1354 fixed (byte *src = &data[index]){
1355 PutBytesLE ((byte *) &ret, src, 4);
1357 return ret;
1360 static public unsafe short Int16FromLE (byte [] data, int index)
1362 if (data == null)
1363 throw new ArgumentNullException ("data");
1364 if (data.Length - index < 2)
1365 throw new ArgumentException ("index");
1366 if (index < 0)
1367 throw new ArgumentException ("index");
1369 short ret;
1370 fixed (byte *src = &data[index]){
1371 PutBytesLE ((byte *) &ret, src, 2);
1373 return ret;
1376 static public unsafe ushort UInt16FromLE (byte [] data, int index)
1378 if (data == null)
1379 throw new ArgumentNullException ("data");
1380 if (data.Length - index < 2)
1381 throw new ArgumentException ("index");
1382 if (index < 0)
1383 throw new ArgumentException ("index");
1385 ushort ret;
1386 fixed (byte *src = &data[index]){
1387 PutBytesLE ((byte *) &ret, src, 2);
1389 return ret;
1392 static public unsafe double DoubleFromBE (byte[] data, int index)
1394 if (data == null)
1395 throw new ArgumentNullException ("data");
1396 if (data.Length - index < 8)
1397 throw new ArgumentException ("index");
1398 if (index < 0)
1399 throw new ArgumentException ("index");
1401 double ret;
1402 fixed (byte *src = &data[index]){
1403 PutBytesBE ((byte *) &ret, src, 8);
1405 return ret;
1408 static public unsafe float FloatFromBE (byte [] data, int index)
1410 if (data == null)
1411 throw new ArgumentNullException ("data");
1412 if (data.Length - index < 4)
1413 throw new ArgumentException ("index");
1414 if (index < 0)
1415 throw new ArgumentException ("index");
1417 float ret;
1418 fixed (byte *src = &data[index]){
1419 PutBytesBE ((byte *) &ret, src, 4);
1421 return ret;
1424 static public unsafe long Int64FromBE (byte [] data, int index)
1426 if (data == null)
1427 throw new ArgumentNullException ("data");
1428 if (data.Length - index < 8)
1429 throw new ArgumentException ("index");
1430 if (index < 0)
1431 throw new ArgumentException ("index");
1433 long ret;
1434 fixed (byte *src = &data[index]){
1435 PutBytesBE ((byte *) &ret, src, 8);
1437 return ret;
1440 static public unsafe ulong UInt64FromBE (byte [] data, int index)
1442 if (data == null)
1443 throw new ArgumentNullException ("data");
1444 if (data.Length - index < 8)
1445 throw new ArgumentException ("index");
1446 if (index < 0)
1447 throw new ArgumentException ("index");
1449 ulong ret;
1450 fixed (byte *src = &data[index]){
1451 PutBytesBE ((byte *) &ret, src, 8);
1453 return ret;
1456 static public unsafe int Int32FromBE (byte [] data, int index)
1458 if (data == null)
1459 throw new ArgumentNullException ("data");
1460 if (data.Length - index < 4)
1461 throw new ArgumentException ("index");
1462 if (index < 0)
1463 throw new ArgumentException ("index");
1465 int ret;
1466 fixed (byte *src = &data[index]){
1467 PutBytesBE ((byte *) &ret, src, 4);
1469 return ret;
1472 static public unsafe uint UInt32FromBE (byte [] data, int index)
1474 if (data == null)
1475 throw new ArgumentNullException ("data");
1476 if (data.Length - index < 4)
1477 throw new ArgumentException ("index");
1478 if (index < 0)
1479 throw new ArgumentException ("index");
1481 uint ret;
1482 fixed (byte *src = &data[index]){
1483 PutBytesBE ((byte *) &ret, src, 4);
1485 return ret;
1488 static public unsafe short Int16FromBE (byte [] data, int index)
1490 if (data == null)
1491 throw new ArgumentNullException ("data");
1492 if (data.Length - index < 2)
1493 throw new ArgumentException ("index");
1494 if (index < 0)
1495 throw new ArgumentException ("index");
1497 short ret;
1498 fixed (byte *src = &data[index]){
1499 PutBytesBE ((byte *) &ret, src, 2);
1501 return ret;
1504 static public unsafe ushort UInt16FromBE (byte [] data, int index)
1506 if (data == null)
1507 throw new ArgumentNullException ("data");
1508 if (data.Length - index < 2)
1509 throw new ArgumentException ("index");
1510 if (index < 0)
1511 throw new ArgumentException ("index");
1513 ushort ret;
1514 fixed (byte *src = &data[index]){
1515 PutBytesBE ((byte *) &ret, src, 2);
1517 return ret;
1520 static public unsafe double DoubleFromNative (byte[] data, int index)
1522 if (data == null)
1523 throw new ArgumentNullException ("data");
1524 if (data.Length - index < 8)
1525 throw new ArgumentException ("index");
1526 if (index < 0)
1527 throw new ArgumentException ("index");
1529 double ret;
1530 fixed (byte *src = &data[index]){
1531 PutBytesNative ((byte *) &ret, src, 8);
1533 return ret;
1536 static public unsafe float FloatFromNative (byte [] data, int index)
1538 if (data == null)
1539 throw new ArgumentNullException ("data");
1540 if (data.Length - index < 4)
1541 throw new ArgumentException ("index");
1542 if (index < 0)
1543 throw new ArgumentException ("index");
1545 float ret;
1546 fixed (byte *src = &data[index]){
1547 PutBytesNative ((byte *) &ret, src, 4);
1549 return ret;
1552 static public unsafe long Int64FromNative (byte [] data, int index)
1554 if (data == null)
1555 throw new ArgumentNullException ("data");
1556 if (data.Length - index < 8)
1557 throw new ArgumentException ("index");
1558 if (index < 0)
1559 throw new ArgumentException ("index");
1561 long ret;
1562 fixed (byte *src = &data[index]){
1563 PutBytesNative ((byte *) &ret, src, 8);
1565 return ret;
1568 static public unsafe ulong UInt64FromNative (byte [] data, int index)
1570 if (data == null)
1571 throw new ArgumentNullException ("data");
1572 if (data.Length - index < 8)
1573 throw new ArgumentException ("index");
1574 if (index < 0)
1575 throw new ArgumentException ("index");
1577 ulong ret;
1578 fixed (byte *src = &data[index]){
1579 PutBytesNative ((byte *) &ret, src, 8);
1581 return ret;
1584 static public unsafe int Int32FromNative (byte [] data, int index)
1586 if (data == null)
1587 throw new ArgumentNullException ("data");
1588 if (data.Length - index < 4)
1589 throw new ArgumentException ("index");
1590 if (index < 0)
1591 throw new ArgumentException ("index");
1593 int ret;
1594 fixed (byte *src = &data[index]){
1595 PutBytesNative ((byte *) &ret, src, 4);
1597 return ret;
1600 static public unsafe uint UInt32FromNative (byte [] data, int index)
1602 if (data == null)
1603 throw new ArgumentNullException ("data");
1604 if (data.Length - index < 4)
1605 throw new ArgumentException ("index");
1606 if (index < 0)
1607 throw new ArgumentException ("index");
1609 uint ret;
1610 fixed (byte *src = &data[index]){
1611 PutBytesNative ((byte *) &ret, src, 4);
1613 return ret;
1616 static public unsafe short Int16FromNative (byte [] data, int index)
1618 if (data == null)
1619 throw new ArgumentNullException ("data");
1620 if (data.Length - index < 2)
1621 throw new ArgumentException ("index");
1622 if (index < 0)
1623 throw new ArgumentException ("index");
1625 short ret;
1626 fixed (byte *src = &data[index]){
1627 PutBytesNative ((byte *) &ret, src, 2);
1629 return ret;
1632 static public unsafe ushort UInt16FromNative (byte [] data, int index)
1634 if (data == null)
1635 throw new ArgumentNullException ("data");
1636 if (data.Length - index < 2)
1637 throw new ArgumentException ("index");
1638 if (index < 0)
1639 throw new ArgumentException ("index");
1641 ushort ret;
1642 fixed (byte *src = &data[index]){
1643 PutBytesNative ((byte *) &ret, src, 2);
1645 return ret;
1648 unsafe static byte[] GetBytesPtr (byte *ptr, int count)
1650 byte [] ret = new byte [count];
1652 for (int i = 0; i < count; i++) {
1653 ret [i] = ptr [i];
1656 return ret;
1659 unsafe static byte[] GetBytesSwap (bool swap, byte *ptr, int count)
1661 byte [] ret = new byte [count];
1663 if (swap){
1664 int t = count-1;
1665 for (int i = 0; i < count; i++) {
1666 ret [t-i] = ptr [i];
1668 } else {
1669 for (int i = 0; i < count; i++) {
1670 ret [i] = ptr [i];
1673 return ret;
1676 unsafe public static byte[] GetBytesNative (bool value)
1678 return GetBytesPtr ((byte *) &value, 1);
1681 unsafe public static byte[] GetBytesNative (char value)
1683 return GetBytesPtr ((byte *) &value, 2);
1686 unsafe public static byte[] GetBytesNative (short value)
1688 return GetBytesPtr ((byte *) &value, 2);
1691 unsafe public static byte[] GetBytesNative (int value)
1693 return GetBytesPtr ((byte *) &value, 4);
1696 unsafe public static byte[] GetBytesNative (long value)
1698 return GetBytesPtr ((byte *) &value, 8);
1701 [CLSCompliant (false)]
1702 unsafe public static byte[] GetBytesNative (ushort value)
1704 return GetBytesPtr ((byte *) &value, 2);
1707 [CLSCompliant (false)]
1708 unsafe public static byte[] GetBytesNative (uint value)
1710 return GetBytesPtr ((byte *) &value, 4);
1713 [CLSCompliant (false)]
1714 unsafe public static byte[] GetBytesNative (ulong value)
1716 return GetBytesPtr ((byte *) &value, 8);
1719 unsafe public static byte[] GetBytesNative (float value)
1721 return GetBytesPtr ((byte *) &value, 4);
1724 unsafe public static byte[] GetBytesNative (double value)
1726 return GetBytesPtr ((byte *) &value, 8);
1729 unsafe public static byte[] GetBytesLE (bool value)
1731 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 1);
1734 unsafe public static byte[] GetBytesLE (char value)
1736 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
1739 unsafe public static byte[] GetBytesLE (short value)
1741 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
1744 unsafe public static byte[] GetBytesLE (int value)
1746 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
1749 unsafe public static byte[] GetBytesLE (long value)
1751 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
1754 [CLSCompliant (false)]
1755 unsafe public static byte[] GetBytesLE (ushort value)
1757 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
1760 [CLSCompliant (false)]
1761 unsafe public static byte[] GetBytesLE (uint value)
1763 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
1766 [CLSCompliant (false)]
1767 unsafe public static byte[] GetBytesLE (ulong value)
1769 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
1772 unsafe public static byte[] GetBytesLE (float value)
1774 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
1777 unsafe public static byte[] GetBytesLE (double value)
1779 return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
1782 unsafe public static byte[] GetBytesBE (bool value)
1784 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 1);
1787 unsafe public static byte[] GetBytesBE (char value)
1789 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
1792 unsafe public static byte[] GetBytesBE (short value)
1794 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
1797 unsafe public static byte[] GetBytesBE (int value)
1799 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
1802 unsafe public static byte[] GetBytesBE (long value)
1804 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
1807 [CLSCompliant (false)]
1808 unsafe public static byte[] GetBytesBE (ushort value)
1810 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
1813 [CLSCompliant (false)]
1814 unsafe public static byte[] GetBytesBE (uint value)
1816 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
1819 [CLSCompliant (false)]
1820 unsafe public static byte[] GetBytesBE (ulong value)
1822 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
1825 unsafe public static byte[] GetBytesBE (float value)
1827 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
1830 unsafe public static byte[] GetBytesBE (double value)
1832 return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
1834 #endif