summaryrefslogtreecommitdiffstats
path: root/mono/DBusType/Array.cs
blob: dd93a5cc0a8821e290db7cf4b5ca2bd643942521 (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
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().UnderlyingSystemType);
      this.service = service;
    }

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

      IntPtr arrayIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
      
      int elementTypeCode;
      bool notEmpty = dbus_message_iter_init_array_iterator(iter, arrayIter, out elementTypeCode);
      this.elementType = (Type) Arguments.DBusTypes[(char) elementTypeCode];

      elements = new ArrayList();

      if (notEmpty) {
	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_append_array(iter,
					  arrayIter,
					  (int) Arguments.GetCode(this.elementType))) {
	throw new ApplicationException("Failed to append INT32 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);
      }

      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_init_array_iterator(IntPtr iter,
								     IntPtr arrayIter,
								     out int elementType);
 
    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_append_array(IntPtr iter, 
							      IntPtr arrayIter,
							      int elementType);

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

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