Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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/qnumeric_p.h>
23#include <private/qsimd_p.h>
24
25#include <new>
26
28
29// Worst case memory allocation for a corrupt stream: 256 MB for 32-bit, 1 GB for 64-bit
30static constexpr quint64 MaxAcceptableMemoryUse = (sizeof(void*) == 4 ? 256 : 1024) * 1024 * 1024;
31
32// Internal limits to ensure we don't blow up the memory when parsing a corrupt
33// (possibly crafted to exploit) CBOR stream. The recursion impacts both the
34// maps/arrays we'll open when parsing and the thread's stack, as the parser is
35// itself recursive. If someone really needs more than 1024 layers of nesting,
36// they probably have a weird use-case for which custom parsing and
37// serialisation code would make sense. The limit on element count is the
38// preallocated limit: if the stream does actually have more elements, we will
39// grow the container.
40Q_DECL_UNUSED static constexpr int MaximumRecursionDepth = 1024;
43
751using namespace QtCbor;
752
754{
755 if (d == x)
756 return d;
757 if (d)
758 d->deref();
759 if (x)
760 x->ref.ref();
761 return d = x;
762}
763
765{
766 qint64 tag = d->elements.at(0).value;
767 auto &e = d->elements[1];
768 const ByteData *b = d->byteData(e);
769
770 auto replaceByteData = [&](const char *buf, qsizetype len, Element::ValueFlags f) {
771 d->data.clear();
772 d->usedData = 0;
773 e.flags = Element::HasByteData | f;
774 e.value = d->addByteData(buf, len);
775 };
776
777 switch (tag) {
780 QDateTime dt;
782 e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) {
783 // The data is supposed to be US-ASCII. If it isn't (contains UTF-8),
784 // QDateTime::fromString will fail anyway.
785 dt = QDateTime::fromString(b->asLatin1(), Qt::ISODateWithMs);
786 } else if (tag == qint64(QCborKnownTags::UnixTime_t)) {
787 qint64 msecs;
788 bool ok = false;
789 if (e.type == QCborValue::Integer) {
790#if QT_POINTER_SIZE == 8
791 // we don't have a fast 64-bit qMulOverflow implementation on
792 // 32-bit architectures.
793 ok = !qMulOverflow(e.value, qint64(1000), &msecs);
794#else
795 static const qint64 Limit = std::numeric_limits<qint64>::max() / 1000;
796 ok = (e.value > -Limit && e.value < Limit);
797 if (ok)
798 msecs = e.value * 1000;
799#endif
800 } else if (e.type == QCborValue::Double) {
801 ok = convertDoubleTo(round(e.fpvalue() * 1000), &msecs);
802 }
803 if (ok)
805 }
806 if (dt.isValid()) {
807 QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1();
808 if (!text.isEmpty()) {
809 replaceByteData(text, text.size(), Element::StringIsAscii);
810 e.type = QCborValue::String;
811 d->elements[0].value = qint64(QCborKnownTags::DateTimeString);
813 }
814 }
815 break;
816 }
817
818#ifndef QT_BOOTSTRAPPED
820 if (e.type == QCborValue::String) {
821 if (b) {
822 // normalize to a short (decoded) form, so as to save space
823 QUrl url(e.flags & Element::StringIsUtf16 ?
824 b->asQStringRaw() :
825 b->toUtf8String(), QUrl::StrictMode);
826 if (url.isValid()) {
828 replaceByteData(encoded, encoded.size(), {});
829 }
830 }
831 return QCborValue::Url;
832 }
833 break;
834#endif // QT_BOOTSTRAPPED
835
836#if QT_CONFIG(regularexpression)
838 if (e.type == QCborValue::String) {
839 // no normalization is necessary
841 }
842 break;
843#endif // QT_CONFIG(regularexpression)
844
846 if (e.type == QCborValue::ByteArray) {
847 // force the size to 16
848 char buf[sizeof(QUuid)] = {};
849 if (b)
850 memcpy(buf, b->byte(), qMin(sizeof(buf), size_t(b->len)));
851 replaceByteData(buf, sizeof(buf), {});
852
853 return QCborValue::Uuid;
854 }
855 break;
856 }
857
858 // no enriching happened
859 return QCborValue::Tag;
860}
861
862#if QT_CONFIG(cborstreamwriter)
863static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
864{
865 if (qt_is_nan(d)) {
867#ifndef QT_BOOTSTRAPPED
869 return writer.append(std::numeric_limits<qfloat16>::quiet_NaN());
870#endif
871 return writer.append(std::numeric_limits<float>::quiet_NaN());
872 }
873 return writer.append(qt_qnan());
874 }
875
876 if (qt_is_inf(d)) {
877 d = d > 0 ? qt_inf() : -qt_inf();
878 } else if (opt & QCborValue::UseIntegers) {
879 quint64 i;
880 if (convertDoubleTo(d, &i)) {
881 if (d < 0)
882 return writer.append(QCborNegativeInteger(i));
883 return writer.append(i);
884 }
885 }
886
888 float f = float(d);
889 if (f == d) {
890 // no data loss, we could use float
891#ifndef QT_BOOTSTRAPPED
893 qfloat16 f16 = qfloat16(f);
894 if (f16 == f)
895 return writer.append(f16);
896 }
897#endif
898
899 return writer.append(f);
900 }
901 }
902
903 writer.append(d);
904}
905#endif // QT_CONFIG(cborstreamwriter)
906
908{
909 auto comparable = [](QCborValue::Type type) {
910 if (type >= 0x10000) // see QCborValue::isTag_helper()
911 return QCborValue::Tag;
912 return type;
913 };
914 return comparable(e1) - comparable(e2);
915}
916
917QCborContainerPrivate::~QCborContainerPrivate()
918{
919 // delete our elements
920 for (Element &e : elements) {
921 if (e.flags & Element::IsContainer)
922 e.container->deref();
923 }
924}
925
927{
928 if (usedData > data.size() / 2)
929 return;
930
931 // 50% savings if we recreate the byte data
932 QByteArray newData;
933 QByteArray::size_type newUsedData = 0;
934 // Compact only elements that have byte data.
935 // Nested containers will be compacted when their data changes.
936 for (auto &e : elements) {
937 if (e.flags & Element::HasByteData) {
938 if (const ByteData *b = byteData(e))
939 e.value = addByteDataImpl(newData, newUsedData, b->byte(), b->len);
940 }
941 }
942 data = newData;
943 usedData = newUsedData;
944}
945
947{
948 if (!d) {
950 } else {
951 // in case QList::reserve throws
953 if (reserved >= 0) {
954 u->elements.reserve(reserved);
955 u->compact();
956 }
957
958 d = u.take();
959 d->ref.storeRelaxed(0);
960
961 for (auto &e : std::as_const(d->elements)) {
962 if (e.flags & Element::IsContainer)
963 e.container->ref.ref();
964 }
965 }
966 return d;
967}
968
970{
971 if (!d || d->ref.loadRelaxed() != 1)
972 return clone(d, reserved);
973 return d;
974}
975
983{
984 Q_ASSERT(index >= 0);
985 d = detach(d, index + 1);
986 Q_ASSERT(d);
987 qsizetype j = d->elements.size();
988 while (j++ < index)
989 d->append(Undefined());
990 return d;
991}
992
993// Copies or moves \a value into element at position \a e. If \a disp is
994// CopyContainer, then this function increases the reference count of the
995// container, but otherwise leaves it unmodified. If \a disp is MoveContainer,
996// then it transfers ownership (move semantics) and the caller must set
997// value.container back to nullptr.
999{
1000 if (value.n < 0) {
1001 // This QCborValue is an array, map, or tagged value (container points
1002 // to itself).
1003
1004 // detect self-assignment
1005 if (Q_UNLIKELY(this == value.container)) {
1006 Q_ASSERT(ref.loadRelaxed() >= 2);
1007 if (disp == MoveContainer)
1008 ref.deref(); // not deref() because it can't drop to 0
1010 d->elements.detach();
1011 d->ref.storeRelaxed(1);
1012 e.container = d;
1013 } else {
1014 e.container = value.container;
1015 if (disp == CopyContainer)
1016 e.container->ref.ref();
1017 }
1018
1019 e.type = value.type();
1020 e.flags = Element::IsContainer;
1021 } else {
1022 // String data, copy contents
1024
1025 // Copy string data, if any
1026 if (const ByteData *b = value.container->byteData(value.n)) {
1027 const auto flags = e.flags;
1028 // The element e has an invalid e.value, because it is copied from
1029 // value. It means that calling compact() will trigger an assertion
1030 // or just silently corrupt the data.
1031 // Temporarily unset the Element::HasByteData flag in order to skip
1032 // the element e in the call to compact().
1033 e.flags = e.flags & ~Element::HasByteData;
1034 if (this == value.container) {
1035 const QByteArray valueData = b->toByteArray();
1036 compact();
1037 e.value = addByteData(valueData, valueData.size());
1038 } else {
1039 compact();
1040 e.value = addByteData(b->byte(), b->len);
1041 }
1042 // restore the flags
1043 e.flags = flags;
1044 }
1045
1046 if (disp == MoveContainer)
1047 value.container->deref();
1048 }
1049}
1050
1051// in qstring.cpp
1052void qt_to_latin1_unchecked(uchar *dst, const char16_t *uc, qsizetype len);
1053
1055{
1056 qsizetype len = s.size();
1058 e.value = addByteData(nullptr, len);
1060 e.flags = Element::HasByteData | Element::StringIsAscii;
1061 elements.append(e);
1062
1063 char *ptr = data.data() + e.value + sizeof(ByteData);
1064 uchar *l = reinterpret_cast<uchar *>(ptr);
1065 qt_to_latin1_unchecked(l, s.utf16(), len);
1066}
1067
1069{
1070 appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
1071 QCborValue::String, QtCbor::Element::StringIsUtf16);
1072}
1073
1075{
1076 // create a new container for the returned value, containing the byte data
1077 // from this element, if it's worth it
1078 Q_ASSERT(e.flags & Element::HasByteData);
1079 auto b = byteData(e);
1080 auto container = new QCborContainerPrivate;
1081
1082 if (b->len + qsizetype(sizeof(*b)) < data.size() / 4) {
1083 // make a shallow copy of the byte data
1084 container->appendByteData(b->byte(), b->len, e.type, e.flags);
1085 usedData -= b->len + qsizetype(sizeof(*b));
1086 compact();
1087 } else {
1088 // just share with the original byte data
1089 container->data = data;
1090 container->elements.reserve(1);
1091 container->elements.append(e);
1092 }
1093
1094 return makeValue(e.type, 0, container);
1095}
1096
1097// Similar to QStringIterator::next() but returns malformed surrogate pair
1098// itself when one is detected, and returns the length in UTF-8.
1099static auto nextUtf32Character(const char16_t *&ptr, const char16_t *end) noexcept
1100{
1101 Q_ASSERT(ptr != end);
1102 struct R {
1103 char32_t c;
1104 qsizetype len = 1; // in UTF-8 code units (bytes)
1105 } r = { *ptr++ };
1106
1107 if (r.c < 0x0800) {
1108 if (r.c >= 0x0080)
1109 ++r.len;
1110 } else if (!QChar::isHighSurrogate(r.c) || ptr == end) {
1111 r.len += 2;
1112 } else {
1113 r.len += 3;
1114 r.c = QChar::surrogateToUcs4(r.c, *ptr++);
1115 }
1116
1117 return r;
1118}
1119
1120static qsizetype stringLengthInUtf8(const char16_t *ptr, const char16_t *end) noexcept
1121{
1122 qsizetype len = 0;
1123 while (ptr < end)
1124 len += nextUtf32Character(ptr, end).len;
1125 return len;
1126}
1127
1129{
1130 if (mode == Comparison::ForEquality)
1131 return lhs == rhs ? 0 : 1;
1132
1133 // The UTF-16 length is *usually* comparable, but not always. There are
1134 // pathological cases where they can be wrong, so we need to compare as if
1135 // we were doing it in UTF-8. That includes the case of UTF-16 surrogate
1136 // pairs, because qstring.cpp sorts them before U+E000-U+FFFF.
1137 int diff = 0;
1138 qsizetype len1 = 0;
1139 qsizetype len2 = 0;
1140 const char16_t *src1 = lhs.utf16();
1141 const char16_t *src2 = rhs.utf16();
1142 const char16_t *end1 = src1 + lhs.size();
1143 const char16_t *end2 = src2 + rhs.size();
1144
1145 // first, scan until we find a difference (if any)
1146 do {
1147 auto r1 = nextUtf32Character(src1, end1);
1148 auto r2 = nextUtf32Character(src2, end2);
1149 len1 += r1.len;
1150 len2 += r2.len;
1151 diff = int(r1.c) - int(r2.c); // no underflow due to limited range
1152 } while (src1 < end1 && src2 < end2 && diff == 0);
1153
1154 // compute the full length past this first difference
1155 len1 += stringLengthInUtf8(src1, end1);
1156 len2 += stringLengthInUtf8(src2, end2);
1157 if (len1 == len2)
1158 return diff;
1159 return len1 < len2 ? -1 : 1;
1160}
1161
1163{
1164 // CBOR requires that the shortest of the two strings be sorted first, so
1165 // we have to calculate the UTF-8 length of the UTF-16 string while
1166 // comparing. Unlike the UTF-32 comparison above, we convert the UTF-16
1167 // string to UTF-8 so we only need to decode one string.
1168
1169 const qsizetype len1 = lhs.size();
1170 const auto src1 = reinterpret_cast<const uchar *>(lhs.data());
1171 const char16_t *src2 = rhs.utf16();
1172 const char16_t *const end2 = src2 + rhs.size();
1173
1174 // Compare the two strings until we find a difference.
1175 int diff = 0;
1176 qptrdiff idx1 = 0;
1177 qsizetype len2 = 0;
1178 do {
1179 uchar utf8[4]; // longest possible Unicode character in UTF-8
1180 uchar *ptr = utf8;
1181 char16_t uc = *src2++;
1182 int r = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, ptr, src2, end2);
1183 Q_UNUSED(r); // ignore failure to encode proper UTF-16 surrogates
1184
1185 qptrdiff n = ptr - utf8;
1186 len2 += n;
1187 if (len1 - idx1 < n)
1188 return -1; // lhs is definitely shorter
1189 diff = memcmp(src1 + idx1, utf8, n);
1190 idx1 += n;
1191 } while (diff == 0 && idx1 < len1 && src2 < end2);
1192
1193 if (mode == Comparison::ForEquality && diff)
1194 return diff;
1195 if ((idx1 == len1) != (src2 == end2)) {
1196 // One of the strings ended earlier than the other
1197 return idx1 == len1 ? -1 : 1;
1198 }
1199
1200 // We found a difference and neither string ended, so continue calculating
1201 // the UTF-8 length of rhs.
1202 len2 += stringLengthInUtf8(src2, end2);
1203
1204 if (len1 != len2)
1205 return len1 < len2 ? -1 : 1;
1206 return diff;
1207}
1208
1210{
1211 return -compareStringsInUtf8(rhs, lhs, mode);
1212}
1213
1214QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
1216 Comparison mode) noexcept;
1217static int compareElementNoData(const Element &e1, const Element &e2) noexcept
1218{
1219 Q_ASSERT(e1.type == e2.type);
1220
1221 if (e1.type == QCborValue::Integer) {
1222 // CBOR sorting order is 0, 1, 2, ..., INT64_MAX, -1, -2, -3, ... INT64_MIN
1223 // So we transform:
1224 // 0 -> 0
1225 // 1 -> 1
1226 // INT64_MAX -> INT64_MAX
1227 // -1 -> INT64_MAX + 1 = INT64_MAX - (-1)
1228 // -2 -> INT64_MAX + 2 = INT64_MAX - (-2)
1229 // INT64_MIN -> UINT64_MAX = INT64_MAX - INT64_MIN
1230 // Note how the unsigned arithmetic is well defined in C++ (it's
1231 // always performed modulo 2^64).
1232 auto makeSortable = [](qint64 v) {
1233 quint64 u = quint64(v);
1234 if (v < 0)
1235 return quint64(std::numeric_limits<qint64>::max()) + (-u);
1236 return u;
1237 };
1238 quint64 u1 = makeSortable(e1.value);
1239 quint64 u2 = makeSortable(e2.value);
1240 if (u1 < u2)
1241 return -1;
1242 if (u1 > u2)
1243 return 1;
1244 }
1245
1246 if (e1.type == QCborValue::Tag || e1.type == QCborValue::Double) {
1247 // Perform unsigned comparisons for the tag value and floating point
1248 quint64 u1 = quint64(e1.value);
1249 quint64 u2 = quint64(e2.value);
1250 if (u1 != u2)
1251 return u1 < u2 ? -1 : 1;
1252 }
1253
1254 // Any other type is equal at this point:
1255 // - simple types carry no value
1256 // - empty strings, arrays and maps
1257 return 0;
1258}
1259
1261 const QCborContainerPrivate *c2, const Element &e2,
1262 Comparison mode) noexcept
1263{
1264 int cmp = typeOrder(e1.type, e2.type);
1265 if (cmp != 0)
1266 return cmp;
1267
1268 if ((e1.flags & Element::IsContainer) || (e2.flags & Element::IsContainer))
1269 return compareContainer(e1.flags & Element::IsContainer ? e1.container : nullptr,
1270 e2.flags & Element::IsContainer ? e2.container : nullptr, mode);
1271
1272 // string data?
1273 const ByteData *b1 = c1 ? c1->byteData(e1) : nullptr;
1274 const ByteData *b2 = c2 ? c2->byteData(e2) : nullptr;
1275 if (b1 || b2) {
1276 auto len1 = b1 ? b1->len : 0;
1277 auto len2 = b2 ? b2->len : 0;
1278 if (len1 == 0 || len2 == 0)
1279 return len1 < len2 ? -1 : len1 == len2 ? 0 : 1;
1280
1281 // we definitely have data from this point forward
1282 Q_ASSERT(b1);
1283 Q_ASSERT(b2);
1284
1285 // Officially with CBOR, we sort first the string with the shortest
1286 // UTF-8 length. Since US-ASCII is just a subset of UTF-8, its length
1287 // is the UTF-8 length. But the UTF-16 length may not be directly
1288 // comparable.
1289 if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16))
1290 return compareStringsInUtf8(b1->asStringView(), b2->asStringView(), mode);
1291
1292 if (!(e1.flags & Element::StringIsUtf16) && !(e2.flags & Element::StringIsUtf16)) {
1293 // Neither is UTF-16, so lengths are comparable too
1294 // (this case includes byte arrays too)
1295 if (len1 == len2) {
1296 if (mode == Comparison::ForEquality) {
1297 // GCC optimizes this to __memcmpeq(); Clang to bcmp()
1298 return memcmp(b1->byte(), b2->byte(), size_t(len1)) == 0 ? 0 : 1;
1299 }
1300 return memcmp(b1->byte(), b2->byte(), size_t(len1));
1301 }
1302 return len1 < len2 ? -1 : 1;
1303 }
1304
1305 // Only one is UTF-16
1306 if (e1.flags & Element::StringIsUtf16)
1307 return compareStringsInUtf8(b1->asStringView(), b2->asUtf8StringView(), mode);
1308 else
1309 return compareStringsInUtf8(b1->asUtf8StringView(), b2->asStringView(), mode);
1310 }
1311
1312 return compareElementNoData(e1, e2);
1313}
1314
1316 Comparison mode) noexcept
1317{
1318 auto len1 = c1 ? c1->elements.size() : 0;
1319 auto len2 = c2 ? c2->elements.size() : 0;
1320 if (len1 != len2) {
1321 // sort the shorter container first
1322 return len1 < len2 ? -1 : 1;
1323 }
1324
1325 for (qsizetype i = 0; i < len1; ++i) {
1326 const Element &e1 = c1->elements.at(i);
1327 const Element &e2 = c2->elements.at(i);
1328 int cmp = compareElementRecursive(c1, e1, c2, e2, mode);
1329 if (cmp)
1330 return cmp;
1331 }
1332
1333 return 0;
1334}
1335
1337 const QCborContainerPrivate *c2, Element e2,
1338 Comparison mode) noexcept
1339{
1340 return compareElementRecursive(c1, e1, c2, e2, mode);
1341}
1342
1369 const QCborValue &rhs) noexcept
1370{
1373 return compareElementRecursive(lhs.container, e1, rhs.container, e2,
1374 Comparison::ForEquality) == 0;
1375}
1376
1493{
1496 return compareElementRecursive(container, e1, other.container, e2, Comparison::ForOrdering);
1497}
1498
1499bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
1500{
1501 return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
1502}
1503
1504int QCborArray::compare(const QCborArray &other) const noexcept
1505{
1506 return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
1507}
1508
1509bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1510{
1511 if (typeOrder(QCborValue::Array, rhs.type()))
1512 return false;
1513 return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
1514}
1515
1517QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1518{
1519 int c = typeOrder(QCborValue::Array, rhs.type());
1520 if (c == 0)
1521 c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
1522 return Qt::compareThreeWay(c, 0);
1523}
1524
1525bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
1526{
1527 return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
1528}
1529
1530int QCborMap::compare(const QCborMap &other) const noexcept
1531{
1532 return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
1533}
1534
1535bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1536{
1537 if (typeOrder(QCborValue::Map, rhs.type()))
1538 return false;
1539 return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
1540}
1541
1543QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1544{
1545 int c = typeOrder(QCborValue::Map, rhs.type());
1546 if (c == 0)
1547 c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
1548 return Qt::compareThreeWay(c, 0);
1549}
1550
1551#if QT_CONFIG(cborstreamwriter)
1552static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate *d, qsizetype idx,
1553 QCborValue::EncodingOptions opt)
1554{
1555 if (idx == -QCborValue::Array || idx == -QCborValue::Map) {
1556 bool isArray = (idx == -QCborValue::Array);
1557 qsizetype len = d ? d->elements.size() : 0;
1558 if (isArray)
1559 writer.startArray(quint64(len));
1560 else
1561 writer.startMap(quint64(len) / 2);
1562
1563 for (idx = 0; idx < len; ++idx)
1564 encodeToCbor(writer, d, idx, opt);
1565
1566 if (isArray)
1567 writer.endArray();
1568 else
1569 writer.endMap();
1570 } else if (idx < 0) {
1571 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1572 if (d->elements.size() != 2) {
1573 // invalid state!
1574 qWarning("QCborValue: invalid tag state; are you encoding something that was improperly decoded?");
1575 return;
1576 }
1577
1578 // write the tag and the tagged element
1579 writer.append(QCborTag(d->elements.at(0).value));
1580 encodeToCbor(writer, d, 1, opt);
1581 } else {
1582 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1583 // just one element
1584 auto e = d->elements.at(idx);
1585 const ByteData *b = d->byteData(idx);
1586 switch (e.type) {
1588 return writer.append(qint64(e.value));
1589
1591 if (b)
1592 return writer.appendByteString(b->byte(), b->len);
1593 return writer.appendByteString("", 0);
1594
1595 case QCborValue::String:
1596 if (b) {
1597 if (e.flags & Element::StringIsUtf16)
1598 return writer.append(b->asStringView());
1599 return writer.appendTextString(b->byte(), b->len);
1600 }
1601 return writer.append(QLatin1StringView());
1602
1603 case QCborValue::Array:
1604 case QCborValue::Map:
1605 case QCborValue::Tag:
1606 // recurse
1607 return encodeToCbor(writer,
1608 e.flags & Element::IsContainer ? e.container : nullptr,
1609 -qsizetype(e.type), opt);
1610
1612 case QCborValue::False:
1613 case QCborValue::True:
1614 case QCborValue::Null:
1616 break;
1617
1618 case QCborValue::Double:
1619 return writeDoubleToCbor(writer, e.fpvalue(), opt);
1620
1622 return;
1623
1625 case QCborValue::Url:
1627 case QCborValue::Uuid:
1628 // recurse as tag
1629 return encodeToCbor(writer, e.container, -QCborValue::Tag, opt);
1630 }
1631
1632 // maybe it's a simple type
1633 int simpleType = e.type - QCborValue::SimpleType;
1634 if (unsigned(simpleType) < 0x100)
1635 return writer.append(QCborSimpleType(simpleType));
1636
1637 // if we got here, we've got an unknown type
1638 qWarning("QCborValue: found unknown type 0x%x", e.type);
1639 }
1640}
1641#endif // QT_CONFIG(cborstreamwriter)
1642
1643#if QT_CONFIG(cborstreamreader)
1644static inline double integerOutOfRange(const QCborStreamReader &reader)
1645{
1646 Q_ASSERT(reader.isInteger());
1647 if (reader.isUnsignedInteger()) {
1648 quint64 v = reader.toUnsignedInteger();
1649 if (qint64(v) < 0)
1650 return double(v);
1651 } else {
1652 quint64 v = quint64(reader.toNegativeInteger());
1653 if (qint64(v - 1) < 0)
1654 return -double(v);
1655 }
1656
1657 // result is in range
1658 return 0;
1659}
1660
1661static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
1662{
1663 Element e = {};
1664
1665 switch (reader.type()) {
1668 if (double d = integerOutOfRange(reader)) {
1670 qToUnaligned(d, &e.value);
1671 } else {
1673 e.value = reader.toInteger();
1674 }
1675 break;
1677 e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
1678 break;
1681 qToUnaligned(double(reader.toFloat16()), &e.value);
1682 break;
1685 qToUnaligned(double(reader.toFloat()), &e.value);
1686 break;
1689 qToUnaligned(reader.toDouble(), &e.value);
1690 break;
1691
1692 default:
1693 Q_UNREACHABLE();
1694 }
1695
1696 reader.next();
1697 return e;
1698}
1699
1700// Clamp allocation to avoid crashing due to corrupt stream. This also
1701// ensures we never overflow qsizetype. The returned length is doubled for Map
1702// entries to account for key-value pairs.
1703static qsizetype clampedContainerLength(const QCborStreamReader &reader)
1704{
1705 if (!reader.isLengthKnown())
1706 return 0;
1707 int mapShift = reader.isMap() ? 1 : 0;
1708 quint64 shiftedMaxElements = MaximumPreallocatedElementCount >> mapShift;
1709 qsizetype len = qsizetype(qMin(reader.length(), shiftedMaxElements));
1710 return len << mapShift;
1711}
1712
1713static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1714{
1715 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1716 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1717 return nullptr;
1718 }
1719
1720 QCborContainerPrivate *d = nullptr;
1721 {
1722 // in case QList::reserve throws
1724 if (qsizetype len = clampedContainerLength(reader))
1725 u->elements.reserve(len);
1726 d = u.take();
1727 }
1728
1729 reader.enterContainer();
1730 if (reader.lastError() != QCborError::NoError) {
1731 d->elements.clear();
1732 return d;
1733 }
1734
1735 while (reader.hasNext() && reader.lastError() == QCborError::NoError)
1736 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1737
1738 if (reader.lastError() == QCborError::NoError)
1739 reader.leaveContainer();
1740 else
1741 d->elements.squeeze();
1742
1743 return d;
1744}
1745
1746static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1747{
1748 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1749 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1750 return QCborValue::Invalid;
1751 }
1752
1753 auto d = new QCborContainerPrivate;
1754 d->append(reader.toTag());
1755 reader.next();
1756
1757 if (reader.lastError() == QCborError::NoError) {
1758 // decode tagged value
1759 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1760 }
1761
1763 if (reader.lastError() == QCborError::NoError) {
1764 // post-process to create our extended types
1766 } else {
1767 // decoding error
1769 }
1770
1771 // note: may return invalid state!
1773}
1774
1775// in qcborstream.cpp
1777inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
1778{
1780}
1781
1783
1784void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
1785{
1786 if (reader.lastError() != QCborError::NoError)
1787 return;
1788
1789 qsizetype rawlen = reader.currentStringChunkSize();
1790 QByteArray::size_type len = rawlen;
1791 if (rawlen < 0)
1792 return; // error
1793 if (len != rawlen) {
1794 // truncation
1795 setErrorInReader(reader, { QCborError::DataTooLarge });
1796 return;
1797 }
1798
1799 Element e = {};
1800 e.type = (reader.isByteArray() ? QCborValue::ByteArray : QCborValue::String);
1801 if (len || !reader.isLengthKnown()) {
1802 // The use of size_t means none of the operations here can overflow because
1803 // all inputs are less than half SIZE_MAX.
1804 constexpr size_t EstimatedOverhead = 16;
1805 constexpr size_t MaxMemoryIncrement = 16384;
1806 size_t offset = data.size();
1807
1808 // add space for aligned ByteData (this can't overflow)
1809 offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
1810 offset &= ~(alignof(QtCbor::ByteData) - 1);
1811 if (offset > size_t(QByteArray::max_size())) {
1812 // overflow
1813 setErrorInReader(reader, { QCborError::DataTooLarge });
1814 return;
1815 }
1816
1817 // and calculate the size we want to have
1818 size_t newCapacity = offset + len; // can't overflow
1819 if (size_t(len) > MaxMemoryIncrement - EstimatedOverhead) {
1820 // there's a non-zero chance that we won't need this memory at all,
1821 // so capa how much we allocate
1822 newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
1823 }
1824 if (newCapacity > size_t(QByteArray::max_size())) {
1825 // this may cause an allocation failure
1826 newCapacity = QByteArray::max_size();
1827 }
1828 if (newCapacity > size_t(data.capacity()))
1829 data.reserve(newCapacity);
1830 data.resize(offset + sizeof(QtCbor::ByteData));
1831 e.value = offset;
1832 e.flags = Element::HasByteData;
1833 }
1834
1835 // read chunks
1836 bool isAscii = (e.type == QCborValue::String);
1838 while (status == QCborStreamReader::Ok) {
1839 if (e.type == QCborValue::String && len) {
1840 // verify UTF-8 string validity
1841 auto utf8result = QUtf8::isValidUtf8(QByteArrayView(data).last(len));
1842 if (!utf8result.isValidUtf8) {
1843 status = QCborStreamReader::Error;
1844 setErrorInReader(reader, { QCborError::InvalidUtf8String });
1845 break;
1846 }
1847 isAscii = isAscii && utf8result.isValidAscii;
1848 }
1849
1850 rawlen = reader.currentStringChunkSize();
1851 len = rawlen;
1852 if (len == rawlen) {
1853 status = qt_cbor_append_string_chunk(reader, &data);
1854 } else {
1855 // error
1856 status = QCborStreamReader::Error;
1857 setErrorInReader(reader, { QCborError::DataTooLarge });
1858 }
1859 }
1860
1861 // update size
1862 if (status == QCborStreamReader::EndOfString && e.flags & Element::HasByteData) {
1863 Q_ASSERT(data.isDetached());
1864 const char *ptr = data.constData() + e.value;
1865 auto b = new (const_cast<char *>(ptr)) ByteData;
1866 b->len = data.size() - e.value - int(sizeof(*b));
1867 usedData += b->len;
1868
1869 if (isAscii) {
1870 // set the flag if it is US-ASCII only (as it often is)
1872 e.flags |= Element::StringIsAscii;
1873 }
1874
1875 // check that this UTF-8 text string can be loaded onto a QString
1876 if (e.type == QCborValue::String) {
1877 if (Q_UNLIKELY(b->len > QString::max_size())) {
1878 setErrorInReader(reader, { QCborError::DataTooLarge });
1879 status = QCborStreamReader::Error;
1880 }
1881 }
1882 }
1883
1884 if (status == QCborStreamReader::Error) {
1885 data.truncate(e.value);
1886 } else {
1887 elements.append(e);
1888 }
1889}
1890
1891void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1892{
1894 switch (t) {
1901 elements.append(decodeBasicValueFromCbor(reader));
1902 break;
1903
1906 decodeStringFromCbor(reader);
1907 break;
1908
1912 createContainerFromCbor(reader, remainingRecursionDepth),
1913 MoveContainer));
1914
1916 return append(taggedValueFromCbor(reader, remainingRecursionDepth));
1917
1919 return; // probably a decode error
1920 }
1921}
1922#endif // QT_CONFIG(cborstreamreader)
1923
1931 : n(0), container(new QCborContainerPrivate), t(ByteArray)
1932{
1933 container->appendByteData(ba.constData(), ba.size(), t);
1934 container->ref.storeRelaxed(1);
1935}
1936
1944
1952 : n(0), container(new QCborContainerPrivate), t(String)
1953{
1954 container->append(s);
1955 container->ref.storeRelaxed(1);
1956}
1957
1967 : n(0), container(new QCborContainerPrivate), t(String)
1968{
1969 container->append(s);
1970 container->ref.storeRelaxed(1);
1971}
1972
1983 : n(-1), container(a.d.data()), t(Array)
1984{
1985 if (container)
1986 container->ref.ref();
1987}
1988
1999 : n(-1), container(m.d.data()), t(Map)
2000{
2001 if (container)
2002 container->ref.ref();
2003}
2004
2016 : n(-1), container(new QCborContainerPrivate), t(Tag)
2017{
2018 container->ref.storeRelaxed(1);
2019 container->append(tag);
2020 container->append(tv);
2021 t = convertToExtendedType(container);
2022}
2023
2028 : n(other.n), container(other.container), t(other.t)
2029{
2030 if (container)
2031 container->ref.ref();
2032}
2033
2048 : QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1())
2049{
2050 // change types
2051 t = DateTime;
2052 container->elements[1].type = String;
2053}
2054
2055#ifndef QT_BOOTSTRAPPED
2066 : QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8())
2067{
2068 // change types
2069 t = Url;
2070 container->elements[1].type = String;
2071}
2072
2073#if QT_CONFIG(regularexpression)
2088{
2089 // change type
2091}
2092#endif // QT_CONFIG(regularexpression)
2093
2105 : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
2106{
2107 // change our type
2108 t = Uuid;
2109}
2110#endif
2111
2112// destructor
2113void QCborValue::dispose()
2114{
2115 container->deref();
2116}
2117
2122{
2123 n = other.n;
2124 assignContainer(container, other.container);
2125 t = other.t;
2126 return *this;
2127}
2128
2140{
2141 return isTag() && container && container->elements.size() == 2 ?
2142 QCborTag(container->elements.at(0).value) : defaultValue;
2143}
2144
2156{
2157 return isTag() && container && container->elements.size() == 2 ?
2158 container->valueAt(1) : defaultValue;
2159}
2160
2171{
2172 if (!container || !isByteArray())
2173 return defaultValue;
2174
2175 Q_ASSERT(n >= 0);
2176 return container->byteArrayAt(n);
2177}
2178
2188QString QCborValue::toString(const QString &defaultValue) const
2189{
2190 if (!container || !isString())
2191 return defaultValue;
2192
2193 Q_ASSERT(n >= 0);
2194 return container->stringAt(n);
2195}
2196
2207{
2208 if (!container || !isDateTime() || container->elements.size() != 2)
2209 return defaultValue;
2210
2211 Q_ASSERT(n == -1);
2212 const ByteData *byteData = container->byteData(1);
2213 if (!byteData)
2214 return defaultValue; // date/times are never empty, so this must be invalid
2215
2216 // Our data must be US-ASCII.
2217 Q_ASSERT((container->elements.at(1).flags & Element::StringIsUtf16) == 0);
2218 return QDateTime::fromString(byteData->asLatin1(), Qt::ISODateWithMs);
2219}
2220
2221#ifndef QT_BOOTSTRAPPED
2230QUrl QCborValue::toUrl(const QUrl &defaultValue) const
2231{
2232 if (!container || !isUrl() || container->elements.size() != 2)
2233 return defaultValue;
2234
2235 Q_ASSERT(n == -1);
2236 const ByteData *byteData = container->byteData(1);
2237 if (!byteData)
2238 return QUrl(); // valid, empty URL
2239
2240 return QUrl::fromEncoded(byteData->asByteArrayView());
2241}
2242
2243#if QT_CONFIG(regularexpression)
2254QRegularExpression QCborValue::toRegularExpression(const QRegularExpression &defaultValue) const
2255{
2256 if (!container || !isRegularExpression() || container->elements.size() != 2)
2257 return defaultValue;
2258
2259 Q_ASSERT(n == -1);
2260 return QRegularExpression(container->stringAt(1));
2261}
2262#endif // QT_CONFIG(regularexpression)
2263
2272QUuid QCborValue::toUuid(const QUuid &defaultValue) const
2273{
2274 if (!container || !isUuid() || container->elements.size() != 2)
2275 return defaultValue;
2276
2277 Q_ASSERT(n == -1);
2278 const ByteData *byteData = container->byteData(1);
2279 if (!byteData)
2280 return defaultValue; // UUIDs must always be 16 bytes, so this must be invalid
2281
2282 return QUuid::fromRfc4122(byteData->asByteArrayView());
2283}
2284#endif
2285
2313{
2314 return toArray(QCborArray());
2315}
2316
2318{
2319 if (!isArray())
2320 return defaultValue;
2321 QCborContainerPrivate *dd = nullptr;
2322 Q_ASSERT(n == -1 || container == nullptr);
2323 if (n < 0)
2324 dd = container;
2325 // return QCborArray(*dd); but that's UB if dd is nullptr
2326 return dd ? QCborArray(*dd) : QCborArray();
2327}
2328
2356{
2357 return toMap(QCborMap());
2358}
2359
2360QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2361{
2362 if (!isMap())
2363 return defaultValue;
2364 QCborContainerPrivate *dd = nullptr;
2365 Q_ASSERT(n == -1 || container == nullptr);
2366 if (n < 0)
2367 dd = container;
2368 // return QCborMap(*dd); but that's UB if dd is nullptr
2369 return dd ? QCborMap(*dd) : QCborMap();
2370}
2371
2388
2407
2420{
2421 if (isArray() && container && quint64(key) < quint64(container->elements.size()))
2422 return container->valueAt(key);
2424}
2425
2427{
2428 constexpr qint64 LargeKey = 0x10000;
2429 if (t != QCborValue::Array)
2430 return false;
2431 if (key < 0)
2432 return false; // negative keys can't be an array index
2433 if (key < LargeKey)
2434 return true;
2435
2436 // Only convert to map if key is greater than array size + 1
2437 qsizetype currentSize = container ? container->elements.size() : 0;
2438 return key <= currentSize;
2439}
2440
2445{
2446 if (Q_LIKELY(!array || array->elements.isEmpty()))
2447 return;
2448
2449 // The Q_LIKELY and the qWarning mark the rest of this function as unlikely
2450 qWarning("Using CBOR array as map forced conversion");
2451
2452 qsizetype size = array->elements.size();
2454 map->elements.resize(size * 2);
2455
2456 // this may be an in-place copy, so we have to do it from the end
2457 auto dst = map->elements.begin();
2458 auto src = array->elements.constBegin();
2459 for (qsizetype i = size - 1; i >= 0; --i) {
2461 dst[i * 2 + 1] = src[i];
2462 }
2463 for (qsizetype i = 0; i < size; ++i)
2464 dst[i * 2] = { i, QCborValue::Integer };
2465
2466 // update reference counts
2468}
2469
2474{
2475 auto replace = QCborContainerPrivate::grow(container, index);
2476 Q_ASSERT(replace);
2477 if (replace->elements.size() == index)
2478 replace->append(Undefined());
2479 else
2480 Q_ASSERT(replace->elements.size() > index);
2481 return assignContainer(container, replace);
2482}
2483
2484template <typename KeyType> inline QCborValueRef
2486{
2487 // we need a map, so convert if necessary
2488 if (self.isArray())
2489 convertArrayToMap(self.container);
2490 else if (!self.isMap())
2492 self.t = QCborValue::Map;
2493 self.n = -1;
2494
2495 QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
2496 assignContainer(self.container, result.d);
2497 return result;
2498}
2499
2500template<typename KeyType> QCborValueRef
2502{
2503 auto &e = self.d->elements[self.i];
2504
2505 // we need a map, so convert if necessary
2506 if (e.type == QCborValue::Array) {
2508 } else if (e.type != QCborValue::Map) {
2509 if (e.flags & QtCbor::Element::IsContainer)
2510 e.container->deref();
2511 e.container = nullptr;
2512 }
2513 e.flags = QtCbor::Element::IsContainer;
2515
2516 QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
2518 return result;
2519}
2520
2538
2558
2576{
2577 if (shouldArrayRemainArray(key, t, container)) {
2578 container = maybeGrow(container, key);
2579 return { container, qsizetype(key) };
2580 }
2582}
2583
2584#if QT_CONFIG(cborstreamreader)
2605QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
2606{
2608 auto t = reader.type();
2609 if (reader.lastError() != QCborError::NoError)
2611
2612 switch (t) {
2613 // basic types, no container needed:
2620 Element e = decodeBasicValueFromCbor(reader);
2621 result.n = e.value;
2622 result.t = e.type;
2623 break;
2624 }
2625
2628 break; // probably a decode error
2629
2630 // strings
2633 result.n = 0;
2634 result.t = reader.isString() ? String : ByteArray;
2635 result.container = new QCborContainerPrivate;
2636 result.container->ref.ref();
2637 result.container->decodeStringFromCbor(reader);
2638 break;
2639
2640 // containers
2643 result.n = -1;
2644 result.t = reader.isArray() ? Array : Map;
2645 result.container = createContainerFromCbor(reader, MaximumRecursionDepth);
2646 break;
2647
2648 // tag
2650 result = taggedValueFromCbor(reader, MaximumRecursionDepth);
2651 break;
2652 }
2653
2654 return result;
2655}
2656
2679QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
2680{
2682 QCborValue result = fromCbor(reader);
2683 if (error) {
2684 error->error = reader.lastError();
2685 error->offset = reader.currentOffset();
2686 }
2687 return result;
2688}
2689
2699#endif // QT_CONFIG(cborstreamreader)
2700
2701#if QT_CONFIG(cborstreamwriter)
2728QByteArray QCborValue::toCbor(EncodingOptions opt) const
2729{
2731 QCborStreamWriter writer(&result);
2732 toCbor(writer, opt);
2733 return result;
2734}
2735
2765Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt) const
2766{
2767 if (isContainer() || isTag())
2768 return encodeToCbor(writer, container, -type(), opt);
2769 if (container)
2770 return encodeToCbor(writer, container, n, opt);
2771
2772 // very simple types
2773 if (isSimpleType())
2774 return writer.append(toSimpleType());
2775
2776 switch (type()) {
2777 case Integer:
2778 return writer.append(n);
2779
2780 case Double:
2781 return writeDoubleToCbor(writer, fp_helper(), opt);
2782
2783 case Invalid:
2784 return;
2785
2786 case SimpleType:
2787 case False:
2788 case True:
2789 case Null:
2790 case Undefined:
2791 // handled by "if (isSimpleType())"
2792 Q_UNREACHABLE();
2793 break;
2794
2795 case ByteArray:
2796 // Byte array with no container is empty
2797 return writer.appendByteString("", 0);
2798
2799 case String:
2800 // String with no container is empty
2801 return writer.appendTextString("", 0);
2802
2803 case Array:
2804 case Map:
2805 case Tag:
2806 // handled by "if (isContainer() || isTag())"
2807 Q_UNREACHABLE();
2808 break;
2809
2810 case DateTime:
2811 case Url:
2812 case RegularExpression:
2813 case Uuid:
2814 // not possible
2815 Q_UNREACHABLE();
2816 break;
2817 }
2818}
2819
2820# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
2821void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
2822{
2823 concrete().toCbor(writer, opt);
2824}
2825# endif
2826#endif // QT_CONFIG(cborstreamwriter)
2827
2828void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
2829{
2830 that.d->replaceAt(that.i, other);
2831}
2832
2833void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
2834{
2835 that.d->replaceAt(that.i, other, QCborContainerPrivate::MoveContainer);
2836}
2837
2838void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
2839{
2840 // ### optimize?
2841 that = other.concrete();
2842}
2843
2844bool QCborValueConstRef::concreteBoolean(QCborValueConstRef self, bool defaultValue) noexcept
2845{
2846 QtCbor::Element e = self.d->elements.at(self.i);
2848 return defaultValue;
2849 return e.type == QCborValue::True;
2850}
2851
2852double QCborValueConstRef::concreteDouble(QCborValueConstRef self, double defaultValue) noexcept
2853{
2854 QtCbor::Element e = self.d->elements.at(self.i);
2855 if (e.type == QCborValue::Integer)
2856 return e.value;
2857 if (e.type != QCborValue::Double)
2858 return defaultValue;
2859 return e.fpvalue();
2860}
2861
2863{
2864 QtCbor::Element e = self.d->elements.at(self.i);
2866 if (t == QCborValue::Double)
2867 return e.fpvalue();
2868 if (t != QCborValue::Integer)
2869 return defaultValue;
2870 return e.value;
2871}
2872
2874 const QByteArray &defaultValue)
2875{
2876 QtCbor::Element e = self.d->elements.at(self.i);
2877 if (e.type != QCborValue::ByteArray)
2878 return defaultValue;
2879 return self.d->byteArrayAt(self.i);
2880}
2881
2883{
2884 QtCbor::Element e = self.d->elements.at(self.i);
2885 if (e.type != QCborValue::String)
2886 return defaultValue;
2887 return self.d->stringAt(self.i);
2888}
2889
2890bool
2892{
2893 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
2894 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2895 return compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForEquality) == 0;
2896}
2897
2900{
2901 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
2902 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2903 int c = compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForOrdering);
2904 return Qt::compareThreeWay(c, 0);
2905}
2906
2907bool
2909{
2910 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
2912 return compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForEquality) == 0;
2913}
2914
2917{
2918 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
2920 int c = compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForOrdering);
2921 return Qt::compareThreeWay(c, 0);
2922}
2923
2924bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2925{
2926 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2928 return false;
2929 return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
2930}
2931
2933QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2934{
2935 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2936 int c = typeOrder(QCborValue::Array, e2.type);
2937 if (c == 0)
2938 c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
2939 return Qt::compareThreeWay(c, 0);
2940}
2941
2942bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
2943{
2944 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2946 return false;
2947 return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
2948}
2949
2951QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
2952{
2953 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
2954 int c = typeOrder(QCborValue::Map, e2.type);
2955 if (c == 0)
2956 c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
2957 return Qt::compareThreeWay(c, 0);
2958}
2959
2961{
2962 return self.d->valueAt(self.i);
2963}
2964
2966{
2967 return self.d->elements.at(self.i).type;
2968}
2969
2971{
2972 const QCborValue item = d->valueAt(i);
2973 return item[key];
2974}
2975
2977{
2978 const QCborValue item = d->valueAt(i);
2979 return item[key];
2980}
2981
2983{
2984 const QCborValue item = d->valueAt(i);
2985 return item[key];
2986}
2987
2988#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
2989QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
2990{
2991 return self.d->valueAt(self.i);
2992}
2993
2994QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
2995{
2996 return self.d->elements.at(self.i).type;
2997}
2998
3013const QCborValue QCborValueRef::operator[](const QString &key) const
3014{
3016}
3017
3034const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
3035{
3037}
3038
3051const QCborValue QCborValueRef::operator[](qint64 key) const
3052{
3054}
3055
3070QCborValueRef QCborValueRef::operator[](const QString &key)
3071{
3073}
3074
3090QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
3091{
3093}
3094
3111QCborValueRef QCborValueRef::operator[](qint64 key)
3112{
3113 auto &e = d->elements[i];
3117 return { e.container, qsizetype(key) };
3118 }
3120}
3121#endif // < Qt 7
3122
3124 : d(&dd)
3125{
3126}
3127
3128inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept
3129 : d(&dd)
3130{
3131}
3132
3133size_t qHash(const QCborValue &value, size_t seed)
3134{
3135 switch (value.type()) {
3137 return qHash(value.toInteger(), seed);
3139 return qHash(value.toByteArray(), seed);
3140 case QCborValue::String:
3141 return qHash(value.toString(), seed);
3142 case QCborValue::Array:
3143 return qHash(value.toArray(), seed);
3144 case QCborValue::Map:
3145 return qHash(value.toMap(), seed);
3146 case QCborValue::Tag: {
3148 seed = hash(seed, value.tag());
3149 seed = hash(seed, value.taggedValue());
3150 return seed;
3151 }
3153 break;
3154 case QCborValue::False:
3155 return qHash(false, seed);
3156 case QCborValue::True:
3157 return qHash(true, seed);
3158 case QCborValue::Null:
3159 return qHash(nullptr, seed);
3161 return seed;
3162 case QCborValue::Double:
3163 return qHash(value.toDouble(), seed);
3165 return qHash(value.toDateTime(), seed);
3166#ifndef QT_BOOTSTRAPPED
3167 case QCborValue::Url:
3168 return qHash(value.toUrl(), seed);
3169# if QT_CONFIG(regularexpression)
3171 return qHash(value.toRegularExpression(), seed);
3172# endif
3173 case QCborValue::Uuid:
3174 return qHash(value.toUuid(), seed);
3175#endif
3177 return seed;
3178 default:
3179 break;
3180 }
3181
3182 Q_ASSERT(value.isSimpleType());
3183 return qHash(value.toSimpleType(), seed);
3184}
3185
3186Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
3187{
3188 switch (st) {
3190 return "False";
3192 return "True";
3194 return "Null";
3196 return "Undefined";
3197 }
3198 return nullptr;
3199}
3200
3201Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
3202{
3203 // Casting to QCborKnownTags's underlying type will make the comparison
3204 // below fail if the tag value is out of range.
3205 auto n = std::underlying_type<QCborKnownTags>::type(tag);
3206 if (QCborTag(n) == tag) {
3207 switch (QCborKnownTags(n)) {
3209 return "DateTimeString";
3211 return "UnixTime_t";
3213 return "PositiveBignum";
3215 return "NegativeBignum";
3217 return "Decimal";
3219 return "Bigfloat";
3221 return "COSE_Encrypt0";
3223 return "COSE_Mac0";
3225 return "COSE_Sign1";
3227 return "ExpectedBase64url";
3229 return "ExpectedBase64";
3231 return "ExpectedBase16";
3233 return "EncodedCbor";
3235 return "Url";
3237 return "Base64url";
3239 return "Base64";
3241 return "RegularExpression";
3243 return "MimeMessage";
3245 return "Uuid";
3247 return "COSE_Encrypt";
3249 return "COSE_Mac";
3251 return "COSE_Sign";
3253 return "Signature";
3254 }
3255 }
3256 return nullptr;
3257}
3258
3259#if !defined(QT_NO_DEBUG_STREAM)
3261{
3262 switch (v.type()) {
3264 return dbg << v.toInteger();
3266 return dbg << "QByteArray(" << v.toByteArray() << ')';
3267 case QCborValue::String:
3268 return dbg << v.toString();
3269 case QCborValue::Array:
3270 return dbg << v.toArray();
3271 case QCborValue::Map:
3272 return dbg << v.toMap();
3273 case QCborValue::Tag: {
3274 QCborTag tag = v.tag();
3275 const char *id = qt_cbor_tag_id(tag);
3276 if (id)
3277 dbg.nospace() << "QCborKnownTags::" << id << ", ";
3278 else
3279 dbg.nospace() << "QCborTag(" << quint64(tag) << "), ";
3280 return dbg << v.taggedValue();
3281 }
3283 break;
3284 case QCborValue::True:
3285 return dbg << true;
3286 case QCborValue::False:
3287 return dbg << false;
3288 case QCborValue::Null:
3289 return dbg << "nullptr";
3291 return dbg;
3292 case QCborValue::Double: {
3293 qint64 i;
3294 if (convertDoubleTo(v.toDouble(), &i))
3295 return dbg << i << ".0";
3296 else
3297 return dbg << v.toDouble();
3298 }
3300 return dbg << v.toDateTime();
3301#ifndef QT_BOOTSTRAPPED
3302 case QCborValue::Url:
3303 return dbg << v.toUrl();
3304#if QT_CONFIG(regularexpression)
3306 return dbg << v.toRegularExpression();
3307#endif
3308 case QCborValue::Uuid:
3309 return dbg << v.toUuid();
3310#endif
3312 return dbg << "<invalid>";
3313 default:
3314 break;
3315 }
3316 if (v.isSimpleType())
3317 return dbg << v.toSimpleType();
3318 return dbg << "<unknown type 0x" << Qt::hex << int(v.type()) << Qt::dec << '>';
3319}
3321{
3322 QDebugStateSaver saver(dbg);
3323 dbg.nospace() << "QCborValue(";
3324 return debugContents(dbg, v) << ')';
3325}
3326
3328{
3329 QDebugStateSaver saver(dbg);
3330 const char *id = qt_cbor_simpletype_id(st);
3331 if (id)
3332 return dbg.nospace() << "QCborSimpleType::" << id;
3333
3334 return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
3335}
3336
3338{
3339 QDebugStateSaver saver(dbg);
3340 const char *id = qt_cbor_tag_id(tag);
3341 dbg.nospace() << "QCborTag(";
3342 if (id)
3343 dbg.nospace() << "QCborKnownTags::" << id;
3344 else
3345 dbg.nospace() << quint64(tag);
3346
3347 return dbg << ')';
3348}
3349
3351{
3352 QDebugStateSaver saver(dbg);
3353 const char *id = qt_cbor_tag_id(QCborTag(int(tag)));
3354 if (id)
3355 return dbg.nospace() << "QCborKnownTags::" << id;
3356
3357 return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
3358}
3359#endif
3360
3361#ifndef QT_NO_DATASTREAM
3362#if QT_CONFIG(cborstreamwriter)
3364{
3365 stream << QCborValue(value).toCbor();
3366 return stream;
3367}
3368#endif
3369
3371{
3373 stream >> buffer;
3374 QCborParserError parseError{};
3375 value = QCborValue::fromCbor(buffer, &parseError);
3376 if (parseError.error)
3377 stream.setStatus(QDataStream::ReadCorruptData);
3378 return stream;
3379}
3380#endif
3381
3382
3384
3385#include "qcborarray.cpp"
3386#include "qcbormap.cpp"
3387
3388#ifndef QT_NO_QOBJECT
3389#include "moc_qcborvalue.cpp"
3390#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:494
qsizetype size_type
Definition qbytearray.h:459
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:634
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static constexpr qsizetype max_size() noexcept
Definition qbytearray.h:485
\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 int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1, const QCborContainerPrivate *c2, QtCbor::Element e2, QtCbor::Comparison mode) noexcept
static QCborContainerPrivate * detach(QCborContainerPrivate *d, qsizetype reserved)
QCborValueConstRef findCborMapKey(KeyType key)
QList< QtCbor::Element > elements
void appendNonAsciiString(QStringView s)
void append(QtCbor::Undefined)
static qptrdiff addByteDataImpl(QByteArray &target, QByteArray::size_type &targetUsed, const char *block, qsizetype len)
QByteArray byteArrayAt(qsizetype idx) const
static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d=nullptr, ContainerDisposition disp=CopyContainer)
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:173
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
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
static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
QCborContainerPrivate * d
Definition qcborvalue.h:444
static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
static Q_CORE_EXPORT bool concreteBoolean(QCborValueConstRef that, bool defaultValue) noexcept Q_DECL_PURE_FUNCTION
QCborValue concrete() const noexcept
Definition qcborvalue.h:394
\inmodule QtCore\reentrant
Definition qcborvalue.h:47
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:174
friend class QCborMap
Definition qcborvalue.h:263
bool isDateTime() const
Returns true if this QCborValue is of the date/time type.
Definition qcborvalue.h:167
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:157
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:168
bool isByteArray() const
Returns true if this QCborValue is of the byte array type.
Definition qcborvalue.h:156
Type
This enum represents the QCborValue type.
Definition qcborvalue.h:70
@ RegularExpression
Definition qcborvalue.h:90
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:97
bool isRegularExpression() const
Returns true if this QCborValue contains a regular expression's pattern.
Definition qcborvalue.h:169
bool isContainer() const
This convenience function returns true if the QCborValue is either an array or a map.
Definition qcborvalue.h:172
friend class QCborContainerPrivate
Definition qcborvalue.h:266
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:154
QCborSimpleType toSimpleType(QCborSimpleType defaultValue=QCborSimpleType::Undefined) const
Returns the simple type this QCborValue is of, if it is a simple type.
Definition qcborvalue.h:182
bool isTag() const
Returns true if this QCborValue is of the tag type.
Definition qcborvalue.h:160
bool isArray() const
Returns true if this QCborValue is of the array type.
Definition qcborvalue.h:158
bool isUuid() const
Returns true if this QCborValue contains a UUID.
Definition qcborvalue.h:170
QCborTag tag(QCborTag defaultValue=QCborTag(-1)) const
Returns the tag of this extended QCborValue object, if it is of the tag type, defaultValue otherwise.
friend class QCborArray
Definition qcborvalue.h:262
bool isMap() const
Returns true if this QCborValue is of the map type.
Definition qcborvalue.h:159
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:46
\inmodule QtCore\reentrant
Definition qdatetime.h:283
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
\inmodule QtCore
\inmodule QtCore
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
iterator begin()
Definition qmap.h:598
\inmodule QtCore \reentrant
QAtomicInt ref
Definition qshareddata.h:21
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static constexpr qsizetype max_size() noexcept
Definition qstring.h:964
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QByteArray toUtf8() const &
Definition qstring.h:634
\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:1882
@ 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:2988
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
\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:595
\inmodule QtCore \title Classes and helpers for defining comparison operators \keyword qtcompare
Definition qcompare.h:400
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
QHash< int, QWidget * > hash
[35multi]
QMap< QString, QString > map
[6]
QString text
QStyleOptionButton opt
Combined button and popup list for selecting options.
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1StringView s) noexcept
Definition qstring.cpp:850
Definition qcompare.h:63
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.
constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
@ ISODateWithMs
QString self
Definition language.cpp:58
QImageReader reader("image.png")
[1]
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 typeOrder(QCborValue::Type e1, QCborValue::Type 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:1188
static int compareStringsInUtf8(QStringView lhs, QStringView rhs, Comparison mode) noexcept
static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
static auto nextUtf32Character(const char16_t *&ptr, const char16_t *end) noexcept
static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2, Comparison mode) noexcept
QDebug operator<<(QDebug dbg, const QCborValue &v)
static QCborContainerPrivate * assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
size_t qHash(const QCborValue &value, size_t seed)
static qsizetype stringLengthInUtf8(const char16_t *ptr, const char16_t *end) noexcept
static Q_DECL_UNUSED constexpr quint64 MaximumPreallocatedElementCount
static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
Q_CORE_EXPORT const char * qt_cbor_tag_id(QCborTag tag)
bool comparesEqual(const QCborValue &lhs, const QCborValue &rhs) noexcept
static QCborContainerPrivate * maybeGrow(QCborContainerPrivate *container, qsizetype index)
static QDebug debugContents(QDebug &dbg, const QCborValue &v)
static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1, const QCborContainerPrivate *c2, const Element &e2, Comparison mode) noexcept
static Q_DECL_UNUSED constexpr int MaximumRecursionDepth
static QT_BEGIN_NAMESPACE constexpr quint64 MaxAcceptableMemoryUse
QDataStream & operator>>(QDataStream &stream, QCborValue &value)
static void convertArrayToMap(QCborContainerPrivate *&array)
static int compareElementNoData(const Element &e1, const Element &e2) noexcept
#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
quint32 Tag
#define qWarning
Definition qlogging.h:166
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:112
constexpr static Q_DECL_CONST_FUNCTION double qt_qnan() noexcept
Definition qnumeric_p.h:100
constexpr static Q_DECL_CONST_FUNCTION double qt_inf() noexcept
Definition qnumeric_p.h:83
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
Definition qnumeric_p.h:107
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLenum GLuint GLintptr offset
GLint ref
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLfixed GLfixed u2
const GLubyte * c
GLenum array
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLenum GLsizei len
GLfixed u1
GLubyte * pattern
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 Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qptrdiff
Definition qtypes.h:164
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
QByteArray ba
[0]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
MyCustomStruct c2
QCborValue(QCborTag(2), QByteArray("\x01\0\0\0\0\0\0\0\0", 9))
[0]
p rx()++
QRect r1(100, 200, 11, 16)
[0]
QRect r2(QPoint(100, 200), QSize(11, 16))
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:37
static ValidUtf8Result isValidUtf8(QByteArrayView in)
QLatin1StringView asLatin1() const
QByteArray::size_type len
QByteArray asByteArrayView() const
double fpvalue() const
QCborValue::Type type
ValueFlags flags
QCborContainerPrivate * container