Replaced public MessageReader.Position with something marginally better.
[versaplex.git] / dbus-sharp / Introspection.cs
blob64f0e9ef716fcdf3f396d5ee715a823d7a82cf8f
1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Xml;
9 using System.Text;
10 using System.Reflection;
12 namespace Wv
14 //TODO: complete this class
15 class Introspector
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;
22 public string xml;
23 public ObjectPath root_path = ObjectPath.Root;
25 protected XmlWriter writer;
27 public Introspector ()
29 XmlWriterSettings settings = new XmlWriterSettings ();
30 settings.Indent = true;
31 settings.IndentChars = (" ");
32 settings.OmitXmlDeclaration = true;
34 sb = new StringBuilder ();
36 writer = XmlWriter.Create (sb, settings);
39 static string GetProductDescription ()
41 String version;
43 Assembly assembly = Assembly.GetExecutingAssembly ();
44 AssemblyName aname = assembly.GetName ();
46 AssemblyInformationalVersionAttribute iversion = Attribute.GetCustomAttribute (assembly, typeof (AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
48 if (iversion != null)
49 version = iversion.InformationalVersion;
50 else
51 version = aname.Version.ToString ();
53 return aname.Name + " " + version;
56 public void WriteStart ()
58 writer.WriteDocType ("node", PUBLIC_IDENTIFIER, SYSTEM_IDENTIFIER, null);
60 writer.WriteComment (" " + GetProductDescription () + " ");
62 //the root node element
63 writer.WriteStartElement ("node");
66 public void WriteNode (string name)
68 writer.WriteStartElement ("node");
69 writer.WriteAttributeString ("name", name);
70 writer.WriteEndElement ();
73 public void WriteEnd ()
76 WriteEnum (typeof (org.freedesktop.DBus.NameFlag));
77 WriteEnum (typeof (org.freedesktop.DBus.NameReply));
78 WriteEnum (typeof (org.freedesktop.DBus.ReleaseNameReply));
79 WriteEnum (typeof (org.freedesktop.DBus.StartReply));
80 WriteInterface (typeof (org.freedesktop.DBus.IBus));
83 writer.WriteEndElement ();
85 writer.Flush ();
86 xml = sb.ToString ();
89 //public void WriteNode ()
90 public void WriteType (Type target_type)
92 //writer.WriteStartElement ("node");
94 //TODO: non-well-known introspection has paths as well, which we don't do yet. read the spec again
95 //hackishly just remove the root '/' to make the path relative for now
96 //writer.WriteAttributeString ("name", target_path.Value.Substring (1));
97 //writer.WriteAttributeString ("name", "test");
99 //reflect our own interface manually
100 WriteInterface (typeof (org.freedesktop.DBus.Introspectable));
102 //reflect the target interface
103 if (target_type != null) {
104 WriteInterface (target_type);
106 foreach (Type ifType in target_type.GetInterfaces ())
107 WriteInterface (ifType);
110 //TODO: review recursion of interfaces and inheritance hierarchy
112 //writer.WriteEndElement ();
115 public void WriteArg (ParameterInfo pi)
117 WriteArg (pi.ParameterType, Mapper.GetArgumentName (pi), pi.IsOut, false);
120 public void WriteArgReverse (ParameterInfo pi)
122 WriteArg (pi.ParameterType, Mapper.GetArgumentName (pi), pi.IsOut, true);
125 //TODO: clean up and get rid of reverse (or argIsOut) parm
126 public void WriteArg (Type argType, string argName, bool argIsOut, bool reverse)
128 argType = argIsOut ? argType.GetElementType () : argType;
129 if (argType == typeof (void))
130 return;
132 writer.WriteStartElement ("arg");
134 if (!String.IsNullOrEmpty (argName))
135 writer.WriteAttributeString ("name", argName);
137 //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
139 if (argIsOut)
140 writer.WriteAttributeString ("direction", !reverse ? "out" : "in");
141 else
142 writer.WriteAttributeString ("direction", !reverse ? "in" : "out");
144 Signature sig = Signature.GetSig (argType);
146 //TODO: avoid writing null (DType.Invalid) to the XML stream
147 writer.WriteAttributeString ("type", sig.Value);
149 //annotations aren't valid in an arg element, so this is disabled
150 //if (argType.IsEnum)
151 // WriteAnnotation ("org.ndesk.DBus.Enum", Mapper.GetInterfaceName (argType));
153 writer.WriteEndElement ();
156 public void WriteMethod (MethodInfo mi)
158 writer.WriteStartElement ("method");
159 writer.WriteAttributeString ("name", mi.Name);
161 foreach (ParameterInfo pi in mi.GetParameters ())
162 WriteArg (pi);
164 //Mono <= 1.1.13 doesn't support MethodInfo.ReturnParameter, so avoid it
165 //WriteArgReverse (mi.ReturnParameter);
166 WriteArg (mi.ReturnType, Mapper.GetArgumentName (mi.ReturnTypeCustomAttributes, "ret"), false, true);
168 WriteAnnotations (mi);
170 writer.WriteEndElement ();
173 public void WriteProperty (PropertyInfo pri)
175 //expose properties as dbus properties
176 writer.WriteStartElement ("property");
177 writer.WriteAttributeString ("name", pri.Name);
178 writer.WriteAttributeString ("type", Signature.GetSig (pri.PropertyType).Value);
179 string access = (pri.CanRead ? "read" : String.Empty) + (pri.CanWrite ? "write" : String.Empty);
180 writer.WriteAttributeString ("access", access);
181 WriteAnnotations (pri);
182 writer.WriteEndElement ();
184 //expose properties as methods also
185 //it may not be worth doing this in the long run
187 if (pri.CanRead) {
188 writer.WriteStartElement ("method");
189 writer.WriteAttributeString ("name", "Get" + pri.Name);
190 WriteArgReverse (pri.GetGetMethod ().ReturnParameter);
191 writer.WriteEndElement ();
194 if (pri.CanWrite) {
195 writer.WriteStartElement ("method");
196 writer.WriteAttributeString ("name", "Set" + pri.Name);
197 foreach (ParameterInfo pi in pri.GetSetMethod ().GetParameters ())
198 WriteArg (pi);
199 writer.WriteEndElement ();
204 public void WriteSignal (EventInfo ei)
206 writer.WriteStartElement ("signal");
207 writer.WriteAttributeString ("name", ei.Name);
209 foreach (ParameterInfo pi in ei.EventHandlerType.GetMethod ("Invoke").GetParameters ())
210 WriteArgReverse (pi);
212 WriteAnnotations (ei);
214 //no need to consider the delegate return value as dbus doesn't support it
215 writer.WriteEndElement ();
218 const BindingFlags relevantBindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
220 public void WriteInterface (Type type)
222 if (type == null)
223 return;
225 //TODO: this is unreliable, fix it
226 if (!Mapper.IsPublic (type))
227 return;
229 writer.WriteStartElement ("interface");
231 writer.WriteAttributeString ("name", Mapper.GetInterfaceName (type));
234 foreach (MemberInfo mbi in type.GetMembers (relevantBindingFlags)) {
235 switch (mbi.MemberType) {
236 case MemberTypes.Method:
237 if (!((MethodInfo)mbi).IsSpecialName)
238 WriteMethod ((MethodInfo)mbi);
239 break;
240 case MemberTypes.Event:
241 WriteSignal ((EventInfo)mbi);
242 break;
243 case MemberTypes.Property:
244 WriteProperty ((PropertyInfo)mbi);
245 break;
246 default:
247 Console.Error.WriteLine ("Warning: Unhandled MemberType '{0}' encountered while introspecting {1}", mbi.MemberType, type.FullName);
248 break;
253 foreach (MethodInfo mi in type.GetMethods (relevantBindingFlags))
254 if (!mi.IsSpecialName)
255 WriteMethod (mi);
257 foreach (EventInfo ei in type.GetEvents (relevantBindingFlags))
258 WriteSignal (ei);
260 foreach (PropertyInfo pri in type.GetProperties (relevantBindingFlags))
261 WriteProperty (pri);
263 //TODO: indexers
265 //TODO: attributes as annotations?
267 writer.WriteEndElement ();
269 //this recursion seems somewhat inelegant
270 WriteInterface (type.BaseType);
273 public void WriteAnnotations (ICustomAttributeProvider attrProvider)
275 if (Mapper.IsDeprecated (attrProvider))
276 WriteAnnotation ("org.freedesktop.DBus.Deprecated", "true");
279 public void WriteAnnotation (string name, string value)
281 writer.WriteStartElement ("annotation");
283 writer.WriteAttributeString ("name", name);
284 writer.WriteAttributeString ("value", value);
286 writer.WriteEndElement ();
289 //this is not in the spec, and is not finalized
290 public void WriteEnum (Type type)
292 writer.WriteStartElement ("enum");
293 writer.WriteAttributeString ("name", Mapper.GetInterfaceName (type));
294 writer.WriteAttributeString ("type", Signature.GetSig (type.GetElementType ()).Value);
295 writer.WriteAttributeString ("flags", (type.IsDefined (typeof (FlagsAttribute), false)) ? "true" : "false");
297 string[] names = Enum.GetNames (type);
299 int i = 0;
300 foreach (Enum val in Enum.GetValues (type)) {
301 writer.WriteStartElement ("element");
302 writer.WriteAttributeString ("name", names[i++]);
303 writer.WriteAttributeString ("value", val.ToString ("d"));
304 writer.WriteEndElement ();
307 writer.WriteEndElement ();