diff options
Diffstat (limited to 'qt/qdbusxmlparser.cpp')
-rw-r--r-- | qt/qdbusxmlparser.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/qt/qdbusxmlparser.cpp b/qt/qdbusxmlparser.cpp new file mode 100644 index 00000000..9d80fe22 --- /dev/null +++ b/qt/qdbusxmlparser.cpp @@ -0,0 +1,347 @@ +/* -*- C++ -*- + * + * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> + * Copyright (C) 2006 Trolltech AS. All rights reserved. + * Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "qdbusxmlparser_p.h" +#include "qdbusinterface.h" +#include "qdbusinterface_p.h" +#include "qdbusconnection_p.h" +#include "qdbusobject_p.h" + +#include <QtXml/qdom.h> +#include <QtCore/qmap.h> +#include <QtCore/qvariant.h> +#include <QtCore/qtextstream.h> + +static QDBusIntrospection::Annotations +parseAnnotations(const QDomElement& elem) +{ + QDBusIntrospection::Annotations retval; + QDomNodeList list = elem.elementsByTagName("annotation"); + for (int i = 0; i < list.count(); ++i) + { + QDomElement ann = list.item(i).toElement(); + if (ann.isNull()) + continue; + + QString name = ann.attribute("name"), + value = ann.attribute("value"); + + if (name.isEmpty()) + continue; + + retval.insert(name, value); + } + + return retval; +} + +static QDBusType +parseType(const QString& type) +{ + if (type.isEmpty()) + return QDBusType(); + return QDBusType(type); +} + +static QDBusIntrospection::Arguments +parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty = false) +{ + QDBusIntrospection::Arguments retval; + QDomNodeList list = elem.elementsByTagName("arg"); + for (int i = 0; i < list.count(); ++i) + { + QDomElement arg = list.item(i).toElement(); + if (arg.isNull()) + continue; + + if ((acceptEmpty && !arg.hasAttribute("direction")) || + arg.attribute("direction") == direction) { + + QDBusIntrospection::Argument argData; + if (arg.hasAttribute("name")) + argData.name = arg.attribute("name"); // can be empty + argData.type = parseType(arg.attribute("type")); + + if (!argData.type.isValid()) + continue; + + retval << argData; + } + } + return retval; +} + +QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, + const QString& xmlData, QDBusConnectionPrivate* store) + : m_service(service), m_path(path), m_store(store) +{ + QDomDocument doc; + doc.setContent(xmlData); + m_node = doc.firstChildElement("node"); +} + +QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path, + const QDomElement& node, QDBusConnectionPrivate* store) + : m_service(service), m_path(path), m_node(node), m_store(store) +{ +} + +void QDBusXmlParser::parse(const QDBusObjectPrivate* d, const QString &xml) +{ + QDBusXmlParser parser(d->data->service, d->data->path, xml, d->parent); + parser.object(); + parser.interfaces(); +} + +QDBusIntrospection::Interfaces +QDBusXmlParser::interfaces() const +{ + QDBusIntrospection::Interfaces retval; + + if (m_node.isNull()) + return retval; + + QDomNodeList interfaces = m_node.elementsByTagName("interface"); + for (int i = 0; i < interfaces.count(); ++i) + { + QDomElement iface = interfaces.item(i).toElement(); + QString ifaceName = iface.attribute("name"); + if (iface.isNull() || ifaceName.isEmpty()) + continue; // for whatever reason + + QDBusIntrospection::Interface *ifaceData; + if (m_store) { + QSharedDataPointer<QDBusIntrospection::Interface> knownData = + m_store->findInterface(ifaceName); + if (!knownData.constData()->introspection.isEmpty()) { + // it's already known + // we don't have to re-parse + retval.insert(ifaceName, knownData); + continue; + } + + // ugly, but ok + // we don't want to detach + // we *WANT* to modify the shared data + ifaceData = const_cast<QDBusIntrospection::Interface*>( knownData.constData() ); + } + else { + 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("method"); + for (int j = 0; j < list.count(); ++j) + { + QDomElement method = list.item(j).toElement(); + QString methodName = method.attribute("name"); + if (method.isNull() || methodName.isEmpty()) + continue; + + QDBusIntrospection::Method methodData; + methodData.name = methodName; + + // parse arguments + methodData.inputArgs = parseArgs(method, QLatin1String("in")); + methodData.outputArgs = parseArgs(method, QLatin1String("out")); + methodData.annotations = parseAnnotations(method); + + // add it + ifaceData->methods.insert(methodName, methodData); + } + + // parse signals + list = iface.elementsByTagName("signal"); + for (int j = 0; j < list.count(); ++j) + { + QDomElement signal = list.item(j).toElement(); + QString signalName = signal.attribute("name"); + if (signal.isNull() || signalName.isEmpty()) + 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("property"); + for (int j = 0; j < list.count(); ++j) + { + QDomElement property = list.item(j).toElement(); + QString propertyName = property.attribute("name"); + if (property.isNull() || propertyName.isEmpty()) + continue; + + QDBusIntrospection::Property propertyData; + + // parse data + propertyData.name = propertyName; + propertyData.type = parseType(property.attribute("type")); + propertyData.annotations = parseAnnotations(property); + + if (!propertyData.type.isValid()) + // cannot be! + continue; + + QString access = property.attribute("access"); + if (access.isEmpty()) + // can't be empty either! + continue; + else 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 + 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 +{ + QSharedDataPointer<QDBusIntrospection::Object> retval; + + if (m_node.isNull()) + return retval; + + // check if the store knows about this one + QDBusIntrospection::Object* objData; + if (m_store) { + retval = objData = m_store->findObject(m_service, m_path); + } + else { + 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("node"); + for (int i = 0; i < objects.count(); ++i) { + QDomElement obj = objects.item(i).toElement(); + QString objName = obj.attribute("name"); + if (obj.isNull() || objName.isEmpty()) + continue; // for whatever reason + + objData->childObjects.append(objName); + } + + QDomNodeList interfaces = m_node.elementsByTagName("interface"); + for (int i = 0; i < interfaces.count(); ++i) { + QDomElement iface = interfaces.item(i).toElement(); + QString ifaceName = iface.attribute("name"); + if (iface.isNull() || ifaceName.isEmpty()) + continue; + + objData->interfaces.append(ifaceName); + } + } + + 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("node"); + for (int i = 0; i < objects.count(); ++i) { + QDomElement obj = objects.item(i).toElement(); + QString objName = obj.attribute("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 ts(&xml); + obj.save(ts,0); + + // parse it + QString objAbsName = m_path; + if (!objAbsName.endsWith('/')) + objAbsName.append('/'); + objAbsName += objName; + + QDBusXmlParser parser(m_service, objAbsName, obj, m_store); + retval->childObjectData.insert(objName, parser.objectTree()); + } + + retval->childObjects << objName; + } + + return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval ); +} + |