source: trunk/src/dbus/qdbusutil.cpp@ 930

Last change on this file since 930 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 16.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtDBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdbusutil_p.h"
43
44#include "qdbus_symbols_p.h"
45
46#include <QtCore/qstringlist.h>
47
48#include "qdbusargument.h"
49
50#ifndef QT_NO_DBUS
51
52QT_BEGIN_NAMESPACE
53
54static inline bool isValidCharacterNoDash(const QChar &c)
55{
56 register ushort u = c.unicode();
57 return (u >= 'a' && u <= 'z')
58 || (u >= 'A' && u <= 'Z')
59 || (u >= '0' && u <= '9')
60 || (u == '_');
61}
62
63static inline bool isValidCharacter(const QChar &c)
64{
65 register ushort u = c.unicode();
66 return (u >= 'a' && u <= 'z')
67 || (u >= 'A' && u <= 'Z')
68 || (u >= '0' && u <= '9')
69 || (u == '_') || (u == '-');
70}
71
72static inline bool isValidNumber(const QChar &c)
73{
74 register ushort u = c.unicode();
75 return (u >= '0' && u <= '9');
76}
77
78static bool argToString(const QDBusArgument &arg, QString &out);
79
80static bool variantToString(const QVariant &arg, QString &out)
81{
82 int argType = arg.userType();
83
84 if (argType == QVariant::StringList) {
85 out += QLatin1Char('{');
86 QStringList list = arg.toStringList();
87 foreach (QString item, list)
88 out += QLatin1Char('\"') + item + QLatin1String("\", ");
89 if (!list.isEmpty())
90 out.chop(2);
91 out += QLatin1Char('}');
92 } else if (argType == QVariant::ByteArray) {
93 out += QLatin1Char('{');
94 QByteArray list = arg.toByteArray();
95 for (int i = 0; i < list.count(); ++i) {
96 out += QString::number(list.at(i));
97 out += QLatin1String(", ");
98 }
99 if (!list.isEmpty())
100 out.chop(2);
101 out += QLatin1Char('}');
102 } else if (argType == QVariant::List) {
103 out += QLatin1Char('{');
104 QList<QVariant> list = arg.toList();
105 foreach (QVariant item, list) {
106 if (!variantToString(item, out))
107 return false;
108 out += QLatin1String(", ");
109 }
110 if (!list.isEmpty())
111 out.chop(2);
112 out += QLatin1Char('}');
113 } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
114 || argType == QMetaType::Long || argType == QMetaType::LongLong) {
115 out += QString::number(arg.toLongLong());
116 } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
117 || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
118 out += QString::number(arg.toULongLong());
119 } else if (argType == QMetaType::Double) {
120 out += QString::number(arg.toDouble());
121 } else if (argType == QMetaType::Bool) {
122 out += QLatin1String(arg.toBool() ? "true" : "false");
123 } else if (argType == qMetaTypeId<QDBusArgument>()) {
124 argToString(qvariant_cast<QDBusArgument>(arg), out);
125 } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
126 const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
127 out += QLatin1String("[ObjectPath: ");
128 out += path;
129 out += QLatin1Char(']');
130 } else if (argType == qMetaTypeId<QDBusSignature>()) {
131 out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
132 out += QLatin1Char(']');
133 } else if (argType == qMetaTypeId<QDBusVariant>()) {
134 const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
135 out += QLatin1String("[Variant");
136 int vUserType = v.userType();
137 if (vUserType != qMetaTypeId<QDBusVariant>()
138 && vUserType != qMetaTypeId<QDBusSignature>()
139 && vUserType != qMetaTypeId<QDBusObjectPath>()
140 && vUserType != qMetaTypeId<QDBusArgument>())
141 out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
142 out += QLatin1String(": ");
143 if (!variantToString(v, out))
144 return false;
145 out += QLatin1Char(']');
146 } else if (arg.canConvert(QVariant::String)) {
147 out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
148 } else {
149 out += QLatin1Char('[');
150 out += QLatin1String(arg.typeName());
151 out += QLatin1Char(']');
152 }
153
154 return true;
155}
156
157bool argToString(const QDBusArgument &busArg, QString &out)
158{
159 QString busSig = busArg.currentSignature();
160 bool doIterate = false;
161 QDBusArgument::ElementType elementType = busArg.currentType();
162
163 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
164 && elementType != QDBusArgument::MapEntryType)
165 out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
166
167 switch (elementType) {
168 case QDBusArgument::BasicType:
169 case QDBusArgument::VariantType:
170 if (!variantToString(busArg.asVariant(), out))
171 return false;
172 break;
173 case QDBusArgument::StructureType:
174 busArg.beginStructure();
175 doIterate = true;
176 break;
177 case QDBusArgument::ArrayType:
178 busArg.beginArray();
179 out += QLatin1Char('{');
180 doIterate = true;
181 break;
182 case QDBusArgument::MapType:
183 busArg.beginMap();
184 out += QLatin1Char('{');
185 doIterate = true;
186 break;
187 case QDBusArgument::MapEntryType:
188 busArg.beginMapEntry();
189 if (!variantToString(busArg.asVariant(), out))
190 return false;
191 out += QLatin1String(" = ");
192 if (!argToString(busArg, out))
193 return false;
194 busArg.endMapEntry();
195 break;
196 case QDBusArgument::UnknownType:
197 default:
198 out += QLatin1String("<ERROR - Unknown Type>");
199 return false;
200 }
201 if (doIterate && !busArg.atEnd()) {
202 while (!busArg.atEnd()) {
203 if (!argToString(busArg, out))
204 return false;
205 out += QLatin1String(", ");
206 }
207 out.chop(2);
208 }
209 switch (elementType) {
210 case QDBusArgument::BasicType:
211 case QDBusArgument::VariantType:
212 case QDBusArgument::UnknownType:
213 case QDBusArgument::MapEntryType:
214 // nothing to do
215 break;
216 case QDBusArgument::StructureType:
217 busArg.endStructure();
218 break;
219 case QDBusArgument::ArrayType:
220 out += QLatin1Char('}');
221 busArg.endArray();
222 break;
223 case QDBusArgument::MapType:
224 out += QLatin1Char('}');
225 busArg.endMap();
226 break;
227 }
228
229 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
230 && elementType != QDBusArgument::MapEntryType)
231 out += QLatin1Char(']');
232
233 return true;
234}
235
236/*!
237 \namespace QDBusUtil
238 \inmodule QtDBus
239 \internal
240
241 \brief The QDBusUtil namespace contains a few functions that are of general use when
242 dealing with D-Bus strings.
243*/
244namespace QDBusUtil
245{
246 /*!
247 \internal
248 \since 4.5
249 Dumps the contents of a QtDBus argument from \a arg into a string.
250 */
251 QString argumentToString(const QVariant &arg)
252 {
253 QString out;
254
255 variantToString(arg, out);
256
257 return out;
258 }
259
260 /*!
261 \internal
262 \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
263 See QDBusUtil::isValidObjectPath
264 */
265 bool isValidPartOfObjectPath(const QString &part)
266 {
267 if (part.isEmpty())
268 return false; // can't be valid if it's empty
269
270 const QChar *c = part.unicode();
271 for (int i = 0; i < part.length(); ++i)
272 if (!isValidCharacterNoDash(c[i]))
273 return false;
274
275 return true;
276 }
277
278 /*!
279 \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
280 Returns true if this is \a ifaceName is a valid interface name.
281
282 Valid interface names must:
283 \list
284 \o not be empty
285 \o not exceed 255 characters in length
286 \o be composed of dot-separated string components that contain only ASCII letters, digits
287 and the underscore ("_") character
288 \o contain at least two such components
289 \endlist
290 */
291 bool isValidInterfaceName(const QString& ifaceName)
292 {
293 if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
294 return false;
295
296 QStringList parts = ifaceName.split(QLatin1Char('.'));
297 if (parts.count() < 2)
298 return false; // at least two parts
299
300 for (int i = 0; i < parts.count(); ++i)
301 if (!isValidMemberName(parts.at(i)))
302 return false;
303
304 return true;
305 }
306
307 /*!
308 \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
309 Returns true if \a connName is a valid unique connection name.
310
311 Unique connection names start with a colon (":") and are followed by a list of dot-separated
312 components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
313 */
314 bool isValidUniqueConnectionName(const QString &connName)
315 {
316 if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
317 !connName.startsWith(QLatin1Char(':')))
318 return false;
319
320 QStringList parts = connName.mid(1).split(QLatin1Char('.'));
321 if (parts.count() < 1)
322 return false;
323
324 for (int i = 0; i < parts.count(); ++i) {
325 const QString &part = parts.at(i);
326 if (part.isEmpty())
327 return false;
328
329 const QChar* c = part.unicode();
330 for (int j = 0; j < part.length(); ++j)
331 if (!isValidCharacter(c[j]))
332 return false;
333 }
334
335 return true;
336 }
337
338 /*!
339 \fn bool QDBusUtil::isValidBusName(const QString &busName)
340 Returns true if \a busName is a valid bus name.
341
342 A valid bus name is either a valid unique connection name or follows the rules:
343 \list
344 \o is not empty
345 \o does not exceed 255 characters in length
346 \o be composed of dot-separated string components that contain only ASCII letters, digits,
347 hyphens or underscores ("_"), but don't start with a digit
348 \o contains at least two such elements
349 \endlist
350
351 \sa isValidUniqueConnectionName()
352 */
353 bool isValidBusName(const QString &busName)
354 {
355 if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
356 return false;
357
358 if (busName.startsWith(QLatin1Char(':')))
359 return isValidUniqueConnectionName(busName);
360
361 QStringList parts = busName.split(QLatin1Char('.'));
362 if (parts.count() < 1)
363 return false;
364
365 for (int i = 0; i < parts.count(); ++i) {
366 const QString &part = parts.at(i);
367 if (part.isEmpty())
368 return false;
369
370 const QChar *c = part.unicode();
371 if (isValidNumber(c[0]))
372 return false;
373 for (int j = 0; j < part.length(); ++j)
374 if (!isValidCharacter(c[j]))
375 return false;
376 }
377
378 return true;
379 }
380
381 /*!
382 \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
383 Returns true if \a memberName is a valid member name. A valid member name does not exceed
384 255 characters in length, is not empty, is composed only of ASCII letters, digits and
385 underscores, but does not start with a digit.
386 */
387 bool isValidMemberName(const QString &memberName)
388 {
389 if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
390 return false;
391
392 const QChar* c = memberName.unicode();
393 if (isValidNumber(c[0]))
394 return false;
395 for (int j = 0; j < memberName.length(); ++j)
396 if (!isValidCharacterNoDash(c[j]))
397 return false;
398 return true;
399 }
400
401 /*!
402 \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
403 Returns true if \a errorName is a valid error name. Valid error names are valid interface
404 names and vice-versa, so this function is actually an alias for isValidInterfaceName.
405 */
406 bool isValidErrorName(const QString &errorName)
407 {
408 return isValidInterfaceName(errorName);
409 }
410
411 /*!
412 \fn bool QDBusUtil::isValidObjectPath(const QString &path)
413 Returns true if \a path is valid object path.
414
415 Valid object paths follow the rules:
416 \list
417 \o start with the slash character ("/")
418 \o do not end in a slash, unless the path is just the initial slash
419 \o do not contain any two slashes in sequence
420 \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
421 underscores ("_")
422 \endlist
423 */
424 bool isValidObjectPath(const QString &path)
425 {
426 if (path == QLatin1String("/"))
427 return true;
428
429 if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
430 path.endsWith(QLatin1Char('/')))
431 return false;
432
433 QStringList parts = path.split(QLatin1Char('/'));
434 Q_ASSERT(parts.count() >= 1);
435 parts.removeFirst(); // it starts with /, so we get an empty first part
436
437 for (int i = 0; i < parts.count(); ++i)
438 if (!isValidPartOfObjectPath(parts.at(i)))
439 return false;
440
441 return true;
442 }
443
444 /*!
445 \fn bool QDBusUtil::isValidSignature(const QString &signature)
446 Returns true if \a signature is a valid D-Bus type signature for one or more types.
447 This function returns true if it can all of \a signature into valid, individual types and no
448 characters remain in \a signature.
449
450 \sa isValidSingleSignature()
451 */
452 bool isValidSignature(const QString &signature)
453 {
454 return q_dbus_signature_validate(signature.toUtf8(), 0);
455 }
456
457 /*!
458 \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
459 Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
460 function tries to convert the type signature into a D-Bus type and, if it succeeds and no
461 characters remain in the signature, it returns true.
462 */
463 bool isValidSingleSignature(const QString &signature)
464 {
465 return q_dbus_signature_validate_single(signature.toUtf8(), 0);
466 }
467
468} // namespace QDBusUtil
469
470QT_END_NAMESPACE
471
472#endif // QT_NO_DBUS
Note: See TracBrowser for help on using the repository browser.