3 * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
4 * Copyright (C) 2006 Trolltech AS. All rights reserved.
5 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "qdbusxmlparser_p.h"
26 #include "qdbusinterface.h"
27 #include "qdbusinterface_p.h"
28 #include "qdbusconnection_p.h"
29 #include "qdbusutil.h"
31 #include <QtXml/qdom.h>
32 #include <QtCore/qmap.h>
33 #include <QtCore/qvariant.h>
34 #include <QtCore/qtextstream.h>
36 static QDBusIntrospection::Annotations
37 parseAnnotations(const QDomElement& elem)
39 QDBusIntrospection::Annotations retval;
40 QDomNodeList list = elem.elementsByTagName(QLatin1String("annotation"));
41 for (int i = 0; i < list.count(); ++i)
43 QDomElement ann = list.item(i).toElement();
47 QString name = ann.attribute(QLatin1String("name")),
48 value = ann.attribute(QLatin1String("value"));
53 retval.insert(name, value);
59 static QDBusIntrospection::Arguments
60 parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty = false)
62 QDBusIntrospection::Arguments retval;
63 QDomNodeList list = elem.elementsByTagName(QLatin1String("arg"));
64 for (int i = 0; i < list.count(); ++i)
66 QDomElement arg = list.item(i).toElement();
70 if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
71 arg.attribute(QLatin1String("direction")) == direction) {
73 QDBusIntrospection::Argument argData;
74 if (arg.hasAttribute(QLatin1String("name")))
75 argData.name = arg.attribute(QLatin1String("name")); // can be empty
76 argData.type = arg.attribute(QLatin1String("type"));
77 if (!QDBusUtil::isValidSingleSignature(argData.type))
86 QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
87 const QString& xmlData)
88 : m_service(service), m_path(path)
91 doc.setContent(xmlData);
92 m_node = doc.firstChildElement(QLatin1String("node"));
95 QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
96 const QDomElement& node)
97 : m_service(service), m_path(path), m_node(node)
101 QDBusIntrospection::Interfaces
102 QDBusXmlParser::interfaces() const
104 QDBusIntrospection::Interfaces retval;
109 QDomNodeList interfaces = m_node.elementsByTagName(QLatin1String("interface"));
110 for (int i = 0; i < interfaces.count(); ++i)
112 QDomElement iface = interfaces.item(i).toElement();
113 QString ifaceName = iface.attribute(QLatin1String("name"));
114 if (iface.isNull() || ifaceName.isEmpty())
115 continue; // for whatever reason
117 QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
118 ifaceData->name = ifaceName;
121 QTextStream ts(&ifaceData->introspection);
126 ifaceData->annotations = parseAnnotations(iface);
129 QDomNodeList list = iface.elementsByTagName(QLatin1String("method"));
130 for (int j = 0; j < list.count(); ++j)
132 QDomElement method = list.item(j).toElement();
133 QString methodName = method.attribute(QLatin1String("name"));
134 if (method.isNull() || methodName.isEmpty())
137 QDBusIntrospection::Method methodData;
138 methodData.name = methodName;
141 methodData.inputArgs = parseArgs(method, QLatin1String("in"));
142 methodData.outputArgs = parseArgs(method, QLatin1String("out"));
143 methodData.annotations = parseAnnotations(method);
146 ifaceData->methods.insert(methodName, methodData);
150 list = iface.elementsByTagName(QLatin1String("signal"));
151 for (int j = 0; j < list.count(); ++j)
153 QDomElement signal = list.item(j).toElement();
154 QString signalName = signal.attribute(QLatin1String("name"));
155 if (signal.isNull() || signalName.isEmpty())
158 QDBusIntrospection::Signal signalData;
159 signalData.name = signalName;
162 signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
163 signalData.annotations = parseAnnotations(signal);
166 ifaceData->signals_.insert(signalName, signalData);
170 list = iface.elementsByTagName(QLatin1String("property"));
171 for (int j = 0; j < list.count(); ++j)
173 QDomElement property = list.item(j).toElement();
174 QString propertyName = property.attribute(QLatin1String("name"));
175 if (property.isNull() || propertyName.isEmpty())
178 QDBusIntrospection::Property propertyData;
181 propertyData.name = propertyName;
182 propertyData.type = property.attribute(QLatin1String("type"));
183 propertyData.annotations = parseAnnotations(property);
185 if (!QDBusUtil::isValidSingleSignature(propertyData.type))
189 QString access = property.attribute(QLatin1String("access"));
190 if (access.isEmpty())
191 // can't be empty either!
193 else if (access == QLatin1String("read"))
194 propertyData.access = QDBusIntrospection::Property::Read;
195 else if (access == QLatin1String("write"))
196 propertyData.access = QDBusIntrospection::Property::Write;
197 else if (access == QLatin1String("readwrite"))
198 propertyData.access = QDBusIntrospection::Property::ReadWrite;
200 continue; // invalid one!
203 ifaceData->properties.insert(propertyName, propertyData);
207 retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
213 QSharedDataPointer<QDBusIntrospection::Object>
214 QDBusXmlParser::object() const
217 return QSharedDataPointer<QDBusIntrospection::Object>();
219 QDBusIntrospection::Object* objData;
220 objData = new QDBusIntrospection::Object;
221 objData->service = m_service;
222 objData->path = m_path;
224 // check if we have anything to process
225 if (objData->introspection.isNull() && !m_node.firstChild().isNull()) {
226 // yes, introspect this object
227 QTextStream ts(&objData->introspection);
230 QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
231 for (int i = 0; i < objects.count(); ++i) {
232 QDomElement obj = objects.item(i).toElement();
233 QString objName = obj.attribute(QLatin1String("name"));
234 if (obj.isNull() || objName.isEmpty())
235 continue; // for whatever reason
237 objData->childObjects.append(objName);
240 QDomNodeList interfaces = m_node.elementsByTagName(QLatin1String("interface"));
241 for (int i = 0; i < interfaces.count(); ++i) {
242 QDomElement iface = interfaces.item(i).toElement();
243 QString ifaceName = iface.attribute(QLatin1String("name"));
244 if (iface.isNull() || ifaceName.isEmpty())
247 objData->interfaces.append(ifaceName);
250 objData->introspection = QLatin1String("<node/>\n");
253 QSharedDataPointer<QDBusIntrospection::Object> retval;
258 QSharedDataPointer<QDBusIntrospection::ObjectTree>
259 QDBusXmlParser::objectTree() const
261 QSharedDataPointer<QDBusIntrospection::ObjectTree> retval;
266 retval = new QDBusIntrospection::ObjectTree;
268 retval->service = m_service;
269 retval->path = m_path;
271 QTextStream ts(&retval->introspection);
274 // interfaces are easy:
275 retval->interfaceData = interfaces();
276 retval->interfaces = retval->interfaceData.keys();
278 // sub-objects are slightly more difficult:
279 QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
280 for (int i = 0; i < objects.count(); ++i) {
281 QDomElement obj = objects.item(i).toElement();
282 QString objName = obj.attribute(QLatin1String("name"));
283 if (obj.isNull() || objName.isEmpty())
284 continue; // for whatever reason
286 // check if we have anything to process
287 if (!obj.firstChild().isNull()) {
288 // yes, introspect this object
290 QTextStream ts(&xml);
294 QString objAbsName = m_path;
295 if (!objAbsName.endsWith(QLatin1Char('/')))
296 objAbsName.append(QLatin1Char('/'));
297 objAbsName += objName;
299 QDBusXmlParser parser(m_service, objAbsName, obj);
300 retval->childObjectData.insert(objName, parser.objectTree());
303 retval->childObjects << objName;
306 return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );