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// Qt-Security score:critical reason:data-parser
4
5#include "qcborvalue.h"
6#include "qcborvalue_p.h"
7#include "qdatastream.h"
8#include "qcborarray.h"
9#include "qcbormap.h"
10
11#if QT_CONFIG(cborstreamreader)
12#include "qcborstreamreader.h"
13#endif
14
15#if QT_CONFIG(cborstreamwriter)
16#include "qcborstreamwriter.h"
17#endif
18
19#include <QtCore/qdebug.h>
20#include <qendian.h>
21#include <qlocale.h>
22#include <qdatetime.h>
23#include <qtimezone.h>
24#include <private/qnumeric_p.h>
25#include <private/qsimd_p.h>
26
27#include <new>
28
29QT_BEGIN_NAMESPACE
30
31QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCborContainerPrivate)
32
33// Worst case memory allocation for a corrupt stream: 256 MB for 32-bit, 1 GB for 64-bit
34static constexpr quint64 MaxAcceptableMemoryUse = (sizeof(void*) == 4 ? 256 : 1024) * 1024 * 1024;
35
36// Internal limits to ensure we don't blow up the memory when parsing a corrupt
37// (possibly crafted to exploit) CBOR stream. The recursion impacts both the
38// maps/arrays we'll open when parsing and the thread's stack, as the parser is
39// itself recursive. If someone really needs more than 1024 layers of nesting,
40// they probably have a weird use-case for which custom parsing and
41// serialisation code would make sense. The limit on element count is the
42// preallocated limit: if the stream does actually have more elements, we will
43// grow the container.
44Q_DECL_UNUSED static constexpr int MaximumRecursionDepth = 1024;
45Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
46 MaxAcceptableMemoryUse / MaximumRecursionDepth / sizeof(QtCbor::Element) - 1;
47
48/*!
49 \class QCborValue
50 \inmodule QtCore
51 \ingroup cbor
52 \ingroup qtserialization
53 \reentrant
54 \since 5.12
55
56 \brief The QCborValue class encapsulates a value in CBOR.
57
58 \compares strong
59
60 This class can be used to hold one of the many types available in CBOR.
61 CBOR is the Concise Binary Object Representation, a very compact form of
62 binary data encoding that is a superset of JSON. It was created by the IETF
63 Constrained RESTful Environments (CoRE) WG, which has used it in many
64 new RFCs. It is meant to be used alongside the
65 \l{RFC 7252}{CoAP protocol}.
66
67 CBOR has three groups of built-in types:
68
69 \list
70 \li Basic types: integers, floating point (double), boolean, null, etc.
71 \li String-like types: strings and byte arrays
72 \li Containers: arrays and maps
73 \endlist
74
75 Additionally, CBOR supports a form of type extensibility by associating a
76 "tag" to one of the above types to convey more information. For example, a
77 UUID is represented by a tag and a byte array containing the 16 bytes of
78 the UUID content. QCborValue supports creating and decoding several of those
79 extended types directly with Qt classes (like QUuid).
80
81 For the complete list, see \l QCborValue::Type. The type of a QCborValue can
82 be queried using type() or one of the "isXxxx" functions.
83
84 \section1 Extended types and tagged values
85
86 A tagged value is a normal QCborValue that is paired with a number that
87 is its tag. See \l QCborKnownTags for more information on what tags are in
88 the API as well as the full, official list. Such combinations form extended
89 types.
90
91 QCborValue has support for certain extended types in the API, like URL
92 (with \l QUrl) and UUID (with \l QUuid). Other extended types not supported
93 in the API are represented by a QCborValue of \l {Type}{Tag} type. The tag
94 can later be retrieved by tag() and the tagged value using taggedValue().
95
96 In order to support future compatibility, QCborValues containing extended
97 Qt types compare equal to the tag type of the same contents. In other
98 words, the following expression is true:
99
100 \snippet code/src_corelib_serialization_qcborvalue.cpp 0
101
102 \section1 Undefined and null values
103
104 QCborValue can contain a value of "null", which is not of any specific type.
105 It resembles the C++ \c {std::nullptr_t} type, whose only possible value is
106 \nullptr. QCborValue has a constructor taking such a type and creates a
107 null QCborValue.
108
109 Null values are used to indicate that an optional value is not present. In
110 that aspect, it is similar to the C++ Standard Library type \c
111 {std::optional} when that is disengaged. Unlike the C++ type, CBOR nulls
112 are simply of type "Null" and it is not possible to determine what concrete
113 type it is replacing.
114
115 QCborValue can also be of the undefined type, which represents a value of
116 "undefined". In fact, that is what the QCborValue default constructor
117 creates.
118
119 Undefined values are different from null values. While nulls are used to
120 indicate an optional value that is not provided, Undefined is usually
121 used to indicate that an expected value could not be provided, usually due
122 to an error or a precondition that could not be satisfied.
123
124 Such values are completely valid and may appear in CBOR streams, unlike
125 JSON content and QJsonValue's undefined bit. But like QJsonValue's
126 Undefined, it is returned by a CBOR container's value() or read-only
127 operator[] for invalid look-ups (index out of range for QCborArray, or key
128 not found for QCborMap). It is not possible to tell such a case apart from
129 the value of Undefined, so if that is required, check the QCborArray size
130 and use the QCborMap iterator API.
131
132 \section1 Simple types
133
134 CBOR supports additional simple types that, like Null and Undefined, carry
135 no other value. They are called interchangeably "Simple Types" and "Simple
136 Values". CBOR encodes booleans as two distinct types (one for \c true and
137 one for \c false), but QCborValue has a convenience API for them.
138
139 There are currently no other defined CBOR simple types. QCborValue supports
140 them simply by their number with API like isSimpleType() and
141 toSimpleType(), available for compatibility with future specifications
142 before the Qt API can be updated. Their use before such a specification is
143 discouraged, as other CBOR implementations may not support them fully.
144
145 \section1 CBOR support
146
147 QCborValue supports all CBOR features required to create canonical and
148 strict streams. It implements almost all of the features specified in \l
149 {RFC 7049}.
150
151 The following table lists the CBOR features that QCborValue supports.
152
153 \table
154 \header \li Feature \li Support
155 \row \li Unsigned numbers \li Yes (\l qint64 range)
156 \row \li Negative numbers \li Yes (\l qint64 range)
157 \row \li Byte strings \li Yes
158 \row \li Text strings \li Yes
159 \row \li Chunked strings \li See below
160 \row \li Tags \li Yes (arbitrary)
161 \row \li Booleans \li Yes
162 \row \li Null \li Yes
163 \row \li Undefined \li Yes
164 \row \li Arbitrary simple values \li Yes
165 \row \li Half-precision float (16-bit) \li Yes
166 \row \li Single-precision float (32-bit) \li Yes
167 \row \li Double-precision float (64-bit) \li Yes
168 \row \li Infinities and NaN floating point \li Yes
169 \row \li Determinate-length arrays and maps \li Yes
170 \row \li Indeterminate-length arrays and maps \li Yes
171 \row \li Map key types other than strings and integers \li Yes (arbitrary)
172 \endtable
173
174 Integers in QCborValue are limited to the range of the \l qint64 type. That
175 is, from -9,223,372,036,854,775,808 (-2\sup{63}) to
176 9,223,372,036,854,775,807 (2\sup{63} - 1). CBOR itself can represent integer
177 values outside of this range, which QCborValue does not support. When
178 decoding a stream using fromCbor() containing one of those values,
179 QCborValue will convert automatically to \l {Type}{Double}, but that may
180 lose up to 11 bits of precision.
181
182 fromCbor() is able to decode chunked strings, but will always merge the
183 chunks together into a single QCborValue. For that reason, it always writes
184 non-chunked strings when using toCbor() (which is required by the Canonical
185 format anyway).
186
187 QCborValue will always convert half- and single-precision floating point
188 values in the CBOR stream to double-precision. The toCbor() function can
189 take a parameter indicating to recreate them.
190
191 \section1 QCborValueRef
192
193 QCborValueRef is a helper class for QCborArray and QCborMap. It is the type
194 you get when using one of the mutating APIs in those classes. Unlike
195 QCborValue, new values can be assigned to that class. When that is done, the
196 array or map it refers to will be modified with the new value. In all other
197 aspects, its API is identical to QCborValue.
198
199 \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter,
200 QJsonValue, QJsonDocument, {Serialization Converter}, {Saving and Loading a Game}
201 {Parsing and displaying CBOR data}
202 */
203
204/*!
205 \class QCborParserError
206 \inmodule QtCore
207 \ingroup cbor
208 \reentrant
209 \since 5.12
210
211 \brief The QCborParserError is used by QCborValue to report a parsing error.
212
213 This class is used by \l {QCborValue::fromCbor(const QByteArray &ba,
214 QCborParserError *error)} to report a parser error and the byte offset
215 where the error was detected.
216
217 \sa QCborValue, QCborError
218 */
219
220/*!
221 \variable QCborParserError::offset
222
223 This field contains the offset from the beginning of the data where the
224 error was detected. The offset should point to the beginning of the item
225 that contained the error, even if the error itself was elsewhere (for
226 example, for UTF-8 decoding issues).
227
228 \sa QCborValue::fromCbor()
229 */
230
231/*!
232 \variable QCborParserError::error
233
234 This field contains the error code that indicates what decoding problem was
235 found.
236
237 \sa QCborValue::fromCbor()
238 */
239
240/*!
241 \fn QString QCborParserError::errorString() const
242
243 Returns a string representation of the error code. This string is not
244 translated.
245
246 \sa QCborError::toString(), QCborValue::fromCbor()
247 */
248
249/*!
250 \enum QCborValue::EncodingOption
251
252 This enum is used in the options argument to toCbor(), modifying the
253 behavior of the encoder.
254
255 \omitvalue SortKeysInMaps
256 \value NoTransformation (Default) Performs no transformations.
257 \value UseFloat Tells the encoder to use IEEE 754 single-precision floating point
258 (that is, \c float) whenever possible.
259 \value UseFloat16 Tells the encoder to use IEEE 754 half-precision floating point
260 (that is, \c qfloat16), whenever possible. Implies \c UseFloat.
261 \value UseIntegers Tells the encoder to use integers whenever a value of type \l
262 {Type}{Double} contains an integer.
263
264 The use of \c UseFloat16 is required to encode the stream in Canonical
265 Format, but is not otherwise necessary.
266
267 \sa toCbor()
268 */
269
270/*!
271 \enum QCborValue::DiagnosticNotationOption
272
273 This enum is used in the option argument to toDiagnosticNotation(), to
274 modify the output format.
275
276 \value Compact Does not use any line-breaks, producing a compact representation.
277 \value LineWrapped Uses line-breaks, one QCborValue per line.
278 \value ExtendedFormat Uses some different options to represent values, not found in
279 RFC 7049. Those options are subject to change.
280
281 Currently, \c ExtendedFormat will change how byte arrays are represented.
282 Without it, they are always hex-encoded and without spaces. With it,
283 QCborValue::toCbor() will either use hex with spaces, base64 or base64url
284 encoding, depending on the context.
285
286 \sa toDiagnosticNotation()
287 */
288
289/*!
290 \enum QCborValue::Type
291
292 This enum represents the QCborValue type. It is returned by the type()
293 function.
294
295 The CBOR built-in types are:
296
297 \value Integer \c qint64: An integer value
298 \value ByteArray \l QByteArray: a byte array ("byte string")
299 \value String \l QString: a Unicode string ("text string")
300 \value Array \l QCborArray: an array of QCborValues
301 \value Map \l QCborMap: an associative container of QCborValues
302 \value SimpleType \l QCborSimpleType: one of several simple types/values
303 \value False \c bool: the simple type for value \c false
304 \value True \c bool: the simple type for value \c true
305 \value Null \c std::nullptr_t: the simple type for the null value
306 \value Undefined (no type) the simple type for the undefined value
307 \value Double \c double: a double-precision floating point
308 \value Invalid Not a valid value, this usually indicates a CBOR decoding error
309
310 Additionally, QCborValue can represent extended types:
311
312 \value Tag An unknown or unrecognized extended type, represented by its
313 tag (a \l QCborTag) and the tagged value (a QCborValue)
314 \value DateTime \l QDateTime: a date and time stamp
315 \value Url \l QUrl: a URL or URI
316 \value RegularExpression \l QRegularExpression: the pattern of a regular expression
317 \value Uuid \l QUuid: a UUID
318
319 \sa type()
320 */
321
322/*!
323 \fn QCborValue::QCborValue()
324
325 Creates a QCborValue of the \l {Type}{Undefined} type.
326
327 CBOR undefined values are used to indicate missing information, usually as
328 a result of a previous operation that did not complete as expected. They
329 are also used by the QCborArray and QCborMap API to indicate the searched
330 item was not found.
331
332 Undefined values are represented by the \l {QCborSimpleType}{Undefined
333 simple type}. Because of that, QCborValues with undefined values will also
334 return true for isSimpleType() and
335 \c{isSimpleType(QCborSimpleType::Undefined)}.
336
337 Undefined values are different from null values.
338
339 QCborValue objects with undefined values are also different from invalid
340 QCborValue objects. The API will not create invalid QCborValues, but they
341 may exist as a result of a parsing error.
342
343 \sa isUndefined(), isNull(), isSimpleType()
344 */
345
346/*!
347 \fn QCborValue::QCborValue(Type t_)
348
349 Creates a QCborValue of type \a t_. The value associated with such a type
350 (if any) will be default constructed.
351
352 \sa type()
353 */
354
355/*!
356 \fn QCborValue::QCborValue(std::nullptr_t)
357
358 Creates a QCborValue of the \l {Type}{Null} type.
359
360 CBOR null values are used to indicate optional values that were not
361 provided. They are distinct from undefined values, in that null values are
362 usually not the result of an earlier error or problem.
363
364 \sa isNull(), isUndefined(), isSimpleType()
365 */
366
367/*!
368 \fn QCborValue::QCborValue(bool b)
369
370 Creates a QCborValue with boolean value \a b. The value can later be
371 retrieved using toBool().
372
373 Internally, CBOR booleans are represented by a pair of types, one for true
374 and one for false. For that reason, boolean QCborValues will return true
375 for isSimpleType() and one of \c{isSimpleType(QCborSimpleType::False)} or
376 \c{isSimpleType(QCborSimpleType::True)}.
377
378 \sa toBool(), isBool(), isTrue(), isFalse(), isSimpleType()
379 */
380
381/*!
382 \fn QCborValue::QCborValue(qint64 i)
383
384 Creates a QCborValue with integer value \a i. The value can later be
385 retrieved using toInteger().
386
387 CBOR integer values are distinct from floating point values. Therefore,
388 QCborValue objects with integers will compare differently to QCborValue
389 objects containing floating-point, even if the values contained in the
390 objects are equivalent.
391
392 \sa toInteger(), isInteger(), isDouble()
393 */
394
395/*!
396 \fn QCborValue::QCborValue(double d)
397
398 Creates a QCborValue with floating point value \a d. The value can later be
399 retrieved using toDouble().
400
401 CBOR floating point values are distinct from integer values. Therefore,
402 QCborValue objects with integers will compare differently to QCborValue
403 objects containing floating-point, even if the values contained in the
404 objects are equivalent.
405
406 \sa toDouble(), isDouble(), isInteger()
407 */
408
409/*!
410 \fn QCborValue::QCborValue(QCborSimpleType st)
411
412 Creates a QCborValue of simple type \a st. The type can later be retrieved
413 using toSimpleType() as well as isSimpleType(st).
414
415 CBOR simple types are types that do not have any associated value, like
416 C++'s \c{std::nullptr_t} type, whose only possible value is \nullptr.
417
418 If \a st is \c{QCborSimpleType::Null}, the resulting QCborValue will be of
419 the \l{Type}{Null} type and similarly for \c{QCborSimpleType::Undefined}.
420 If \a st is \c{QCborSimpleType::False} or \c{QCborSimpleType::True}, the
421 created QCborValue will be a boolean containing a value of false or true,
422 respectively.
423
424 This function can be used with simple types not defined in the API. For
425 example, to create a QCborValue with simple type 12, one could write:
426
427 \snippet code/src_corelib_serialization_qcborvalue.cpp 1
428
429 Simple types should not be used until a specification for them has been
430 published, since other implementations may not support them properly.
431 Simple type values 24 to 31 are reserved and must not be used.
432
433 isSimpleType(), isNull(), isUndefined(), isTrue(), isFalse()
434 */
435
436/*!
437 \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &taggedValue)
438 \overload
439
440 Creates a QCborValue for the extended type represented by the tag value \a
441 tag, tagging value \a taggedValue. The tag can later be retrieved using
442 tag() and the tagged value using taggedValue().
443
444 \sa isTag(), tag(), taggedValue(), QCborKnownTags
445 */
446
447/*!
448 \fn QCborValue::~QCborValue()
449
450 Disposes of the current QCborValue object and frees any associated resources.
451 */
452
453/*!
454 \fn QCborValue::QCborValue(QCborValue &&other)
455 \overload
456
457 Moves the contents of the \a other QCborValue object into this one and frees
458 the resources of this one.
459 */
460
461/*!
462 \fn QCborValue &&QCborValue::operator=(QCborValue &&other)
463 \overload
464
465 Moves the contents of the \a other QCborValue object into this one and frees
466 the resources of this one. Returns a reference to this object.
467 */
468
469/*!
470 \fn void QCborValue::swap(QCborValue &other)
471 \memberswap{value}
472 */
473
474/*!
475 \fn QCborValue::Type QCborValue::type() const
476
477 Returns the type of this QCborValue. The type can also later be retrieved by one
478 of the "isXxx" functions.
479
480 \sa isInteger(), isByteArray(), isString(), isArray(), isMap(),
481 isTag(), isFalse(), isTrue(), isBool(), isNull(), isUndefined, isDouble(),
482 isDateTime(), isUrl(), isRegularExpression(), isUuid()
483 */
484
485/*!
486 \fn bool QCborValue::isInteger() const
487
488 Returns true if this QCborValue is of the integer type. The integer value
489 can be retrieved using toInteger().
490
491 \sa type(), toInteger()
492 */
493
494/*!
495 \fn bool QCborValue::isByteArray() const
496
497 Returns true if this QCborValue is of the byte array type. The byte array
498 value can be retrieved using toByteArray().
499
500 \sa type(), toByteArray()
501 */
502
503/*!
504 \fn bool QCborValue::isString() const
505
506 Returns true if this QCborValue is of the string type. The string value
507 can be retrieved using toString().
508
509 \sa type(), toString()
510 */
511
512/*!
513 \fn bool QCborValue::isArray() const
514
515 Returns true if this QCborValue is of the array type. The array value can
516 be retrieved using toArray().
517
518 \sa type(), toArray()
519 */
520
521/*!
522 \fn bool QCborValue::isMap() const
523
524 Returns true if this QCborValue is of the map type. The map value can be
525 retrieved using toMap().
526
527 \sa type(), toMap()
528 */
529
530/*!
531 \fn bool QCborValue::isTag() const
532
533 Returns true if this QCborValue is of the tag type. The tag value can be
534 retrieved using tag() and the tagged value using taggedValue().
535
536 This function also returns true for extended types that the API
537 recognizes. For code that handles extended types directly before the Qt API
538 is updated to support them, it is possible to recreate the tag + tagged
539 value pair by using taggedValue().
540
541 \sa type(), tag(), taggedValue(), taggedValue()
542 */
543
544/*!
545 \fn bool QCborValue::isFalse() const
546
547 Returns true if this QCborValue is a boolean with false value. This
548 function exists because, internally, CBOR booleans are stored as two
549 separate types, one for true and one for false.
550
551 \sa type(), isBool(), isTrue(), toBool()
552 */
553
554/*!
555 \fn bool QCborValue::isTrue() const
556
557 Returns true if this QCborValue is a boolean with true value. This
558 function exists because, internally, CBOR booleans are stored as two
559 separate types, one for false and one for true.
560
561 \sa type(), isBool(), isFalse(), toBool()
562 */
563
564/*!
565 \fn bool QCborValue::isBool() const
566
567 Returns true if this QCborValue is a boolean. The value can be retrieved
568 using toBool().
569
570 \sa type(), toBool(), isTrue(), isFalse()
571 */
572
573/*!
574 \fn bool QCborValue::isUndefined() const
575
576 Returns true if this QCborValue is of the undefined type.
577
578 CBOR undefined values are used to indicate missing information, usually as
579 a result of a previous operation that did not complete as expected. They
580 are also used by the QCborArray and QCborMap API to indicate the searched
581 item was not found.
582
583 Undefined values are distinct from null values.
584
585 QCborValue objects with undefined values are also different from invalid
586 QCborValue objects. The API will not create invalid QCborValues, but they
587 may exist as a result of a parsing error.
588
589 \sa type(), isNull(), isInvalid()
590 */
591
592/*!
593 \fn bool QCborValue::isNull() const
594
595 Returns true if this QCborValue is of the null type.
596
597 CBOR null values are used to indicate optional values that were not
598 provided. They are distinct from undefined values, in that null values are
599 usually not the result of an earlier error or problem.
600
601 Null values are distinct from undefined values and from invalid QCborValue
602 objects. The API will not create invalid QCborValues, but they may exist as
603 a result of a parsing error.
604
605 \sa type(), isUndefined(), isInvalid()
606 */
607
608/*!
609 \fn bool QCborValue::isDouble() const
610
611 Returns true if this QCborValue is of the floating-point type. The value
612 can be retrieved using toDouble().
613
614 \sa type(), toDouble()
615 */
616
617/*!
618 \fn bool QCborValue::isDateTime() const
619
620 Returns true if this QCborValue is of the date/time type. The value can be
621 retrieved using toDateTime(). Date/times are extended types that use the
622 tag \l{QCborKnownTags}{DateTime}.
623
624 Additionally, when decoding from a CBOR stream, QCborValue will interpret
625 tags of value \l{QCborKnownTags}{UnixTime_t} and convert them to the
626 equivalent date/time.
627
628 \sa type(), toDateTime()
629 */
630
631/*!
632 \fn bool QCborValue::isUrl() const
633
634 Returns true if this QCborValue is of the URL type. The URL value
635 can be retrieved using toUrl().
636
637 \sa type(), toUrl()
638 */
639
640/*!
641 \fn bool QCborValue::isRegularExpression() const
642
643 Returns true if this QCborValue contains a regular expression's pattern.
644 The pattern can be retrieved using toRegularExpression().
645
646 \sa type(), toRegularExpression()
647 */
648
649/*!
650 \fn bool QCborValue::isUuid() const
651
652 Returns true if this QCborValue contains a UUID. The value can be retrieved
653 using toUuid().
654
655 \sa type(), toUuid()
656 */
657
658/*!
659 \fn bool QCborValue::isInvalid() const
660
661 Returns true if this QCborValue is not of any valid type. Invalid
662 QCborValues are distinct from those with undefined values and they usually
663 represent a decoding error.
664
665 \sa isUndefined(), isNull()
666 */
667
668/*!
669 \fn bool QCborValue::isContainer() const
670
671 This convenience function returns true if the QCborValue is either an array
672 or a map.
673
674 \sa isArray(), isMap()
675 */
676
677/*!
678 \fn bool QCborValue::isSimpleType() const
679
680 Returns true if this QCborValue is of one of the CBOR simple types. The
681 type itself can later be retrieved using type(), even for types that don't have an
682 enumeration in the API. They can also be checked with the
683 \l{isSimpleType(QCborSimpleType)} overload.
684
685 \sa QCborSimpleType, isSimpleType(QCborSimpleType), toSimpleType()
686 */
687
688/*!
689 \fn bool QCborValue::isSimpleType(QCborSimpleType st) const
690 \overload
691
692 Returns true if this QCborValue is of a simple type and toSimpleType()
693 would return \a st, false otherwise. This function can be used to check for
694 any CBOR simple type, even those for which there is no enumeration in the
695 API. For example, for the simple type of value 12, you could write:
696
697 \snippet code/src_corelib_serialization_qcborvalue.cpp 2
698
699 \sa QCborValue::QCborValue(QCborSimpleType), isSimpleType(), isFalse(),
700 isTrue(), isNull, isUndefined(), toSimpleType()
701 */
702
703/*!
704 \fn QCborSimpleType QCborValue::toSimpleType(QCborSimpleType defaultValue) const
705
706 Returns the simple type this QCborValue is of, if it is a simple type. If
707 it is not a simple type, it returns \a defaultValue.
708
709 The following types are simple types and this function will return the
710 listed values:
711
712 \table
713 \row \li QCborValue::False \li QCborSimpleType::False
714 \row \li QCborValue::True \li QCborSimpleType::True
715 \row \li QCborValue::Null \li QCborSimpleType::Null
716 \row \li QCborValue::Undefined \li QCborSimpleType::Undefined
717 \endtable
718
719 \sa type(), isSimpleType(), isBool(), isTrue(), isFalse(), isTrue(),
720 isNull(), isUndefined()
721 */
722
723/*!
724 \fn qint64 QCborValue::toInteger(qint64 defaultValue) const
725
726 Returns the integer value stored in this QCborValue, if it is of the
727 integer type. If it is of the Double type, this function returns the
728 floating point value converted to integer. In any other case, it returns \a
729 defaultValue.
730
731 \sa isInteger(), isDouble(), toDouble()
732 */
733
734/*!
735 \fn bool QCborValue::toBool(bool defaultValue) const
736
737 Returns the boolean value stored in this QCborValue, if it is of a boolean
738 type. Otherwise, it returns \a defaultValue.
739
740 \sa isBool(), isTrue(), isFalse()
741 */
742
743/*!
744 \fn double QCborValue::toDouble(double defaultValue) const
745
746 Returns the floating point value stored in this QCborValue, if it is of the
747 Double type. If it is of the Integer type, this function returns the
748 integer value converted to double. In any other case, it returns \a
749 defaultValue.
750
751 \sa isDouble(), isInteger(), toInteger()
752 */
753
754using namespace QtCbor;
755
756static QCborContainerPrivate *assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
757{
758 if (d == x)
759 return d;
760 if (d)
761 d->deref();
762 if (x)
763 x->ref.ref();
764 return d = x;
765}
766
767static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
768{
769 qint64 tag = d->elements.at(i: 0).value;
770 auto &e = d->elements[1];
771 const ByteData *b = d->byteData(e);
772
773 auto replaceByteData = [&](const char *buf, qsizetype len, Element::ValueFlags f) {
774 d->data.clear();
775 d->usedData = 0;
776 e.flags = Element::HasByteData | f;
777 e.value = d->addByteData(block: buf, len);
778 };
779
780 switch (tag) {
781#if QT_CONFIG(datestring)
782 case qint64(QCborKnownTags::DateTimeString):
783 case qint64(QCborKnownTags::UnixTime_t): {
784 QDateTime dt;
785 if (tag == qint64(QCborKnownTags::DateTimeString) && b &&
786 e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) {
787 // The data is supposed to be US-ASCII. If it isn't (contains UTF-8),
788 // QDateTime::fromString will fail anyway.
789 dt = QDateTime::fromString(string: b->asLatin1(), format: Qt::ISODateWithMs);
790 } else if (tag == qint64(QCborKnownTags::UnixTime_t)) {
791 qint64 msecs;
792 bool ok = false;
793 if (e.type == QCborValue::Integer) {
794#if QT_POINTER_SIZE == 8
795 // we don't have a fast 64-bit qMulOverflow implementation on
796 // 32-bit architectures.
797 ok = !qMulOverflow(v1: e.value, v2: qint64(1000), r: &msecs);
798#else
799 static const qint64 Limit = std::numeric_limits<qint64>::max() / 1000;
800 ok = (e.value > -Limit && e.value < Limit);
801 if (ok)
802 msecs = e.value * 1000;
803#endif
804 } else if (e.type == QCborValue::Double) {
805 ok = convertDoubleTo(v: round(x: e.fpvalue() * 1000), value: &msecs);
806 }
807 if (ok)
808 dt = QDateTime::fromMSecsSinceEpoch(msecs, timeZone: QTimeZone::UTC);
809 }
810 if (dt.isValid()) {
811 QByteArray text = dt.toString(format: Qt::ISODateWithMs).toLatin1();
812 if (!text.isEmpty()) {
813 replaceByteData(text, text.size(), Element::StringIsAscii);
814 e.type = QCborValue::String;
815 d->elements[0].value = qint64(QCborKnownTags::DateTimeString);
816 return QCborValue::DateTime;
817 }
818 }
819 break;
820 }
821#endif
822
823#ifndef QT_BOOTSTRAPPED
824 case qint64(QCborKnownTags::Url):
825 if (e.type == QCborValue::String) {
826 if (b) {
827 // normalize to a short (decoded) form, so as to save space
828 QUrl url(e.flags & Element::StringIsUtf16 ?
829 b->asQStringRaw() :
830 b->toUtf8String(), QUrl::StrictMode);
831 if (url.isValid()) {
832 QByteArray encoded = url.toString(options: QUrl::DecodeReserved).toUtf8();
833 replaceByteData(encoded, encoded.size(), {});
834 }
835 }
836 return QCborValue::Url;
837 }
838 break;
839#endif // QT_BOOTSTRAPPED
840
841#if QT_CONFIG(regularexpression)
842 case quint64(QCborKnownTags::RegularExpression):
843 if (e.type == QCborValue::String) {
844 // no normalization is necessary
845 return QCborValue::RegularExpression;
846 }
847 break;
848#endif // QT_CONFIG(regularexpression)
849
850 case qint64(QCborKnownTags::Uuid):
851 if (e.type == QCborValue::ByteArray) {
852 // force the size to 16
853 char buf[sizeof(QUuid)] = {};
854 if (b)
855 memcpy(dest: buf, src: b->byte(), n: qMin(a: sizeof(buf), b: size_t(b->len)));
856 replaceByteData(buf, sizeof(buf), {});
857
858 return QCborValue::Uuid;
859 }
860 break;
861 }
862
863 // no enriching happened
864 return QCborValue::Tag;
865}
866
867#if QT_CONFIG(cborstreamwriter) && !defined(QT_BOOTSTRAPPED)
868static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
869{
870 if (qt_is_nan(d)) {
871 if (opt & QCborValue::UseFloat) {
872 if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16)
873 return writer.append(f: std::numeric_limits<qfloat16>::quiet_NaN());
874 return writer.append(f: std::numeric_limits<float>::quiet_NaN());
875 }
876 return writer.append(d: qt_qnan());
877 }
878
879 if (qt_is_inf(d)) {
880 d = d > 0 ? qt_inf() : -qt_inf();
881 } else if (opt & QCborValue::UseIntegers) {
882 quint64 i;
883 if (convertDoubleTo(v: d, value: &i)) {
884 if (d < 0)
885 return writer.append(n: QCborNegativeInteger(i));
886 return writer.append(u: i);
887 }
888 }
889
890 if (opt & QCborValue::UseFloat) {
891 float f = float(d);
892 if (f == d) {
893 // no data loss, we could use float
894 if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16) {
895 qfloat16 f16 = qfloat16(f);
896 if (f16 == f)
897 return writer.append(f: f16);
898 }
899
900 return writer.append(f);
901 }
902 }
903
904 writer.append(d);
905}
906#endif // QT_CONFIG(cborstreamwriter) && !QT_BOOTSTRAPPED
907
908static inline int typeOrder(QCborValue::Type e1, QCborValue::Type e2)
909{
910 auto comparable = [](QCborValue::Type type) {
911 if (type >= 0x10000) // see QCborValue::isTag_helper()
912 return QCborValue::Tag;
913 return type;
914 };
915 return comparable(e1) - comparable(e2);
916}
917
918QCborContainerPrivate::~QCborContainerPrivate()
919{
920 // delete our elements
921 for (Element &e : elements) {
922 if (e.flags & Element::IsContainer)
923 e.container->deref();
924 }
925}
926
927void QCborContainerPrivate::compact()
928{
929 if (usedData > data.size() / 2)
930 return;
931
932 // 50% savings if we recreate the byte data
933 QByteArray newData;
934 QByteArray::size_type newUsedData = 0;
935 // Compact only elements that have byte data.
936 // Nested containers will be compacted when their data changes.
937 for (auto &e : elements) {
938 if (e.flags & Element::HasByteData) {
939 if (const ByteData *b = byteData(e))
940 e.value = addByteDataImpl(target&: newData, targetUsed&: newUsedData, block: b->byte(), len: b->len);
941 }
942 }
943 data = newData;
944 usedData = newUsedData;
945}
946
947QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qsizetype reserved)
948{
949 if (!d) {
950 d = new QCborContainerPrivate;
951 } else {
952 // in case QList::reserve throws
953 QExplicitlySharedDataPointer u(new QCborContainerPrivate(*d));
954 if (reserved >= 0) {
955 u->elements.reserve(asize: reserved);
956 u->compact();
957 }
958
959 d = u.take();
960 d->ref.storeRelaxed(newValue: 0);
961
962 for (auto &e : std::as_const(t&: d->elements)) {
963 if (e.flags & Element::IsContainer)
964 e.container->ref.ref();
965 }
966 }
967 return d;
968}
969
970QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, qsizetype reserved)
971{
972 if (!d || d->ref.loadRelaxed() != 1)
973 return clone(d, reserved);
974 return d;
975}
976
977/*!
978 Prepare for an insertion at position \a index
979
980 Detaches and ensures there are at least index entries in the array, padding
981 with Undefined as needed.
982*/
983QCborContainerPrivate *QCborContainerPrivate::grow(QCborContainerPrivate *d, qsizetype index)
984{
985 Q_ASSERT(index >= 0);
986 d = detach(d, reserved: index + 1);
987 Q_ASSERT(d);
988 qsizetype j = d->elements.size();
989 while (j++ < index)
990 d->append(Undefined());
991 return d;
992}
993
994// Copies or moves \a value into element at position \a e. If \a disp is
995// CopyContainer, then this function increases the reference count of the
996// container, but otherwise leaves it unmodified. If \a disp is MoveContainer,
997// then it transfers ownership (move semantics) and the caller must set
998// value.container back to nullptr.
999void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &value, ContainerDisposition disp)
1000{
1001 if (value.n < 0) {
1002 // This QCborValue is an array, map, or tagged value (container points
1003 // to itself).
1004
1005 // detect self-assignment
1006 if (Q_UNLIKELY(this == value.container)) {
1007 Q_ASSERT(ref.loadRelaxed() >= 2);
1008 if (disp == MoveContainer)
1009 ref.deref(); // not deref() because it can't drop to 0
1010 QCborContainerPrivate *d = QCborContainerPrivate::clone(d: this);
1011 d->elements.detach();
1012 d->ref.storeRelaxed(newValue: 1);
1013 e.container = d;
1014 } else {
1015 e.container = value.container;
1016 if (disp == CopyContainer)
1017 e.container->ref.ref();
1018 }
1019
1020 e.type = value.type();
1021 e.flags = Element::IsContainer;
1022 } else {
1023 // String data, copy contents
1024 e = value.container->elements.at(i: value.n);
1025
1026 // Copy string data, if any
1027 if (const ByteData *b = value.container->byteData(idx: value.n)) {
1028 const auto flags = e.flags;
1029 // The element e has an invalid e.value, because it is copied from
1030 // value. It means that calling compact() will trigger an assertion
1031 // or just silently corrupt the data.
1032 // Temporarily unset the Element::HasByteData flag in order to skip
1033 // the element e in the call to compact().
1034 e.flags = e.flags & ~Element::HasByteData;
1035 if (this == value.container) {
1036 const QByteArray valueData = b->toByteArray();
1037 compact();
1038 e.value = addByteData(block: valueData, len: valueData.size());
1039 } else {
1040 compact();
1041 e.value = addByteData(block: b->byte(), len: b->len);
1042 }
1043 // restore the flags
1044 e.flags = flags;
1045 }
1046
1047 if (disp == MoveContainer)
1048 value.container->deref();
1049 }
1050}
1051
1052// in qstring.cpp
1053void qt_to_latin1_unchecked(uchar *dst, const char16_t *uc, qsizetype len);
1054
1055Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s)
1056{
1057 qsizetype len = s.size();
1058 QtCbor::Element e;
1059 e.value = addByteData(block: nullptr, len);
1060 e.type = QCborValue::String;
1061 e.flags = Element::HasByteData | Element::StringIsAscii;
1062 elements.append(t: e);
1063
1064 char *ptr = data.data() + e.value + sizeof(ByteData);
1065 uchar *l = reinterpret_cast<uchar *>(ptr);
1066 qt_to_latin1_unchecked(dst: l, uc: s.utf16(), len);
1067}
1068
1069void QCborContainerPrivate::appendNonAsciiString(QStringView s)
1070{
1071 appendByteData(data: reinterpret_cast<const char *>(s.utf16()), len: s.size() * 2,
1072 type: QCborValue::String, extraFlags: QtCbor::Element::StringIsUtf16);
1073}
1074
1075QCborValue QCborContainerPrivate::extractAt_complex(Element e)
1076{
1077 // create a new container for the returned value, containing the byte data
1078 // from this element, if it's worth it
1079 Q_ASSERT(e.flags & Element::HasByteData);
1080 auto b = byteData(e);
1081 auto container = new QCborContainerPrivate;
1082
1083 if (b->len + qsizetype(sizeof(*b)) < data.size() / 4) {
1084 // make a shallow copy of the byte data
1085 container->appendByteData(data: b->byte(), len: b->len, type: e.type, extraFlags: e.flags);
1086 usedData -= b->len + qsizetype(sizeof(*b));
1087 compact();
1088 } else {
1089 // just share with the original byte data
1090 container->data = data;
1091 container->elements.reserve(asize: 1);
1092 container->elements.append(t: e);
1093 }
1094
1095 return makeValue(type: e.type, n: 0, d: container);
1096}
1097
1098// Similar to QStringIterator::next() but returns malformed surrogate pair
1099// itself when one is detected, and returns the length in UTF-8.
1100static auto nextUtf32Character(const char16_t *&ptr, const char16_t *end) noexcept
1101{
1102 Q_ASSERT(ptr != end);
1103 struct R {
1104 char32_t c;
1105 qsizetype len = 1; // in UTF-8 code units (bytes)
1106 } r = { .c: *ptr++ };
1107
1108 if (r.c < 0x0800) {
1109 if (r.c >= 0x0080)
1110 ++r.len;
1111 } else if (!QChar::isHighSurrogate(ucs4: r.c) || ptr == end) {
1112 r.len += 2;
1113 } else {
1114 r.len += 3;
1115 r.c = QChar::surrogateToUcs4(high: r.c, low: *ptr++);
1116 }
1117
1118 return r;
1119}
1120
1121static qsizetype stringLengthInUtf8(const char16_t *ptr, const char16_t *end) noexcept
1122{
1123 qsizetype len = 0;
1124 while (ptr < end)
1125 len += nextUtf32Character(ptr, end).len;
1126 return len;
1127}
1128
1129static int compareStringsInUtf8(QStringView lhs, QStringView rhs, Comparison mode) noexcept
1130{
1131 if (mode == Comparison::ForEquality)
1132 return lhs == rhs ? 0 : 1;
1133
1134 // The UTF-16 length is *usually* comparable, but not always. There are
1135 // pathological cases where they can be wrong, so we need to compare as if
1136 // we were doing it in UTF-8. That includes the case of UTF-16 surrogate
1137 // pairs, because qstring.cpp sorts them before U+E000-U+FFFF.
1138 int diff = 0;
1139 qsizetype len1 = 0;
1140 qsizetype len2 = 0;
1141 const char16_t *src1 = lhs.utf16();
1142 const char16_t *src2 = rhs.utf16();
1143 const char16_t *end1 = src1 + lhs.size();
1144 const char16_t *end2 = src2 + rhs.size();
1145
1146 // first, scan until we find a difference (if any)
1147 do {
1148 auto r1 = nextUtf32Character(ptr&: src1, end: end1);
1149 auto r2 = nextUtf32Character(ptr&: src2, end: end2);
1150 len1 += r1.len;
1151 len2 += r2.len;
1152 diff = int(r1.c) - int(r2.c); // no underflow due to limited range
1153 } while (src1 < end1 && src2 < end2 && diff == 0);
1154
1155 // compute the full length past this first difference
1156 len1 += stringLengthInUtf8(ptr: src1, end: end1);
1157 len2 += stringLengthInUtf8(ptr: src2, end: end2);
1158 if (len1 == len2)
1159 return diff;
1160 return len1 < len2 ? -1 : 1;
1161}
1162
1163static int compareStringsInUtf8(QUtf8StringView lhs, QStringView rhs, Comparison mode) noexcept
1164{
1165 // CBOR requires that the shortest of the two strings be sorted first, so
1166 // we have to calculate the UTF-8 length of the UTF-16 string while
1167 // comparing. Unlike the UTF-32 comparison above, we convert the UTF-16
1168 // string to UTF-8 so we only need to decode one string.
1169
1170 const qsizetype len1 = lhs.size();
1171 const auto src1 = reinterpret_cast<const uchar *>(lhs.data());
1172 const char16_t *src2 = rhs.utf16();
1173 const char16_t *const end2 = src2 + rhs.size();
1174
1175 // Compare the two strings until we find a difference.
1176 int diff = 0;
1177 qptrdiff idx1 = 0;
1178 qsizetype len2 = 0;
1179 do {
1180 uchar utf8[4]; // longest possible Unicode character in UTF-8
1181 uchar *ptr = utf8;
1182 char16_t uc = *src2++;
1183 int r = QUtf8Functions::toUtf8<QUtf8BaseTraits>(u: uc, dst&: ptr, src&: src2, end: end2);
1184 Q_UNUSED(r); // ignore failure to encode proper UTF-16 surrogates
1185
1186 qptrdiff n = ptr - utf8;
1187 len2 += n;
1188 if (len1 - idx1 < n)
1189 return -1; // lhs is definitely shorter
1190 diff = memcmp(s1: src1 + idx1, s2: utf8, n: n);
1191 idx1 += n;
1192 } while (diff == 0 && idx1 < len1 && src2 < end2);
1193
1194 if (mode == Comparison::ForEquality && diff)
1195 return diff;
1196 if ((idx1 == len1) != (src2 == end2)) {
1197 // One of the strings ended earlier than the other
1198 return idx1 == len1 ? -1 : 1;
1199 }
1200
1201 // We found a difference and neither string ended, so continue calculating
1202 // the UTF-8 length of rhs.
1203 len2 += stringLengthInUtf8(ptr: src2, end: end2);
1204
1205 if (len1 != len2)
1206 return len1 < len2 ? -1 : 1;
1207 return diff;
1208}
1209
1210static int compareStringsInUtf8(QStringView lhs, QUtf8StringView rhs, Comparison mode) noexcept
1211{
1212 return -compareStringsInUtf8(lhs: rhs, rhs: lhs, mode);
1213}
1214
1215QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
1216static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
1217 Comparison mode) noexcept;
1218static int compareElementNoData(const Element &e1, const Element &e2) noexcept
1219{
1220 Q_ASSERT(e1.type == e2.type);
1221
1222 if (e1.type == QCborValue::Integer) {
1223 // CBOR sorting order is 0, 1, 2, ..., INT64_MAX, -1, -2, -3, ... INT64_MIN
1224 // So we transform:
1225 // 0 -> 0
1226 // 1 -> 1
1227 // INT64_MAX -> INT64_MAX
1228 // -1 -> INT64_MAX + 1 = INT64_MAX - (-1)
1229 // -2 -> INT64_MAX + 2 = INT64_MAX - (-2)
1230 // INT64_MIN -> UINT64_MAX = INT64_MAX - INT64_MIN
1231 // Note how the unsigned arithmetic is well defined in C++ (it's
1232 // always performed modulo 2^64).
1233 auto makeSortable = [](qint64 v) {
1234 quint64 u = quint64(v);
1235 if (v < 0)
1236 return quint64(std::numeric_limits<qint64>::max()) + (-u);
1237 return u;
1238 };
1239 quint64 u1 = makeSortable(e1.value);
1240 quint64 u2 = makeSortable(e2.value);
1241 if (u1 < u2)
1242 return -1;
1243 if (u1 > u2)
1244 return 1;
1245 }
1246
1247 if (e1.type == QCborValue::Tag || e1.type == QCborValue::Double) {
1248 // Perform unsigned comparisons for the tag value and floating point
1249 quint64 u1 = quint64(e1.value);
1250 quint64 u2 = quint64(e2.value);
1251 if (u1 != u2)
1252 return u1 < u2 ? -1 : 1;
1253 }
1254
1255 // Any other type is equal at this point:
1256 // - simple types carry no value
1257 // - empty strings, arrays and maps
1258 return 0;
1259}
1260
1261static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1,
1262 const QCborContainerPrivate *c2, const Element &e2,
1263 Comparison mode) noexcept
1264{
1265 int cmp = typeOrder(e1: e1.type, e2: e2.type);
1266 if (cmp != 0)
1267 return cmp;
1268
1269 if ((e1.flags & Element::IsContainer) || (e2.flags & Element::IsContainer))
1270 return compareContainer(c1: e1.flags & Element::IsContainer ? e1.container : nullptr,
1271 c2: e2.flags & Element::IsContainer ? e2.container : nullptr, mode);
1272
1273 // string data?
1274 const ByteData *b1 = c1 ? c1->byteData(e: e1) : nullptr;
1275 const ByteData *b2 = c2 ? c2->byteData(e: e2) : nullptr;
1276 if (b1 || b2) {
1277 auto len1 = b1 ? b1->len : 0;
1278 auto len2 = b2 ? b2->len : 0;
1279 if (len1 == 0 || len2 == 0)
1280 return len1 < len2 ? -1 : len1 == len2 ? 0 : 1;
1281
1282 // we definitely have data from this point forward
1283 Q_ASSERT(b1);
1284 Q_ASSERT(b2);
1285
1286 // Officially with CBOR, we sort first the string with the shortest
1287 // UTF-8 length. Since US-ASCII is just a subset of UTF-8, its length
1288 // is the UTF-8 length. But the UTF-16 length may not be directly
1289 // comparable.
1290 if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16))
1291 return compareStringsInUtf8(lhs: b1->asStringView(), rhs: b2->asStringView(), mode);
1292
1293 if (!(e1.flags & Element::StringIsUtf16) && !(e2.flags & Element::StringIsUtf16)) {
1294 // Neither is UTF-16, so lengths are comparable too
1295 // (this case includes byte arrays too)
1296 if (len1 == len2) {
1297 if (mode == Comparison::ForEquality) {
1298 // GCC optimizes this to __memcmpeq(); Clang to bcmp()
1299 return memcmp(s1: b1->byte(), s2: b2->byte(), n: size_t(len1)) == 0 ? 0 : 1;
1300 }
1301 return memcmp(s1: b1->byte(), s2: b2->byte(), n: size_t(len1));
1302 }
1303 return len1 < len2 ? -1 : 1;
1304 }
1305
1306 // Only one is UTF-16
1307 if (e1.flags & Element::StringIsUtf16)
1308 return compareStringsInUtf8(lhs: b1->asStringView(), rhs: b2->asUtf8StringView(), mode);
1309 else
1310 return compareStringsInUtf8(lhs: b1->asUtf8StringView(), rhs: b2->asStringView(), mode);
1311 }
1312
1313 return compareElementNoData(e1, e2);
1314}
1315
1316static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
1317 Comparison mode) noexcept
1318{
1319 auto len1 = c1 ? c1->elements.size() : 0;
1320 auto len2 = c2 ? c2->elements.size() : 0;
1321 if (len1 != len2) {
1322 // sort the shorter container first
1323 return len1 < len2 ? -1 : 1;
1324 }
1325
1326 for (qsizetype i = 0; i < len1; ++i) {
1327 const Element &e1 = c1->elements.at(i);
1328 const Element &e2 = c2->elements.at(i);
1329 int cmp = compareElementRecursive(c1, e1, c2, e2, mode);
1330 if (cmp)
1331 return cmp;
1332 }
1333
1334 return 0;
1335}
1336
1337inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPrivate *c1, Element e1,
1338 const QCborContainerPrivate *c2, Element e2,
1339 Comparison mode) noexcept
1340{
1341 return compareElementRecursive(c1, e1, c2, e2, mode);
1342}
1343
1344/*!
1345 \fn bool QCborValue::operator==(const QCborValue &lhs, const QCborValue &rhs)
1346
1347 Compares \a lhs and \a rhs, and returns true if they hold the same
1348 contents, false otherwise. If each QCborValue contains an array or map, the
1349 comparison is recursive to elements contained in them.
1350
1351 For more information on CBOR equality in Qt, see, compare().
1352
1353 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1354 operator!=(), operator<()
1355 */
1356
1357/*!
1358 \fn bool QCborValue::operator!=(const QCborValue &lhs, const QCborValue &rhs)
1359
1360 Compares \a lhs and \a rhs, and returns true if contents differ,
1361 false otherwise. If each QCborValue contains an array or map, the comparison
1362 is recursive to elements contained in them.
1363
1364 For more information on CBOR equality in Qt, see, QCborValue::compare().
1365
1366 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1367 operator==(), operator<()
1368 */
1369bool comparesEqual(const QCborValue &lhs,
1370 const QCborValue &rhs) noexcept
1371{
1372 Element e1 = QCborContainerPrivate::elementFromValue(value: lhs);
1373 Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
1374 return compareElementRecursive(c1: lhs.container, e1, c2: rhs.container, e2,
1375 mode: Comparison::ForEquality) == 0;
1376}
1377
1378/*!
1379 \fn bool QCborValue::operator<(const QCborValue &lhs, const QCborValue &rhs)
1380
1381 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1382 sorted before \a rhs, false otherwise. If each QCborValue contains an
1383 array or map, the comparison is recursive to elements contained in them.
1384
1385 For more information on CBOR sorting order, see QCborValue::compare().
1386
1387 \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
1388 operator==(), operator!=()
1389 */
1390
1391/*!
1392 \fn bool QCborValue::operator<=(const QCborValue &lhs, const QCborValue &rhs)
1393
1394 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1395 sorted before \a rhs or is being equal to \a rhs, false otherwise.
1396 If each QCborValue contains an array or map, the comparison is recursive
1397 to elements contained in them.
1398
1399 For more information on CBOR sorting order, see QCborValue::compare().
1400
1401 \sa compare(), QCborValue::operator<(), QCborMap::operator==(),
1402 operator==(), operator!=()
1403*/
1404
1405/*!
1406 \fn bool QCborValue::operator>(const QCborValue &lhs, const QCborValue &rhs)
1407
1408 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1409 sorted after \a rhs, false otherwise. If each QCborValue contains an
1410 array or map, the comparison is recursive to elements contained in them.
1411
1412 For more information on CBOR sorting order, see QCborValue::compare().
1413
1414 \sa compare(), QCborValue::operator>=(), QCborMap::operator==(),
1415 operator==(), operator!=()
1416*/
1417
1418/*!
1419 \fn bool QCborValue::operator>=(const QCborValue &lhs, const QCborValue &rhs)
1420
1421 Compares \a lhs and \a rhs, and returns true if \a lhs should be
1422 sorted after \a rhs or is being equal to \a rhs, false otherwise.
1423 If each QCborValue contains an array or map, the comparison is recursive
1424 to elements contained in them.
1425
1426 For more information on CBOR sorting order, see QCborValue::compare().
1427
1428 \sa compare(), QCborValue::operator>(), QCborMap::operator==(),
1429 operator==(), operator!=()
1430*/
1431
1432/*!
1433 Compares this value and \a other, and returns an integer that indicates
1434 whether this value should be sorted prior to (if the result is negative) or
1435 after \a other (if the result is positive). If this function returns 0, the
1436 two values are equal and hold the same contents.
1437
1438 If each QCborValue contains an array or map, the comparison is recursive to
1439 elements contained in them.
1440
1441 \section3 Extended types
1442
1443 QCborValue compares equal a QCborValue containing an extended type, like
1444 \l{Type}{Url} and \l{Type}{Url} and its equivalent tagged representation.
1445 So, for example, the following expression is true:
1446
1447 \snippet code/src_corelib_serialization_qcborvalue.cpp 3
1448
1449 Do note that Qt types like \l QUrl and \l QDateTime will normalize and
1450 otherwise modify their arguments. The expression above is true only because
1451 the string on the right side is the normalized value that the QCborValue on
1452 the left would take. If, for example, the "https" part were uppercase in
1453 both sides, the comparison would fail. For information on normalizations
1454 performed by QCborValue, please consult the documentation of the
1455 constructor taking the Qt type in question.
1456
1457 \section3 Sorting order
1458
1459 Sorting order in CBOR is defined in
1460 \l{RFC 7049, section 3.9}, which
1461 discusses the sorting of keys in a map when following the Canonical
1462 encoding. According to the specification, "sorting is performed on the
1463 bytes of the representation of the key data items" and lists as
1464 consequences that:
1465
1466 \list
1467 \li "If two keys have different lengths, the shorter one sorts earlier;"
1468 \li "If two keys have the same length, the one with the lower value in
1469 (byte-wise) lexical order sorts earlier."
1470 \endlist
1471
1472 This results in surprising sorting of QCborValues, where the result of this
1473 function is different from that which would later be retrieved by comparing the
1474 contained elements. For example, the QCborValue containing string "zzz"
1475 sorts before the QCborValue with string "foobar", even though when
1476 comparing as \l{QString::compare()}{QStrings} or
1477 \l{QByteArray}{QByteArrays} the "zzz" sorts after "foobar"
1478 (dictionary order).
1479
1480 The specification does not clearly indicate what sorting order should be
1481 done for values of different types (it says sorting should not pay
1482 "attention to the 3/5 bit splitting for major types"). QCborValue makes the
1483 assumption that types should be sorted too. The numeric values of the
1484 QCborValue::Type enumeration are in that order, with the exception of the
1485 extended types, which compare as their tagged equivalents.
1486
1487 \note Sorting order is preliminary and is subject to change. Applications
1488 should not depend on the order returned by this function for the time
1489 being.
1490
1491 \sa QCborArray::compare(), QCborMap::compare(), operator==()
1492 */
1493int QCborValue::compare(const QCborValue &other) const
1494{
1495 Element e1 = QCborContainerPrivate::elementFromValue(value: *this);
1496 Element e2 = QCborContainerPrivate::elementFromValue(value: other);
1497 return compareElementRecursive(c1: container, e1, c2: other.container, e2, mode: Comparison::ForOrdering);
1498}
1499
1500bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
1501{
1502 return compareContainer(c1: lhs.d.constData(), c2: rhs.d.constData(), mode: Comparison::ForEquality) == 0;
1503}
1504
1505int QCborArray::compare(const QCborArray &other) const noexcept
1506{
1507 return compareContainer(c1: d.data(), c2: other.d.data(), mode: Comparison::ForOrdering);
1508}
1509
1510bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1511{
1512 if (typeOrder(e1: QCborValue::Array, e2: rhs.type()))
1513 return false;
1514 return compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForEquality) == 0;
1515}
1516
1517Qt::strong_ordering
1518QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1519{
1520 int c = typeOrder(e1: QCborValue::Array, e2: rhs.type());
1521 if (c == 0)
1522 c = compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForOrdering);
1523 return Qt::compareThreeWay(lhs: c, rhs: 0);
1524}
1525
1526bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
1527{
1528 return compareContainer(c1: lhs.d.constData(), c2: rhs.d.constData(), mode: Comparison::ForEquality) == 0;
1529}
1530
1531int QCborMap::compare(const QCborMap &other) const noexcept
1532{
1533 return compareContainer(c1: d.data(), c2: other.d.data(), mode: Comparison::ForOrdering);
1534}
1535
1536bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1537{
1538 if (typeOrder(e1: QCborValue::Map, e2: rhs.type()))
1539 return false;
1540 return compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForEquality) == 0;
1541}
1542
1543Qt::strong_ordering
1544QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1545{
1546 int c = typeOrder(e1: QCborValue::Map, e2: rhs.type());
1547 if (c == 0)
1548 c = compareContainer(c1: lhs.d.constData(), c2: rhs.container, mode: Comparison::ForOrdering);
1549 return Qt::compareThreeWay(lhs: c, rhs: 0);
1550}
1551
1552#if QT_CONFIG(cborstreamwriter) && !defined(QT_BOOTSTRAPPED)
1553static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate *d, qsizetype idx,
1554 QCborValue::EncodingOptions opt)
1555{
1556 if (idx == -QCborValue::Array || idx == -QCborValue::Map) {
1557 bool isArray = (idx == -QCborValue::Array);
1558 qsizetype len = d ? d->elements.size() : 0;
1559 if (isArray)
1560 writer.startArray(count: quint64(len));
1561 else
1562 writer.startMap(count: quint64(len) / 2);
1563
1564 for (idx = 0; idx < len; ++idx)
1565 encodeToCbor(writer, d, idx, opt);
1566
1567 if (isArray)
1568 writer.endArray();
1569 else
1570 writer.endMap();
1571 } else if (idx < 0) {
1572 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1573 if (d->elements.size() != 2) {
1574 // invalid state!
1575 qWarning(msg: "QCborValue: invalid tag state; are you encoding something that was improperly decoded?");
1576 return;
1577 }
1578
1579 // write the tag and the tagged element
1580 writer.append(tag: QCborTag(d->elements.at(i: 0).value));
1581 encodeToCbor(writer, d, idx: 1, opt);
1582 } else {
1583 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1584 // just one element
1585 auto e = d->elements.at(i: idx);
1586 const ByteData *b = d->byteData(idx);
1587 switch (e.type) {
1588 case QCborValue::Integer:
1589 return writer.append(i: qint64(e.value));
1590
1591 case QCborValue::ByteArray:
1592 if (b)
1593 return writer.appendByteString(data: b->byte(), len: b->len);
1594 return writer.appendByteString(data: "", len: 0);
1595
1596 case QCborValue::String:
1597 if (b) {
1598 if (e.flags & Element::StringIsUtf16)
1599 return writer.append(str: b->asStringView());
1600 return writer.appendTextString(utf8: b->byte(), len: b->len);
1601 }
1602 return writer.append(str: QLatin1StringView());
1603
1604 case QCborValue::Array:
1605 case QCborValue::Map:
1606 case QCborValue::Tag:
1607 // recurse
1608 return encodeToCbor(writer,
1609 d: e.flags & Element::IsContainer ? e.container : nullptr,
1610 idx: -qsizetype(e.type), opt);
1611
1612 case QCborValue::SimpleType:
1613 case QCborValue::False:
1614 case QCborValue::True:
1615 case QCborValue::Null:
1616 case QCborValue::Undefined:
1617 break;
1618
1619 case QCborValue::Double:
1620 return writeDoubleToCbor(writer, d: e.fpvalue(), opt);
1621
1622 case QCborValue::Invalid:
1623 return;
1624
1625 case QCborValue::DateTime:
1626 case QCborValue::Url:
1627 case QCborValue::RegularExpression:
1628 case QCborValue::Uuid:
1629 // recurse as tag
1630 return encodeToCbor(writer, d: e.container, idx: -QCborValue::Tag, opt);
1631 }
1632
1633 // maybe it's a simple type
1634 int simpleType = e.type - QCborValue::SimpleType;
1635 if (unsigned(simpleType) < 0x100)
1636 return writer.append(st: QCborSimpleType(simpleType));
1637
1638 // if we got here, we've got an unknown type
1639 qWarning(msg: "QCborValue: found unknown type 0x%x", e.type);
1640 }
1641}
1642#endif // QT_CONFIG(cborstreamwriter) && !QT_BOOTSTRAPPED
1643
1644#if QT_CONFIG(cborstreamreader)
1645// confirm that our basic Types match QCborStreamReader::Types
1646static_assert(int(QCborValue::Integer) == int(QCborStreamReader::UnsignedInteger));
1647static_assert(int(QCborValue::ByteArray) == int(QCborStreamReader::ByteArray));
1648static_assert(int(QCborValue::String) == int(QCborStreamReader::String));
1649static_assert(int(QCborValue::Array) == int(QCborStreamReader::Array));
1650static_assert(int(QCborValue::Map) == int(QCborStreamReader::Map));
1651static_assert(int(QCborValue::Tag) == int(QCborStreamReader::Tag));
1652
1653static inline double integerOutOfRange(const QCborStreamReader &reader)
1654{
1655 Q_ASSERT(reader.isInteger());
1656 if (reader.isUnsignedInteger()) {
1657 quint64 v = reader.toUnsignedInteger();
1658 if (qint64(v) < 0)
1659 return double(v);
1660 } else {
1661 quint64 v = quint64(reader.toNegativeInteger());
1662 if (qint64(v - 1) < 0)
1663 return -double(v);
1664 }
1665
1666 // result is in range
1667 return 0;
1668}
1669
1670static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
1671{
1672 Element e = {};
1673
1674 switch (reader.type()) {
1675 case QCborStreamReader::UnsignedInteger:
1676 case QCborStreamReader::NegativeInteger:
1677 if (double d = integerOutOfRange(reader)) {
1678 e.type = QCborValue::Double;
1679 qToUnaligned(src: d, dest: &e.value);
1680 } else {
1681 e.type = QCborValue::Integer;
1682 e.value = reader.toInteger();
1683 }
1684 break;
1685 case QCborStreamReader::SimpleType:
1686 e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
1687 break;
1688 case QCborStreamReader::Float16:
1689 e.type = QCborValue::Double;
1690 qToUnaligned(src: double(reader.toFloat16()), dest: &e.value);
1691 break;
1692 case QCborStreamReader::Float:
1693 e.type = QCborValue::Double;
1694 qToUnaligned(src: double(reader.toFloat()), dest: &e.value);
1695 break;
1696 case QCborStreamReader::Double:
1697 e.type = QCborValue::Double;
1698 qToUnaligned(src: reader.toDouble(), dest: &e.value);
1699 break;
1700
1701 default:
1702 Q_UNREACHABLE();
1703 }
1704
1705 reader.next();
1706 return e;
1707}
1708
1709// Clamp allocation to avoid crashing due to corrupt stream. This also
1710// ensures we never overflow qsizetype. The returned length is doubled for Map
1711// entries to account for key-value pairs.
1712static qsizetype clampedContainerLength(const QCborStreamReader &reader)
1713{
1714 if (!reader.isLengthKnown())
1715 return 0;
1716 int mapShift = reader.isMap() ? 1 : 0;
1717 quint64 shiftedMaxElements = MaximumPreallocatedElementCount >> mapShift;
1718 qsizetype len = qsizetype(qMin(a: reader.length(), b: shiftedMaxElements));
1719 return len << mapShift;
1720}
1721
1722static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1723{
1724 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1725 QCborContainerPrivate::setErrorInReader(reader, error: { .c: QCborError::NestingTooDeep });
1726 return nullptr;
1727 }
1728
1729 QCborContainerPrivate *d = nullptr;
1730 {
1731 // in case QList::reserve throws
1732 QExplicitlySharedDataPointer u(new QCborContainerPrivate);
1733 if (qsizetype len = clampedContainerLength(reader))
1734 u->elements.reserve(asize: len);
1735 d = u.take();
1736 }
1737
1738 reader.enterContainer();
1739 if (reader.lastError() != QCborError::NoError) {
1740 d->elements.clear();
1741 return d;
1742 }
1743
1744 while (reader.hasNext() && reader.lastError() == QCborError::NoError)
1745 d->decodeValueFromCbor(reader, remainingStackDepth: remainingRecursionDepth - 1);
1746
1747 if (reader.lastError() == QCborError::NoError)
1748 reader.leaveContainer();
1749 else
1750 d->elements.squeeze();
1751
1752 return d;
1753}
1754
1755static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1756{
1757 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1758 QCborContainerPrivate::setErrorInReader(reader, error: { .c: QCborError::NestingTooDeep });
1759 return QCborValue::Invalid;
1760 }
1761
1762 auto d = new QCborContainerPrivate;
1763 d->append(tag: reader.toTag());
1764 reader.next();
1765
1766 if (reader.lastError() == QCborError::NoError) {
1767 // decode tagged value
1768 d->decodeValueFromCbor(reader, remainingStackDepth: remainingRecursionDepth - 1);
1769 }
1770
1771 QCborValue::Type type;
1772 if (reader.lastError() == QCborError::NoError) {
1773 // post-process to create our extended types
1774 type = convertToExtendedType(d);
1775 } else {
1776 // decoding error
1777 type = QCborValue::Invalid;
1778 }
1779
1780 // note: may return invalid state!
1781 return QCborContainerPrivate::makeValue(type, n: -1, d);
1782}
1783
1784// in qcborstream.cpp
1785extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
1786inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
1787{
1788 qt_cbor_stream_set_error(d: reader.d.get(), error);
1789}
1790
1791extern QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data);
1792
1793void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
1794{
1795 if (reader.lastError() != QCborError::NoError)
1796 return;
1797
1798 qsizetype rawlen = reader.currentStringChunkSize();
1799 QByteArray::size_type len = rawlen;
1800 if (rawlen < 0)
1801 return; // error
1802 if (len != rawlen) {
1803 // truncation
1804 setErrorInReader(reader, error: { .c: QCborError::DataTooLarge });
1805 return;
1806 }
1807
1808 auto resetSize = qScopeGuard(f: [this, oldSize = data.size()] {
1809 data.resize(size: oldSize);
1810 if (oldSize < data.capacity() / 2)
1811 data.squeeze();
1812 });
1813
1814 Element e = {};
1815 e.type = QCborValue::Type(reader.type());
1816 if (len || !reader.isLengthKnown()) {
1817 // The use of size_t means none of the operations here can overflow because
1818 // all inputs are less than half SIZE_MAX.
1819 constexpr size_t EstimatedOverhead = 16;
1820 constexpr size_t MaxMemoryIncrement = 16384;
1821 size_t offset = data.size();
1822
1823 // add space for aligned ByteData (this can't overflow)
1824 offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
1825 offset &= ~(alignof(QtCbor::ByteData) - 1);
1826 if (offset > size_t(QByteArray::maxSize())) {
1827 // overflow
1828 setErrorInReader(reader, error: { .c: QCborError::DataTooLarge });
1829 return;
1830 }
1831
1832 // and calculate the size we want to have
1833 size_t newCapacity = offset + len; // can't overflow
1834 if (size_t(len) > MaxMemoryIncrement - EstimatedOverhead) {
1835 // there's a non-zero chance that we won't need this memory at all,
1836 // so capa how much we allocate
1837 newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
1838 }
1839 if (newCapacity > size_t(QByteArray::maxSize())) {
1840 // this may cause an allocation failure
1841 newCapacity = QByteArray::maxSize();
1842 }
1843 if (newCapacity > size_t(data.capacity()))
1844 data.reserve(asize: newCapacity);
1845 data.resize(size: offset + sizeof(QtCbor::ByteData));
1846 e.value = offset;
1847 e.flags = Element::HasByteData;
1848 }
1849
1850 // read chunks
1851 bool isAscii = (e.type == QCborValue::String);
1852 QCborStreamReader::StringResultCode status = qt_cbor_append_string_chunk(reader, data: &data);
1853 while (status == QCborStreamReader::Ok) {
1854 if (e.type == QCborValue::String && len) {
1855 // verify UTF-8 string validity
1856 auto utf8result = QUtf8::isValidUtf8(in: QByteArrayView(data).last(n: len));
1857 if (!utf8result.isValidUtf8) {
1858 setErrorInReader(reader, error: { .c: QCborError::InvalidUtf8String });
1859 return;
1860 }
1861 isAscii = isAscii && utf8result.isValidAscii;
1862 }
1863
1864 rawlen = reader.currentStringChunkSize();
1865 len = rawlen;
1866 if (len == rawlen) {
1867 status = qt_cbor_append_string_chunk(reader, data: &data);
1868 } else {
1869 // error
1870 setErrorInReader(reader, error: { .c: QCborError::DataTooLarge });
1871 return;
1872 }
1873 }
1874
1875 // update size
1876 if (status == QCborStreamReader::EndOfString && e.flags & Element::HasByteData) {
1877 Q_ASSERT(data.isDetached());
1878 const char *ptr = data.constData() + e.value;
1879 auto b = new (const_cast<char *>(ptr)) ByteData;
1880 b->len = data.size() - e.value - int(sizeof(*b));
1881 usedData += b->len;
1882
1883 if (isAscii) {
1884 // set the flag if it is US-ASCII only (as it often is)
1885 Q_ASSERT(e.type == QCborValue::String);
1886 e.flags |= Element::StringIsAscii;
1887 }
1888
1889 // check that this UTF-8 text string can be loaded onto a QString
1890 if (e.type == QCborValue::String) {
1891 if (Q_UNLIKELY(b->len > QString::maxSize())) {
1892 setErrorInReader(reader, error: { .c: QCborError::DataTooLarge });
1893 return;
1894 }
1895 }
1896 }
1897
1898 if (status == QCborStreamReader::EndOfString) {
1899 elements.append(t: e);
1900 resetSize.dismiss();
1901 }
1902}
1903
1904void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1905{
1906 QCborStreamReader::Type t = reader.type();
1907 switch (t) {
1908 case QCborStreamReader::UnsignedInteger:
1909 case QCborStreamReader::NegativeInteger:
1910 case QCborStreamReader::SimpleType:
1911 case QCborStreamReader::Float16:
1912 case QCborStreamReader::Float:
1913 case QCborStreamReader::Double:
1914 elements.append(t: decodeBasicValueFromCbor(reader));
1915 break;
1916
1917 case QCborStreamReader::ByteArray:
1918 case QCborStreamReader::String:
1919 decodeStringFromCbor(reader);
1920 break;
1921
1922 case QCborStreamReader::Array:
1923 case QCborStreamReader::Map:
1924 return append(v: makeValue(type: t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, n: -1,
1925 d: createContainerFromCbor(reader, remainingRecursionDepth),
1926 disp: MoveContainer));
1927
1928 case QCborStreamReader::Tag:
1929 return append(v: taggedValueFromCbor(reader, remainingRecursionDepth));
1930
1931 case QCborStreamReader::Invalid:
1932 return; // probably a decode error
1933 }
1934}
1935#endif // QT_CONFIG(cborstreamreader)
1936
1937/*!
1938 Creates a QCborValue with byte array value \a ba. The value can later be
1939 retrieved using toByteArray().
1940
1941 \sa toByteArray(), isByteArray(), isString()
1942 */
1943QCborValue::QCborValue(const QByteArray &ba)
1944 : n(0), container(new QCborContainerPrivate), t(ByteArray)
1945{
1946 container->appendByteData(data: ba.constData(), len: ba.size(), type: t);
1947 container->ref.storeRelaxed(newValue: 1);
1948}
1949
1950/*!
1951 Creates a QCborValue with string value \a s. The value can later be
1952 retrieved using toString().
1953
1954 \sa toString(), isString(), isByteArray()
1955 */
1956QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {}
1957
1958/*!
1959 Creates a QCborValue with string value \a s. The value can later be
1960 retrieved using toString().
1961
1962 \sa toString(), isString(), isByteArray()
1963*/
1964QCborValue::QCborValue(QStringView s)
1965 : n(0), container(new QCborContainerPrivate), t(String)
1966{
1967 container->append(s);
1968 container->ref.storeRelaxed(newValue: 1);
1969}
1970
1971/*!
1972 \overload
1973
1974 Creates a QCborValue with the Latin-1 string viewed by \a s.
1975 The value can later be retrieved using toString().
1976
1977 \sa toString(), isString(), isByteArray()
1978 */
1979QCborValue::QCborValue(QLatin1StringView s)
1980 : n(0), container(new QCborContainerPrivate), t(String)
1981{
1982 container->append(s);
1983 container->ref.storeRelaxed(newValue: 1);
1984}
1985
1986/*!
1987 \fn QCborValue::QCborValue(const QCborArray &a)
1988 \fn QCborValue::QCborValue(QCborArray &&a)
1989
1990 Creates a QCborValue with the array \a a. The array can later be retrieved
1991 using toArray().
1992
1993 \sa toArray(), isArray(), isMap()
1994 */
1995QCborValue::QCborValue(const QCborArray &a)
1996 : n(-1), container(a.d.data()), t(Array)
1997{
1998 if (container)
1999 container->ref.ref();
2000}
2001
2002/*!
2003 \fn QCborValue::QCborValue(const QCborMap &m)
2004 \fn QCborValue::QCborValue(QCborMap &&m)
2005
2006 Creates a QCborValue with the map \a m. The map can later be retrieved
2007 using toMap().
2008
2009 \sa toMap(), isMap(), isArray()
2010 */
2011QCborValue::QCborValue(const QCborMap &m)
2012 : n(-1), container(m.d.data()), t(Map)
2013{
2014 if (container)
2015 container->ref.ref();
2016}
2017
2018/*!
2019 \fn QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2020 \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &tv)
2021
2022 Creates a QCborValue for the extended type represented by the tag value \a
2023 tag, tagging value \a tv. The tag can later be retrieved using tag() and
2024 the tagged value using taggedValue().
2025
2026 \sa isTag(), tag(), taggedValue(), QCborKnownTags
2027 */
2028QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2029 : n(-1), container(new QCborContainerPrivate), t(Tag)
2030{
2031 container->ref.storeRelaxed(newValue: 1);
2032 container->append(tag);
2033 container->append(v: tv);
2034 t = convertToExtendedType(d: container);
2035}
2036
2037/*!
2038 Copies the contents of \a other into this object.
2039 */
2040QCborValue::QCborValue(const QCborValue &other) noexcept
2041 : n(other.n), container(other.container), t(other.t)
2042{
2043 if (container)
2044 container->ref.ref();
2045}
2046
2047#if QT_CONFIG(datestring)
2048/*!
2049 Creates a QCborValue object of the date/time extended type and containing
2050 the value represented by \a dt. The value can later be retrieved using
2051 toDateTime().
2052
2053 The CBOR date/time types are extension types using tags: either a string
2054 (in ISO date format) tagged as a \l{QCborKnownTags}{DateTime} or a number
2055 (of seconds since the start of 1970, UTC) tagged as a
2056 \l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will
2057 convert \l{QCborKnownTags}{UnixTime_t} to the string-based type.
2058
2059 \sa toDateTime(), isDateTime(), taggedValue()
2060 */
2061QCborValue::QCborValue(const QDateTime &dt)
2062 : QCborValue(QCborKnownTags::DateTimeString, dt.toString(format: Qt::ISODateWithMs).toLatin1())
2063{
2064 // change types
2065 t = DateTime;
2066 container->elements[1].type = String;
2067}
2068#endif
2069
2070#ifndef QT_BOOTSTRAPPED
2071/*!
2072 Creates a QCborValue object of the URL extended type and containing the
2073 value represented by \a url. The value can later be retrieved using toUrl().
2074
2075 The CBOR URL type is an extended type represented by a string tagged as an
2076 \l{QCborKnownTags}{Url}.
2077
2078 \sa toUrl(), isUrl(), taggedValue()
2079 */
2080QCborValue::QCborValue(const QUrl &url)
2081 : QCborValue(QCborKnownTags::Url, url.toString(options: QUrl::DecodeReserved).toUtf8())
2082{
2083 // change types
2084 t = Url;
2085 container->elements[1].type = String;
2086}
2087
2088#if QT_CONFIG(regularexpression)
2089/*!
2090 Creates a QCborValue object of the regular expression pattern extended type
2091 and containing the value represented by \a rx. The value can later be retrieved
2092 using toRegularExpression().
2093
2094 The CBOR regular expression type is an extended type represented by a
2095 string tagged as an \l{QCborKnownTags}{RegularExpression}. Note that CBOR
2096 regular expressions only store the patterns, so any flags that the
2097 QRegularExpression object may carry will be lost.
2098
2099 \sa toRegularExpression(), isRegularExpression(), taggedValue()
2100 */
2101QCborValue::QCborValue(const QRegularExpression &rx)
2102 : QCborValue(QCborKnownTags::RegularExpression, rx.pattern())
2103{
2104 // change type
2105 t = RegularExpression;
2106}
2107#endif // QT_CONFIG(regularexpression)
2108
2109/*!
2110 Creates a QCborValue object of the UUID extended type and containing the
2111 value represented by \a uuid. The value can later be retrieved using
2112 toUuid().
2113
2114 The CBOR UUID type is an extended type represented by a byte array tagged
2115 as an \l{QCborKnownTags}{Uuid}.
2116
2117 \sa toUuid(), isUuid(), taggedValue()
2118 */
2119QCborValue::QCborValue(const QUuid &uuid)
2120 : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
2121{
2122 // change our type
2123 t = Uuid;
2124}
2125#endif
2126
2127// destructor
2128void QCborValue::dispose()
2129{
2130 container->deref();
2131}
2132
2133/*!
2134 Replaces the contents of this QCborObject with a copy of \a other.
2135 */
2136QCborValue &QCborValue::operator=(const QCborValue &other) noexcept
2137{
2138 n = other.n;
2139 assignContainer(d&: container, x: other.container);
2140 t = other.t;
2141 return *this;
2142}
2143
2144/*!
2145 Returns the tag of this extended QCborValue object, if it is of the tag
2146 type, \a defaultValue otherwise.
2147
2148 CBOR represents extended types by associating a number (the tag) with a
2149 stored representation. This function returns that number. To retrieve the
2150 representation, use taggedValue().
2151
2152 \sa isTag(), taggedValue(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2153 */
2154QCborTag QCborValue::tag(QCborTag defaultValue) const
2155{
2156 return isTag() && container && container->elements.size() == 2 ?
2157 QCborTag(container->elements.at(i: 0).value) : defaultValue;
2158}
2159
2160/*!
2161 Returns the tagged value of this extended QCborValue object, if it is of
2162 the tag type, \a defaultValue otherwise.
2163
2164 CBOR represents extended types by associating a number (the tag) with a
2165 stored representation. This function returns that representation. To
2166 retrieve the tag, use tag().
2167
2168 \sa isTag(), tag(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2169 */
2170QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
2171{
2172 return isTag() && container && container->elements.size() == 2 ?
2173 container->valueAt(idx: 1) : defaultValue;
2174}
2175
2176/*!
2177 Returns the byte array value stored in this QCborValue, if it is of the byte
2178 array type. Otherwise, it returns \a defaultValue.
2179
2180 Note that this function performs no conversion from other types to
2181 QByteArray.
2182
2183 \sa isByteArray(), isString(), toString()
2184 */
2185QByteArray QCborValue::toByteArray(const QByteArray &defaultValue) const
2186{
2187 if (!container || !isByteArray())
2188 return defaultValue;
2189
2190 Q_ASSERT(n >= 0);
2191 return container->byteArrayAt(idx: n);
2192}
2193
2194/*!
2195 Returns the string value stored in this QCborValue, if it is of the string
2196 type. Otherwise, it returns \a defaultValue.
2197
2198 Note that this function performs no conversion from other types to
2199 QString.
2200
2201 \sa toStringView(), isString(), isByteArray(), toByteArray()
2202 */
2203QString QCborValue::toString(const QString &defaultValue) const
2204{
2205 if (!container || !isString())
2206 return defaultValue;
2207
2208 Q_ASSERT(n >= 0);
2209 return container->stringAt(idx: n);
2210}
2211
2212/*!
2213 \since 6.10
2214
2215 Returns the string value stored in this QCborValue, if it is of the string
2216 type. Otherwise, it returns \a defaultValue. Since QCborValue stores
2217 strings in either US-ASCII, UTF-8 or UTF-16, the returned QAnyStringView
2218 may be in any of these encodings.
2219
2220 This function does not allocate memory. The return value is valid until the
2221 next call to a non-const member function on this object. If this object goes
2222 out of scope, the return value is valid until the next call to a non-const
2223 member function on the parent CBOR object (map or array).
2224
2225 Note that this function performs no conversion from other types to
2226 QString.
2227
2228 \sa toString(), isString(), isByteArray(), toByteArray()
2229*/
2230QAnyStringView QCborValue::toStringView(QAnyStringView defaultValue) const
2231{
2232 if (!container || !isString())
2233 return defaultValue;
2234
2235 Q_ASSERT(n >= 0);
2236 return container->anyStringViewAt(idx: n);
2237}
2238
2239#if QT_CONFIG(datestring)
2240/*!
2241 Returns the date/time value stored in this QCborValue, if it is of the
2242 date/time extended type. Otherwise, it returns \a defaultValue.
2243
2244 Note that this function performs no conversion from other types to
2245 QDateTime.
2246
2247 \sa isDateTime(), isTag(), taggedValue()
2248 */
2249QDateTime QCborValue::toDateTime(const QDateTime &defaultValue) const
2250{
2251 if (!container || !isDateTime() || container->elements.size() != 2)
2252 return defaultValue;
2253
2254 Q_ASSERT(n == -1);
2255 const ByteData *byteData = container->byteData(idx: 1);
2256 if (!byteData)
2257 return defaultValue; // date/times are never empty, so this must be invalid
2258
2259 // Our data must be US-ASCII.
2260 Q_ASSERT((container->elements.at(1).flags & Element::StringIsUtf16) == 0);
2261 return QDateTime::fromString(string: byteData->asLatin1(), format: Qt::ISODateWithMs);
2262}
2263#endif
2264
2265#ifndef QT_BOOTSTRAPPED
2266/*!
2267 Returns the URL value stored in this QCborValue, if it is of the URL
2268 extended type. Otherwise, it returns \a defaultValue.
2269
2270 Note that this function performs no conversion from other types to QUrl.
2271
2272 \sa isUrl(), isTag(), taggedValue()
2273 */
2274QUrl QCborValue::toUrl(const QUrl &defaultValue) const
2275{
2276 if (!container || !isUrl() || container->elements.size() != 2)
2277 return defaultValue;
2278
2279 Q_ASSERT(n == -1);
2280 const ByteData *byteData = container->byteData(idx: 1);
2281 if (!byteData)
2282 return QUrl(); // valid, empty URL
2283
2284 return QUrl::fromEncoded(input: byteData->asByteArrayView());
2285}
2286
2287#if QT_CONFIG(regularexpression)
2288/*!
2289 Returns the regular expression value stored in this QCborValue, if it is of
2290 the regular expression pattern extended type. Otherwise, it returns \a
2291 defaultValue.
2292
2293 Note that this function performs no conversion from other types to
2294 QRegularExpression.
2295
2296 \sa isRegularExpression(), isTag(), taggedValue()
2297 */
2298QRegularExpression QCborValue::toRegularExpression(const QRegularExpression &defaultValue) const
2299{
2300 if (!container || !isRegularExpression() || container->elements.size() != 2)
2301 return defaultValue;
2302
2303 Q_ASSERT(n == -1);
2304 return QRegularExpression(container->stringAt(idx: 1));
2305}
2306#endif // QT_CONFIG(regularexpression)
2307
2308/*!
2309 Returns the UUID value stored in this QCborValue, if it is of the UUID
2310 extended type. Otherwise, it returns \a defaultValue.
2311
2312 Note that this function performs no conversion from other types to QUuid.
2313
2314 \sa isUuid(), isTag(), taggedValue()
2315 */
2316QUuid QCborValue::toUuid(const QUuid &defaultValue) const
2317{
2318 if (!container || !isUuid() || container->elements.size() != 2)
2319 return defaultValue;
2320
2321 Q_ASSERT(n == -1);
2322 const ByteData *byteData = container->byteData(idx: 1);
2323 if (!byteData)
2324 return defaultValue; // UUIDs must always be 16 bytes, so this must be invalid
2325
2326 return QUuid::fromRfc4122(byteData->asByteArrayView());
2327}
2328#endif
2329
2330/*!
2331 \fn QCborArray QCborValue::toArray() const
2332 \fn QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
2333
2334 Returns the array value stored in this QCborValue, if it is of the array
2335 type. Otherwise, it returns \a defaultValue.
2336
2337 Note that this function performs no conversion from other types to
2338 QCborArray.
2339
2340 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2341 */
2342
2343/*!
2344 \fn QCborArray QCborValueRef::toArray() const
2345 \fn QCborArray QCborValueRef::toArray(const QCborArray &defaultValue) const
2346 \internal
2347
2348 Returns the array value stored in this QCborValue, if it is of the array
2349 type. Otherwise, it returns \a defaultValue.
2350
2351 Note that this function performs no conversion from other types to
2352 QCborArray.
2353
2354 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2355 */
2356QCborArray QCborValue::toArray() const
2357{
2358 return toArray(defaultValue: QCborArray());
2359}
2360
2361QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
2362{
2363 if (!isArray())
2364 return defaultValue;
2365 QCborContainerPrivate *dd = nullptr;
2366 Q_ASSERT(n == -1 || container == nullptr);
2367 if (n < 0)
2368 dd = container;
2369 // return QCborArray(*dd); but that's UB if dd is nullptr
2370 return dd ? QCborArray(*dd) : QCborArray();
2371}
2372
2373/*!
2374 \fn QCborMap QCborValue::toMap() const
2375 \fn QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2376
2377 Returns the map value stored in this QCborValue, if it is of the map type.
2378 Otherwise, it returns \a defaultValue.
2379
2380 Note that this function performs no conversion from other types to
2381 QCborMap.
2382
2383 \sa isMap(), isArray(), isContainer(), toArray()
2384 */
2385
2386/*!
2387 \fn QCborMap QCborValueRef::toMap() const
2388 \fn QCborMap QCborValueRef::toMap(const QCborMap &defaultValue) const
2389 \internal
2390
2391 Returns the map value stored in this QCborValue, if it is of the map type.
2392 Otherwise, it returns \a defaultValue.
2393
2394 Note that this function performs no conversion from other types to
2395 QCborMap.
2396
2397 \sa isMap(), isArray(), isContainer(), toArray()
2398 */
2399QCborMap QCborValue::toMap() const
2400{
2401 return toMap(defaultValue: QCborMap());
2402}
2403
2404QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2405{
2406 if (!isMap())
2407 return defaultValue;
2408 QCborContainerPrivate *dd = nullptr;
2409 Q_ASSERT(n == -1 || container == nullptr);
2410 if (n < 0)
2411 dd = container;
2412 // return QCborMap(*dd); but that's UB if dd is nullptr
2413 return dd ? QCborMap(*dd) : QCborMap();
2414}
2415
2416/*!
2417 If this QCborValue is a QCborMap, searches elements for the value whose key
2418 matches \a key. If there's no key matching \a key in the map or if this
2419 QCborValue object is not a map, returns the undefined value.
2420
2421 This function is equivalent to:
2422
2423 \snippet code/src_corelib_serialization_qcborvalue.cpp 4
2424
2425 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2426 QCborMap::find()
2427 */
2428const QCborValue QCborValue::operator[](const QString &key) const
2429{
2430 return QCborContainerPrivate::findCborMapKey(self: *this, key: qToStringViewIgnoringNull(s: key));
2431}
2432
2433/*!
2434 \overload
2435
2436 If this QCborValue is a QCborMap, searches elements for the value whose key
2437 matches \a key. If there's no key matching \a key in the map or if this
2438 QCborValue object is not a map, returns the undefined value.
2439
2440 This function is equivalent to:
2441
2442 \snippet code/src_corelib_serialization_qcborvalue.cpp 5
2443
2444 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2445 QCborMap::find()
2446 */
2447const QCborValue QCborValue::operator[](QLatin1StringView key) const
2448{
2449 return QCborContainerPrivate::findCborMapKey(self: *this, key);
2450}
2451
2452/*!
2453 \overload
2454
2455 If this QCborValue is a QCborMap, searches elements for the value whose key
2456 matches \a key. If this is a QCborArray, returns the element whose index is
2457 \a key. If there's no matching value in the array or map, or if this
2458 QCborValue object is not an array or map, returns the undefined value.
2459
2460 \sa operator[], QCborMap::operator[], QCborMap::value(),
2461 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2462 */
2463const QCborValue QCborValue::operator[](qint64 key) const
2464{
2465 if (isArray() && container && quint64(key) < quint64(container->elements.size()))
2466 return container->valueAt(idx: key);
2467 return QCborContainerPrivate::findCborMapKey(self: *this, key);
2468}
2469
2470static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
2471{
2472 constexpr qint64 LargeKey = 0x10000;
2473 if (t != QCborValue::Array)
2474 return false;
2475 if (key < 0)
2476 return false; // negative keys can't be an array index
2477 if (key < LargeKey)
2478 return true;
2479
2480 // Only convert to map if key is greater than array size + 1
2481 qsizetype currentSize = container ? container->elements.size() : 0;
2482 return key <= currentSize;
2483}
2484
2485/*!
2486 \internal
2487 */
2488static void convertArrayToMap(QCborContainerPrivate *&array)
2489{
2490 if (Q_LIKELY(!array || array->elements.isEmpty()))
2491 return;
2492
2493 // The Q_LIKELY and the qWarning mark the rest of this function as unlikely
2494 qWarning(msg: "Using CBOR array as map forced conversion");
2495
2496 qsizetype size = array->elements.size();
2497 QCborContainerPrivate *map = QCborContainerPrivate::detach(d: array, reserved: size * 2);
2498 map->elements.resize(size: size * 2);
2499
2500 // this may be an in-place copy, so we have to do it from the end
2501 auto dst = map->elements.begin();
2502 auto src = array->elements.constBegin();
2503 for (qsizetype i = size - 1; i >= 0; --i) {
2504 Q_ASSERT(src->type != QCborValue::Invalid);
2505 dst[i * 2 + 1] = src[i];
2506 }
2507 for (qsizetype i = 0; i < size; ++i)
2508 dst[i * 2] = { i, QCborValue::Integer };
2509
2510 // update reference counts
2511 assignContainer(d&: array, x: map);
2512}
2513
2514/*!
2515 \internal
2516 */
2517static QCborContainerPrivate *maybeGrow(QCborContainerPrivate *container, qsizetype index)
2518{
2519 auto replace = QCborContainerPrivate::grow(d: container, index);
2520 Q_ASSERT(replace);
2521 if (replace->elements.size() == index)
2522 replace->append(Undefined());
2523 else
2524 Q_ASSERT(replace->elements.size() > index);
2525 return assignContainer(d&: container, x: replace);
2526}
2527
2528template <typename KeyType> inline QCborValueRef
2529QCborContainerPrivate::findOrAddMapKey(QCborValue &self, KeyType key)
2530{
2531 // we need a map, so convert if necessary
2532 if (self.isArray())
2533 convertArrayToMap(array&: self.container);
2534 else if (!self.isMap())
2535 self = QCborValue(QCborValue::Map);
2536 self.t = QCborValue::Map;
2537 self.n = -1;
2538
2539 QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
2540 assignContainer(d&: self.container, x: result.d);
2541 return result;
2542}
2543
2544template<typename KeyType> QCborValueRef
2545QCborContainerPrivate::findOrAddMapKey(QCborValueRef self, KeyType key)
2546{
2547 auto &e = self.d->elements[self.i];
2548
2549 // we need a map, so convert if necessary
2550 if (e.type == QCborValue::Array) {
2551 convertArrayToMap(array&: e.container);
2552 } else if (e.type != QCborValue::Map) {
2553 if (e.flags & QtCbor::Element::IsContainer)
2554 e.container->deref();
2555 e.container = nullptr;
2556 }
2557 e.flags = QtCbor::Element::IsContainer;
2558 e.type = QCborValue::Map;
2559
2560 QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
2561 assignContainer(d&: e.container, x: result.d);
2562 return result;
2563}
2564
2565/*!
2566 Returns a QCborValueRef that can be used to read or modify the entry in
2567 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2568 this function is equivalent to the matching operator[] on that map.
2569
2570 Before returning the reference: if this QCborValue was an array, it is first
2571 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2572 with valid \c{array[i]}); otherwise, if it was not a map it will be
2573 over-written with an empty map.
2574
2575 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2576 QCborMap::find()
2577 */
2578QCborValueRef QCborValue::operator[](const QString &key)
2579{
2580 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key: qToStringViewIgnoringNull(s: key));
2581}
2582
2583/*!
2584 \overload
2585
2586 Returns a QCborValueRef that can be used to read or modify the entry in
2587 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2588 this function is equivalent to the matching operator[] on that map.
2589
2590 Before returning the reference: if this QCborValue was an array, it is first
2591 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2592 with valid \c{array[i]}); otherwise, if it was not a map it will be
2593 over-written with an empty map.
2594
2595 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2596 QCborMap::find()
2597 */
2598QCborValueRef QCborValue::operator[](QLatin1StringView key)
2599{
2600 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key);
2601}
2602
2603/*!
2604 \overload
2605
2606 Returns a QCborValueRef that can be used to read or modify the entry in
2607 this, as a map or array, with the given \a key. When this QCborValue is a
2608 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
2609 equivalent to the matching operator[] on that map or array.
2610
2611 Before returning the reference: if this QCborValue was an array but the key
2612 is out of range, the array is first converted to a map (so that \c{map[i]}
2613 is \c{array[i]} for each index, \c i, with valid \c{array[i]}); otherwise,
2614 if it was not a map it will be over-written with an empty map.
2615
2616 \sa operator[], QCborMap::operator[], QCborMap::value(),
2617 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2618 */
2619QCborValueRef QCborValue::operator[](qint64 key)
2620{
2621 if (shouldArrayRemainArray(key, t, container)) {
2622 container = maybeGrow(container, index: key);
2623 return { container, qsizetype(key) };
2624 }
2625 return QCborContainerPrivate::findOrAddMapKey(self&: *this, key);
2626}
2627
2628#if QT_CONFIG(cborstreamreader)
2629/*!
2630 Decodes one item from the CBOR stream found in \a reader and returns the
2631 equivalent representation. This function is recursive: if the item is a map
2632 or array, it will decode all items found in that map or array, until the
2633 outermost object is finished.
2634
2635 This function need not be used on the root element of a \l
2636 QCborStreamReader. For example, the following code illustrates how to skip
2637 the CBOR signature tag from the beginning of a file:
2638
2639 \snippet code/src_corelib_serialization_qcborvalue.cpp 6
2640
2641 The returned value may be partially complete and indistinguishable from a
2642 valid QCborValue even if the decoding failed. To determine if there was an
2643 error, check if \l{QCborStreamReader::lastError()}{reader.lastError()} is
2644 indicating an error condition. This function stops decoding immediately
2645 after the first error.
2646
2647 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2648 */
2649QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
2650{
2651 QCborValue result;
2652 auto t = reader.type();
2653 if (reader.lastError() != QCborError::NoError)
2654 t = QCborStreamReader::Invalid;
2655
2656 switch (t) {
2657 // basic types, no container needed:
2658 case QCborStreamReader::UnsignedInteger:
2659 case QCborStreamReader::NegativeInteger:
2660 case QCborStreamReader::SimpleType:
2661 case QCborStreamReader::Float16:
2662 case QCborStreamReader::Float:
2663 case QCborStreamReader::Double: {
2664 Element e = decodeBasicValueFromCbor(reader);
2665 result.n = e.value;
2666 result.t = e.type;
2667 break;
2668 }
2669
2670 case QCborStreamReader::Invalid:
2671 result.t = QCborValue::Invalid;
2672 break; // probably a decode error
2673
2674 // strings
2675 case QCborStreamReader::ByteArray:
2676 case QCborStreamReader::String:
2677 result.n = 0;
2678 result.t = reader.isString() ? String : ByteArray;
2679 result.container = new QCborContainerPrivate;
2680 result.container->ref.ref();
2681 result.container->decodeStringFromCbor(reader);
2682 break;
2683
2684 // containers
2685 case QCborStreamReader::Array:
2686 case QCborStreamReader::Map:
2687 result.n = -1;
2688 result.t = reader.isArray() ? Array : Map;
2689 result.container = createContainerFromCbor(reader, remainingRecursionDepth: MaximumRecursionDepth);
2690 break;
2691
2692 // tag
2693 case QCborStreamReader::Tag:
2694 result = taggedValueFromCbor(reader, remainingRecursionDepth: MaximumRecursionDepth);
2695 break;
2696 }
2697
2698 return result;
2699}
2700
2701/*!
2702 \overload
2703
2704 Decodes one item from the CBOR stream found in the byte array \a ba and
2705 returns the equivalent representation. This function is recursive: if the
2706 item is a map or array, it will decode all items found in that map or
2707 array, until the outermost object is finished.
2708
2709 This function stores the error state, if any, in the object pointed to by
2710 \a error, along with the offset of where the error occurred. If no error
2711 happened, it stores \l{QCborError}{NoError} in the error state and the
2712 number of bytes that it consumed (that is, it stores the offset for the
2713 first unused byte). Using that information makes it possible to parse
2714 further data that may exist in the same byte array.
2715
2716 The returned value may be partially complete and indistinguishable from a
2717 valid QCborValue even if the decoding failed. To determine if there was an
2718 error, check if there was an error stored in \a error. This function stops
2719 decoding immediately after the first error.
2720
2721 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2722 */
2723QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
2724{
2725 QCborStreamReader reader(ba);
2726 QCborValue result = fromCbor(reader);
2727 if (error) {
2728 error->error = reader.lastError();
2729 error->offset = reader.currentOffset();
2730 }
2731 return result;
2732}
2733
2734/*!
2735 \fn QCborValue QCborValue::fromCbor(const char *data, qsizetype len, QCborParserError *error)
2736 \fn QCborValue QCborValue::fromCbor(const quint8 *data, qsizetype len, QCborParserError *error)
2737 \overload
2738
2739 Converts \a len bytes of \a data to a QByteArray and then calls the
2740 overload of this function that accepts a QByteArray, also passing \a error,
2741 if provided.
2742*/
2743#endif // QT_CONFIG(cborstreamreader)
2744
2745#if QT_CONFIG(cborstreamwriter) && !defined(QT_BOOTSTRAPPED)
2746/*!
2747 Encodes this QCborValue object to its CBOR representation, using the
2748 options specified in \a opt, and return the byte array containing that
2749 representation.
2750
2751 This function will not fail, except if this QCborValue or any of the
2752 contained items, if this is a map or array, are invalid. Invalid types are
2753 not produced normally by the API, but can result from decoding errors.
2754
2755 By default, this function performs no transformation on the values in the
2756 QCborValue, writing all floating point directly as double-precision (\c
2757 double) types. If the \l{EncodingOption}{UseFloat} option is specified, it
2758 will use single precision (\c float) for any floating point value for which
2759 there's no loss of precision in using that representation. That includes
2760 infinities and NaN values.
2761
2762 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2763 will try to use half-precision (\c qfloat16) floating point if the
2764 conversion to that results in no loss of precision. This is always true for
2765 infinities and NaN.
2766
2767 If \l{EncodingOption}{UseIntegers} is specified, it will use integers for
2768 any floating point value that contains an actual integer.
2769
2770 \sa fromCbor(), fromVariant(), fromJsonValue()
2771 */
2772QByteArray QCborValue::toCbor(EncodingOptions opt) const
2773{
2774 QByteArray result;
2775 QCborStreamWriter writer(&result);
2776 toCbor(writer, opt);
2777 return result;
2778}
2779
2780/*!
2781 \overload
2782
2783 Encodes this QCborValue object to its CBOR representation, using the
2784 options specified in \a opt, to the writer specified by \a writer. The same
2785 writer can be used by multiple QCborValues, for example, in order to encode
2786 different elements in a larger array.
2787
2788 This function will not fail, except if this QCborValue or any of the
2789 contained items, if this is a map or array, are invalid. Invalid types are
2790 not produced normally by the API, but can result from decoding errors.
2791
2792 By default, this function performs no transformation on the values in the
2793 QCborValue, writing all floating point directly as double-precision
2794 (binary64) types. If the \l{EncodingOption}{UseFloat} option is
2795 specified, it will use single precision (binary32) for any floating point
2796 value for which there's no loss of precision in using that representation.
2797 That includes infinities and NaN values.
2798
2799 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2800 will try to use half-precision (binary16) floating point if the conversion
2801 to that results in no loss of precision. This is always true for infinities
2802 and NaN.
2803
2804 If \l{EncodingOption}{UseIntegers} is specified, it will use integers
2805 for any floating point value that contains an actual integer.
2806
2807 \sa fromCbor(), fromVariant(), fromJsonValue()
2808 */
2809Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt) const
2810{
2811 if (isContainer() || isTag())
2812 return encodeToCbor(writer, d: container, idx: -type(), opt);
2813 if (container)
2814 return encodeToCbor(writer, d: container, idx: n, opt);
2815
2816 // very simple types
2817 if (isSimpleType())
2818 return writer.append(st: toSimpleType());
2819
2820 switch (type()) {
2821 case Integer:
2822 return writer.append(i: n);
2823
2824 case Double:
2825 return writeDoubleToCbor(writer, d: fp_helper(), opt);
2826
2827 case Invalid:
2828 return;
2829
2830 case SimpleType:
2831 case False:
2832 case True:
2833 case Null:
2834 case Undefined:
2835 // handled by "if (isSimpleType())"
2836 Q_UNREACHABLE();
2837 break;
2838
2839 case ByteArray:
2840 // Byte array with no container is empty
2841 return writer.appendByteString(data: "", len: 0);
2842
2843 case String:
2844 // String with no container is empty
2845 return writer.appendTextString(utf8: "", len: 0);
2846
2847 case Array:
2848 case Map:
2849 case Tag:
2850 // handled by "if (isContainer() || isTag())"
2851 Q_UNREACHABLE();
2852 break;
2853
2854 case DateTime:
2855 case Url:
2856 case RegularExpression:
2857 case Uuid:
2858 // not possible
2859 Q_UNREACHABLE();
2860 break;
2861 }
2862}
2863
2864# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2865void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
2866{
2867 concrete().toCbor(writer, opt);
2868}
2869# endif
2870#endif // QT_CONFIG(cborstreamwriter) && !QT_BOOTSTRAPPED
2871
2872void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
2873{
2874 that.d->replaceAt(idx: that.i, value: other);
2875}
2876
2877void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
2878{
2879 that.d->replaceAt(idx: that.i, value: other, disp: QCborContainerPrivate::MoveContainer);
2880}
2881
2882void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
2883{
2884 // ### optimize?
2885 that = other.concrete();
2886}
2887
2888bool QCborValueConstRef::concreteBoolean(QCborValueConstRef self, bool defaultValue) noexcept
2889{
2890 QtCbor::Element e = self.d->elements.at(i: self.i);
2891 if (e.type != QCborValue::False && e.type != QCborValue::True)
2892 return defaultValue;
2893 return e.type == QCborValue::True;
2894}
2895
2896double QCborValueConstRef::concreteDouble(QCborValueConstRef self, double defaultValue) noexcept
2897{
2898 QtCbor::Element e = self.d->elements.at(i: self.i);
2899 if (e.type == QCborValue::Integer)
2900 return e.value;
2901 if (e.type != QCborValue::Double)
2902 return defaultValue;
2903 return e.fpvalue();
2904}
2905
2906qint64 QCborValueConstRef::concreteIntegral(QCborValueConstRef self, qint64 defaultValue) noexcept
2907{
2908 QtCbor::Element e = self.d->elements.at(i: self.i);
2909 QCborValue::Type t = e.type;
2910 if (t == QCborValue::Double)
2911 return e.fpvalue();
2912 if (t != QCborValue::Integer)
2913 return defaultValue;
2914 return e.value;
2915}
2916
2917QByteArray QCborValueConstRef::concreteByteArray(QCborValueConstRef self,
2918 const QByteArray &defaultValue)
2919{
2920 QtCbor::Element e = self.d->elements.at(i: self.i);
2921 if (e.type != QCborValue::ByteArray)
2922 return defaultValue;
2923 return self.d->byteArrayAt(idx: self.i);
2924}
2925
2926QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QString &defaultValue)
2927{
2928 QtCbor::Element e = self.d->elements.at(i: self.i);
2929 if (e.type != QCborValue::String)
2930 return defaultValue;
2931 return self.d->stringAt(idx: self.i);
2932}
2933
2934QAnyStringView QCborValueConstRef::concreteStringView(QCborValueConstRef self, QAnyStringView defaultValue)
2935{
2936 QtCbor::Element e = self.d->elements.at(i: self.i);
2937 if (e.type != QCborValue::String)
2938 return defaultValue;
2939 return self.d->anyStringViewAt(idx: self.i);
2940}
2941
2942bool
2943QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
2944{
2945 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2946 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2947 return compareElementRecursive(c1: lhs.d, e1, c2: rhs.d, e2, mode: Comparison::ForEquality) == 0;
2948}
2949
2950Qt::strong_ordering
2951QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
2952{
2953 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2954 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2955 int c = compareElementRecursive(c1: lhs.d, e1, c2: rhs.d, e2, mode: Comparison::ForOrdering);
2956 return Qt::compareThreeWay(lhs: c, rhs: 0);
2957}
2958
2959bool
2960QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
2961{
2962 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2963 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
2964 return compareElementRecursive(c1: lhs.d, e1, c2: rhs.container, e2, mode: Comparison::ForEquality) == 0;
2965}
2966
2967Qt::strong_ordering
2968QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
2969{
2970 QtCbor::Element e1 = lhs.d->elements.at(i: lhs.i);
2971 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(value: rhs);
2972 int c = compareElementRecursive(c1: lhs.d, e1, c2: rhs.container, e2, mode: Comparison::ForOrdering);
2973 return Qt::compareThreeWay(lhs: c, rhs: 0);
2974}
2975
2976bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2977{
2978 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2979 if (typeOrder(e1: QCborValue::Array, e2: e2.type))
2980 return false;
2981 return compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForEquality) == 0;
2982}
2983
2984Qt::strong_ordering
2985QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
2986{
2987 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2988 int c = typeOrder(e1: QCborValue::Array, e2: e2.type);
2989 if (c == 0)
2990 c = compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForOrdering);
2991 return Qt::compareThreeWay(lhs: c, rhs: 0);
2992}
2993
2994bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
2995{
2996 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
2997 if (typeOrder(e1: QCborValue::Array, e2: e2.type))
2998 return false;
2999 return compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForEquality) == 0;
3000}
3001
3002Qt::strong_ordering
3003QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
3004{
3005 QtCbor::Element e2 = rhs.d->elements.at(i: rhs.i);
3006 int c = typeOrder(e1: QCborValue::Map, e2: e2.type);
3007 if (c == 0)
3008 c = compareContainer(c1: lhs.d.constData(), c2: e2.container, mode: Comparison::ForOrdering);
3009 return Qt::compareThreeWay(lhs: c, rhs: 0);
3010}
3011
3012QCborValue QCborValueConstRef::concrete(QCborValueConstRef self) noexcept
3013{
3014 return self.d->valueAt(idx: self.i);
3015}
3016
3017QCborValue::Type QCborValueConstRef::concreteType(QCborValueConstRef self) noexcept
3018{
3019 return self.d->elements.at(i: self.i).type;
3020}
3021
3022const QCborValue QCborValueConstRef::operator[](const QString &key) const
3023{
3024 const QCborValue item = d->valueAt(idx: i);
3025 return item[key];
3026}
3027
3028const QCborValue QCborValueConstRef::operator[](const QLatin1StringView key) const
3029{
3030 const QCborValue item = d->valueAt(idx: i);
3031 return item[key];
3032}
3033
3034const QCborValue QCborValueConstRef::operator[](qint64 key) const
3035{
3036 const QCborValue item = d->valueAt(idx: i);
3037 return item[key];
3038}
3039
3040#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
3041QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
3042{
3043 return self.d->valueAt(idx: self.i);
3044}
3045
3046QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
3047{
3048 return self.d->elements.at(i: self.i).type;
3049}
3050
3051/*!
3052 If this QCborValueRef refers to a QCborMap, searches elements for the value
3053 whose key matches \a key. If there's no key matching \a key in the map or if
3054 this QCborValueRef object is not a map, returns the undefined value.
3055
3056 This function is equivalent to:
3057
3058 \code
3059 value.toMap().value(key);
3060 \endcode
3061
3062 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3063 QCborMap::find()
3064 */
3065const QCborValue QCborValueRef::operator[](const QString &key) const
3066{
3067 return QCborValueConstRef::operator[](key);
3068}
3069
3070/*!
3071 \overload
3072
3073 If this QCborValueRef refers to a QCborMap, searches elements for the value
3074 whose key matches \a key. If there's no key matching \a key in the map or if
3075 this QCborValueRef object is not a map, returns the undefined value.
3076
3077 This function is equivalent to:
3078
3079 \code
3080 value.toMap().value(key);
3081 \endcode
3082
3083 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3084 QCborMap::find()
3085 */
3086const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
3087{
3088 return QCborValueConstRef::operator[](key);
3089}
3090
3091/*!
3092 \overload
3093
3094 If this QCborValueRef refers to a QCborMap, searches elements for the value
3095 whose key matches \a key. If this is a QCborArray, returns the element whose
3096 index is \a key. If there's no matching value in the array or map, or if
3097 this QCborValueRef object is not an array or map, returns the undefined
3098 value.
3099
3100 \sa operator[], QCborMap::operator[], QCborMap::value(),
3101 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3102 */
3103const QCborValue QCborValueRef::operator[](qint64 key) const
3104{
3105 return QCborValueConstRef::operator[](key);
3106}
3107
3108/*!
3109 Returns a QCborValueRef that can be used to read or modify the entry in
3110 this, as a map, with the given \a key. When this QCborValueRef refers to a
3111 QCborMap, this function is equivalent to the matching operator[] on that
3112 map.
3113
3114 Before returning the reference: if the QCborValue referenced was an array,
3115 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3116 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3117 will be over-written with an empty map.
3118
3119 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3120 QCborMap::find()
3121 */
3122QCborValueRef QCborValueRef::operator[](const QString &key)
3123{
3124 return QCborContainerPrivate::findOrAddMapKey(self: *this, key: qToStringViewIgnoringNull(s: key));
3125}
3126
3127/*!
3128 \overload
3129
3130 Returns a QCborValueRef that can be used to read or modify the entry in
3131 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
3132 this function is equivalent to the matching operator[] on that map.
3133
3134 Before returning the reference: if the QCborValue referenced was an array,
3135 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3136 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3137 will be over-written with an empty map.
3138
3139 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3140 QCborMap::find()
3141 */
3142QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
3143{
3144 return QCborContainerPrivate::findOrAddMapKey(self: *this, key);
3145}
3146
3147/*!
3148 \overload
3149
3150 Returns a QCborValueRef that can be used to read or modify the entry in
3151 this, as a map or array, with the given \a key. When this QCborValue is a
3152 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
3153 equivalent to the matching operator[] on that map or array.
3154
3155 Before returning the reference: if the QCborValue referenced was an array
3156 but the key is out of range, the array is first converted to a map (so that
3157 \c{map[i]} is \c{array[i]} for each index, \c i, with valid \c{array[i]});
3158 otherwise, if it was not a map it will be over-written with an empty map.
3159
3160 \sa operator[], QCborMap::operator[], QCborMap::value(),
3161 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3162 */
3163QCborValueRef QCborValueRef::operator[](qint64 key)
3164{
3165 auto &e = d->elements[i];
3166 if (shouldArrayRemainArray(key, t: e.type, container: e.container)) {
3167 e.container = maybeGrow(container: e.container, index: key);
3168 e.flags |= QtCbor::Element::IsContainer;
3169 return { e.container, qsizetype(key) };
3170 }
3171 return QCborContainerPrivate::findOrAddMapKey(self: *this, key);
3172}
3173#endif // < Qt 7
3174
3175inline QCborArray::QCborArray(QCborContainerPrivate &dd) noexcept
3176 : d(&dd)
3177{
3178}
3179
3180inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept
3181 : d(&dd)
3182{
3183}
3184
3185size_t qHash(const QCborValue &value, size_t seed)
3186{
3187 switch (value.type()) {
3188 case QCborValue::Integer:
3189 return qHash(key: value.toInteger(), seed);
3190 case QCborValue::ByteArray:
3191 return qHash(key: value.toByteArray(), seed);
3192 case QCborValue::String:
3193 return qHash(key: value.toString(), seed);
3194 case QCborValue::Array:
3195 return qHash(array: value.toArray(), seed);
3196 case QCborValue::Map:
3197 return qHash(map: value.toMap(), seed);
3198 case QCborValue::Tag:
3199 return qHashMulti(seed, args: value.tag(), args: value.taggedValue());
3200 case QCborValue::SimpleType:
3201 break;
3202 case QCborValue::False:
3203 return qHash(key: false, seed);
3204 case QCborValue::True:
3205 return qHash(key: true, seed);
3206 case QCborValue::Null:
3207 return qHash(nullptr, seed);
3208 case QCborValue::Undefined:
3209 return seed;
3210 case QCborValue::Double:
3211 return qHash(key: value.toDouble(), seed);
3212#if QT_CONFIG(datestring)
3213 case QCborValue::DateTime:
3214 return qHash(key: value.toDateTime(), seed);
3215#endif
3216#ifndef QT_BOOTSTRAPPED
3217 case QCborValue::Url:
3218 return qHash(url: value.toUrl(), seed);
3219# if QT_CONFIG(regularexpression)
3220 case QCborValue::RegularExpression:
3221 return qHash(key: value.toRegularExpression(), seed);
3222# endif
3223 case QCborValue::Uuid:
3224 return qHash(uuid: value.toUuid(), seed);
3225#endif
3226 case QCborValue::Invalid:
3227 return seed;
3228 default:
3229 break;
3230 }
3231
3232 Q_ASSERT(value.isSimpleType());
3233 return qHash(tag: value.toSimpleType(), seed);
3234}
3235
3236Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
3237{
3238 switch (st) {
3239 case QCborSimpleType::False:
3240 return "False";
3241 case QCborSimpleType::True:
3242 return "True";
3243 case QCborSimpleType::Null:
3244 return "Null";
3245 case QCborSimpleType::Undefined:
3246 return "Undefined";
3247 }
3248 return nullptr;
3249}
3250
3251Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
3252{
3253 // Casting to QCborKnownTags's underlying type will make the comparison
3254 // below fail if the tag value is out of range.
3255 auto n = std::underlying_type<QCborKnownTags>::type(tag);
3256 if (QCborTag(n) == tag) {
3257 switch (QCborKnownTags(n)) {
3258 case QCborKnownTags::DateTimeString:
3259 return "DateTimeString";
3260 case QCborKnownTags::UnixTime_t:
3261 return "UnixTime_t";
3262 case QCborKnownTags::PositiveBignum:
3263 return "PositiveBignum";
3264 case QCborKnownTags::NegativeBignum:
3265 return "NegativeBignum";
3266 case QCborKnownTags::Decimal:
3267 return "Decimal";
3268 case QCborKnownTags::Bigfloat:
3269 return "Bigfloat";
3270 case QCborKnownTags::COSE_Encrypt0:
3271 return "COSE_Encrypt0";
3272 case QCborKnownTags::COSE_Mac0:
3273 return "COSE_Mac0";
3274 case QCborKnownTags::COSE_Sign1:
3275 return "COSE_Sign1";
3276 case QCborKnownTags::ExpectedBase64url:
3277 return "ExpectedBase64url";
3278 case QCborKnownTags::ExpectedBase64:
3279 return "ExpectedBase64";
3280 case QCborKnownTags::ExpectedBase16:
3281 return "ExpectedBase16";
3282 case QCborKnownTags::EncodedCbor:
3283 return "EncodedCbor";
3284 case QCborKnownTags::Url:
3285 return "Url";
3286 case QCborKnownTags::Base64url:
3287 return "Base64url";
3288 case QCborKnownTags::Base64:
3289 return "Base64";
3290 case QCborKnownTags::RegularExpression:
3291 return "RegularExpression";
3292 case QCborKnownTags::MimeMessage:
3293 return "MimeMessage";
3294 case QCborKnownTags::Uuid:
3295 return "Uuid";
3296 case QCborKnownTags::COSE_Encrypt:
3297 return "COSE_Encrypt";
3298 case QCborKnownTags::COSE_Mac:
3299 return "COSE_Mac";
3300 case QCborKnownTags::COSE_Sign:
3301 return "COSE_Sign";
3302 case QCborKnownTags::Signature:
3303 return "Signature";
3304 }
3305 }
3306 return nullptr;
3307}
3308
3309#if !defined(QT_NO_DEBUG_STREAM)
3310static QDebug debugContents(QDebug &dbg, const QCborValue &v)
3311{
3312 switch (v.type()) {
3313 case QCborValue::Integer:
3314 return dbg << v.toInteger();
3315 case QCborValue::ByteArray:
3316 return dbg << "QByteArray(" << v.toByteArray() << ')';
3317 case QCborValue::String:
3318 return dbg << v.toString();
3319 case QCborValue::Array:
3320 return dbg << v.toArray();
3321 case QCborValue::Map:
3322 return dbg << v.toMap();
3323 case QCborValue::Tag: {
3324 QCborTag tag = v.tag();
3325 const char *id = qt_cbor_tag_id(tag);
3326 if (id)
3327 dbg.nospace() << "QCborKnownTags::" << id << ", ";
3328 else
3329 dbg.nospace() << "QCborTag(" << quint64(tag) << "), ";
3330 return dbg << v.taggedValue();
3331 }
3332 case QCborValue::SimpleType:
3333 break;
3334 case QCborValue::True:
3335 return dbg << true;
3336 case QCborValue::False:
3337 return dbg << false;
3338 case QCborValue::Null:
3339 return dbg << "nullptr";
3340 case QCborValue::Undefined:
3341 return dbg;
3342 case QCborValue::Double: {
3343 qint64 i;
3344 if (convertDoubleTo(v: v.toDouble(), value: &i))
3345 return dbg << i << ".0";
3346 else
3347 return dbg << v.toDouble();
3348 }
3349#if QT_CONFIG(datestring)
3350 case QCborValue::DateTime:
3351 return dbg << v.toDateTime();
3352#endif
3353#ifndef QT_BOOTSTRAPPED
3354 case QCborValue::Url:
3355 return dbg << v.toUrl();
3356#if QT_CONFIG(regularexpression)
3357 case QCborValue::RegularExpression:
3358 return dbg << v.toRegularExpression();
3359#endif
3360 case QCborValue::Uuid:
3361 return dbg << v.toUuid();
3362#endif
3363 case QCborValue::Invalid:
3364 return dbg << "<invalid>";
3365 default:
3366 break;
3367 }
3368 if (v.isSimpleType())
3369 return dbg << v.toSimpleType();
3370 return dbg << "<unknown type 0x" << Qt::hex << int(v.type()) << Qt::dec << '>';
3371}
3372QDebug operator<<(QDebug dbg, const QCborValue &v)
3373{
3374 QDebugStateSaver saver(dbg);
3375 dbg.nospace() << "QCborValue(";
3376 return debugContents(dbg, v) << ')';
3377}
3378
3379QDebug operator<<(QDebug dbg, QCborSimpleType st)
3380{
3381 QDebugStateSaver saver(dbg);
3382 const char *id = qt_cbor_simpletype_id(st);
3383 if (id)
3384 return dbg.nospace() << "QCborSimpleType::" << id;
3385
3386 return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
3387}
3388
3389QDebug operator<<(QDebug dbg, QCborTag tag)
3390{
3391 QDebugStateSaver saver(dbg);
3392 const char *id = qt_cbor_tag_id(tag);
3393 dbg.nospace() << "QCborTag(";
3394 if (id)
3395 dbg.nospace() << "QCborKnownTags::" << id;
3396 else
3397 dbg.nospace() << quint64(tag);
3398
3399 return dbg << ')';
3400}
3401
3402QDebug operator<<(QDebug dbg, QCborKnownTags tag)
3403{
3404 QDebugStateSaver saver(dbg);
3405 const char *id = qt_cbor_tag_id(tag: QCborTag(int(tag)));
3406 if (id)
3407 return dbg.nospace() << "QCborKnownTags::" << id;
3408
3409 return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
3410}
3411#endif
3412
3413#ifndef QT_NO_DATASTREAM
3414#if QT_CONFIG(cborstreamwriter)
3415QDataStream &operator<<(QDataStream &stream, const QCborValue &value)
3416{
3417 stream << QCborValue(value).toCbor();
3418 return stream;
3419}
3420#endif
3421
3422#if QT_CONFIG(cborstreamreader)
3423QDataStream &operator>>(QDataStream &stream, QCborValue &value)
3424{
3425 QByteArray buffer;
3426 stream >> buffer;
3427 QCborParserError parseError{};
3428 value = QCborValue::fromCbor(ba: buffer, error: &parseError);
3429 if (parseError.error)
3430 stream.setStatus(QDataStream::ReadCorruptData);
3431 return stream;
3432}
3433#endif
3434#endif // QT_NO_DATASTREAM
3435
3436
3437QT_END_NAMESPACE
3438
3439#include "qcborarray.cpp"
3440#include "qcbormap.cpp"
3441
3442#ifndef QT_NO_QOBJECT
3443#include "moc_qcborvalue.cpp"
3444#endif
3445

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