cpw.gillux.detachablepurple: a82660ab: Added a DBus code generation script.

gillux at soc.pidgin.im gillux at soc.pidgin.im
Thu May 19 16:21:19 EDT 2011


----------------------------------------------------------------------
Revision: a82660ab5e31dbe1d7e86014eaafa25264b0d438
Parent:   14c4e310f1830a05a41b1898e2b7a4dff51b047a
Author:   gillux at soc.pidgin.im
Date:     05/19/11 14:39:54
Branch:   im.pidgin.cpw.gillux.detachablepurple
URL: http://d.pidgin.im/viewmtn/revision/info/a82660ab5e31dbe1d7e86014eaafa25264b0d438

Changelog: 

Added a DBus code generation script.
Actually, it only generates the DBus interface information data in
C source form. It's mainly copied from glib's gdbus-codegen code script.
We needed our own script, because the code generated by gdbus-codegen
doesn't suit our needs. It's good if you have DBus-dedicated gobjects,
but not if you want e.g. to directly export the existing properties and
methods of your gobjects.
But it still worth to have such a script to keep the XML DBus interface
information in static C structures instead of generating it at runtime
from hardcoded XML strings, so here it is.

Changes against parent 14c4e310f1830a05a41b1898e2b7a4dff51b047a

  added    libpurple/dbus/codegen.py
  added    libpurple/dbus/dbusxml-to-c.py
  added    libpurple/dbus/parser.py
  patched  libpurple/Makefile.am
  attr on  libpurple/dbus/dbusxml-to-c.py
      set  mtn:execute
       to  true

-------------- next part --------------
============================================================
--- libpurple/Makefile.am	79c96e27a874752a61f0ac452ad2c17958a2f931
+++ libpurple/Makefile.am	7ffa75dbdf1c225955adcf330e6fe6cfd9277a45
@@ -207,15 +207,15 @@ purple_builtheaders = \
 
 purple_builtheaders = \
 	purple.h version.h marshallers.h enums.h \
-	dbus/account-server.h dbus/account-client.h \
-	dbus/blist-server.h dbus/blist-client.h \
-	dbus/buddy-server.h dbus/buddy-client.h \
-	dbus/chat-server.h dbus/chat-client.h \
-	dbus/connection-server.h dbus/connection-client.h \
-	dbus/contact-server.h dbus/contact-client.h \
-	dbus/group-server.h dbus/group-client.h \
-	dbus/constructor-server.h dbus/constructor-client.h \
-	dbus/callback-server.h dbus/callback-client.h
+	dbus/account.xml.h \
+	dbus/blist.xml.h \
+	dbus/buddy.xml.h \
+	dbus/callback.xml.h \
+	dbus/chat.xml.h \
+	dbus/connection.xml.h \
+	dbus/constructor.xml.h \
+	dbus/contact.xml.h \
+	dbus/group.xml.h
 
 purple_enumheaders = \
 	account.h \
@@ -264,60 +264,33 @@ if ENABLE_DBUS
 
 if ENABLE_DBUS
 
-dbus/constructor-server.h: dbus/constructor.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_constructor --mode=glib-server --output=$@ $<
+dbus/constructor.xml.h: dbus/constructor.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_constructor $@
 
-dbus/constructor-client.h: dbus/constructor.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_constructor --mode=glib-client --output=$@ $<
+dbus/callback.xml.h: dbus/callback.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_callback $@
 
-dbus/callback-server.h: dbus/callback.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_callback --mode=glib-server --output=$@ $<
+dbus/account.xml.h: dbus/account.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_account $@
 
-dbus/callback-client.h: dbus/callback.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_callback --mode=glib-client --output=$@ $<
+dbus/blist.xml.h: dbus/blist.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_blist $@
 
-dbus/account-server.h: dbus/account.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_account --mode=glib-server --output=$@ $<
+dbus/buddy.xml.h: dbus/buddy.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_buddy $@
 
