Remove dependency of QtDBus onto QtXml

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>
This commit is contained in:
Harald Fernengel 2012-01-18 21:28:31 +01:00 committed by Qt by Nokia
parent 7c247d3e70
commit 0696071316
9 changed files with 313 additions and 433 deletions

View File

@ -2,8 +2,7 @@ load(qt_module)
TARGET = QtDBus TARGET = QtDBus
QPRO_PWD = $$PWD QPRO_PWD = $$PWD
QT = core-private \ QT = core-private
xml
CONFIG += link_pkgconfig module CONFIG += link_pkgconfig module
MODULE_PRI = ../modules/qt_dbus.pri MODULE_PRI = ../modules/qt_dbus.pri
@ -21,8 +20,7 @@ unix|win32-g++* {
QMAKE_PKGCONFIG_DESCRIPTION = Qt \ QMAKE_PKGCONFIG_DESCRIPTION = Qt \
DBus \ DBus \
module module
QMAKE_PKGCONFIG_REQUIRES = QtCore \ QMAKE_PKGCONFIG_REQUIRES = QtCore
QtXml
} }
win32 { win32 {
wince*:LIBS_PRIVATE += -lws2 wince*:LIBS_PRIVATE += -lws2

View File

@ -407,23 +407,6 @@ QDBusIntrospection::parseObject(const QString &xml, const QString &service, cons
return *retval; 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 QT_END_NAMESPACE
#endif // QT_NO_DBUS #endif // QT_NO_DBUS

View File

@ -59,7 +59,7 @@
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
#include <QtCore/qpair.h> #include <QtCore/qpair.h>
#include <QtCore/qshareddata.h> #include <QtCore/qshareddata.h>
#include <qdbusmacros.h> #include "qdbusmacros.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -150,26 +150,16 @@ public:
{ {
QString service; QString service;
QString path; QString path;
QString introspection;
QStringList interfaces; QStringList interfaces;
QStringList childObjects; QStringList childObjects;
}; };
struct ObjectTree: public Object
{
Interfaces interfaceData;
Objects childObjectData;
};
public: public:
static Interface parseInterface(const QString &xml); static Interface parseInterface(const QString &xml);
static Interfaces parseInterfaces(const QString &xml); static Interfaces parseInterfaces(const QString &xml);
static Object parseObject(const QString &xml, const QString &service = QString(), static Object parseObject(const QString &xml, const QString &service = QString(),
const QString &path = QString()); const QString &path = QString());
static ObjectTree parseObjectTree(const QString &xml,
const QString &service,
const QString &path);
private: private:
QDBusIntrospection(); QDBusIntrospection();

View File

@ -40,337 +40,319 @@
****************************************************************************/ ****************************************************************************/
#include "qdbusxmlparser_p.h" #include "qdbusxmlparser_p.h"
#include "qdbusinterface.h"
#include "qdbusinterface_p.h"
#include "qdbusconnection_p.h"
#include "qdbusutil_p.h" #include "qdbusutil_p.h"
#include <QtXml/qdom.h>
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtCore/qtextstream.h> #include <QtCore/qtextstream.h>
#include <QtCore/qxmlstream.h>
#include <QtCore/qdebug.h>
#ifndef QT_NO_DBUS #ifndef QT_NO_DBUS
//#define QDBUS_PARSER_DEBUG //#define QDBUS_PARSER_DEBUG
#ifdef QDBUS_PARSER_DEBUG #ifdef QDBUS_PARSER_DEBUG
# define qDBusParserError qWarning # define qDBusParserError qDebug
#else #else
# define qDBusParserError if (true) {} else qDebug # define qDBusParserError if (true) {} else qDebug
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
static QDBusIntrospection::Annotations static bool parseArg(const QXmlStreamAttributes &attributes, QDBusIntrospection::Argument &argData)
parseAnnotations(const QDomElement& elem)
{ {
QDBusIntrospection::Annotations retval; const QString argType = attributes.value(QLatin1String("type")).toString();
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")), bool ok = QDBusUtil::isValidSingleSignature(argType);
value = ann.attribute(QLatin1String("value")); if (!ok) {
qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
if (!QDBusUtil::isValidInterfaceName(name)) { qPrintable(argType));
qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
qPrintable(name));
continue;
}
retval.insert(name, value);
} }
return retval; argData.name = attributes.value(QLatin1String("name")).toString();
argData.type = argType;
return ok;
} }
static QDBusIntrospection::Arguments static bool parseAnnotation(const QXmlStreamReader &xml, QDBusIntrospection::Annotations &annotations)
parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty)
{ {
QDBusIntrospection::Arguments retval; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("annotation"));
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"))) || const QXmlStreamAttributes attributes = xml.attributes();
arg.attribute(QLatin1String("direction")) == direction) { const QString name = attributes.value(QLatin1String("name")).toString();
QDBusIntrospection::Argument argData; if (!QDBusUtil::isValidInterfaceName(name)) {
if (arg.hasAttribute(QLatin1String("name"))) qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
argData.name = arg.attribute(QLatin1String("name")); // can be empty qPrintable(name));
argData.type = arg.attribute(QLatin1String("type")); return false;
if (!QDBusUtil::isValidSingleSignature(argData.type)) { }
qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection", annotations.insert(name, attributes.value(QLatin1String("value")).toString());
qPrintable(argData.type)); return true;
}
static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &propertyData,
const QString &ifaceName)
{
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;
}
// parse data
propertyData.name = propertyName;
propertyData.type = attributes.value(QLatin1String("type")).toString();
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!
}
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();
}
if (!xml.isEndElement() || xml.name() != QLatin1String("property")) {
qDBusParserError() << "Invalid property specification" << xml.tokenString() << xml.name();
return false;
}
return true;
}
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;
}
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();
}
retval << argData; methodData.inputArgs = inArguments;
methodData.outputArgs = outArguments;
methodData.annotations = annotations;
return true;
}
static bool parseSignal(QXmlStreamReader &xml, QDBusIntrospection::Signal &signalData,
const QString &ifaceName)
{
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("signal"));
const QXmlStreamAttributes attributes = xml.attributes();
const QString signalName = attributes.value(QLatin1String("name")).toString();
if (!QDBusUtil::isValidMemberName(signalName)) {
qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
qPrintable(signalName), qPrintable(ifaceName));
return false;
}
signalData.name = signalName;
QDBusIntrospection::Arguments arguments;
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();
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";
}
xml.skipCurrentElement();
}
signalData.outputArgs = arguments;
signalData.annotations = annotations;
return true;
}
static void readInterface(QXmlStreamReader &xml, QDBusIntrospection::Object *objData,
QDBusIntrospection::Interfaces *interfaces)
{
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->interfaces.append(ifaceName);
QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
ifaceData->name = 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();
} }
} }
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);
} }
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData) const QString& xmlData)
: m_service(service), m_path(path) : m_service(service), m_path(path), m_object(new QDBusIntrospection::Object)
{ {
QDomDocument doc; // qDBusParserError() << "parsing" << xmlData;
doc.setContent(xmlData);
m_node = doc.firstChildElement(QLatin1String("node"));
}
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, m_object->service = m_service;
const QDomElement& node) m_object->path = m_path;
: m_service(service), m_path(path), m_node(node)
{
}
QDBusIntrospection::Interfaces QXmlStreamReader xml(xmlData);
QDBusXmlParser::interfaces() const
{
QDBusIntrospection::Interfaces retval;
if (m_node.isNull()) int nodeLevel = -1;
return retval;
QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface")); while (!xml.atEnd()) {
for (int i = 0; i < interfaceList.count(); ++i) xml.readNext();
{
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;
}
QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface; switch (xml.tokenType()) {
ifaceData->name = ifaceName; case QXmlStreamReader::StartElement:
{ if (xml.name() == QLatin1String("node")) {
// save the data readNode(xml, m_object, ++nodeLevel);
QTextStream ts(&ifaceData->introspection); } else if (xml.name() == QLatin1String("interface")) {
iface.save(ts,2); readInterface(xml, m_object, &m_interfaces);
} } else {
if (xml.prefix().isEmpty()) {
// parse annotations qDBusParserError() << "skipping unknown element" << xml.name();
ifaceData->annotations = parseAnnotations(iface); }
xml.skipCurrentElement();
// 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;
} }
break;
QDBusIntrospection::Method methodData; case QXmlStreamReader::EndElement:
methodData.name = methodName; if (xml.name() == QLatin1String("node")) {
--nodeLevel;
// parse arguments } else {
methodData.inputArgs = parseArgs(method, QLatin1String("in"), true); qDBusParserError() << "Invalid Node declaration" << xml.name();
methodData.outputArgs = parseArgs(method, QLatin1String("out"), false); }
methodData.annotations = parseAnnotations(method); break;
case QXmlStreamReader::StartDocument:
// add it case QXmlStreamReader::EndDocument:
ifaceData->methods.insert(methodName, methodData); case QXmlStreamReader::DTD:
// not interested
break;
case QXmlStreamReader::Comment:
// ignore comments and processing instructions
break;
default:
qDBusParserError() << "unknown token" << xml.name() << xml.tokenString();
break;
} }
// 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;
}
QDBusIntrospection::Signal signalData;
signalData.name = signalName;
// parse data
signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
signalData.annotations = parseAnnotations(signal);
// add it
ifaceData->signals_.insert(signalName, signalData);
}
// 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;
}
QDBusIntrospection::Property propertyData;
// parse data
propertyData.name = propertyName;
propertyData.type = property.attribute(QLatin1String("type"));
propertyData.annotations = parseAnnotations(property);
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!
}
// add it
ifaceData->properties.insert(propertyName, propertyData);
}
// add it
retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
} }
return retval; if (xml.hasError()) {
} qDBusParserError() << "xml error" << xml.errorString() << "doc" << xmlData;
QSharedDataPointer<QDBusIntrospection::Object>
QDBusXmlParser::object() const
{
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;
}
objData->childObjects.append(objName);
}
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;
}
objData->interfaces.append(ifaceName);
}
} else {
objData->introspection = QLatin1String("<node/>\n");
} }
QSharedDataPointer<QDBusIntrospection::Object> retval;
retval = objData;
return retval;
}
QSharedDataPointer<QDBusIntrospection::ObjectTree>
QDBusXmlParser::objectTree() const
{
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());
}
retval->childObjects << objName;
}
return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -54,7 +54,6 @@
// //
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
#include <QtXml/qdom.h>
#include <qdbusmacros.h> #include <qdbusmacros.h>
#include "qdbusintrospection_p.h" #include "qdbusintrospection_p.h"
@ -69,17 +68,15 @@ class QDBusXmlParser
{ {
QString m_service; QString m_service;
QString m_path; QString m_path;
QDomElement m_node; QSharedDataPointer<QDBusIntrospection::Object> m_object;
QDBusIntrospection::Interfaces m_interfaces;
public: public:
QDBusXmlParser(const QString& service, const QString& path, QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData); const QString& xmlData);
QDBusXmlParser(const QString& service, const QString& path,
const QDomElement& node);
QDBusIntrospection::Interfaces interfaces() const; inline QDBusIntrospection::Interfaces interfaces() const { return m_interfaces; }
QSharedDataPointer<QDBusIntrospection::Object> object() const; inline QSharedDataPointer<QDBusIntrospection::Object> object() const { return m_object; }
QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -11,6 +11,6 @@ QT.dbus.sources = $$QT_MODULE_BASE/src/dbus
QT.dbus.libs = $$QT_MODULE_LIB_BASE QT.dbus.libs = $$QT_MODULE_LIB_BASE
QT.dbus.plugins = $$QT_MODULE_PLUGIN_BASE QT.dbus.plugins = $$QT_MODULE_PLUGIN_BASE
QT.dbus.imports = $$QT_MODULE_IMPORT_BASE QT.dbus.imports = $$QT_MODULE_IMPORT_BASE
QT.dbus.depends = core xml QT.dbus.depends = core
QT.dbus.CONFIG = dbusadaptors dbusinterfaces QT.dbus.CONFIG = dbusadaptors dbusinterfaces
QT.dbus.DEFINES = QT_DBUS_LIB QT.dbus.DEFINES = QT_DBUS_LIB

View File

@ -50,7 +50,7 @@ src_platformsupport.target = sub-platformsupport
src_platformsupport.depends = src_corelib src_gui src_network src_platformsupport.depends = src_corelib src_gui src_network
src_widgets.depends = src_corelib src_gui src_tools_uic src_widgets.depends = src_corelib src_gui src_tools_uic
src_xml.depends = src_corelib src_xml.depends = src_corelib
src_dbus.depends = src_corelib src_xml src_dbus.depends = src_corelib
src_network.depends = src_corelib src_network.depends = src_corelib
src_opengl.depends = src_gui src_widgets src_opengl.depends = src_gui src_widgets
src_sql.depends = src_corelib src_sql.depends = src_corelib

View File

@ -46,7 +46,7 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtDBus/QtDBus> #include <QtDBus/QtDBus>
#include <qdebug.h>
#include "../qdbusmarshall/common.h" #include "../qdbusmarshall/common.h"
#include "myobject.h" #include "myobject.h"

View File

@ -61,9 +61,6 @@ private slots:
void parsingWithDoctype_data(); void parsingWithDoctype_data();
void parsingWithDoctype(); void parsingWithDoctype();
void objectWithContent_data();
void objectWithContent();
void methods_data(); void methods_data();
void methods(); void methods();
void signals__data(); void signals__data();
@ -77,40 +74,49 @@ void tst_QDBusXmlParser::parsing_data()
QTest::addColumn<QString>("xmlData"); QTest::addColumn<QString>("xmlData");
QTest::addColumn<int>("interfaceCount"); QTest::addColumn<int>("interfaceCount");
QTest::addColumn<int>("objectCount"); QTest::addColumn<int>("objectCount");
QTest::addColumn<int>("annotationCount");
QTest::newRow("null") << QString() << 0 << 0; QTest::newRow("null") << QString() << 0 << 0 << 0;
QTest::newRow("empty") << QString("") << 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>" 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>" QTest::newRow("object-inside-junk") << "<junk><node name=\"obj1\" /></junk>"
<< 0 << 0; << 0 << 0 << 0;
QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0; QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0 << 0;
QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0; QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0 << 0;
QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />" QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />"
"<interface name=\"iface.iface2\"></node>" "<interface name=\"iface.iface2\" /></node>"
<< 2 << 0; << 2 << 0 << 0;
QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>" << 0 << 1; 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; 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) void tst_QDBusXmlParser::parsing_common(const QString &xmlData)
{ {
QDBusIntrospection::ObjectTree obj = QDBusIntrospection::Object obj =
QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/"); QDBusIntrospection::parseObject(xmlData, "local.testing", "/");
QFETCH(int, interfaceCount); QFETCH(int, interfaceCount);
QFETCH(int, objectCount); QFETCH(int, objectCount);
QFETCH(int, annotationCount);
QCOMPARE(obj.interfaces.count(), interfaceCount); QCOMPARE(obj.interfaces.count(), interfaceCount);
QCOMPARE(obj.childObjects.count(), objectCount); QCOMPARE(obj.childObjects.count(), objectCount);
QCOMPARE(QDBusIntrospection::parseInterface(xmlData).annotations.count(), annotationCount);
// also verify the naming // also verify the naming
int i = 0; int i = 0;
@ -140,92 +146,14 @@ void tst_QDBusXmlParser::parsingWithDoctype()
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"; "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
QFETCH(QString, xmlData); QFETCH(QString, xmlData);
parsing_common(docType + xmlData); QString toParse;
} if (xmlData.startsWith(QLatin1String("<?xml"))) {
int split = xmlData.indexOf(QLatin1Char('>')) + 1;
void tst_QDBusXmlParser::objectWithContent_data() toParse = xmlData.left(split) + docType + xmlData.mid(split);
{ } else {
QTest::addColumn<QString>("xmlData"); toParse = docType + 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));
} }
parsing_common(toParse);
} }
void tst_QDBusXmlParser::methods_data() void tst_QDBusXmlParser::methods_data()
@ -261,7 +189,7 @@ void tst_QDBusXmlParser::methods_data()
QTest::newRow("method-with-annotation") << QTest::newRow("method-with-annotation") <<
"<method name=\"Foo\"/>" "<method name=\"Foo\"/>"
"<method name=\"Bar\"/>" "<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; << map;
// arguments // arguments
@ -428,7 +356,7 @@ void tst_QDBusXmlParser::signals__data()
QTest::newRow("signal-with-annotation") << QTest::newRow("signal-with-annotation") <<
"<signal name=\"Foo\"/>" "<signal name=\"Foo\"/>"
"<signal name=\"Bar\"/>" "<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; << map;
// one out argument // one out argument
@ -563,6 +491,7 @@ void tst_QDBusXmlParser::properties_data()
"<property name=\"baz\" type=\"as\" access=\"write\">" "<property name=\"baz\" type=\"as\" access=\"write\">"
"<annotation name=\"foo.annotation\" value=\"Hello, World\" />" "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
"<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />" "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
"</property>"
"<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map; "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
// and now change the order // and now change the order
@ -570,6 +499,7 @@ void tst_QDBusXmlParser::properties_data()
"<property name=\"baz\" type=\"as\" access=\"write\">" "<property name=\"baz\" type=\"as\" access=\"write\">"
"<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />" "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
"<annotation name=\"foo.annotation\" value=\"Hello, World\" />" "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
"</property>"
"<property name=\"bar\" type=\"i\" access=\"read\"/>" "<property name=\"bar\" type=\"i\" access=\"read\"/>"
"<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map; "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
} }