Remove dependency of QtDBus onto QtXml
authorHarald Fernengel <harald.fernengel@nokia.com>
Wed, 18 Jan 2012 20:28:31 +0000 (21:28 +0100)
committerQt by Nokia <qt-info@nokia.com>
Sun, 22 Jan 2012 21:10:02 +0000 (22:10 +0100)
Replace the QDom based code in qdbusxmlparser
with code using QXmlStreamReader.

Task-number: QTBUG-20856
Change-Id: I294e3ebd6faa813c20806be3ae225ac00befb622
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
src/dbus/dbus.pro
src/dbus/qdbusintrospection.cpp
src/dbus/qdbusintrospection_p.h
src/dbus/qdbusxmlparser.cpp
src/dbus/qdbusxmlparser_p.h
src/modules/qt_dbus.pri
src/src.pro
tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp

index 8669bb0..6fd48de 100644 (file)
@@ -2,8 +2,7 @@ load(qt_module)
 
 TARGET = QtDBus
 QPRO_PWD = $$PWD
-QT = core-private \
-    xml
+QT = core-private
 
 CONFIG += link_pkgconfig module
 MODULE_PRI = ../modules/qt_dbus.pri
@@ -21,8 +20,7 @@ unix|win32-g++* {
     QMAKE_PKGCONFIG_DESCRIPTION = Qt \
         DBus \
         module
-    QMAKE_PKGCONFIG_REQUIRES = QtCore \
-        QtXml
+    QMAKE_PKGCONFIG_REQUIRES = QtCore
 }
 win32 { 
     wince*:LIBS_PRIVATE += -lws2
index 23eda78..60e3bb9 100644 (file)
@@ -407,23 +407,6 @@ QDBusIntrospection::parseObject(const QString &xml, const QString &service, cons
     return *retval;
 }
 
-/*!
-    Parses the XML document fragment (given by \a xml) containing one object node and returns all
-    the information about the interfaces and sub-objects, found at the service \a service and path
-    \a path.
-
-    The Objects map returned will contain the absolute path names in the key.
-*/
-QDBusIntrospection::ObjectTree
-QDBusIntrospection::parseObjectTree(const QString &xml, const QString &service, const QString &path)
-{
-    QDBusXmlParser parser(service, path, xml);
-    QSharedDataPointer<QDBusIntrospection::ObjectTree> retval = parser.objectTree();
-    if (!retval)
-        return QDBusIntrospection::ObjectTree();
-    return *retval;
-}
-
 QT_END_NAMESPACE
 
 #endif // QT_NO_DBUS
index 025cf63..780e706 100644 (file)
@@ -59,7 +59,7 @@
 #include <QtCore/qmap.h>
 #include <QtCore/qpair.h>
 #include <QtCore/qshareddata.h>
-#include <qdbusmacros.h>
+#include "qdbusmacros.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -150,26 +150,16 @@ public:
     {
         QString service;
         QString path;
-        QString introspection;
 
         QStringList interfaces;
         QStringList childObjects;
     };
 
-    struct ObjectTree: public Object
-    {
-        Interfaces interfaceData;
-        Objects childObjectData;
-    };
-
 public:
     static Interface parseInterface(const QString &xml);
     static Interfaces parseInterfaces(const QString &xml);
     static Object parseObject(const QString &xml, const QString &service = QString(),
                               const QString &path = QString());
-    static ObjectTree parseObjectTree(const QString &xml,
-                                      const QString &service,
-                                      const QString &path);
 
 private:
     QDBusIntrospection();
index b1d0b78..b563fa9 100644 (file)
 ****************************************************************************/
 
 #include "qdbusxmlparser_p.h"
-#include "qdbusinterface.h"
-#include "qdbusinterface_p.h"
-#include "qdbusconnection_p.h"
 #include "qdbusutil_p.h"
 
-#include <QtXml/qdom.h>
 #include <QtCore/qmap.h>
 #include <QtCore/qvariant.h>
 #include <QtCore/qtextstream.h>
+#include <QtCore/qxmlstream.h>
+#include <QtCore/qdebug.h>
 
 #ifndef QT_NO_DBUS
 
 //#define QDBUS_PARSER_DEBUG
 #ifdef QDBUS_PARSER_DEBUG
-# define qDBusParserError qWarning
+# define qDBusParserError qDebug
 #else
 # define qDBusParserError if (true) {} else qDebug
 #endif
 
 QT_BEGIN_NAMESPACE
 
-static QDBusIntrospection::Annotations
-parseAnnotations(const QDomElement& elem)
+static bool parseArg(const QXmlStreamAttributes &attributes, QDBusIntrospection::Argument &argData)
 {
-    QDBusIntrospection::Annotations retval;
-    QDomNodeList list = elem.elementsByTagName(QLatin1String("annotation"));
-    for (int i = 0; i < list.count(); ++i)
-    {
-        QDomElement ann = list.item(i).toElement();
-        if (ann.isNull())
-            continue;
-
-        QString name = ann.attribute(QLatin1String("name")),
-               value = ann.attribute(QLatin1String("value"));
-
-        if (!QDBusUtil::isValidInterfaceName(name)) {
-            qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
-                             qPrintable(name));
-            continue;
-        }
+    const QString argType = attributes.value(QLatin1String("type")).toString();
 
-        retval.insert(name, value);
+    bool ok = QDBusUtil::isValidSingleSignature(argType);
+    if (!ok) {
+        qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
+                qPrintable(argType));
     }
 
-    return retval;
+    argData.name = attributes.value(QLatin1String("name")).toString();
+    argData.type = argType;
+
+    return ok;
 }
 
