* qt/Makfile.am:
[platform/upstream/dbus.git] / mono / DBusType / Array.cs
1 using System;
2 using System.Collections;
3 using System.Runtime.InteropServices;
4 using System.Reflection.Emit;
5
6 using DBus;
7
8 namespace DBus.DBusType
9 {
10   /// <summary>
11   /// Array.
12   /// </summary>
13   public class Array : IDBusType
14   {
15     public const char Code = 'a';
16     private System.Array val;
17     private ArrayList elements;
18     private Type elementType;
19     private Service service = null;
20
21     private Array()
22     {
23     }
24     
25     public Array(System.Array val, Service service) 
26     {
27       this.val = val;
28       this.elementType = Arguments.MatchType(val.GetType().GetElementType());
29       this.service = service;
30     }
31
32     public Array(IntPtr iter, Service service)
33     {
34       this.service = service;
35
36       IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
37
38       int elementTypeCode = dbus_message_iter_get_element_type (iter);
39       dbus_message_iter_recurse (iter, arrayIter);
40       this.elementType = (Type) Arguments.DBusTypes [(char) elementTypeCode];
41
42       elements = new ArrayList ();
43
44       if (dbus_message_iter_get_arg_type (arrayIter) != 0) {
45         do {
46           object [] pars = new Object[2];
47           pars[0] = arrayIter;
48           pars[1] = service;
49           DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
50           elements.Add(dbusType);
51         } while (dbus_message_iter_next(arrayIter));
52       }      
53
54       Marshal.FreeCoTaskMem(arrayIter);
55     }
56
57     public string GetElementCodeAsString ()
58     {
59       string ret = System.String.Empty;
60       Type t = val.GetType ().GetElementType ();
61
62       while (true) {
63         ret += Arguments.GetCodeAsString (Arguments.MatchType(t));
64
65         if (t.IsArray)
66           t = t.GetElementType ();
67         else
68           break;
69       }
70      
71       return ret; 
72     }
73     
74     public void Append(IntPtr iter)
75     {
76       IntPtr arrayIter = Marshal.AllocCoTaskMem (Arguments.DBusMessageIterSize);
77
78       if (!dbus_message_iter_open_container (iter,
79                                              (int) Code, GetElementCodeAsString(),
80                                              arrayIter)) {
81         throw new ApplicationException("Failed to append array argument: " + val);
82       }
83       
84       foreach (object element in this.val) {
85         object [] pars = new Object[2];
86         pars[0] = element;
87         pars[1] = this.service;
88         DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
89         dbusType.Append(arrayIter);
90       }
91
92       if (!dbus_message_iter_close_container (iter, arrayIter)) {
93         throw new ApplicationException ("Failed to append array argument: " + val);
94       }
95
96       Marshal.FreeCoTaskMem (arrayIter);
97     }    
98
99     public static bool Suits(System.Type type) 
100     {
101       Type type2 = type.GetElementType ();
102       if (type.IsArray || (type2 != null && type2.IsArray)) {
103         return true;
104       }
105       
106       return false;
107     }
108
109     public static void EmitMarshalIn(ILGenerator generator, Type type)
110     {
111       if (type.IsByRef) {
112         generator.Emit(OpCodes.Ldind_Ref);
113       }
114     }
115
116     public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
117     {
118       generator.Emit(OpCodes.Castclass, type);
119       if (!isReturn) {
120         generator.Emit(OpCodes.Stind_Ref);
121       }
122     }
123     
124     public object Get() 
125     {
126       throw new ArgumentException("Cannot call Get on an Array without specifying type.");
127     }
128
129     public object Get(System.Type type)
130     {
131       if (type.IsArray)
132         type = type.GetElementType ();
133
134       if (Arguments.Suits(elementType, type.UnderlyingSystemType)) {
135         this.val = System.Array.CreateInstance(type.UnderlyingSystemType, elements.Count);
136         int i = 0;
137         foreach (DBusType.IDBusType element in elements) {
138           this.val.SetValue(element.Get(type.UnderlyingSystemType), i++);
139         }       
140       } else {
141         throw new ArgumentException("Cannot cast DBus.Type.Array to type '" + type.ToString() + "'");
142       }
143         
144         return this.val;
145     }    
146
147     [DllImport("dbus-1")]
148     private extern static bool dbus_message_iter_open_container (IntPtr iter,
149                                                                  int containerType,
150                                                                  string elementType,
151                                                                  IntPtr subIter);
152
153     [DllImport("dbus-1")]
154     private extern static bool dbus_message_iter_close_container (IntPtr iter,
155                                                                   IntPtr subIter);
156  
157     [DllImport("dbus-1")]
158     private extern static int dbus_message_iter_get_element_type(IntPtr iter);
159
160     [DllImport("dbus-1")]
161     private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
162
163     [DllImport("dbus-1")]
164     private extern static void dbus_message_iter_recurse(IntPtr iter, IntPtr subIter);
165
166     [DllImport("dbus-1")]
167     private extern static bool dbus_message_iter_next(IntPtr iter);
168
169     [DllImport("dbus-1")]
170     private extern static bool dbus_message_iter_has_next (IntPtr iter);
171   }
172 }