Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdbusmarshaller.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// Qt-Security score:critical reason:data-parser
4
8#include "qdbusutil_p.h"
9
10#ifndef QT_NO_DBUS
11
13
14using namespace Qt::StringLiterals;
15
16static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
17{
18 if (ba)
19 *ba += char(type);
20 else
21 q_dbus_message_iter_append_basic(it, type, arg);
22}
23
24QDBusMarshaller::~QDBusMarshaller()
25{
26 close();
27}
28
29void QDBusMarshaller::unregisteredTypeError(QMetaType id)
30{
31 const char *name = id.name();
32 qWarning("QDBusMarshaller: type '%s' (%d) is not registered with D-Bus. "
33 "Use qDBusRegisterMetaType to register it",
34 name ? name : "", id.id());
35 error("Unregistered type %1 passed in arguments"_L1
36 .arg(QLatin1StringView(id.name())));
37}
38
39inline QString QDBusMarshaller::currentSignature()
40{
41 if (message)
42 return QString::fromUtf8(q_dbus_message_get_signature(message));
43 return QString();
44}
45
46inline void QDBusMarshaller::append(uchar arg)
47{
48 if (!skipSignature)
49 qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
50}
51
52inline void QDBusMarshaller::append(bool arg)
53{
54 dbus_bool_t cast = arg;
55 if (!skipSignature)
56 qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
57}
58
59inline void QDBusMarshaller::append(short arg)
60{
61 if (!skipSignature)
62 qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
63}
64
65inline void QDBusMarshaller::append(ushort arg)
66{
67 if (!skipSignature)
68 qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
69}
70
71inline void QDBusMarshaller::append(int arg)
72{
73 if (!skipSignature)
74 qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
75}
76
77inline void QDBusMarshaller::append(uint arg)
78{
79 if (!skipSignature)
80 qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
81}
82
83inline void QDBusMarshaller::append(qlonglong arg)
84{
85 if (!skipSignature)
86 qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
87}
88
89inline void QDBusMarshaller::append(qulonglong arg)
90{
91 if (!skipSignature)
92 qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
93}
94
95inline void QDBusMarshaller::append(double arg)
96{
97 if (!skipSignature)
98 qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
99}
100
101void QDBusMarshaller::append(const QString &arg)
102{
103 QByteArray data = arg.toUtf8();
104 const char *cdata = data.constData();
105 if (!skipSignature)
106 qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
107}
108
109inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
110{
111 QByteArray data = arg.path().toUtf8();
112 if (!ba && data.isEmpty()) {
113 error("Invalid object path passed in arguments"_L1);
114 } else {
115 const char *cdata = data.constData();
116 if (!skipSignature)
117 qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
118 }
119}
120
121inline void QDBusMarshaller::append(const QDBusSignature &arg)
122{
123 QByteArray data = arg.signature().toUtf8();
124 if (!ba && data.isNull()) {
125 error("Invalid signature passed in arguments"_L1);
126 } else {
127 const char *cdata = data.constData();
128 if (!skipSignature)
129 qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
130 }
131}
132
133inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg)
134{
135 int fd = arg.fileDescriptor();
136 if (!ba && fd == -1) {
137 error("Invalid file descriptor passed in arguments"_L1);
138 } else {
139 if (!skipSignature)
140 qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd);
141 }
142}
143
144inline void QDBusMarshaller::append(const QByteArray &arg)
145{
146 if (ba) {
147 if (!skipSignature)
149 return;
150 }
151
152 const char* cdata = arg.constData();
153 DBusMessageIter subiterator;
154 q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
155 &subiterator);
156 q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.size());
157 q_dbus_message_iter_close_container(&iterator, &subiterator);
158}
159
160inline bool QDBusMarshaller::append(const QDBusVariant &arg)
161{
162 if (ba) {
163 if (!skipSignature)
165 return true;
166 }
167
168 const QVariant &value = arg.variant();
169 QMetaType id = value.metaType();
170 if (!id.isValid()) {
171 qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
172 error("Invalid QVariant passed in arguments"_L1);
173 return false;
174 }
175
176 QByteArray tmpSignature;
177 const char *signature = nullptr;
178 if (id == QDBusMetaTypeId::argument()) {
179 // take the signature from the QDBusArgument object we're marshalling
180 tmpSignature =
181 qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
182 signature = tmpSignature.constData();
183 } else {
184 // take the signatuer from the metatype we're marshalling
185 signature = QDBusMetaType::typeToSignature(id);
186 }
187 if (!signature) {
188 unregisteredTypeError(id);
189 return false;
190 }
191
192 QDBusMarshaller sub(capabilities);
193 open(sub, DBUS_TYPE_VARIANT, signature);
194 bool isOk = sub.appendVariantInternal(value);
195 // don't call sub.close(): it auto-closes
196
197 return isOk;
198}
199
200inline void QDBusMarshaller::append(const QStringList &arg)
201{
202 if (ba) {
203 if (!skipSignature)
205 return;
206 }
207
208 QDBusMarshaller sub(capabilities);
210 for (const QString &s : arg)
211 sub.append(s);
212 // don't call sub.close(): it auto-closes
213}
214
215inline QDBusMarshaller *QDBusMarshaller::beginStructure()
216{
217 return beginCommon(DBUS_TYPE_STRUCT, nullptr);
218}
219
220inline QDBusMarshaller *QDBusMarshaller::beginArray(QMetaType id)
221{
222 const char *signature = QDBusMetaType::typeToSignature(id);
223 if (!signature) {
224 unregisteredTypeError(id);
225 return this;
226 }
227
228 return beginCommon(DBUS_TYPE_ARRAY, signature);
229}
230
231inline QDBusMarshaller *QDBusMarshaller::beginMap(QMetaType kid, QMetaType vid)
232{
233 const char *ksignature = QDBusMetaType::typeToSignature(kid);
234 if (!ksignature) {
235 unregisteredTypeError(kid);
236 return this;
237 }
238 if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
239QT_WARNING_PUSH
240QT_WARNING_DISABLE_GCC("-Wformat-overflow")
241 qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-Bus map.",
242 kid.name(), kid.id());
243QT_WARNING_POP
244 error("Type %1 passed in arguments cannot be used as a key in a map"_L1
245 .arg(QLatin1StringView(kid.name())));
246 return this;
247 }
248
249 const char *vsignature = QDBusMetaType::typeToSignature(vid);
250 if (!vsignature) {
251 unregisteredTypeError(vid);
252 return this;
253 }
254
255 QByteArray signature;
257 signature += ksignature;
258 signature += vsignature;
260 return beginCommon(DBUS_TYPE_ARRAY, signature);
261}
262
263inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
264{
266}
267
268void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
269{
270 sub.parent = this;
271 sub.ba = ba;
272 sub.ok = true;
273 sub.capabilities = capabilities;
275
276 if (ba) {
277 if (!skipSignature) {
278 switch (code) {
279 case DBUS_TYPE_ARRAY:
280 *ba += char(code);
281 *ba += signature;
282 Q_FALLTHROUGH();
283
285 sub.closeCode = 0;
286 sub.skipSignature = true;
287 break;
288
289 case DBUS_TYPE_STRUCT:
292 break;
293 }
294 }
295 } else {
296 q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
297 }
298}
299
300QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
301{
302 QDBusMarshaller *d = new QDBusMarshaller(capabilities);
303 open(*d, code, signature);
304 return d;
305}
306
307inline QDBusMarshaller *QDBusMarshaller::endStructure()
308{ return endCommon(); }
309
310inline QDBusMarshaller *QDBusMarshaller::endArray()
311{ return endCommon(); }
312
313inline QDBusMarshaller *QDBusMarshaller::endMap()
314{ return endCommon(); }
315
316inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
317{ return endCommon(); }
318
319QDBusMarshaller *QDBusMarshaller::endCommon()
320{
321 QDBusMarshaller *retval = parent;
322 delete this;
323 return retval;
324}
325
326void QDBusMarshaller::close()
327{
328 if (ba) {
329 if (!skipSignature && closeCode)
330 *ba += closeCode;
331 } else if (parent) {
332 q_dbus_message_iter_close_container(&parent->iterator, &iterator);
333 }
334}
335
336void QDBusMarshaller::error(const QString &msg)
337{
338 ok = false;
339 if (parent)
340 parent->error(msg);
341 else
342 errorString = msg;
343}
344
345bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
346{
347 QMetaType id = arg.metaType();
348 if (!id.isValid()) {
349 qWarning("QDBusMarshaller: cannot add an invalid QVariant");
350 error("Invalid QVariant passed in arguments"_L1);
351 return false;
352 }
353
354 // intercept QDBusArgument parameters here
355 if (id == QDBusMetaTypeId::argument()) {
356 QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
357 QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
358 if (!d->message)
359 return false; // can't append this one...
360
361 QDBusDemarshaller demarshaller(capabilities);
362 demarshaller.message = q_dbus_message_ref(d->message);
363
364 if (d->direction == Direction::Demarshalling) {
365 // it's demarshalling; just copy
366 demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
367 } else {
368 // it's marshalling; start over
369 if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
370 return false; // error!
371 }
372
373 return appendCrossMarshalling(&demarshaller);
374 }
375
376 const char *signature = QDBusMetaType::typeToSignature(id);
377 if (!signature) {
378 unregisteredTypeError(id);
379 return false;
380 }
381
382 switch (*signature) {
383#ifdef __OPTIMIZE__
384 case DBUS_TYPE_BYTE:
385 case DBUS_TYPE_INT16:
386 case DBUS_TYPE_UINT16:
387 case DBUS_TYPE_INT32:
388 case DBUS_TYPE_UINT32:
389 case DBUS_TYPE_INT64:
390 case DBUS_TYPE_UINT64:
391 case DBUS_TYPE_DOUBLE:
392 qIterAppend(&iterator, ba, *signature, arg.constData());
393 return true;
394 case DBUS_TYPE_BOOLEAN:
395 append( arg.toBool() );
396 return true;
397#else
398 case DBUS_TYPE_BYTE:
399 append( qvariant_cast<uchar>(arg) );
400 return true;
402 append( arg.toBool() );
403 return true;
404 case DBUS_TYPE_INT16:
405 append( qvariant_cast<short>(arg) );
406 return true;
407 case DBUS_TYPE_UINT16:
408 append( qvariant_cast<ushort>(arg) );
409 return true;
410 case DBUS_TYPE_INT32:
411 append( static_cast<dbus_int32_t>(arg.toInt()) );
412 return true;
413 case DBUS_TYPE_UINT32:
414 append( static_cast<dbus_uint32_t>(arg.toUInt()) );
415 return true;
416 case DBUS_TYPE_INT64:
417 append( arg.toLongLong() );
418 return true;
419 case DBUS_TYPE_UINT64:
420 append( arg.toULongLong() );
421 return true;
422 case DBUS_TYPE_DOUBLE:
423 append( arg.toDouble() );
424 return true;
425#endif
426
427 case DBUS_TYPE_STRING:
428 append( arg.toString() );
429 return true;
431 append( qvariant_cast<QDBusObjectPath>(arg) );
432 return true;
434 append( qvariant_cast<QDBusSignature>(arg) );
435 return true;
436
437 // compound types:
439 // nested QVariant
440 return append( qvariant_cast<QDBusVariant>(arg) );
441
442 case DBUS_TYPE_ARRAY:
443 // could be many things
444 // find out what kind of array it is
445 switch (arg.metaType().id()) {
446 case QMetaType::QStringList:
447 append( arg.toStringList() );
448 return true;
449
450 case QMetaType::QByteArray:
451 append( arg.toByteArray() );
452 return true;
453
454 default:
455 ;
456 }
457 Q_FALLTHROUGH();
458
459 case DBUS_TYPE_STRUCT:
461 return appendRegisteredType( arg );
462
465 qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
466 return false;
467
469 if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) {
470 append(qvariant_cast<QDBusUnixFileDescriptor>(arg));
471 return true;
472 }
473 Q_FALLTHROUGH();
474
475 default:
476 qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-Bus type '%s'",
477 signature);
478 return false;
479 }
480
481 return true;
482}
483
484bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
485{
486 ref.ref(); // reference up
487 QDBusArgument self(QDBusArgumentPrivate::create(this));
488 return QDBusMetaType::marshall(self, arg.metaType(), arg.constData());
489}
490
491bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
492{
493 int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
494 if (QDBusUtil::isValidBasicType(code)) {
495 // easy: just append
496 // do exactly like the D-Bus docs suggest
497 // (see apidocs for q_dbus_message_iter_get_basic)
498
499 qlonglong value;
500 q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
501 q_dbus_message_iter_next(&demarshaller->iterator);
502 q_dbus_message_iter_append_basic(&iterator, code, &value);
503 return true;
504 }
505
506 if (code == DBUS_TYPE_ARRAY) {
507 int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
508 if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) {
509 // another optimization: fixed size arrays
510 // code is exactly like QDBusDemarshaller::toByteArray
511 DBusMessageIter sub;
512 q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
513 q_dbus_message_iter_next(&demarshaller->iterator);
514 int len;
515 void* data;
516 q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
517
518 char signature[2] = { char(element), 0 };
519 q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
520 q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
521 q_dbus_message_iter_close_container(&iterator, &sub);
522
523 return true;
524 }
525 }
526
527 // We have to recurse
528 QDBusDemarshaller *drecursed = demarshaller->beginCommon();
529
530 QDBusMarshaller mrecursed(capabilities); // create on the stack makes it autoclose
531 QByteArray subSignature;
532 const char *sig = nullptr;
533 if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
534 subSignature = drecursed->currentSignature().toLatin1();
535 if (!subSignature.isEmpty())
536 sig = subSignature.constData();
537 }
538 open(mrecursed, code, sig);
539
540 while (!drecursed->atEnd()) {
541 if (!mrecursed.appendCrossMarshalling(drecursed)) {
542 delete drecursed;
543 return false;
544 }
545 }
546
547 delete drecursed;
548 return true;
549}
550
551QT_END_NAMESPACE
552
553#endif // QT_NO_DBUS
\inmodule QtDBus
QDBusDemarshaller * beginCommon()
QDBusArgument::ElementType currentType()
void append(const QString &arg)
void append(uchar arg)
QDBusMarshaller * parent
void append(short arg)
QDBusMarshaller * endMapEntry()
void append(double arg)
QDBusMarshaller * endCommon()
QDBusMarshaller * endStructure()
void append(bool arg)
void open(QDBusMarshaller &sub, int code, const char *signature)
QString currentSignature()
bool appendVariantInternal(const QVariant &arg)
QDBusMarshaller * beginMap(QMetaType kid, QMetaType vid)
QDBusMarshaller * endMap()
QDBusMarshaller * beginCommon(int code, const char *signature)
void append(const QDBusUnixFileDescriptor &arg)
QDBusMarshaller * beginMapEntry()
bool appendRegisteredType(const QVariant &arg)
void error(const QString &message)
QDBusMarshaller * beginStructure()
QDBusMarshaller * beginArray(QMetaType id)
bool appendCrossMarshalling(QDBusDemarshaller *arg)
QDBusMarshaller * endArray()
\inmodule QtDBus
\inmodule QtDBus
\inmodule QtDBus
#define DBUS_TYPE_SIGNATURE
#define DBUS_TYPE_BYTE_AS_STRING
#define DBUS_TYPE_OBJECT_PATH
#define DBUS_TYPE_BYTE
#define DBUS_TYPE_INT16
#define DBUS_TYPE_VARIANT
#define DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
#define DBUS_TYPE_INT32
#define DBUS_TYPE_UNIX_FD
#define DBUS_TYPE_BOOLEAN
#define DBUS_STRUCT_BEGIN_CHAR
#define DBUS_TYPE_STRING
#define DBUS_TYPE_ARRAY
#define DBUS_TYPE_ARRAY_AS_STRING
#define DBUS_TYPE_STRING_AS_STRING
#define DBUS_TYPE_INT64
#define DBUS_TYPE_DOUBLE
#define DBUS_TYPE_UINT64
#define DBUS_TYPE_VARIANT_AS_STRING
#define DBUS_TYPE_DICT_ENTRY
#define DBUS_DICT_ENTRY_BEGIN_CHAR
#define DBUS_TYPE_UINT16
#define DBUS_DICT_ENTRY_END_CHAR_AS_STRING
#define DBUS_TYPE_STRUCT
#define DBUS_STRUCT_END_CHAR
#define DBUS_TYPE_UINT32
\inmodule QtDBus
Definition qdbusutil_p.h:33
Q_DBUS_EXPORT bool isValidFixedType(int c)
Returns true if c is a valid, fixed D-Bus type.
Q_DBUS_EXPORT bool isValidBasicType(int c)
Returns true if c is a valid, basic D-Bus type.