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:
parent
7c247d3e70
commit
0696071316
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -40,337 +40,319 @@
|
||||
****************************************************************************/
|
||||
|
||||
#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;
|
||||
const QString argType = attributes.value(QLatin1String("type")).toString();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("annotation"));
|
||||
|
||||
if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
|
||||
arg.attribute(QLatin1String("direction")) == direction) {
|
||||
const QXmlStreamAttributes attributes = xml.attributes();
|
||||
const QString name = attributes.value(QLatin1String("name")).toString();
|
||||
|
||||
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));
|
||||
if (!QDBusUtil::isValidInterfaceName(name)) {
|
||||
qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
|
||||
qPrintable(name));
|
||||
return false;
|
||||
}
|
||||
annotations.insert(name, attributes.value(QLatin1String("value")).toString());
|
||||
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,
|
||||
const QString& xmlData)
|
||||
: m_service(service), m_path(path)
|
||||
: m_service(service), m_path(path), m_object(new QDBusIntrospection::Object)
|
||||
{
|
||||
QDomDocument doc;
|
||||
doc.setContent(xmlData);
|
||||
m_node = doc.firstChildElement(QLatin1String("node"));
|
||||
}
|
||||
// qDBusParserError() << "parsing" << xmlData;
|
||||
|
||||
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
|
||||
const QDomElement& node)
|
||||
: m_service(service), m_path(path), m_node(node)
|
||||
{
|
||||
}
|
||||
m_object->service = m_service;
|
||||
m_object->path = m_path;
|
||||
|
||||
QDBusIntrospection::Interfaces
|
||||
QDBusXmlParser::interfaces() const
|
||||
{
|
||||
QDBusIntrospection::Interfaces retval;
|
||||
QXmlStreamReader xml(xmlData);
|
||||
|
||||
if (m_node.isNull())
|
||||
return retval;
|
||||
int nodeLevel = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
while (!xml.atEnd()) {
|
||||
xml.readNext();
|
||||
|
||||
QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
|
||||
ifaceData->name = ifaceName;
|
||||
{
|
||||
// save the data
|
||||
QTextStream ts(&ifaceData->introspection);
|
||||
iface.save(ts,2);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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();
|
||||
}
|
||||
|
||||
QDBusIntrospection::Method methodData;
|
||||
methodData.name = methodName;
|
||||
|
||||
// parse arguments
|
||||
methodData.inputArgs = parseArgs(method, QLatin1String("in"), true);
|
||||
methodData.outputArgs = parseArgs(method, QLatin1String("out"), false);
|
||||
methodData.annotations = parseAnnotations(method);
|
||||
|
||||
// add it
|
||||
ifaceData->methods.insert(methodName, methodData);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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");
|
||||
if (xml.hasError()) {
|
||||
qDBusParserError() << "xml error" << xml.errorString() << "doc" << xmlData;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -46,7 +46,7 @@
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtDBus/QtDBus>
|
||||
|
||||
#include <qdebug.h>
|
||||
#include "../qdbusmarshall/common.h"
|
||||
#include "myobject.h"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user