QDBusPendingCallPrivate: save 8 bytes on 64-bit archs
[profile/ivi/qtbase.git] / src / dbus / qdbusdemarshaller.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbusargument_p.h"
43 #include "qdbusconnection.h"
44 #include <stdlib.h>
45
46 QT_BEGIN_NAMESPACE
47
48 template <typename T>
49 static inline T qIterGet(DBusMessageIter *it)
50 {
51     // Use a union of expected and largest type q_dbus_message_iter_get_basic
52     // will return to ensure reading the wrong basic type does not result in
53     // stack overwrite
54     union {
55         // The value to be extracted
56         T t;
57         // Largest type that q_dbus_message_iter_get_basic will return
58         // according to dbus_message_iter_get_basic API documentation
59         dbus_uint64_t maxValue;
60         // A pointer to ensure no stack overwrite in case there is a platform
61         // where sizeof(void*) > sizeof(dbus_uint64_t)
62         void* ptr;
63     } value;
64
65     // Initialize the value in case a narrower type is extracted to it.
66     // Note that the result of extracting a narrower type in place of a wider
67     // one and vice-versa will be platform-dependent.
68     value.t = T();
69
70     q_dbus_message_iter_get_basic(it, &value);
71     q_dbus_message_iter_next(it);
72     return value.t;
73 }
74
75 QDBusDemarshaller::~QDBusDemarshaller()
76 {
77 }
78
79 inline QString QDBusDemarshaller::currentSignature()
80 {
81     char *sig = q_dbus_message_iter_get_signature(&iterator);
82     QString retval = QString::fromUtf8(sig);
83     q_dbus_free(sig);
84
85     return retval;
86 }
87
88 inline uchar QDBusDemarshaller::toByte()
89 {
90     return qIterGet<uchar>(&iterator);
91 }
92
93 inline bool QDBusDemarshaller::toBool()
94 {
95     return bool(qIterGet<dbus_bool_t>(&iterator));
96 }
97
98 inline ushort QDBusDemarshaller::toUShort()
99 {
100     return qIterGet<dbus_uint16_t>(&iterator);
101 }
102
103 inline short QDBusDemarshaller::toShort()
104 {
105     return qIterGet<dbus_int16_t>(&iterator);
106 }
107
108 inline int QDBusDemarshaller::toInt()
109 {
110     return qIterGet<dbus_int32_t>(&iterator);
111 }
112
113 inline uint QDBusDemarshaller::toUInt()
114 {
115     return qIterGet<dbus_uint32_t>(&iterator);
116 }
117
118 inline qlonglong QDBusDemarshaller::toLongLong()
119 {
120     return qIterGet<qlonglong>(&iterator);
121 }
122
123 inline qulonglong QDBusDemarshaller::toULongLong()
124 {
125     return qIterGet<qulonglong>(&iterator);
126 }
127
128 inline double QDBusDemarshaller::toDouble()
129 {
130     return qIterGet<double>(&iterator);
131 }
132
133 inline QString QDBusDemarshaller::toStringUnchecked()
134 {
135     return QString::fromUtf8(qIterGet<char *>(&iterator));
136 }
137
138 inline QString QDBusDemarshaller::toString()
139 {
140     if (isCurrentTypeStringLike())
141         return toStringUnchecked();
142     else
143         return QString();
144 }
145
146 inline QDBusObjectPath QDBusDemarshaller::toObjectPathUnchecked()
147  {
148      return QDBusObjectPath(QString::fromUtf8(qIterGet<char *>(&iterator)));
149  }
150
151 inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
152 {
153     if (isCurrentTypeStringLike())
154         return toObjectPathUnchecked();
155     else
156         return QDBusObjectPath();
157 }
158
159 inline QDBusSignature QDBusDemarshaller::toSignatureUnchecked()
160  {
161      return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator)));
162  }
163
164 inline QDBusSignature QDBusDemarshaller::toSignature()
165 {
166     if (isCurrentTypeStringLike())
167         return toSignatureUnchecked();
168     else
169         return QDBusSignature();
170 }
171
172 inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
173 {
174     QDBusUnixFileDescriptor fd;
175     fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator));
176     return fd;
177 }
178
179 inline QDBusVariant QDBusDemarshaller::toVariant()
180 {
181     QDBusDemarshaller sub(capabilities);
182     sub.message = q_dbus_message_ref(message);
183     q_dbus_message_iter_recurse(&iterator, &sub.iterator);
184     q_dbus_message_iter_next(&iterator);
185
186     return QDBusVariant( sub.toVariantInternal() );
187 }
188
189 QDBusArgument::ElementType QDBusDemarshaller::currentType()
190 {
191     switch (q_dbus_message_iter_get_arg_type(&iterator)) {
192     case DBUS_TYPE_BYTE:
193     case DBUS_TYPE_INT16:
194     case DBUS_TYPE_UINT16:
195     case DBUS_TYPE_INT32:
196     case DBUS_TYPE_UINT32:
197     case DBUS_TYPE_INT64:
198     case DBUS_TYPE_UINT64:
199     case DBUS_TYPE_BOOLEAN:
200     case DBUS_TYPE_DOUBLE:
201     case DBUS_TYPE_STRING:
202     case DBUS_TYPE_OBJECT_PATH:
203     case DBUS_TYPE_SIGNATURE:
204         return QDBusArgument::BasicType;
205
206     case DBUS_TYPE_VARIANT:
207         return QDBusArgument::VariantType;
208
209     case DBUS_TYPE_ARRAY:
210         switch (q_dbus_message_iter_get_element_type(&iterator)) {
211         case DBUS_TYPE_BYTE:
212         case DBUS_TYPE_STRING:
213             // QByteArray and QStringList
214             return QDBusArgument::BasicType;
215         case DBUS_TYPE_DICT_ENTRY:
216             return QDBusArgument::MapType;
217         default:
218             return QDBusArgument::ArrayType;
219         }
220
221     case DBUS_TYPE_STRUCT:
222         return QDBusArgument::StructureType;
223     case DBUS_TYPE_DICT_ENTRY:
224         return QDBusArgument::MapEntryType;
225
226     case DBUS_TYPE_UNIX_FD:
227         return capabilities & QDBusConnection::UnixFileDescriptorPassing ?
228                     QDBusArgument::BasicType : QDBusArgument::UnknownType;
229
230     case DBUS_TYPE_INVALID:
231         return QDBusArgument::UnknownType;
232
233 //    default:
234 //        qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
235 //                 q_dbus_message_iter_get_arg_type(&iterator),
236 //                 q_dbus_message_iter_get_arg_type(&iterator));
237     }
238     return QDBusArgument::UnknownType;
239 }
240
241 QVariant QDBusDemarshaller::toVariantInternal()
242 {
243     switch (q_dbus_message_iter_get_arg_type(&iterator)) {
244     case DBUS_TYPE_BYTE:
245         return QVariant::fromValue(toByte());
246     case DBUS_TYPE_INT16:
247         return QVariant::fromValue(toShort());
248     case DBUS_TYPE_UINT16:
249         return QVariant::fromValue(toUShort());
250     case DBUS_TYPE_INT32:
251         return toInt();
252     case DBUS_TYPE_UINT32:
253         return toUInt();
254     case DBUS_TYPE_DOUBLE:
255         return toDouble();
256     case DBUS_TYPE_BOOLEAN:
257         return toBool();
258     case DBUS_TYPE_INT64:
259         return toLongLong();
260     case DBUS_TYPE_UINT64:
261         return toULongLong();
262     case DBUS_TYPE_STRING:
263         return toStringUnchecked();
264     case DBUS_TYPE_OBJECT_PATH:
265         return QVariant::fromValue(toObjectPathUnchecked());
266     case DBUS_TYPE_SIGNATURE:
267         return QVariant::fromValue(toSignatureUnchecked());
268     case DBUS_TYPE_VARIANT:
269         return QVariant::fromValue(toVariant());
270
271     case DBUS_TYPE_ARRAY:
272         switch (q_dbus_message_iter_get_element_type(&iterator)) {
273         case DBUS_TYPE_BYTE:
274             // QByteArray
275             return toByteArrayUnchecked();
276         case DBUS_TYPE_STRING:
277             return toStringListUnchecked();
278         case DBUS_TYPE_DICT_ENTRY:
279             return QVariant::fromValue(duplicate());
280
281         default:
282             return QVariant::fromValue(duplicate());
283         }
284
285     case DBUS_TYPE_STRUCT:
286         return QVariant::fromValue(duplicate());
287
288     case DBUS_TYPE_UNIX_FD:
289         if (capabilities & QDBusConnection::UnixFileDescriptorPassing)
290             return QVariant::fromValue(toUnixFileDescriptor());
291         // fall through
292
293     default:
294 //        qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
295 //                 q_dbus_message_iter_get_arg_type(&iterator),
296 //                 q_dbus_message_iter_get_arg_type(&iterator));
297         char *ptr = 0;
298         ptr += q_dbus_message_iter_get_arg_type(&iterator);
299         q_dbus_message_iter_next(&iterator);
300
301         // I hope you never dereference this pointer!
302         return QVariant::fromValue<void *>(ptr);
303         break;
304     };
305 }
306
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
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
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
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
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
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
368 inline QDBusDemarshaller *QDBusDemarshaller::beginStructure()
369 {
370     return beginCommon();
371 }
372
373 inline QDBusDemarshaller *QDBusDemarshaller::beginArray()
374 {
375     return beginCommon();
376 }
377
378 inline QDBusDemarshaller *QDBusDemarshaller::beginMap()
379 {
380     return beginCommon();
381 }
382
383 inline QDBusDemarshaller *QDBusDemarshaller::beginMapEntry()
384 {
385     return beginCommon();
386 }
387
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
400 inline QDBusDemarshaller *QDBusDemarshaller::endStructure()
401 {
402     return endCommon();
403 }
404
405 inline QDBusDemarshaller *QDBusDemarshaller::endArray()
406 {
407     return endCommon();
408 }
409
410 inline QDBusDemarshaller *QDBusDemarshaller::endMap()
411 {
412     return endCommon();
413 }
414
415 inline QDBusDemarshaller *QDBusDemarshaller::endMapEntry()
416 {
417     return endCommon();
418 }
419
420 QDBusDemarshaller *QDBusDemarshaller::endCommon()
421 {
422     QDBusDemarshaller *retval = parent;
423     delete this;
424     return retval;
425 }
426
427 QDBusArgument QDBusDemarshaller::duplicate()
428 {
429     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);
435 }
436
437 QT_END_NAMESPACE