-static QDBusIntrospection::Arguments
-parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty)
+static bool parseAnnotation(const QXmlStreamReader &xml, QDBusIntrospection::Annotations &annotations)
 {
-    QDBusIntrospection::Arguments retval;
-    QDomNodeList list = elem.elementsByTagName(QLatin1String("arg"));
-    for (int i = 0; i < list.count(); ++i)
-    {
-        QDomElement arg = list.item(i).toElement();
-        if (arg.isNull())
-            continue;
-
-        if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
-            arg.attribute(QLatin1String("direction")) == direction) {
-
-            QDBusIntrospection::Argument argData;
-            if (arg.hasAttribute(QLatin1String("name")))
-                argData.name = arg.attribute(QLatin1String("name")); // can be empty
-            argData.type = arg.attribute(QLatin1String("type"));
-            if (!QDBusUtil::isValidSingleSignature(argData.type)) {
-                qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
-                                 qPrintable(argData.type));
-            }
+    Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("annotation"));
 
-            retval << argData;
-        }
+    const QXmlStreamAttributes attributes = xml.attributes();
+    const QString name = attributes.value(QLatin1String("name")).toString();
+
+    if (!QDBusUtil::isValidInterfaceName(name)) {
+        qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
+                qPrintable(name));
+        return false;
     }
-    return retval;
+    annotations.insert(name, attributes.value(QLatin1String("value")).toString());
+    return true;
 }
 
-QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
-                               const QString& xmlData)
-    : m_service(service), m_path(path)
+static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &propertyData,
+                const QString &ifaceName)
 {
-    QDomDocument doc;
-    doc.setContent(xmlData);
-    m_node = doc.firstChildElement(QLatin1String("node"));
-}
+    Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("property"));
+
+    QXmlStreamAttributes attributes = xml.attributes();
+    const QString propertyName = attributes.value(QLatin1String("name")).toString();
+    if (!QDBusUtil::isValidMemberName(propertyName)) {
+        qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+                qPrintable(propertyName), qPrintable(ifaceName));
+        xml.skipCurrentElement();
+        return false;
+    }
 
-QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
-                               const QDomElement& node)
-    : m_service(service), m_path(path), m_node(node)
-{
-}
+    // parse data
+    propertyData.name = propertyName;
+    propertyData.type = attributes.value(QLatin1String("type")).toString();
 
-QDBusIntrospection::Interfaces
-QDBusXmlParser::interfaces() const
-{
-    QDBusIntrospection::Interfaces retval;
-
-    if (m_node.isNull())
-        return retval;
-
-    QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
-    for (int i = 0; i < interfaceList.count(); ++i)
-    {
-        QDomElement iface = interfaceList.item(i).toElement();
-        QString ifaceName = iface.attribute(QLatin1String("name"));
-        if (iface.isNull())
-            continue;           // for whatever reason
-        if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
-            qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
-                             qPrintable(ifaceName));
-            continue;
-        }
+    if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
+        // cannot be!
+        qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
+                qPrintable(propertyData.type), qPrintable(ifaceName),
+                qPrintable(propertyName));
+    }
+
+    const QString access = attributes.value(QLatin1String("access")).toString();
+    if (access == QLatin1String("read"))
+        propertyData.access = QDBusIntrospection::Property::Read;
+    else if (access == QLatin1String("write"))
+        propertyData.access = QDBusIntrospection::Property::Write;
+    else if (access == QLatin1String("readwrite"))
+        propertyData.access = QDBusIntrospection::Property::ReadWrite;
+    else {
+        qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
+                qPrintable(access), qPrintable(ifaceName),
+                qPrintable(propertyName));
+        return false;       // invalid one!
+    }
 
