summaryrefslogtreecommitdiffstats
path: root/src/dbus/qdbusxmlparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbus/qdbusxmlparser.cpp')
-rw-r--r--src/dbus/qdbusxmlparser.cpp514
1 files changed, 248 insertions, 266 deletions
diff --git a/src/dbus/qdbusxmlparser.cpp b/src/dbus/qdbusxmlparser.cpp
index b1d0b78c96..b563fa934b 100644
--- a/src/dbus/qdbusxmlparser.cpp
+++ b/src/dbus/qdbusxmlparser.cpp
@@ -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;
-
- 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