Qt 4.8
qdbusxmlparser.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdbusxmlparser_p.h"
43 #include "qdbusinterface.h"
44 #include "qdbusinterface_p.h"
45 #include "qdbusconnection_p.h"
46 #include "qdbusutil_p.h"
47 
48 #include <QtXml/qdom.h>
49 #include <QtCore/qmap.h>
50 #include <QtCore/qvariant.h>
51 #include <QtCore/qtextstream.h>
52 
53 #ifndef QT_NO_DBUS
54 
55 //#define QDBUS_PARSER_DEBUG
56 #ifdef QDBUS_PARSER_DEBUG
57 # define qDBusParserError qWarning
58 #else
59 # define qDBusParserError if (true) {} else qDebug
60 #endif
61 
63 
66 {
68  QDomNodeList list = elem.elementsByTagName(QLatin1String("annotation"));
69  for (int i = 0; i < list.count(); ++i)
70  {
71  QDomElement ann = list.item(i).toElement();
72  if (ann.isNull())
73  continue;
74 
75  QString name = ann.attribute(QLatin1String("name")),
76  value = ann.attribute(QLatin1String("value"));
77 
79  qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
80  qPrintable(name));
81  continue;
82  }
83 
84  retval.insert(name, value);
85  }
86 
87  return retval;
88 }
89 
91 parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty)
92 {
94  QDomNodeList list = elem.elementsByTagName(QLatin1String("arg"));
95  for (int i = 0; i < list.count(); ++i)
96  {
97  QDomElement arg = list.item(i).toElement();
98  if (arg.isNull())
99  continue;
100 
101  if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
102  arg.attribute(QLatin1String("direction")) == direction) {
103 
105  if (arg.hasAttribute(QLatin1String("name")))
106  argData.name = arg.attribute(QLatin1String("name")); // can be empty
107  argData.type = arg.attribute(QLatin1String("type"));
108  if (!QDBusUtil::isValidSingleSignature(argData.type)) {
109  qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
110  qPrintable(argData.type));
111  }
112 
113  retval << argData;
114  }
115  }
116  return retval;
117 }
118 
119 QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
120  const QString& xmlData)
121  : m_service(service), m_path(path)
122 {
123  QDomDocument doc;
124  doc.setContent(xmlData);
125  m_node = doc.firstChildElement(QLatin1String("node"));
126 }
127 
128 QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
129  const QDomElement& node)
130  : m_service(service), m_path(path), m_node(node)
131 {
132 }
133 
136 {
138 
139  if (m_node.isNull())
140  return retval;
141 
142  QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
143  for (int i = 0; i < interfaceList.count(); ++i)
144  {
145  QDomElement iface = interfaceList.item(i).toElement();
146  QString ifaceName = iface.attribute(QLatin1String("name"));
147  if (iface.isNull())
148  continue; // for whatever reason
149  if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
150  qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
151  qPrintable(ifaceName));
152  continue;
153  }
154 
156  ifaceData->name = ifaceName;
157  {
158  // save the data
159  QTextStream ts(&ifaceData->introspection);
160  iface.save(ts,2);
161  }
162 
163  // parse annotations
164  ifaceData->annotations = parseAnnotations(iface);
165 
166  // parse methods
167  QDomNodeList list = iface.elementsByTagName(QLatin1String("method"));
168  for (int j = 0; j < list.count(); ++j)
169  {
170  QDomElement method = list.item(j).toElement();
171  QString methodName = method.attribute(QLatin1String("name"));
172  if (method.isNull())
173  continue;
174  if (!QDBusUtil::isValidMemberName(methodName)) {
175  qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
176  qPrintable(methodName), qPrintable(ifaceName));
177  continue;
178  }
179 
180  QDBusIntrospection::Method methodData;
181  methodData.name = methodName;
182 
183  // parse arguments
184  methodData.inputArgs = parseArgs(method, QLatin1String("in"), true);
185  methodData.outputArgs = parseArgs(method, QLatin1String("out"), false);
186  methodData.annotations = parseAnnotations(method);
187 
188  // add it
189  ifaceData->methods.insert(methodName, methodData);
190  }
191 
192  // parse signals
193  list = iface.elementsByTagName(QLatin1String("signal"));
194  for (int j = 0; j < list.count(); ++j)
195  {
196  QDomElement signal = list.item(j).toElement();
197  QString signalName = signal.attribute(QLatin1String("name"));
198  if (signal.isNull())
199  continue;
200  if (!QDBusUtil::isValidMemberName(signalName)) {
201  qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
202  qPrintable(signalName), qPrintable(ifaceName));
203  continue;
204  }
205 
206  QDBusIntrospection::Signal signalData;
207  signalData.name = signalName;
208 
209  // parse data
210  signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
211  signalData.annotations = parseAnnotations(signal);
212 
213  // add it
214  ifaceData->signals_.insert(signalName, signalData);
215  }
216 
217  // parse properties
218  list = iface.elementsByTagName(QLatin1String("property"));
219  for (int j = 0; j < list.count(); ++j)
220  {
221  QDomElement property = list.item(j).toElement();
222  QString propertyName = property.attribute(QLatin1String("name"));
223  if (property.isNull())
224  continue;
225  if (!QDBusUtil::isValidMemberName(propertyName)) {
226  qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
227  qPrintable(propertyName), qPrintable(ifaceName));
228  continue;
229  }
230 
231  QDBusIntrospection::Property propertyData;
232 
233  // parse data
234  propertyData.name = propertyName;
235  propertyData.type = property.attribute(QLatin1String("type"));
236  propertyData.annotations = parseAnnotations(property);
237 
238  if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
239  // cannot be!
240  qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
241  qPrintable(propertyData.type), qPrintable(ifaceName),
242  qPrintable(propertyName));
243  }
244 
245  QString access = property.attribute(QLatin1String("access"));
246  if (access == QLatin1String("read"))
248  else if (access == QLatin1String("write"))
250  else if (access == QLatin1String("readwrite"))
252  else {
253  qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
254  qPrintable(access), qPrintable(ifaceName),
255  qPrintable(propertyName));
256  continue; // invalid one!
257  }
258 
259  // add it
260  ifaceData->properties.insert(propertyName, propertyData);
261  }
262 
263  // add it
264  retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
265  }
266 
267  return retval;
268 }
269 
272 {
273  if (m_node.isNull())
275 
277  objData = new QDBusIntrospection::Object;
278  objData->service = m_service;
279  objData->path = m_path;
280 
281  // check if we have anything to process
282  if (objData->introspection.isNull() && !m_node.firstChild().isNull()) {
283  // yes, introspect this object
284  QTextStream ts(&objData->introspection);
285  m_node.save(ts,2);
286 
288  for (int i = 0; i < objects.count(); ++i) {
289  QDomElement obj = objects.item(i).toElement();
290  QString objName = obj.attribute(QLatin1String("name"));
291  if (obj.isNull())
292  continue; // for whatever reason
293  if (!QDBusUtil::isValidObjectPath(m_path + QLatin1Char('/') + objName)) {
294  qDBusParserError("Invalid D-BUS object path '%s/%s' found while parsing introspection",
295  qPrintable(m_path), qPrintable(objName));
296  continue;
297  }
298 
299  objData->childObjects.append(objName);
300  }
301 
302  QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
303  for (int i = 0; i < interfaceList.count(); ++i) {
304  QDomElement iface = interfaceList.item(i).toElement();
305  QString ifaceName = iface.attribute(QLatin1String("name"));
306  if (iface.isNull())
307  continue;
308  if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
309  qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
310  qPrintable(ifaceName));
311  continue;
312  }
313 
314  objData->interfaces.append(ifaceName);
315  }
316  } else {
317  objData->introspection = QLatin1String("<node/>\n");
318  }
319 
321  retval = objData;
322  return retval;
323 }
324 
327 {
329 
330  if (m_node.isNull())
331  return retval;
332 
333  retval = new QDBusIntrospection::ObjectTree;
334 
335  retval->service = m_service;
336  retval->path = m_path;
337 
338  QTextStream ts(&retval->introspection);
339  m_node.save(ts,2);
340 
341  // interfaces are easy:
342  retval->interfaceData = interfaces();
343  retval->interfaces = retval->interfaceData.keys();
344 
345  // sub-objects are slightly more difficult:
347  for (int i = 0; i < objects.count(); ++i) {
348  QDomElement obj = objects.item(i).toElement();
349  QString objName = obj.attribute(QLatin1String("name"));
350  if (obj.isNull() || objName.isEmpty())
351  continue; // for whatever reason
352 
353  // check if we have anything to process
354  if (!obj.firstChild().isNull()) {
355  // yes, introspect this object
356  QString xml;
357  QTextStream ts2(&xml);
358  obj.save(ts2,0);
359 
360  // parse it
361  QString objAbsName = m_path;
362  if (!objAbsName.endsWith(QLatin1Char('/')))
363  objAbsName.append(QLatin1Char('/'));
364  objAbsName += objName;
365 
366  QDBusXmlParser parser(m_service, objAbsName, obj);
367  retval->childObjectData.insert(objName, parser.objectTree());
368  }
369 
370  retval->childObjects << objName;
371  }
372 
374 }
375 
377 
378 #endif // QT_NO_DBUS
QString path
The object&#39;s path on the service.
QStringList childObjects
The list of child object names in this object.
QDomElement firstChildElement(const QString &tagName=QString()) const
Returns the first child element with tag name tagName if tagName is non-empty; otherwise returns the ...
Definition: qdom.cpp:2990
QStringList interfaces
The list of interface names in this object.
static QDBusIntrospection::Annotations parseAnnotations(const QDomElement &elem)
Information about one object on the bus.
Objects childObjectData
A map of object paths and their data.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QString name
The method&#39;s name.
static QDBusIntrospection::Arguments parseArgs(const QDomElement &elem, const QLatin1String &direction, bool acceptEmpty)
bool isValidObjectPath(const QString &path)
Returns true if path is valid object path.
Definition: qdbusutil.cpp:515
QString name
The property&#39;s name.
Arguments outputArgs
A list of the signal&#39;s arguments.
QDBusXmlParser(const QString &service, const QString &path, const QString &xmlData)
Information about one property.
Annotations annotations
The annotations associated with the method.
One argument to a D-Bus method or signal.
QMap< Key, T >::iterator insert(const Key &key, const T &value)
Inserts a new item with the key key and a value of value.
Definition: qmap.h:982
QDBusIntrospection::Interfaces interfaces() const
Signals signals_
The signals available in this interface.
QSharedDataPointer< QDBusIntrospection::ObjectTree > objectTree() const
QDomNode firstChild() const
Returns the first child of the node.
Definition: qdom.cpp:2304
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
Interfaces interfaceData
A map of interfaces and their names.
The QString class provides a Unicode character string.
Definition: qstring.h:83
Properties properties
The properties available in this interface.
bool isValidInterfaceName(const QString &ifaceName)
Returns true if this is ifaceName is a valid interface name.
Definition: qdbusutil.cpp:367
Arguments outputArgs
A list of the method&#39;s output arguments (i.
bool setContent(const QByteArray &text, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
Definition: qdom.cpp:6887
QDomNodeList elementsByTagName(const QString &tagname) const
Returns a QDomNodeList containing all descendants of this element named tagname encountered during a ...
Definition: qdom.cpp:5075
QString name
The interface&#39;s name.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QDomDocument class represents an XML document.
Definition: qdom.h:308
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QDomElement toElement() const
Converts a QDomNode into a QDomElement.
Definition: qdom.cpp:7449
Arguments inputArgs
A list of the method&#39;s input arguments.
int access(const char *, int)
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
const char * name
Annotations annotations
The annotations associated with the signal.
bool isValidMemberName(const QString &memberName)
Returns true if memberName is a valid member name.
Definition: qdbusutil.cpp:472
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
bool isValidSingleSignature(const QString &signature)
Returns true if signature is a valid D-Bus type signature for exactly one full type.
Definition: qdbusutil.cpp:593
QList< Key > keys() const
Returns a list containing all the keys in the map in ascending order.
Definition: qmap.h:818
Complete information about one object node and its descendency.
QString type
The argument type.
Information about one signal.
QString service
The object&#39;s service name.
Annotations annotations
The annotations associated with the interface.
QString introspection
The XML document fragment describing this interface.
QString attribute(const QString &name, const QString &defValue=QString()) const
Returns the attribute called name.
Definition: qdom.cpp:4897
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition: qstring.h:505
QString name
The argument name.
#define qDBusParserError
QString & append(QChar c)
Definition: qstring.cpp:1777
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:73
QString type
The property&#39;s type.
Methods methods
The methods available in this interface.
bool hasAttribute(const QString &name) const
Returns true if this element has an attribute called name; otherwise returns false.
Definition: qdom.cpp:5092
iterator insert(const Key &key, const T &value)
Inserts a new item with the key key and a value of value.
Definition: qmap.h:559
int count() const
This function is provided for Qt API consistency.
Definition: qdom.h:269
QSharedDataPointer< QDBusIntrospection::Object > object() const
Information about one interface on the bus.
static QByteArray methodName(const char *signature, int nameLength)
Makes a deep copy of the first nameLength characters of the given method signature and returns the co...
bool isNull() const
Returns true if this node is null (i.e.
Definition: qdom.cpp:2679
const char * property
Definition: qwizard.cpp:138
The QDomNodeList class is a list of QDomNode objects.
Definition: qdom.h:253
QDomNode item(int index) const
Returns the node at position index.
Definition: qdom.cpp:1410
QString name
The signal&#39;s name.
QDomElement m_node
Access access
The property&#39;s access rights.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
Annotations annotations
The annotations associated with the property.
#define qPrintable(string)
Definition: qglobal.h:1750
Information about one method.
The QDomElement class represents one element in the DOM tree.
Definition: qdom.h:476
void save(QTextStream &, int) const
Writes the XML representation of the node and all its children to the stream str. ...
Definition: qdom.cpp:2728
The QSharedDataPointer class represents a pointer to an implicitly shared object. ...
Definition: qshareddata.h:54
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
QString introspection
The XML document fragment describing this object, its interfaces and sub-objects at the time of the p...
Qt::LayoutDirection direction