1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdbusutil_p.h"
44 #include "qdbus_symbols_p.h"
46 #include <QtCore/qstringlist.h>
48 #include "qdbusargument.h"
49 #include "qdbusunixfiledescriptor.h"
55 static inline bool isValidCharacterNoDash(const QChar &c)
57 register ushort u = c.unicode();
58 return (u >= 'a' && u <= 'z')
59 || (u >= 'A' && u <= 'Z')
60 || (u >= '0' && u <= '9')
64 static inline bool isValidCharacter(const QChar &c)
66 register ushort u = c.unicode();
67 return (u >= 'a' && u <= 'z')
68 || (u >= 'A' && u <= 'Z')
69 || (u >= '0' && u <= '9')
70 || (u == '_') || (u == '-');
73 static inline bool isValidNumber(const QChar &c)
75 register ushort u = c.unicode();
76 return (u >= '0' && u <= '9');
79 static bool argToString(const QDBusArgument &arg, QString &out);
81 static bool variantToString(const QVariant &arg, QString &out)
83 int argType = arg.userType();
85 if (argType == QVariant::StringList) {
86 out += QLatin1Char('{');
87 QStringList list = arg.toStringList();
88 foreach (QString item, list)
89 out += QLatin1Char('\"') + item + QLatin1String("\", ");
92 out += QLatin1Char('}');
93 } else if (argType == QVariant::ByteArray) {
94 out += QLatin1Char('{');
95 QByteArray list = arg.toByteArray();
96 for (int i = 0; i < list.count(); ++i) {
97 out += QString::number(list.at(i));
98 out += QLatin1String(", ");
102 out += QLatin1Char('}');
103 } else if (argType == QVariant::List) {
104 out += QLatin1Char('{');
105 QList<QVariant> list = arg.toList();
106 foreach (QVariant item, list) {
107 if (!variantToString(item, out))
109 out += QLatin1String(", ");
113 out += QLatin1Char('}');
114 } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
115 || argType == QMetaType::Long || argType == QMetaType::LongLong) {
116 out += QString::number(arg.toLongLong());
117 } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
118 || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
119 out += QString::number(arg.toULongLong());
120 } else if (argType == QMetaType::Double) {
121 out += QString::number(arg.toDouble());
122 } else if (argType == QMetaType::Bool) {
123 out += QLatin1String(arg.toBool() ? "true" : "false");
124 } else if (argType == qMetaTypeId<QDBusArgument>()) {
125 argToString(qvariant_cast<QDBusArgument>(arg), out);
126 } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
127 const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
128 out += QLatin1String("[ObjectPath: ");
130 out += QLatin1Char(']');
131 } else if (argType == qMetaTypeId<QDBusSignature>()) {
132 out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
133 out += QLatin1Char(']');
134 } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
135 out += QLatin1String("[Unix FD: ");
136 out += QLatin1String(qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid" : "not valid");
137 out += QLatin1Char(']');
138 } else if (argType == qMetaTypeId<QDBusVariant>()) {
139 const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
140 out += QLatin1String("[Variant");
141 int vUserType = v.userType();
142 if (vUserType != qMetaTypeId<QDBusVariant>()
143 && vUserType != qMetaTypeId<QDBusSignature>()
144 && vUserType != qMetaTypeId<QDBusObjectPath>()
145 && vUserType != qMetaTypeId<QDBusArgument>())
146 out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
147 out += QLatin1String(": ");
148 if (!variantToString(v, out))
150 out += QLatin1Char(']');
151 } else if (arg.canConvert(QVariant::String)) {
152 out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
154 out += QLatin1Char('[');
155 out += QLatin1String(arg.typeName());
156 out += QLatin1Char(']');
162 bool argToString(const QDBusArgument &busArg, QString &out)
164 QString busSig = busArg.currentSignature();
165 bool doIterate = false;
166 QDBusArgument::ElementType elementType = busArg.currentType();
168 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
169 && elementType != QDBusArgument::MapEntryType)
170 out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
172 switch (elementType) {
173 case QDBusArgument::BasicType:
174 case QDBusArgument::VariantType:
175 if (!variantToString(busArg.asVariant(), out))
178 case QDBusArgument::StructureType:
179 busArg.beginStructure();
182 case QDBusArgument::ArrayType:
184 out += QLatin1Char('{');
187 case QDBusArgument::MapType:
189 out += QLatin1Char('{');
192 case QDBusArgument::MapEntryType:
193 busArg.beginMapEntry();
194 if (!variantToString(busArg.asVariant(), out))
196 out += QLatin1String(" = ");
197 if (!argToString(busArg, out))
199 busArg.endMapEntry();
201 case QDBusArgument::UnknownType:
203 out += QLatin1String("<ERROR - Unknown Type>");
206 if (doIterate && !busArg.atEnd()) {
207 while (!busArg.atEnd()) {
208 if (!argToString(busArg, out))
210 out += QLatin1String(", ");
214 switch (elementType) {
215 case QDBusArgument::BasicType:
216 case QDBusArgument::VariantType:
217 case QDBusArgument::UnknownType:
218 case QDBusArgument::MapEntryType:
221 case QDBusArgument::StructureType:
222 busArg.endStructure();
224 case QDBusArgument::ArrayType:
225 out += QLatin1Char('}');
228 case QDBusArgument::MapType:
229 out += QLatin1Char('}');
234 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
235 && elementType != QDBusArgument::MapEntryType)
236 out += QLatin1Char(']');
241 //------- D-Bus Types --------
242 static const char oneLetterTypes[] = "vsogybnqiuxtdh";
243 static const char basicTypes[] = "sogybnqiuxtdh";
244 static const char fixedTypes[] = "ybnqiuxtdh";
246 static bool isBasicType(int c)
248 return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL;
251 static bool isFixedType(int c)
253 return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL;
256 // Returns a pointer to one-past-end of this type if it's valid;
257 // returns NULL if it isn't valid.
258 static const char *validateSingleType(const char *signature)
260 register char c = *signature;
261 if (c == DBUS_TYPE_INVALID)
264 // is it one of the one-letter types?
265 if (strchr(oneLetterTypes, c) != NULL)
266 return signature + 1;
269 if (c == DBUS_TYPE_ARRAY) {
270 // then it's valid if the next type is valid
271 // or if it's a dict-entry
273 if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) {
274 // beginning of a dictionary entry
275 // a dictionary entry has a key which is of basic types
280 signature = validateSingleType(signature + 1);
281 return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0;
284 return validateSingleType(signature);
287 if (c == DBUS_STRUCT_BEGIN_CHAR) {
288 // beginning of a struct
291 signature = validateSingleType(signature);
294 if (*signature == DBUS_STRUCT_END_CHAR)
295 return signature + 1;
299 // invalid/unknown type
308 \brief The QDBusUtil namespace contains a few functions that are of general use when
309 dealing with D-Bus strings.
316 Dumps the contents of a QtDBus argument from \a arg into a string.
318 QString argumentToString(const QVariant &arg)
322 variantToString(arg, out);
329 \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
330 See QDBusUtil::isValidObjectPath
332 bool isValidPartOfObjectPath(const QString &part)
335 return false; // can't be valid if it's empty
337 const QChar *c = part.unicode();
338 for (int i = 0; i < part.length(); ++i)
339 if (!isValidCharacterNoDash(c[i]))
346 \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
347 Returns true if this is \a ifaceName is a valid interface name.
349 Valid interface names must:
352 \o not exceed 255 characters in length
353 \o be composed of dot-separated string components that contain only ASCII letters, digits
354 and the underscore ("_") character
355 \o contain at least two such components
358 bool isValidInterfaceName(const QString& ifaceName)
360 if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
363 QStringList parts = ifaceName.split(QLatin1Char('.'));
364 if (parts.count() < 2)
365 return false; // at least two parts
367 for (int i = 0; i < parts.count(); ++i)
368 if (!isValidMemberName(parts.at(i)))
375 \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
376 Returns true if \a connName is a valid unique connection name.
378 Unique connection names start with a colon (":") and are followed by a list of dot-separated
379 components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
381 bool isValidUniqueConnectionName(const QString &connName)
383 if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
384 !connName.startsWith(QLatin1Char(':')))
387 QStringList parts = connName.mid(1).split(QLatin1Char('.'));
388 if (parts.count() < 1)
391 for (int i = 0; i < parts.count(); ++i) {
392 const QString &part = parts.at(i);
396 const QChar* c = part.unicode();
397 for (int j = 0; j < part.length(); ++j)
398 if (!isValidCharacter(c[j]))
406 \fn bool QDBusUtil::isValidBusName(const QString &busName)
407 Returns true if \a busName is a valid bus name.
409 A valid bus name is either a valid unique connection name or follows the rules:
412 \o does not exceed 255 characters in length
413 \o be composed of dot-separated string components that contain only ASCII letters, digits,
414 hyphens or underscores ("_"), but don't start with a digit
415 \o contains at least two such elements
418 \sa isValidUniqueConnectionName()
420 bool isValidBusName(const QString &busName)
422 if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
425 if (busName.startsWith(QLatin1Char(':')))
426 return isValidUniqueConnectionName(busName);
428 QStringList parts = busName.split(QLatin1Char('.'));
429 if (parts.count() < 1)
432 for (int i = 0; i < parts.count(); ++i) {
433 const QString &part = parts.at(i);
437 const QChar *c = part.unicode();
438 if (isValidNumber(c[0]))
440 for (int j = 0; j < part.length(); ++j)
441 if (!isValidCharacter(c[j]))
449 \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
450 Returns true if \a memberName is a valid member name. A valid member name does not exceed
451 255 characters in length, is not empty, is composed only of ASCII letters, digits and
452 underscores, but does not start with a digit.
454 bool isValidMemberName(const QString &memberName)
456 if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
459 const QChar* c = memberName.unicode();
460 if (isValidNumber(c[0]))
462 for (int j = 0; j < memberName.length(); ++j)
463 if (!isValidCharacterNoDash(c[j]))
469 \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
470 Returns true if \a errorName is a valid error name. Valid error names are valid interface
471 names and vice-versa, so this function is actually an alias for isValidInterfaceName.
473 bool isValidErrorName(const QString &errorName)
475 return isValidInterfaceName(errorName);
479 \fn bool QDBusUtil::isValidObjectPath(const QString &path)
480 Returns true if \a path is valid object path.
482 Valid object paths follow the rules:
484 \o start with the slash character ("/")
485 \o do not end in a slash, unless the path is just the initial slash
486 \o do not contain any two slashes in sequence
487 \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
491 bool isValidObjectPath(const QString &path)
493 if (path == QLatin1String("/"))
496 if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
497 path.endsWith(QLatin1Char('/')))
500 QStringList parts = path.split(QLatin1Char('/'));
501 Q_ASSERT(parts.count() >= 1);
502 parts.removeFirst(); // it starts with /, so we get an empty first part
504 for (int i = 0; i < parts.count(); ++i)
505 if (!isValidPartOfObjectPath(parts.at(i)))
512 \fn bool QDBusUtil::isValidBasicType(int type)
513 Returns true if \a c is a valid, basic D-Bus type.
515 bool isValidBasicType(int c)
517 return isBasicType(c);
521 \fn bool QDBusUtil::isValidFixedType(int type)
522 Returns true if \a c is a valid, fixed D-Bus type.
524 bool isValidFixedType(int c)
526 return isFixedType(c);
531 \fn bool QDBusUtil::isValidSignature(const QString &signature)
532 Returns true if \a signature is a valid D-Bus type signature for one or more types.
533 This function returns true if it can all of \a signature into valid, individual types and no
534 characters remain in \a signature.
536 \sa isValidSingleSignature()
538 bool isValidSignature(const QString &signature)
540 QByteArray ba = signature.toLatin1();
541 const char *data = ba.constData();
543 data = validateSingleType(data);
552 \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
553 Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
554 function tries to convert the type signature into a D-Bus type and, if it succeeds and no
555 characters remain in the signature, it returns true.
557 bool isValidSingleSignature(const QString &signature)
559 QByteArray ba = signature.toLatin1();
560 const char *data = validateSingleType(ba.constData());
561 return data && *data == '\0';
564 } // namespace QDBusUtil