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(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(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(QChar c)
75 register ushort u = c.unicode();
76 return (u >= '0' && u <= '9');
79 #ifndef QT_BOOTSTRAPPED
80 static bool argToString(const QDBusArgument &arg, QString &out);
82 static bool variantToString(const QVariant &arg, QString &out)
84 int argType = arg.userType();
86 if (argType == QVariant::StringList) {
87 out += QLatin1Char('{');
88 QStringList list = arg.toStringList();
89 foreach (const QString &item, list)
90 out += QLatin1Char('\"') + item + QLatin1String("\", ");
93 out += QLatin1Char('}');
94 } else if (argType == QVariant::ByteArray) {
95 out += QLatin1Char('{');
96 QByteArray list = arg.toByteArray();
97 for (int i = 0; i < list.count(); ++i) {
98 out += QString::number(list.at(i));
99 out += QLatin1String(", ");
103 out += QLatin1Char('}');
104 } else if (argType == QVariant::List) {
105 out += QLatin1Char('{');
106 QList<QVariant> list = arg.toList();
107 foreach (const QVariant &item, list) {
108 if (!variantToString(item, out))
110 out += QLatin1String(", ");
114 out += QLatin1Char('}');
115 } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
116 || argType == QMetaType::Long || argType == QMetaType::LongLong) {
117 out += QString::number(arg.toLongLong());
118 } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
119 || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
120 out += QString::number(arg.toULongLong());
121 } else if (argType == QMetaType::Double) {
122 out += QString::number(arg.toDouble());
123 } else if (argType == QMetaType::Bool) {
124 out += QLatin1String(arg.toBool() ? "true" : "false");
125 } else if (argType == qMetaTypeId<QDBusArgument>()) {
126 argToString(qvariant_cast<QDBusArgument>(arg), out);
127 } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
128 const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
129 out += QLatin1String("[ObjectPath: ");
131 out += QLatin1Char(']');
132 } else if (argType == qMetaTypeId<QDBusSignature>()) {
133 out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
134 out += QLatin1Char(']');
135 } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
136 out += QLatin1String("[Unix FD: ");
137 out += QLatin1String(qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid" : "not valid");
138 out += QLatin1Char(']');
139 } else if (argType == qMetaTypeId<QDBusVariant>()) {
140 const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
141 out += QLatin1String("[Variant");
142 int vUserType = v.userType();
143 if (vUserType != qMetaTypeId<QDBusVariant>()
144 && vUserType != qMetaTypeId<QDBusSignature>()
145 && vUserType != qMetaTypeId<QDBusObjectPath>()
146 && vUserType != qMetaTypeId<QDBusArgument>())
147 out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
148 out += QLatin1String(": ");
149 if (!variantToString(v, out))
151 out += QLatin1Char(']');
152 } else if (arg.canConvert(QVariant::String)) {
153 out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
155 out += QLatin1Char('[');
156 out += QLatin1String(arg.typeName());
157 out += QLatin1Char(']');
163 bool argToString(const QDBusArgument &busArg, QString &out)
165 QString busSig = busArg.currentSignature();
166 bool doIterate = false;
167 QDBusArgument::ElementType elementType = busArg.currentType();
169 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
170 && elementType != QDBusArgument::MapEntryType)
171 out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
173 switch (elementType) {
174 case QDBusArgument::BasicType:
175 case QDBusArgument::VariantType:
176 if (!variantToString(busArg.asVariant(), out))
179 case QDBusArgument::StructureType:
180 busArg.beginStructure();
183 case QDBusArgument::ArrayType:
185 out += QLatin1Char('{');
188 case QDBusArgument::MapType:
190 out += QLatin1Char('{');
193 case QDBusArgument::MapEntryType:
194 busArg.beginMapEntry();
195 if (!variantToString(busArg.asVariant(), out))
197 out += QLatin1String(" = ");
198 if (!argToString(busArg, out))
200 busArg.endMapEntry();
202 case QDBusArgument::UnknownType:
204 out += QLatin1String("<ERROR - Unknown Type>");
207 if (doIterate && !busArg.atEnd()) {
208 while (!busArg.atEnd()) {
209 if (!argToString(busArg, out))
211 out += QLatin1String(", ");
215 switch (elementType) {
216 case QDBusArgument::BasicType:
217 case QDBusArgument::VariantType:
218 case QDBusArgument::UnknownType:
219 case QDBusArgument::MapEntryType:
222 case QDBusArgument::StructureType:
223 busArg.endStructure();
225 case QDBusArgument::ArrayType:
226 out += QLatin1Char('}');
229 case QDBusArgument::MapType:
230 out += QLatin1Char('}');
235 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
236 && elementType != QDBusArgument::MapEntryType)
237 out += QLatin1Char(']');
243 //------- D-Bus Types --------
244 static const char oneLetterTypes[] = "vsogybnqiuxtdh";
245 static const char basicTypes[] = "sogybnqiuxtdh";
246 static const char fixedTypes[] = "ybnqiuxtdh";
248 static bool isBasicType(int c)
250 return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL;
253 static bool isFixedType(int c)
255 return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL;
258 // Returns a pointer to one-past-end of this type if it's valid;
259 // returns NULL if it isn't valid.
260 static const char *validateSingleType(const char *signature)
262 register char c = *signature;
263 if (c == DBUS_TYPE_INVALID)
266 // is it one of the one-letter types?
267 if (strchr(oneLetterTypes, c) != NULL)
268 return signature + 1;
271 if (c == DBUS_TYPE_ARRAY) {
272 // then it's valid if the next type is valid
273 // or if it's a dict-entry
275 if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) {
276 // beginning of a dictionary entry
277 // a dictionary entry has a key which is of basic types
282 signature = validateSingleType(signature + 1);
283 return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0;
286 return validateSingleType(signature);
289 if (c == DBUS_STRUCT_BEGIN_CHAR) {
290 // beginning of a struct
293 signature = validateSingleType(signature);
296 if (*signature == DBUS_STRUCT_END_CHAR)
297 return signature + 1;
301 // invalid/unknown type
310 \brief The QDBusUtil namespace contains a few functions that are of general use when
311 dealing with D-Bus strings.
318 Dumps the contents of a QtDBus argument from \a arg into a string.
320 QString argumentToString(const QVariant &arg)
324 #ifndef QT_BOOTSTRAPPED
325 variantToString(arg, out);
335 \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
336 See QDBusUtil::isValidObjectPath
338 bool isValidPartOfObjectPath(const QString &part)
341 return false; // can't be valid if it's empty
343 const QChar *c = part.unicode();
344 for (int i = 0; i < part.length(); ++i)
345 if (!isValidCharacterNoDash(c[i]))
352 \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
353 Returns true if this is \a ifaceName is a valid interface name.
355 Valid interface names must:
358 \li not exceed 255 characters in length
359 \li be composed of dot-separated string components that contain only ASCII letters, digits
360 and the underscore ("_") character
361 \li contain at least two such components
364 bool isValidInterfaceName(const QString& ifaceName)
366 if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
369 QStringList parts = ifaceName.split(QLatin1Char('.'));
370 if (parts.count() < 2)
371 return false; // at least two parts
373 for (int i = 0; i < parts.count(); ++i)
374 if (!isValidMemberName(parts.at(i)))
381 \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
382 Returns true if \a connName is a valid unique connection name.
384 Unique connection names start with a colon (":") and are followed by a list of dot-separated
385 components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
387 bool isValidUniqueConnectionName(const QString &connName)
389 if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
390 !connName.startsWith(QLatin1Char(':')))
393 QStringList parts = connName.mid(1).split(QLatin1Char('.'));
394 if (parts.count() < 1)
397 for (int i = 0; i < parts.count(); ++i) {
398 const QString &part = parts.at(i);
402 const QChar* c = part.unicode();
403 for (int j = 0; j < part.length(); ++j)
404 if (!isValidCharacter(c[j]))
412 \fn bool QDBusUtil::isValidBusName(const QString &busName)
413 Returns true if \a busName is a valid bus name.
415 A valid bus name is either a valid unique connection name or follows the rules:
418 \li does not exceed 255 characters in length
419 \li be composed of dot-separated string components that contain only ASCII letters, digits,
420 hyphens or underscores ("_"), but don't start with a digit
421 \li contains at least two such elements
424 \sa isValidUniqueConnectionName()
426 bool isValidBusName(const QString &busName)
428 if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
431 if (busName.startsWith(QLatin1Char(':')))
432 return isValidUniqueConnectionName(busName);
434 QStringList parts = busName.split(QLatin1Char('.'));
435 if (parts.count() < 1)
438 for (int i = 0; i < parts.count(); ++i) {
439 const QString &part = parts.at(i);
443 const QChar *c = part.unicode();
444 if (isValidNumber(c[0]))
446 for (int j = 0; j < part.length(); ++j)
447 if (!isValidCharacter(c[j]))
455 \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
456 Returns true if \a memberName is a valid member name. A valid member name does not exceed
457 255 characters in length, is not empty, is composed only of ASCII letters, digits and
458 underscores, but does not start with a digit.
460 bool isValidMemberName(const QString &memberName)
462 if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
465 const QChar* c = memberName.unicode();
466 if (isValidNumber(c[0]))
468 for (int j = 0; j < memberName.length(); ++j)
469 if (!isValidCharacterNoDash(c[j]))
475 \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
476 Returns true if \a errorName is a valid error name. Valid error names are valid interface
477 names and vice-versa, so this function is actually an alias for isValidInterfaceName.
479 bool isValidErrorName(const QString &errorName)
481 return isValidInterfaceName(errorName);
485 \fn bool QDBusUtil::isValidObjectPath(const QString &path)
486 Returns true if \a path is valid object path.
488 Valid object paths follow the rules:
490 \li start with the slash character ("/")
491 \li do not end in a slash, unless the path is just the initial slash
492 \li do not contain any two slashes in sequence
493 \li contain slash-separated parts, each of which is composed of ASCII letters, digits and
497 bool isValidObjectPath(const QString &path)
499 if (path == QLatin1String("/"))
502 if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
503 path.endsWith(QLatin1Char('/')))
506 QStringList parts = path.split(QLatin1Char('/'));
507 Q_ASSERT(parts.count() >= 1);
508 parts.removeFirst(); // it starts with /, so we get an empty first part
510 for (int i = 0; i < parts.count(); ++i)
511 if (!isValidPartOfObjectPath(parts.at(i)))
518 \fn bool QDBusUtil::isValidBasicType(int type)
519 Returns true if \a c is a valid, basic D-Bus type.
521 bool isValidBasicType(int c)
523 return isBasicType(c);
527 \fn bool QDBusUtil::isValidFixedType(int type)
528 Returns true if \a c is a valid, fixed D-Bus type.
530 bool isValidFixedType(int c)
532 return isFixedType(c);
537 \fn bool QDBusUtil::isValidSignature(const QString &signature)
538 Returns true if \a signature is a valid D-Bus type signature for one or more types.
539 This function returns true if it can all of \a signature into valid, individual types and no
540 characters remain in \a signature.
542 \sa isValidSingleSignature()
544 bool isValidSignature(const QString &signature)
546 QByteArray ba = signature.toLatin1();
547 const char *data = ba.constData();
549 data = validateSingleType(data);
558 \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
559 Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
560 function tries to convert the type signature into a D-Bus type and, if it succeeds and no
561 characters remain in the signature, it returns true.
563 bool isValidSingleSignature(const QString &signature)
565 QByteArray ba = signature.toLatin1();
566 const char *data = validateSingleType(ba.constData());
567 return data && *data == '\0';
570 } // namespace QDBusUtil