summaryrefslogtreecommitdiffstats
path: root/src/dbus/qdbusmarshaller.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/dbus/qdbusmarshaller.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/dbus/qdbusmarshaller.cpp')
-rw-r--r--src/dbus/qdbusmarshaller.cpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
new file mode 100644
index 0000000000..6dec359713
--- /dev/null
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -0,0 +1,573 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusargument_p.h"
+#include "qdbusconnection.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
+{
+ if (ba)
+ *ba += char(type);
+ else
+ q_dbus_message_iter_append_basic(it, type, arg);
+}
+
+QDBusMarshaller::~QDBusMarshaller()
+{
+ close();
+}
+
+inline QString QDBusMarshaller::currentSignature()
+{
+ if (message)
+ return QString::fromUtf8(q_dbus_message_get_signature(message));
+ return QString();
+}
+
+inline void QDBusMarshaller::append(uchar arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
+}
+
+inline void QDBusMarshaller::append(bool arg)
+{
+ dbus_bool_t cast = arg;
+ qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
+}
+
+inline void QDBusMarshaller::append(short arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
+}
+
+inline void QDBusMarshaller::append(ushort arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
+}
+
+inline void QDBusMarshaller::append(int arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
+}
+
+inline void QDBusMarshaller::append(uint arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
+}
+
+inline void QDBusMarshaller::append(qlonglong arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
+}
+
+inline void QDBusMarshaller::append(qulonglong arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
+}
+
+inline void QDBusMarshaller::append(double arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
+}
+
+void QDBusMarshaller::append(const QString &arg)
+{
+ QByteArray data = arg.toUtf8();
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
+{
+ QByteArray data = arg.path().toUtf8();
+ if (!ba && data.isEmpty())
+ error(QLatin1String("Invalid object path passed in arguments"));
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusSignature &arg)
+{
+ QByteArray data = arg.signature().toUtf8();
+ if (!ba && data.isEmpty())
+ error(QLatin1String("Invalid signature passed in arguments"));
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg)
+{
+ int fd = arg.fileDescriptor();
+ if (!ba && fd == -1) {
+ error(QLatin1String("Invalid file descriptor passed in arguments"));
+ } else {
+ qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd);
+ }
+}
+
+inline void QDBusMarshaller::append(const QByteArray &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
+ return;
+ }
+
+ const char* cdata = arg.constData();
+ DBusMessageIter subiterator;
+ q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
+ &subiterator);
+ q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.length());
+ q_dbus_message_iter_close_container(&iterator, &subiterator);
+}
+
+inline bool QDBusMarshaller::append(const QDBusVariant &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_VARIANT_AS_STRING;
+ return true;
+ }
+
+ const QVariant &value = arg.variant();
+ QVariant::Type id = QVariant::Type(value.userType());
+ if (id == QVariant::Invalid) {
+ qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
+ return false;
+ }
+
+ QByteArray tmpSignature;
+ const char *signature = 0;
+ if (int(id) == QDBusMetaTypeId::argument) {
+ // take the signature from the QDBusArgument object we're marshalling
+ tmpSignature =
+ qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
+ signature = tmpSignature.constData();
+ } else {
+ // take the signatuer from the metatype we're marshalling
+ signature = QDBusMetaType::typeToSignature(id);
+ }
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( id ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(id))));
+ return false;
+ }
+
+ QDBusMarshaller sub(capabilities);
+ open(sub, DBUS_TYPE_VARIANT, signature);
+ bool isOk = sub.appendVariantInternal(value);
+ // don't call sub.close(): it auto-closes
+
+ return isOk;
+}
+
+inline void QDBusMarshaller::append(const QStringList &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
+ return;
+ }
+
+ QDBusMarshaller sub(capabilities);
+ open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
+ QStringList::ConstIterator it = arg.constBegin();
+ QStringList::ConstIterator end = arg.constEnd();
+ for ( ; it != end; ++it)
+ sub.append(*it);
+ // don't call sub.close(): it auto-closes
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginStructure()
+{
+ return beginCommon(DBUS_TYPE_STRUCT, 0);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginArray(int id)
+{
+ const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(id) ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
+ return this;
+ }
+
+ return beginCommon(DBUS_TYPE_ARRAY, signature);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid)
+{
+ const char *ksignature = QDBusMetaType::typeToSignature( QVariant::Type(kid) );
+ if (!ksignature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(kid) ), kid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
+ return this;
+ }
+ if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
+ qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
+ QVariant::typeToName( QVariant::Type(kid) ), kid);
+ error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
+ return this;
+ }
+
+ const char *vsignature = QDBusMetaType::typeToSignature( QVariant::Type(vid) );
+ if (!vsignature) {
+ const char *typeName = QVariant::typeToName(QVariant::Type(vid));
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ typeName, vid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(typeName)));
+ return this;
+ }
+
+ QByteArray signature;
+ signature = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
+ signature += ksignature;
+ signature += vsignature;
+ signature += DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
+ return beginCommon(DBUS_TYPE_ARRAY, signature);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
+{
+ return beginCommon(DBUS_TYPE_DICT_ENTRY, 0);
+}
+
+void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
+{
+ sub.parent = this;
+ sub.ba = ba;
+ sub.ok = true;
+ sub.capabilities = capabilities;
+
+ if (ba)
+ switch (code) {
+ case DBUS_TYPE_ARRAY:
+ *ba += char(code);
+ *ba += signature;
+ // fall through
+
+ case DBUS_TYPE_DICT_ENTRY:
+ sub.closeCode = 0;
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ *ba += DBUS_STRUCT_BEGIN_CHAR;
+ sub.closeCode = DBUS_STRUCT_END_CHAR;
+ break;
+ }
+ else
+ q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
+}
+
+QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
+{
+ QDBusMarshaller *d = new QDBusMarshaller(capabilities);
+ open(*d, code, signature);
+ return d;
+}
+
+inline QDBusMarshaller *QDBusMarshaller::endStructure()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endArray()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endMap()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
+{ return endCommon(); }
+
+QDBusMarshaller *QDBusMarshaller::endCommon()
+{
+ QDBusMarshaller *retval = parent;
+ delete this;
+ return retval;
+}
+
+void QDBusMarshaller::close()
+{
+ if (ba) {
+ if (closeCode)
+ *ba += closeCode;
+ } else if (parent) {
+ q_dbus_message_iter_close_container(&parent->iterator, &iterator);
+ }
+}
+
+void QDBusMarshaller::error(const QString &msg)
+{
+ ok = false;
+ if (parent)
+ parent->error(msg);
+ else
+ errorString = msg;
+}
+
+bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
+{
+ int id = arg.userType();
+ if (id == QVariant::Invalid) {
+ qWarning("QDBusMarshaller: cannot add an invalid QVariant");
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
+ return false;
+ }
+
+ // intercept QDBusArgument parameters here
+ if (id == QDBusMetaTypeId::argument) {
+ QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
+ QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
+ if (!d->message)
+ return false; // can't append this one...
+
+ QDBusDemarshaller demarshaller(capabilities);
+ demarshaller.message = q_dbus_message_ref(d->message);
+
+ if (d->direction == Demarshalling) {
+ // it's demarshalling; just copy
+ demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
+ } else {
+ // it's marshalling; start over
+ if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
+ return false; // error!
+ }
+
+ return appendCrossMarshalling(&demarshaller);
+ }
+
+ const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(id) ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
+ return false;
+ }
+
+ switch (*signature) {
+#ifdef __OPTIMIZE__
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_DOUBLE:
+ qIterAppend(&iterator, ba, *signature, arg.constData());
+ return true;
+ case DBUS_TYPE_BOOLEAN:
+ append( arg.toBool() );
+ return true;
+#else
+ case DBUS_TYPE_BYTE:
+ append( qvariant_cast<uchar>(arg) );
+ return true;
+ case DBUS_TYPE_BOOLEAN:
+ append( arg.toBool() );
+ return true;
+ case DBUS_TYPE_INT16:
+ append( qvariant_cast<short>(arg) );
+ return true;
+ case DBUS_TYPE_UINT16:
+ append( qvariant_cast<ushort>(arg) );
+ return true;
+ case DBUS_TYPE_INT32:
+ append( static_cast<dbus_int32_t>(arg.toInt()) );
+ return true;
+ case DBUS_TYPE_UINT32:
+ append( static_cast<dbus_uint32_t>(arg.toUInt()) );
+ return true;
+ case DBUS_TYPE_INT64:
+ append( arg.toLongLong() );
+ return true;
+ case DBUS_TYPE_UINT64:
+ append( arg.toULongLong() );
+ return true;
+ case DBUS_TYPE_DOUBLE:
+ append( arg.toDouble() );
+ return true;
+#endif
+
+ case DBUS_TYPE_STRING:
+ append( arg.toString() );
+ return true;
+ case DBUS_TYPE_OBJECT_PATH:
+ append( qvariant_cast<QDBusObjectPath>(arg) );
+ return true;
+ case DBUS_TYPE_SIGNATURE:
+ append( qvariant_cast<QDBusSignature>(arg) );
+ return true;
+
+ // compound types:
+ case DBUS_TYPE_VARIANT:
+ // nested QVariant
+ return append( qvariant_cast<QDBusVariant>(arg) );
+
+ case DBUS_TYPE_ARRAY:
+ // could be many things
+ // find out what kind of array it is
+ switch (arg.type()) {
+ case QVariant::StringList:
+ append( arg.toStringList() );
+ return true;
+
+ case QVariant::ByteArray:
+ append( arg.toByteArray() );
+ return true;
+
+ default:
+ ; // fall through
+ }
+ // fall through
+
+ case DBUS_TYPE_STRUCT:
+ case DBUS_STRUCT_BEGIN_CHAR:
+ return appendRegisteredType( arg );
+
+ case DBUS_TYPE_DICT_ENTRY:
+ case DBUS_DICT_ENTRY_BEGIN_CHAR:
+ qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
+ return false;
+
+ case DBUS_TYPE_UNIX_FD:
+ if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) {
+ append(qvariant_cast<QDBusUnixFileDescriptor>(arg));
+ return true;
+ }
+ // fall through
+
+ default:
+ qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'",
+ signature);
+ return false;
+ }
+
+ return true;
+}
+
+bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
+{
+ ref.ref(); // reference up
+ QDBusArgument self(QDBusArgumentPrivate::create(this));
+ return QDBusMetaType::marshall(self, arg.userType(), arg.constData());
+}
+
+bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
+{
+ int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
+ if (QDBusUtil::isValidBasicType(code)) {
+ // easy: just append
+ // do exactly like the D-BUS docs suggest
+ // (see apidocs for q_dbus_message_iter_get_basic)
+
+ qlonglong value;
+ q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
+ q_dbus_message_iter_next(&demarshaller->iterator);
+ q_dbus_message_iter_append_basic(&iterator, code, &value);
+ return true;
+ }
+
+ if (code == DBUS_TYPE_ARRAY) {
+ int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
+ if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) {
+ // another optimization: fixed size arrays
+ // code is exactly like QDBusDemarshaller::toByteArray
+ DBusMessageIter sub;
+ q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
+ q_dbus_message_iter_next(&demarshaller->iterator);
+ int len;
+ void* data;
+ q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
+
+ char signature[2] = { char(element), 0 };
+ q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
+ q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
+ q_dbus_message_iter_close_container(&iterator, &sub);
+
+ return true;
+ }
+ }
+
+ // We have to recurse
+ QDBusDemarshaller *drecursed = demarshaller->beginCommon();
+
+ QDBusMarshaller mrecursed(capabilities); // create on the stack makes it autoclose
+ QByteArray subSignature;
+ const char *sig = 0;
+ if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
+ subSignature = drecursed->currentSignature().toLatin1();
+ if (!subSignature.isEmpty())
+ sig = subSignature.constData();
+ }
+ open(mrecursed, code, sig);
+
+ while (!drecursed->atEnd()) {
+ if (!mrecursed.appendCrossMarshalling(drecursed)) {
+ delete drecursed;
+ return false;
+ }
+ }
+
+ delete drecursed;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS