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 | |
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 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 | |
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 |
438 | |