-        QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
-        ifaceData->name = ifaceName;
-        {
-            // save the data
-            QTextStream ts(&ifaceData->introspection);
-            iface.save(ts,2);
+    while (xml.readNextStartElement()) {
+        if (xml.name() == QLatin1String("annotation")) {
+            parseAnnotation(xml, propertyData.annotations);
+        } else if (xml.prefix().isEmpty()) {
+            qDBusParserError() << "Unknown element" << xml.name() << "while checking for annotations";
         }
+        xml.skipCurrentElement();
+    }
 
-        // parse annotations
-        ifaceData->annotations = parseAnnotations(iface);
-
-        // parse methods
-        QDomNodeList list = iface.elementsByTagName(QLatin1String("method"));
-        for (int j = 0; j < list.count(); ++j)
-        {
-            QDomElement method = list.item(j).toElement();
-            QString methodName = method.attribute(QLatin1String("name"));
-            if (method.isNull())
-                continue;
-            if (!QDBusUtil::isValidMemberName(methodName)) {
-                qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
-                                 qPrintable(methodName), qPrintable(ifaceName));
-                continue;
-            }
+    if (!xml.isEndElement() || xml.name() != QLatin1String("property")) {
+        qDBusParserError() << "Invalid property specification" << xml.tokenString() << xml.name();
+        return false;
+    }
 
-            QDBusIntrospection::Method methodData;
-            methodData.name = methodName;
+    return true;
+}
 
-            // parse arguments
-            methodData.inputArgs = parseArgs(method, QLatin1String("in"), true);
-            methodData.outputArgs = parseArgs(method, QLatin1String("out"), false);
-            methodData.annotations = parseAnnotations(method);
+static bool parseMethod(QXmlStreamReader &xml, QDBusIntrospection::Method &methodData,
+        const QString &ifaceName)
+{
+    Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("method"));
+
+    const QXmlStreamAttributes attributes = xml.attributes();
+    const QString methodName = attributes.value(QLatin1String("name")).toString();
+    if (!QDBusUtil::isValidMemberName(methodName)) {
+        qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+                qPrintable(methodName), qPrintable(ifaceName));
+        return false;
+    }
 
-            // add it
-            ifaceData->methods.insert(methodName, methodData);
+    methodData.name = methodName;
+
+    QDBusIntrospection::Arguments outArguments;
+    QDBusIntrospection::Arguments inArguments;
+    QDBusIntrospection::Annotations annotations;
+
+    while (xml.readNextStartElement()) {
+        if (xml.name() == QLatin1String("annotation")) {
+            parseAnnotation(xml, annotations);
+        } else if (xml.name() == QLatin1String("arg")) {
+            const QXmlStreamAttributes attributes = xml.attributes();
+            const QString direction = attributes.value(QLatin1String("direction")).toString();
+            QDBusIntrospection::Argument argument;
+            if (!attributes.hasAttribute(QLatin1String("direction"))
+                    || direction == QLatin1String("in")) {
+                parseArg(attributes, argument);
+                inArguments << argument;
+            } else if (direction == QLatin1String("out")) {
+                parseArg(attributes, argument);
+                outArguments << argument;
+            }
+        } else if (xml.prefix().isEmpty()) {
+            qDBusParserError() << "Unknown element" << xml.name() << "while checking for method arguments";
         }
+        xml.skipCurrentElement();
+    }
 
-        // parse signals
-        list = iface.elementsByTagName(QLatin1String("signal"));
-        for (int j = 0; j < list.count(); ++j)
-        {
-            QDomElement signal = list.item(j).toElement();
-            QString signalName = signal.attribute(QLatin1String("name"));
-            if (signal.isNull())
-                continue;
-            if (!QDBusUtil::isValidMemberName(signalName)) {
-                qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
-                                 qPrintable(signalName), qPrintable(ifaceName));
-                continue;
-            }
+    methodData.inputArgs = inArguments;
+    methodData.outputArgs = outArguments;
+    methodData.annotations = annotations;
 
-            QDBusIntrospection::Signal signalData;
-            signalData.name = signalName;
+    return true;
+}
 
-            // parse data
-            signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
-            signalData.annotations = parseAnnotations(signal);
 
