1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtDBus module of the Qt Toolkit.
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.
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.
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.
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.
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