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