From bcbefcd6457adac9d92a410b1f7250ed5b0e8955 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 15 Oct 2019 16:37:52 -0700 Subject: QCborValue: Extend the constructor to also create extended types We already did that when parsing from CBOR binary data, so the code was already present. [ChangeLog][QtCore][QCborValue] The constructor taking a CBOR tag and a value to be tagged now attempts to convert to a QCborValue extended type. For example, if the tag is 0 (UnixTime_t) and the payload is a number, the resulting object will become tag 1 (DateTime) and the payload will be the the ISO-8601 date/time string. Fixes: QTBUG-79196 Change-Id: I6edce5101800424a8093fffd15cdf650fb2fc45c Reviewed-by: Ulf Hermann --- src/corelib/serialization/qcborvalue.cpp | 157 ++++++++++++++++--------------- 1 file changed, 83 insertions(+), 74 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 0e3d317518..4052bfa22e 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -758,6 +758,81 @@ QT_BEGIN_NAMESPACE using namespace QtCbor; +static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d) +{ + qint64 tag = d->elements.at(0).value; + auto &e = d->elements[1]; + const ByteData *b = d->byteData(e); + + auto replaceByteData = [&](const char *buf, qsizetype len, Element::ValueFlags f) { + d->data.clear(); + d->usedData = 0; + e.flags = Element::HasByteData | f; + e.value = d->addByteData(buf, len); + }; + + switch (tag) { + case qint64(QCborKnownTags::DateTimeString): + case qint64(QCborKnownTags::UnixTime_t): { + QDateTime dt; + if (tag == qint64(QCborKnownTags::DateTimeString) && b && + e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) { + // The data is supposed to be US-ASCII. If it isn't (contains UTF-8), + // QDateTime::fromString will fail anyway. + dt = QDateTime::fromString(b->asLatin1(), Qt::ISODateWithMs); + } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Integer) { + dt = QDateTime::fromSecsSinceEpoch(e.value, Qt::UTC); + } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Double) { + dt = QDateTime::fromMSecsSinceEpoch(qint64(e.fpvalue() * 1000), Qt::UTC); + } + if (dt.isValid()) { + QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1(); + replaceByteData(text, text.size(), Element::StringIsAscii); + e.type = QCborValue::String; + d->elements[0].value = qint64(QCborKnownTags::DateTimeString); + return QCborValue::DateTime; + } + break; + } + + case qint64(QCborKnownTags::Url): + if (e.type == QCborValue::String) { + if (b) { + // normalize to a short (decoded) form, so as to save space + QUrl url(e.flags & Element::StringIsUtf16 ? + b->asQStringRaw() : + b->toUtf8String()); + QByteArray encoded = url.toString(QUrl::DecodeReserved).toUtf8(); + replaceByteData(encoded, encoded.size(), {}); + } + return QCborValue::Url; + } + break; + + case quint64(QCborKnownTags::RegularExpression): + if (e.type == QCborValue::String) { + // no normalization is necessary + return QCborValue::RegularExpression; + } + break; + + case qint64(QCborKnownTags::Uuid): + if (e.type == QCborValue::ByteArray) { + // force the size to 16 + char buf[sizeof(QUuid)] = {}; + if (b) + memcpy(buf, b->byte(), qMin(sizeof(buf), size_t(b->len))); + replaceByteData(buf, sizeof(buf), {}); + + return QCborValue::Uuid; + } + break; + } + + // no enriching happened + return QCborValue::Tag; +} + // in qcborstream.cpp extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error); @@ -1384,77 +1459,10 @@ static QCborValue taggedValueFromCbor(QCborStreamReader &reader) d->decodeValueFromCbor(reader); } - QCborValue::Type type = QCborValue::Tag; + QCborValue::Type type; if (reader.lastError() == QCborError::NoError) { // post-process to create our extended types - qint64 tag = d->elements.at(0).value; - auto &e = d->elements[1]; - const ByteData *b = d->byteData(e); - - auto replaceByteData = [&](const char *buf, qsizetype len, Element::ValueFlags f) { - d->data.clear(); - d->usedData = 0; - e.flags = Element::HasByteData | f; - e.value = d->addByteData(buf, len); - }; - - switch (tag) { - case qint64(QCborKnownTags::DateTimeString): - case qint64(QCborKnownTags::UnixTime_t): { - QDateTime dt; - if (tag == qint64(QCborKnownTags::DateTimeString) && b && - e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) { - // The data is supposed to be US-ASCII. If it isn't, - // QDateTime::fromString will fail anyway. - dt = QDateTime::fromString(b->asLatin1(), Qt::ISODateWithMs); - } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Integer) { - dt = QDateTime::fromSecsSinceEpoch(e.value, Qt::UTC); - } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Double) { - dt = QDateTime::fromMSecsSinceEpoch(qint64(e.fpvalue() * 1000), Qt::UTC); - } - if (dt.isValid()) { - QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1(); - replaceByteData(text, text.size(), Element::StringIsAscii); - e.type = QCborValue::String; - d->elements[0].value = qint64(QCborKnownTags::DateTimeString); - type = QCborValue::DateTime; - } - break; - } - - case qint64(QCborKnownTags::Url): - if (e.type == QCborValue::String) { - if (b) { - // normalize to a short (decoded) form, so as to save space - QUrl url(e.flags & Element::StringIsUtf16 ? - b->asQStringRaw() : - b->toUtf8String()); - QByteArray encoded = url.toString(QUrl::DecodeReserved).toUtf8(); - replaceByteData(encoded, encoded.size(), {}); - } - type = QCborValue::Url; - } - break; - - case quint64(QCborKnownTags::RegularExpression): - if (e.type == QCborValue::String) { - // no normalization is necessary - type = QCborValue::RegularExpression; - } - break; - - case qint64(QCborKnownTags::Uuid): - if (e.type == QCborValue::ByteArray) { - // force the size to 16 - char buf[sizeof(QUuid)] = {}; - if (b) - memcpy(buf, b->byte(), qMin(sizeof(buf), size_t(b->len))); - replaceByteData(buf, sizeof(buf), {}); - - type = QCborValue::Uuid; - } - break; - } + type = convertToExtendedType(d); } else { // decoding error type = QCborValue::Invalid; @@ -1717,21 +1725,22 @@ QCborValue::QCborValue(const QCborMap &m) } /*! - \fn QCborValue::QCborValue(QCborTag t, const QCborValue &tv) - \fn QCborValue::QCborValue(QCborKnownTags t, const QCborValue &tv) + \fn QCborValue::QCborValue(QCborTag tag, const QCborValue &tv) + \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &tv) Creates a QCborValue for the extended type represented by the tag value \a - t, tagging value \a tv. The tag can later be retrieved using tag() and + tag, tagging value \a tv. The tag can later be retrieved using tag() and the tagged value using taggedValue(). \sa isTag(), tag(), taggedValue(), QCborKnownTags */ -QCborValue::QCborValue(QCborTag t, const QCborValue &tv) +QCborValue::QCborValue(QCborTag tag, const QCborValue &tv) : n(-1), container(new QCborContainerPrivate), t(Tag) { container->ref.storeRelaxed(1); - container->append(t); + container->append(tag); container->append(tv); + t = convertToExtendedType(container); } /*! -- cgit v1.2.3