Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qcborvalue.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcborvalue.h"
5#include "qcborvalue_p.h"
6#include "qdatastream.h"
7#include "qcborarray.h"
8#include "qcbormap.h"
9
10#if QT_CONFIG(cborstreamreader)
11#include "qcborstreamreader.h"
12#endif
13
14#if QT_CONFIG(cborstreamwriter)
15#include "qcborstreamwriter.h"
16#endif
17
18#include <qendian.h>
19#include <qlocale.h>
20#include <qdatetime.h>
21#include <qtimezone.h>
22#include <private/qbytearray_p.h>
23#include <private/qnumeric_p.h>
24#include <private/qsimd_p.h>
25
26#include <new>
27
29
30// Worst case memory allocation for a corrupt stream: 256 MB for 32-bit, 1 GB for 64-bit
31static constexpr quint64 MaxAcceptableMemoryUse = (sizeof(void*) == 4 ? 256 : 1024) * 1024 * 1024;
32
33// Internal limits to ensure we don't blow up the memory when parsing a corrupt
34// (possibly crafted to exploit) CBOR stream. The recursion impacts both the
35// maps/arrays we'll open when parsing and the thread's stack, as the parser is
36// itself recursive. If someone really needs more than 1024 layers of nesting,
37// they probably have a weird use-case for which custom parsing and
38// serialisation code would make sense. The limit on element count is the
39// preallocated limit: if the stream does actually have more elements, we will
40// grow the container.
41Q_DECL_UNUSED static constexpr int MaximumRecursionDepth = 1024;
44
750using namespace QtCbor;
751
753{
754 if (d == x)
755 return d;
756 if (d)
757 d->deref();
758 if (x)
759 x->ref.ref();
760 return d = x;
761}
762
764{
765 qint64 tag = d->elements.at(0).value;
766 auto &e = d->elements[1];
767 const ByteData *b = d->byteData(e);
768
769 auto replaceByteData = [&](const char *buf, qsizetype len, Element::ValueFlags f) {
770 d->data.clear();
771 d->usedData = 0;
772 e.flags = Element::HasByteData | f;
773 e.value = d->addByteData(buf, len);
774 };
775
776 switch (tag) {
779 QDateTime dt;
781 e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) {
782 // The data is supposed to be US-ASCII. If it isn't (contains UTF-8),
783 // QDateTime::fromString will fail anyway.
784 dt = QDateTime::fromString(b->asLatin1(), Qt::ISODateWithMs);
785 } else if (tag == qint64(QCborKnownTags::UnixTime_t)) {
786 qint64 msecs;
787 bool ok = false;
788 if (e.type == QCborValue::Integer) {
789#if QT_POINTER_SIZE == 8
790 // we don't have a fast 64-bit qMulOverflow implementation on
791 // 32-bit architectures.
792 ok = !qMulOverflow(e.value, qint64(1000), &msecs);
793#else
794 static const qint64 Limit = std::numeric_limits<qint64>::max() / 1000;
795 ok = (e.value > -Limit && e.value < Limit);
796 if (ok)
797 msecs = e.value * 1000;
798#endif
799 } else if (e.type == QCborValue::Double) {
800 ok = convertDoubleTo(round(e.fpvalue() * 1000), &msecs);
801 }
802 if (ok)
804 }
805 if (dt.isValid()) {
806 QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1();
807 if (!text.isEmpty()) {
808 replaceByteData(text, text.size(), Element::StringIsAscii);
809 e.type = QCborValue::String;
810 d->elements[0].value = qint64(QCborKnownTags::DateTimeString);
812 }
813 }
814 break;
815 }
816
817#ifndef QT_BOOTSTRAPPED
819 if (e.type == QCborValue::String) {
820 if (b) {
821 // normalize to a short (decoded) form, so as to save space
823 b->asQStringRaw() :
824 b->toUtf8String(), QUrl::StrictMode);
825 if (url.isValid()) {
827 replaceByteData(encoded, encoded.size(), {});
828 }
829 }
830 return QCborValue::Url;
831 }
832 break;
833#endif // QT_BOOTSTRAPPED
834
835#if QT_CONFIG(regularexpression)
837 if (e.type == QCborValue::String) {
838 // no normalization is necessary
840 }
841 break;
842#endif // QT_CONFIG(regularexpression)
843
845 if (e.type == QCborValue::ByteArray) {
846 // force the size to 16
847 char buf[sizeof(QUuid)] = {};
848 if (b)
849 memcpy(buf, b->byte(), qMin(sizeof(buf), size_t(b->len)));
850 replaceByteData(buf, sizeof(buf), {});
851
852 return QCborValue::Uuid;
853 }
854 break;
855 }
856
857 // no enriching happened
858 return QCborValue::Tag;
859}
860
861#if QT_CONFIG(cborstreamwriter)
862static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
863{
864 if (qt_is_nan(d)) {
866#ifndef QT_BOOTSTRAPPED
868 return writer.append(std::numeric_limits<qfloat16>::quiet_NaN());
869#endif
870 return writer.append(std::numeric_limits<float>::quiet_NaN());
871 }
872 return writer.append(qt_qnan());
873 }
874
875 if (qt_is_inf(d)) {
876 d = d > 0 ? qt_inf() : -qt_inf();
877 } else if (opt & QCborValue::UseIntegers) {
878 quint64 i;
879 if (convertDoubleTo(d, &i)) {
880 if (d < 0)
881 return writer.append(QCborNegativeInteger(i));
882 return writer.append(i);
883 }
884 }
885
887 float f = float(d);
888 if (f == d) {
889 // no data loss, we could use float
890#ifndef QT_BOOTSTRAPPED
892 qfloat16 f16 = qfloat16(f);
893 if (f16 == f)
894 return writer.append(f16);
895 }
896#endif
897
898 return writer.append(f);
899 }
900 }
901
902 writer.append(d);
903}
904#endif // QT_CONFIG(cborstreamwriter)
905
906static inline int typeOrder(Element e1, Element e2)
907{
908 auto comparable = [](Element e) {
909 if (e.type >= 0x10000) // see QCborValue::isTag_helper()
910 return QCborValue::Tag;
911 return e.type;
912 };
913 return comparable(e1) - comparable(e2);
914}
915
916QCborContainerPrivate::~QCborContainerPrivate()
917{
918 // delete our elements
919 for (Element &e : elements) {
920 if (e.flags & Element::IsContainer)
921 e.container->deref();
922 }
923}
924
926{
927 if (usedData > data.size() / 2)
928 return;
929
930 // 50% savings if we recreate the byte data
931 // ### TBD
932 Q_UNUSED(reserved);
933}
934
936{
937 if (!d) {
939 } else {
940 // in case QList::reserve throws
942 if (reserved >= 0) {
943 u->elements.reserve(reserved);
944 u->compact(reserved);
945 }
946
947 d = u.take();
948 d->ref.storeRelaxed(0);
949
950 for (auto &e : std::as_const(d->elements)) {
951 if (e.flags & Element::IsContainer)
952 e.container->ref.ref();
953 }
954 }
955 return d;
956}
957
959{
960 if (!d || d->ref.loadRelaxed() != 1)
961 return clone(d, reserved);
962 return d;
963}
964
972{
973 Q_ASSERT(index >= 0);
974 d = detach(d, index + 1);
975 Q_ASSERT(d);
976 qsizetype j = d->elements.size();
977 while (j++ < index)
978 d->append(Undefined());
979 return d;
980}
981
982// Copies or moves \a value into element at position \a e. If \a disp is
983// CopyContainer, then this function increases the reference count of the
984// container, but otherwise leaves it unmodified. If \a disp is MoveContainer,
985// then it transfers ownership (move semantics) and the caller must set
986// value.container back to nullptr.
988{
989 if (value.n < 0) {
990 // This QCborValue is an array, map, or tagged value (container points
991 // to itself).
992
993 // detect self-assignment
994 if (Q_UNLIKELY(this == value.container)) {
995 Q_ASSERT(ref.loadRelaxed() >= 2);
996 if (disp == MoveContainer)
997 ref.deref(); // not deref() because it can't drop to 0
999 d->elements.detach();
1000 d->ref.storeRelaxed(1);
1001 e.container = d;
1002 } else {
1003 e.container = value.container;
1004 if (disp == CopyContainer)
1005 e.container->ref.ref();
1006 }
1007
1008 e.type = value.type();
1009 e.flags = Element::IsContainer;
1010 } else {
1011 // String data, copy contents
1012 e = value.container->elements.at(value.n);
1013
1014 // Copy string data, if any
1015 if (const ByteData *b = value.container->byteData(value.n)) {
1016 if (this == value.container)
1017 e.value = addByteData(b->toByteArray(), b->len);
1018 else
1019 e.value = addByteData(b->byte(), b->len);
1020 }
1021
1022 if (disp == MoveContainer)
1023 value.container->deref();
1024 }
1025}
1026
1027// in qstring.cpp
1028void qt_to_latin1_unchecked(uchar *dst, const char16_t *uc, qsizetype len);
1029
1031{
1032 qsizetype len = s.size();
1034 e.value = addByteData(nullptr, len);
1035 e.type = QCborValue::String;
1037 elements.append(e);
1038
1039 char *ptr = data.data() + e.value + sizeof(ByteData);
1040 uchar *l = reinterpret_cast<uchar *>(ptr);
1041 qt_to_latin1_unchecked(l, s.utf16(), len);
1042}
1043
1045{
1046 // create a new container for the returned value, containing the byte data
1047 // from this element, if it's worth it
1049 auto b = byteData(e);
1050 auto container = new QCborContainerPrivate;
1051
1052 if (b->len + qsizetype(sizeof(*b)) < data.size() / 4) {
1053 // make a shallow copy of the byte data
1054 container->appendByteData(b->byte(), b->len, e.type, e.flags);
1055 usedData -= b->len + qsizetype(sizeof(*b));
1057 } else {
1058 // just share with the original byte data
1059 container->data = data;
1060 container->elements.reserve(1);
1061 container->elements.append(e);
1062 }
1063
1064 return makeValue(e.type, 0, container);
1065}
1066
1067QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
1069static int compareElementNoData(const Element &e1, const Element &e2)
1070{
1071 Q_ASSERT(e1.type == e2.type);
1072
1073 if (e1.type == QCborValue::Integer) {
1074 // CBOR sorting order is 0, 1, 2, ..., INT64_MAX, -1, -2, -3, ... INT64_MIN
1075 // So we transform:
1076 // 0 -> 0
1077 // 1 -> 1
1078 // INT64_MAX -> INT64_MAX
1079 // -1 -> INT64_MAX + 1 = INT64_MAX - (-1)
1080 // -2 -> INT64_MAX + 2 = INT64_MAX - (-2)
1081 // INT64_MIN -> UINT64_MAX = INT64_MAX - INT64_MIN
1082 // Note how the unsigned arithmetic is well defined in C++ (it's
1083 // always performed modulo 2^64).
1084 auto makeSortable = [](qint64 v) {
1085 quint64 u = quint64(v);
1086 if (v < 0)
1087 return quint64(std::numeric_limits<qint64>::max()) + (-u);
1088 return u;
1089 };
1090 quint64 u1 = makeSortable(e1.value);
1091 quint64 u2 = makeSortable(e2.value);
1092 if (u1 < u2)
1093 return -1;
1094 if (u1 > u2)
1095 return 1;
1096 }
1097
1098 if (e1.type == QCborValue::Tag || e1.type == QCborValue::Double) {
1099 // Perform unsigned comparisons for the tag value and floating point
1100 quint64 u1 = quint64(e1.value);
1101 quint64 u2 = quint64(e2.value);
1102 if (u1 != u2)
1103 return u1 < u2 ? -1 : 1;
1104 }
1105
1106 // Any other type is equal at this point:
1107 // - simple types carry no value
1108 // - empty strings, arrays and maps
1109 return 0;
1110}
1111
1113 const QCborContainerPrivate *c2, const Element &e2)
1114{
1115 int cmp = typeOrder(e1, e2);
1116 if (cmp != 0)
1117 return cmp;
1118
1120 return compareContainer(e1.flags & Element::IsContainer ? e1.container : nullptr,
1121 e2.flags & Element::IsContainer ? e2.container : nullptr);
1122
1123 // string data?
1124 const ByteData *b1 = c1 ? c1->byteData(e1) : nullptr;
1125 const ByteData *b2 = c2 ? c2->byteData(e2) : nullptr;
1126 if (b1 || b2) {
1127 auto len1 = b1 ? b1->len : 0;
1128 auto len2 = b2 ? b2->len : 0;
1129
1131 len1 /= 2;
1133 len2 /= 2;
1134 if (len1 == 0 || len2 == 0)
1135 return len1 < len2 ? -1 : len1 == len2 ? 0 : 1;
1136
1137 // we definitely have data from this point forward
1138 Q_ASSERT(b1);
1139 Q_ASSERT(b2);
1140
1141 // Officially with CBOR, we sort first the string with the shortest
1142 // UTF-8 length. The length of an ASCII string is the same as its UTF-8
1143 // and UTF-16 ones, but the UTF-8 length of a string is bigger than the
1144 // UTF-16 equivalent. Combinations are:
1145 // 1) UTF-16 and UTF-16
1146 // 2) UTF-16 and UTF-8 <=== this is the problem case
1147 // 3) UTF-16 and US-ASCII
1148 // 4) UTF-8 and UTF-8
1149 // 5) UTF-8 and US-ASCII
1150 // 6) US-ASCII and US-ASCII
1152 // Case 1: both UTF-16, so lengths are comparable.
1153 // (we can't use memcmp in little-endian machines)
1154 if (len1 == len2)
1155 return QtPrivate::compareStrings(b1->asStringView(), b2->asStringView());
1156 return len1 < len2 ? -1 : 1;
1157 }
1158
1160 // Cases 4, 5 and 6: neither is UTF-16, so lengths are comparable too
1161 // (this case includes byte arrays too)
1162 if (len1 == len2)
1163 return memcmp(b1->byte(), b2->byte(), size_t(len1));
1164 return len1 < len2 ? -1 : 1;
1165 }
1166
1168 // Case 2: one of them is UTF-8 and the other is UTF-16, so lengths
1169 // are NOT comparable. We need to convert to UTF-16 first...
1170 // (we can't use QUtf8::compareUtf8 because we need to compare lengths)
1171 auto string = [](const Element &e, const ByteData *b) {
1172 return e.flags & Element::StringIsUtf16 ? b->asQStringRaw() : b->toUtf8String();
1173 };
1174
1175 QString s1 = string(e1, b1);
1176 QString s2 = string(e2, b2);
1177 if (s1.size() == s2.size())
1178 return s1.compare(s2);
1179 return s1.size() < s2.size() ? -1 : 1;
1180 }
1181
1182 // Case 3 (UTF-16 and US-ASCII) remains, so lengths are comparable again
1183 if (len1 != len2)
1184 return len1 < len2 ? -1 : 1;
1186 return QtPrivate::compareStrings(b1->asStringView(), b2->asLatin1());
1187 return QtPrivate::compareStrings(b1->asLatin1(), b2->asStringView());
1188 }
1189
1190 return compareElementNoData(e1, e2);
1191}
1192
1194{
1195 auto len1 = c1 ? c1->elements.size() : 0;
1196 auto len2 = c2 ? c2->elements.size() : 0;
1197 if (len1 != len2) {
1198 // sort the shorter container first
1199 return len1 < len2 ? -1 : 1;
1200 }
1201
1202 for (qsizetype i = 0; i < len1; ++i) {
1203 const Element &e1 = c1->elements.at(i);
1204 const Element &e2 = c2->elements.at(i);
1205 int cmp = QCborContainerPrivate::compareElement_helper(c1, e1, c2, e2);
1206 if (cmp)
1207 return cmp;
1208 }
1209
1210 return 0;
1211}
1212
1214 const QCborContainerPrivate *c2, Element e2)
1215{
1216 return compareElementRecursive(c1, e1, c2, e2);
1217}
1218
1320{
1323 return compareElementRecursive(container, e1, other.container, e2);
1324}
1325
1326int QCborArray::compare(const QCborArray &other) const noexcept
1327{
1328 return compareContainer(d.data(), other.d.data());
1329}
1330
1331int QCborMap::compare(const QCborMap &other) const noexcept
1332{
1333 return compareContainer(d.data(), other.d.data());
1334}
1335
1336#if QT_CONFIG(cborstreamwriter)
1337static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate *d, qsizetype idx,
1338 QCborValue::EncodingOptions opt)
1339{
1340 if (idx == -QCborValue::Array || idx == -QCborValue::Map) {
1341 bool isArray = (idx == -QCborValue::Array);
1342 qsizetype len = d ? d->elements.size() : 0;
1343 if (isArray)
1344 writer.startArray(quint64(len));
1345 else
1346 writer.startMap(quint64(len) / 2);
1347
1348 for (idx = 0; idx < len; ++idx)
1349 encodeToCbor(writer, d, idx, opt);
1350
1351 if (isArray)
1352 writer.endArray();
1353 else
1354 writer.endMap();
1355 } else if (idx < 0) {
1356 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1357 if (d->elements.size() != 2) {
1358 // invalid state!
1359 qWarning("QCborValue: invalid tag state; are you encoding something that was improperly decoded?");
1360 return;
1361 }
1362
1363 // write the tag and the tagged element
1364 writer.append(QCborTag(d->elements.at(0).value));
1365 encodeToCbor(writer, d, 1, opt);
1366 } else {
1367 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1368 // just one element
1369 auto e = d->elements.at(idx);
1370 const ByteData *b = d->byteData(idx);
1371 switch (e.type) {
1373 return writer.append(qint64(e.value));
1374
1376 if (b)
1377 return writer.appendByteString(b->byte(), b->len);
1378 return writer.appendByteString("", 0);
1379
1380 case QCborValue::String:
1381 if (b) {
1382 if (e.flags & Element::StringIsUtf16)
1383 return writer.append(b->asStringView());
1384 return writer.appendTextString(b->byte(), b->len);
1385 }
1386 return writer.append(QLatin1StringView());
1387
1388 case QCborValue::Array:
1389 case QCborValue::Map:
1390 case QCborValue::Tag:
1391 // recurse
1392 return encodeToCbor(writer,
1393 e.flags & Element::IsContainer ? e.container : nullptr,
1394 -qsizetype(e.type), opt);
1395
1397 case QCborValue::False:
1398 case QCborValue::True:
1399 case QCborValue::Null:
1401 break;
1402
1403 case QCborValue::Double:
1404 return writeDoubleToCbor(writer, e.fpvalue(), opt);
1405
1407 return;
1408
1410 case QCborValue::Url:
1412 case QCborValue::Uuid:
1413 // recurse as tag
1414 return encodeToCbor(writer, e.container, -QCborValue::Tag, opt);
1415 }
1416
1417 // maybe it's a simple type
1418 int simpleType = e.type - QCborValue::SimpleType;
1419 if (unsigned(simpleType) < 0x100)
1420 return writer.append(QCborSimpleType(simpleType));
1421
1422 // if we got here, we've got an unknown type
1423 qWarning("QCborValue: found unknown type 0x%x", e.type);
1424 }
1425}
1426#endif // QT_CONFIG(cborstreamwriter)
1427
1428#if QT_CONFIG(cborstreamreader)
1429static inline double integerOutOfRange(const QCborStreamReader &reader)
1430{
1431 Q_ASSERT(reader.isInteger());
1432 if (reader.isUnsignedInteger()) {
1433 quint64 v = reader.toUnsignedInteger();
1434 if (qint64(v) < 0)
1435 return double(v);
1436 } else {
1437 quint64 v = quint64(reader.toNegativeInteger());
1438 if (qint64(v - 1) < 0)
1439 return -double(v);
1440 }
1441
1442 // result is in range
1443 return 0;
1444}
1445
1446static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
1447{
1448 Element e = {};
1449
1450 switch (reader.type()) {
1453 if (double d = integerOutOfRange(reader)) {
1454 e.type = QCborValue::Double;
1455 qToUnaligned(d, &e.value);
1456 } else {
1457 e.type = QCborValue::Integer;
1458 e.value = reader.toInteger();
1459 }
1460 break;
1462 e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
1463 break;
1465 e.type = QCborValue::Double;
1466 qToUnaligned(double(reader.toFloat16()), &e.value);
1467 break;
1469 e.type = QCborValue::Double;
1470 qToUnaligned(double(reader.toFloat()), &e.value);
1471 break;
1473 e.type = QCborValue::Double;
1474 qToUnaligned(reader.toDouble(), &e.value);
1475 break;
1476
1477 default:
1478 Q_UNREACHABLE();
1479 }
1480
1481 reader.next();
1482 return e;
1483}
1484
1485// Clamp allocation to avoid crashing due to corrupt stream. This also
1486// ensures we never overflow qsizetype. The returned length is doubled for Map
1487// entries to account for key-value pairs.
1488static qsizetype clampedContainerLength(const QCborStreamReader &reader)
1489{
1490 if (!reader.isLengthKnown())
1491 return 0;
1492 int mapShift = reader.isMap() ? 1 : 0;
1493 quint64 shiftedMaxElements = MaximumPreallocatedElementCount >> mapShift;
1494 qsizetype len = qsizetype(qMin(reader.length(), shiftedMaxElements));
1495 return len << mapShift;
1496}
1497
1498static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1499{
1500 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1501 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1502 return nullptr;
1503 }
1504
1505 QCborContainerPrivate *d = nullptr;
1506 {
1507 // in case QList::reserve throws
1509 if (qsizetype len = clampedContainerLength(reader))
1510 u->elements.reserve(len);
1511 d = u.take();
1512 }
1513
1514 reader.enterContainer();
1515 if (reader.lastError() != QCborError::NoError) {
1516 d->elements.clear();
1517 return d;
1518 }
1519
1520 while (reader.hasNext() && reader.lastError() == QCborError::NoError)
1521 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1522
1523 if (reader.lastError() == QCborError::NoError)
1524 reader.leaveContainer();
1525 else
1526 d->elements.squeeze();
1527
1528 return d;
1529}
1530
1531static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1532{
1533 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1534 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1535 return QCborValue::Invalid;
1536 }
1537
1538 auto d = new QCborContainerPrivate;
1539 d->append(reader.toTag());
1540 reader.next();
1541
1542 if (reader.lastError() == QCborError::NoError) {
1543 // decode tagged value
1544 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1545 }
1546
1548 if (reader.lastError() == QCborError::NoError) {
1549 // post-process to create our extended types
1551 } else {
1552 // decoding error
1554 }
1555
1556 // note: may return invalid state!
1558}
1559
1560// in qcborstream.cpp
1562inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
1563{
1565}
1566
1568
1569void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
1570{
1571 if (reader.lastError() != QCborError::NoError)
1572 return;
1573
1574 qsizetype rawlen = reader.currentStringChunkSize();
1575 QByteArray::size_type len = rawlen;
1576 if (rawlen < 0)
1577 return; // error
1578 if (len != rawlen) {
1579 // truncation
1580 setErrorInReader(reader, { QCborError::DataTooLarge });
1581 return;
1582 }
1583
1584 Element e = {};
1585 e.type = (reader.isByteArray() ? QCborValue::ByteArray : QCborValue::String);
1586 if (len || !reader.isLengthKnown()) {
1587 // The use of size_t means none of the operations here can overflow because
1588 // all inputs are less than half SIZE_MAX.
1589 constexpr size_t EstimatedOverhead = 16;
1590 constexpr size_t MaxMemoryIncrement = 16384;
1591 size_t offset = data.size();
1592
1593 // add space for aligned ByteData (this can't overflow)
1594 offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
1595 offset &= ~(alignof(QtCbor::ByteData) - 1);
1596 if (offset > size_t(MaxByteArraySize)) {
1597 // overflow
1598 setErrorInReader(reader, { QCborError::DataTooLarge });
1599 return;
1600 }
1601
1602 // and calculate the size we want to have
1603 size_t newCapacity = offset + len; // can't overflow
1604 if (size_t(len) > MaxMemoryIncrement - EstimatedOverhead) {
1605 // there's a non-zero chance that we won't need this memory at all,
1606 // so capa how much we allocate
1607 newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
1608 }
1609 if (newCapacity > size_t(MaxByteArraySize)) {
1610 // this may cause an allocation failure
1611 newCapacity = MaxByteArraySize;
1612 }
1613 if (newCapacity > size_t(data.capacity()))
1614 data.reserve(newCapacity);
1615 data.resize(offset + sizeof(QtCbor::ByteData));
1616 e.value = offset;
1617 e.flags = Element::HasByteData;
1618 }
1619
1620 // read chunks
1621 bool isAscii = (e.type == QCborValue::String);
1623 while (status == QCborStreamReader::Ok) {
1624 if (e.type == QCborValue::String && len) {
1625 // verify UTF-8 string validity
1626 auto utf8result = QUtf8::isValidUtf8(QByteArrayView(data).last(len));
1627 if (!utf8result.isValidUtf8) {
1628 status = QCborStreamReader::Error;
1629 setErrorInReader(reader, { QCborError::InvalidUtf8String });
1630 break;
1631 }
1632 isAscii = isAscii && utf8result.isValidAscii;
1633 }
1634
1635 rawlen = reader.currentStringChunkSize();
1636 len = rawlen;
1637 if (len == rawlen) {
1638 status = qt_cbor_append_string_chunk(reader, &data);
1639 } else {
1640 // error
1641 status = QCborStreamReader::Error;
1642 setErrorInReader(reader, { QCborError::DataTooLarge });
1643 }
1644 }
1645
1646 // update size
1647 if (status == QCborStreamReader::EndOfString && e.flags & Element::HasByteData) {
1648 Q_ASSERT(data.isDetached());
1649 const char *ptr = data.constData() + e.value;
1650 auto b = new (const_cast<char *>(ptr)) ByteData;
1651 b->len = data.size() - e.value - int(sizeof(*b));
1652 usedData += b->len;
1653
1654 if (isAscii) {
1655 // set the flag if it is US-ASCII only (as it often is)
1656 Q_ASSERT(e.type == QCborValue::String);
1657 e.flags |= Element::StringIsAscii;
1658 }
1659
1660 // check that this UTF-8 text string can be loaded onto a QString
1661 if (e.type == QCborValue::String) {
1662 if (Q_UNLIKELY(b->len > MaxStringSize)) {
1663 setErrorInReader(reader, { QCborError::DataTooLarge });
1664 status = QCborStreamReader::Error;
1665 }
1666 }
1667 }
1668
1669 if (status == QCborStreamReader::Error) {
1670 data.truncate(e.value);
1671 } else {
1672 elements.append(e);
1673 }
1674}
1675
1676void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1677{
1679 switch (t) {
1686 elements.append(decodeBasicValueFromCbor(reader));
1687 break;
1688
1691 decodeStringFromCbor(reader);
1692 break;
1693
1697 createContainerFromCbor(reader, remainingRecursionDepth),
1698 MoveContainer));
1699
1701 return append(taggedValueFromCbor(reader, remainingRecursionDepth));
1702
1704 return; // probably a decode error
1705 }
1706}
1707#endif // QT_CONFIG(cborstreamreader)
1708
1716 : n(0), container(new QCborContainerPrivate), t(ByteArray)
1717{
1718 container->appendByteData(ba.constData(), ba.size(), t);
1719 container->ref.storeRelaxed(1);
1720}
1721
1729
1737 : n(0), container(new QCborContainerPrivate), t(String)
1738{
1739 container->append(s);
1740 container->ref.storeRelaxed(1);
1741}
1742
1752 : n(0), container(new QCborContainerPrivate), t(String)
1753{
1754 container->append(s);
1755 container->ref.storeRelaxed(1);
1756}
1757
1768 : n(-1), container(a.d.data()), t(Array)
1769{
1770 if (container)
1771 container->ref.ref();
1772}
1773
1784 : n(-1), container(m.d.data()), t(Map)
1785{
1786 if (container)
1787 container->ref.ref();
1788}
1789
1801 : n(-1), container(new QCborContainerPrivate), t(Tag)
1802{
1803 container->ref.storeRelaxed(1);
1804 container->append(tag);
1805 container->append(tv);
1806 t = convertToExtendedType(container);
1807}
1808
1813 : n(other.n), container(other.container), t(other.t)
1814{
1815 if (container)
1816 container->ref.ref();
1817}
1818
1833 : QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1())
1834{
1835 // change types
1836 t = DateTime;
1837 container->elements[1].type = String;
1838}
1839
1840#ifndef QT_BOOTSTRAPPED
1851 : QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8())
1852{
1853 // change types
1854 t = Url;
1855 container->elements[1].type = String;
1856}
1857
1858#if QT_CONFIG(regularexpression)
1873{
1874 // change type
1876}
1877#endif // QT_CONFIG(regularexpression)
1878
1890 : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
1891{
1892 // change our type
1893 t = Uuid;
1894}
1895#endif
1896
1897// destructor
1898void QCborValue::dispose()
1899{
1900 container->deref();
1901}
1902
1907{
1908 n = other.n;
1909 assignContainer(container, other.container);
1910 t = other.t;
1911 return *this;
1912}
1913
1925{
1926 return isTag() && container && container->elements.size() == 2 ?
1927 QCborTag(container->elements.at(0).value) : defaultValue;
1928}
1929
1941{
1942 return isTag() && container && container->elements.size() == 2 ?
1943 container->valueAt(1) : defaultValue;
1944}
1945
1956{
1957 if (!container || !isByteArray())
1958 return defaultValue;
1959
1960 Q_ASSERT(n >= 0);
1961 return container->byteArrayAt(n);
1962}
1963
1973QString QCborValue::toString(const QString &defaultValue) const
1974{
1975 if (!container || !isString())
1976 return defaultValue;
1977
1978 Q_ASSERT(n >= 0);
1979 return container->stringAt(n);
1980}
1981
1992{
1993 if (!container || !isDateTime() || container->elements.size() != 2)
1994 return defaultValue;
1995
1996 Q_ASSERT(n == -1);
1997 const ByteData *byteData = container->byteData(1);
1998 if (!byteData)
1999 return defaultValue; // date/times are never empty, so this must be invalid
2000
2001 // Our data must be US-ASCII.
2002 Q_ASSERT((container->elements.at(1).flags & Element::StringIsUtf16) == 0);
2003 return QDateTime::fromString(byteData->asLatin1(), Qt::ISODateWithMs);
2004}
2005
2006#ifndef QT_BOOTSTRAPPED
2015QUrl QCborValue::toUrl(const QUrl &defaultValue) const
2016{
2017 if (!container || !isUrl() || container->elements.size() != 2)
2018 return defaultValue;
2019
2020 Q_ASSERT(n == -1);
2021 const ByteData *byteData = container->byteData(1);
2022 if (!byteData)
2023 return QUrl(); // valid, empty URL
2024
2025 return QUrl::fromEncoded(byteData->asByteArrayView());
2026}
2027
2028#if QT_CONFIG(regularexpression)
2039QRegularExpression QCborValue::toRegularExpression(const QRegularExpression &defaultValue) const
2040{
2041 if (!container || !isRegularExpression() || container->elements.size() != 2)
2042 return defaultValue;
2043
2044 Q_ASSERT(n == -1);
2045 return QRegularExpression(container->stringAt(1));
2046}
2047#endif // QT_CONFIG(regularexpression)
2048
2057QUuid QCborValue::toUuid(const QUuid &defaultValue) const
2058{
2059 if (!container || !isUuid() || container->elements.size() != 2)
2060 return defaultValue;
2061
2062 Q_ASSERT(n == -1);
2063 const ByteData *byteData = container->byteData(1);
2064 if (!byteData)
2065 return defaultValue; // UUIDs must always be 16 bytes, so this must be invalid
2066
2067 return QUuid::fromRfc4122(byteData->asByteArrayView());
2068}
2069#endif
2070
2098{
2099 return toArray(QCborArray());
2100}
2101
2103{
2104 if (!isArray())
2105 return defaultValue;
2106 QCborContainerPrivate *dd = nullptr;
2107 Q_ASSERT(n == -1 || container == nullptr);
2108 if (n < 0)
2109 dd = container;
2110 // return QCborArray(*dd); but that's UB if dd is nullptr
2111 return dd ? QCborArray(*dd) : QCborArray();
2112}
2113
2141{
2142 return toMap(QCborMap());
2143}
2144
2145QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2146{
2147 if (!isMap())
2148 return defaultValue;
2149 QCborContainerPrivate *dd = nullptr;
2150 Q_ASSERT(n == -1 || container == nullptr);
2151 if (n < 0)
2152 dd = container;
2153 // return QCborMap(*dd); but that's UB if dd is nullptr
2154 return dd ? QCborMap(*dd) : QCborMap();
2155}
2156
2170{
2172}
2173
2189{
2191}
2192
2205{
2206 if (isArray() && container && quint64(key) < quint64(container->elements.size()))
2207 return container->valueAt(key);
2209}
2210
2212{
2213 constexpr qint64 LargeKey = 0x10000;
2214 if (t != QCborValue::Array)
2215 return false;
2216 if (key < 0)
2217 return false; // negative keys can't be an array index
2218 if (key < LargeKey)
2219 return true;
2220
2221 // Only convert to map if key is greater than array size + 1
2222 qsizetype currentSize = container ? container->elements.size() : 0;
2223 return key <= currentSize;
2224}
2225
2230{
2231 if (Q_LIKELY(!array || array->elements.isEmpty()))
2232 return;
2233
2234 // The Q_LIKELY and the qWarning mark the rest of this function as unlikely
2235 qWarning("Using CBOR array as map forced conversion");
2236
2237 qsizetype size = array->elements.size();
2239 map->elements.resize(size * 2);
2240
2241 // this may be an in-place copy, so we have to do it from the end
2242 auto dst = map->elements.begin();
2243 auto src = array->elements.constBegin();
2244 for (qsizetype i = size - 1; i >= 0; --i) {
2246 dst[i * 2 + 1] = src[i];
2247 }
2248 for (qsizetype i = 0; i < size; ++i)
2249 dst[i * 2] = { i, QCborValue::Integer };
2250
2251 // only do this last portion if we're not modifying in-place
2252 for (qsizetype i = 0; src != dst && i < size; ++i) {
2253 if (dst[i * 2 + 1].flags & QtCbor::Element::IsContainer)
2254 dst[i * 2 + 1].container->ref.ref();
2255 }
2256
2257 // update reference counts
2259}
2260
2265{
2266 auto replace = QCborContainerPrivate::grow(container, index);
2267 Q_ASSERT(replace);
2268 if (replace->elements.size() == index)
2269 replace->append(Undefined());
2270 else
2271 Q_ASSERT(replace->elements.size() > index);
2272 return assignContainer(container, replace);
2273}
2274
2275template <typename KeyType> inline QCborValueRef
2277{
2278 // we need a map, so convert if necessary
2279 if (self.isArray())
2280 convertArrayToMap(self.container);
2281 else if (!self.isMap())
2283 self.t = QCborValue::Map;
2284 self.n = -1;
2285
2286 QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
2287 assignContainer(self.container, result.d);
2288 return result;
2289}
2290
2291template<typename KeyType> QCborValueRef
2293{
2294 auto &e = self.d->elements[self.i];
2295
2296 // we need a map, so convert if necessary
2297 if (e.type == QCborValue::Array) {
2298 convertArrayToMap(e.container);
2299 } else if (e.type != QCborValue::Map) {
2300 if (e.flags & QtCbor::Element::IsContainer)
2301 e.container->deref();
2302 e.container = nullptr;
2303 }
2305 e.type = QCborValue::Map;
2306
2307 QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
2308 assignContainer(e.container, result.d);
2309 return result;
2310}
2311
2326{
2328}
2329
2346{
2348}
2349
2367{
2368 if (shouldArrayRemainArray(key, t, container)) {
2369 container = maybeGrow(container, key);
2370 return { container, qsizetype(key) };
2371 }
2373}
2374
2375#if QT_CONFIG(cborstreamreader)
2396QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
2397{
2399 auto t = reader.type();
2400 if (reader.lastError() != QCborError::NoError)
2402
2403 switch (t) {
2404 // basic types, no container needed:
2411 Element e = decodeBasicValueFromCbor(reader);
2412 result.n = e.value;
2413 result.t = e.type;
2414 break;
2415 }
2416
2419 break; // probably a decode error
2420
2421 // strings
2424 result.n = 0;
2425 result.t = reader.isString() ? String : ByteArray;
2426 result.container = new QCborContainerPrivate;
2427 result.container->ref.ref();
2428 result.container->decodeStringFromCbor(reader);
2429 break;
2430
2431 // containers
2434 result.n = -1;
2435 result.t = reader.isArray() ? Array : Map;
2436 result.container = createContainerFromCbor(reader, MaximumRecursionDepth);
2437 break;
2438
2439 // tag
2441 result = taggedValueFromCbor(reader, MaximumRecursionDepth);
2442 break;
2443 }
2444
2445 return result;
2446}
2447
2470QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
2471{
2473 QCborValue result = fromCbor(reader);
2474 if (error) {
2475 error->error = reader.lastError();
2476 error->offset = reader.currentOffset();
2477 }
2478 return result;
2479}
2480
2490#endif // QT_CONFIG(cborstreamreader)
2491
2492#if QT_CONFIG(cborstreamwriter)
2519QByteArray QCborValue::toCbor(EncodingOptions opt) const
2520{
2522 QCborStreamWriter writer(&result);
2523 toCbor(writer, opt);
2524 return result;
2525}
2526
2556Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt) const
2557{
2558 if (isContainer() || isTag())
2559 return encodeToCbor(writer, container, -type(), opt);
2560 if (container)
2561 return encodeToCbor(writer, container, n, opt);
2562
2563 // very simple types
2564 if (isSimpleType())
2565 return writer.append(toSimpleType());
2566
2567 switch (type()) {
2568 case Integer:
2569 return writer.append(n);
2570
2571 case Double:
2572 return writeDoubleToCbor(writer, fp_helper(), opt);
2573
2574 case Invalid:
2575 return;
2576
2577 case SimpleType:
2578 case False:
2579 case True:
2580 case Null:
2581 case Undefined:
2582 // handled by "if (isSimpleType())"
2583 Q_UNREACHABLE();
2584 break;
2585
2586 case ByteArray:
2587 // Byte array with no container is empty
2588 return writer.appendByteString("", 0);
2589
2590 case String:
2591 // String with no container is empty
2592 return writer.appendTextString("", 0);
2593
2594 case Array:
2595 case Map:
2596 case Tag:
2597 // handled by "if (isContainer() || isTag())"
2598 Q_UNREACHABLE();
2599 break;
2600
2601 case DateTime:
2602 case Url:
2603 case RegularExpression:
2604 case Uuid:
2605 // not possible
2606 Q_UNREACHABLE();
2607 break;
2608 }
2609}
2610
2611# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
2612void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
2613{
2614 concrete().toCbor(writer, opt);
2615}
2616# endif
2617#endif // QT_CONFIG(cborstreamwriter)
2618
2619void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
2620{
2621 that.d->replaceAt(that.i, other);
2622}
2623
2624void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
2625{
2626 that.d->replaceAt(that.i, other, QCborContainerPrivate::MoveContainer);
2627}
2628
2629void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
2630{
2631 // ### optimize?
2632 that = other.concrete();
2633}
2634
2635bool QCborValueConstRef::concreteBoolean(QCborValueConstRef self, bool defaultValue) noexcept
2636{
2637 QtCbor::Element e = self.d->elements.at(self.i);
2638 if (e.type != QCborValue::False && e.type != QCborValue::True)
2639 return defaultValue;
2640 return e.type == QCborValue::True;
2641}
2642
2643double QCborValueConstRef::concreteDouble(QCborValueConstRef self, double defaultValue) noexcept
2644{
2645 QtCbor::Element e = self.d->elements.at(self.i);
2646 if (e.type == QCborValue::Integer)
2647 return e.value;
2648 if (e.type != QCborValue::Double)
2649 return defaultValue;
2650 return e.fpvalue();
2651}
2652
2654{
2655 QtCbor::Element e = self.d->elements.at(self.i);
2656 QCborValue::Type t = e.type;
2657 if (t == QCborValue::Double)
2658 return e.fpvalue();
2659 if (t != QCborValue::Integer)
2660 return defaultValue;
2661 return e.value;
2662}
2663
2665 const QByteArray &defaultValue)
2666{
2667 QtCbor::Element e = self.d->elements.at(self.i);
2668 if (e.type != QCborValue::ByteArray)
2669 return defaultValue;
2670 return self.d->byteArrayAt(self.i);
2671}
2672
2674{
2675 QtCbor::Element e = self.d->elements.at(self.i);
2676 if (e.type != QCborValue::String)
2677 return defaultValue;
2678 return self.d->stringAt(self.i);
2679}
2680
2682{
2683 return self.d->valueAt(self.i);
2684}
2685
2687{
2688 return self.d->elements.at(self.i).type;
2689}
2690
2692{
2693 const QCborValue item = d->valueAt(i);
2694 return item[key];
2695}
2696
2698{
2699 const QCborValue item = d->valueAt(i);
2700 return item[key];
2701}
2702
2704{
2705 const QCborValue item = d->valueAt(i);
2706 return item[key];
2707}
2708
2709#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
2710QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
2711{
2712 return self.d->valueAt(self.i);
2713}
2714
2715QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
2716{
2717 return self.d->elements.at(self.i).type;
2718}
2719
2734const QCborValue QCborValueRef::operator[](const QString &key) const
2735{
2737}
2738
2755const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
2756{
2758}
2759
2772const QCborValue QCborValueRef::operator[](qint64 key) const
2773{
2775}
2776
2791QCborValueRef QCborValueRef::operator[](const QString &key)
2792{
2794}
2795
2811QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
2812{
2814}
2815
2832QCborValueRef QCborValueRef::operator[](qint64 key)
2833{
2834 auto &e = d->elements[i];
2835 if (shouldArrayRemainArray(key, e.type, e.container)) {
2836 e.container = maybeGrow(e.container, key);
2838 return { e.container, qsizetype(key) };
2839 }
2841}
2842#endif // < Qt 7
2843
2845 : d(&dd)
2846{
2847}
2848
2849inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept
2850 : d(&dd)
2851{
2852}
2853
2854size_t qHash(const QCborValue &value, size_t seed)
2855{
2856 switch (value.type()) {
2858 return qHash(value.toInteger(), seed);
2860 return qHash(value.toByteArray(), seed);
2861 case QCborValue::String:
2862 return qHash(value.toString(), seed);
2863 case QCborValue::Array:
2864 return qHash(value.toArray(), seed);
2865 case QCborValue::Map:
2866 return qHash(value.toMap(), seed);
2867 case QCborValue::Tag: {
2869 seed = hash(seed, value.tag());
2870 seed = hash(seed, value.taggedValue());
2871 return seed;
2872 }
2874 break;
2875 case QCborValue::False:
2876 return qHash(false, seed);
2877 case QCborValue::True:
2878 return qHash(true, seed);
2879 case QCborValue::Null:
2880 return qHash(nullptr, seed);
2882 return seed;
2883 case QCborValue::Double:
2884 return qHash(value.toDouble(), seed);
2886 return qHash(value.toDateTime(), seed);
2887#ifndef QT_BOOTSTRAPPED
2888 case QCborValue::Url:
2889 return qHash(value.toUrl(), seed);
2890# if QT_CONFIG(regularexpression)
2892 return qHash(value.toRegularExpression(), seed);
2893# endif
2894 case QCborValue::Uuid:
2895 return qHash(value.toUuid(), seed);
2896#endif
2898 return seed;
2899 default:
2900 break;
2901 }
2902
2903 Q_ASSERT(value.isSimpleType());
2904 return qHash(value.toSimpleType(), seed);
2905}
2906
2907Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
2908{
2909 switch (st) {
2911 return "False";
2913 return "True";
2915 return "Null";
2917 return "Undefined";
2918 }
2919 return nullptr;
2920}
2921
2922Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
2923{
2924 // Casting to QCborKnownTags's underlying type will make the comparison
2925 // below fail if the tag value is out of range.
2926 auto n = std::underlying_type<QCborKnownTags>::type(tag);
2927 if (QCborTag(n) == tag) {
2928 switch (QCborKnownTags(n)) {
2930 return "DateTimeString";
2932 return "UnixTime_t";
2934 return "PositiveBignum";
2936 return "NegativeBignum";
2938 return "Decimal";
2940 return "Bigfloat";
2942 return "COSE_Encrypt0";
2944 return "COSE_Mac0";
2946 return "COSE_Sign1";
2948 return "ExpectedBase64url";
2950 return "ExpectedBase64";
2952 return "ExpectedBase16";
2954 return "EncodedCbor";
2956 return "Url";
2958 return "Base64url";
2960 return "Base64";
2962 return "RegularExpression";
2964 return "MimeMessage";
2966 return "Uuid";
2968 return "COSE_Encrypt";
2970 return "COSE_Mac";
2972 return "COSE_Sign";
2974 return "Signature";
2975 }
2976 }
2977 return nullptr;
2978}
2979
2980#if !defined(QT_NO_DEBUG_STREAM)
2982{
2983 switch (v.type()) {
2985 return dbg << v.toInteger();
2987 return dbg << "QByteArray(" << v.toByteArray() << ')';
2988 case QCborValue::String:
2989 return dbg << v.toString();
2990 case QCborValue::Array:
2991 return dbg << v.toArray();
2992 case QCborValue::Map:
2993 return dbg << v.toMap();
2994 case QCborValue::Tag: {
2995 QCborTag tag = v.tag();
2996 const char *id = qt_cbor_tag_id(tag);
2997 if (id)
2998 dbg.nospace() << "QCborKnownTags::" << id << ", ";
2999 else
3000 dbg.nospace() << "QCborTag(" << quint64(tag) << "), ";
3001 return dbg << v.taggedValue();
3002 }
3004 break;
3005 case QCborValue::True:
3006 return dbg << true;
3007 case QCborValue::False:
3008 return dbg << false;
3009 case QCborValue::Null:
3010 return dbg << "nullptr";
3012 return dbg;
3013 case QCborValue::Double: {
3014 qint64 i;
3015 if (convertDoubleTo(v.toDouble(), &i))
3016 return dbg << i << ".0";
3017 else
3018 return dbg << v.toDouble();
3019 }
3021 return dbg << v.toDateTime();
3022#ifndef QT_BOOTSTRAPPED
3023 case QCborValue::Url:
3024 return dbg << v.toUrl();
3025#if QT_CONFIG(regularexpression)
3027 return dbg << v.toRegularExpression();
3028#endif
3029 case QCborValue::Uuid:
3030 return dbg << v.toUuid();
3031#endif
3033 return dbg << "<invalid>";
3034 default:
3035 break;
3036 }
3037 if (v.isSimpleType())
3038 return dbg << v.toSimpleType();
3039 return dbg << "<unknown type 0x" << Qt::hex << int(v.type()) << Qt::dec << '>';
3040}
3042{
3043 QDebugStateSaver saver(dbg);
3044 dbg.nospace() << "QCborValue(";
3045 return debugContents(dbg, v) << ')';
3046}
3047
3049{
3050 QDebugStateSaver saver(dbg);
3051 const char *id = qt_cbor_simpletype_id(st);
3052 if (id)
3053 return dbg.nospace() << "QCborSimpleType::" << id;
3054
3055 return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
3056}
3057
3059{
3060 QDebugStateSaver saver(dbg);
3061 const char *id = qt_cbor_tag_id(tag);
3062 dbg.nospace() << "QCborTag(";
3063 if (id)
3064 dbg.nospace() << "QCborKnownTags::" << id;
3065 else
3066 dbg.nospace() << quint64(tag);
3067
3068 return dbg << ')';
3069}
3070
3072{
3073 QDebugStateSaver saver(dbg);
3074 const char *id = qt_cbor_tag_id(QCborTag(int(tag)));
3075 if (id)
3076 return dbg.nospace() << "QCborKnownTags::" << id;
3077
3078 return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
3079}
3080#endif
3081
3082#ifndef QT_NO_DATASTREAM
3083#if QT_CONFIG(cborstreamwriter)
3085{
3086 stream << QCborValue(value).toCbor();
3087 return stream;
3088}
3089#endif
3090
3092{
3094 stream >> buffer;
3095 QCborParserError parseError{};
3096 value = QCborValue::fromCbor(buffer, &parseError);
3097 if (parseError.error)
3099 return stream;
3100}
3101#endif
3102
3103
3105
3106#include "qcborarray.cpp"
3107#include "qcbormap.cpp"
3108
3109#ifndef QT_NO_QOBJECT
3110#include "moc_qcborvalue.cpp"
3111#endif
bool ref() noexcept
void storeRelaxed(T newValue) noexcept
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
qsizetype size_type
Definition qbytearray.h:444
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:557
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
\inmodule QtCore\reentrant
Definition qcborarray.h:20
int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION
Compares this array and other, comparing each element in sequence, and returns an integer that indica...
QCborArray() noexcept
Constructs an empty QCborArray.
QString stringAt(qsizetype idx) const
QByteArray::size_type usedData
const QtCbor::ByteData * byteData(QtCbor::Element e) const
void appendByteData(const char *data, qsizetype len, QCborValue::Type type, QtCbor::Element::ValueFlags extraFlags={})
static QCborContainerPrivate * grow(QCborContainerPrivate *d, qsizetype index)
Prepare for an insertion at position index.
static QCborContainerPrivate * detach(QCborContainerPrivate *d, qsizetype reserved)
QCborValueConstRef findCborMapKey(KeyType key)
QList< QtCbor::Element > elements
void compact(qsizetype reserved)
void append(QtCbor::Undefined)
QByteArray byteArrayAt(qsizetype idx) const
static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d=nullptr, ContainerDisposition disp=CopyContainer)
static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1, const QCborContainerPrivate *c2, QtCbor::Element e2)
static QCborValueRef findOrAddMapKey(QCborContainerPrivate *container, KeyType key)
QCborValue extractAt_complex(QtCbor::Element e)
void appendAsciiString(const QString &s)
qptrdiff addByteData(const char *block, qsizetype len)
static QtCbor::Element elementFromValue(const QCborValue &value)
void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
QCborValue valueAt(qsizetype idx) const
static QCborContainerPrivate * clone(QCborContainerPrivate *d, qsizetype reserved=-1)
\inmodule QtCore\reentrant
Definition qcbormap.h:21
QCborMap() noexcept
Constructs an empty CBOR Map object.
Definition qcbormap.cpp:169
int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION
Compares this map and other, comparing each element in sequence, and returns an integer that indicate...
\inmodule QtCore\reentrant
StringResultCode
This enum is returned by readString() and readByteArray() and is used to indicate what the status of ...
Type
This enumeration contains all possible CBOR types as decoded by QCborStreamReader.
\inmodule QtCore\reentrant
bool endMap()
Terminates the map started by either overload of startMap() and returns true if the correct number of...
void startMap()
Starts a CBOR Map with indeterminate length in the CBOR stream.
void appendTextString(const char *utf8, qsizetype len)
Appends len bytes of text starting from utf8 to the stream, creating a CBOR Text String value.
void appendByteString(const char *data, qsizetype len)
Appends len bytes of data starting from data to the stream, creating a CBOR Byte String value.
void startArray()
Starts a CBOR Array with indeterminate length in the CBOR stream.
void append(quint64 u)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endArray()
Terminates the array started by either overload of startArray() and returns true if the correct numbe...
static Q_CORE_EXPORT QString concreteString(QCborValueConstRef that, const QString &defaultValue)
static Q_CORE_EXPORT double concreteDouble(QCborValueConstRef that, double defaultValue) noexcept Q_DECL_PURE_FUNCTION
static Q_CORE_EXPORT QByteArray concreteByteArray(QCborValueConstRef that, const QByteArray &defaultValue)
static Q_CORE_EXPORT qint64 concreteIntegral(QCborValueConstRef that, qint64 defaultValue) noexcept Q_DECL_PURE_FUNCTION
static Q_CORE_EXPORT QCborValue::Type concreteType(QCborValueConstRef that) noexcept Q_DECL_PURE_FUNCTION
Q_CORE_EXPORT const QCborValue operator[](const QString &key) const
QCborContainerPrivate * d
Definition qcborvalue.h:427
static Q_CORE_EXPORT bool concreteBoolean(QCborValueConstRef that, bool defaultValue) noexcept Q_DECL_PURE_FUNCTION
QCborValue concrete() const noexcept
Definition qcborvalue.h:408
\inmodule QtCore\reentrant
Definition qcborvalue.h:50
const QCborValue operator[](const QString &key) const
If this QCborValue is a QCborMap, searches elements for the value whose key matches key.
bool isSimpleType() const
Returns true if this QCborValue is of one of the CBOR simple types.
Definition qcborvalue.h:177
bool isDateTime() const
Returns true if this QCborValue is of the date/time type.
Definition qcborvalue.h:170
QCborValue & operator=(const QCborValue &other) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isString() const
Returns true if this QCborValue is of the string type.
Definition qcborvalue.h:160
QString toString(const QString &defaultValue={}) const
Returns the string value stored in this QCborValue, if it is of the string type.
QCborArray toArray() const
QUuid toUuid(const QUuid &defaultValue={}) const
Returns the UUID value stored in this QCborValue, if it is of the UUID extended type.
QCborMap toMap() const
int compare(const QCborValue &other) const
Compares this value and other, and returns an integer that indicates whether this value should be sor...
bool isUrl() const
Returns true if this QCborValue is of the URL type.
Definition qcborvalue.h:171
bool isByteArray() const
Returns true if this QCborValue is of the byte array type.
Definition qcborvalue.h:159
Type
This enum represents the QCborValue type.
Definition qcborvalue.h:73
@ RegularExpression
Definition qcborvalue.h:93
QUrl toUrl(const QUrl &defaultValue={}) const
Returns the URL value stored in this QCborValue, if it is of the URL extended type.
QCborValue()
Creates a QCborValue of the \l {Type}{Undefined} type.
Definition qcborvalue.h:100
bool isRegularExpression() const
Returns true if this QCborValue contains a regular expression's pattern.
Definition qcborvalue.h:172
bool isContainer() const
This convenience function returns true if the QCborValue is either an array or a map.
Definition qcborvalue.h:175
friend class QCborContainerPrivate
Definition qcborvalue.h:264
QByteArray toByteArray(const QByteArray &defaultValue={}) const
Returns the byte array value stored in this QCborValue, if it is of the byte array type.
Type type() const
Returns the type of this QCborValue.
Definition qcborvalue.h:157
QCborSimpleType toSimpleType(QCborSimpleType defaultValue=QCborSimpleType::Undefined) const
Returns the simple type this QCborValue is of, if it is a simple type.
Definition qcborvalue.h:185
bool isTag() const
Returns true if this QCborValue is of the tag type.
Definition qcborvalue.h:163
bool isArray() const
Returns true if this QCborValue is of the array type.
Definition qcborvalue.h:161
bool isUuid() const
Returns true if this QCborValue contains a UUID.
Definition qcborvalue.h:173
QCborTag tag(QCborTag defaultValue=QCborTag(-1)) const
Returns the tag of this extended QCborValue object, if it is of the tag type, defaultValue otherwise.
bool isMap() const
Returns true if this QCborValue is of the map type.
Definition qcborvalue.h:162
QDateTime toDateTime(const QDateTime &defaultValue={}) const
Returns the date/time value stored in this QCborValue, if it is of the date/time extended type.
QCborValue taggedValue(const QCborValue &defaultValue=QCborValue()) const
Returns the tagged value of this extended QCborValue object, if it is of the tag type,...
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore\reentrant
Definition qdatetime.h:257
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
\inmodule QtCore
\inmodule QtCore
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
iterator begin()
Definition qmap.h:597
\inmodule QtCore \reentrant
QAtomicInt ref
Definition qshareddata.h:21
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QByteArray toUtf8() const &
Definition qstring.h:563
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
@ StrictMode
Definition qurl.h:98
@ DecodeReserved
Definition qurl.h:126
static QUrl fromEncoded(QByteArrayView input, ParsingMode mode=TolerantMode)
Parses input and returns the corresponding QUrl.
Definition qurl.cpp:2985
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
\inmodule QtCore
Definition quuid.h:31
static QUuid fromRfc4122(QByteArrayView) noexcept
Creates a QUuid object from the binary representation of the UUID, as specified by RFC 4122 section 4...
Definition quuid.cpp:547
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:46
QHash< int, QWidget * > hash
[35multi]
QMap< QString, QString > map
[6]
QString text
double e
QStyleOptionButton opt
Combined button and popup list for selecting options.
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1StringView s) noexcept
Definition qstring.cpp:860
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
@ ISODateWithMs
QString self
Definition language.cpp:57
QImageReader reader("image.png")
[1]
constexpr qsizetype MaxStringSize
QT_BEGIN_NAMESPACE constexpr qsizetype MaxByteArraySize
QCborKnownTags
Definition qcborcommon.h:31
QCborTag
Definition qcborcommon.h:30
QCborSimpleType
Definition qcborcommon.h:23
QCborNegativeInteger
QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data)
void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error)
static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1, const QCborContainerPrivate *c2, const Element &e2)
Q_CORE_EXPORT const char * qt_cbor_simpletype_id(QCborSimpleType st)
void qt_to_latin1_unchecked(uchar *dst, const char16_t *uc, qsizetype len)
Definition qstring.cpp:1198
static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
static int typeOrder(Element e1, Element e2)
QDebug operator<<(QDebug dbg, const QCborValue &v)
static QCborContainerPrivate * assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
size_t qHash(const QCborValue &value, size_t seed)
static Q_DECL_UNUSED constexpr quint64 MaximumPreallocatedElementCount
static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
Q_CORE_EXPORT const char * qt_cbor_tag_id(QCborTag tag)
static int compareElementNoData(const Element &e1, const Element &e2)
static QCborContainerPrivate * maybeGrow(QCborContainerPrivate *container, qsizetype index)
static QDebug debugContents(QDebug &dbg, const QCborValue &v)
static Q_DECL_UNUSED constexpr int MaximumRecursionDepth
static QT_BEGIN_NAMESPACE constexpr quint64 MaxAcceptableMemoryUse
QDataStream & operator>>(QDataStream &stream, QCborValue &value)
static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2)
static void convertArrayToMap(QCborContainerPrivate *&array)
#define Q_UNLIKELY(x)
#define Q_DECL_UNUSED
#define Q_NEVER_INLINE
#define QT_WARNING_DISABLE_MSVC(number)
#define Q_LIKELY(x)
AudioChannelLayoutTag tag
DBusConnection const char DBusError * error
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
Definition qendian.h:34
#define qWarning
Definition qlogging.h:162
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
Definition qnumeric.h:182
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:106
constexpr static Q_DECL_CONST_FUNCTION double qt_qnan() noexcept
Definition qnumeric_p.h:94
constexpr static Q_DECL_CONST_FUNCTION double qt_inf() noexcept
Definition qnumeric_p.h:77
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
Definition qnumeric_p.h:101
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLenum GLuint id
[7]
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint ref
GLfloat n
GLfixed GLfixed u2
GLenum array
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfixed u1
GLubyte * pattern
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
#define s2
#define Q_UNUSED(x)
Tag
unsigned char uchar
Definition qtypes.h:27
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned char quint8
Definition qtypes.h:41
QList< QPair< QString, QString > > Map
QByteArray ba
[0]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
MyCustomStruct c2
p rx()++
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
char * toString(const MyType &t)
[31]
\inmodule QtCore \inheaderfile QtCborCommon \reentrant
Definition qcborcommon.h:63
@ InvalidUtf8String
Definition qcborcommon.h:78
\inmodule QtCore\reentrant
Definition qcborvalue.h:40
static ValidUtf8Result isValidUtf8(QByteArrayView in)
QStringView asStringView() const
QLatin1StringView asLatin1() const
const char * byte() const
QByteArray::size_type len
QByteArray asByteArrayView() const
ValueFlags flags
QCborContainerPrivate * container