Orb/Doxygen/src/dbusxmlscanner.cpp
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Orb/Doxygen/src/dbusxmlscanner.cpp	Thu Jan 21 17:29:01 2010 +0000
@@ -0,0 +1,889 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#include "dbusxmlscanner.h"
+
+#include "commentscan.h"
+#include "entry.h"
+
+#include <qfile.h>
+#include <qxml.h>
+#include <qstring.h>
+
+#include "message.h"
+#include "util.h"
+
+// -----------------------------------------------------------------------
+// Convenience defines:
+// -----------------------------------------------------------------------
+
+#define CONDITION(cond, msg) \
+    do {\
+        if (cond)\
+        {\
+            if (m_errorString.isEmpty()) { m_errorString = msg; }\
+            return false;\
+        }\
+    }\
+    while (0)
+
+#define DOC_ERROR(msg) \
+    warn_doc_error(m_fileName.utf8().data(), lineNumber(), msg.utf8().data())
+
+#define COND_DOC_ERROR(cond, msg) \
+    do {\
+        if (cond)\
+        {\
+             DOC_ERROR(msg);\
+             return true;\
+        }\
+    }\
+    while (0)
+
+#define DBUS(name) isDBusElement(namespaceURI, localName, qName, name)
+#define EXTENSION(name) isExtensionElement(namespaceURI, localName, qName, name)
+
+// -----------------------------------------------------------------------
+// DBusXMLHandler class
+// -----------------------------------------------------------------------
+
+const QString EXTENSION_URI("http://psiamp.org/dtd/doxygen_dbusxml.dtd");
+
+class DBusXMLHandler : public QXmlDefaultHandler
+{
+public:
+    DBusXMLHandler(ParserInterface * parser,
+                   QXmlSimpleReader * reader,
+                   const char * file_name,
+                   Entry * root) :
+        m_parser(parser),
+        m_locator(reader),
+        m_currentEntry(0),
+        m_currentInterface(0),
+        m_currentMethod(0),
+        m_currentArgument(0),
+        m_currentProperty(0),
+        m_currentEnum(0),
+        m_fileName(file_name),
+        m_currentComment(0)
+    {
+        setDocumentLocator(&m_locator);
+
+        m_scopeCount = 0;
+
+        // Set up stack cleanup:
+        m_structStack.setAutoDelete(TRUE);
+        m_elementStack.setAutoDelete(TRUE);
+        m_scopeStack.setAutoDelete(TRUE);
+
+        openScopes(root);
+    }
+
+    ~DBusXMLHandler()
+    { closeScopes(); }
+
+    QString errorString()
+    { return m_errorString; }
+
+    bool startElement(const QString &namespaceURI,
+                      const QString &localName,
+                      const QString &qName,
+                      const QXmlAttributes &attributes)
+    {
+        // add to elements stack:
+        m_elementStack.append(new ElementData(qName));
+
+        // First we need a node.
+        if (DBUS("node"))
+        {
+            CONDITION(!m_currentNode.isEmpty(), "Node inside a node.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous node found."));
+
+            m_currentNode = attributes.value(idx);
+            // A node is actually of little interest, so do nothing here.
+            return true;
+        }
+
+        // Then we need an interface.
+        if (DBUS("interface"))
+        {
+            // We need a nodeName for interfaces:
+            CONDITION(m_currentNode.isEmpty(), "Interface without a node.");
+            CONDITION(m_currentInterface, "Interface within another interface.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Interface without a name found."));
+
+            // A interface is roughly equivalent to a class:
+            m_currentInterface = createEntry();
+
+            m_currentInterface->section = Entry::CLASS_SEC;
+            m_currentInterface->spec |= Entry::Interface;
+            m_currentInterface->type = "Interface";
+            m_currentInterface->name = substitute(attributes.value(idx), ".", "::");
+
+            openScopes(m_currentInterface);
+
+            return true;
+        }
+
+        if (DBUS("method") || DBUS("signal"))
+        {
+            // We need a interfaceName for methods and signals:
+            CONDITION(!m_currentInterface, "Method or signal found outside a interface.");
+            CONDITION(m_currentMethod, "Method or signal found inside another method or signal.");
+            CONDITION(m_currentProperty, "Methor or signal found inside a property.");
+            CONDITION(!m_structStack.isEmpty(), "Method or signal found inside a struct.");
+            CONDITION(m_currentEnum, "Methor or signal found inside a enum.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Method or signal without a name found."));
+
+            m_currentMethod = createEntry();
+
+            m_currentMethod->section = Entry::FUNCTION_SEC;
+            m_currentMethod->name = attributes.value(idx);
+            m_currentMethod->mtype = Method;
+            m_currentMethod->type = "void";
+
+            if (DBUS("signal"))
+            { m_currentMethod->mtype = Signal; }
+        }
+
+        if (DBUS("arg"))
+        {
+            // We need a method for arguments:
+            CONDITION(!m_currentMethod, "Argument found outside a method or signal.");
+            CONDITION(m_currentArgument, "Argument found inside another argument.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Argument without a name found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Argument without a type found."));
+
+            const int direction_idx(indexOf(attributes, "direction"));
+
+            if ((m_currentMethod->mtype == Signal &&
+                 direction_idx >= 0 &&
+                 attributes.value(direction_idx) != "in") ||
+                (m_currentMethod->mtype == Method &&
+                 direction_idx >= 0 &&
+                 attributes.value(direction_idx) != "in" &&
+                 attributes.value(direction_idx) != "out"))
+            {
+                m_errorString = "Invalid direction found.";
+                return false;
+            }
+
+            m_currentArgument = new Argument;
+            m_currentArgument->type = getType(attributes);
+            m_currentArgument->name = attributes.value(name_idx);
+            if (direction_idx >= 0)
+            { m_currentArgument->attrib = attributes.value(direction_idx); }
+            else
+            {
+                if (m_currentMethod->mtype == Signal)
+                { m_currentArgument->attrib = "in"; }
+                else
+                { m_currentArgument->attrib = "out"; }
+            }
+        }
+
+        if (DBUS("property"))
+        {
+            CONDITION(m_currentMethod, "Property found inside a method or signal.");
+            CONDITION(!m_currentInterface, "Property found outside an interface.");
+            CONDITION(m_currentProperty, "Property found inside another property.");
+            CONDITION(!m_structStack.isEmpty(), "Property found inside a struct.");
+            CONDITION(m_currentEnum, "Property found inside a enum.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous property found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Property without a type found."));
+
+            const int access_idx(indexOf(attributes, "access"));
+            COND_DOC_ERROR(access_idx < 0, QString("Property without a access attribute found."));
+            COND_DOC_ERROR(attributes.value(access_idx) != "read" &&
+                           attributes.value(access_idx) != "write" &&
+                           attributes.value(access_idx) != "readwrite",
+                           QString("Property with invalid access attribute \"%1\" found.").
+                           arg(attributes.value(access_idx)));
+
+            m_currentProperty = createEntry();
+
+            m_currentProperty->section = Entry::FUNCTION_SEC;
+
+            if (attributes.value(access_idx) == "read" ||
+                attributes.value(access_idx) == "readwrite")
+            { m_currentProperty->spec |= Entry::Readable; }
+
+            if (attributes.value(access_idx) == "write" ||
+                attributes.value(access_idx) == "readwrite")
+            { m_currentProperty->spec |= Entry::Writable; }
+
+            m_currentProperty->name = attributes.value(name_idx);
+            m_currentProperty->mtype = Property;
+            m_currentProperty->type = getType(attributes);
+        }
+
+        if (EXTENSION("namespace"))
+        {
+            CONDITION(m_currentNode.isEmpty(), "Namespace found outside a node.");
+            CONDITION(m_currentInterface, "Namespace found inside an interface.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous namespace found."));
+
+            m_namespaceStack.append(openNamespace(attributes.value(idx)));
+            openScopes(m_namespaceStack.last());
+        }
+
+        if (EXTENSION("struct"))
+        {
+            CONDITION(m_currentMethod, "Struct found inside a method or signal.");
+            CONDITION(m_currentProperty, "Struct found inside a property.");
+            CONDITION(m_currentEnum, "Struct found inside an enum.");
+
+            const int idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(idx < 0, QString("Anonymous struct found."));
+
+            Entry * current_struct = createEntry();
+            current_struct->section = Entry::CLASS_SEC;
+            current_struct->spec = Entry::Struct;
+            current_struct->name = attributes.value(idx);
+
+            openScopes(current_struct);
+
+            current_struct->type = current_struct->name + " struct";
+
+            m_structStack.append(new StructData(current_struct));
+        }
+
+        if (EXTENSION("member"))
+        {
+            CONDITION(m_structStack.isEmpty(), "Member found outside of struct.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous member found."));
+            COND_DOC_ERROR(!hasType(attributes), QString("Member without a type found."));
+
+            createEntry();
+
+            m_currentEntry->section = Entry::VARIABLE_SEC;
+            m_currentEntry->name = attributes.value(name_idx);
+            m_currentEntry->type = getType(attributes);
+
+            QString type(getDBusType(m_currentEntry->type));
+            m_structStack.last()->type.append(type);
+        }
+
+        if (EXTENSION("enum") || EXTENSION("flagset"))
+        {
+            CONDITION(m_currentMethod, "Enum found inside a method or signal.");
+            CONDITION(m_currentProperty, "Enum found inside a property.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous enum found."));
+
+            const int type_idx(indexOf(attributes, "type"));
+            QString type = "u";
+            if (type_idx >= 0)
+            { type = attributes.value(type_idx); }
+            if (type != "y" && type != "q" && type != "u" && type != "t")
+            { DOC_ERROR(QString("Invalid enum type \"%1\" found.").arg(type)); }
+
+            m_currentEnum = createEntry();
+            m_currentEnum->section = Entry::ENUM_SEC;
+            m_currentEnum->name = attributes.value(name_idx);
+
+            openScopes(m_currentEnum);
+
+            m_currentEnum->type = m_currentEntry->name + " enum";
+
+            addNamedType(type);
+        }
+
+        if (EXTENSION("value"))
+        {
+            CONDITION(!m_currentEnum, "Value found outside an enum.");
+
+            const int name_idx(indexOf(attributes, "name"));
+            COND_DOC_ERROR(name_idx < 0, QString("Anonymous value found."));
+
+            const int value_idx(indexOf(attributes, "value"));
+
+            createEntry();
+
+            m_currentEntry->section = Entry::VARIABLE_SEC;
+            m_currentEntry->name = attributes.value(name_idx);
+            m_currentEntry->type = m_currentEnum->name; // "@"; // enum marker!
+            if (value_idx >= 0)
+            { m_currentEntry->initializer = attributes.value(value_idx); }
+        }
+
+        return true;
+    }
+
+    bool endElement(const QString &namespaceURI,
+                    const QString &localName,
+                    const QString &qName)
+    {
+        // Clean up elements stack:
+        // Since we made sure to get the elements in the proper order when
+        // adding we do not need to do so again here.
+        COND_DOC_ERROR(m_elementStack.last()->element != qName,
+                       QString("Malformed XML: Unexpected closing element found.").
+                       arg(m_elementStack.last()->element));
+        m_elementStack.removeLast();
+
+        // Interface:
+        if (DBUS("interface"))
+        {
+            CONDITION(m_currentInterface, "end of interface found without start.");
+            m_currentInterface->endBodyLine = lineNumber();
+            closeScopes();
+            m_currentInterface = 0;
+        }
+
+        if (DBUS("method") || DBUS("signal"))
+        {
+            CONDITION(m_currentMethod, "end of method found without start.");
+            CONDITION(m_currentInterface, "end of method found outside interface.");
+            m_currentMethod->endBodyLine = lineNumber();
+            m_currentInterface->addSubEntry(m_currentMethod);
+            m_currentMethod = 0;
+        }
+
+        if (DBUS("property"))
+        {
+            CONDITION(m_currentMethod, "end of property found without start.");
+            CONDITION(m_currentInterface, "end of property found outside interface.");
+            m_currentProperty->endBodyLine = lineNumber();
+            m_currentInterface->addSubEntry(m_currentProperty);
+            m_currentProperty = 0;
+        }
+
+        if (DBUS("arg"))
+        {
+            CONDITION(m_currentMethod, "end of arg found outside method.");
+            m_currentMethod->argList->append(m_currentArgument);
+            m_currentArgument = 0;
+        }
+
+        if (EXTENSION("namespace"))
+        {
+            Entry * current = m_namespaceStack.last();
+            CONDITION(current, "end of namespace without start.");
+            m_namespaceStack.removeLast();
+
+            current->endBodyLine = lineNumber();
+            closeScopes();
+        }
+
+        if (EXTENSION("struct"))
+        {
+            StructData * data = m_structStack.last();
+            CONDITION(data, "end of struct without start.");
+
+            data->entry->endBodyLine = lineNumber();
+
+            QString current_type;
+            current_type.append(QString("("));
+            current_type.append(data->type);
+            current_type.append(QString(")"));
+
+            addNamedType(current_type);
+
+            closeScopes();
+
+            m_structStack.removeLast();
+        }
+
+        if (EXTENSION("member"))
+        {
+           StructData * data = m_structStack.last();
+           CONDITION(data, "end of struct without start");
+           data->entry->addSubEntry(m_currentEntry);
+        }
+
+        if (EXTENSION("enum") || EXTENSION("flagset"))
+        {
+            CONDITION(m_currentEnum, "end of enum without start");
+            m_currentEnum->endBodyLine = lineNumber();
+            closeScopes();
+
+            m_currentEnum = 0;
+        }
+
+        if (EXTENSION("value"))
+        {
+            CONDITION(m_currentEntry, "end of value without start");
+            m_currentEntry->endBodyLine = lineNumber();
+
+            m_currentEnum->addSubEntry(m_currentEntry);
+        }
+
+        return true;
+    }
+
+    bool characters(const QString & /*chars*/)
+    { return true; }
+
+    bool comment(const QString & comment_)
+    {
+        if (m_currentComment)
+        { handleComment(); }
+
+        m_currentComment = new CommentData(m_fileName, lineNumber(), comment_);
+
+        if (!m_currentComment->shouldIgnore)
+        {
+            delete m_currentComment;
+            m_currentComment = 0;
+            return true;
+        }
+
+        if (m_currentComment->associateWithPrevious)
+        { handleComment(); }
+
+        return true;
+    }
+
+    void handleComment()
+    {
+        if (m_currentComment == 0 || m_currentEntry == 0)
+        { return; }
+
+        QCString text(m_currentComment->text);
+
+        m_currentEntry->docFile = m_currentComment->fileName;
+        m_currentEntry->docLine = m_currentComment->line;
+
+        int position(0);
+        bool needs_entry(false);
+        bool brief(false);
+        Protection prot(Public);
+        int lineNr = lineNumber();
+
+        while (parseCommentBlock(m_parser,
+                                 m_currentEntry,
+                                 text, m_fileName.utf8().data(), 
+                                 lineNr,
+                                 brief, m_currentComment->isJavaStyle,
+                                 false,
+                                 prot,
+                                 position,
+                                 needs_entry))
+        {
+            if (needs_entry) { createEntry(); }
+        }
+        if (needs_entry) { createEntry(); }
+
+        delete m_currentComment;
+        m_currentComment = 0;
+    }
+
+    QXmlLocator * locator()
+    { return &m_locator; }
+
+    int lineNumber()
+    { return m_locator.lineNumber(); }
+
+    void setSection()
+    {
+        Entry * current = createEntry();
+        current->reset();
+
+        current->name    = m_fileName.utf8();
+        current->section = Entry::SOURCE_SEC;
+
+        // Open/Close the scope to do the bookkeeping:
+        openScopes(current);
+        closeScopes();
+    }
+
+private:
+    bool isDBusElement(const QString & namespaceURI,
+                       const QString & localName,
+                       const QString & qName,
+                       const QString & element)
+    {
+        return (namespaceURI.isEmpty() && localName == element && qName == element) ||
+               (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);
+    }
+
+    bool isExtensionElement(const QString & namespaceURI,
+                            const QString & localName,
+                            const QString & qName,
+                            const QString & element)
+    {
+        // isNull happens in startelement if no URI is used.
+        if (namespaceURI.isNull())
+        { return false; }
+
+        // We are in a endElement: URI is always empty there:-(
+        if (namespaceURI.isEmpty())
+        { return qName == m_scopeStack.last()->extensionPrefix + element; }
+
+        // startElemennt: We need to save the qName prefix
+        // since endElement will forget about the namespaceURi:-(
+        if (namespaceURI == EXTENSION_URI)
+        {
+            int pos = qName.find(':');
+            m_scopeStack.last()->extensionPrefix = qName.left(pos + 1);
+        }
+
+        return namespaceURI == EXTENSION_URI && localName == element;
+    }
+
+    bool hasType(const QXmlAttributes & attributes)
+    {
+        const int type_idx(indexOf(attributes, "type"));
+        const int named_type_idx(indexOf(attributes, "named-type"));
+
+        return named_type_idx >= 0 || type_idx >= 0;
+    }
+
+    QString getType(const QXmlAttributes & attributes)
+    {
+        const int type_idx(indexOf(attributes, "type"));
+        const int named_type_idx(indexOf(attributes, "named-type"));
+
+        QString type;
+
+        if (named_type_idx >= 0)
+        {
+            type = attributes.value(named_type_idx);
+            if (!type.startsWith("::"))
+            { type = getCurrentScope(attributes.value(named_type_idx)); }
+            else
+            { type = type.mid(2); }
+            if (m_namedTypeMap.contains(type))
+            {
+                if (type_idx >= 0)
+                {
+                    const QString dbus_type(attributes.value(type_idx));
+                    if (dbus_type != m_namedTypeMap[type])
+                    {
+                        DOC_ERROR(QString("Type \"%1\" does not match up with "
+                                          "previous definition of named type \"%2\" (which was \"%3\".").
+                                          arg(dbus_type).
+                                          arg(type).
+                                          arg(m_namedTypeMap[type]));
+                    }
+                }
+                return type;
+            }
+
+            DOC_ERROR(QString("Undefined named type \"%1\" used.").arg(type));
+        }
+
+        if (type_idx >= 0)
+        {
+            type = attributes.value(type_idx);
+
+            QRegExp reg_exp(QString("(a?[ybnqiuxdtsogv]|a[{]sv[}])"));
+            if (reg_exp.match(type))
+            { return type; }
+
+            DOC_ERROR(QString("Unnamed complex D-Bus type \"%1\" found.").arg(type));
+        }
+
+        return QString();
+    }
+
+    QString getDBusType(const QString & type)
+    {
+        QString scoped_type = type;
+        if (!scoped_type.contains("::"))
+        { scoped_type = getCurrentScope(type); }
+
+        if (m_namedTypeMap.contains(scoped_type))
+        { return m_namedTypeMap[scoped_type]; }
+        else
+        { return type; }
+    }
+
+    void addNamedType(const QString type)
+    {
+        QString scoped_name(getCurrentScope());
+
+        if (m_namedTypeMap.contains(scoped_name))
+        {
+            DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name));
+            return;
+        }
+
+        m_namedTypeMap.insert(scoped_name, type);
+    }
+
+    QString getCurrentScope(const QString & type = QString())
+    {
+        QString scoped_name;
+        if (!m_scopeStack.isEmpty())
+        {
+            scoped_name = m_scopeStack.last()->scope->name;
+            scoped_name.append("::");
+        }
+        if (!type.isEmpty())
+        { scoped_name.append(type); }
+        else
+        { scoped_name = scoped_name.left(scoped_name.length() - 2); }
+
+        return scoped_name;
+    }
+
+    int indexOf(const QXmlAttributes & attributes, const QString & name,
+                 const QString & type = "CDATA", const bool mandatory = true)
+    {
+        const int idx(attributes.index(name));
+        if (idx < 0 || idx > attributes.length()) { return -1; }
+        if (attributes.type(idx) != type) { return -1; }
+        if (mandatory && attributes.value(idx).isEmpty()) { return -1; }
+
+        return idx;
+    }
+
+    Entry * createEntry()
+    {
+        Entry * entry = new Entry();
+
+        entry->protection = Public ;
+        entry->virt       = Normal;
+        entry->stat       = false;
+        entry->objc       = false;
+        entry->spec       = 0;
+
+        entry->fileName  = m_fileName;
+        entry->startLine = lineNumber();
+        entry->bodyLine = lineNumber();
+
+        entry->callGraph = false;
+        entry->callerGraph = false;
+
+        initGroupInfo(entry);
+
+        m_currentEntry = entry;
+
+        handleComment();
+
+        return entry;
+    }
+
+    void openScopes(Entry * object)
+    {
+        int cur_scope_separator_pos = 0;
+        int last_scope_separator_pos = 0;
+        while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos)))
+        {
+            QString scope = object->name.mid(last_scope_separator_pos,
+                                             cur_scope_separator_pos - last_scope_separator_pos);
+            last_scope_separator_pos = cur_scope_separator_pos + 2;
+
+            Entry * current_namespace = openNamespace(scope);
+
+            if (!m_scopeStack.isEmpty())
+            { m_scopeStack.last()->scope->addSubEntry(current_namespace); }
+
+            m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount));
+        }
+
+        QString scoped_name(getCurrentScope());
+        if (!scoped_name.isEmpty())
+        { scoped_name.append("::"); }
+        scoped_name.append(object->name.mid(last_scope_separator_pos));
+
+        object->name = scoped_name;
+
+        if (!m_scopeStack.isEmpty())
+        { m_scopeStack.last()->scope->addSubEntry(object); }
+        m_scopeStack.append(new ScopeData(object, m_scopeCount));
+
+        ++m_scopeCount;
+    }
+
+    Entry * openNamespace(const QString & name)
+    {
+        Entry * current_namespace = createEntry();
+        QString scoped_name(getCurrentScope());
+        if (!scoped_name.isEmpty())
+        { scoped_name.append("::"); }
+        scoped_name.append(name);
+        current_namespace->name = scoped_name;
+        current_namespace->section = Entry::NAMESPACE_SEC;
+        current_namespace->type = "namespace" ;
+
+        return current_namespace;
+    }
+
+    void closeScopes()
+    {
+        const int current_scope_count(m_scopeStack.last()->count);
+
+        // Do not close the root scope.
+        if (current_scope_count == 0)
+        { return; }
+
+        while (current_scope_count == m_scopeStack.last()->count)
+        { m_scopeStack.removeLast(); }
+    }
+
+    ParserInterface * m_parser;
+
+    QXmlLocator m_locator;
+    QString m_currentNode; // Nodes can not be nested, no entry necessary.
+
+    struct ElementData
+    {
+        ElementData(const QString & e) :
+            element(e)
+        { }
+        ~ElementData() { }
+
+        QString element; //*< The element name
+        QString extensionPrefix; //*< The prefix used for our extension.
+        QString text; //*< The actual xml code.
+    };
+    QList<ElementData> m_elementStack;
+
+    Entry * m_currentEntry; // The currently open entry.
+
+    Entry * m_currentInterface; // Interfaces can not be nested.
+    Entry * m_currentMethod; // Methods can not be nested.
+    Argument * m_currentArgument; // Arguments can not be nested.
+    Entry * m_currentProperty; // Properties can not be nested.
+    Entry * m_currentEnum; // Enums can not be nested.
+    QList<Entry> m_namespaceStack;
+
+    struct StructData
+    {
+        StructData(Entry * e) : entry(e) { }
+        ~StructData() { }
+
+        QString type;
+        Entry * entry;
+    };
+    QList<StructData> m_structStack; // Structs can be nested.
+
+    struct ScopeData
+    {
+        ScopeData(Entry * s, int c) :
+            scope(s),
+            count(c)
+        { }
+        ~ScopeData() { }
+
+        Entry * scope;
+        QString extensionPrefix;
+        int count;
+    };
+    QList<ScopeData> m_scopeStack; // Scopes are nested.
+
+    QString m_fileName;
+
+    struct CommentData
+    {
+        CommentData(const QString & f, const int l, const QString & t) :
+            isJavaStyle(false),
+            isQtStyle(false),
+            line(l),
+            fileName(f)
+        {
+            isJavaStyle = t.startsWith(QChar('*'));
+            isQtStyle = t.startsWith(QChar('!'));
+            shouldIgnore = (!isJavaStyle && !isQtStyle);
+            associateWithPrevious = (t.at(1) == QChar('<'));
+            if (associateWithPrevious)
+            { text = t.mid(2); }
+            else
+            { text = t.mid(1); }
+        }
+        ~CommentData() { }
+
+        QString text;
+        bool isJavaStyle;
+        bool isQtStyle;
+        bool shouldIgnore;
+        bool associateWithPrevious;
+        int line;
+        QString fileName;
+    };
+    CommentData * m_currentComment;
+
+    int m_scopeCount; //*< unique scope id.
+
+    QString m_errorString;
+
+    QMap<QString, QString> m_namedTypeMap;
+};
+
+// -----------------------------------------------------------------------
+// DBusXMLScanner
+// -----------------------------------------------------------------------
+
+DBusXMLScanner::DBusXMLScanner()
+{ }
+
+DBusXMLScanner::~DBusXMLScanner()
+{ }
+
+void DBusXMLScanner::parseInput(const char * fileName,
+                                const char * /* fileBuf */,
+                                Entry * root)
+{
+    QFile inputFile(fileName);
+
+    QXmlInputSource inputSource(inputFile);
+    QXmlSimpleReader reader;
+
+    DBusXMLHandler handler(this, &reader, fileName, root);
+    reader.setContentHandler(&handler);
+    reader.setErrorHandler(&handler);
+    reader.setLexicalHandler(&handler);
+
+    groupEnterFile(fileName, 1);
+    handler.setSection();
+    reader.parse(inputSource);
+
+    if (handler.errorString())
+    { err("DBus XML Parser: Error at line %d: %s\n", 
+        handler.locator()->lineNumber(),handler.errorString().utf8().data()); }
+
+    groupLeaveFile(fileName, 1);
+}
+
+bool DBusXMLScanner::needsPreprocessing(const QCString & /* extension */)
+{ return (false); }
+
+void DBusXMLScanner::parseCode(CodeOutputInterface & /* codeOutIntf */,
+                               const char * /* scopeName */,
+                               const QCString & /* input */,
+                               bool /* isExampleBlock */,
+                               const char * /* exampleName */,
+                               FileDef * /* fileDef */,
+                               int /* startLine */,
+                               int /* endLine */,
+                               bool /* inlineFragment */,
+                               MemberDef * /* memberDef */)
+{ }
+
+void DBusXMLScanner::resetCodeParserState()
+{ }
+
+void DBusXMLScanner::parsePrototype(const char * /* text */)
+{ }