diff -r 000000000000 -r 1918ee327afb src/dbus/qdbusxmlparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dbus/qdbusxmlparser.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdbusxmlparser_p.h" +#include "qdbusinterface.h" +#include "qdbusinterface_p.h" +#include "qdbusconnection_p.h" +#include "qdbusutil_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QDBusIntrospection::Annotations +parseAnnotations(const QDomElement& elem) +{ + 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)) { + qWarning("Invalid D-BUS annotation '%s' found while parsing introspection", + qPrintable(name)); + continue; + } + + retval.insert(name, value); + } + + return retval; +} + +static QDBusIntrospection::Arguments +parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty) +{ + 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)) { + qWarning("Invalid D-BUS type signature '%s' found while parsing introspection", + qPrintable(argData.type)); + continue; + } + + retval << argData; + } + } + return retval; +} + +QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, + const QString& xmlData) + : m_service(service), m_path(path) +{ + QDomDocument doc; + doc.setContent(xmlData); + m_node = doc.firstChildElement(QLatin1String("node")); +} + +QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, + const QDomElement& node) + : m_service(service), m_path(path), m_node(node) +{ +} + +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)) { + qWarning("Invalid D-BUS interface name '%s' found while parsing introspection", + qPrintable(ifaceName)); + continue; + } + + 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)) { + qWarning("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", + qPrintable(methodName), qPrintable(ifaceName)); + continue; + } + + 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); + } + + // 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)) { + qWarning("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)) { + qWarning("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! + qWarning("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection", + qPrintable(propertyData.type), qPrintable(ifaceName), + qPrintable(propertyName)); + continue; + } + + 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 { + qWarning("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(ifaceData)); + } + + return retval; +} + +QSharedDataPointer +QDBusXmlParser::object() const +{ + if (m_node.isNull()) + return QSharedDataPointer(); + + 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)) { + qWarning("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)) { + qWarning("Invalid D-BUS interface name '%s' found while parsing introspection", + qPrintable(ifaceName)); + continue; + } + + objData->interfaces.append(ifaceName); + } + } else { + objData->introspection = QLatin1String("\n"); + } + + QSharedDataPointer retval; + retval = objData; + return retval; +} + +QSharedDataPointer +QDBusXmlParser::objectTree() const +{ + QSharedDataPointer 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( retval ); +} + +QT_END_NAMESPACE