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

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

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

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