-            // add it
-            ifaceData->signals_.insert(signalName, signalData);
-        }
+static bool parseSignal(QXmlStreamReader &xml, QDBusIntrospection::Signal &signalData,
+        const QString &ifaceName)
+{
+    Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("signal"));
 
-        // parse properties
-        list = iface.elementsByTagName(QLatin1String("property"));
-        for (int j = 0; j < list.count(); ++j)
-        {
-            QDomElement property = list.item(j).toElement();
-            QString propertyName = property.attribute(QLatin1String("name"));
-            if (property.isNull())
-                continue;
-            if (!QDBusUtil::isValidMemberName(propertyName)) {
-                qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
-                                 qPrintable(propertyName), qPrintable(ifaceName));
-                continue;
-            }
+    const QXmlStreamAttributes attributes = xml.attributes();
+    const QString signalName = attributes.value(QLatin1String("name")).toString();
 
-            QDBusIntrospection::Property propertyData;
+    if (!QDBusUtil::isValidMemberName(signalName)) {
+        qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+                qPrintable(signalName), qPrintable(ifaceName));
+        return false;
+    }
 
-            // parse data
-            propertyData.name = propertyName;
-            propertyData.type = property.attribute(QLatin1String("type"));
-            propertyData.annotations = parseAnnotations(property);
+    signalData.name = signalName;
 
-            if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
-                // cannot be!
-                qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
-                                 qPrintable(propertyData.type), qPrintable(ifaceName),
-                                 qPrintable(propertyName));
-            }
 
-            QString access = property.attribute(QLatin1String("access"));
-            if (access == QLatin1String("read"))
-                propertyData.access = QDBusIntrospection::Property::Read;
-            else if (access == QLatin1String("write"))
-                propertyData.access = QDBusIntrospection::Property::Write;
-            else if (access == QLatin1String("readwrite"))
-                propertyData.access = QDBusIntrospection::Property::ReadWrite;
-            else {
-                qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
-                                 qPrintable(access), qPrintable(ifaceName),
-                                 qPrintable(propertyName));
-                continue;       // invalid one!
-            }
+    QDBusIntrospection::Arguments arguments;
+    QDBusIntrospection::Annotations annotations;
 
-            // add it
-            ifaceData->properties.insert(propertyName, propertyData);
+    while (xml.readNextStartElement()) {
+        if (xml.name() == QLatin1String("annotation")) {
+            parseAnnotation(xml, annotations);
+        } else if (xml.name() == QLatin1String("arg")) {
+            const QXmlStreamAttributes attributes = xml.attributes();
+            QDBusIntrospection::Argument argument;
+            if (!attributes.hasAttribute(QLatin1String("direction")) ||
+                attributes.value(QLatin1String("direction")) == QLatin1String("out")) {
+                parseArg(attributes, argument);
+                arguments << argument;
+            }
+        } else {
+            qDBusParserError() << "Unknown element" << xml.name() << "while checking for signal arguments";
         }
-
-        // add it
-        retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
+        xml.skipCurrentElement();
     }
 
-    return retval;
+    signalData.outputArgs = arguments;
+    signalData.annotations = annotations;
+
+    return true;
 }
 
-QSharedDataPointer<QDBusIntrospection::Object>
-QDBusXmlParser::object() const
+static void readInterface(QXmlStreamReader &xml, QDBusIntrospection::Object *objData,
+        QDBusIntrospection::Interfaces *interfaces)
 {
-    if (m_node.isNull())
-        return QSharedDataPointer<QDBusIntrospection::Object>();
-
-    QDBusIntrospection::Object* objData;
-    objData = new QDBusIntrospection::Object;
-    objData->service = m_service;
-    objData->path = m_path;
-
-    // check if we have anything to process
-    if (objData->introspection.isNull() && !m_node.firstChild().isNull()) {
-        // yes, introspect this object
-        QTextStream ts(&objData->introspection);
-        m_node.save(ts,2);
-
-        QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
-        for (int i = 0; i < objects.count(); ++i) {
-            QDomElement obj = objects.item(i).toElement();
-            QString objName = obj.attribute(QLatin1String("name"));
-            if (obj.isNull())
-                continue;           // for whatever reason
-            if (!QDBusUtil::isValidObjectPath(m_path + QLatin1Char('/') + objName)) {
-                qDBusParserError("Invalid D-BUS object path '%s/%s' found while parsing introspection",
-                                 qPrintable(m_path), qPrintable(objName));
-                continue;
-            }
+    const QString ifaceName = xml.attributes().value(QLatin1String("name")).toString();
+    if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
+        qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
+                qPrintable(ifaceName));
+        return;
+    }
 
-            objData->childObjects.append(objName);
-        }
+    objData->interfaces.append(ifaceName);
 
