diff options
Diffstat (limited to 'src/dbus/qdbusmetatype.cpp')
-rw-r--r-- | src/dbus/qdbusmetatype.cpp | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp new file mode 100644 index 0000000000..9d9112cde5 --- /dev/null +++ b/src/dbus/qdbusmetatype.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** 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 "qdbusmetatype.h" + +#include <string.h> +#include "qdbus_symbols_p.h" + +#include <qbytearray.h> +#include <qglobal.h> +#include <qreadwritelock.h> +#include <qvector.h> + +#include "qdbusmessage.h" +#include "qdbusunixfiledescriptor.h" +#include "qdbusutil_p.h" +#include "qdbusmetatype_p.h" +#include "qdbusargument_p.h" + +#ifndef QT_NO_DBUS + +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +# define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + +Q_DECLARE_METATYPE(QList<bool>) +Q_DECLARE_METATYPE(QList<short>) +Q_DECLARE_METATYPE(QList<ushort>) +Q_DECLARE_METATYPE(QList<int>) +Q_DECLARE_METATYPE(QList<uint>) +Q_DECLARE_METATYPE(QList<qlonglong>) +Q_DECLARE_METATYPE(QList<qulonglong>) +Q_DECLARE_METATYPE(QList<double>) + +QT_BEGIN_NAMESPACE + +class QDBusCustomTypeInfo +{ +public: + QDBusCustomTypeInfo() : signature(0, '\0'), marshall(0), demarshall(0) + { } + + // Suggestion: + // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type + QByteArray signature; + QDBusMetaType::MarshallFunction marshall; + QDBusMetaType::DemarshallFunction demarshall; +}; + +template<typename T> +inline static void registerHelper(T * = 0) +{ + void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>; + void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>; + QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(), + reinterpret_cast<QDBusMetaType::MarshallFunction>(mf), + reinterpret_cast<QDBusMetaType::DemarshallFunction>(df)); +} + +int QDBusMetaTypeId::message; +int QDBusMetaTypeId::argument; +int QDBusMetaTypeId::variant; +int QDBusMetaTypeId::objectpath; +int QDBusMetaTypeId::signature; +int QDBusMetaTypeId::error; +int QDBusMetaTypeId::unixfd; + +void QDBusMetaTypeId::init() +{ + static volatile bool initialized = false; + + // reentrancy is not a problem since everything else is locked on their own + // set the guard variable at the end + if (!initialized) { + // register our types with QtCore + message = qRegisterMetaType<QDBusMessage>("QDBusMessage"); + argument = qRegisterMetaType<QDBusArgument>("QDBusArgument"); + variant = qRegisterMetaType<QDBusVariant>("QDBusVariant"); + objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath"); + signature = qRegisterMetaType<QDBusSignature>("QDBusSignature"); + error = qRegisterMetaType<QDBusError>("QDBusError"); + unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("QDBusUnixFileDescriptor"); + +#ifndef QDBUS_NO_SPECIALTYPES + // and register QtCore's with us + registerHelper<QDate>(); + registerHelper<QTime>(); + registerHelper<QDateTime>(); + registerHelper<QRect>(); + registerHelper<QRectF>(); + registerHelper<QSize>(); + registerHelper<QSizeF>(); + registerHelper<QPoint>(); + registerHelper<QPointF>(); + registerHelper<QLine>(); + registerHelper<QLineF>(); + registerHelper<QVariantList>(); + registerHelper<QVariantMap>(); + registerHelper<QVariantHash>(); + + qDBusRegisterMetaType<QList<bool> >(); + qDBusRegisterMetaType<QList<short> >(); + qDBusRegisterMetaType<QList<ushort> >(); + qDBusRegisterMetaType<QList<int> >(); + qDBusRegisterMetaType<QList<uint> >(); + qDBusRegisterMetaType<QList<qlonglong> >(); + qDBusRegisterMetaType<QList<qulonglong> >(); + qDBusRegisterMetaType<QList<double> >(); + qDBusRegisterMetaType<QList<QDBusObjectPath> >(); + qDBusRegisterMetaType<QList<QDBusSignature> >(); + qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >(); +#endif + + initialized = true; + } +} + +Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes) +Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) + +/*! + \class QDBusMetaType + \brief Meta-type registration system for the QtDBus module. + \internal + + The QDBusMetaType class allows you to register class types for + marshalling and demarshalling over D-Bus. D-Bus supports a very + limited set of primitive types, but allows one to extend the type + system by creating compound types, such as arrays (lists) and + structs. In order to use them with QtDBus, those types must be + registered. + + See \l {qdbustypesystem.html}{QtDBus type system} for more + information on the type system and how to register additional + types. + + \sa {qdbustypesystem.html}{QtDBus type system}, + qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument +*/ + +/*! + \fn int qDBusRegisterMetaType() + \relates QDBusArgument + \threadsafe + \since 4.2 + + Registers \c{T} with the + \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l + {QMetaType}{meta-type system}, if it's not already registered. + + To register a type, it must be declared as a meta-type with the + Q_DECLARE_METATYPE() macro, and then registered as in the + following example: + + \snippet doc/src/snippets/code/src_qdbus_qdbusmetatype.cpp 0 + + If \c{T} isn't a type derived from one of + Qt's \l{container classes}, the \c{operator<<} and + \c{operator>>} streaming operators between \c{T} and QDBusArgument + must be already declared. See the \l {qdbustypesystem.html}{QtDBus + type system} page for more information on how to declare such + types. + + This function returns the Qt meta type id for the type (the same + value that is returned from qRegisterMetaType()). + + \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType +*/ + +/*! + \typedef QDBusMetaType::MarshallFunction + \internal +*/ + +/*! + \typedef QDBusMetaType::DemarshallFunction + \internal +*/ + +/*! + \internal + Registers the marshalling and demarshalling functions for meta + type \a id. +*/ +void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf, + DemarshallFunction df) +{ + QByteArray var; + QVector<QDBusCustomTypeInfo> *ct = customTypes(); + if (id < 0 || !mf || !df || !ct) + return; // error! + + QWriteLocker locker(customTypesLock()); + if (id >= ct->size()) + ct->resize(id + 1); + QDBusCustomTypeInfo &info = (*ct)[id]; + info.marshall = mf; + info.demarshall = df; +} + +/*! + \internal + Executes the marshalling of type \a id (whose data is contained in + \a data) to the D-Bus marshalling argument \a arg. Returns true if + the marshalling succeeded, or false if an error occurred. +*/ +bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data) +{ + QDBusMetaTypeId::init(); + + MarshallFunction mf; + { + QReadLocker locker(customTypesLock()); + QVector<QDBusCustomTypeInfo> *ct = customTypes(); + if (id >= ct->size()) + return false; // non-existent + + const QDBusCustomTypeInfo &info = (*ct).at(id); + if (!info.marshall) { + mf = 0; // make gcc happy + return false; + } else + mf = info.marshall; + } + + mf(arg, data); + return true; +} + +/*! + \internal + Executes the demarshalling of type \a id (whose data will be placed in + \a data) from the D-Bus marshalling argument \a arg. Returns true if + the demarshalling succeeded, or false if an error occurred. +*/ +bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data) +{ + QDBusMetaTypeId::init(); + + DemarshallFunction df; + { + QReadLocker locker(customTypesLock()); + QVector<QDBusCustomTypeInfo> *ct = customTypes(); + if (id >= ct->size()) + return false; // non-existent + + const QDBusCustomTypeInfo &info = (*ct).at(id); + if (!info.demarshall) { + df = 0; // make gcc happy + return false; + } else + df = info.demarshall; + } + + QDBusArgument copy = arg; + df(copy, data); + return true; +} + +/*! + \fn QDBusMetaType::signatureToType(const char *signature) + \internal + + Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given + by \a signature. + + Note: this function only handles the basic D-Bus types. + + \sa QDBusUtil::isValidSingleSignature(), typeToSignature(), + QVariant::type(), QVariant::userType() +*/ +int QDBusMetaType::signatureToType(const char *signature) +{ + if (!signature) + return QVariant::Invalid; + + QDBusMetaTypeId::init(); + switch (signature[0]) + { + case DBUS_TYPE_BOOLEAN: + return QVariant::Bool; + + case DBUS_TYPE_BYTE: + return QMetaType::UChar; + + case DBUS_TYPE_INT16: + return QMetaType::Short; + + case DBUS_TYPE_UINT16: + return QMetaType::UShort; + + case DBUS_TYPE_INT32: + return QVariant::Int; + + case DBUS_TYPE_UINT32: + return QVariant::UInt; + + case DBUS_TYPE_INT64: + return QVariant::LongLong; + + case DBUS_TYPE_UINT64: + return QVariant::ULongLong; + + case DBUS_TYPE_DOUBLE: + return QVariant::Double; + + case DBUS_TYPE_STRING: + return QVariant::String; + + case DBUS_TYPE_OBJECT_PATH: + return QDBusMetaTypeId::objectpath; + + case DBUS_TYPE_SIGNATURE: + return QDBusMetaTypeId::signature; + + case DBUS_TYPE_UNIX_FD: + return QDBusMetaTypeId::unixfd; + + case DBUS_TYPE_VARIANT: + return QDBusMetaTypeId::variant; + + case DBUS_TYPE_ARRAY: // special case + switch (signature[1]) { + case DBUS_TYPE_BYTE: + return QVariant::ByteArray; + + case DBUS_TYPE_STRING: + return QVariant::StringList; + + case DBUS_TYPE_VARIANT: + return QVariant::List; + + case DBUS_TYPE_OBJECT_PATH: + return qMetaTypeId<QList<QDBusObjectPath> >(); + + case DBUS_TYPE_SIGNATURE: + return qMetaTypeId<QList<QDBusSignature> >(); + + } + // fall through + default: + return QVariant::Invalid; + } +} + +/*! + \fn QDBusMetaType::typeToSignature(int type) + \internal + + Returns the D-Bus signature equivalent to the supplied meta type id \a type. + + More types can be registered with the qDBusRegisterMetaType() function. + + \sa QDBusUtil::isValidSingleSignature(), signatureToType(), + QVariant::type(), QVariant::userType() +*/ +const char *QDBusMetaType::typeToSignature(int type) +{ + // check if it's a static type + switch (type) + { + case QMetaType::UChar: + return DBUS_TYPE_BYTE_AS_STRING; + + case QVariant::Bool: + return DBUS_TYPE_BOOLEAN_AS_STRING; + + case QMetaType::Short: + return DBUS_TYPE_INT16_AS_STRING; + + case QMetaType::UShort: + return DBUS_TYPE_UINT16_AS_STRING; + + case QVariant::Int: + return DBUS_TYPE_INT32_AS_STRING; + + case QVariant::UInt: + return DBUS_TYPE_UINT32_AS_STRING; + + case QVariant::LongLong: + return DBUS_TYPE_INT64_AS_STRING; + + case QVariant::ULongLong: + return DBUS_TYPE_UINT64_AS_STRING; + + case QVariant::Double: + return DBUS_TYPE_DOUBLE_AS_STRING; + + case QVariant::String: + return DBUS_TYPE_STRING_AS_STRING; + + case QVariant::StringList: + return DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_STRING_AS_STRING; // as + + case QVariant::ByteArray: + return DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING; // ay + } + + QDBusMetaTypeId::init(); + if (type == QDBusMetaTypeId::variant) + return DBUS_TYPE_VARIANT_AS_STRING; + else if (type == QDBusMetaTypeId::objectpath) + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + else if (type == QDBusMetaTypeId::signature) + return DBUS_TYPE_SIGNATURE_AS_STRING; + else if (type == QDBusMetaTypeId::unixfd) + return DBUS_TYPE_UNIX_FD_AS_STRING; + + // try the database + QVector<QDBusCustomTypeInfo> *ct = customTypes(); + { + QReadLocker locker(customTypesLock()); + if (type >= ct->size()) + return 0; // type not registered with us + + const QDBusCustomTypeInfo &info = (*ct).at(type); + + if (!info.signature.isNull()) + return info.signature; + + if (!info.marshall) + return 0; // type not registered with us + } + + // call to user code to construct the signature type + QDBusCustomTypeInfo *info; + { + // createSignature will never return a null QByteArray + // if there was an error, it'll return "" + QByteArray signature = QDBusArgumentPrivate::createSignature(type); + + // re-acquire lock + QWriteLocker locker(customTypesLock()); + info = &(*ct)[type]; + info->signature = signature; + } + return info->signature; +} + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS |