00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "qdbusmarshall.h"
00024 #include "qdbusvariant.h"
00025
00026 #include <QtCore/qdebug.h>
00027 #include <QtCore/qvariant.h>
00028 #include <QtCore/qlist.h>
00029 #include <QtCore/qmap.h>
00030 #include <QtCore/qstringlist.h>
00031 #include <QtCore/qvarlengtharray.h>
00032 #include <QtCore/qvector.h>
00033
00034 #include <dbus/dbus.h>
00035
00036 template <typename T>
00037 inline T qIterGet(DBusMessageIter *it)
00038 {
00039 T t;
00040 dbus_message_iter_get_basic(it, &t);
00041 return t;
00042 }
00043
00044 static QStringList qFetchStringList(DBusMessageIter *arrayIt)
00045 {
00046 QStringList list;
00047
00048 DBusMessageIter it;
00049 dbus_message_iter_recurse(arrayIt, &it);
00050
00051 do {
00052 list.append(QString::fromUtf8(qIterGet<char *>(&it)));
00053 } while (dbus_message_iter_next(&it));
00054
00055 return list;
00056 }
00057
00058 static QVariant qFetchParameter(DBusMessageIter *it)
00059 {
00060 switch (dbus_message_iter_get_arg_type(it)) {
00061 case DBUS_TYPE_BYTE:
00062 return qIterGet<unsigned char>(it);
00063 case DBUS_TYPE_INT32:
00064 return qIterGet<dbus_int32_t>(it);
00065 case DBUS_TYPE_UINT32:
00066 return qIterGet<dbus_uint32_t>(it);
00067 case DBUS_TYPE_DOUBLE:
00068 return qIterGet<double>(it);
00069 case DBUS_TYPE_BOOLEAN:
00070 return qIterGet<dbus_bool_t>(it);
00071 case DBUS_TYPE_INT64:
00072 return (qlonglong) qIterGet<dbus_int64_t>(it);
00073 case DBUS_TYPE_UINT64:
00074 return (qulonglong) qIterGet<dbus_uint64_t>(it);
00075 case DBUS_TYPE_STRING:
00076 case DBUS_TYPE_OBJECT_PATH:
00077 case DBUS_TYPE_SIGNATURE:
00078 return QString::fromUtf8(qIterGet<char *>(it));
00079 case DBUS_TYPE_ARRAY: {
00080 int arrayType = dbus_message_iter_get_element_type(it);
00081 if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH) {
00082 return qFetchStringList(it);
00083 } else if (arrayType == DBUS_TYPE_DICT_ENTRY) {
00084
00085 QMap<QString, QVariant> map;
00086 DBusMessageIter sub;
00087 dbus_message_iter_recurse(it, &sub);
00088 if (!dbus_message_iter_has_next(&sub))
00089 return map;
00090 do {
00091 DBusMessageIter itemIter;
00092 dbus_message_iter_recurse(&sub, &itemIter);
00093 Q_ASSERT(dbus_message_iter_has_next(&itemIter));
00094 QString key = qFetchParameter(&itemIter).toString();
00095 dbus_message_iter_next(&itemIter);
00096 map.insertMulti(key, qFetchParameter(&itemIter));
00097 } while (dbus_message_iter_next(&sub));
00098 return map;
00099 } else {
00100 QList<QVariant> list;
00101 DBusMessageIter sub;
00102 dbus_message_iter_recurse(it, &sub);
00103 if (!dbus_message_iter_has_next(&sub))
00104 return list;
00105 do {
00106 list.append(qFetchParameter(&sub));
00107 } while (dbus_message_iter_next(&sub));
00108 return list;
00109 }
00110 break; }
00111 case DBUS_TYPE_VARIANT: {
00112 QDBusVariant dvariant;
00113 DBusMessageIter sub;
00114 dbus_message_iter_recurse(it, &sub);
00115 dvariant.signature = QString::fromUtf8(dbus_message_iter_get_signature(&sub));
00116 dvariant.value = qFetchParameter(&sub);
00117 return qVariantFromValue(dvariant);
00118 }
00119 #if 0
00120 case DBUS_TYPE_DICT: {
00121 QMap<QString, QVariant> map;
00122 DBusMessageIter sub;
00123 dbus_message
00124 if (dbus_message_iter_init_dict_iterator(it, &dictIt)) {
00125 do {
00126 map[QString::fromUtf8(dbus_message_iter_get_dict_key(&dictIt))] =
00127 qFetchParameter(&dictIt);
00128 } while (dbus_message_iter_next(&dictIt));
00129 }
00130 return map;
00131 break; }
00132 case DBUS_TYPE_CUSTOM:
00133 return qGetCustomValue(it);
00134 break;
00135 #endif
00136 default:
00137 qWarning("Don't know how to handle type %d '%c'", dbus_message_iter_get_arg_type(it), dbus_message_iter_get_arg_type(it));
00138 return QVariant();
00139 break;
00140 }
00141 }
00142
00143 void QDBusMarshall::messageToList(QList<QVariant> &list, DBusMessage *message)
00144 {
00145 Q_ASSERT(message);
00146
00147 DBusMessageIter it;
00148 if (!dbus_message_iter_init(message, &it))
00149 return;
00150
00151 do {
00152 list.append(qFetchParameter(&it));
00153 } while (dbus_message_iter_next(&it));
00154 }
00155
00156 #define DBUS_APPEND(type,dtype,var) \
00157 type dtype##v=(var); \
00158 dbus_message_append_args(msg, dtype, &dtype##v, DBUS_TYPE_INVALID)
00159 #define DBUS_APPEND_LIST(type,dtype,var,size) \
00160 type dtype##v=(var); \
00161 dbus_message_append_args(msg, DBUS_TYPE_ARRAY, dtype, &dtype##v, size, DBUS_TYPE_INVALID)
00162
00163
00164 static void qAppendToMessage(DBusMessageIter *it, const QString &str)
00165 {
00166 QByteArray ba = str.toUtf8();
00167 const char *cdata = ba.constData();
00168 dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &cdata);
00169 }
00170
00171 static QVariant::Type qVariantListType(const QList<QVariant> &list)
00172 {
00173
00174 QVariant::Type tp = list.value(0).type();
00175 if (tp < QVariant::Int || tp > QVariant::Double)
00176 return QVariant::Invalid;
00177
00178 for (int i = 1; i < list.count(); ++i) {
00179 const QVariant &var = list.at(i);
00180 if (var.type() != tp
00181 && (var.type() != QVariant::List || qVariantListType(var.toList()) != tp))
00182 return QVariant::Invalid;
00183 }
00184 return tp;
00185 }
00186
00187 static const char *qDBusListType(const QList<QVariant> &list)
00188 {
00189 static const char *DBusArgs[] = { 0, 0, DBUS_TYPE_INT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING,
00190 DBUS_TYPE_INT64_AS_STRING, DBUS_TYPE_UINT64_AS_STRING, DBUS_TYPE_DOUBLE_AS_STRING };
00191
00192 return DBusArgs[qVariantListType(list)];
00193 }
00194
00195 static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list);
00196
00197 static void qVariantToIterator(DBusMessageIter *it, const QVariant &var)
00198 {
00199 static const int Variant2DBus[] = { DBUS_TYPE_INVALID,
00200 DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT32, DBUS_TYPE_UINT32,
00201 DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE };
00202
00203
00204 Q_ASSERT(QVariant::Invalid == 0);
00205 Q_ASSERT(QVariant::Int == 2);
00206 Q_ASSERT(QVariant::Double == 6);
00207
00208 switch (var.type()) {
00209 case QVariant::Int:
00210 case QVariant::UInt:
00211 case QVariant::LongLong:
00212 case QVariant::ULongLong:
00213 case QVariant::Double:
00214 dbus_message_iter_append_basic(it, Variant2DBus[var.type()],
00215 var.constData());
00216 break;
00217 case QVariant::String:
00218 qAppendToMessage(it, var.toString());
00219 break;
00220 case QVariant::StringList: {
00221 const QStringList list = var.toStringList();
00222 DBusMessageIter sub;
00223 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
00224 DBUS_TYPE_STRING_AS_STRING, &sub);
00225 for (int s = 0; s < list.count(); ++s)
00226 qAppendToMessage(&sub, list.at(s));
00227 dbus_message_iter_close_container(it, &sub);
00228 break;
00229 }
00230 case QVariant::List: {
00231 const QList<QVariant> &list = var.toList();
00232 const char *listType = qDBusListType(list);
00233 if (!listType) {
00234 qWarning("Don't know how to marshall list.");
00235 break;
00236 }
00237 DBusMessageIter sub;
00238 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, listType, &sub);
00239 qListToIterator(&sub, list);
00240 dbus_message_iter_close_container(it, &sub);
00241 break;
00242 }
00243 case QVariant::Map: {
00244
00245 const QMap<QString, QVariant> &map = var.toMap();
00246 DBusMessageIter sub;
00247 QVarLengthArray<char, 16> sig;
00248 sig.append(DBUS_DICT_ENTRY_BEGIN_CHAR);
00249 sig.append(DBUS_TYPE_STRING);
00250 sig.append(DBUS_TYPE_STRING);
00251 sig.append(DBUS_DICT_ENTRY_END_CHAR);
00252 sig.append('\0');
00253 qDebug() << QString::fromAscii(sig.constData());
00254 dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.constData(), &sub);
00255 for (QMap<QString, QVariant>::const_iterator mit = map.constBegin();
00256 mit != map.constEnd(); ++mit) {
00257 DBusMessageIter itemIterator;
00258 dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, 0, &itemIterator);
00259 qAppendToMessage(&itemIterator, mit.key());
00260 qAppendToMessage(&itemIterator, mit.value().toString());
00261 dbus_message_iter_close_container(&sub, &itemIterator);
00262 }
00263 dbus_message_iter_close_container(it, &sub);
00264 break;
00265 }
00266 case QVariant::UserType: {
00267 if (var.userType() == QMetaTypeId<QDBusVariant>::qt_metatype_id()) {
00268 DBusMessageIter sub;
00269 QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
00270 dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT,
00271 dvariant.signature.toUtf8().constData(), &sub);
00272 qVariantToIterator(&sub, dvariant.value);
00273 dbus_message_iter_close_container(it, &sub);
00274 break;
00275 }
00276 }
00277
00278 default:
00279 qWarning("Don't know how to handle type %s", var.typeName());
00280 break;
00281 }
00282 }
00283
00284 void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
00285 {
00286 if (list.isEmpty())
00287 return;
00288
00289 for (int i = 0; i < list.count(); ++i)
00290 qVariantToIterator(it, list.at(i));
00291 }
00292
00293 void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg)
00294 {
00295 Q_ASSERT(msg);
00296 DBusMessageIter it;
00297 dbus_message_iter_init_append(msg, &it);
00298 qListToIterator(&it, list);
00299 }
00300