-        QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
-        for (int i = 0; i < interfaceList.count(); ++i) {
-            QDomElement iface = interfaceList.item(i).toElement();
-            QString ifaceName = iface.attribute(QLatin1String("name"));
-            if (iface.isNull())
-                continue;
-            if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
-                qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
-                                 qPrintable(ifaceName));
-                continue;
-            }
+    QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
+    ifaceData->name = ifaceName;
 
-            objData->interfaces.append(ifaceName);
+    while (xml.readNextStartElement()) {
+        if (xml.name() == QLatin1String("method")) {
+            QDBusIntrospection::Method methodData;
+            if (parseMethod(xml, methodData, ifaceName))
+                ifaceData->methods.insert(methodData.name, methodData);
+        } else if (xml.name() == QLatin1String("signal")) {
+            QDBusIntrospection::Signal signalData;
+            if (parseSignal(xml, signalData, ifaceName))
+                ifaceData->signals_.insert(signalData.name, signalData);
+        } else if (xml.name() == QLatin1String("property")) {
+            QDBusIntrospection::Property propertyData;
+            if (parseProperty(xml, propertyData, ifaceName))
+                ifaceData->properties.insert(propertyData.name, propertyData);
+        } else if (xml.name() == QLatin1String("annotation")) {
+            parseAnnotation(xml, ifaceData->annotations);
+            xml.skipCurrentElement(); // skip over annotation object
+        } else {
+            if (xml.prefix().isEmpty()) {
+                qDBusParserError() << "Unknown element while parsing interface" << xml.name();
+            }
+            xml.skipCurrentElement();
         }
-    } else {
-        objData->introspection = QLatin1String("<node/>\n");
     }
 
-    QSharedDataPointer<QDBusIntrospection::Object> retval;
-    retval = objData;
-    return retval;
+    interfaces->insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
+
+    if (!xml.isEndElement() || xml.name() != QLatin1String("interface")) {
+        qDBusParserError() << "Invalid Interface specification";
+    }
+}
+
+static void readNode(const QXmlStreamReader &xml, QDBusIntrospection::Object *objData, int nodeLevel)
+{
+    const QString objName = xml.attributes().value(QLatin1String("name")).toString();
+    const QString fullName = objData->path.endsWith(QLatin1Char('/'))
+                                ? (objData->path + objName)
+                                : QString(objData->path + QLatin1Char('/') + objName);
+    if (!QDBusUtil::isValidObjectPath(fullName)) {
+        qDBusParserError("Invalid D-BUS object path '%s' found while parsing introspection",
+                 qPrintable(fullName));
+        return;
+    }
+
+    if (nodeLevel > 0)
+        objData->childObjects.append(objName);
 }
 
-QSharedDataPointer<QDBusIntrospection::ObjectTree>
-QDBusXmlParser::objectTree() const
+QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
+                               const QString& xmlData)
+    : m_service(service), m_path(path), m_object(new QDBusIntrospection::Object)
 {
-    QSharedDataPointer<QDBusIntrospection::ObjectTree> retval;
-
-    if (m_node.isNull())
-        return retval;
-
-    retval = new QDBusIntrospection::ObjectTree;
-
-    retval->service = m_service;
-    retval->path = m_path;
-
-    QTextStream ts(&retval->introspection);
-    m_node.save(ts,2);
-
-    // interfaces are easy:
-    retval->interfaceData = interfaces();
-    retval->interfaces = retval->interfaceData.keys();
-
-    // sub-objects are slightly more difficult:
-    QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
-    for (int i = 0; i < objects.count(); ++i) {
-        QDomElement obj = objects.item(i).toElement();
-        QString objName = obj.attribute(QLatin1String("name"));
-        if (obj.isNull() || objName.isEmpty())
-            continue;           // for whatever reason
-
-        // check if we have anything to process
-        if (!obj.firstChild().isNull()) {
-            // yes, introspect this object
-            QString xml;
-            QTextStream ts2(&xml);
-            obj.save(ts2,0);
-
-            // parse it
-            QString objAbsName = m_path;
-            if (!objAbsName.endsWith(QLatin1Char('/')))
-                objAbsName.append(QLatin1Char('/'));
-            objAbsName += objName;
-
-            QDBusXmlParser parser(m_service, objAbsName, obj);
-            retval->childObjectData.insert(objName, parser.objectTree());
-        }
+//    qDBusParserError() << "parsing" << xmlData;
 
-        retval->childObjects << objName;
+    m_object->service = m_service;
+    m_object->path = m_path;
+
+    QXmlStreamReader xml(xmlData);
+
+    int nodeLevel = -1;
+
+    while (!xml.atEnd()) {
+        xml.readNext();
+
+        switch (xml.tokenType()) {
+        case QXmlStreamReader::StartElement:
+            if (xml.name() == QLatin1String("node")) {
+                readNode(xml, m_object, ++nodeLevel);
+            } else if (xml.name() == QLatin1String("interface")) {
+                readInterface(xml, m_object, &m_interfaces);
+            } else {
+                if (xml.prefix().isEmpty()) {
+                    qDBusParserError() << "skipping unknown element" << xml.name();
+                }
+                xml.skipCurrentElement();
+            }
+            break;
+        case QXmlStreamReader::EndElement:
+            if (xml.name() == QLatin1String("node")) {
+                --nodeLevel;
+            } else {
+                qDBusParserError() << "Invalid Node declaration" << xml.name();
+            }
+            break;
+        case QXmlStreamReader::StartDocument:
+        case QXmlStreamReader::EndDocument:
+        case QXmlStreamReader::DTD:
+            // not interested
+            break;
+        case QXmlStreamReader::Comment:
+            // ignore comments and processing instructions
+            break;
+        default:
+            qDBusParserError() << "unknown token" << xml.name() << xml.tokenString();
+            break;
+        }
     }
 
-    return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );
+    if (xml.hasError()) {
+        qDBusParserError() << "xml error" << xml.errorString() << "doc" << xmlData;
+    }
 }
 
 QT_END_NAMESPACE
index f7677e0..bd063e7 100644 (file)
@@ -54,7 +54,6 @@
 //
 
 #include <QtCore/qmap.h>
-#include <QtXml/qdom.h>
 #include <qdbusmacros.h>
 #include "qdbusintrospection_p.h"
 
@@ -69,17 +68,15 @@ class QDBusXmlParser
 {
     QString m_service;
     QString m_path;
-    QDomElement m_node;
+    QSharedDataPointer<QDBusIntrospection::Object> m_object;
+    QDBusIntrospection::Interfaces m_interfaces;
 
 public:
     QDBusXmlParser(const QString& service, const QString& path,
                    const QString& xmlData);
-    QDBusXmlParser(const QString& service, const QString& path,
-                   const QDomElement& node);
 
-    QDBusIntrospection::Interfaces interfaces() const;
-    QSharedDataPointer<QDBusIntrospection::Object> object() const;
-    QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const;
+    inline QDBusIntrospection::Interfaces interfaces() const { return m_interfaces; }
+    inline QSharedDataPointer<QDBusIntrospection::Object> object() const { return m_object; }
 };
 
 QT_END_NAMESPACE
index d57160e..8514265 100644 (file)
@@ -11,6 +11,6 @@ QT.dbus.sources = $$QT_MODULE_BASE/src/dbus
 QT.dbus.libs = $$QT_MODULE_LIB_BASE
 QT.dbus.plugins = $$QT_MODULE_PLUGIN_BASE
 QT.dbus.imports = $$QT_MODULE_IMPORT_BASE
-QT.dbus.depends = core xml
+QT.dbus.depends = core
 QT.dbus.CONFIG = dbusadaptors dbusinterfaces
 QT.dbus.DEFINES = QT_DBUS_LIB
index 80d1c4e..8d750ba 100644 (file)
@@ -50,7 +50,7 @@ src_platformsupport.target = sub-platformsupport
    src_platformsupport.depends = src_corelib src_gui src_network
    src_widgets.depends = src_corelib src_gui src_tools_uic
    src_xml.depends = src_corelib
-   src_dbus.depends = src_corelib src_xml
+   src_dbus.depends = src_corelib
    src_network.depends = src_corelib
    src_opengl.depends = src_gui src_widgets
    src_sql.depends = src_corelib
index dc8363d..44f1b1c 100644 (file)
@@ -46,7 +46,7 @@
 #include <QtTest/QtTest>
 #include <QtCore/qvariant.h>
 #include <QtDBus/QtDBus>
-
+#include <qdebug.h>
 #include "../qdbusmarshall/common.h"
 #include "myobject.h"
 
index 42a3fd1..dad8c6d 100644 (file)
@@ -61,9 +61,6 @@ private slots:
     void parsingWithDoctype_data();
     void parsingWithDoctype();
 
-    void objectWithContent_data();
-    void objectWithContent();
-
     void methods_data();
     void methods();
     void signals__data();
@@ -77,40 +74,49 @@ void tst_QDBusXmlParser::parsing_data()
     QTest::addColumn<QString>("xmlData");
     QTest::addColumn<int>("interfaceCount");
     QTest::addColumn<int>("objectCount");
+    QTest::addColumn<int>("annotationCount");
 
-    QTest::newRow("null") << QString() << 0 << 0;
-    QTest::newRow("empty") << QString("") << 0 << 0;
+    QTest::newRow("null") << QString() << 0 << 0 << 0;
+    QTest::newRow("empty") << QString("") << 0 << 0 << 0;
     
-    QTest::newRow("junk") << "<junk/>" << 0 << 0;
+    QTest::newRow("junk") << "<junk/>" << 0 << 0 << 0;
     QTest::newRow("interface-inside-junk") << "<junk><interface name=\"iface.iface1\" /></junk>"
-                                           << 0 << 0;
+                                           << 0 << 0 << 0;
     QTest::newRow("object-inside-junk") << "<junk><node name=\"obj1\" /></junk>"
-                                        << 0 << 0;
+                                        << 0 << 0 << 0;
 
-    QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0;
-    QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0;
+    QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0 << 0;
+    QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0 << 0;
 
     
     QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />"
-                                       "<interface name=\"iface.iface2\"></node>"
-                                    << 2 << 0;        
+                                       "<interface name=\"iface.iface2\" /></node>"
+                                    << 2 << 0 << 0;
 
 
-    QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>" << 0 << 1;
-    QTest::newRow("two-objects") << "<node><node name=\"obj1\"/><node name=\"obj2\"></node>" << 0 << 2;
+    QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>" << 0 << 1 << 0;
+    QTest::newRow("two-objects") << "<node><node name=\"obj1\"/><node name=\"obj2\"/></node>" << 0 << 2 << 0;
 
-    QTest::newRow("i1o1") << "<node><interface name=\"iface.iface1\"><node name=\"obj1\"></node>" << 1 << 1;
+    QTest::newRow("i1o1") << "<node><interface name=\"iface.iface1\"/><node name=\"obj1\"/></node>" << 1 << 1 << 0;
 
