source: trunk/src/dbus/qdbusmarshaller.cpp@ 467

Last change on this file since 467 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 16.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtDBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdbusargument_p.h"
43#include "qdbusutil_p.h"
44
45QT_BEGIN_NAMESPACE
46
47static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
48{
49 if (ba)
50 *ba += char(type);
51 else
52 q_dbus_message_iter_append_basic(it, type, arg);
53}
54
55QDBusMarshaller::~QDBusMarshaller()
56{
57 close();
58}
59
60inline QString QDBusMarshaller::currentSignature()
61{
62 if (message)
63 return QString::fromUtf8(q_dbus_message_get_signature(message));
64 return QString();
65}
66
67inline void QDBusMarshaller::append(uchar arg)
68{
69 qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
70}
71
72inline void QDBusMarshaller::append(bool arg)
73{
74 dbus_bool_t cast = arg;
75 qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
76}
77
78inline void QDBusMarshaller::append(short arg)
79{
80 qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
81}
82
83inline void QDBusMarshaller::append(ushort arg)
84{
85 qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
86}
87
88inline void QDBusMarshaller::append(int arg)
89{
90 qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
91}
92
93inline void QDBusMarshaller::append(uint arg)
94{
95 qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
96}
97
98inline void QDBusMarshaller::append(qlonglong arg)
99{
100 qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
101}
102
103inline void QDBusMarshaller::append(qulonglong arg)
104{
105 qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
106}
107
108inline void QDBusMarshaller::append(double arg)
109{
110 qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
111}
112
113void QDBusMarshaller::append(const QString &arg)
114{
115 QByteArray data = arg.toUtf8();
116 const char *cdata = data.constData();
117 qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
118}
119
120inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
121{
122 QByteArray data = arg.path().toUtf8();
123 if (!ba && data.isEmpty())
124 error();
125 const char *cdata = data.constData();
126 qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
127}
128
129inline void QDBusMarshaller::append(const QDBusSignature &arg)
130{
131 QByteArray data = arg.signature().toUtf8();
132 if (!ba && data.isEmpty())
133 error();
134 const char *cdata = data.constData();
135 qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
136}
137
138inline void QDBusMarshaller::append(const QByteArray &arg)
139{
140 if (ba) {
141 *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
142 return;
143 }
144
145 const char* cdata = arg.constData();
146 DBusMessageIter subiterator;
147 q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
148 &subiterator);
149 q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.length());
150 q_dbus_message_iter_close_container(&iterator, &subiterator);
151}
152
153inline bool QDBusMarshaller::append(const QDBusVariant &arg)
154{
155 if (ba) {
156 *ba += DBUS_TYPE_VARIANT_AS_STRING;
157 return true;
158 }
159
160 const QVariant &value = arg.variant();
161 QVariant::Type id = QVariant::Type(value.userType());
162 if (id == QVariant::Invalid) {
163 qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
164 error();
165 return false;
166 }
167
168 QByteArray tmpSignature;
169 const char *signature = 0;
170 if (int(id) == qMetaTypeId<QDBusArgument>()) {
171 // take the signature from the QDBusArgument object we're marshalling
172 tmpSignature =
173 qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
174 signature = tmpSignature.constData();
175 } else {
176 // take the signatuer from the metatype we're marshalling
177 signature = QDBusMetaType::typeToSignature(id);
178 }
179 if (!signature) {
180 qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
181 "Use qDBusRegisterMetaType to register it",
182 QVariant::typeToName( id ), id);
183 error();
184 return false;
185 }
186
187 QDBusMarshaller sub;
188 open(sub, DBUS_TYPE_VARIANT, signature);
189 bool isOk = sub.appendVariantInternal(value);
190 // don't call sub.close(): it auto-closes
191
192 return isOk;
193}
194
195inline void QDBusMarshaller::append(const QStringList &arg)
196{
197 if (ba) {
198 *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
199 return;
200 }
201
202 QDBusMarshaller sub;
203 open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
204 QStringList::ConstIterator it = arg.constBegin();
205 QStringList::ConstIterator end = arg.constEnd();
206 for ( ; it != end; ++it)
207 sub.append(*it);
208 // don't call sub.close(): it auto-closes
209}
210
211inline QDBusMarshaller *QDBusMarshaller::beginStructure()
212{
213 return beginCommon(DBUS_TYPE_STRUCT, 0);
214}
215
216inline QDBusMarshaller *QDBusMarshaller::beginArray(int id)
217{
218 const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
219 if (!signature) {
220 qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
221 "Use qDBusRegisterMetaType to register it",
222 QVariant::typeToName( QVariant::Type(id) ), id);
223 error();
224 return this;
225 }
226
227 return beginCommon(DBUS_TYPE_ARRAY, signature);
228}
229
230inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid)
231{
232 const char *ksignature = QDBusMetaType::typeToSignature( QVariant::Type(kid) );
233 if (!ksignature) {
234 qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
235 "Use qDBusRegisterMetaType to register it",
236 QVariant::typeToName( QVariant::Type(kid) ), kid);
237 error();
238 return this;
239 }
240 if (ksignature[1] != 0 || !q_dbus_type_is_basic(*ksignature)) {
241 qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
242 QVariant::typeToName( QVariant::Type(kid) ), kid);
243 error();
244 return this;
245 }
246
247 const char *vsignature = QDBusMetaType::typeToSignature( QVariant::Type(vid) );
248 if (!vsignature) {
249 qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
250 "Use qDBusRegisterMetaType to register it",
251 QVariant::typeToName( QVariant::Type(vid) ), vid);
252 error();
253 return this;
254 }
255
256 QByteArray signature;
257 signature = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
258 signature += ksignature;
259 signature += vsignature;
260 signature += DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
261 return beginCommon(DBUS_TYPE_ARRAY, signature);
262}
263
264inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
265{
266 return beginCommon(DBUS_TYPE_DICT_ENTRY, 0);
267}
268
269void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
270{
271 sub.parent = this;
272 sub.ba = ba;
273 sub.ok = true;
274
275 if (ba)
276 switch (code) {
277 case DBUS_TYPE_ARRAY:
278 *ba += char(code);
279 *ba += signature;
280 // fall through
281
282 case DBUS_TYPE_DICT_ENTRY:
283 sub.closeCode = 0;
284 break;
285
286 case DBUS_TYPE_STRUCT:
287 *ba += DBUS_STRUCT_BEGIN_CHAR;
288 sub.closeCode = DBUS_STRUCT_END_CHAR;
289 break;
290 }
291 else
292 q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
293}
294
295QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
296{
297 QDBusMarshaller *d = new QDBusMarshaller;
298 open(*d, code, signature);
299 return d;
300}
301
302inline QDBusMarshaller *QDBusMarshaller::endStructure()
303{ return endCommon(); }
304
305inline QDBusMarshaller *QDBusMarshaller::endArray()
306{ return endCommon(); }
307
308inline QDBusMarshaller *QDBusMarshaller::endMap()
309{ return endCommon(); }
310
311inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
312{ return endCommon(); }
313
314QDBusMarshaller *QDBusMarshaller::endCommon()
315{
316 QDBusMarshaller *retval = parent;
317 delete this;
318 return retval;
319}
320
321void QDBusMarshaller::close()
322{
323 if (ba) {
324 if (closeCode)
325 *ba += closeCode;
326 } else if (parent) {
327 q_dbus_message_iter_close_container(&parent->iterator, &iterator);
328 }
329}
330
331void QDBusMarshaller::error()
332{
333 ok = false;
334 if (parent)
335 parent->error();
336}
337
338bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
339{
340 int id = arg.userType();
341 if (id == QVariant::Invalid) {
342 qWarning("QDBusMarshaller: cannot add an invalid QVariant");
343 error();
344 return false;
345 }
346
347 // intercept QDBusArgument parameters here
348 if (id == qMetaTypeId<QDBusArgument>()) {
349 QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
350 QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
351 if (!d->message)
352 return false; // can't append this one...
353
354 QDBusDemarshaller demarshaller;
355 demarshaller.message = q_dbus_message_ref(d->message);
356
357 if (d->direction == Demarshalling) {
358 // it's demarshalling; just copy
359 demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
360 } else {
361 // it's marshalling; start over
362 if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
363 return false; // error!
364 }
365
366 return appendCrossMarshalling(&demarshaller);
367 }
368
369 const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
370 if (!signature) {
371 qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
372 "Use qDBusRegisterMetaType to register it",
373 QVariant::typeToName( QVariant::Type(id) ), id);
374 error();
375 return false;
376 }
377
378 switch (*signature) {
379#ifdef __OPTIMIZE__
380 case DBUS_TYPE_BYTE:
381 case DBUS_TYPE_BOOLEAN:
382 case DBUS_TYPE_INT16:
383 case DBUS_TYPE_UINT16:
384 case DBUS_TYPE_INT32:
385 case DBUS_TYPE_UINT32:
386 case DBUS_TYPE_INT64:
387 case DBUS_TYPE_UINT64:
388 case DBUS_TYPE_DOUBLE:
389 qIterAppend(&iterator, ba, *signature, arg.constData());
390 return true;
391
392 case DBUS_TYPE_STRING:
393 case DBUS_TYPE_OBJECT_PATH:
394 case DBUS_TYPE_SIGNATURE: {
395 const QByteArray data =
396 reinterpret_cast<const QString *>(arg.constData())->toUtf8();
397 const char *rawData = data.constData();
398 qIterAppend(&iterator, ba, *signature, &rawData);
399 return true;
400 }
401#else
402 case DBUS_TYPE_BYTE:
403 append( qvariant_cast<uchar>(arg) );
404 return true;
405 case DBUS_TYPE_BOOLEAN:
406 append( arg.toBool() );
407 return true;
408 case DBUS_TYPE_INT16:
409 append( qvariant_cast<short>(arg) );
410 return true;
411 case DBUS_TYPE_UINT16:
412 append( qvariant_cast<ushort>(arg) );
413 return true;
414 case DBUS_TYPE_INT32:
415 append( static_cast<dbus_int32_t>(arg.toInt()) );
416 return true;
417 case DBUS_TYPE_UINT32:
418 append( static_cast<dbus_uint32_t>(arg.toUInt()) );
419 return true;
420 case DBUS_TYPE_INT64:
421 append( arg.toLongLong() );
422 return true;
423 case DBUS_TYPE_UINT64:
424 append( arg.toULongLong() );
425 return true;
426 case DBUS_TYPE_DOUBLE:
427 append( arg.toDouble() );
428 return true;
429 case DBUS_TYPE_STRING:
430 append( arg.toString() );
431 return true;
432 case DBUS_TYPE_OBJECT_PATH:
433 append( qvariant_cast<QDBusObjectPath>(arg) );
434 return true;
435 case DBUS_TYPE_SIGNATURE:
436 append( qvariant_cast<QDBusSignature>(arg) );
437 return true;
438#endif
439
440 // compound types:
441 case DBUS_TYPE_VARIANT:
442 // nested QVariant
443 return append( qvariant_cast<QDBusVariant>(arg) );
444
445 case DBUS_TYPE_ARRAY:
446 // could be many things
447 // find out what kind of array it is
448 switch (arg.type()) {
449 case QVariant::StringList:
450 append( arg.toStringList() );
451 return true;
452
453 case QVariant::ByteArray:
454 append( arg.toByteArray() );
455 return true;
456
457 default:
458 ; // fall through
459 }
460 // fall through
461
462 case DBUS_TYPE_STRUCT:
463 case DBUS_STRUCT_BEGIN_CHAR:
464 return appendRegisteredType( arg );
465
466 case DBUS_TYPE_DICT_ENTRY:
467 case DBUS_DICT_ENTRY_BEGIN_CHAR:
468 qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
469 return false;
470
471 default:
472 qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'",
473 signature);
474 return false;
475 }
476
477 return true;
478}
479
480bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
481{
482 ref.ref(); // reference up
483 QDBusArgument self(QDBusArgumentPrivate::create(this));
484 return QDBusMetaType::marshall(self, arg.userType(), arg.constData());
485}
486
487bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
488{
489 int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
490 if (q_dbus_type_is_basic(code)) {
491 // easy: just append
492 // do exactly like the D-BUS docs suggest
493 // (see apidocs for q_dbus_message_iter_get_basic)
494
495 qlonglong value;
496 q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
497 q_dbus_message_iter_next(&demarshaller->iterator);
498 q_dbus_message_iter_append_basic(&iterator, code, &value);
499 return true;
500 }
501
502 if (code == DBUS_TYPE_ARRAY) {
503 int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
504 if (q_dbus_type_is_fixed(element)) {
505 // another optimisation: fixed size arrays
506 // code is exactly like QDBusDemarshaller::toByteArray
507 DBusMessageIter sub;
508 q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
509 q_dbus_message_iter_next(&demarshaller->iterator);
510 int len;
511 void* data;
512 q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
513
514 char signature[2] = { element, 0 };
515 q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
516 q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
517 q_dbus_message_iter_close_container(&iterator, &sub);
518
519 return true;
520 }
521 }
522
523 // We have to recurse
524 QDBusDemarshaller *drecursed = demarshaller->beginCommon();
525
526 QDBusMarshaller mrecursed; // create on the stack makes it autoclose
527 QByteArray subSignature;
528 const char *sig = 0;
529 if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
530 subSignature = drecursed->currentSignature().toLatin1();
531 if (!subSignature.isEmpty())
532 sig = subSignature.constData();
533 }
534 open(mrecursed, code, sig);
535
536 while (!drecursed->atEnd()) {
537 if (!mrecursed.appendCrossMarshalling(drecursed)) {
538 delete drecursed;
539 return false;
540 }
541 }
542
543 delete drecursed;
544 return true;
545}
546
547QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.