From fcb0f68e77bb69544f0ae310baffd3ceff8a9e5d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 25 Jan 2018 15:25:35 -0800 Subject: CBOR: Complete the conversions between CBOR, JSON and Qt meta types Change-Id: I56b444f9d6274221a3b7fffd150d3130db6ef1a0 Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/corelib/kernel/qvariant.cpp | 343 ++++++++++++++++++++++++++++++- src/corelib/serialization/qjsoncbor.cpp | 11 +- src/corelib/serialization/qjsonvalue.cpp | 30 +++ 3 files changed, 376 insertions(+), 8 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 827f3cbf48..c2faca4220 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -170,6 +170,8 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d) #ifndef QT_BOOTSTRAPPED case QMetaType::QJsonValue: return v_cast(d)->toDouble(); + case QMetaType::QCborValue: + return v_cast(d)->toInteger(); #endif } Q_ASSERT(false); @@ -208,6 +210,10 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok) case QVariant::Bool: return qlonglong(d->data.b); #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + if (!v_cast(d)->isInteger() && !v_cast(d)->isDouble()) + break; + return qMetaTypeNumber(d); case QMetaType::QJsonValue: if (!v_cast(d)->isDouble()) break; @@ -232,7 +238,7 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok) } QMetaType typeInfo(d->type); - if (typeInfo.flags() & QMetaType::IsEnumeration) { + if (typeInfo.flags() & QMetaType::IsEnumeration || d->type == QMetaType::QCborSimpleType) { switch (typeInfo.sizeOf()) { case 1: return d->is_shared ? *reinterpret_cast(d->data.shared->ptr) : d->data.sc; @@ -264,6 +270,8 @@ static qreal qConvertToRealNumber(const QVariant::Private *d, bool *ok) case QMetaType::ULong: return qreal(qMetaTypeUNumber(d)); #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + return v_cast(d)->toDouble(); case QMetaType::QJsonValue: return v_cast(d)->toDouble(); #endif @@ -287,6 +295,12 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok) case QVariant::Bool: return qulonglong(d->data.b); #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + if (v_cast(d)->isDouble()) + return qulonglong(qConvertToRealNumber(d, ok)); + if (!v_cast(d)->isInteger()) + return false; + return qulonglong(qMetaTypeNumber(d)); case QMetaType::QJsonValue: if (!v_cast(d)->isDouble()) break; @@ -394,6 +408,12 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) case QVariant::String: *static_cast(result) = QUrl(*v_cast(d)); break; + case QMetaType::QCborValue: + if (v_cast(d)->isUrl()) { + *static_cast(result) = v_cast(d)->toUrl(); + break; + } + return false; default: return false; } @@ -479,6 +499,11 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) else if (!v_cast(d)->isNull()) return false; break; + case QMetaType::QCborValue: + if (v_cast(d)->isContainer() || v_cast(d)->isTag()) + return false; + *str = v_cast(d)->toVariant().toString(); + break; #endif case QVariant::Uuid: *str = v_cast(d)->toString(); @@ -624,6 +649,14 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) case QVariant::String: *dt = QDateTime::fromString(*v_cast(d), Qt::ISODate); break; +# ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + if (v_cast(d)->isDateTime()) + *dt = v_cast(d)->toDateTime(); + else + return false; + break; +# endif #endif case QVariant::Date: *dt = QDateTime(*v_cast(d)); @@ -671,6 +704,14 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) case QMetaType::Nullptr: *ba = QByteArray(); break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + if (v_cast(d)->isByteArray()) + *ba = v_cast(d)->toByteArray(); + else + return false; + break; +#endif default: #ifndef QT_NO_QOBJECT { @@ -749,6 +790,11 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *b = qMetaTypeUNumber(d) != Q_UINT64_C(0); break; #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + *b = v_cast(d)->toBool(); + if (!v_cast(d)->isBool()) + return false; + break; case QMetaType::QJsonValue: *b = v_cast(d)->toBool(false); if (!v_cast(d)->isBool()) @@ -792,6 +838,11 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *f = double(qMetaTypeUNumber(d)); break; #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + *f = v_cast(d)->toDouble(); + if (!v_cast(d)->isDouble()) + return false; + break; case QMetaType::QJsonValue: *f = v_cast(d)->toDouble(0.0); if (!v_cast(d)->isDouble()) @@ -835,6 +886,11 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *f = float(qMetaTypeUNumber(d)); break; #ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + *f = v_cast(d)->toDouble(); + if (!v_cast(d)->isDouble()) + return false; + break; case QMetaType::QJsonValue: *f = v_cast(d)->toDouble(0.0); if (!v_cast(d)->isDouble()) @@ -859,6 +915,12 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *static_cast(result) = *static_cast *>(d->data.shared->ptr); #ifndef QT_BOOTSTRAPPED + } else if (d->type == QMetaType::QCborValue) { + if (!v_cast(d)->isArray()) + return false; + *static_cast(result) = v_cast(d)->toArray().toVariantList(); + } else if (d->type == QMetaType::QCborArray) { + *static_cast(result) = v_cast(d)->toVariantList(); } else if (d->type == QMetaType::QJsonValue) { if (!v_cast(d)->isArray()) return false; @@ -881,6 +943,12 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) for (auto it = hash->begin(); it != end; ++it) map->insertMulti(it.key(), it.value()); #ifndef QT_BOOTSTRAPPED + } else if (d->type == QMetaType::QCborValue) { + if (!v_cast(d)->isMap()) + return false; + *static_cast(result) = v_cast(d)->toMap().toVariantMap(); + } else if (d->type == QMetaType::QCborMap) { + *static_cast(result) = v_cast(d)->toVariantMap(); } else if (d->type == QMetaType::QJsonValue) { if (!v_cast(d)->isObject()) return false; @@ -903,6 +971,12 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) for (auto it = map->begin(); it != end; ++it) hash->insertMulti(it.key(), it.value()); #ifndef QT_BOOTSTRAPPED + } else if (d->type == QMetaType::QCborValue) { + if (!v_cast(d)->isMap()) + return false; + *static_cast(result) = v_cast(d)->toMap().toVariantHash(); + } else if (d->type == QMetaType::QCborMap) { + *static_cast(result) = v_cast(d)->toVariantHash(); } else if (d->type == QMetaType::QJsonValue) { if (!v_cast(d)->isObject()) return false; @@ -953,11 +1027,36 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) case QVariant::ByteArray: *static_cast(result) = QUuid(*v_cast(d)); break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QCborValue: + if (!v_cast(d)->isUuid()) + return false; + *static_cast(result) = v_cast(d)->toUuid(); + break; +#endif default: return false; } break; + case QMetaType::Nullptr: + *static_cast(result) = nullptr; + if (QMetaType::typeFlags(t) & (QMetaType::PointerToGadget | QMetaType::PointerToQObject) + || d->type == QMetaType::VoidStar) { + if (v_cast(d) == nullptr) + break; + } #ifndef QT_BOOTSTRAPPED + if (d->type == QMetaType::QCborValue && v_cast(d)->isNull()) + break; +#endif + return false; + +#ifndef QT_BOOTSTRAPPED + case QMetaType::QRegularExpression: + if (d->type != QMetaType::QCborValue || !v_cast(d)->isRegularExpression()) + return false; + *static_cast(result) = v_cast(d)->toRegularExpression(); + break; case QMetaType::QJsonValue: switch (d->type) { case QMetaType::Nullptr: @@ -1008,6 +1107,15 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *static_cast(result) = doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object()); break; } + case QMetaType::QCborValue: + *static_cast(result) = v_cast(d)->toJsonValue(); + break; + case QMetaType::QCborMap: + *static_cast(result) = v_cast(d)->toJsonObject(); + break; + case QMetaType::QCborArray: + *static_cast(result) = v_cast(d)->toJsonArray(); + break; default: *static_cast(result) = QJsonValue(QJsonValue::Undefined); return false; @@ -1031,6 +1139,14 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) return false; *static_cast(result) = v_cast(d)->array(); break; + case QMetaType::QCborValue: + if (!v_cast(d)->isArray()) + return false; + *static_cast(result) = v_cast(d)->toArray().toJsonArray(); + break; + case QMetaType::QCborArray: + *static_cast(result) = v_cast(d)->toJsonArray(); + break; default: return false; } @@ -1053,11 +1169,177 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) return false; *static_cast(result) = v_cast(d)->object(); break; + case QMetaType::QCborValue: + if (!v_cast(d)->isMap()) + return false; + *static_cast(result) = v_cast(d)->toMap().toJsonObject(); + break; + case QMetaType::QCborMap: + *static_cast(result) = v_cast(d)->toJsonObject(); + break; + default: + return false; + } + break; + case QMetaType::QCborSimpleType: + if (d->type == QMetaType::QCborValue && v_cast(d)->isSimpleType()) { + *static_cast(result) = v_cast(d)->toSimpleType(); + break; + } + return false; + case QMetaType::QCborValue: + switch (d->type) { + case QMetaType::Nullptr: + *static_cast(result) = QCborValue(QCborValue::Null); + break; + case QVariant::Bool: + *static_cast(result) = QCborValue(d->data.b); + break; + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::ULong: + case QMetaType::Long: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::UChar: + case QMetaType::Char: + case QMetaType::SChar: + case QMetaType::Short: + *static_cast(result) = QCborValue(qConvertToNumber(d, ok)); + Q_ASSERT(ok); + break; + case QMetaType::Double: + case QMetaType::Float: + *static_cast(result) = QCborValue(qConvertToRealNumber(d, ok)); + Q_ASSERT(ok); + break; + case QVariant::String: + *static_cast(result) = *v_cast(d); + break; + case QVariant::StringList: + *static_cast(result) = QCborArray::fromStringList(*v_cast(d)); + break; + case QVariant::ByteArray: + *static_cast(result) = *v_cast(d); + break; + case QVariant::Date: + *static_cast(result) = QCborValue(QDateTime(*v_cast(d))); + break; + case QVariant::DateTime: + *static_cast(result) = QCborValue(*v_cast(d)); + break; + case QVariant::Url: + *static_cast(result) = QCborValue(*v_cast(d)); + break; + case QVariant::RegularExpression: + *static_cast(result) = QCborValue(*v_cast(d)); + break; + case QVariant::Uuid: + *static_cast(result) = QCborValue(*v_cast(d)); + break; + case QVariant::List: + *static_cast(result) = QCborArray::fromVariantList(*v_cast(d)); + break; + case QVariant::Map: + *static_cast(result) = QCborMap::fromVariantMap(*v_cast(d)); + break; + case QVariant::Hash: + *static_cast(result) = QCborMap::fromVariantHash(*v_cast(d)); + break; + case QMetaType::QJsonValue: + *static_cast(result) = QCborValue::fromJsonValue(*v_cast(d)); + break; + case QMetaType::QJsonObject: + *static_cast(result) = QCborMap::fromJsonObject(*v_cast(d)); + break; + case QMetaType::QJsonArray: + *static_cast(result) = QCborArray::fromJsonArray(*v_cast(d)); + break; + case QMetaType::QJsonDocument: { + QJsonDocument doc = *v_cast(d); + if (doc.isArray()) + *static_cast(result) = QCborArray::fromJsonArray(doc.array()); + else + *static_cast(result) = QCborMap::fromJsonObject(doc.object()); + break; + } + case QMetaType::QCborSimpleType: + *static_cast(result) = *v_cast(d); + break; + case QMetaType::QCborMap: + *static_cast(result) = *v_cast(d); + break; + case QMetaType::QCborArray: + *static_cast(result) = *v_cast(d); + break; + default: + *static_cast(result) = {}; + return false; + } + break; + case QMetaType::QCborArray: + switch (d->type) { + case QVariant::StringList: + *static_cast(result) = QCborArray::fromStringList(*v_cast(d)); + break; + case QVariant::List: + *static_cast(result) = QCborArray::fromVariantList(*v_cast(d)); + break; + case QMetaType::QCborValue: + if (!v_cast(d)->isArray()) + return false; + *static_cast(result) = v_cast(d)->toArray(); + break; + case QMetaType::QJsonDocument: + if (!v_cast(d)->isArray()) + return false; + *static_cast(result) = QCborArray::fromJsonArray(v_cast(d)->array()); + break; + case QMetaType::QJsonValue: + if (!v_cast(d)->isArray()) + return false; + *static_cast(result) = QCborArray::fromJsonArray(v_cast(d)->toArray()); + break; + case QMetaType::QJsonArray: + *static_cast(result) = QCborArray::fromJsonArray(*v_cast(d)); + break; + default: + return false; + } + break; + case QMetaType::QCborMap: + switch (d->type) { + case QVariant::Map: + *static_cast(result) = QCborMap::fromVariantMap(*v_cast(d)); + break; + case QVariant::Hash: + *static_cast(result) = QCborMap::fromVariantHash(*v_cast(d)); + break; + case QMetaType::QCborValue: + if (!v_cast(d)->isMap()) + return false; + *static_cast(result) = v_cast(d)->toMap(); + break; + case QMetaType::QJsonDocument: + if (v_cast(d)->isArray()) + return false; + *static_cast(result) = QCborMap::fromJsonObject(v_cast(d)->object()); + break; + case QMetaType::QJsonValue: + if (!v_cast(d)->isObject()) + return false; + *static_cast(result) = QCborMap::fromJsonObject(v_cast(d)->toObject()); + break; + case QMetaType::QJsonObject: + *static_cast(result) = QCborMap::fromJsonObject(*v_cast(d)); + break; default: return false; } break; #endif + default: #ifndef QT_NO_QOBJECT if (d->type == QVariant::String || d->type == QVariant::ByteArray) { @@ -1084,7 +1366,7 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) } } #endif - if (QMetaType::typeFlags(t) & QMetaType::IsEnumeration) { + if (QMetaType::typeFlags(t) & QMetaType::IsEnumeration || d->type == QMetaType::QCborSimpleType) { qlonglong value = qConvertToNumber(d, ok); if (*ok) { switch (QMetaType::sizeOf(t)) { @@ -3282,15 +3564,66 @@ bool QVariant::canConvert(int targetTypeId) const case QMetaType::QVariantList: case QMetaType::QVariantMap: case QMetaType::QVariantHash: + case QMetaType::QCborValue: + case QMetaType::QCborArray: + case QMetaType::QCborMap: return true; default: return false; } } if (currentType == QMetaType::QJsonArray) - return targetTypeId == QMetaType::QVariantList; + return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue + || targetTypeId == QMetaType::QCborArray; if (currentType == QMetaType::QJsonObject) - return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash; + return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash + || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QCborMap; + + if (currentType == QMetaType::QCborValue || targetTypeId == QMetaType::QCborValue) { + switch (currentType == QMetaType::QCborValue ? targetTypeId : currentType) { + case QMetaType::UnknownType: + case QMetaType::Nullptr: + case QMetaType::Bool: + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::Double: + case QMetaType::Float: + case QMetaType::ULong: + case QMetaType::Long: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::UChar: + case QMetaType::Char: + case QMetaType::SChar: + case QMetaType::Short: + case QMetaType::QString: + case QMetaType::QByteArray: + case QMetaType::QDateTime: + case QMetaType::QUrl: + case QMetaType::QRegularExpression: + case QMetaType::QUuid: + case QMetaType::QVariantList: + case QMetaType::QVariantMap: + case QMetaType::QVariantHash: + case QMetaType::QJsonValue: + case QMetaType::QJsonArray: + case QMetaType::QJsonObject: + case QMetaType::QJsonDocument: + case QMetaType::QCborArray: + case QMetaType::QCborMap: + case QMetaType::QCborSimpleType: + return true; + default: + return false; + } + } + if (currentType == QMetaType::QCborArray) + return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue + || targetTypeId == QMetaType::QJsonArray; + if (currentType == QMetaType::QCborMap) + return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash + || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QJsonObject; // FIXME It should be LastCoreType intead of Uuid if (currentType > int(QMetaType::QUuid) || targetTypeId > int(QMetaType::QUuid)) { @@ -3390,7 +3723,7 @@ bool QVariant::convert(int targetTypeId) create(targetTypeId, 0); // Fail if the value is not initialized or was forced null by a previous failed convert. - if (oldValue.d.is_null) + if (oldValue.d.is_null && oldValue.d.type != QMetaType::Nullptr) return false; if ((QMetaType::typeFlags(oldValue.userType()) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) { diff --git a/src/corelib/serialization/qjsoncbor.cpp b/src/corelib/serialization/qjsoncbor.cpp index ef6acbcbf0..46d2555554 100644 --- a/src/corelib/serialization/qjsoncbor.cpp +++ b/src/corelib/serialization/qjsoncbor.cpp @@ -728,14 +728,19 @@ QCborValue QCborValue::fromVariant(const QVariant &variant) return QCborArray::fromJsonArray(doc.array()); return QCborMap::fromJsonObject(doc.object()); } + case QMetaType::QCborValue: + return variant.value(); + case QMetaType::QCborArray: + return variant.value(); + case QMetaType::QCborMap: + return variant.value(); + case QMetaType::QCborSimpleType: + return variant.value(); #endif default: break; } - if (variant.userType() == qMetaTypeId()) - return variant.value(); - if (variant.isNull()) return QCborValue(nullptr); diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp index b8051d6228..3c5b0a0e02 100644 --- a/src/corelib/serialization/qjsonvalue.cpp +++ b/src/corelib/serialization/qjsonvalue.cpp @@ -46,6 +46,11 @@ #include #include +#ifndef QT_BOOTSTRAPPED +# include +# include +#endif + #include "qjson_p.h" QT_BEGIN_NAMESPACE @@ -423,6 +428,25 @@ QJsonValue &QJsonValue::operator =(const QJsonValue &other) \li QMetaType::QUuid \endlist \li QJsonValue::String. Since Qt 5.11, the resulting string will not include braces + \row + \li + \list + \li QMetaType::QCborValue + \endlist + \li Whichever type QCborValue::toJsonValue() returns. + \row + \li + \list + \li QMetaType::QCborArray + \endlist + \li QJsonValue::Array. See QCborValue::toJsonValue() for conversion restrictions. + \row + \li + \list + \li QMetaType::QCborMap + \endlist + \li QJsonValue::Map. See QCborValue::toJsonValue() for conversion restrictions and the + "stringification" of map keys. \endtable For all other QVariant types a conversion to a QString will be attempted. If the returned string @@ -469,6 +493,12 @@ QJsonValue QJsonValue::fromVariant(const QVariant &variant) QJsonDocument doc = variant.toJsonDocument(); return doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object()); } + case QMetaType::QCborValue: + return variant.value().toJsonValue(); + case QMetaType::QCborArray: + return variant.value().toJsonArray(); + case QMetaType::QCborMap: + return variant.value().toJsonObject(); #endif default: break; -- cgit v1.2.3