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
47 QT_BEGIN_NAMESPACE
48
49 template <typename T>
qIterGet(DBusMessageIter * it)50 static 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
~QDBusDemarshaller()76 QDBusDemarshaller::~QDBusDemarshaller()
77 {
78 }
79
currentSignature()80 inline 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
toByte()89 inline uchar QDBusDemarshaller::toByte()
90 {
91 return qIterGet<uchar>(&iterator);
92 }
93
toBool()94 inline bool QDBusDemarshaller::toBool()
95 {
96 return bool(qIterGet<dbus_bool_t>(&iterator));
97 }
98
toUShort()99 inline ushort QDBusDemarshaller::toUShort()
100 {
101 return qIterGet<dbus_uint16_t>(&iterator);
102 }
103
toShort()104 inline short QDBusDemarshaller::toShort()
105 {
106 return qIterGet<dbus_int16_t>(&iterator);
107 }
108
toInt()109 inline int QDBusDemarshaller::toInt()
110 {
111 return qIterGet<dbus_int32_t>(&iterator);
112 }
113
toUInt()114 inline uint QDBusDemarshaller::toUInt()
115 {
116 return qIterGet<dbus_uint32_t>(&iterator);
117 }
118
toLongLong()119 inline qlonglong QDBusDemarshaller::toLongLong()
120 {
121 return qIterGet<qlonglong>(&iterator);
122 }
123
toULongLong()124 inline qulonglong QDBusDemarshaller::toULongLong()
125 {
126 return qIterGet<qulonglong>(&iterator);
127 }
128
toDouble()129 inline double QDBusDemarshaller::toDouble()
130 {
131 return qIterGet<double>(&iterator);
132 }
133
toStringUnchecked()134 inline QString QDBusDemarshaller::toStringUnchecked()
135 {
136 return QString::fromUtf8(qIterGet<char *>(&iterator));
137 }
138
toString()139 inline QString QDBusDemarshaller::toString()
140 {
141 if (isCurrentTypeStringLike())
142 return toStringUnchecked();
143 else
144 return QString();
145 }
146
toObjectPathUnchecked()147 inline QDBusObjectPath QDBusDemarshaller::toObjectPathUnchecked()
148 {
149 return QDBusObjectPath(QString::fromUtf8(qIterGet<char *>(&iterator)));
150 }
151
toObjectPath()152 inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
153 {
154 if (isCurrentTypeStringLike())
155 return toObjectPathUnchecked();
156 else
157 return QDBusObjectPath();
158 }
159
toSignatureUnchecked()160 inline QDBusSignature QDBusDemarshaller::toSignatureUnchecked()
161 {
162 return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator)));
163 }
164
toSignature()165 inline QDBusSignature QDBusDemarshaller::toSignature()
166 {
167 if (isCurrentTypeStringLike())
168 return toSignatureUnchecked();
169 else
170 return QDBusSignature();
171 }
172
toUnixFileDescriptor()173 inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
174 {
175 QDBusUnixFileDescriptor fd;
176 fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator));
177 return fd;
178 }
179
toVariant()180 inline 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
currentType()190 QDBusArgument::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
toVariantInternal()242 QVariant 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
isCurrentTypeStringLike()307 bool 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
toStringListUnchecked()320 QStringList 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
toStringList()333 QStringList 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
toByteArrayUnchecked()342 QByteArray 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
toByteArray()353 QByteArray 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
atEnd()362 bool 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
beginStructure()368 inline QDBusDemarshaller *QDBusDemarshaller::beginStructure()
369 {
370 return beginCommon();
371 }
372
beginArray()373 inline QDBusDemarshaller *QDBusDemarshaller::beginArray()
374 {
375 return beginCommon();
376 }
377
beginMap()378 inline QDBusDemarshaller *QDBusDemarshaller::beginMap()
379 {
380 return beginCommon();
381 }
382
beginMapEntry()383 inline QDBusDemarshaller *QDBusDemarshaller::beginMapEntry()
384 {
385 return beginCommon();
386 }
387
beginCommon()388 QDBusDemarshaller *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
endStructure()400 inline QDBusDemarshaller *QDBusDemarshaller::endStructure()
401 {
402 return endCommon();
403 }
404
endArray()405 inline QDBusDemarshaller *QDBusDemarshaller::endArray()
406 {
407 return endCommon();
408 }
409
endMap()410 inline QDBusDemarshaller *QDBusDemarshaller::endMap()
411 {
412 return endCommon();
413 }
414
endMapEntry()415 inline QDBusDemarshaller *QDBusDemarshaller::endMapEntry()
416 {
417 return endCommon();
418 }
419
endCommon()420 QDBusDemarshaller *QDBusDemarshaller::endCommon()
421 {
422 QDBusDemarshaller *retval = parent;
423 delete this;
424 return retval;
425 }
426
duplicate()427 QDBusArgument 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
437 QT_END_NAMESPACE
438