Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdbusutil.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qdbusutil_p.h"
5
6#include "qdbus_symbols_p.h"
7
8#include <QtCore/qlist.h>
9#include <QtCore/qstringlist.h>
10#include <private/qtools_p.h>
11
12#include "qdbusargument.h"
14
15#ifndef QT_NO_DBUS
16
18
19using namespace Qt::StringLiterals;
20using namespace QtMiscUtils;
21
22static inline bool isValidCharacterNoDash(QChar c)
23{
24 ushort u = c.unicode();
25 return isAsciiLetterOrNumber(u) || (u == '_');
26}
27
28static inline bool isValidCharacter(QChar c)
29{
30 ushort u = c.unicode();
31 return isAsciiLetterOrNumber(u)
32 || (u == '_') || (u == '-');
33}
34
35static inline bool isValidNumber(QChar c)
36{
37 return (isAsciiDigit(c.toLatin1()));
38}
39
40#ifndef QT_BOOTSTRAPPED
41static bool argToString(const QDBusArgument &arg, QString &out);
42
43static bool variantToString(const QVariant &arg, QString &out)
44{
45 int argType = arg.metaType().id();
46
47 if (argType == QMetaType::QStringList) {
48 out += u'{';
49 const QStringList list = arg.toStringList();
50 for (const QString &item : list)
51 out += u'\"' + item + "\", "_L1;
52 if (!list.isEmpty())
53 out.chop(2);
54 out += u'}';
55 } else if (argType == QMetaType::QByteArray) {
56 out += u'{';
57 QByteArray list = arg.toByteArray();
58 for (int i = 0; i < list.size(); ++i) {
60 out += ", "_L1;
61 }
62 if (!list.isEmpty())
63 out.chop(2);
64 out += u'}';
65 } else if (argType == QMetaType::QVariantList) {
66 out += u'{';
67 const QList<QVariant> list = arg.toList();
68 for (const QVariant &item : list) {
70 return false;
71 out += ", "_L1;
72 }
73 if (!list.isEmpty())
74 out.chop(2);
75 out += u'}';
76 } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
77 || argType == QMetaType::Long || argType == QMetaType::LongLong) {
78 out += QString::number(arg.toLongLong());
79 } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
80 || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
81 out += QString::number(arg.toULongLong());
82 } else if (argType == QMetaType::Double) {
83 out += QString::number(arg.toDouble());
84 } else if (argType == QMetaType::Bool) {
85 out += arg.toBool() ? "true"_L1 : "false"_L1;
86 } else if (argType == qMetaTypeId<QDBusArgument>()) {
87 argToString(qvariant_cast<QDBusArgument>(arg), out);
88 } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
89 const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
90 out += "[ObjectPath: "_L1;
91 out += path;
92 out += u']';
93 } else if (argType == qMetaTypeId<QDBusSignature>()) {
94 out += "[Signature: "_L1 + qvariant_cast<QDBusSignature>(arg).signature();
95 out += u']';
96 } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
97 out += "[Unix FD: "_L1;
98 out += qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid"_L1 : "not valid"_L1;
99 out += u']';
100 } else if (argType == qMetaTypeId<QDBusVariant>()) {
101 const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
102 out += "[Variant"_L1;
103 QMetaType vUserType = v.metaType();
104 if (vUserType != QMetaType::fromType<QDBusVariant>()
105 && vUserType != QMetaType::fromType<QDBusSignature>()
106 && vUserType != QMetaType::fromType<QDBusObjectPath>()
107 && vUserType != QMetaType::fromType<QDBusArgument>())
108 out += u'(' + QLatin1StringView(v.typeName()) + u')';
109 out += ": "_L1;
110 if (!variantToString(v, out))
111 return false;
112 out += u']';
113 } else if (arg.canConvert<QString>()) {
114 out += u'\"' + arg.toString() + u'\"';
115 } else {
116 out += u'[';
117 out += QLatin1StringView(arg.typeName());
118 out += u']';
119 }
120
121 return true;
122}
123
125{
126 QString busSig = busArg.currentSignature();
127 bool doIterate = false;
128 QDBusArgument::ElementType elementType = busArg.currentType();
129
130 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
131 && elementType != QDBusArgument::MapEntryType)
132 out += "[Argument: "_L1 + busSig + u' ';
133
134 switch (elementType) {
137 if (!variantToString(busArg.asVariant(), out))
138 return false;
139 break;
141 busArg.beginStructure();
142 doIterate = true;
143 break;
145 busArg.beginArray();
146 out += u'{';
147 doIterate = true;
148 break;
150 busArg.beginMap();
151 out += u'{';
152 doIterate = true;
153 break;
155 busArg.beginMapEntry();
156 if (!variantToString(busArg.asVariant(), out))
157 return false;
158 out += " = "_L1;
159 if (!argToString(busArg, out))
160 return false;
161 busArg.endMapEntry();
162 break;
164 default:
165 out += "<ERROR - Unknown Type>"_L1;
166 return false;
167 }
168 if (doIterate && !busArg.atEnd()) {
169 while (!busArg.atEnd()) {
170 if (!argToString(busArg, out))
171 return false;
172 out += ", "_L1;
173 }
174 out.chop(2);
175 }
176 switch (elementType) {
181 // nothing to do
182 break;
184 busArg.endStructure();
185 break;
187 out += u'}';
188 busArg.endArray();
189 break;
191 out += u'}';
192 busArg.endMap();
193 break;
194 }
195
196 if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
197 && elementType != QDBusArgument::MapEntryType)
198 out += u']';
199
200 return true;
201}
202#endif
203
204//------- D-Bus Types --------
205static const char oneLetterTypes[] = "vsogybnqiuxtdh";
206static const char basicTypes[] = "sogybnqiuxtdh";
207static const char fixedTypes[] = "ybnqiuxtdh";
208
209/*
210 D-Bus signature grammar (in ABNF), as of 0.42 (2023-08-21):
211 https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
212
213 <signature> = *<single-complete-type>
214 <single-complete-type> = <basic-type> / <variant> / <struct> / <array>
215 <fixed-type> = "y" / "b" / "n" / "q" / "i" / "u" / "x" / "t" / "d" / "h"
216 <variable-length-type> = "s" / "o" / "g"
217 <basic-type> = <variable-length-type> / <fixed-type>
218 <variant> = "v"
219 <struct> = "(" 1*<single-complete-type> ")"
220 <array> = "a" ( <single-complete-type> / <dict-entry> )
221 <dict-entry> = "{" <basic-type> <single-complete-type> "}"
222*/
223
224static bool isBasicType(int c)
225{
226 return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != nullptr;
227}
228
229static bool isFixedType(int c)
230{
231 return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != nullptr;
232}
233
234// Returns a pointer to one-past-end of this type if it's valid;
235// returns NULL if it isn't valid.
236static const char *validateSingleType(const char *signature)
237{
238 char c = *signature;
239 if (c == DBUS_TYPE_INVALID)
240 return nullptr;
241
242 // is it one of the one-letter types?
243 if (strchr(oneLetterTypes, c) != nullptr)
244 return signature + 1;
245
246 // is it an array?
247 if (c == DBUS_TYPE_ARRAY) {
248 // then it's valid if the next type is valid
249 // or if it's a dict-entry
250 c = *++signature;
252 // beginning of a dictionary entry
253 // a dictionary entry has a key which is of basic types
254 // and a free value
255 c = *++signature;
256 if (!isBasicType(c))
257 return nullptr;
258 signature = validateSingleType(signature + 1);
259 return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : nullptr;
260 }
261
262 return validateSingleType(signature);
263 }
264
265 if (c == DBUS_STRUCT_BEGIN_CHAR) {
266 // beginning of a struct
267 ++signature;
268 while (true) {
269 signature = validateSingleType(signature);
270 if (!signature)
271 return nullptr;
272 if (*signature == DBUS_STRUCT_END_CHAR)
273 return signature + 1;
274 }
275 }
276
277 // invalid/unknown type
278 return nullptr;
279}
280
289namespace QDBusUtil
290{
297 {
298 QString out;
299
300#ifndef QT_BOOTSTRAPPED
302#else
303 Q_UNUSED(arg);
304#endif
305
306 return out;
307 }
308
315 {
316 if (part.isEmpty())
317 return false; // can't be valid if it's empty
318
319 const QChar *c = part.data();
320 for (int i = 0; i < part.size(); ++i)
322 return false;
323
324 return true;
325 }
326
340 bool isValidInterfaceName(const QString& ifaceName)
341 {
342 if (ifaceName.isEmpty() || ifaceName.size() > DBUS_MAXIMUM_NAME_LENGTH)
343 return false;
344
345 const auto parts = QStringView{ifaceName}.split(u'.');
346 if (parts.size() < 2)
347 return false; // at least two parts
348
349 for (auto part : parts)
350 if (!isValidMemberName(part))
351 return false;
352
353 return true;
354 }
355
364 {
365 if (connName.isEmpty() || connName.size() > DBUS_MAXIMUM_NAME_LENGTH ||
366 !connName.startsWith(u':'))
367 return false;
368
369 const auto parts = connName.mid(1).split(u'.');
370 if (parts.size() < 1)
371 return false;
372
373 for (QStringView part : parts) {
374 if (part.isEmpty())
375 return false;
376
377 const QChar* c = part.data();
378 for (int j = 0; j < part.size(); ++j)
379 if (!isValidCharacter(c[j]))
380 return false;
381 }
382
383 return true;
384 }
385
401 bool isValidBusName(const QString &busName)
402 {
403 if (busName.isEmpty() || busName.size() > DBUS_MAXIMUM_NAME_LENGTH)
404 return false;
405
406 if (busName.startsWith(u':'))
407 return isValidUniqueConnectionName(busName);
408
409 const auto parts = QStringView{busName}.split(u'.');
410 for (QStringView part : parts) {
411 if (part.isEmpty())
412 return false;
413
414 const QChar *c = part.data();
415 if (isValidNumber(c[0]))
416 return false;
417 for (int j = 0; j < part.size(); ++j)
418 if (!isValidCharacter(c[j]))
419 return false;
420 }
421
422 return true;
423 }
424
432 {
433 if (memberName.isEmpty() || memberName.size() > DBUS_MAXIMUM_NAME_LENGTH)
434 return false;
435
436 const QChar* c = memberName.data();
437 if (isValidNumber(c[0]))
438 return false;
439 for (int j = 0; j < memberName.size(); ++j)
441 return false;
442 return true;
443 }
444
450 bool isValidErrorName(const QString &errorName)
451 {
452 return isValidInterfaceName(errorName);
453 }
454
468 {
469 if (path == "/"_L1)
470 return true;
471
472 if (!path.startsWith(u'/') || path.indexOf("//"_L1) != -1 ||
473 path.endsWith(u'/'))
474 return false;
475
476 // it starts with /, so we skip the empty first part
477 const auto parts = QStringView{path}.mid(1).split(u'/');
478 for (QStringView part : parts)
479 if (!isValidPartOfObjectPath(part))
480 return false;
481
482 return true;
483 }
484
490 {
491 return isBasicType(c);
492 }
493
499 {
500 return isFixedType(c);
501 }
502
503
512 bool isValidSignature(const QString &signature)
513 {
514 QByteArray ba = signature.toLatin1();
515 const char *data = ba.constBegin();
516 const char *end = ba.constEnd();
517 while (data != end) {
519 if (!data)
520 return false;
521 }
522 return true;
523 }
524
531 bool isValidSingleSignature(const QString &signature)
532 {
533 QByteArray ba = signature.toLatin1();
534 const char *data = validateSingleType(ba.constData());
535 return data && *data == '\0';
536 }
537
538} // namespace QDBusUtil
539
541
542#endif // QT_NO_DBUS
\inmodule QtCore
Definition qbytearray.h:57
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last byte in the ...
Definition qbytearray.h:450
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first byte in the byte-ar...
Definition qbytearray.h:446
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
\inmodule QtDBus
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
const_pointer data() const noexcept
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8249
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qvariant.h:65
#define DBUS_DICT_ENTRY_END_CHAR
#define DBUS_STRUCT_BEGIN_CHAR
#define DBUS_MAXIMUM_NAME_LENGTH
#define DBUS_TYPE_ARRAY
#define DBUS_TYPE_INVALID
#define DBUS_DICT_ENTRY_BEGIN_CHAR
#define DBUS_STRUCT_END_CHAR
\inmodule QtDBus
bool isValidMemberName(QStringView memberName)
Returns true if memberName is a valid member name.
bool isValidInterfaceName(const QString &ifaceName)
Returns true if this is ifaceName is a valid interface name.
bool isValidErrorName(const QString &errorName)
Returns true if errorName is a valid error name.
bool isValidPartOfObjectPath(QStringView part)
bool isValidUniqueConnectionName(QStringView connName)
Returns true if connName is a valid unique connection name.
bool isValidBusName(const QString &busName)
Returns true if busName is a valid bus name.
bool isValidObjectPath(const QString &path)
Returns true if path is valid object path.
QString argumentToString(const QVariant &arg)
bool isValidBasicType(int c)
Returns true if c is a valid, basic D-Bus type.
bool isValidSignature(const QString &signature)
Returns true if signature is a valid D-Bus type signature for one or more types.
bool isValidFixedType(int c)
Returns true if c is a valid, fixed D-Bus type.
bool isValidSingleSignature(const QString &signature)
Returns true if signature is a valid D-Bus type signature for exactly one full type.
Combined button and popup list for selecting options.
constexpr bool isAsciiDigit(char32_t c) noexcept
Definition qtools_p.h:67
constexpr bool isAsciiLetterOrNumber(char32_t c) noexcept
Definition qtools_p.h:82
static bool argToString(const QDBusArgument &arg, QString &out)
static bool isFixedType(int c)
static const char basicTypes[]
static bool variantToString(const QVariant &arg, QString &out)
Definition qdbusutil.cpp:43
static const char * validateSingleType(const char *signature)
static bool isBasicType(int c)
static const char fixedTypes[]
static bool isValidCharacterNoDash(QChar c)
Definition qdbusutil.cpp:22
static const char oneLetterTypes[]
static bool isValidCharacter(QChar c)
Definition qdbusutil.cpp:28
static bool isValidNumber(QChar c)
Definition qdbusutil.cpp:35
GLsizei const GLfloat * v
[13]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const GLubyte * c
GLsizei const GLchar *const * path
SSL_CTX int void * arg
#define Q_UNUSED(x)
unsigned short ushort
Definition qtypes.h:33
QList< int > list
[14]
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QGraphicsItem * item