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