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