summaryrefslogtreecommitdiffstats
path: root/mono/DBusType/Dict.cs
blob: 660cac5773fba791b5441b3731b1d86acae12252 (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
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Reflection.Emit;

using DBus;

namespace DBus.DBusType
{
  /// <summary>
  /// Dict.
  /// </summary>
  public class Dict : IDBusType
  {
    public const char Code = 'm';
    private Hashtable val;
    
    private Dict()
    {
    }
    
    public Dict(IDictionary val, Service service)
    {
      this.val = new Hashtable();
      foreach (DictionaryEntry entry in val) {
	this.val.Add(entry.Key, entry.Value);
      }
    }

    public Dict(IntPtr iter, Service service)
    {
      IntPtr dictIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);
      
      bool notEmpty = dbus_message_iter_init_dict_iterator(iter, dictIter);

      this.val = new Hashtable();

      if (notEmpty) {
	do {
	  string key = dbus_message_iter_get_dict_key(dictIter);
	  
	  // Get the argument type and get the value
	  Type elementType = (Type) DBus.Arguments.DBusTypes[(char) dbus_message_iter_get_arg_type(dictIter)];
	  object [] pars = new Object[2];
	  pars[0] = dictIter;
	  pars[1] = service;
	  DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
	  this.val.Add(key, dbusType);
	} while (dbus_message_iter_next(dictIter));
      }
      
      Marshal.FreeCoTaskMem(dictIter);
    }
    
    public void Append(IntPtr iter)
    {
      IntPtr dictIter = Marshal.AllocCoTaskMem(Arguments.DBusMessageIterSize);

      if (!dbus_message_iter_append_dict(iter,
					 dictIter)) {
	throw new ApplicationException("Failed to append DICT argument:" + val);
      }

      foreach (DictionaryEntry entry in this.val) {
	if (!dbus_message_iter_append_dict_key(dictIter, (string) entry.Key)) {
	  throw new ApplicationException("Failed to append DICT key:" + entry.Key);
	}
	
	// Get the element type
	Type elementType = Arguments.MatchType(entry.Value.GetType());
	object [] pars = new Object[1];
	pars[0] = entry.Value;
	DBusType.IDBusType dbusType = (DBusType.IDBusType) Activator.CreateInstance(elementType, pars);
	dbusType.Append(dictIter);
      }

      Marshal.FreeCoTaskMem(dictIter);
    }    

    public static bool Suits(System.Type type) 
    {
      if (typeof(IDictionary).IsAssignableFrom(type)) {
	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() 
    {
      return Get(typeof(Hashtable));
    }

    public object Get(System.Type type)
    {
      IDictionary retVal;

      if (Suits(type)) {
	retVal = (IDictionary) Activator.CreateInstance(type, new object[0]);
	foreach (DictionaryEntry entry in this.val) {
	  retVal.Add(entry.Key, ((IDBusType) entry.Value).Get());
	}
      } else {
	throw new ArgumentException("Cannot cast DBus.Type.Dict to type '" + type.ToString() + "'");
      }
	
      return retVal;
    }    

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_init_dict_iterator(IntPtr iter,
								    IntPtr dictIter);
 
    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_append_dict(IntPtr iter, 
							     IntPtr dictIter);

    [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);

    [DllImport("dbus-1")]
    private extern static string dbus_message_iter_get_dict_key (IntPtr dictIter);  

    [DllImport("dbus-1")]
    private extern static bool dbus_message_iter_append_dict_key (IntPtr dictIter,
								  string value);
    [DllImport("dbus-1")]
    private extern static int dbus_message_iter_get_arg_type(IntPtr iter);
  }
}