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

Last change on this file since 1023 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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