summaryrefslogtreecommitdiffstats
path: root/mono/DBusType/Array.cs
blob: ef001b98a33278f2f2d3babd453cf64eb8f05d43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Reflection.Emit;

using DBus;

namespace DBus.DBusType
{
  /// <summary>
  /// Array.
  /// </summary>
  public class Array : IDBusType
  {
    public const char Code = 'a';
    private System.Array val;
    private ArrayList elements;
    private Type elementType;
    private Service service = null;
    
    private Array()
    {
    }
    
    public Array(System.Array val, Service service) 
    {
      this.val = val;
      this.elementType = Arguments.MatchType(val.GetType().GetElementType());
      this.service = service;
    }

    public Array(IntPtr iter, Service service)
    {
      this.service = service;

      IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);

      int elementTypeCode = dbus_message_iter_get_element_type (iter);
      dbus_message_iter_recurse (iter, arrayIter);
      this.elementType = (Type) Arguments.DBusTypes [(char) elementTypeCode];

      elements = new ArrayList ();

      if (dbus_message_iter_get_arg_type (arrayIter) != 0) {
        do {
          object [] pars = new Object[2];
	  pars[0] = arrayIter;
  	  pars[1] = service;
	  DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
	  elements.Add(dbusType);
        } while (dbus_message_iter_next(arrayIter));
      }      

      Marshal.FreeCoTaskMem(arrayIter);
    }
    
    public void Append(IntPtr iter)
    {
      IntPtr arrayIter = Marshal.AllocCoTaskMem (Arguments.DBusMessageIterSize);

      if (!dbus_message_iter_open_container (iter,
					     (int) Code,
					     Arguments.GetCodeAsString (elementType),
					     arrayIter)) {
	throw new ApplicationException("Failed to append array argument: " + val);
      }
      
      foreach (object element in this.val) {
	object [] pars = new Object[2];
	pars[0] = element;
	pars[1] = this.service;
	DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
	dbusType.Append(arrayIter);
      }

      if (!dbus_message_iter_close_container (iter, arrayIter)) {
	throw new ApplicationException ("Failed to append array argument: " + val);
      }

      Marshal.FreeCoTaskMem (arrayIter);
    }    

    public static bool Suits(System.Type type) 
    {
      if (type.IsArray) {
	return true;
      }
      
      return false;
    }

    public static void EmitMarshalIn(ILGenerator generator, Type type)
    {
      if (type.IsByRef) {
	generator.Emit(OpCodes.Ldind_Ref);
      }
    }

    public static void EmitMarshalOut(ILGenerator generator, Type type, bool isReturn) 
    {
      generator.Emit(OpCodes.Castclass, type);
      if (!isReturn) {
	generator.Emit(OpCodes.Stind_Ref);
      }
    }
    
    public object Get() 
    {
      throw new ArgumentException("Cannot call Get on an Array without specifying type.");
    }

    public object Get(System.Type type)
    {
      if (type.IsArray)
	type = type.GetElementType ();

      if (Arguments.Suits(elementType, type.UnderlyingSystemType)) {
	this.val = System.Array.CreateInstance(type.UnderlyingSystemType, elements.Count);
	int i = 0;
	foreach (DBusType.IDBusType element in elements) {
	  this.val.SetValue(element.Get(type.UnderlyingSystemType), i++);
	}	
      } else {
	throw new ArgumentException("Cannot cast DBus.Type.Array to type '" + type.ToString() + "'");
      }
	
	return this.val;
    }    

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_open_container (IntPtr iter,
								 int containerType,
								 string elementType,
								 IntPtr subIter);

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_close_container (IntPtr iter,
								  IntPtr subIter);
 
    [DllImport("dbus-1")]
    private extern static int dbus_message_iter_get_element_type(IntPtr iter);

    [DllImport("dbus-1")]
    private extern static int dbus_message_iter_get_arg_type(IntPtr iter);

    [DllImport("dbus-1")]
    private extern static void dbus_message_iter_recurse(IntPtr iter, IntPtr subIter);

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_next(IntPtr iter);

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_has_next (IntPtr iter);
  }
}