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
27QT_BEGIN_NAMESPACE
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;
41Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
42 MaxAcceptableMemoryUse / MaximumRecursionDepth / sizeof(QtCbor::Element) - 1;
43
44/*!
45 \class QCborValue
46 \inmodule QtCore
47 \ingroup cbor
48 \ingroup qtserialization
49 \reentrant
50 \since 5.12
51
52 \brief The QCborValue class encapsulates a value in CBOR.
53
54 \compares strong
55
56 This class can be used to hold one of the many types available in CBOR.
57 CBOR is the Concise Binary Object Representation, a very compact form of
58 binary data encoding that is a superset of JSON. It was created by the IETF
59 Constrained RESTful Environments (CoRE) WG, which has used it in many
60 new RFCs. It is meant to be used alongside the
61 \l{RFC 7252}{CoAP protocol}.
62
63 CBOR has three groups of built-in types:
64
65 \list
66 \li Basic types: integers, floating point (double), boolean, null, etc.
67 \li String-like types: strings and byte arrays
68 \li Containers: arrays and maps
69 \endlist
70
71 Additionally, CBOR supports a form of type extensibility by associating a
72 "tag" to one of the above types to convey more information. For example, a
73 UUID is represented by a tag and a byte array containing the 16 bytes of
74 the UUID content. QCborValue supports creating and decoding several of those
75 extended types directly with Qt classes (like QUuid).
76
77 For the complete list, see \l QCborValue::Type. The type of a QCborValue can
78 be queried using type() or one of the "isXxxx" functions.
79
80 \section1 Extended types and tagged values
81
82 A tagged value is a normal QCborValue that is paired with a number that
83 is its tag. See \l QCborKnownTags for more information on what tags are in
84 the API as well as the full, official list. Such combinations form extended
85 types.
86
87 QCborValue has support for certain extended types in the API, like URL
88 (with \l QUrl) and UUID (with \l QUuid). Other extended types not supported
89 in the API are represented by a QCborValue of \l {Type}{Tag} type. The tag
90 can later be retrieved by tag() and the tagged value using taggedValue().
91
92 In order to support future compatibility, QCborValues containing extended
93 Qt types compare equal to the tag type of the same contents. In other
94 words, the following expression is true:
95
96 \snippet code/src_corelib_serialization_qcborvalue.cpp 0
97
98 \section1 Undefined and null values
99
100 QCborValue can contain a value of "null", which is not of any specific type.
101 It resembles the C++ \c {std::nullptr_t} type, whose only possible value is
102 \nullptr. QCborValue has a constructor taking such a type and creates a
103 null QCborValue.
104
105 Null values are used to indicate that an optional value is not present. In
106 that aspect, it is similar to the C++ Standard Library type \c
107 {std::optional} when that is disengaged. Unlike the C++ type, CBOR nulls
108 are simply of type "Null" and it is not possible to determine what concrete
109 type it is replacing.
110
111 QCborValue can also be of the undefined type, which represents a value of
112 "undefined". In fact, that is what the QCborValue default constructor
113 creates.
114
115 Undefined values are different from null values. While nulls are used to
116 indicate an optional value that is not provided, Undefined is usually
117 used to indicate that an expected value could not be provided, usually due
118 to an error or a precondition that could not be satisfied.
119
120 Such values are completely valid and may appear in CBOR streams, unlike
121 JSON content and QJsonValue's undefined bit. But like QJsonValue's
122 Undefined, it is returned by a CBOR container's value() or read-only
123 operator[] for invalid look-ups (index out of range for QCborArray, or key
124 not found for QCborMap). It is not possible to tell such a case apart from
125 the value of Undefined, so if that is required, check the QCborArray size
126 and use the QCborMap iterator API.
127
128 \section1 Simple types
129
130 CBOR supports additional simple types that, like Null and Undefined, carry
131 no other value. They are called interchangeably "Simple Types" and "Simple
132 Values". CBOR encodes booleans as two distinct types (one for \c true and
133 one for \c false), but QCborValue has a convenience API for them.
134
135 There are currently no other defined CBOR simple types. QCborValue supports
136 them simply by their number with API like isSimpleType() and
137 toSimpleType(), available for compatibility with future specifications
138 before the Qt API can be updated. Their use before such a specification is
139 discouraged, as other CBOR implementations may not support them fully.
140
141 \section1 CBOR support
142
143 QCborValue supports all CBOR features required to create canonical and
144 strict streams. It implements almost all of the features specified in \l
145 {RFC 7049}.
146
147 The following table lists the CBOR features that QCborValue supports.
148
149 \table
150 \header \li Feature \li Support
151 \row \li Unsigned numbers \li Yes (\l qint64 range)
152 \row \li Negative numbers \li Yes (\l qint64 range)
153 \row \li Byte strings \li Yes
154 \row \li Text strings \li Yes
155 \row \li Chunked strings \li See below
156 \row \li Tags \li Yes (arbitrary)
157 \row \li Booleans \li Yes
158 \row \li Null \li Yes
159 \row \li Undefined \li Yes
160 \row \li Arbitrary simple values \li Yes
161 \row \li Half-precision float (16-bit) \li Yes
162 \row \li Single-precision float (32-bit) \li Yes
163 \row \li Double-precision float (64-bit) \li Yes
164 \row \li Infinities and NaN floating point \li Yes
165 \row \li Determinate-length arrays and maps \li Yes
166 \row \li Indeterminate-length arrays and maps \li Yes
167 \row \li Map key types other than strings and integers \li Yes (arbitrary)
168 \endtable
169
170 Integers in QCborValue are limited to the range of the \l qint64 type. That
171 is, from -9,223,372,036,854,775,808 (-2\sup{63}) to
172 9,223,372,036,854,775,807 (2\sup{63} - 1). CBOR itself can represent integer
173 values outside of this range, which QCborValue does not support. When
174 decoding a stream using fromCbor() containing one of those values,
175 QCborValue will convert automatically to \l {Type}{Double}, but that may
176 lose up to 11 bits of precision.
177
178 fromCbor() is able to decode chunked strings, but will always merge the
179 chunks together into a single QCborValue. For that reason, it always writes
180 non-chunked strings when using toCbor() (which is required by the Canonical
181 format anyway).
182
183 QCborValue will always convert half- and single-precision floating point
184 values in the CBOR stream to double-precision. The toCbor() function can
185 take a parameter indicating to recreate them.
186
187 \section1 QCborValueRef
188
189 QCborValueRef is a helper class for QCborArray and QCborMap. It is the type
190 you get when using one of the mutating APIs in those classes. Unlike
191 QCborValue, new values can be assigned to that class. When that is done, the
192 array or map it refers to will be modified with the new value. In all other
193 aspects, its API is identical to QCborValue.
194
195 \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter,
196 QJsonValue, QJsonDocument, {Serialization Converter}, {Saving and Loading a Game}
197 {Parsing and displaying CBOR data}
198 */
199
200/*!
201 \class QCborParserError
202 \inmodule QtCore
203 \ingroup cbor
204 \reentrant
205 \since 5.12
206
207 \brief The QCborParserError is used by QCborValue to report a parsing error.
208
209 This class is used by \l {QCborValue::fromCbor(const QByteArray &ba,
210 QCborParserError *error)} to report a parser error and the byte offset
211 where the error was detected.
212
213 \sa QCborValue, QCborError
214 */
215
216/*!
217 \variable QCborParserError::offset
218
219 This field contains the offset from the beginning of the data where the
220 error was detected. The offset should point to the beginning of the item
221 that contained the error, even if the error itself was elsewhere (for
222 example, for UTF-8 decoding issues).
223
224 \sa QCborValue::fromCbor()
225 */
226
227/*!
228 \variable QCborParserError::error
229
230 This field contains the error code that indicates what decoding problem was
231 found.
232
233 \sa QCborValue::fromCbor()
234 */
235
236/*!
237 \fn QString QCborParserError::errorString() const
238
239 Returns a string representation of the error code. This string is not
240 translated.
241
242 \sa QCborError::toString(), QCborValue::fromCbor()
243 */
244
245/*!
246 \enum QCborValue::EncodingOption
247
248 This enum is used in the options argument to toCbor(), modifying the
249 behavior of the encoder.
250
251 \omitvalue SortKeysInMaps
252 \value NoTransformation (Default) Performs no transformations.
253 \value UseFloat Tells the encoder to use IEEE 754 single-precision floating point
254 (that is, \c float) whenever possible.
255 \value UseFloat16 Tells the encoder to use IEEE 754 half-precision floating point
256 (that is, \c qfloat16), whenever possible. Implies \c UseFloat.
257 \value UseIntegers Tells the encoder to use integers whenever a value of type \l
258 {Type}{Double} contains an integer.
259
260 The use of \c UseFloat16 is required to encode the stream in Canonical
261 Format, but is not otherwise necessary.
262
263 \sa toCbor()
264 */
265
266/*!
267 \enum QCborValue::DiagnosticNotationOption
268
269 This enum is used in the option argument to toDiagnosticNotation(), to
270 modify the output format.
271
272 \value Compact Does not use any line-breaks, producing a compact representation.
273 \value LineWrapped Uses line-breaks, one QCborValue per line.
274 \value ExtendedFormat Uses some different options to represent values, not found in
275 RFC 7049. Those options are subject to change.
276
277 Currently, \c ExtendedFormat will change how byte arrays are represented.
278 Without it, they are always hex-encoded and without spaces. With it,
279 QCborValue::toCbor() will either use hex with spaces, base64 or base64url
280 encoding, depending on the context.
281
282 \sa toDiagnosticNotation()
283 */
284
285/*!
286 \enum QCborValue::Type
287
288 This enum represents the QCborValue type. It is returned by the type()
289 function.
290
291 The CBOR built-in types are:
292
293 \value Integer \c qint64: An integer value
294 \value ByteArray \l QByteArray: a byte array ("byte string")
295 \value String \l QString: a Unicode string ("text string")
296 \value Array \l QCborArray: an array of QCborValues
297 \value Map \l QCborMap: an associative container of QCborValues
298 \value SimpleType \l QCborSimpleType: one of several simple types/values
299 \value False \c bool: the simple type for value \c false
300 \value True \c bool: the simple type for value \c true
301 \value Null \c std::nullptr_t: the simple type for the null value
302 \value Undefined (no type) the simple type for the undefined value
303 \value Double \c double: a double-precision floating point
304 \value Invalid Not a valid value, this usually indicates a CBOR decoding error
305
306 Additionally, QCborValue can represent extended types:
307
308 \value Tag An unknown or unrecognized extended type, represented by its
309 tag (a \l QCborTag) and the tagged value (a QCborValue)
310 \value DateTime \l QDateTime: a date and time stamp
311 \value Url \l QUrl: a URL or URI
312 \value RegularExpression \l QRegularExpression: the pattern of a regular expression
313 \value Uuid \l QUuid: a UUID
314
315 \sa type()
316 */
317
318/*!
319 \fn QCborValue::QCborValue()
320
321 Creates a QCborValue of the \l {Type}{Undefined} type.
322
323 CBOR undefined values are used to indicate missing information, usually as
324 a result of a previous operation that did not complete as expected. They
325 are also used by the QCborArray and QCborMap API to indicate the searched
326 item was not found.
327
328 Undefined values are represented by the \l {QCborSimpleType}{Undefined
329 simple type}. Because of that, QCborValues with undefined values will also
330 return true for isSimpleType() and
331 \c{isSimpleType(QCborSimpleType::Undefined)}.
332
333 Undefined values are different from null values.
334
335 QCborValue objects with undefined values are also different from invalid
336 QCborValue objects. The API will not create invalid QCborValues, but they
337 may exist as a result of a parsing error.
338
339 \sa isUndefined(), isNull(), isSimpleType()
340 */
341
342/*!
343 \fn QCborValue::QCborValue(Type t_)
344
345 Creates a QCborValue of type \a t_. The value associated with such a type
346 (if any) will be default constructed.
347
348 \sa type()
349 */
350
351/*!
352 \fn QCborValue::QCborValue(std::nullptr_t)
353
354 Creates a QCborValue of the \l {Type}{Null} type.
355
356 CBOR null values are used to indicate optional values that were not
357 provided. They are distinct from undefined values, in that null values are
358 usually not the result of an earlier error or problem.
359
360 \sa isNull(), isUndefined(), isSimpleType()
361 */
362
363/*!
364 \fn QCborValue::QCborValue(bool b)
365
366 Creates a QCborValue with boolean value \a b. The value can later be
367 retrieved using toBool().
368
369 Internally, CBOR booleans are represented by a pair of types, one for true
370 and one for false. For that reason, boolean QCborValues will return true
371 for isSimpleType() and one of \c{isSimpleType(QCborSimpleType::False)} or
372 \c{isSimpleType(QCborSimpleType::True)}.
373
374 \sa toBool(), isBool(), isTrue(), isFalse(), isSimpleType()
375 */
376
377/*!
378 \fn QCborValue::QCborValue(qint64 i)
379
380 Creates a QCborValue with integer value \a i. The value can later be
381 retrieved using toInteger().
382
383 CBOR integer values are distinct from floating point values. Therefore,
384 QCborValue objects with integers will compare differently to QCborValue
385 objects containing floating-point, even if the values contained in the
386 objects are equivalent.
387
388 \sa toInteger(), isInteger(), isDouble()
389 */
390
391/*!
392 \fn QCborValue::QCborValue(double d)
393
394 Creates a QCborValue with floating point value \a d. The value can later be
395 retrieved using toDouble().
396
397 CBOR floating point values are distinct from integer values. Therefore,
398 QCborValue objects with integers will compare differently to QCborValue
399 objects containing floating-point, even if the values contained in the
400 objects are equivalent.
401
402 \sa toDouble(), isDouble(), isInteger()
403 */
404
405/*!
406 \fn QCborValue::QCborValue(QCborSimpleType st)
407
408 Creates a QCborValue of simple type \a st. The type can later be retrieved
409 using toSimpleType() as well as isSimpleType(st).
410
411 CBOR simple types are types that do not have any associated value, like
412 C++'s \c{std::nullptr_t} type, whose only possible value is \nullptr.
413
414 If \a st is \c{QCborSimpleType::Null}, the resulting QCborValue will be of
415 the \l{Type}{Null} type and similarly for \c{QCborSimpleType::Undefined}.
416 If \a st is \c{QCborSimpleType::False} or \c{QCborSimpleType::True}, the
417 created QCborValue will be a boolean containing a value of false or true,
418 respectively.
419
420 This function can be used with simple types not defined in the API. For
421 example, to create a QCborValue with simple type 12, one could write:
422
423 \snippet code/src_corelib_serialization_qcborvalue.cpp 1
424
425 Simple types should not be used until a specification for them has been
426 published, since other implementations may not support them properly.
427 Simple type values 24 to 31 are reserved and must not be used.
428
429 isSimpleType(), isNull(), isUndefined(), isTrue(), isFalse()
430 */
431
432/*!
433 \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &taggedValue)
434 \overload
435
436 Creates a QCborValue for the extended type represented by the tag value \a
437 tag, tagging value \a taggedValue. The tag can later be retrieved using
438 tag() and the tagged value using taggedValue().
439
440 \sa isTag(), tag(), taggedValue(), QCborKnownTags
441 */
442
443/*!
444 \fn QCborValue::~QCborValue()
445
446 Disposes of the current QCborValue object and frees any associated resources.
447 */
448
449/*!
450 \fn QCborValue::QCborValue(QCborValue &&other)
451 \overload
452
453 Moves the contents of the \a other QCborValue object into this one and frees
454 the resources of this one.
455 */
456
457/*!
458 \fn QCborValue &&QCborValue::operator=(QCborValue &&other)
459 \overload
460
461 Moves the contents of the \a other QCborValue object into this one and frees
462 the resources of this one. Returns a reference to this object.
463 */
464
465/*!
466 \fn void QCborValue::swap(QCborValue &other)
467
468 Swaps the contents of this QCborValue object and \a other.
469 */
470
471/*!
472 \fn QCborValue::Type QCborValue::type() const
473
474 Returns the type of this QCborValue. The type can also later be retrieved by one
475 of the "isXxx" functions.
476
477 \sa isInteger(), isByteArray(), isString(), isArray(), isMap(),
478 isTag(), isFalse(), isTrue(), isBool(), isNull(), isUndefined, isDouble(),
479 isDateTime(), isUrl(), isRegularExpression(), isUuid()
480 */
481
482/*!
483 \fn bool QCborValue::isInteger() const
484
485 Returns true if this QCborValue is of the integer type. The integer value
486 can be retrieved using toInteger().
487
488 \sa type(), toInteger()
489 */
490
491/*!
492 \fn bool QCborValue::isByteArray() const
493
494 Returns true if this QCborValue is of the byte array type. The byte array
495 value can be retrieved using toByteArray().
496
497 \sa type(), toByteArray()
498 */
499
500/*!
501 \fn bool QCborValue::isString() const
502
503 Returns true if this QCborValue is of the string type. The string value
504 can be retrieved using toString().
505
506 \sa type(), toString()
507 */
508
509/*!
510 \fn bool QCborValue::isArray() const
511
512 Returns true if this QCborValue is of the array type. The array value can
513 be retrieved using toArray().
514
515 \sa type(), toArray()
516 */
517
518/*!
519 \fn bool QCborValue::isMap() const
520
521 Returns true if this QCborValue is of the map type. The map value can be
522 retrieved using toMap().
523
524 \sa type(), toMap()
525 */
526
527/*!
528 \fn bool QCborValue::isTag() const
529
530 Returns true if this QCborValue is of the tag type. The tag value can be
531 retrieved using tag() and the tagged value using taggedValue().
532
533 This function also returns true for extended types that the API
534 recognizes. For code that handles extended types directly before the Qt API
535 is updated to support them, it is possible to recreate the tag + tagged
536 value pair by using taggedValue().
537
538 \sa type(), tag(), taggedValue(), taggedValue()
539 */
540
541/*!
542 \fn bool QCborValue::isFalse() const
543
544 Returns true if this QCborValue is a boolean with false value. This
545 function exists because, internally, CBOR booleans are stored as two
546 separate types, one for true and one for false.
547
548 \sa type(), isBool(), isTrue(), toBool()
549 */
550
551/*!
552 \fn bool QCborValue::isTrue() const
553
554 Returns true if this QCborValue is a boolean with true value. This
555 function exists because, internally, CBOR booleans are stored as two
556 separate types, one for false and one for true.
557
558 \sa type(), isBool(), isFalse(), toBool()
559 */
560
561/*!
562 \fn bool QCborValue::isBool() const
563
564 Returns true if this QCborValue is a boolean. The value can be retrieved
565 using toBool().
566
567 \sa type(), toBool(), isTrue(), isFalse()
568 */
569
570/*!
571 \fn bool QCborValue::isUndefined() const
572
573 Returns true if this QCborValue is of the undefined type.
574
575 CBOR undefined values are used to indicate missing information, usually as
576 a result of a previous operation that did not complete as expected. They
577 are also used by the QCborArray and QCborMap API to indicate the searched
578 item was not found.
579
580 Undefined values are distinct from null values.
581
582 QCborValue objects with undefined values are also different from invalid
583 QCborValue objects. The API will not create invalid QCborValues, but they
584 may exist as a result of a parsing error.
585
586 \sa type(), isNull(), isInvalid()
587 */
588
589/*!
590 \fn bool QCborValue::isNull() const
591
592 Returns true if this QCborValue is of the null type.
593
594 CBOR null values are used to indicate optional values that were not
595 provided. They are distinct from undefined values, in that null values are
596 usually not the result of an earlier error or problem.
597
598 Null values are distinct from undefined values and from invalid QCborValue
599 objects. The API will not create invalid QCborValues, but they may exist as
600 a result of a parsing error.
601
602 \sa type(), isUndefined(), isInvalid()
603 */
604
605/*!
606 \fn bool QCborValue::isDouble() const
607
608 Returns true if this QCborValue is of the floating-point type. The value
609 can be retrieved using toDouble().
610
611 \sa type(), toDouble()
612 */
613
614/*!
615 \fn bool QCborValue::isDateTime() const
616
617 Returns true if this QCborValue is of the date/time type. The value can be
618 retrieved using toDateTime(). Date/times are extended types that use the
619 tag \l{QCborKnownTags}{DateTime}.
620
621 Additionally, when decoding from a CBOR stream, QCborValue will interpret
622 tags of value \l{QCborKnownTags}{UnixTime_t} and convert them to the
623 equivalent date/time.
624
625 \sa type(), toDateTime()
626 */
627
628/*!
629 \fn bool QCborValue::isUrl() const
630
631 Returns true if this QCborValue is of the URL type. The URL value
632 can be retrieved using toUrl().
633
634 \sa type(), toUrl()
635 */
636
637/*!
638 \fn bool QCborValue::isRegularExpression() const
639
640 Returns true if this QCborValue contains a regular expression's pattern.
641 The pattern can be retrieved using toRegularExpression().
642
643 \sa type(), toRegularExpression()
644 */
645
646/*!
647 \fn bool QCborValue::isUuid() const
648
649 Returns true if this QCborValue contains a UUID. The value can be retrieved
650 using toUuid().
651
652 \sa type(), toUuid()
653 */
654
655/*!
656 \fn bool QCborValue::isInvalid() const
657
658 Returns true if this QCborValue is not of any valid type. Invalid
659 QCborValues are distinct from those with undefined values and they usually
660 represent a decoding error.
661
662 \sa isUndefined(), isNull()
663 */
664
665/*!
666 \fn bool QCborValue::isContainer() const
667
668 This convenience function returns true if the QCborValue is either an array
669 or a map.
670
671 \sa isArray(), isMap()
672 */
673
674/*!
675 \fn bool QCborValue::isSimpleType() const
676
677 Returns true if this QCborValue is of one of the CBOR simple types. The
678 type itself can later be retrieved using type(), even for types that don't have an
679 enumeration in the API. They can also be checked with the
680 \l{isSimpleType(QCborSimpleType)} overload.
681
682 \sa QCborSimpleType, isSimpleType(QCborSimpleType), toSimpleType()
683 */
684
685/*!
686 \fn bool QCborValue::isSimpleType(QCborSimpleType st) const
687 \overload
688
689 Returns true if this QCborValue is of a simple type and toSimpleType()
690 would return \a st, false otherwise. This function can be used to check for
691 any CBOR simple type, even those for which there is no enumeration in the
692 API. For example, for the simple type of value 12, you could write:
693
694 \snippet code/src_corelib_serialization_qcborvalue.cpp 2
695
696 \sa QCborValue::QCborValue(QCborSimpleType), isSimpleType(), isFalse(),
697 isTrue(), isNull, isUndefined(), toSimpleType()
698 */
699
700/*!
701 \fn QCborSimpleType QCborValue::toSimpleType(QCborSimpleType defaultValue) const
702
703 Returns the simple type this QCborValue is of, if it is a simple type. If
704 it is not a simple type, it returns \a defaultValue.
705
706 The following types are simple types and this function will return the
707 listed values:
708
709 \table
710 \row \li QCborValue::False \li QCborSimpleType::False
711 \row \li QCborValue::True \li QCborSimpleType::True
712 \row \li QCborValue::Null \li QCborSimpleType::Null
713 \row \li QCborValue::Undefined \li QCborSimpleType::Undefined
714 \endtable
715
716 \sa type(), isSimpleType(), isBool(), isTrue(), isFalse(), isTrue(),
717 isNull(), isUndefined()
718 */
719
720/*!
721 \fn qint64 QCborValue::toInteger(qint64 defaultValue) const
722
723 Returns the integer value stored in this QCborValue, if it is of the
724 integer type. If it is of the Double type, this function returns the
725 floating point value converted to integer. In any other case, it returns \a
726 defaultValue.
727
728 \sa isInteger(), isDouble(), toDouble()
729 */
730
731/*!
732 \fn bool QCborValue::toBool(bool defaultValue) const
733
734 Returns the boolean value stored in this QCborValue, if it is of a boolean
735 type. Otherwise, it returns \a defaultValue.
736
737 \sa isBool(), isTrue(), isFalse()
738 */
739
740/*!
741 \fn double QCborValue::toDouble(double defaultValue) const
742
743 Returns the floating point value stored in this QCborValue, if it is of the
744 Double type. If it is of the Integer type, this function returns the
745 integer value converted to double. In any other case, it returns \a
746 defaultValue.
747
748 \sa isDouble(), isInteger(), toInteger()
749 */
750
751using namespace QtCbor;
752
753static QCborContainerPrivate *assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
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
764static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
765{
766 qint64 tag = d->elements.at(i: 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(block: buf, len);
775 };
776
777 switch (tag) {
778 case qint64(QCborKnownTags::DateTimeString):
779 case qint64(QCborKnownTags::UnixTime_t): {
780 QDateTime dt;
781 if (tag == qint64(QCborKnownTags::DateTimeString) && b &&
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(string: b->asLatin1(), format: 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(v1: e.value, v2: qint64(1000), r: &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(v: round(x: e.fpvalue() * 1000), value: &msecs);
802 }
803 if (ok)
804 dt = QDateTime::fromMSecsSinceEpoch(msecs, timeZone: QTimeZone::UTC);
805 }
806 if (dt.isValid()) {
807 QByteArray text = dt.toString(format: 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);
812 return QCborValue::DateTime;
813 }
814 }
815 break;
816 }
817
818#ifndef QT_BOOTSTRAPPED
819 case qint64(QCborKnownTags::Url):
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()) {
827 QByteArray encoded = url.toString(options: QUrl::DecodeReserved).toUtf8();
828 replaceByteData(encoded, encoded.size(), {});
829 }
830 }
831 return QCborValue::Url;
832 }
833 break;
834#endif // QT_BOOTSTRAPPED
835
836#if QT_CONFIG(regularexpression)
837 case quint64(QCborKnownTags::RegularExpression):
838 if (e.type == QCborValue::String) {
839 // no normalization is necessary
840 return QCborValue::RegularExpression;
841 }
842 break;
843#endif // QT_CONFIG(regularexpression)
844
845 case qint64(QCborKnownTags::Uuid):
846 if (e.type == QCborValue::ByteArray) {
847 // force the size to 16
848 char buf[sizeof(QUuid)] = {};
849 if (b)
850 memcpy(dest: buf, src: b->byte(), n: qMin(a: sizeof(buf), b: 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)) {
866 if (opt & QCborValue::UseFloat) {
867#ifndef QT_BOOTSTRAPPED
868 if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16)
869 return writer.append(f: std::numeric_limits<qfloat16>::quiet_NaN());
870#endif
871 return writer.append(f: std::numeric_limits<float>::quiet_NaN());
872 }
873 return writer.append(d: 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(v: d, value: &i)) {
881 if (d < 0)
882 return writer.append(n: QCborNegativeInteger(i));
883 return writer.append(u: i);
884 }
885 }
886
887 if (opt & QCborValue::UseFloat) {
888 float f = float(d);
889 if (f == d) {
890 // no data loss, we could use float
891#ifndef QT_BOOTSTRAPPED
892 if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16) {
893 qfloat16 f16 = qfloat16(f);
894 if (f16 == f)
895 return writer.append(f: f16);
896 }
897#endif
898
899 return writer.append(f);
900 }
901 }
902
903 writer.append(d);
904}
905#endif // QT_CONFIG(cborstreamwriter)
906
907static inline int typeOrder(QCborValue::Type e1, QCborValue::Type e2)
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
926void QCborContainerPrivate::compact()
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(target&: newData, targetUsed&: newUsedData, block: b->byte(), len: b->len);
940 }
941 }
942 data = newData;
943 usedData = newUsedData;
944}
945
946QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qsizetype reserved)
947{
948 if (!d) {
949 d = new QCborContainerPrivate;
950 } else {
951 // in case QList::reserve throws
952 QExplicitlySharedDataPointer u(new QCborContainerPrivate(*d));
953 if (reserved >= 0) {
954 u->elements.reserve(asize: reserved);
955 u->compact();
956 }
957
958 d = u.take();
959 d->ref.storeRelaxed(newValue: 0);
960
961 for (auto &e : std::as_const(t&: d->elements)) {
962 if (e.flags & Element::IsContainer)
963 e.container->ref.ref();
964 }
965 }
966 return d;
967}
968
969QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, qsizetype reserved)
970{
971 if (!d || d->ref.loadRelaxed() != 1)
972 return clone(d, reserved);
973 return d;
974}
975
976/*!
977 Prepare for an insertion at position \a index
978
979 Detaches and ensures there are at least index entries in the array, padding
980 with Undefined as needed.
981*/
982QCborContainerPrivate *QCborContainerPrivate::grow(QCborContainerPrivate *d, qsizetype index)
983{
984 Q_ASSERT(index >= 0);
985 d = detach(d, reserved: 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.
998void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &value, ContainerDisposition disp)
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
1009 QCborContainerPrivate *d = QCborContainerPrivate::clone(d: this);
1010 d->elements.detach();
1011 d->ref.storeRelaxed(newValue: 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
1023 e = value.container->elements.at(i: value.n);
1024
1025 // Copy string data, if any
1026 if (const ByteData *b = value.container->byteData(idx: 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(block: valueData, len: valueData.size());
1038 } else {
1039 compact();
1040 e.value = addByteData(block: b->byte(), len: 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
1054Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s)
1055{
1056 qsizetype len = s.size();
1057 QtCbor::Element e;
1058 e.value = addByteData(block: nullptr, len);
1059 e.type = QCborValue::String;
1060 e.flags = Element::HasByteData | Element::StringIsAscii;
1061 elements.append(t: e);
1062
1063 char *ptr = data.data() + e.value + sizeof(ByteData);
1064 uchar *l = reinterpret_cast<uchar *>(ptr);
1065 qt_to_latin1_unchecked(dst: l, uc: s.utf16(), len);
1066}
1067
1068void QCborContainerPrivate::appendNonAsciiString(QStringView s)
1069{
1070 appendByteData(data: reinterpret_cast<const char *>(s.utf16()), len: s.size() * 2,
1071 type: QCborValue::String, extraFlags: QtCbor::Element::StringIsUtf16);
1072}
1073
1074QCborValue QCborContainerPrivate::extractAt_complex(Element e)
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(data: b->byte(), len: b->len, type: e.type, extraFlags: 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(asize: 1);
1091 container->elements.append(t: e);
1092 }
1093
1094 return makeValue(type: e.type, n: 0, d: 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 = { .c: *ptr++ };
1106
1107 if (r.c < 0x0800) {
1108 if (r.c >= 0x0080)
1109 ++r.len;
1110 } else if (!QChar::isHighSurrogate(ucs4: r.c) || ptr == end) {
1111 r.len += 2;
1112 } else {
1113 r.len += 3;
1114 r.c = QChar::surrogateToUcs4(high: r.c, low: *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
1128static int compareStringsInUtf8(QStringView lhs, QStringView rhs, Comparison mode) noexcept
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(ptr&: src1, end: end1);
1148 auto r2 = nextUtf32Character(ptr&: src2, end: 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(ptr: src1, end: end1);
1156 len2 += stringLengthInUtf8(ptr: src2, end: end2);
1157 if (len1 == len2)
1158 return diff;
1159 return len1 < len2 ? -1 : 1;
1160}
1161
1162static int compareStringsInUtf8(QUtf8StringView lhs, QStringView rhs, Comparison mode) noexcept
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>(u: uc, dst&: ptr, src&: src2, end: 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(s1: src1 + idx1, s2: utf8, n: 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(ptr: src2, end: end2);
1203
1204 if (len1 != len2)
1205 return len1 < len2 ? -1 : 1;
1206 return diff;
1207}
1208
1209static int compareStringsInUtf8(QStringView lhs, QUtf8StringView rhs, Comparison mode) noexcept
1210{
1211 return -compareStringsInUtf8(lhs: rhs, rhs: lhs, mode);
1212}
1213
1214QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
1215static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
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
1260static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1,
1261 const QCborContainerPrivate *c2, const Element &e2,
1262 Comparison mode) noexcept
1263{
1264 int cmp = typeOrder(e1: e1.type, e2: e2.type);
1265 if (cmp != 0)
1266 return cmp;
1267
1268 if ((e1.flags & Element::IsContainer) || (e2.flags & Element::IsContainer))
1269 return compareContainer(c1: e1.flags & Element::IsContainer ? e1.container : nullptr,
1270 c2: e2.flags & Element::IsContainer ? e2.container : nullptr, mode);
1271
1272 // string data?
1273 const ByteData *b1 = c1 ? c1->byteData(e: e1) : nullptr;
1274 const ByteData *b2 = c2 ? c2->byteData(e: 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(lhs: b1->asStringView(), rhs: 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(s1: b1->byte(), s2: b2->byte(), n: size_t(len1)) == 0 ? 0 : 1;
1299 }
1300 return memcmp(s1: b1->byte(), s2: b2->byte(), n: 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(lhs: b1->asStringView(), rhs: b2->asUtf8StringView(), mode);
1308 else
1309 return compareStringsInUtf8(lhs: b1->asUtf8StringView(), rhs: b2->asStringView(), mode);
1310 }
1311
1312 return compareElementNoData(e1, e2);
1313}
1314
1315static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
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
1336inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPrivate *c1, Element e1,
1337 const QCborContainerPrivate *c2, Element e2,
1338 Comparison mode) noexcept
1339{
1340 return compareElementRecursive(c1, e1, c2, e2, mode);
1341}
1342
1343/*!
1344 \fn bool QCborValue::operator==(const QCborValue &lhs, const QCborValue &rhs)
1345
1346 Compares \a lhs and \a rhs, and returns true if they hold the same
1347 contents, false otherwise. If each QCborValue contains an array or map, the
1348 comparison is recursive to elements contained in them.
1349
1350 For more information on CBOR equality in Qt, see, compare().
1351
1352 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1353 operator!=(), operator<()
1354 */
1355
1356/*!
1357 \fn bool QCborValue::operator!=(const QCborValue &lhs, const QCborValue &rhs)
1358
1359 Compares \a lhs and \a rhs, and returns true if contents differ,
1360 false otherwise. If each QCborValue contains an array or map, the comparison
1361 is recursive to elements contained in them.
1362
1363 For more information on CBOR equality in Qt, see, QCborValue::compare().
1364
1365 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1366 operator==(), operator<()
1367 */
1368bool comparesEqual(const QCborValue &lhs,
1369 const QCborValue &rhs) noexcept
1370{
1371 Element e1 = QCborContainerPrivate::elementFromValue(value: lhs);
1372 Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
1373 return compareElementRecursive(c1: lhs.container, e1, c2: rhs.container, e2,
1374 mode: Comparison::ForEquality) == 0;
1375}
1376
1377/*!
1378 \fn bool QCborValue::operator<(const QCborValue &lhs, const QCborValue &rhs)
1379
1380 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1381 sorted before \a rhs, false otherwise. If each QCborValue contains an
1382 array or map, the comparison is recursive to elements contained in them.
1383
1384 For more information on CBOR sorting order, see QCborValue::compare().
1385
1386 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1387 operator==(), operator!=()
1388 */
1389
1390/*!
1391 \fn bool QCborValue::operator<=(const QCborValue &lhs, const QCborValue &rhs)
1392
1393 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1394 sorted before \a rhs or is being equal to \a rhs, false otherwise.
1395 If each QCborValue contains an array or map, the comparison is recursive
1396 to elements contained in them.
1397
1398 For more information on CBOR sorting order, see QCborValue::compare().
1399
1400 \sa compare(), QCborValue::operator<(), QCborMap::operator==(),
1401 operator==(), operator!=()
1402*/
1403
1404/*!
1405 \fn bool QCborValue::operator>(const QCborValue &lhs, const QCborValue &rhs)
1406
1407 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1408 sorted after \a rhs, false otherwise. If each QCborValue contains an
1409 array or map, the comparison is recursive to elements contained in them.
1410
1411 For more information on CBOR sorting order, see QCborValue::compare().
1412
1413 \sa compare(), QCborValue::operator>=(), QCborMap::operator==(),
1414 operator==(), operator!=()
1415*/
1416
1417/*!
1418 \fn bool QCborValue::operator>=(const QCborValue &lhs, const QCborValue &rhs)
1419
1420 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1421 sorted after \a rhs or is being equal to \a rhs, false otherwise.
1422 If each QCborValue contains an array or map, the comparison is recursive
1423 to elements contained in them.
1424
1425 For more information on CBOR sorting order, see QCborValue::compare().
1426
1427 \sa compare(), QCborValue::operator>(), QCborMap::operator==(),
1428 operator==(), operator!=()
1429*/
1430
1431/*!
1432 Compares this value and \a other, and returns an integer that indicates
1433 whether this value should be sorted prior to (if the result is negative) or
1434 after \a other (if the result is positive). If this function returns 0, the
1435 two values are equal and hold the same contents.
1436
1437 If each QCborValue contains an array or map, the comparison is recursive to
1438 elements contained in them.
1439
1440 \section3 Extended types
1441
1442 QCborValue compares equal a QCborValue containing an extended type, like
1443 \l{Type}{Url} and \l{Type}{Url} and its equivalent tagged representation.
1444 So, for example, the following expression is true:
1445
1446 \snippet code/src_corelib_serialization_qcborvalue.cpp 3
1447
1448 Do note that Qt types like \l QUrl and \l QDateTime will normalize and
1449 otherwise modify their arguments. The expression above is true only because
1450 the string on the right side is the normalized value that the QCborValue on
1451 the left would take. If, for example, the "https" part were uppercase in
1452 both sides, the comparison would fail. For information on normalizations
1453 performed by QCborValue, please consult the documentation of the
1454 constructor taking the Qt type in question.
1455
1456 \section3 Sorting order
1457
1458 Sorting order in CBOR is defined in
1459 \l{RFC 7049, section 3.9}, which
1460 discusses the sorting of keys in a map when following the Canonical
1461 encoding. According to the specification, "sorting is performed on the
1462 bytes of the representation of the key data items" and lists as
1463 consequences that:
1464
1465 \list
1466 \li "If two keys have different lengths, the shorter one sorts earlier;"
1467 \li "If two keys have the same length, the one with the lower value in
1468 (byte-wise) lexical order sorts earlier."
1469 \endlist
1470
1471 This results in surprising sorting of QCborValues, where the result of this
1472 function is different from that which would later be retrieved by comparing the
1473 contained elements. For example, the QCborValue containing string "zzz"
1474 sorts before the QCborValue with string "foobar", even though when
1475 comparing as \l{QString::compare()}{QStrings} or
1476 \l{QByteArray}{QByteArrays} the "zzz" sorts after "foobar"
1477 (dictionary order).
1478
1479 The specification does not clearly indicate what sorting order should be
1480 done for values of different types (it says sorting should not pay
1481 "attention to the 3/5 bit splitting for major types"). QCborValue makes the
1482 assumption that types should be sorted too. The numeric values of the
1483 QCborValue::Type enumeration are in that order, with the exception of the
1484 extended types, which compare as their tagged equivalents.
1485
1486 \note Sorting order is preliminary and is subject to change. Applications
1487 should not depend on the order returned by this function for the time
1488 being.
1489
1490 \sa QCborArray::compare(), QCborMap::compare(), operator==()
1491 */
1492int QCborValue::compare(const QCborValue &other) const
1493{
1494 Element e1 = QCborContainerPrivate::elementFromValue(value: *this);
1495 Element e2 = QCborContainerPrivate::elementFromValue(value: other);
1496 return compareElementRecursive(c1: container, e1, c2: other.container, e2, mode: Comparison::ForOrdering);
1497}
1498
1499bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
1500{
1501 return compareContainer(c1: lhs.d.constData(), c2: rhs.d.constData(), mode: Comparison::ForEquality) == 0;
1502}
1503
1504int QCborArray::compare(const QCborArray &other) const noexcept
1505{
1506 return compareContainer(c1: d.data(), c2: other.d.data(), mode: Comparison::ForOrdering);
1507}
1508
1509bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1510{
1511 if (typeOrder(e1: QCborValue::Array, e2: rhs.type()))
1512 return false;
1513 return compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForEquality) == 0;
1514}
1515
1516Qt::strong_ordering
1517QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1518{
1519 int c = typeOrder(e1: QCborValue::Array, e2: rhs.type());
1520 if (c == 0)
1521 c = compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForOrdering);
1522 return Qt::compareThreeWay(lhs: c, rhs: 0);
1523}
1524
1525bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
1526{
1527 return compareContainer(c1: lhs.d.constData(), c2: rhs.d.constData(), mode: Comparison::ForEquality) == 0;
1528}
1529
1530int QCborMap::compare(const QCborMap &other) const noexcept
1531{
1532 return compareContainer(c1: d.data(), c2: other.d.data(), mode: Comparison::ForOrdering);
1533}
1534
1535bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1536{
1537 if (typeOrder(e1: QCborValue::Map, e2: rhs.type()))
1538 return false;
1539 return compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForEquality) == 0;
1540}
1541
1542Qt::strong_ordering
1543QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1544{
1545 int c = typeOrder(e1: QCborValue::Map, e2: rhs.type());
1546 if (c == 0)
1547 c = compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForOrdering);
1548 return Qt::compareThreeWay(lhs: c, rhs: 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(count: quint64(len));
1560 else
1561 writer.startMap(count: 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(msg: "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(tag: QCborTag(d->elements.at(i: 0).value));
1580 encodeToCbor(writer, d, idx: 1, opt);
1581 } else {
1582 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1583 // just one element
1584 auto e = d->elements.at(i: idx);
1585 const ByteData *b = d->byteData(idx);
1586 switch (e.type) {
1587 case QCborValue::Integer:
1588 return writer.append(i: qint64(e.value));
1589
1590 case QCborValue::ByteArray:
1591 if (b)
1592 return writer.appendByteString(data: b->byte(), len: b->len);
1593 return writer.appendByteString(data: "", len: 0);
1594
1595 case QCborValue::String:
1596 if (b) {
1597 if (e.flags & Element::StringIsUtf16)
1598 return writer.append(str: b->asStringView());
1599 return writer.appendTextString(utf8: b->byte(), len: b->len);
1600 }
1601 return writer.append(str: QLatin1StringView());
1602
1603 case QCborValue::Array:
1604 case QCborValue::Map:
1605 case QCborValue::Tag:
1606 // recurse
1607 return encodeToCbor(writer,
1608 d: e.flags & Element::IsContainer ? e.container : nullptr,
1609 idx: -qsizetype(e.type), opt);
1610
1611 case QCborValue::SimpleType:
1612 case QCborValue::False:
1613 case QCborValue::True:
1614 case QCborValue::Null:
1615 case QCborValue::Undefined:
1616 break;
1617
1618 case QCborValue::Double:
1619 return writeDoubleToCbor(writer, d: e.fpvalue(), opt);
1620
1621 case QCborValue::Invalid:
1622 return;
1623
1624 case QCborValue::DateTime:
1625 case QCborValue::Url:
1626 case QCborValue::RegularExpression:
1627 case QCborValue::Uuid:
1628 // recurse as tag
1629 return encodeToCbor(writer, d: e.container, idx: -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(st: QCborSimpleType(simpleType));
1636
1637 // if we got here, we've got an unknown type
1638 qWarning(msg: "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()) {
1666 case QCborStreamReader::UnsignedInteger:
1667 case QCborStreamReader::NegativeInteger:
1668 if (double d = integerOutOfRange(reader)) {
1669 e.type = QCborValue::Double;
1670 qToUnaligned(src: d, dest: &e.value);
1671 } else {
1672 e.type = QCborValue::Integer;
1673 e.value = reader.toInteger();
1674 }
1675 break;
1676 case QCborStreamReader::SimpleType:
1677 e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
1678 break;
1679 case QCborStreamReader::Float16:
1680 e.type = QCborValue::Double;
1681 qToUnaligned(src: double(reader.toFloat16()), dest: &e.value);
1682 break;
1683 case QCborStreamReader::Float:
1684 e.type = QCborValue::Double;
1685 qToUnaligned(src: double(reader.toFloat()), dest: &e.value);
1686 break;
1687 case QCborStreamReader::Double:
1688 e.type = QCborValue::Double;
1689 qToUnaligned(src: reader.toDouble(), dest: &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(a: reader.length(), b: 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, error: { .c: QCborError::NestingTooDeep });
1717 return nullptr;
1718 }
1719
1720 QCborContainerPrivate *d = nullptr;
1721 {
1722 // in case QList::reserve throws
1723 QExplicitlySharedDataPointer u(new QCborContainerPrivate);
1724 if (qsizetype len = clampedContainerLength(reader))
1725 u->elements.reserve(asize: 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, remainingStackDepth: 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, error: { .c: QCborError::NestingTooDeep });
1750 return QCborValue::Invalid;
1751 }
1752
1753 auto d = new QCborContainerPrivate;
1754 d->append(tag: reader.toTag());
1755 reader.next();
1756
1757 if (reader.lastError() == QCborError::NoError) {
1758 // decode tagged value
1759 d->decodeValueFromCbor(reader, remainingStackDepth: remainingRecursionDepth - 1);
1760 }
1761
1762 QCborValue::Type type;
1763 if (reader.lastError() == QCborError::NoError) {
1764 // post-process to create our extended types
1765 type = convertToExtendedType(d);
1766 } else {
1767 // decoding error
1768 type = QCborValue::Invalid;
1769 }
1770
1771 // note: may return invalid state!
1772 return QCborContainerPrivate::makeValue(type, n: -1, d);
1773}
1774
1775// in qcborstream.cpp
1776extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
1777inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
1778{
1779 qt_cbor_stream_set_error(d: reader.d.data(), error);
1780}
1781
1782extern QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data);
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, error: { .c: 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::maxSize())) {
1812 // overflow
1813 setErrorInReader(reader, error: { .c: 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::maxSize())) {
1825 // this may cause an allocation failure
1826 newCapacity = QByteArray::maxSize();
1827 }
1828 if (newCapacity > size_t(data.capacity()))
1829 data.reserve(asize: newCapacity);
1830 data.resize(size: 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);
1837 QCborStreamReader::StringResultCode status = qt_cbor_append_string_chunk(reader, data: &data);
1838 while (status == QCborStreamReader::Ok) {
1839 if (e.type == QCborValue::String && len) {
1840 // verify UTF-8 string validity
1841 auto utf8result = QUtf8::isValidUtf8(in: QByteArrayView(data).last(n: len));
1842 if (!utf8result.isValidUtf8) {
1843 status = QCborStreamReader::Error;
1844 setErrorInReader(reader, error: { .c: 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: &data);
1854 } else {
1855 // error
1856 status = QCborStreamReader::Error;
1857 setErrorInReader(reader, error: { .c: 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)
1871 Q_ASSERT(e.type == QCborValue::String);
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::maxSize())) {
1878 setErrorInReader(reader, error: { .c: QCborError::DataTooLarge });
1879 status = QCborStreamReader::Error;
1880 }
1881 }
1882 }
1883
1884 if (status == QCborStreamReader::Error) {
1885 data.truncate(pos: e.value);
1886 } else {
1887 elements.append(t: e);
1888 }
1889}
1890
1891void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1892{
1893 QCborStreamReader::Type t = reader.type();
1894 switch (t) {
1895 case QCborStreamReader::UnsignedInteger:
1896 case QCborStreamReader::NegativeInteger:
1897 case QCborStreamReader::SimpleType:
1898 case QCborStreamReader::Float16:
1899 case QCborStreamReader::Float:
1900 case QCborStreamReader::Double:
1901 elements.append(t: decodeBasicValueFromCbor(reader));
1902 break;
1903
1904 case QCborStreamReader::ByteArray:
1905 case QCborStreamReader::String:
1906 decodeStringFromCbor(reader);
1907 break;
1908
1909 case QCborStreamReader::Array:
1910 case QCborStreamReader::Map:
1911 return append(v: makeValue(type: t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, n: -1,
1912 d: createContainerFromCbor(reader, remainingRecursionDepth),
1913 disp: MoveContainer));
1914
1915 case QCborStreamReader::Tag:
1916 return append(v: taggedValueFromCbor(reader, remainingRecursionDepth));
1917
1918 case QCborStreamReader::Invalid:
1919 return; // probably a decode error
1920 }
1921}
1922#endif // QT_CONFIG(cborstreamreader)
1923
1924/*!
1925 Creates a QCborValue with byte array value \a ba. The value can later be
1926 retrieved using toByteArray().
1927
1928 \sa toByteArray(), isByteArray(), isString()
1929 */
1930QCborValue::QCborValue(const QByteArray &ba)
1931 : n(0), container(new QCborContainerPrivate), t(ByteArray)
1932{
1933 container->appendByteData(data: ba.constData(), len: ba.size(), type: t);
1934 container->ref.storeRelaxed(newValue: 1);
1935}
1936
1937/*!
1938 Creates a QCborValue with string value \a s. The value can later be
1939 retrieved using toString().
1940
1941 \sa toString(), isString(), isByteArray()
1942 */
1943QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {}
1944
1945/*!
1946 Creates a QCborValue with string value \a s. The value can later be
1947 retrieved using toString().
1948
1949 \sa toString(), isString(), isByteArray()
1950*/
1951QCborValue::QCborValue(QStringView s)
1952 : n(0), container(new QCborContainerPrivate), t(String)
1953{
1954 container->append(s);
1955 container->ref.storeRelaxed(newValue: 1);
1956}
1957
1958/*!
1959 \overload
1960
1961 Creates a QCborValue with the Latin-1 string viewed by \a s.
1962 The value can later be retrieved using toString().
1963
1964 \sa toString(), isString(), isByteArray()
1965 */
1966QCborValue::QCborValue(QLatin1StringView s)
1967 : n(0), container(new QCborContainerPrivate), t(String)
1968{
1969 container->append(s);
1970 container->ref.storeRelaxed(newValue: 1);
1971}
1972
1973/*!
1974 \fn QCborValue::QCborValue(const QCborArray &a)
1975 \fn QCborValue::QCborValue(QCborArray &&a)
1976
1977 Creates a QCborValue with the array \a a. The array can later be retrieved
1978 using toArray().
1979
1980 \sa toArray(), isArray(), isMap()
1981 */
1982QCborValue::QCborValue(const QCborArray &a)
1983 : n(-1), container(a.d.data()), t(Array)
1984{
1985 if (container)
1986 container->ref.ref();
1987}
1988
1989/*!
1990 \fn QCborValue::QCborValue(const QCborMap &m)
1991 \fn QCborValue::QCborValue(QCborMap &&m)
1992
1993 Creates a QCborValue with the map \a m. The map can later be retrieved
1994 using toMap().
1995
1996 \sa toMap(), isMap(), isArray()
1997 */
1998QCborValue::QCborValue(const QCborMap &m)
1999 : n(-1), container(m.d.data()), t(Map)
2000{
2001 if (container)
2002 container->ref.ref();
2003}
2004
2005/*!
2006 \fn QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2007 \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &tv)
2008
2009 Creates a QCborValue for the extended type represented by the tag value \a
2010 tag, tagging value \a tv. The tag can later be retrieved using tag() and
2011 the tagged value using taggedValue().
2012
2013 \sa isTag(), tag(), taggedValue(), QCborKnownTags
2014 */
2015QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2016 : n(-1), container(new QCborContainerPrivate), t(Tag)
2017{
2018 container->ref.storeRelaxed(newValue: 1);
2019 container->append(tag);
2020 container->append(v: tv);
2021 t = convertToExtendedType(d: container);
2022}
2023
2024/*!
2025 Copies the contents of \a other into this object.
2026 */
2027QCborValue::QCborValue(const QCborValue &other) noexcept
2028 : n(other.n), container(other.container), t(other.t)
2029{
2030 if (container)
2031 container->ref.ref();
2032}
2033
2034/*!
2035 Creates a QCborValue object of the date/time extended type and containing
2036 the value represented by \a dt. The value can later be retrieved using
2037 toDateTime().
2038
2039 The CBOR date/time types are extension types using tags: either a string
2040 (in ISO date format) tagged as a \l{QCborKnownTags}{DateTime} or a number
2041 (of seconds since the start of 1970, UTC) tagged as a
2042 \l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will
2043 convert \l{QCborKnownTags}{UnixTime_t} to the string-based type.
2044
2045 \sa toDateTime(), isDateTime(), taggedValue()
2046 */
2047QCborValue::QCborValue(const QDateTime &dt)
2048 : QCborValue(QCborKnownTags::DateTimeString, dt.toString(format: Qt::ISODateWithMs).toLatin1())
2049{
2050 // change types
2051 t = DateTime;
2052 container->elements[1].type = String;
2053}
2054
2055#ifndef QT_BOOTSTRAPPED
2056/*!
2057 Creates a QCborValue object of the URL extended type and containing the
2058 value represented by \a url. The value can later be retrieved using toUrl().
2059
2060 The CBOR URL type is an extended type represented by a string tagged as an
2061 \l{QCborKnownTags}{Url}.
2062
2063 \sa toUrl(), isUrl(), taggedValue()
2064 */
2065QCborValue::QCborValue(const QUrl &url)
2066 : QCborValue(QCborKnownTags::Url, url.toString(options: QUrl::DecodeReserved).toUtf8())
2067{
2068 // change types
2069 t = Url;
2070 container->elements[1].type = String;
2071}
2072
2073#if QT_CONFIG(regularexpression)
2074/*!
2075 Creates a QCborValue object of the regular expression pattern extended type
2076 and containing the value represented by \a rx. The value can later be retrieved
2077 using toRegularExpression().
2078
2079 The CBOR regular expression type is an extended type represented by a
2080 string tagged as an \l{QCborKnownTags}{RegularExpression}. Note that CBOR
2081 regular expressions only store the patterns, so any flags that the
2082 QRegularExpression object may carry will be lost.
2083
2084 \sa toRegularExpression(), isRegularExpression(), taggedValue()
2085 */
2086QCborValue::QCborValue(const QRegularExpression &rx)
2087 : QCborValue(QCborKnownTags::RegularExpression, rx.pattern())
2088{
2089 // change type
2090 t = RegularExpression;
2091}
2092#endif // QT_CONFIG(regularexpression)
2093
2094/*!
2095 Creates a QCborValue object of the UUID extended type and containing the
2096 value represented by \a uuid. The value can later be retrieved using
2097 toUuid().
2098
2099 The CBOR UUID type is an extended type represented by a byte array tagged
2100 as an \l{QCborKnownTags}{Uuid}.
2101
2102 \sa toUuid(), isUuid(), taggedValue()
2103 */
2104QCborValue::QCborValue(const QUuid &uuid)
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
2118/*!
2119 Replaces the contents of this QCborObject with a copy of \a other.
2120 */
2121QCborValue &QCborValue::operator=(const QCborValue &other) noexcept
2122{
2123 n = other.n;
2124 assignContainer(d&: container, x: other.container);
2125 t = other.t;
2126 return *this;
2127}
2128
2129/*!
2130 Returns the tag of this extended QCborValue object, if it is of the tag
2131 type, \a defaultValue otherwise.
2132
2133 CBOR represents extended types by associating a number (the tag) with a
2134 stored representation. This function returns that number. To retrieve the
2135 representation, use taggedValue().
2136
2137 \sa isTag(), taggedValue(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2138 */
2139QCborTag QCborValue::tag(QCborTag defaultValue) const
2140{
2141 return isTag() && container && container->elements.size() == 2 ?
2142 QCborTag(container->elements.at(i: 0).value) : defaultValue;
2143}
2144
2145/*!
2146 Returns the tagged value of this extended QCborValue object, if it is of
2147 the tag type, \a defaultValue otherwise.
2148
2149 CBOR represents extended types by associating a number (the tag) with a
2150 stored representation. This function returns that representation. To
2151 retrieve the tag, use tag().
2152
2153 \sa isTag(), tag(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2154 */
2155QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
2156{
2157 return isTag() && container && container->elements.size() == 2 ?
2158 container->valueAt(idx: 1) : defaultValue;
2159}
2160
2161/*!
2162 Returns the byte array value stored in this QCborValue, if it is of the byte
2163 array type. Otherwise, it returns \a defaultValue.
2164
2165 Note that this function performs no conversion from other types to
2166 QByteArray.
2167
2168 \sa isByteArray(), isString(), toString()
2169 */
2170QByteArray QCborValue::toByteArray(const QByteArray &defaultValue) const
2171{
2172 if (!container || !isByteArray())
2173 return defaultValue;
2174
2175 Q_ASSERT(n >= 0);
2176 return container->byteArrayAt(idx: n);
2177}
2178
2179/*!
2180 Returns the string value stored in this QCborValue, if it is of the string
2181 type. Otherwise, it returns \a defaultValue.
2182
2183 Note that this function performs no conversion from other types to
2184 QString.
2185
2186 \sa isString(), isByteArray(), toByteArray()
2187 */
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(idx: n);
2195}
2196
2197/*!
2198 Returns the date/time value stored in this QCborValue, if it is of the
2199 date/time extended type. Otherwise, it returns \a defaultValue.
2200
2201 Note that this function performs no conversion from other types to
2202 QDateTime.
2203
2204 \sa isDateTime(), isTag(), taggedValue()
2205 */
2206QDateTime QCborValue::toDateTime(const QDateTime &defaultValue) const
2207{
2208 if (!container || !isDateTime() || container->elements.size() != 2)
2209 return defaultValue;
2210
2211 Q_ASSERT(n == -1);
2212 const ByteData *byteData = container->byteData(idx: 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(string: byteData->asLatin1(), format: Qt::ISODateWithMs);
2219}
2220
2221#ifndef QT_BOOTSTRAPPED
2222/*!
2223 Returns the URL value stored in this QCborValue, if it is of the URL
2224 extended type. Otherwise, it returns \a defaultValue.
2225
2226 Note that this function performs no conversion from other types to QUrl.
2227
2228 \sa isUrl(), isTag(), taggedValue()
2229 */
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(idx: 1);
2237 if (!byteData)
2238 return QUrl(); // valid, empty URL
2239
2240 return QUrl::fromEncoded(input: byteData->asByteArrayView());
2241}
2242
2243#if QT_CONFIG(regularexpression)
2244/*!
2245 Returns the regular expression value stored in this QCborValue, if it is of
2246 the regular expression pattern extended type. Otherwise, it returns \a
2247 defaultValue.
2248
2249 Note that this function performs no conversion from other types to
2250 QRegularExpression.
2251
2252 \sa isRegularExpression(), isTag(), taggedValue()
2253 */
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(idx: 1));
2261}
2262#endif // QT_CONFIG(regularexpression)
2263
2264/*!
2265 Returns the UUID value stored in this QCborValue, if it is of the UUID
2266 extended type. Otherwise, it returns \a defaultValue.
2267
2268 Note that this function performs no conversion from other types to QUuid.
2269
2270 \sa isUuid(), isTag(), taggedValue()
2271 */
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(idx: 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
2286/*!
2287 \fn QCborArray QCborValue::toArray() const
2288 \fn QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
2289
2290 Returns the array value stored in this QCborValue, if it is of the array
2291 type. Otherwise, it returns \a defaultValue.
2292
2293 Note that this function performs no conversion from other types to
2294 QCborArray.
2295
2296 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2297 */
2298
2299/*!
2300 \fn QCborArray QCborValueRef::toArray() const
2301 \fn QCborArray QCborValueRef::toArray(const QCborArray &defaultValue) const
2302 \internal
2303
2304 Returns the array value stored in this QCborValue, if it is of the array
2305 type. Otherwise, it returns \a defaultValue.
2306
2307 Note that this function performs no conversion from other types to
2308 QCborArray.
2309
2310 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2311 */
2312QCborArray QCborValue::toArray() const
2313{
2314 return toArray(defaultValue: QCborArray());
2315}
2316
2317QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
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
2329/*!
2330 \fn QCborMap QCborValue::toMap() const
2331 \fn QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2332
2333 Returns the map value stored in this QCborValue, if it is of the map type.
2334 Otherwise, it returns \a defaultValue.
2335
2336 Note that this function performs no conversion from other types to
2337 QCborMap.
2338
2339 \sa isMap(), isArray(), isContainer(), toArray()
2340 */
2341
2342/*!
2343 \fn QCborMap QCborValueRef::toMap() const
2344 \fn QCborMap QCborValueRef::toMap(const QCborMap &defaultValue) const
2345 \internal
2346
2347 Returns the map value stored in this QCborValue, if it is of the map type.
2348 Otherwise, it returns \a defaultValue.
2349
2350 Note that this function performs no conversion from other types to
2351 QCborMap.
2352
2353 \sa isMap(), isArray(), isContainer(), toArray()
2354 */
2355QCborMap QCborValue::toMap() const
2356{
2357 return toMap(defaultValue: 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
2372/*!
2373 If this QCborValue is a QCborMap, searches elements for the value whose key
2374 matches \a key. If there's no key matching \a key in the map or if this
2375 QCborValue object is not a map, returns the undefined value.
2376
2377 This function is equivalent to:
2378
2379 \snippet code/src_corelib_serialization_qcborvalue.cpp 4
2380
2381 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2382 QCborMap::find()
2383 */
2384const QCborValue QCborValue::operator[](const QString &key) const
2385{
2386 return QCborContainerPrivate::findCborMapKey(self: *this, key: qToStringViewIgnoringNull(s: key));
2387}
2388
2389/*!
2390 \overload
2391
2392 If this QCborValue is a QCborMap, searches elements for the value whose key
2393 matches \a key. If there's no key matching \a key in the map or if this
2394 QCborValue object is not a map, returns the undefined value.
2395
2396 This function is equivalent to:
2397
2398 \snippet code/src_corelib_serialization_qcborvalue.cpp 5
2399
2400 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2401 QCborMap::find()
2402 */
2403const QCborValue QCborValue::operator[](QLatin1StringView key) const
2404{
2405 return QCborContainerPrivate::findCborMapKey(self: *this, key);
2406}
2407
2408/*!
2409 \overload
2410
2411 If this QCborValue is a QCborMap, searches elements for the value whose key
2412 matches \a key. If this is a QCborArray, returns the element whose index is
2413 \a key. If there's no matching value in the array or map, or if this
2414 QCborValue object is not an array or map, returns the undefined value.
2415
2416 \sa operator[], QCborMap::operator[], QCborMap::value(),
2417 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2418 */
2419const QCborValue QCborValue::operator[](qint64 key) const
2420{
2421 if (isArray() && container && quint64(key) < quint64(container->elements.size()))
2422 return container->valueAt(idx: key);
2423 return QCborContainerPrivate::findCborMapKey(self: *this, key);
2424}
2425
2426static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
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
2441/*!
2442 \internal
2443 */
2444static void convertArrayToMap(QCborContainerPrivate *&array)
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(msg: "Using CBOR array as map forced conversion");
2451
2452 qsizetype size = array->elements.size();
2453 QCborContainerPrivate *map = QCborContainerPrivate::detach(d: array, reserved: size * 2);
2454 map->elements.resize(size: 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) {
2460 Q_ASSERT(src->type != QCborValue::Invalid);
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
2467 assignContainer(d&: array, x: map);
2468}
2469
2470/*!
2471 \internal
2472 */
2473static QCborContainerPrivate *maybeGrow(QCborContainerPrivate *container, qsizetype index)
2474{
2475 auto replace = QCborContainerPrivate::grow(d: 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(d&: container, x: replace);
2482}
2483
2484template <typename KeyType> inline QCborValueRef
2485QCborContainerPrivate::findOrAddMapKey(QCborValue &self, KeyType key)
2486{
2487 // we need a map, so convert if necessary
2488 if (self.isArray())
2489 convertArrayToMap(array&: self.container);
2490 else if (!self.isMap())
2491 self = QCborValue(QCborValue::Map);
2492 self.t = QCborValue::Map;
2493 self.n = -1;
2494
2495 QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
2496 assignContainer(d&: self.container, x: result.d);
2497 return result;
2498}
2499
2500template<typename KeyType> QCborValueRef
2501QCborContainerPrivate::findOrAddMapKey(QCborValueRef self, KeyType key)
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) {
2507 convertArrayToMap(array&: e.container);
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;
2514 e.type = QCborValue::Map;
2515
2516 QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
2517 assignContainer(d&: e.container, x: result.d);
2518 return result;
2519}
2520
2521/*!
2522 Returns a QCborValueRef that can be used to read or modify the entry in
2523 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2524 this function is equivalent to the matching operator[] on that map.
2525
2526 Before returning the reference: if this QCborValue was an array, it is first
2527 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2528 with valid \c{array[i]}); otherwise, if it was not a map it will be
2529 over-written with an empty map.
2530
2531 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2532 QCborMap::find()
2533 */
2534QCborValueRef QCborValue::operator[](const QString &key)
2535{
2536 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key: qToStringViewIgnoringNull(s: key));
2537}
2538
2539/*!
2540 \overload
2541
2542 Returns a QCborValueRef that can be used to read or modify the entry in
2543 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2544 this function is equivalent to the matching operator[] on that map.
2545
2546 Before returning the reference: if this QCborValue was an array, it is first
2547 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2548 with valid \c{array[i]}); otherwise, if it was not a map it will be
2549 over-written with an empty map.
2550
2551 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2552 QCborMap::find()
2553 */
2554QCborValueRef QCborValue::operator[](QLatin1StringView key)
2555{
2556 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key);
2557}
2558
2559/*!
2560 \overload
2561
2562 Returns a QCborValueRef that can be used to read or modify the entry in
2563 this, as a map or array, with the given \a key. When this QCborValue is a
2564 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
2565 equivalent to the matching operator[] on that map or array.
2566
2567 Before returning the reference: if this QCborValue was an array but the key
2568 is out of range, the array is first converted to a map (so that \c{map[i]}
2569 is \c{array[i]} for each index, \c i, with valid \c{array[i]}); otherwise,
2570 if it was not a map it will be over-written with an empty map.
2571
2572 \sa operator[], QCborMap::operator[], QCborMap::value(),
2573 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2574 */
2575QCborValueRef QCborValue::operator[](qint64 key)
2576{
2577 if (shouldArrayRemainArray(key, t, container)) {
2578 container = maybeGrow(container, index: key);
2579 return { container, qsizetype(key) };
2580 }
2581 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key);
2582}
2583
2584#if QT_CONFIG(cborstreamreader)
2585/*!
2586 Decodes one item from the CBOR stream found in \a reader and returns the
2587 equivalent representation. This function is recursive: if the item is a map
2588 or array, it will decode all items found in that map or array, until the
2589 outermost object is finished.
2590
2591 This function need not be used on the root element of a \l
2592 QCborStreamReader. For example, the following code illustrates how to skip
2593 the CBOR signature tag from the beginning of a file:
2594
2595 \snippet code/src_corelib_serialization_qcborvalue.cpp 6
2596
2597 The returned value may be partially complete and indistinguishable from a
2598 valid QCborValue even if the decoding failed. To determine if there was an
2599 error, check if \l{QCborStreamReader::lastError()}{reader.lastError()} is
2600 indicating an error condition. This function stops decoding immediately
2601 after the first error.
2602
2603 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2604 */
2605QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
2606{
2607 QCborValue result;
2608 auto t = reader.type();
2609 if (reader.lastError() != QCborError::NoError)
2610 t = QCborStreamReader::Invalid;
2611
2612 switch (t) {
2613 // basic types, no container needed:
2614 case QCborStreamReader::UnsignedInteger:
2615 case QCborStreamReader::NegativeInteger:
2616 case QCborStreamReader::SimpleType:
2617 case QCborStreamReader::Float16:
2618 case QCborStreamReader::Float:
2619 case QCborStreamReader::Double: {
2620 Element e = decodeBasicValueFromCbor(reader);
2621 result.n = e.value;
2622 result.t = e.type;
2623 break;
2624 }
2625
2626 case QCborStreamReader::Invalid:
2627 result.t = QCborValue::Invalid;
2628 break; // probably a decode error
2629
2630 // strings
2631 case QCborStreamReader::ByteArray:
2632 case QCborStreamReader::String:
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
2641 case QCborStreamReader::Array:
2642 case QCborStreamReader::Map:
2643 result.n = -1;
2644 result.t = reader.isArray() ? Array : Map;
2645 result.container = createContainerFromCbor(reader, remainingRecursionDepth: MaximumRecursionDepth);
2646 break;
2647
2648 // tag
2649 case QCborStreamReader::Tag:
2650 result = taggedValueFromCbor(reader, remainingRecursionDepth: MaximumRecursionDepth);
2651 break;
2652 }
2653
2654 return result;
2655}
2656
2657/*!
2658 \overload
2659
2660 Decodes one item from the CBOR stream found in the byte array \a ba and
2661 returns the equivalent representation. This function is recursive: if the
2662 item is a map or array, it will decode all items found in that map or
2663 array, until the outermost object is finished.
2664
2665 This function stores the error state, if any, in the object pointed to by
2666 \a error, along with the offset of where the error occurred. If no error
2667 happened, it stores \l{QCborError}{NoError} in the error state and the
2668 number of bytes that it consumed (that is, it stores the offset for the
2669 first unused byte). Using that information makes it possible to parse
2670 further data that may exist in the same byte array.
2671
2672 The returned value may be partially complete and indistinguishable from a
2673 valid QCborValue even if the decoding failed. To determine if there was an
2674 error, check if there was an error stored in \a error. This function stops
2675 decoding immediately after the first error.
2676
2677 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2678 */
2679QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
2680{
2681 QCborStreamReader reader(ba);
2682 QCborValue result = fromCbor(reader);
2683 if (error) {
2684 error->error = reader.lastError();
2685 error->offset = reader.currentOffset();
2686 }
2687 return result;
2688}
2689
2690/*!
2691 \fn QCborValue QCborValue::fromCbor(const char *data, qsizetype len, QCborParserError *error)
2692 \fn QCborValue QCborValue::fromCbor(const quint8 *data, qsizetype len, QCborParserError *error)
2693 \overload
2694
2695 Converts \a len bytes of \a data to a QByteArray and then calls the
2696 overload of this function that accepts a QByteArray, also passing \a error,
2697 if provided.
2698*/
2699#endif // QT_CONFIG(cborstreamreader)
2700
2701#if QT_CONFIG(cborstreamwriter)
2702/*!
2703 Encodes this QCborValue object to its CBOR representation, using the
2704 options specified in \a opt, and return the byte array containing that
2705 representation.
2706
2707 This function will not fail, except if this QCborValue or any of the
2708 contained items, if this is a map or array, are invalid. Invalid types are
2709 not produced normally by the API, but can result from decoding errors.
2710
2711 By default, this function performs no transformation on the values in the
2712 QCborValue, writing all floating point directly as double-precision (\c
2713 double) types. If the \l{EncodingOption}{UseFloat} option is specified, it
2714 will use single precision (\c float) for any floating point value for which
2715 there's no loss of precision in using that representation. That includes
2716 infinities and NaN values.
2717
2718 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2719 will try to use half-precision (\c qfloat16) floating point if the
2720 conversion to that results in no loss of precision. This is always true for
2721 infinities and NaN.
2722
2723 If \l{EncodingOption}{UseIntegers} is specified, it will use integers for
2724 any floating point value that contains an actual integer.
2725
2726 \sa fromCbor(), fromVariant(), fromJsonValue()
2727 */
2728QByteArray QCborValue::toCbor(EncodingOptions opt) const
2729{
2730 QByteArray result;
2731 QCborStreamWriter writer(&result);
2732 toCbor(writer, opt);
2733 return result;
2734}
2735
2736/*!
2737 \overload
2738
2739 Encodes this QCborValue object to its CBOR representation, using the
2740 options specified in \a opt, to the writer specified by \a writer. The same
2741 writer can be used by multiple QCborValues, for example, in order to encode
2742 different elements in a larger array.
2743
2744 This function will not fail, except if this QCborValue or any of the
2745 contained items, if this is a map or array, are invalid. Invalid types are
2746 not produced normally by the API, but can result from decoding errors.
2747
2748 By default, this function performs no transformation on the values in the
2749 QCborValue, writing all floating point directly as double-precision
2750 (binary64) types. If the \l{EncodingOption}{UseFloat} option is
2751 specified, it will use single precision (binary32) for any floating point
2752 value for which there's no loss of precision in using that representation.
2753 That includes infinities and NaN values.
2754
2755 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2756 will try to use half-precision (binary16) floating point if the conversion
2757 to that results in no loss of precision. This is always true for infinities
2758 and NaN.
2759
2760 If \l{EncodingOption}{UseIntegers} is specified, it will use integers
2761 for any floating point value that contains an actual integer.
2762
2763 \sa fromCbor(), fromVariant(), fromJsonValue()
2764 */
2765Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt) const
2766{
2767 if (isContainer() || isTag())
2768 return encodeToCbor(writer, d: container, idx: -type(), opt);
2769 if (container)
2770 return encodeToCbor(writer, d: container, idx: n, opt);
2771
2772 // very simple types
2773 if (isSimpleType())
2774 return writer.append(st: toSimpleType());
2775
2776 switch (type()) {
2777 case Integer:
2778 return writer.append(i: n);
2779
2780 case Double:
2781 return writeDoubleToCbor(writer, d: 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(data: "", len: 0);
2798
2799 case String:
2800 // String with no container is empty
2801 return writer.appendTextString(utf8: "", len: 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(idx: that.i, value: other);
2831}
2832
2833void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
2834{
2835 that.d->replaceAt(idx: that.i, value: other, disp: 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(i: self.i);
2847 if (e.type != QCborValue::False && e.type != QCborValue::True)
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(i: 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
2862qint64 QCborValueConstRef::concreteIntegral(QCborValueConstRef self, qint64 defaultValue) noexcept
2863{
2864 QtCbor::Element e = self.d->elements.at(i: self.i);
2865 QCborValue::Type t = e.type;
2866 if (t == QCborValue::Double)
2867 return e.fpvalue();
2868 if (t != QCborValue::Integer)
2869 return defaultValue;
2870 return e.value;
2871}
2872
2873QByteArray QCborValueConstRef::concreteByteArray(QCborValueConstRef self,
2874 const QByteArray &defaultValue)
2875{
2876 QtCbor::Element e = self.d->elements.at(i: self.i);
2877 if (e.type != QCborValue::ByteArray)
2878 return defaultValue;
2879 return self.d->byteArrayAt(idx: self.i);
2880}
2881
2882QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QString &defaultValue)
2883{
2884 QtCbor::Element e = self.d->elements.at(i: self.i);
2885 if (e.type != QCborValue::String)
2886 return defaultValue;
2887 return self.d->stringAt(idx: self.i);
2888}
2889
2890bool
2891QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
2892{
2893 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2894 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2895 return compareElementRecursive(c1: lhs.d, e1, c2: rhs.d, e2, mode: Comparison::ForEquality) == 0;
2896}
2897
2898Qt::strong_ordering
2899QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
2900{
2901 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2902 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2903 int c = compareElementRecursive(c1: lhs.d, e1, c2: rhs.d, e2, mode: Comparison::ForOrdering);
2904 return Qt::compareThreeWay(lhs: c, rhs: 0);
2905}
2906
2907bool
2908QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
2909{
2910 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2911 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
2912 return compareElementRecursive(c1: lhs.d, e1, c2: rhs.container, e2, mode: Comparison::ForEquality) == 0;
2913}
2914
2915Qt::strong_ordering
2916QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
2917{
2918 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2919 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
2920 int c = compareElementRecursive(c1: lhs.d, e1, c2: rhs.container, e2, mode: Comparison::ForOrdering);
2921 return Qt::compareThreeWay(lhs: c, rhs: 0);
2922}
2923
2924bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2925{
2926 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2927 if (typeOrder(e1: QCborValue::Array, e2: e2.type))
2928 return false;
2929 return compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForEquality) == 0;
2930}
2931
2932Qt::strong_ordering
2933QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2934{
2935 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2936 int c = typeOrder(e1: QCborValue::Array, e2: e2.type);
2937 if (c == 0)
2938 c = compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForOrdering);
2939 return Qt::compareThreeWay(lhs: c, rhs: 0);
2940}
2941
2942bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
2943{
2944 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2945 if (typeOrder(e1: QCborValue::Array, e2: e2.type))
2946 return false;
2947 return compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForEquality) == 0;
2948}
2949
2950Qt::strong_ordering
2951QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
2952{
2953 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2954 int c = typeOrder(e1: QCborValue::Map, e2: e2.type);
2955 if (c == 0)
2956 c = compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForOrdering);
2957 return Qt::compareThreeWay(lhs: c, rhs: 0);
2958}
2959
2960QCborValue QCborValueConstRef::concrete(QCborValueConstRef self) noexcept
2961{
2962 return self.d->valueAt(idx: self.i);
2963}
2964
2965QCborValue::Type QCborValueConstRef::concreteType(QCborValueConstRef self) noexcept
2966{
2967 return self.d->elements.at(i: self.i).type;
2968}
2969
2970const QCborValue QCborValueConstRef::operator[](const QString &key) const
2971{
2972 const QCborValue item = d->valueAt(idx: i);
2973 return item[key];
2974}
2975
2976const QCborValue QCborValueConstRef::operator[](const QLatin1StringView key) const
2977{
2978 const QCborValue item = d->valueAt(idx: i);
2979 return item[key];
2980}
2981
2982const QCborValue QCborValueConstRef::operator[](qint64 key) const
2983{
2984 const QCborValue item = d->valueAt(idx: 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(idx: self.i);
2992}
2993
2994QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
2995{
2996 return self.d->elements.at(i: self.i).type;
2997}
2998
2999/*!
3000 If this QCborValueRef refers to a QCborMap, searches elements for the value
3001 whose key matches \a key. If there's no key matching \a key in the map or if
3002 this QCborValueRef object is not a map, returns the undefined value.
3003
3004 This function is equivalent to:
3005
3006 \code
3007 value.toMap().value(key);
3008 \endcode
3009
3010 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3011 QCborMap::find()
3012 */
3013const QCborValue QCborValueRef::operator[](const QString &key) const
3014{
3015 return QCborValueConstRef::operator[](key);
3016}
3017
3018/*!
3019 \overload
3020
3021 If this QCborValueRef refers to a QCborMap, searches elements for the value
3022 whose key matches \a key. If there's no key matching \a key in the map or if
3023 this QCborValueRef object is not a map, returns the undefined value.
3024
3025 This function is equivalent to:
3026
3027 \code
3028 value.toMap().value(key);
3029 \endcode
3030
3031 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3032 QCborMap::find()
3033 */
3034const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
3035{
3036 return QCborValueConstRef::operator[](key);
3037}
3038
3039/*!
3040 \overload
3041
3042 If this QCborValueRef refers to a QCborMap, searches elements for the value
3043 whose key matches \a key. If this is a QCborArray, returns the element whose
3044 index is \a key. If there's no matching value in the array or map, or if
3045 this QCborValueRef object is not an array or map, returns the undefined
3046 value.
3047
3048 \sa operator[], QCborMap::operator[], QCborMap::value(),
3049 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3050 */
3051const QCborValue QCborValueRef::operator[](qint64 key) const
3052{
3053 return QCborValueConstRef::operator[](key);
3054}
3055
3056/*!
3057 Returns a QCborValueRef that can be used to read or modify the entry in
3058 this, as a map, with the given \a key. When this QCborValueRef refers to a
3059 QCborMap, this function is equivalent to the matching operator[] on that
3060 map.
3061
3062 Before returning the reference: if the QCborValue referenced was an array,
3063 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3064 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3065 will be over-written with an empty map.
3066
3067 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3068 QCborMap::find()
3069 */
3070QCborValueRef QCborValueRef::operator[](const QString &key)
3071{
3072 return QCborContainerPrivate::findOrAddMapKey(self: *this, key: qToStringViewIgnoringNull(s: key));
3073}
3074
3075/*!
3076 \overload
3077
3078 Returns a QCborValueRef that can be used to read or modify the entry in
3079 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
3080 this function is equivalent to the matching operator[] on that map.
3081
3082 Before returning the reference: if the QCborValue referenced was an array,
3083 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3084 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3085 will be over-written with an empty map.
3086
3087 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3088 QCborMap::find()
3089 */
3090QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
3091{
3092 return QCborContainerPrivate::findOrAddMapKey(self: *this, key);
3093}
3094
3095/*!
3096 \overload
3097
3098 Returns a QCborValueRef that can be used to read or modify the entry in
3099 this, as a map or array, with the given \a key. When this QCborValue is a
3100 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
3101 equivalent to the matching operator[] on that map or array.
3102
3103 Before returning the reference: if the QCborValue referenced was an array
3104 but the key is out of range, the array is first converted to a map (so that
3105 \c{map[i]} is \c{array[i]} for each index, \c i, with valid \c{array[i]});
3106 otherwise, if it was not a map it will be over-written with an empty map.
3107
3108 \sa operator[], QCborMap::operator[], QCborMap::value(),
3109 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3110 */
3111QCborValueRef QCborValueRef::operator[](qint64 key)
3112{
3113 auto &e = d->elements[i];
3114 if (shouldArrayRemainArray(key, t: e.type, container: e.container)) {
3115 e.container = maybeGrow(container: e.container, index: key);
3116 e.flags |= QtCbor::Element::IsContainer;
3117 return { e.container, qsizetype(key) };
3118 }
3119 return QCborContainerPrivate::findOrAddMapKey(self: *this, key);
3120}
3121#endif // < Qt 7
3122
3123inline QCborArray::QCborArray(QCborContainerPrivate &dd) noexcept
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()) {
3136 case QCborValue::Integer:
3137 return qHash(key: value.toInteger(), seed);
3138 case QCborValue::ByteArray:
3139 return qHash(key: value.toByteArray(), seed);
3140 case QCborValue::String:
3141 return qHash(key: value.toString(), seed);
3142 case QCborValue::Array:
3143 return qHash(array: value.toArray(), seed);
3144 case QCborValue::Map:
3145 return qHash(map: value.toMap(), seed);
3146 case QCborValue::Tag: {
3147 QtPrivate::QHashCombine hash;
3148 seed = hash(seed, value.tag());
3149 seed = hash(seed, value.taggedValue());
3150 return seed;
3151 }
3152 case QCborValue::SimpleType:
3153 break;
3154 case QCborValue::False:
3155 return qHash(t: false, seed);
3156 case QCborValue::True:
3157 return qHash(t: true, seed);
3158 case QCborValue::Null:
3159 return qHash(nullptr, seed);
3160 case QCborValue::Undefined:
3161 return seed;
3162 case QCborValue::Double:
3163 return qHash(key: value.toDouble(), seed);
3164 case QCborValue::DateTime:
3165 return qHash(key: value.toDateTime(), seed);
3166#ifndef QT_BOOTSTRAPPED
3167 case QCborValue::Url:
3168 return qHash(url: value.toUrl(), seed);
3169# if QT_CONFIG(regularexpression)
3170 case QCborValue::RegularExpression:
3171 return qHash(key: value.toRegularExpression(), seed);
3172# endif
3173 case QCborValue::Uuid:
3174 return qHash(uuid: value.toUuid(), seed);
3175#endif
3176 case QCborValue::Invalid:
3177 return seed;
3178 default:
3179 break;
3180 }
3181
3182 Q_ASSERT(value.isSimpleType());
3183 return qHash(tag: value.toSimpleType(), seed);
3184}
3185
3186Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
3187{
3188 switch (st) {
3189 case QCborSimpleType::False:
3190 return "False";
3191 case QCborSimpleType::True:
3192 return "True";
3193 case QCborSimpleType::Null:
3194 return "Null";
3195 case QCborSimpleType::Undefined:
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)) {
3208 case QCborKnownTags::DateTimeString:
3209 return "DateTimeString";
3210 case QCborKnownTags::UnixTime_t:
3211 return "UnixTime_t";
3212 case QCborKnownTags::PositiveBignum:
3213 return "PositiveBignum";
3214 case QCborKnownTags::NegativeBignum:
3215 return "NegativeBignum";
3216 case QCborKnownTags::Decimal:
3217 return "Decimal";
3218 case QCborKnownTags::Bigfloat:
3219 return "Bigfloat";
3220 case QCborKnownTags::COSE_Encrypt0:
3221 return "COSE_Encrypt0";
3222 case QCborKnownTags::COSE_Mac0:
3223 return "COSE_Mac0";
3224 case QCborKnownTags::COSE_Sign1:
3225 return "COSE_Sign1";
3226 case QCborKnownTags::ExpectedBase64url:
3227 return "ExpectedBase64url";
3228 case QCborKnownTags::ExpectedBase64:
3229 return "ExpectedBase64";
3230 case QCborKnownTags::ExpectedBase16:
3231 return "ExpectedBase16";
3232 case QCborKnownTags::EncodedCbor:
3233 return "EncodedCbor";
3234 case QCborKnownTags::Url:
3235 return "Url";
3236 case QCborKnownTags::Base64url:
3237 return "Base64url";
3238 case QCborKnownTags::Base64:
3239 return "Base64";
3240 case QCborKnownTags::RegularExpression:
3241 return "RegularExpression";
3242 case QCborKnownTags::MimeMessage:
3243 return "MimeMessage";
3244 case QCborKnownTags::Uuid:
3245 return "Uuid";
3246 case QCborKnownTags::COSE_Encrypt:
3247 return "COSE_Encrypt";
3248 case QCborKnownTags::COSE_Mac:
3249 return "COSE_Mac";
3250 case QCborKnownTags::COSE_Sign:
3251 return "COSE_Sign";
3252 case QCborKnownTags::Signature:
3253 return "Signature";
3254 }
3255 }
3256 return nullptr;
3257}
3258
3259#if !defined(QT_NO_DEBUG_STREAM)
3260static QDebug debugContents(QDebug &dbg, const QCborValue &v)
3261{
3262 switch (v.type()) {
3263 case QCborValue::Integer:
3264 return dbg << v.toInteger();
3265 case QCborValue::ByteArray:
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 }
3282 case QCborValue::SimpleType:
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";
3290 case QCborValue::Undefined:
3291 return dbg;
3292 case QCborValue::Double: {
3293 qint64 i;
3294 if (convertDoubleTo(v: v.toDouble(), value: &i))
3295 return dbg << i << ".0";
3296 else
3297 return dbg << v.toDouble();
3298 }
3299 case QCborValue::DateTime:
3300 return dbg << v.toDateTime();
3301#ifndef QT_BOOTSTRAPPED
3302 case QCborValue::Url:
3303 return dbg << v.toUrl();
3304#if QT_CONFIG(regularexpression)
3305 case QCborValue::RegularExpression:
3306 return dbg << v.toRegularExpression();
3307#endif
3308 case QCborValue::Uuid:
3309 return dbg << v.toUuid();
3310#endif
3311 case QCborValue::Invalid:
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}
3320QDebug operator<<(QDebug dbg, const QCborValue &v)
3321{
3322 QDebugStateSaver saver(dbg);
3323 dbg.nospace() << "QCborValue(";
3324 return debugContents(dbg, v) << ')';
3325}
3326
3327QDebug operator<<(QDebug dbg, QCborSimpleType st)
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
3337QDebug operator<<(QDebug dbg, QCborTag tag)
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
3350QDebug operator<<(QDebug dbg, QCborKnownTags tag)
3351{
3352 QDebugStateSaver saver(dbg);
3353 const char *id = qt_cbor_tag_id(tag: 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)
3363QDataStream &operator<<(QDataStream &stream, const QCborValue &value)
3364{
3365 stream << QCborValue(value).toCbor();
3366 return stream;
3367}
3368#endif
3369
3370QDataStream &operator>>(QDataStream &stream, QCborValue &value)
3371{
3372 QByteArray buffer;
3373 stream >> buffer;
3374 QCborParserError parseError{};
3375 value = QCborValue::fromCbor(ba: buffer, error: &parseError);
3376 if (parseError.error)
3377 stream.setStatus(QDataStream::ReadCorruptData);
3378 return stream;
3379}
3380#endif
3381
3382
3383QT_END_NAMESPACE
3384
3385#include "qcborarray.cpp"
3386#include "qcbormap.cpp"
3387
3388#ifndef QT_NO_QOBJECT
3389#include "moc_qcborvalue.cpp"
3390#endif
3391

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/serialization/qcborvalue.cpp