+    QTest::newRow("one-interface-annotated") << "<node><interface name=\"iface.iface1\">"
+                                                "<annotation name=\"foo.testing\" value=\"nothing to see here\" />"
+                                                "</interface></node>" << 1 << 0 << 1;
+    QTest::newRow("one-interface-docnamespace") << "<?xml version=\"1.0\" xmlns:doc=\"foo\" ?><node>"
+                                                   "<interface name=\"iface.iface1\"><doc:something />"
+                                                   "</interface></node>" << 1 << 0 << 0;
 }
 
 void tst_QDBusXmlParser::parsing_common(const QString &xmlData)
 {
-    QDBusIntrospection::ObjectTree obj =
-        QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/");
+    QDBusIntrospection::Object obj =
+        QDBusIntrospection::parseObject(xmlData, "local.testing", "/");
     QFETCH(int, interfaceCount);
     QFETCH(int, objectCount);
+    QFETCH(int, annotationCount);
     QCOMPARE(obj.interfaces.count(), interfaceCount);
     QCOMPARE(obj.childObjects.count(), objectCount);
+    QCOMPARE(QDBusIntrospection::parseInterface(xmlData).annotations.count(), annotationCount);
 
     // also verify the naming
     int i = 0;
@@ -140,92 +146,14 @@ void tst_QDBusXmlParser::parsingWithDoctype()
                       "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
     QFETCH(QString, xmlData);
 
-    parsing_common(docType + xmlData);
-}    
-
-void tst_QDBusXmlParser::objectWithContent_data()
-{
-    QTest::addColumn<QString>("xmlData");
-    QTest::addColumn<QString>("probedObject");
-    QTest::addColumn<int>("interfaceCount");
-    QTest::addColumn<int>("objectCount");
-
-    QTest::newRow("zero") << "<node><node name=\"obj\"/></node>" << "obj" << 0 << 0;
-
-    QString xmlData = "<node><node name=\"obj\">"
-                      "<interface name=\"iface.iface1\" />"
-                      "</node></node>";
-    QTest::newRow("one-interface") << xmlData << "obj" << 1 << 0;
-    QTest::newRow("one-interface2") << xmlData << "obj2" << 0 << 0;
-
-    xmlData = "<node><node name=\"obj\">"
-              "<interface name=\"iface.iface1\" />"
-              "<interface name=\"iface.iface2\" />"
-              "</node></node>";
-    QTest::newRow("two-interfaces") << xmlData << "obj" << 2 << 0;
-    QTest::newRow("two-interfaces2") << xmlData << "obj2" << 0 << 0;
-
-    xmlData = "<node><node name=\"obj\">"
-              "<interface name=\"iface.iface1\" />"
-              "<interface name=\"iface.iface2\" />"
-              "</node><node name=\"obj2\">"
-              "<interface name=\"iface.iface1\" />"
-              "</node></node>";
-    QTest::newRow("two-nodes-two-interfaces") << xmlData << "obj" << 2 << 0;
-    QTest::newRow("two-nodes-one-interface") << xmlData << "obj2" << 1 << 0;
-
-    xmlData = "<node><node name=\"obj\">"
-              "<node name=\"obj1\" />"
-              "</node></node>";
-    QTest::newRow("one-object") << xmlData << "obj" << 0 << 1;
-    QTest::newRow("one-object2") << xmlData << "obj2" << 0 << 0;
-
-    xmlData = "<node><node name=\"obj\">"
-              "<node name=\"obj1\" />"
-              "<node name=\"obj2\" />"
-              "</node></node>";
-    QTest::newRow("two-objects") << xmlData << "obj" << 0 << 2;
-    QTest::newRow("two-objects2") << xmlData << "obj2" << 0 << 0;
-
-    xmlData = "<node><node name=\"obj\">"
-              "<node name=\"obj1\" />"
-              "<node name=\"obj2\" />"
-              "</node><node name=\"obj2\">"
-              "<node name=\"obj1\" />"
-              "</node></node>";
-    QTest::newRow("two-nodes-two-objects") << xmlData << "obj" << 0 << 2;
-    QTest::newRow("two-nodes-one-object") << xmlData << "obj2" << 0 << 1;
-}
-
-void tst_QDBusXmlParser::objectWithContent()
-{
-    QFETCH(QString, xmlData);
-    QFETCH(QString, probedObject);
-
-    QDBusIntrospection::ObjectTree tree =
-        QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/");
-
-    const ObjectMap &om = tree.childObjectData;
-
-    if (om.contains(probedObject)) {
-        const QSharedDataPointer<QDBusIntrospection::ObjectTree>& obj = om.value(probedObject);
-        QVERIFY(obj != 0);
-    
-        QFETCH(int, interfaceCount);
-        QFETCH(int, objectCount);
-
-        QCOMPARE(obj->interfaces.count(), interfaceCount);
-        QCOMPARE(obj->childObjects.count(), objectCount);
-
-        // verify the object names
-        int i = 0;
-        foreach (QString name, obj->interfaces)
-            QCOMPARE(name, QString("iface.iface%1").arg(++i));
-
-        i = 0;
-        foreach (QString name, obj->childObjects)
-            QCOMPARE(name, QString("obj%1").arg(++i));
+    QString toParse;
+    if (xmlData.startsWith(QLatin1String("<?xml"))) {
+        int split = xmlData.indexOf(QLatin1Char('>')) + 1;
+        toParse = xmlData.left(split) + docType + xmlData.mid(split);
+    } else {
+        toParse = docType + xmlData;
     }
+    parsing_common(toParse);
 }
 
 void tst_QDBusXmlParser::methods_data()
@@ -261,7 +189,7 @@ void tst_QDBusXmlParser::methods_data()
     QTest::newRow("method-with-annotation") <<
         "<method name=\"Foo\"/>"
         "<method name=\"Bar\"/>"
-        "<method name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></method>"
+        "<method name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\" /></method>"
                                             << map;
 
     // arguments
@@ -428,7 +356,7 @@ void tst_QDBusXmlParser::signals__data()
     QTest::newRow("signal-with-annotation") <<
         "<signal name=\"Foo\"/>"
         "<signal name=\"Bar\"/>"
-        "<signal name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></signal>"
+        "<signal name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\" /></signal>"
                                             << map;
 
     // one out argument
@@ -563,6 +491,7 @@ void tst_QDBusXmlParser::properties_data()
         "<property name=\"baz\" type=\"as\" access=\"write\">"
         "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
         "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
+        "</property>"
         "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
 
     // and now change the order
@@ -570,6 +499,7 @@ void tst_QDBusXmlParser::properties_data()
         "<property name=\"baz\" type=\"as\" access=\"write\">"
         "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
         "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
+        "</property>"
         "<property name=\"bar\" type=\"i\" access=\"read\"/>"
         "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
 }