-dbus/account-client.h: dbus/account.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_account --mode=glib-client --output=$@ $<
+dbus/chat.xml.h: dbus/chat.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_chat $@
 
-dbus/blist-server.h: dbus/blist.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_blist --mode=glib-server --output=$@ $<
+dbus/connection.xml.h: dbus/connection.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_connection $@
 
-dbus/blist-client.h: dbus/blist.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_blist --mode=glib-client --output=$@ $<
+dbus/contact.xml.h: dbus/contact.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_contact $@
 
-dbus/buddy-server.h: dbus/buddy.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_buddy --mode=glib-server --output=$@ $<
+dbus/group.xml.h: dbus/group.xml
+	$(AM_V_GEN)dbus/dbusxml-to-c.py $< purple_group $@
 
-dbus/buddy-client.h: dbus/buddy.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_buddy --mode=glib-client --output=$@ $<
-
-dbus/chat-server.h: dbus/chat.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_chat --mode=glib-server --output=$@ $<
-
-dbus/chat-client.h: dbus/chat.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_chat --mode=glib-client --output=$@ $<
-
-dbus/connection-server.h: dbus/connection.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_connection --mode=glib-server --output=$@ $<
-
-dbus/connection-client.h: dbus/connection.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_connection --mode=glib-client --output=$@ $<
-
-dbus/contact-server.h: dbus/contact.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_contact --mode=glib-server --output=$@ $<
-
-dbus/contact-client.h: dbus/contact.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_contact --mode=glib-client --output=$@ $<
-
-dbus/group-server.h: dbus/group.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_group --mode=glib-server --output=$@ $<
-
-dbus/group-client.h: dbus/group.xml
-	$(AM_V_GEN)dbus-binding-tool --prefix=DBUS_purple_group --mode=glib-client --output=$@ $<
-
 CLEANFILES = \
 	dbus-bindings.c \
 	dbus-client-binding.c \
