1
// Copyright 2006 Alp Toker <alp@atoker.com>
2
// This software is made available under the MIT License
3
// See COPYING for details
6
using System.Collections.Generic;
10
using System.Reflection;
14
//TODO: complete this class
17
const string NAMESPACE = "http://www.freedesktop.org/standards/dbus";
18
const string PUBLIC_IDENTIFIER = "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN";
19
const string SYSTEM_IDENTIFIER = "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";
21
public StringBuilder sb;
23
public ObjectPath root_path = ObjectPath.Root;
24
public bool ExtendedAnnotations = false;
26
protected XmlWriter writer;
28
public Introspector ()
30
XmlWriterSettings settings = new XmlWriterSettings ();
31
settings.Indent = true;
32
settings.IndentChars = (" ");
33
settings.OmitXmlDeclaration = true;
35
sb = new StringBuilder ();
37
writer = XmlWriter.Create (sb, settings);
40
static string GetProductDescription ()
44
Assembly assembly = Assembly.GetExecutingAssembly ();
45
AssemblyName aname = assembly.GetName ();
47
AssemblyInformationalVersionAttribute iversion = Attribute.GetCustomAttribute (assembly, typeof (AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
50
version = iversion.InformationalVersion;
52
version = aname.Version.ToString ();
54
return aname.Name + " " + version;
57
public void WriteStart ()
59
writer.WriteDocType ("node", PUBLIC_IDENTIFIER, SYSTEM_IDENTIFIER, null);
61
writer.WriteComment (" " + GetProductDescription () + " ");
63
//the root node element
64
writer.WriteStartElement ("node");
67
public void WriteNode (string name)
69
writer.WriteStartElement ("node");
70
writer.WriteAttributeString ("name", name);
71
writer.WriteEndElement ();
74
public void WriteEnd ()
77
WriteEnum (typeof (org.freedesktop.DBus.NameFlag));
78
WriteEnum (typeof (org.freedesktop.DBus.NameReply));
79
WriteEnum (typeof (org.freedesktop.DBus.ReleaseNameReply));
80
WriteEnum (typeof (org.freedesktop.DBus.StartReply));
81
WriteInterface (typeof (org.freedesktop.DBus.IBus));
84
writer.WriteEndElement ();
90
//public void WriteNode ()
91
public void WriteType (Type target_type)
93
//writer.WriteStartElement ("node");
95
//TODO: non-well-known introspection has paths as well, which we don't do yet. read the spec again
96
//hackishly just remove the root '/' to make the path relative for now
97
//writer.WriteAttributeString ("name", target_path.Value.Substring (1));
98
//writer.WriteAttributeString ("name", "test");
100
//reflect our own interface manually
101
WriteInterface (typeof (org.freedesktop.DBus.Introspectable));
103
//reflect the target interface
104
if (target_type != null) {
105
WriteInterface (target_type);
107
foreach (Type ifType in target_type.GetInterfaces ())
108
WriteInterface (ifType);
111
//TODO: review recursion of interfaces and inheritance hierarchy
113
//writer.WriteEndElement ();
116
public void WriteArg (ParameterInfo pi)
118
WriteArg (pi.ParameterType, Mapper.GetArgumentName (pi), pi.IsOut, false);
121
public void WriteArgReverse (ParameterInfo pi)
123
WriteArg (pi.ParameterType, Mapper.GetArgumentName (pi), pi.IsOut, true);
126
//TODO: clean up and get rid of reverse (or argIsOut) parm
127
public void WriteArg (Type argType, string argName, bool argIsOut, bool reverse)
129
argType = argIsOut ? argType.GetElementType () : argType;
130
if (argType == typeof (void))
133
writer.WriteStartElement ("arg");
135
if (!String.IsNullOrEmpty (argName))
136
writer.WriteAttributeString ("name", argName);
138
//we can't rely on the default direction (qt-dbus requires a direction at time of writing), so we use a boolean to reverse the parameter direction and make it explicit
141
writer.WriteAttributeString ("direction", !reverse ? "out" : "in");
143
writer.WriteAttributeString ("direction", !reverse ? "in" : "out");
145
Signature sig = Signature.GetSig (argType);
147
//TODO: avoid writing null (DType.Invalid) to the XML stream
148
writer.WriteAttributeString ("type", sig.Value);
150
//annotations aren't valid in an arg element, so this is disabled
151
//if (argType.IsEnum)
152
// WriteAnnotation ("org.ndesk.DBus.Enum", Mapper.GetInterfaceName (argType));
154
writer.WriteEndElement ();
157
public void WriteMethod (MethodInfo mi)
159
writer.WriteStartElement ("method");
160
writer.WriteAttributeString ("name", mi.Name);
162
foreach (ParameterInfo pi in mi.GetParameters ())
165
//Mono <= 1.1.13 doesn't support MethodInfo.ReturnParameter, so avoid it
166
//WriteArgReverse (mi.ReturnParameter);
167
WriteArg (mi.ReturnType, Mapper.GetArgumentName (mi.ReturnTypeCustomAttributes, "ret"), false, true);
169
WriteAnnotations (mi);
171
writer.WriteEndElement ();
174
public void WriteProperty (PropertyInfo pri)
176
//expose properties as dbus properties
177
writer.WriteStartElement ("property");
178
writer.WriteAttributeString ("name", pri.Name);
179
writer.WriteAttributeString ("type", Signature.GetSig (pri.PropertyType).Value);
180
string access = (pri.CanRead ? "read" : String.Empty) + (pri.CanWrite ? "write" : String.Empty);
181
writer.WriteAttributeString ("access", access);
182
WriteAnnotations (pri);
183
writer.WriteEndElement ();
185
//expose properties as methods also
186
//it may not be worth doing this in the long run
189
writer.WriteStartElement ("method");
190
writer.WriteAttributeString ("name", "Get" + pri.Name);
191
WriteArgReverse (pri.GetGetMethod ().ReturnParameter);
192
writer.WriteEndElement ();
196
writer.WriteStartElement ("method");
197
writer.WriteAttributeString ("name", "Set" + pri.Name);
198
foreach (ParameterInfo pi in pri.GetSetMethod ().GetParameters ())
200
writer.WriteEndElement ();
205
public void WriteSignal (EventInfo ei)
207
writer.WriteStartElement ("signal");
208
writer.WriteAttributeString ("name", ei.Name);
210
foreach (ParameterInfo pi in ei.EventHandlerType.GetMethod ("Invoke").GetParameters ())
211
WriteArgReverse (pi);
213
if (ExtendedAnnotations) {
214
string handlerName = Mapper.GetInterfaceName (ei.EventHandlerType);
215
WriteAnnotation ("org.ndesk.DBus.SignalHandler", handlerName);
218
WriteAnnotations (ei);
220
//no need to consider the delegate return value as dbus doesn't support it
221
writer.WriteEndElement ();
224
const BindingFlags relevantBindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
226
public void WriteInterface (Type type)
231
//TODO: this is unreliable, fix it
232
if (!Mapper.IsPublic (type))
235
writer.WriteStartElement ("interface");
237
writer.WriteAttributeString ("name", Mapper.GetInterfaceName (type));
240
foreach (MemberInfo mbi in type.GetMembers (relevantBindingFlags)) {
241
switch (mbi.MemberType) {
242
case MemberTypes.Method:
243
if (!((MethodInfo)mbi).IsSpecialName)
244
WriteMethod ((MethodInfo)mbi);
246
case MemberTypes.Event:
247
WriteSignal ((EventInfo)mbi);
249
case MemberTypes.Property:
250
WriteProperty ((PropertyInfo)mbi);
253
Console.Error.WriteLine ("Warning: Unhandled MemberType '{0}' encountered while introspecting {1}", mbi.MemberType, type.FullName);
259
foreach (MethodInfo mi in type.GetMethods (relevantBindingFlags))
260
if (!mi.IsSpecialName)
263
foreach (EventInfo ei in type.GetEvents (relevantBindingFlags))
266
foreach (PropertyInfo pri in type.GetProperties (relevantBindingFlags))
271
//TODO: attributes as annotations?
273
writer.WriteEndElement ();
275
//this recursion seems somewhat inelegant
276
WriteInterface (type.BaseType);
279
public void WriteAnnotations (ICustomAttributeProvider attrProvider)
281
if (Mapper.IsDeprecated (attrProvider))
282
WriteAnnotation ("org.freedesktop.DBus.Deprecated", "true");
285
public void WriteAnnotation (string name, string value)
287
writer.WriteStartElement ("annotation");
289
writer.WriteAttributeString ("name", name);
290
writer.WriteAttributeString ("value", value);
292
writer.WriteEndElement ();
295
//this is not in the spec, and is not finalized
296
public void WriteEnum (Type type)
298
writer.WriteStartElement ("enum");
299
writer.WriteAttributeString ("name", Mapper.GetInterfaceName (type));
300
writer.WriteAttributeString ("type", Signature.GetSig (type.GetElementType ()).Value);
301
writer.WriteAttributeString ("flags", (type.IsDefined (typeof (FlagsAttribute), false)) ? "true" : "false");
303
string[] names = Enum.GetNames (type);
306
foreach (Enum val in Enum.GetValues (type)) {
307
writer.WriteStartElement ("element");
308
writer.WriteAttributeString ("name", names[i++]);
309
writer.WriteAttributeString ("value", val.ToString ("d"));
310
writer.WriteEndElement ();
313
writer.WriteEndElement ();