Skip to content

Commit 362f1b4

Browse files
QCborValue: make QDateTime constructor consistent with fromCbor
The QCborValue(const QDateTime &) constructor unconditionally set the type to QCborValue::DateTime. For a null QDateTime, toString() yields an empty string, so the value was encoded as tag 0 wrapping an empty text string, 0(""). An empty string is not a valid date/time. RFC 3339's ABNF requires both a date and a time: iso-date-time = date "T" time and QDateTime::fromString() agrees by returning an invalid QDateTime. If we tried decoding that with fromCbor(), it would correctly fail, leaving type() to Tag and breaking equality over toCbor()/fromCbor() round-trip (though the tagged values still compared equal). Rather than keep two notions of what a DateTime is, let's add a central function to set it. A valid QDateTime is promoted to DateTime as before; a null one stays a plain Tag(0, ""), matching what fromCbor() produces. Fixes: QTBUG-149559 Pick-to: 6.12 6.11 6.8 Change-Id: I3502380cd23dbc867fdefffda35f95940c6e0091 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
1 parent 3f2e5bc commit 362f1b4

2 files changed

Lines changed: 22 additions & 14 deletions

File tree

src/corelib/serialization/qcborvalue.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
752752
*/
753753

754754
using namespace QtCbor;
755+
static QCborValue::Type setToExtendedDateTimeType(QCborContainerPrivate *d, QStringView dtString);
755756

756757
static QCborContainerPrivate *assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
757758
{
@@ -798,15 +799,8 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
798799
if (ok)
799800
dt = QDateTime::fromMSecsSinceEpoch(msecs, QTimeZone::UTC);
800801
}
801-
if (dt.isValid()) {
802-
QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1();
803-
if (!text.isEmpty()) {
804-
replaceByteData(text, text.size(), Element::StringIsAscii);
805-
e.type = QCborValue::String;
806-
d->elements[0].value = qint64(QCborKnownTags::DateTimeString);
807-
return QCborValue::DateTime;
808-
}
809-
}
802+
if (QString dtString = dt.toString(Qt::ISODateWithMs); !dtString.isEmpty())
803+
return setToExtendedDateTimeType(d, dtString);
810804
break;
811805
}
812806
#endif
@@ -2086,6 +2080,18 @@ QCborValue::QCborValue(const QCborValue &other) noexcept
20862080
}
20872081

20882082
#if QT_CONFIG(datestring)
2083+
static QCborValue::Type setToExtendedDateTimeType(QCborContainerPrivate *d, QStringView text)
2084+
{
2085+
// when called from convertToExtendedType(), *d isn't pristine
2086+
d->data.resize(0);
2087+
d->elements.resize(0);
2088+
d->elements.reserve(2);
2089+
2090+
d->append(QCborTag(QCborKnownTags::DateTimeString));
2091+
d->appendAsciiString(text);
2092+
return text.isEmpty() ? QCborValue::Tag : QCborValue::DateTime;
2093+
}
2094+
20892095
/*!
20902096
Creates a QCborValue object of the date/time extended type and containing
20912097
the value represented by \a dt. The value can later be retrieved using
@@ -2100,11 +2106,10 @@ QCborValue::QCborValue(const QCborValue &other) noexcept
21002106
\sa toDateTime(), isDateTime(), taggedValue()
21012107
*/
21022108
QCborValue::QCborValue(const QDateTime &dt)
2103-
: QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1())
2109+
: n(-1), container(new QCborContainerPrivate),
2110+
t(setToExtendedDateTimeType(container, dt.toString(Qt::ISODateWithMs)))
21042111
{
2105-
// change types
2106-
t = DateTime;
2107-
container->elements[1].type = String;
2112+
container->ref.storeRelaxed(1);
21082113
}
21092114
#endif
21102115

tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,9 @@ static void addCommonCborData()
24172417
QTest::newRow("String:Unicode") << QCborValue(QStringLiteral(u"éś α €"))
24182418
<< raw("\x6b\xc3\xa9\xc5\x9b \xce\xb1 \xe2\x82\xac") << noxfrm;
24192419

2420+
QTest::newRow("DateTime:Empty") << QCborValue(QDateTime())
2421+
<< raw("\xc0\x60")
2422+
<< noxfrm;
24202423
QTest::newRow("DateTime") << QCborValue(dt) // this is UTC
24212424
<< "\xc0\x78\x18" + dt.toString(Qt::ISODateWithMs).toLatin1()
24222425
<< noxfrm;
@@ -2771,7 +2774,7 @@ void tst_QCborValue::extendedTypeValidation_data()
27712774
QTest::addColumn<QCborValue>("expected");
27722775

27732776
// QDateTime currently stores time in milliseconds, so make sure
2774-
// we don't overflow
2777+
// we don't overflow and therefore keep the QCborValue as UnixTime_t.
27752778
{
27762779
quint64 limit = std::numeric_limits<quint64>::max() / 1000;
27772780
QTest::newRow("UnixTime_t:integer-overflow-positive")

0 commit comments

Comments
 (0)