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 "qdbusargument_p.h"
5#include "qdbusconnection.h"
6
7#include <memory>
8
9#include <stdlib.h>
10
11QT_BEGIN_NAMESPACE
12
13template <typename T>
14static inline T qIterGet(DBusMessageIter *it)
15{
16 // Use a union of expected and largest type q_dbus_message_iter_get_basic
17 // will return to ensure reading the wrong basic type does not result in
18 // stack overwrite
19 union {
20 // The value to be extracted
21 T t;
22 // Largest type that q_dbus_message_iter_get_basic will return
23 // according to dbus_message_iter_get_basic API documentation
24 dbus_uint64_t maxValue;
25 // A pointer to ensure no stack overwrite in case there is a platform
26 // where sizeof(void*) > sizeof(dbus_uint64_t)
27 void* ptr;
28 } value;
29
30 // Initialize the value in case a narrower type is extracted to it.
31 // Note that the result of extracting a narrower type in place of a wider
32 // one and vice-versa will be platform-dependent.
33 value.t = T();
34
35 q_dbus_message_iter_get_basic(it, &value);
36 q_dbus_message_iter_next(iter: it);
37 return value.t;
38}
39
40QDBusDemarshaller::~QDBusDemarshaller()
41{
42}
43
44inline QString QDBusDemarshaller::currentSignature()
45{
46 char *sig = q_dbus_message_iter_get_signature(iter: &iterator);
47 QString retval = QString::fromUtf8(utf8: sig);
48 q_dbus_free(memory: sig);
49
50 return retval;
51}
52
53inline uchar QDBusDemarshaller::toByte()
54{
55 return qIterGet<uchar>(it: &iterator);
56}
57
58inline bool QDBusDemarshaller::toBool()
59{
60 return bool(qIterGet<dbus_bool_t>(it: &iterator));
61}
62
63inline ushort QDBusDemarshaller::toUShort()
64{
65 return qIterGet<dbus_uint16_t>(it: &iterator);
66}
67
68inline short QDBusDemarshaller::toShort()
69{
70 return qIterGet<dbus_int16_t>(it: &iterator);
71}
72
73inline int QDBusDemarshaller::toInt()
74{
75 return qIterGet<dbus_int32_t>(it: &iterator);
76}
77
78inline uint QDBusDemarshaller::toUInt()
79{
80 return qIterGet<dbus_uint32_t>(it: &iterator);
81}
82
83inline qlonglong QDBusDemarshaller::toLongLong()
84{
85 return qIterGet<qlonglong>(it: &iterator);
86}
87
88inline qulonglong QDBusDemarshaller::toULongLong()
89{
90 return qIterGet<qulonglong>(it: &iterator);
91}
92
93inline double QDBusDemarshaller::toDouble()
94{
95 return qIterGet<double>(it: &iterator);
96}
97
98inline QString QDBusDemarshaller::toStringUnchecked()
99{
100 return QString::fromUtf8(utf8: qIterGet<char *>(it: &iterator));
101}
102
103inline QString QDBusDemarshaller::toString()
104{
105 if (isCurrentTypeStringLike())
106 return toStringUnchecked();
107 else
108 return QString();
109}
110
111inline QDBusObjectPath QDBusDemarshaller::toObjectPathUnchecked()
112 {
113 return QDBusObjectPath(QString::fromUtf8(utf8: qIterGet<char *>(it: &iterator)));
114 }
115
116inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
117{
118 if (isCurrentTypeStringLike())
119 return toObjectPathUnchecked();
120 else
121 return QDBusObjectPath();
122}
123
124inline QDBusSignature QDBusDemarshaller::toSignatureUnchecked()
125 {
126 return QDBusSignature(QString::fromUtf8(utf8: qIterGet<char *>(it: &iterator)));
127 }
128
129inline QDBusSignature QDBusDemarshaller::toSignature()
130{
131 if (isCurrentTypeStringLike())
132 return toSignatureUnchecked();
133 else
134 return QDBusSignature();
135}
136
137inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
138{
139 QDBusUnixFileDescriptor fd;
140 fd.giveFileDescriptor(fileDescriptor: qIterGet<dbus_int32_t>(it: &iterator));
141 return fd;
142}
143
144inline QDBusVariant QDBusDemarshaller::toVariant()
145{
146 QDBusDemarshaller sub(capabilities);
147 sub.message = q_dbus_message_ref(message);
148 q_dbus_message_iter_recurse(iter: &iterator, sub: &sub.iterator);
149 q_dbus_message_iter_next(iter: &iterator);
150
151 return QDBusVariant( sub.toVariantInternal() );
152}
153
154QDBusArgument::ElementType QDBusDemarshaller::currentType()
155{
156 switch (q_dbus_message_iter_get_arg_type(iter: &iterator)) {
157 case DBUS_TYPE_BYTE:
158 case DBUS_TYPE_INT16:
159 case DBUS_TYPE_UINT16:
160 case DBUS_TYPE_INT32:
161 case DBUS_TYPE_UINT32:
162 case DBUS_TYPE_INT64:
163 case DBUS_TYPE_UINT64:
164 case DBUS_TYPE_BOOLEAN:
165 case DBUS_TYPE_DOUBLE:
166 case DBUS_TYPE_STRING:
167 case DBUS_TYPE_OBJECT_PATH:
168 case DBUS_TYPE_SIGNATURE:
169 return QDBusArgument::BasicType;
170
171 case DBUS_TYPE_VARIANT:
172 return QDBusArgument::VariantType;
173
174 case DBUS_TYPE_ARRAY:
175 switch (q_dbus_message_iter_get_element_type(iter: &iterator)) {
176 case DBUS_TYPE_BYTE:
177 case DBUS_TYPE_STRING:
178 // QByteArray and QStringList
179 return QDBusArgument::BasicType;
180 case DBUS_TYPE_DICT_ENTRY:
181 return QDBusArgument::MapType;
182 default:
183 return QDBusArgument::ArrayType;
184 }
185
186 case DBUS_TYPE_STRUCT:
187 return QDBusArgument::StructureType;
188 case DBUS_TYPE_DICT_ENTRY:
189 return QDBusArgument::MapEntryType;
190
191 case DBUS_TYPE_UNIX_FD:
192 return capabilities & QDBusConnection::UnixFileDescriptorPassing ?
193 QDBusArgument::BasicType : QDBusArgument::UnknownType;
194
195 case DBUS_TYPE_INVALID:
196 return QDBusArgument::UnknownType;
197
198// default:
199// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
200// q_dbus_message_iter_get_arg_type(&iterator),
201// q_dbus_message_iter_get_arg_type(&iterator));
202 }
203 return QDBusArgument::UnknownType;
204}
205
206QVariant QDBusDemarshaller::toVariantInternal()
207{
208 switch (q_dbus_message_iter_get_arg_type(iter: &iterator)) {
209 case DBUS_TYPE_BYTE:
210 return QVariant::fromValue(value: toByte());
211 case DBUS_TYPE_INT16:
212 return QVariant::fromValue(value: toShort());
213 case DBUS_TYPE_UINT16:
214 return QVariant::fromValue(value: toUShort());
215 case DBUS_TYPE_INT32:
216 return toInt();
217 case DBUS_TYPE_UINT32:
218 return toUInt();
219 case DBUS_TYPE_DOUBLE:
220 return toDouble();
221 case DBUS_TYPE_BOOLEAN:
222 return toBool();
223 case DBUS_TYPE_INT64:
224 return toLongLong();
225 case DBUS_TYPE_UINT64:
226 return toULongLong();
227 case DBUS_TYPE_STRING:
228 return toStringUnchecked();
229 case DBUS_TYPE_OBJECT_PATH:
230 return QVariant::fromValue(value: toObjectPathUnchecked());
231 case DBUS_TYPE_SIGNATURE:
232 return QVariant::fromValue(value: toSignatureUnchecked());
233 case DBUS_TYPE_VARIANT:
234 return QVariant::fromValue(value: toVariant());
235
236 case DBUS_TYPE_ARRAY:
237 switch (q_dbus_message_iter_get_element_type(iter: &iterator)) {
238 case DBUS_TYPE_BYTE:
239 // QByteArray
240 return toByteArrayUnchecked();
241 case DBUS_TYPE_STRING:
242 return toStringListUnchecked();
243 case DBUS_TYPE_DICT_ENTRY:
244 return QVariant::fromValue(value: duplicate());
245
246 default:
247 return QVariant::fromValue(value: duplicate());
248 }
249
250 case DBUS_TYPE_STRUCT:
251 return QVariant::fromValue(value: duplicate());
252
253 case DBUS_TYPE_UNIX_FD:
254 if (capabilities & QDBusConnection::UnixFileDescriptorPassing)
255 return QVariant::fromValue(value: toUnixFileDescriptor());
256 Q_FALLTHROUGH();
257
258 default:
259// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
260// q_dbus_message_iter_get_arg_type(&iterator),
261// q_dbus_message_iter_get_arg_type(&iterator));
262 char *ptr = nullptr;
263 ptr += q_dbus_message_iter_get_arg_type(iter: &iterator);
264 q_dbus_message_iter_next(iter: &iterator);
265
266 // I hope you never dereference this pointer!
267 return QVariant::fromValue<void *>(value: ptr);
268 };
269}
270
271bool QDBusDemarshaller::isCurrentTypeStringLike()
272{
273 const int type = q_dbus_message_iter_get_arg_type(iter: &iterator);
274 switch (type) {
275 case DBUS_TYPE_STRING: //FALLTHROUGH
276 case DBUS_TYPE_OBJECT_PATH: //FALLTHROUGH
277 case DBUS_TYPE_SIGNATURE:
278 return true;
279 default:
280 return false;
281 }
282}
283
284QStringList QDBusDemarshaller::toStringListUnchecked()
285{
286 QStringList list;
287
288 QDBusDemarshaller sub(capabilities);
289 q_dbus_message_iter_recurse(iter: &iterator, sub: &sub.iterator);
290 q_dbus_message_iter_next(iter: &iterator);
291 while (!sub.atEnd())
292 list.append(t: sub.toStringUnchecked());
293
294 return list;
295}
296
297QStringList QDBusDemarshaller::toStringList()
298{
299 if (q_dbus_message_iter_get_arg_type(iter: &iterator) == DBUS_TYPE_ARRAY
300 && q_dbus_message_iter_get_element_type(iter: &iterator) == DBUS_TYPE_STRING)
301 return toStringListUnchecked();
302 else
303 return QStringList();
304}
305
306QByteArray QDBusDemarshaller::toByteArrayUnchecked()
307{
308 DBusMessageIter sub;
309 q_dbus_message_iter_recurse(iter: &iterator, sub: &sub);
310 q_dbus_message_iter_next(iter: &iterator);
311 int len;
312 char* data;
313 q_dbus_message_iter_get_fixed_array(iter: &sub,value: &data,n_elements: &len);
314 return QByteArray(data,len);
315}
316
317QByteArray QDBusDemarshaller::toByteArray()
318{
319 if (q_dbus_message_iter_get_arg_type(iter: &iterator) == DBUS_TYPE_ARRAY
320 && q_dbus_message_iter_get_element_type(iter: &iterator) == DBUS_TYPE_BYTE) {
321 return toByteArrayUnchecked();
322 }
323 return QByteArray();
324}
325
326bool QDBusDemarshaller::atEnd()
327{
328 // dbus_message_iter_has_next is broken if the list has one single element
329 return q_dbus_message_iter_get_arg_type(iter: &iterator) == DBUS_TYPE_INVALID;
330}
331
332inline QDBusDemarshaller *QDBusDemarshaller::beginStructure()
333{
334 return beginCommon();
335}
336
337inline QDBusDemarshaller *QDBusDemarshaller::beginArray()
338{
339 return beginCommon();
340}
341
342inline QDBusDemarshaller *QDBusDemarshaller::beginMap()
343{
344 return beginCommon();
345}
346
347inline QDBusDemarshaller *QDBusDemarshaller::beginMapEntry()
348{
349 return beginCommon();
350}
351
352QDBusDemarshaller *QDBusDemarshaller::beginCommon()
353{
354 QDBusDemarshaller *d = new QDBusDemarshaller(capabilities);
355 d->parent = this;
356 d->message = q_dbus_message_ref(message);
357
358 // recurse
359 q_dbus_message_iter_recurse(iter: &iterator, sub: &d->iterator);
360 q_dbus_message_iter_next(iter: &iterator);
361 return d;
362}
363
364inline QDBusDemarshaller *QDBusDemarshaller::endStructure()
365{
366 return endCommon();
367}
368
369inline QDBusDemarshaller *QDBusDemarshaller::endArray()
370{
371 return endCommon();
372}
373
374inline QDBusDemarshaller *QDBusDemarshaller::endMap()
375{
376 return endCommon();
377}
378
379inline QDBusDemarshaller *QDBusDemarshaller::endMapEntry()
380{
381 return endCommon();
382}
383
384QDBusDemarshaller *QDBusDemarshaller::endCommon()
385{
386 QDBusDemarshaller *retval = parent;
387 delete this;
388 return retval;
389}
390
391QDBusArgument QDBusDemarshaller::duplicate()
392{
393 std::unique_ptr<QDBusDemarshaller> d(new QDBusDemarshaller(capabilities));
394 d->iterator = iterator;
395 d->message = q_dbus_message_ref(message);
396
397 q_dbus_message_iter_next(iter: &iterator);
398 return QDBusArgumentPrivate::create(d: d.release());
399}
400
401QT_END_NAMESPACE
402

source code of qtbase/src/dbus/qdbusdemarshaller.cpp