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

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