Made all DBusTypes take Service in the constructor because Array also needed it in...
[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().UnderlyingSystemType);
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;
39       dbus_message_iter_init_array_iterator(iter, arrayIter, out elementTypeCode);
40       this.elementType = (Type) Arguments.DBusTypes[(char) elementTypeCode];
41
42       elements = new ArrayList();
43
44       do {
45         object [] pars = new Object[2];
46         pars[0] = arrayIter;
47         pars[1] = service;
48         DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
49         elements.Add(dbusType);
50       } while (dbus_message_iter_next(arrayIter));
51       
52       Marshal.FreeCoTaskMem(arrayIter);
53     }
54     
55     public void Append(IntPtr iter)
56     {
57       IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
58
59       if (!dbus_message_iter_append_array(iter,
60                                           arrayIter,
61                                           (int) Arguments.GetCode(this.elementType))) {
62         throw new ApplicationException("Failed to append INT32 argument:" + val);
63       }
64
65       foreach (object element in this.val) {
66         object [] pars = new Object[2];
67         pars[0] = element;
68         pars[1] = this.service;
69         DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
70         dbusType.Append(arrayIter);
71       }
72
73       Marshal.FreeCoTaskMem(arrayIter);
74     }    
75
76     public static bool Suits(System.Type type) 
77     {
78       if (type.IsArray) {
79         return true;
80       }
81       
82       return false;
83     }
84
85     public static void EmitMarshalIn(ILGenerator generator, Type type)
86     {
87       if (type.IsByRef) {
88         generator.Emit(OpCodes.Ldind_Ref);
89       }
90     }
91
92     public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
93     {
94       generator.Emit(OpCodes.Castclass, type);
95       if (!isReturn) {
96         generator.Emit(OpCodes.Stind_Ref);
97       }
98     }
99     
100     public object Get() 
101     {
102       throw new ArgumentException("Cannot call Get on an Array without specifying type.");
103     }
104
105     public object Get(System.Type type)
106     {
107       if (Arguments.Suits(elementType, type.UnderlyingSystemType)) {
108         this.val = System.Array.CreateInstance(type.UnderlyingSystemType, elements.Count);
109         int i = 0;
110         foreach (DBusType.IDBusType element in elements) {
111           this.val.SetValue(element.Get(type.UnderlyingSystemType), i++);
112         }       
113       } else {
114         throw new ArgumentException("Cannot cast DBus.Type.Array to type '" + type.ToString() + "'");
115       }
116         
117         return this.val;
118     }    
119
120     [DllImport("dbus-1")]
121     private extern static void dbus_message_iter_init_array_iterator(IntPtr iter,
122                                                                      IntPtr arrayIter,
123                                                                      out int elementType);
124  
125     [DllImport("dbus-1")]
126     private extern static bool dbus_message_iter_append_array(IntPtr iter, 
127                                                               IntPtr arrayIter,
128                                                               int elementType);
129
130     [DllImport("dbus-1")]
131     private extern static bool dbus_message_iter_has_next(IntPtr iter);
132
133     [DllImport("dbus-1")]
134     private extern static bool dbus_message_iter_next(IntPtr iter);
135   }
136 }