1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdbusargument_p.h"
43#include "qdbusconnection.h"
44#include <stdlib.h>
45
46QT_BEGIN_NAMESPACE
47
48template <typename T>
49static 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
75QDBusDemarshaller::~QDBusDemarshaller()
76{
77}
78
79inline 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
88inline uchar QDBusDemarshaller::toByte()
89{
90 return qIterGet<uchar>(&iterator);
91}
92
93inline bool QDBusDemarshaller::toBool()
94{
95 return bool(qIterGet<dbus_bool_t>(&iterator));
96}
97
98inline ushort QDBusDemarshaller::toUShort()
99{
100 return qIterGet<dbus_uint16_t>(&iterator);
101}
102
103inline short QDBusDemarshaller::toShort()
104{
105 return qIterGet<dbus_int16_t>(&iterator);
106}
107
108inline int QDBusDemarshaller::toInt()
109{
110 return qIterGet<dbus_int32_t>(&iterator);
111}
112
113inline uint QDBusDemarshaller::toUInt()
114{
115 return qIterGet<dbus_uint32_t>(&iterator);
116}
117
118inline qlonglong QDBusDemarshaller::toLongLong()
119{
120 return qIterGet<qlonglong>(&iterator);
121}
122
123inline qulonglong QDBusDemarshaller::toULongLong()
124{
125 return qIterGet<qulonglong>(&iterator);
126}
127
128inline double QDBusDemarshaller::toDouble()
129{
130 return qIterGet<double>(&iterator);
131}
132
133inline QString QDBusDemarshaller::toStringUnchecked()
134{
135 return QString::fromUtf8(qIterGet<char *>(&iterator));
136}
137
138inline QString QDBusDemarshaller::toString()
139{
140 if (isCurrentTypeStringLike())
141 return toStringUnchecked();
142 else
143 return QString();
144}
145
146inline QDBusObjectPath QDBusDemarshaller::toObjectPathUnchecked()
147 {
148 return QDBusObjectPath(QString::fromUtf8(qIterGet<char *>(&iterator)));
149 }
150
151inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
152{
153 if (isCurrentTypeStringLike())
154 return toObjectPathUnchecked();
155 else
156 return QDBusObjectPath();
157}
158
159inline QDBusSignature QDBusDemarshaller::toSignatureUnchecked()
160 {
161 return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator)));
162 }
163
164inline QDBusSignature QDBusDemarshaller::toSignature()
165{
166 if (isCurrentTypeStringLike())
167 return toSignatureUnchecked();
168 else
169 return QDBusSignature();
170}
171
172inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
173{
174 QDBusUnixFileDescriptor fd;
175 fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator));
176 return fd;
177}
178
179inline 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
189QDBusArgument::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
241QVariant 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 qVariantFromValue(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
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 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
437QT_END_NAMESPACE
438