============================================================
--- /dev/null	
+++ libpurple/dbus/codegen.py	3912c068c4e7de19cb5124b984083486ec7d96be
@@ -0,0 +1,218 @@
+# -*- Mode: Python -*-
+
+# GDBus - GLib D-Bus Library
+#
+# Copyright (C) 2008-2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# Author: David Zeuthen <davidz at redhat.com>
+
+# Shamelessly cut and pasted from the gdbus-codegen glib tool, with minor
+# modifications. Only the GDBusInterfaceVTable generation code is here.
+
+import sys
+
+class CodeGenerator:
+    def __init__(self, ifaces, namespace, c):
+        self.ifaces = ifaces
+        self.c = c
+        self.namespace = namespace
+
+    def generate_annotations(self, prefix, annotations):
+        if annotations == None:
+            return
+
+        n = 0
+        for a in annotations:
+            # skip internal annotations
+            if a.key.startswith('org.gtk.GDBus'):
+                continue
+
+            self.c.write('static const GDBusAnnotationInfo %s_%d =\n'
+                         '{\n'
+                         '  -1,\n'
+                         '  "%s",\n'
+                         '  "%s",\n'%(prefix, n, a.key, a.value))
+            if len(a.annotations) == 0:
+                self.c.write('  NULL\n')
+            else:
+                self.c.write('  (GDBusAnnotationInfo **) &%s_%d_pointers\n'%(prefix, n))
+            self.c.write('};\n'
+                         '\n')
+            n += 1
+
+        if n > 0:
+            self.c.write('static const GDBusAnnotationInfo * const %s_pointers[] =\n'
+                             '{\n'%(prefix))
+            m = 0;
+            for a in annotations:
+                if a.key.startswith('org.gtk.GDBus'):
+                    continue
+                self.c.write('  &%s_%d,\n'%(prefix, m))
+                m += 1
+            self.c.write('  NULL\n'
+                         '};\n'
+                         '\n')
+        return n
+
+    def generate_args(self, prefix, args):
+        for a in args:
+            num_anno = self.generate_annotations('%s_arg_%s_annotation_info'%(prefix, a.name), a.annotations)
+
+            self.c.write('static const GDBusArgInfo %s_%s =\n'
+                         '{\n'
+                         '  -1,\n'
+                         '  "%s",\n'
+                         '  "%s",\n'%(prefix, a.name_lower, a.name, a.signature))
+            if num_anno == 0:
+                self.c.write('  NULL\n')
+            else:
+                self.c.write('  (GDBusAnnotationInfo **) &%s_arg_%s_annotation_info_pointers\n'%(prefix, a.name))
+            self.c.write('};\n'
+                         '\n')
+
+        if len(args) > 0:
+            self.c.write('static const GDBusArgInfo * const %s_pointers[] =\n'
+                             '{\n'%(prefix))
+            for a in args:
+                self.c.write('  &%s_%s,\n'%(prefix, a.name_lower))
+            self.c.write('  NULL\n'
+                         '};\n'
+                         '\n')
+
+    def generate_introspection_for_interface(self, i):
+            if len(i.methods) > 0:
+                for m in i.methods:
+                    self.generate_args('%s_method_info_%s_IN_ARG'%(self.namespace, m.name_lower), m.in_args)
+                    self.generate_args('%s_method_info_%s_OUT_ARG'%(self.namespace, m.name_lower), m.out_args)
+
+                    num_anno = self.generate_annotations('%s_method_%s_annotation_info'%(self.namespace, m.name_lower), m.annotations)
+
+                    self.c.write('static const GDBusMethodInfo %s_method_info_%s =\n'
+                                 '{\n'
+                                 '  -1,\n'
+                                 '  "%s",\n'%(self.namespace, m.name_lower, m.name))
+                    if len(m.in_args) == 0:
+                        self.c.write('  NULL,\n')
+                    else:
+                        self.c.write('  (GDBusArgInfo **) &%s_method_info_%s_IN_ARG_pointers,\n'%(self.namespace, m.name_lower))
+                    if len(m.out_args) == 0:
+                        self.c.write('  NULL,\n')
+                    else:
+                        self.c.write('  (GDBusArgInfo **) &%s_method_info_%s_OUT_ARG_pointers,\n'%(self.namespace, m.name_lower))
+                    if num_anno == 0:
+                        self.c.write('  NULL\n')
+                    else:
+                        self.c.write('  (GDBusAnnotationInfo **) &%s_method_%s_annotation_info_pointers\n'%(self.namespace, m.name_lower))
+                    self.c.write('};\n'
+                                 '\n')
+
+                self.c.write('static const GDBusMethodInfo * const %s_method_info_pointers[] =\n'
+                             '{\n'%(self.namespace))
+                for m in i.methods:
+                    self.c.write('  &%s_method_info_%s,\n'%(self.namespace, m.name_lower))
+                self.c.write('  NULL\n'
+                             '};\n'
+                             '\n')
+
+            if len(i.signals) > 0:
+                for s in i.signals:
+                    self.generate_args('%s_signal_info_%s_ARG'%(self.namespace, s.name_lower), s.args)
+
+                    num_anno = self.generate_annotations('%s_signal_%s_annotation_info'%(self.namespace, s.name_lower), s.annotations)
+                    self.c.write('static const GDBusSignalInfo %s_signal_info_%s =\n'
+                                 '{\n'
+                                 '  -1,\n'
+                                 '  "%s",\n'%(self.namespace, s.name_lower, s.name))
+                    if len(s.args) == 0:
+                        self.c.write('  NULL,\n')
+                    else:
+                        self.c.write('  (GDBusArgInfo **) &%s_signal_info_%s_ARG_pointers,\n'%(self.namespace, s.name_lower))
+                    if num_anno == 0:
+                        self.c.write('  NULL\n')
+                    else:
+                        self.c.write('  (GDBusAnnotationInfo **) &%s_signal_%s_annotation_info_pointers\n'%(self.namespace, s.name_lower))
+                    self.c.write('};\n'
+                                 '\n')
+
+                self.c.write('static const GDBusSignalInfo * const %s_signal_info_pointers[] =\n'
+                             '{\n'%(self.namespace))
+                for s in i.signals:
+                    self.c.write('  &%s_signal_info_%s,\n'%(self.namespace, s.name_lower))
+                self.c.write('  NULL\n'
+                             '};\n'
+                             '\n')
+
+            if len(i.properties) > 0:
+                for p in i.properties:
+                    if p.readable and p.writable:
+                        access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+                    elif p.readable:
+                        access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
+                    elif p.writable:
+                        access = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+                    else:
+                        access = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
+                    num_anno = self.generate_annotations('%s_property_%s_annotation_info'%(self.namespace, p.name_lower), p.annotations)
+                    self.c.write('static const GDBusPropertyInfo %s_property_info_%s =\n'
+                                 '{\n'
+                                 '  -1,\n'
+                                 '  "%s",\n'
+                                 '  "%s",\n'
+                                 '  %s,\n'%(self.namespace, p.name_lower, p.name, p.arg.signature, access))
+                    if num_anno == 0:
+                        self.c.write('  NULL\n')
+                    else:
+                        self.c.write('  (GDBusAnnotationInfo **) &%s_property_%s_annotation_info_pointers\n'%(self.namespace, p.name_lower))
+                    self.c.write('};\n'
+                                 '\n')
+
+                self.c.write('static const GDBusPropertyInfo * const %s_property_info_pointers[] =\n'
+                             '{\n'%(self.namespace))
+                for p in i.properties:
+                    self.c.write('  &%s_property_info_%s,\n'%(self.namespace, p.name_lower))
+                self.c.write('  NULL\n'
+                             '};\n'
+                             '\n')
+
+            num_anno = self.generate_annotations('%s_annotation_info'%(self.namespace), i.annotations)
+            self.c.write('static GDBusInterfaceInfo %s_interface_info =\n'
+                         '{\n'
+                         '  -1,\n'
+                         '  "%s",\n'%(self.namespace, i.name))
+            if len(i.methods) == 0:
+                self.c.write('  NULL,\n')
+            else:
+                self.c.write('  (GDBusMethodInfo **) &%s_method_info_pointers,\n'%(self.namespace))
+            if len(i.signals) == 0:
+                self.c.write('  NULL,\n')
+            else:
+                self.c.write('  (GDBusSignalInfo **) &%s_signal_info_pointers,\n'%(self.namespace))
+            if len(i.properties) == 0:
+                self.c.write('  NULL,\n')
+            else:
+                self.c.write('  (GDBusPropertyInfo **) &%s_property_info_pointers,\n'%(self.namespace))
+            if num_anno == 0:
+                self.c.write('  NULL\n')
+            else:
+                self.c.write('  (GDBusAnnotationInfo **) &%s_annotation_info_pointers\n'%(self.namespace))
+            self.c.write('};\n');
+
+    def generate(self):
+        for i in self.ifaces:
+            self.generate_introspection_for_interface(i)
+
============================================================
--- /dev/null	
+++ libpurple/dbus/dbusxml-to-c.py	5ff712182a0ad21ead8c0436ff0dd0b6c5a48dcf
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+
+# This file is a part of Purple.
+#
+# Purple is the legal property of its developers, whose names are too numerous
+# to list here.  Please refer to the COPYRIGHT file distributed with this
+# source distribution.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+
+import sys
+import parser
+import codegen
+
+if len(sys.argv) < 3:
+    print("Usage: %s file.xml c_prefix generated.c" % sys.argv[0])
+    sys.exit(1)
+
+f = open(sys.argv[1])
+xml_data = f.read()
+f.close()
+parsed_ifaces = parser.parse_dbus_xml(xml_data)
+
+namespace = sys.argv[2]
+c = open(sys.argv[3], 'w')
+gen = codegen.CodeGenerator(parsed_ifaces, namespace, c)
+gen.generate()
+sys.exit(0)
+
============================================================
--- /dev/null	
+++ libpurple/dbus/parser.py	fb6c24e82e7f3542c110500aadf8b1a49a82ef63
@@ -0,0 +1,264 @@
+# -*- Mode: Python -*-
+
+# GDBus - GLib D-Bus Library
+#
+# Copyright (C) 2008-2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# Author: David Zeuthen <davidz at redhat.com>
+
+# Shamelessly cut and pasted from the gdbus-codegen glib tool, with minor
+# modifications. Only the GDBusInterfaceVTable generation code is here.
+
+import sys
+import xml.parsers.expat
+
+def camel_case_to_uscore(s):
+    ret = ''
+    insert_uscore = False
+    prev_was_lower = False
+    for c in s:
+        if c.isupper():
+            if prev_was_lower:
+                insert_uscore = True
+            prev_was_lower = False
+        else:
+            prev_was_lower = True
+        if insert_uscore:
+            ret += '_'
+        ret += c.lower().replace('-', '_')
+        insert_uscore = False
+    return ret
+
+class Annotation:
+    def __init__(self, key, value):
+        self.key = key
+        self.value = value
+        self.annotations = []
+
+class Arg:
+    def __init__(self, name, signature):
+        self.name = name
+        self.signature = signature
+        self.annotations = []
+        self.name_lower = camel_case_to_uscore(name)
+
+class Method:
+    def __init__(self, name):
+        self.name = name
+        self.in_args = []
+        self.out_args = []
+        self.annotations = []
+        self.name_lower = camel_case_to_uscore(name)
+
+class Signal:
+    def __init__(self, name):
+        self.name = name
+        self.args = []
+        self.annotations = []
+        self.name_lower = camel_case_to_uscore(name)
+
+
+class Property:
+    def __init__(self, name, signature, access):
+        self.name = name
+        self.signature = signature
+        self.access = access
+        self.annotations = []
+        self.arg = Arg('value', self.signature)
+        self.arg.annotations = self.annotations
+        self.readable = False
+        self.writable = False
+        if self.access == 'readwrite':
+            self.readable = True
+            self.writable = True
+        elif self.access == 'read':
+            self.readable = True
+        elif self.access == 'write':
+            self.writable = True
+        else:
+            raise RuntimeError('Invalid access type %s'%self.access)
+        self.name_lower = camel_case_to_uscore(name)
+
+class Interface:
+    def __init__(self, name):
+        self.name = name
+        self.methods = []
+        self.signals = []
+        self.properties = []
+        self.annotations = []
+
+class DBusXMLParser:
+    STATE_TOP = 'top'
+    STATE_NODE = 'node'
+    STATE_INTERFACE = 'interface'
+    STATE_METHOD = 'method'
+    STATE_SIGNAL = 'signal'
+    STATE_PROPERTY = 'property'
+    STATE_ARG = 'arg'
+    STATE_ANNOTATION = 'annotation'
+
+    def __init__(self, xml_data):
+        self._parser = xml.parsers.expat.ParserCreate()
+        self._parser.CharacterDataHandler = self.handle_char_data
+        self._parser.StartElementHandler = self.handle_start_element
+        self._parser.EndElementHandler = self.handle_end_element
+
+        self.parsed_interfaces = []
+        self._cur_object = None
+
+        self.state = DBusXMLParser.STATE_TOP
+        self.state_stack = []
+        self._cur_object = None
+        self._cur_object_stack = []
+
+        self._parser.Parse(xml_data)
+
+    COMMENT_STATE_BEGIN = 'begin'
+    COMMENT_STATE_PARAMS = 'params'
+    COMMENT_STATE_BODY = 'body'
+    COMMENT_STATE_SKIP = 'skip'
+
+    def handle_char_data(self, data):
+        #print 'char_data=%s'%data
+        pass
+
+    def handle_start_element(self, name, attrs):
+        old_state = self.state
+        old_cur_object = self._cur_object
+        if self.state == DBusXMLParser.STATE_TOP:
+            if name == DBusXMLParser.STATE_NODE:
+                self.state = DBusXMLParser.STATE_NODE
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+        elif self.state == DBusXMLParser.STATE_NODE:
+            if name == DBusXMLParser.STATE_INTERFACE:
+                self.state = DBusXMLParser.STATE_INTERFACE
+                iface = Interface(attrs['name'])
+                self._cur_object = iface
+                self.parsed_interfaces.append(iface)
+            elif name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = parser.Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+
+        elif self.state == DBusXMLParser.STATE_INTERFACE:
+            if name == DBusXMLParser.STATE_METHOD:
+                self.state = DBusXMLParser.STATE_METHOD
+                method = Method(attrs['name'])
+                self._cur_object.methods.append(method)
+                self._cur_object = method
+            elif name == DBusXMLParser.STATE_SIGNAL:
+                self.state = DBusXMLParser.STATE_SIGNAL
+                signal = Signal(attrs['name'])
+                self._cur_object.signals.append(signal)
+                self._cur_object = signal
+            elif name == DBusXMLParser.STATE_PROPERTY:
+                self.state = DBusXMLParser.STATE_PROPERTY
+                prop = Property(attrs['name'], attrs['type'], attrs['access'])
+                self._cur_object.properties.append(prop)
+                self._cur_object = prop
+            elif name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+
+        elif self.state == DBusXMLParser.STATE_METHOD:
+            if name == DBusXMLParser.STATE_ARG:
+                self.state = DBusXMLParser.STATE_ARG
+                arg_name = None
+                if 'name' in attrs:
+                    arg_name = attrs['name']
+                arg = Arg(arg_name, attrs['type'])
+                direction = attrs['direction']
+                if direction == 'in':
+                    self._cur_object.in_args.append(arg)
+                elif direction == 'out':
+                    self._cur_object.out_args.append(arg)
+                else:
+                    raise RuntimeError('Invalid direction "%s"'%(direction))
+                self._cur_object = arg
+            elif name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+
+
+        elif self.state == DBusXMLParser.STATE_SIGNAL:
+            if name == DBusXMLParser.STATE_ARG:
+                self.state = DBusXMLParser.STATE_ARG
+                arg_name = None
+                if 'name' in attrs:
+                    arg_name = attrs['name']
+                arg = Arg(arg_name, attrs['type'])
+                self._cur_object.args.append(arg)
+                self._cur_object = arg
+            elif name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+
+
+        elif self.state == DBusXMLParser.STATE_PROPERTY:
+            if name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+        elif self.state == DBusXMLParser.STATE_ARG:
+            if name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+        elif self.state == DBusXMLParser.STATE_ANNOTATION:
+            if name == DBusXMLParser.STATE_ANNOTATION:
+                self.state = DBusXMLParser.STATE_ANNOTATION
+                anno = Annotation(attrs['name'], attrs['value'])
+                self._cur_object.annotations.append(anno)
+                self._cur_object = anno
+            else:
+                raise RuntimeError('Cannot go from state "%s" to element with name "%s"'%(self.state, name))
+        else:
+            raise RuntimeError('Unhandled state "%s" while entering element with name "%s"'%(self.state, name))
+
+        self.state_stack.append(old_state)
+        self._cur_object_stack.append(old_cur_object)
+
+    def handle_end_element(self, name):
+        self.state = self.state_stack.pop()
+        self._cur_object = self._cur_object_stack.pop()
+
+def parse_dbus_xml(xml_data):
+    parser = DBusXMLParser(xml_data)
+    return parser.parsed_interfaces


More information about the Commits mailing list