summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/serialization/qcborarray.h1
-rw-r--r--src/corelib/serialization/qcbormap.h1
-rw-r--r--src/corelib/serialization/qcborvalue_p.h7
-rw-r--r--src/corelib/serialization/qjsoncbor.cpp211
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp7
-rw-r--r--tests/auto/corelib/serialization/json/tst_qtjson.cpp12
6 files changed, 139 insertions, 100 deletions
diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h
index ac4897a39a..0724694f2b 100644
--- a/src/corelib/serialization/qcborarray.h
+++ b/src/corelib/serialization/qcborarray.h
@@ -276,6 +276,7 @@ private:
friend QCborValue;
friend QCborValueRef;
friend class QJsonPrivate::Variant;
+ friend class QCborContainerPrivate;
explicit QCborArray(QCborContainerPrivate &dd) noexcept;
QExplicitlySharedDataPointer<QCborContainerPrivate> d;
};
diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h
index d27ca45e5f..6f89b836dd 100644
--- a/src/corelib/serialization/qcbormap.h
+++ b/src/corelib/serialization/qcbormap.h
@@ -330,6 +330,7 @@ private:
friend class QCborValue;
friend class QCborValueRef;
friend class QJsonPrivate::Variant;
+ friend class QCborContainerPrivate;
void detach(qsizetype reserve = 0);
explicit QCborMap(QCborContainerPrivate &dd) noexcept;
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index 041a20e746..66d5799290 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -128,6 +128,7 @@ class QCborContainerPrivate : public QSharedData
public:
enum ContainerDisposition { CopyContainer, MoveContainer };
+ enum class ConversionMode { FromRaw, FromVariantToJson };
QByteArray::size_type usedData = 0;
QByteArray data;
@@ -139,6 +140,12 @@ public:
static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
+ static QCborMap fromVariantMap(const QVariantMap &map,
+ ConversionMode mode = ConversionMode::FromRaw);
+
+ static QCborArray fromVariantList(const QVariantList &list,
+ ConversionMode mode = ConversionMode::FromRaw);
+
qptrdiff addByteData(const char *block, qsizetype len)
{
// This function does not do overflow checking, since the len parameter
diff --git a/src/corelib/serialization/qjsoncbor.cpp b/src/corelib/serialization/qjsoncbor.cpp
index 2ae02cd239..285ae6a8ec 100644
--- a/src/corelib/serialization/qjsoncbor.cpp
+++ b/src/corelib/serialization/qjsoncbor.cpp
@@ -54,8 +54,7 @@
QT_BEGIN_NAMESPACE
using namespace QtCbor;
-
-enum class ConversionMode { FromRaw, FromVariantToJson };
+using ConversionMode = QCborContainerPrivate::ConversionMode;
static QJsonValue fpToJson(double v)
{
@@ -450,7 +449,8 @@ QJsonArray QCborArray::toJsonArray() const
QJsonArray QJsonPrivate::Variant::toJsonArray(const QVariantList &list)
{
- const auto cborArray = QCborArray::fromVariantList(list);
+ const auto cborArray =
+ QCborContainerPrivate::fromVariantList(list, ConversionMode::FromVariantToJson);
return convertToJsonArray(cborArray.d.data(), ConversionMode::FromVariantToJson);
}
@@ -498,7 +498,8 @@ QJsonObject QCborMap::toJsonObject() const
QJsonObject QJsonPrivate::Variant::toJsonObject(const QVariantMap &map)
{
- const auto cborMap = QCborMap::fromVariantMap(map);
+ const auto cborMap =
+ QCborContainerPrivate::fromVariantMap(map, ConversionMode::FromVariantToJson);
return convertToJsonObject(cborMap.d.data(), ConversionMode::FromVariantToJson);
}
@@ -661,77 +662,8 @@ QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
return QCborValue();
}
-static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
-{
- // Handle strings and byte arrays directly, to avoid creating a temporary
- // dummy container to hold their data.
- int type = variant.userType();
- if (type == QMetaType::QString) {
- d->append(variant.toString());
- } else if (type == QMetaType::QByteArray) {
- QByteArray ba = variant.toByteArray();
- d->appendByteData(ba.constData(), ba.size(), QCborValue::ByteArray);
- } else {
- // For everything else, use the function below.
- d->append(QCborValue::fromVariant(variant));
- }
-}
-
-/*!
- Converts the QVariant \a variant into QCborValue and returns it.
-
- QVariants may contain a large list of different meta types, many of which
- have no corresponding representation in CBOR. That includes all
- user-defined meta types. When preparing transmission using CBOR, it is
- suggested to encode carefully each value to prevent loss of representation.
-
- The following table lists the conversion this function will apply:
-
- \table
- \header \li Qt (C++) type \li CBOR type
- \row \li invalid (QVariant()) \li Undefined
- \row \li \c bool \li Bool
- \row \li \c std::nullptr_t \li Null
- \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
- \row \li \l quint64 \li Integer, but they are cast to \c qint64 first so
- values higher than 2\sup{63}-1 (\c INT64_MAX) will
- be wrapped to negative
- \row \li \c float, \c double \li Double
- \row \li \l QByteArray \li ByteArray
- \row \li \l QDateTime \li DateTime
- \row \li \l QCborSimpleType \li Simple type
- \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
- \row \li \l QJsonDocument \li Array or Map
- \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
- \row \li \l QJsonValue \li converted using fromJsonValue()
- \row \li \l QRegularExpression \li RegularExpression
- \row \li \l QString \li String
- \row \li \l QStringList \li Array
- \row \li \l QVariantHash \li Map
- \row \li \l QVariantList \li Array
- \row \li \l QVariantMap \li Map
- \row \li \l QUrl \li Url
- \row \li \l QUuid \li Uuid
- \endtable
-
- If QVariant::isNull() returns true, a null QCborValue is returned or
- inserted into the list or object, regardless of the type carried by
- QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
- also affects this function.
-
- For other types not listed above, a conversion to string will be attempted,
- usually but not always by calling QVariant::toString(). If the conversion
- fails the value is replaced by an Undefined CBOR value. Note that
- QVariant::toString() is also lossy for the majority of types.
-
- Please note that the conversions via QVariant::toString() are subject to
- change at any time. Both QVariant and QCborValue may be extended in the
- future to support more types, which will result in a change in how this
- function performs conversions.
-
- \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap(), QJsonValue::fromVariant()
- */
-QCborValue QCborValue::fromVariant(const QVariant &variant)
+static QCborValue fromVariantImpl(const QVariant &variant,
+ ConversionMode mode = ConversionMode::FromRaw)
{
switch (variant.userType()) {
case QMetaType::UnknownType:
@@ -744,9 +676,12 @@ QCborValue QCborValue::fromVariant(const QVariant &variant)
case QMetaType::UShort:
case QMetaType::Int:
case QMetaType::LongLong:
- case QMetaType::ULongLong:
case QMetaType::UInt:
return variant.toLongLong();
+ case QMetaType::ULongLong:
+ if (mode != ConversionMode::FromVariantToJson )
+ return variant.toLongLong();
+ Q_FALLTHROUGH();
case QMetaType::Float:
case QMetaType::Double:
return variant.toDouble();
@@ -765,9 +700,9 @@ QCborValue QCborValue::fromVariant(const QVariant &variant)
case QMetaType::QUuid:
return QCborValue(variant.toUuid());
case QMetaType::QVariantList:
- return QCborArray::fromVariantList(variant.toList());
+ return QCborContainerPrivate::fromVariantList(variant.toList(), mode);
case QMetaType::QVariantMap:
- return QCborMap::fromVariantMap(variant.toMap());
+ return QCborContainerPrivate::fromVariantMap(variant.toMap(), mode);
case QMetaType::QVariantHash:
return QCborMap::fromVariantHash(variant.toHash());
#ifndef QT_BOOTSTRAPPED
@@ -776,7 +711,7 @@ QCborValue QCborValue::fromVariant(const QVariant &variant)
return QCborValue(variant.toRegularExpression());
#endif
case QMetaType::QJsonValue:
- return fromJsonValue(variant.toJsonValue());
+ return QCborValue::fromJsonValue(variant.toJsonValue());
case QMetaType::QJsonObject:
return QCborMap::fromJsonObject(variant.toJsonObject());
case QMetaType::QJsonArray:
@@ -809,6 +744,106 @@ QCborValue QCborValue::fromVariant(const QVariant &variant)
return string;
}
+static void appendVariant(QCborContainerPrivate *d, const QVariant &variant,
+ ConversionMode mode = ConversionMode::FromRaw)
+{
+ // Handle strings and byte arrays directly, to avoid creating a temporary
+ // dummy container to hold their data.
+ int type = variant.userType();
+ if (type == QMetaType::QString) {
+ d->append(variant.toString());
+ } else if (type == QMetaType::QByteArray) {
+ QByteArray ba = variant.toByteArray();
+ d->appendByteData(ba.constData(), ba.size(), QCborValue::ByteArray);
+ } else {
+ // For everything else, use the function below.
+ d->append(fromVariantImpl(variant, mode));
+ }
+}
+
+QCborMap QCborContainerPrivate::fromVariantMap(const QVariantMap &map, ConversionMode mode)
+{
+ QCborMap m;
+ m.detach(map.size());
+ QCborContainerPrivate *d = m.d.data();
+
+ auto it = map.begin();
+ auto end = map.end();
+ for ( ; it != end; ++it) {
+ d->append(it.key());
+ appendVariant(d, it.value(), mode);
+ }
+ return m;
+}
+
+QCborArray QCborContainerPrivate::fromVariantList(const QVariantList &list, ConversionMode mode)
+{
+ QCborArray a;
+ a.detach(list.size());
+ for (const QVariant &v : list)
+ appendVariant(a.d.data(), v, mode);
+ return a;
+}
+
+/*!
+ Converts the QVariant \a variant into QCborValue and returns it.
+
+ QVariants may contain a large list of different meta types, many of which
+ have no corresponding representation in CBOR. That includes all
+ user-defined meta types. When preparing transmission using CBOR, it is
+ suggested to encode carefully each value to prevent loss of representation.
+
+ The following table lists the conversion this function will apply:
+
+ \table
+ \header \li Qt (C++) type \li CBOR type
+ \row \li invalid (QVariant()) \li Undefined
+ \row \li \c bool \li Bool
+ \row \li \c std::nullptr_t \li Null
+ \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
+ \row \li \l quint64 \li Integer, but they are cast to \c qint64 first so
+ values higher than 2\sup{63}-1 (\c INT64_MAX) will
+ be wrapped to negative
+ \row \li \c float, \c double \li Double
+ \row \li \l QByteArray \li ByteArray
+ \row \li \l QDateTime \li DateTime
+ \row \li \l QCborSimpleType \li Simple type
+ \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
+ \row \li \l QJsonDocument \li Array or Map
+ \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
+ \row \li \l QJsonValue \li converted using fromJsonValue()
+ \row \li \l QRegularExpression \li RegularExpression
+ \row \li \l QString \li String
+ \row \li \l QStringList \li Array
+ \row \li \l QVariantHash \li Map
+ \row \li \l QVariantList \li Array
+ \row \li \l QVariantMap \li Map
+ \row \li \l QUrl \li Url
+ \row \li \l QUuid \li Uuid
+ \endtable
+
+ If QVariant::isNull() returns true, a null QCborValue is returned or
+ inserted into the list or object, regardless of the type carried by
+ QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
+ also affects this function.
+
+ For other types not listed above, a conversion to string will be attempted,
+ usually but not always by calling QVariant::toString(). If the conversion
+ fails the value is replaced by an Undefined CBOR value. Note that
+ QVariant::toString() is also lossy for the majority of types.
+
+ Please note that the conversions via QVariant::toString() are subject to
+ change at any time. Both QVariant and QCborValue may be extended in the
+ future to support more types, which will result in a change in how this
+ function performs conversions.
+
+ \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap(), QJsonValue::fromVariant()
+ */
+QCborValue QCborValue::fromVariant(const QVariant &variant)
+{
+ return fromVariantImpl(variant);
+}
+
/*!
Recursively converts each \l QCborValue in this array using
QCborValue::toVariant() and returns the QVariantList composed of the
@@ -854,11 +889,7 @@ QCborArray QCborArray::fromStringList(const QStringList &list)
*/
QCborArray QCborArray::fromVariantList(const QVariantList &list)
{
- QCborArray a;
- a.detach(list.size());
- for (const QVariant &v : list)
- appendVariant(a.d.data(), v);
- return a;
+ return QCborContainerPrivate::fromVariantList(list);
}
/*!
@@ -939,17 +970,7 @@ QVariantHash QCborMap::toVariantHash() const
*/
QCborMap QCborMap::fromVariantMap(const QVariantMap &map)
{
- QCborMap m;
- m.detach(map.size());
- QCborContainerPrivate *d = m.d.data();
-
- auto it = map.begin();
- auto end = map.end();
- for ( ; it != end; ++it) {
- d->append(it.key());
- appendVariant(d, it.value());
- }
- return m;
+ return QCborContainerPrivate::fromVariantMap(map);
}
/*!
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index 27a2f0e227..29c29184c1 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -449,11 +449,8 @@ void QJsonValue::swap(QJsonValue &other) noexcept
also affects this function.
A floating point value that is either an infinity or NaN will be converted
- to a null JSON value. Since Qt 6.0, QJsonValue can store the full precision
- of any 64-bit signed integer without loss, but in previous versions values
- outside the range of ±2^53 may lose precision. Unsigned 64-bit values
- greater than or equal to 2^63 will either lose precision or alias to
- negative values, so QMetaType::ULongLong should be avoided.
+ to a null JSON value. The values outside the range of ±2^53 may lose precision,
+ because they are converted to a double QJsonValue.
For other types not listed above, a conversion to string will be attempted,
usually but not always by calling QVariant::toString(). If the conversion
diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
index ecbdb0ab22..a03eca7234 100644
--- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
@@ -33,6 +33,7 @@
#include "qjsonvalue.h"
#include "qjsondocument.h"
#include "qregularexpression.h"
+#include "private/qnumeric_p.h"
#include <limits>
#define INVALID_UNICODE "\xCE\xBA\xE1"
@@ -3584,6 +3585,17 @@ void tst_QtJson::fromToVariantConversions_data()
<< QVariant::fromValue(nullptr);
QTest::newRow("NaN") << QVariant(qQNaN()) << QJsonValue(QJsonValue::Null)
<< QVariant::fromValue(nullptr);
+
+ const qulonglong ulongValue = (1ul << 63) + 1;
+ const double uLongToDouble = ulongValue;
+ qint64 n;
+ if (convertDoubleTo(uLongToDouble, &n)) {
+ QTest::newRow("ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble)
+ << QVariant(n);
+ } else {
+ QTest::newRow("ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble)
+ << QVariant(uLongToDouble);
+ }
}
void tst_QtJson::fromToVariantConversions()