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 Not-a-number (NaN) comparisons
1479
1480 QCborValue compares the exact bit representation of the NaN, as provided in
1481 the constructor. This means NaNs will compare equal if they have the same
1482 representation, unlike what one may expect for floating point comparisons.
1483 However, NaNs with different payloads or sign will compare unequal.
1484
1485 This implies QCborValue provides strong and total ordering semantics.
1486
1487 \section3 Extended types
1488
1489 QCborValue compares equal a QCborValue containing an extended type, like
1490 \l{Type}{Url} and \l{Type}{Url} and its equivalent tagged representation.
1491 So, for example, the following expression is true:
1492
1493 \snippet code/src_corelib_serialization_qcborvalue.cpp 3
1494
1495 Do note that Qt types like \l QUrl and \l QDateTime will normalize and
1496 otherwise modify their arguments. The expression above is true only because
1497 the string on the right side is the normalized value that the QCborValue on
1498 the left would take. If, for example, the "https" part were uppercase in
1499 both sides, the comparison would fail. For information on normalizations
1500 performed by QCborValue, please consult the documentation of the
1501 constructor taking the Qt type in question.
1502
1503 \section3 Sorting order
1504
1505 Sorting order in CBOR is defined in
1506 \l{RFC 7049, section 3.9}, which
1507 discusses the sorting of keys in a map when following the Canonical
1508 encoding. According to the specification, "sorting is performed on the
1509 bytes of the representation of the key data items" and lists as
1510 consequences that:
1511
1512 \list
1513 \li "If two keys have different lengths, the shorter one sorts earlier;"
1514 \li "If two keys have the same length, the one with the lower value in
1515 (byte-wise) lexical order sorts earlier."
1516 \endlist
1517
1518 This results in surprising sorting of QCborValues, where the result of this
1519 function is different from that which would later be retrieved by comparing the
1520 contained elements. For example, the QCborValue containing string "zzz"
1521 sorts before the QCborValue with string "foobar", even though when
1522 comparing as \l{QString::compare()}{QStrings} or
1523 \l{QByteArray}{QByteArrays} the "zzz" sorts after "foobar"
1524 (dictionary order).
1525
1526 The specification does not clearly indicate what sorting order should be
1527 done for values of different types (it says sorting should not pay
1528 "attention to the 3/5 bit splitting for major types"). QCborValue makes the
1529 assumption that types should be sorted too. The numeric values of the
1530 QCborValue::Type enumeration are in that order, with the exception of the
1531 extended types, which compare as their tagged equivalents.
1532
1533 \note Sorting order is preliminary and is subject to change. Applications
1534 should not depend on the order returned by this function for the time
1535 being.
1536
1537 \sa QCborArray::compare(), QCborMap::compare(), operator==()
1538 */
1539int QCborValue::compare(const QCborValue &other) const
1540{
1541 Element e1 = QCborContainerPrivate::elementFromValue(*this);
1542 Element e2 = QCborContainerPrivate::elementFromValue(other);
1543 return compareElementRecursive(container, e1, other.container, e2, Comparison::ForOrdering);
1544}
1545
1546bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
1547{
1548 return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
1549}
1550
1551int QCborArray::compare(const QCborArray &other) const noexcept
1552{
1553 return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
1554}
1555
1556bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1557{
1558 if (typeOrder(QCborValue::Array, rhs.type()))
1559 return false;
1560 return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
1561}
1562
1563Qt::strong_ordering
1564QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
1565{
1566 int c = typeOrder(QCborValue::Array, rhs.type());
1567 if (c == 0)
1568 c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
1569 return Qt::compareThreeWay(c, 0);
1570}
1571
1572bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
1573{
1574 return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
1575}
1576
1577int QCborMap::compare(const QCborMap &other) const noexcept
1578{
1579 return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
1580}
1581
1582bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1583{
1584 if (typeOrder(QCborValue::Map, rhs.type()))
1585 return false;
1586 return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
1587}
1588
1589Qt::strong_ordering
1590QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
1591{
1592 int c = typeOrder(QCborValue::Map, rhs.type());
1593 if (c == 0)
1594 c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
1595 return Qt::compareThreeWay(c, 0);
1596}
1597
1598#if QT_CONFIG(cborstreamwriter) && !defined(QT_BOOTSTRAPPED)
1599static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate *d, qsizetype idx,
1600 QCborValue::EncodingOptions opt)
1601{
1602 if (idx == -QCborValue::Array || idx == -QCborValue::Map) {
1603 bool isArray = (idx == -QCborValue::Array);
1604 qsizetype len = d ? d->elements.size() : 0;
1605 if (isArray)
1606 writer.startArray(quint64(len));
1607 else
1608 writer.startMap(quint64(len) / 2);
1609
1610 for (idx = 0; idx < len; ++idx)
1611 encodeToCbor(writer, d, idx, opt);
1612
1613 if (isArray)
1614 writer.endArray();
1615 else
1616 writer.endMap();
1617 } else if (idx < 0) {
1618 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1619 if (d->elements.size() != 2) {
1620 // invalid state!
1621 qWarning("QCborValue: invalid tag state; are you encoding something that was improperly decoded?");
1622 return;
1623 }
1624
1625 // write the tag and the tagged element
1626 writer.append(QCborTag(d->elements.at(0).value));
1627 encodeToCbor(writer, d, 1, opt);
1628 } else {
1629 Q_ASSERT_X(d != nullptr, "QCborValue", "Unexpected null container");
1630 // just one element
1631 auto e = d->elements.at(idx);
1632 const ByteData *b = d->byteData(idx);
1633 switch (e.type) {
1634 case QCborValue::Integer:
1635 return writer.append(qint64(e.value));
1636
1637 case QCborValue::ByteArray:
1638 if (b)
1639 return writer.appendByteString(b->byte(), b->len);
1640 return writer.appendByteString("", 0);
1641
1642 case QCborValue::String:
1643 if (b) {
1644 if (e.flags & Element::StringIsUtf16)
1645 return writer.append(b->asStringView());
1646 return writer.appendTextString(b->byte(), b->len);
1647 }
1648 return writer.append(QLatin1StringView());
1649
1650 case QCborValue::Array:
1651 case QCborValue::Map:
1652 case QCborValue::Tag:
1653 // recurse
1654 return encodeToCbor(writer,
1655 e.flags & Element::IsContainer ? e.container : nullptr,
1656 -qsizetype(e.type), opt);
1657
1658 case QCborValue::SimpleType:
1659 case QCborValue::False:
1660 case QCborValue::True:
1661 case QCborValue::Null:
1662 case QCborValue::Undefined:
1663 break;
1664
1665 case QCborValue::Double:
1666 return writeDoubleToCbor(writer, e.fpvalue(), opt);
1667
1668 case QCborValue::Invalid:
1669 return;
1670
1671 case QCborValue::DateTime:
1672 case QCborValue::Url:
1673 case QCborValue::RegularExpression:
1674 case QCborValue::Uuid:
1675 // recurse as tag
1676 return encodeToCbor(writer, e.container, -QCborValue::Tag, opt);
1677 }
1678
1679 // maybe it's a simple type
1680 int simpleType = e.type - QCborValue::SimpleType;
1681 if (unsigned(simpleType) < 0x100)
1682 return writer.append(QCborSimpleType(simpleType));
1683
1684 // if we got here, we've got an unknown type
1685 qWarning("QCborValue: found unknown type 0x%x", e.type);
1686 }
1687}
1688#endif // QT_CONFIG(cborstreamwriter) && !QT_BOOTSTRAPPED
1689
1690#if QT_CONFIG(cborstreamreader)
1691// confirm that our basic Types match QCborStreamReader::Types
1692static_assert(int(QCborValue::Integer) == int(QCborStreamReader::UnsignedInteger));
1693static_assert(int(QCborValue::ByteArray) == int(QCborStreamReader::ByteArray));
1694static_assert(int(QCborValue::String) == int(QCborStreamReader::String));
1695static_assert(int(QCborValue::Array) == int(QCborStreamReader::Array));
1696static_assert(int(QCborValue::Map) == int(QCborStreamReader::Map));
1697static_assert(int(QCborValue::Tag) == int(QCborStreamReader::Tag));
1698
1699static inline double integerOutOfRange(const QCborStreamReader &reader)
1700{
1701 Q_ASSERT(reader.isInteger());
1702 if (reader.isUnsignedInteger()) {
1703 quint64 v = reader.toUnsignedInteger();
1704 if (qint64(v) < 0)
1705 return double(v);
1706 } else {
1707 quint64 v = quint64(reader.toNegativeInteger());
1708 if (qint64(v - 1) < 0)
1709 return -double(v);
1710 }
1711
1712 // result is in range
1713 return 0;
1714}
1715
1716static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
1717{
1718 Element e = {};
1719
1720 switch (reader.type()) {
1721 case QCborStreamReader::UnsignedInteger:
1722 case QCborStreamReader::NegativeInteger:
1723 if (double d = integerOutOfRange(reader)) {
1724 e.type = QCborValue::Double;
1725 qToUnaligned(d, &e.value);
1726 } else {
1727 e.type = QCborValue::Integer;
1728 e.value = reader.toInteger();
1729 }
1730 break;
1731 case QCborStreamReader::SimpleType:
1732 e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
1733 break;
1734 case QCborStreamReader::Float16:
1735 e.type = QCborValue::Double;
1736 qToUnaligned(double(reader.toFloat16()), &e.value);
1737 break;
1738 case QCborStreamReader::Float:
1739 e.type = QCborValue::Double;
1740 qToUnaligned(double(reader.toFloat()), &e.value);
1741 break;
1742 case QCborStreamReader::Double:
1743 e.type = QCborValue::Double;
1744 qToUnaligned(reader.toDouble(), &e.value);
1745 break;
1746
1747 default:
1748 Q_UNREACHABLE();
1749 }
1750
1751 reader.next();
1752 return e;
1753}
1754
1755// Clamp allocation to avoid crashing due to corrupt stream. This also
1756// ensures we never overflow qsizetype. The returned length is doubled for Map
1757// entries to account for key-value pairs.
1758static qsizetype clampedContainerLength(const QCborStreamReader &reader)
1759{
1760 if (!reader.isLengthKnown())
1761 return 0;
1762 int mapShift = reader.isMap() ? 1 : 0;
1763 quint64 shiftedMaxElements = MaximumPreallocatedElementCount >> mapShift;
1764 qsizetype len = qsizetype(qMin(reader.length(), shiftedMaxElements));
1765 return len << mapShift;
1766}
1767
1768static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1769{
1770 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1771 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1772 return nullptr;
1773 }
1774
1775 QCborContainerPrivate *d = nullptr;
1776 {
1777 // in case QList::reserve throws
1778 QExplicitlySharedDataPointer u(new QCborContainerPrivate);
1779 if (qsizetype len = clampedContainerLength(reader))
1780 u->elements.reserve(len);
1781 d = u.take();
1782 }
1783
1784 reader.enterContainer();
1785 if (reader.lastError() != QCborError::NoError) {
1786 d->elements.clear();
1787 return d;
1788 }
1789
1790 while (reader.hasNext() && reader.lastError() == QCborError::NoError)
1791 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1792
1793 if (reader.lastError() == QCborError::NoError)
1794 reader.leaveContainer();
1795 else
1796 d->elements.squeeze();
1797
1798 return d;
1799}
1800
1801static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1802{
1803 if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
1804 QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
1805 return QCborValue::Invalid;
1806 }
1807
1808 auto d = new QCborContainerPrivate;
1809 d->append(reader.toTag());
1810 reader.next();
1811
1812 if (reader.lastError() == QCborError::NoError) {
1813 // decode tagged value
1814 d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
1815 }
1816
1817 QCborValue::Type type;
1818 if (reader.lastError() == QCborError::NoError) {
1819 // post-process to create our extended types
1820 type = convertToExtendedType(d);
1821 } else {
1822 // decoding error
1823 type = QCborValue::Invalid;
1824 }
1825
1826 // note: may return invalid state!
1827 return QCborContainerPrivate::makeValue(type, -1, d);
1828}
1829
1830// in qcborstream.cpp
1831extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
1832inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
1833{
1834 qt_cbor_stream_set_error(reader.d.get(), error);
1835}
1836
1837extern QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data);
1838
1839void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
1840{
1841 if (reader.lastError() != QCborError::NoError)
1842 return;
1843
1844 qsizetype rawlen = reader.currentStringChunkSize();
1845 QByteArray::size_type len = rawlen;
1846 if (rawlen < 0)
1847 return; // error
1848 if (len != rawlen) {
1849 // truncation
1850 setErrorInReader(reader, { QCborError::DataTooLarge });
1851 return;
1852 }
1853
1854 auto resetSize = qScopeGuard([this, oldSize = data.size()] {
1855 data.resize(oldSize);
1856 if (oldSize < data.capacity() / 2)
1857 data.squeeze();
1858 });
1859
1860 Element e = {};
1861 e.type = QCborValue::Type(reader.type());
1862 if (len || !reader.isLengthKnown()) {
1863 // The use of size_t means none of the operations here can overflow because
1864 // all inputs are less than half SIZE_MAX.
1865 constexpr size_t EstimatedOverhead = 16;
1866 constexpr size_t MaxMemoryIncrement = 16384;
1867 size_t offset = data.size();
1868
1869 // add space for aligned ByteData (this can't overflow)
1870 offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
1871 offset &= ~(alignof(QtCbor::ByteData) - 1);
1872 if (offset > size_t(QByteArray::maxSize())) {
1873 // overflow
1874 setErrorInReader(reader, { QCborError::DataTooLarge });
1875 return;
1876 }
1877
1878 // and calculate the size we want to have
1879 size_t newCapacity = offset + len; // can't overflow
1880 if (size_t(len) > MaxMemoryIncrement - EstimatedOverhead) {
1881 // there's a non-zero chance that we won't need this memory at all,
1882 // so capa how much we allocate
1883 newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
1884 }
1885 if (newCapacity > size_t(QByteArray::maxSize())) {
1886 // this may cause an allocation failure
1887 newCapacity = QByteArray::maxSize();
1888 }
1889 if (newCapacity > size_t(data.capacity()))
1890 data.reserve(newCapacity);
1891 data.resize(offset + sizeof(QtCbor::ByteData));
1892 e.value = offset;
1893 e.flags = Element::HasByteData;
1894 }
1895
1896 // read chunks
1897 bool isAscii = (e.type == QCborValue::String);
1898 QCborStreamReader::StringResultCode status = qt_cbor_append_string_chunk(reader, &data);
1899 while (status == QCborStreamReader::Ok) {
1900 if (e.type == QCborValue::String && len) {
1901 // verify UTF-8 string validity
1902 auto utf8result = QUtf8::isValidUtf8(QByteArrayView(data).last(len));
1903 if (!utf8result.isValidUtf8) {
1904 setErrorInReader(reader, { QCborError::InvalidUtf8String });
1905 return;
1906 }
1907 isAscii = isAscii && utf8result.isValidAscii;
1908 }
1909
1910 rawlen = reader.currentStringChunkSize();
1911 len = rawlen;
1912 if (len == rawlen) {
1913 status = qt_cbor_append_string_chunk(reader, &data);
1914 } else {
1915 // error
1916 setErrorInReader(reader, { QCborError::DataTooLarge });
1917 return;
1918 }
1919 }
1920
1921 // update size
1922 if (status == QCborStreamReader::EndOfString && e.flags & Element::HasByteData) {
1923 Q_ASSERT(data.isDetached());
1924 const char *ptr = data.constData() + e.value;
1925 auto b = new (const_cast<char *>(ptr)) ByteData;
1926 b->len = data.size() - e.value - int(sizeof(*b));
1927 usedData += b->len;
1928
1929 if (isAscii) {
1930 // set the flag if it is US-ASCII only (as it often is)
1931 Q_ASSERT(e.type == QCborValue::String);
1932 e.flags |= Element::StringIsAscii;
1933 }
1934
1935 // check that this UTF-8 text string can be loaded onto a QString
1936 if (e.type == QCborValue::String) {
1937 if (Q_UNLIKELY(b->len > QString::maxSize())) {
1938 setErrorInReader(reader, { QCborError::DataTooLarge });
1939 return;
1940 }
1941 }
1942 }
1943
1944 if (status == QCborStreamReader::EndOfString) {
1945 elements.append(e);
1946 resetSize.dismiss();
1947 }
1948}
1949
1950void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
1951{
1952 QCborStreamReader::Type t = reader.type();
1953 switch (t) {
1954 case QCborStreamReader::UnsignedInteger:
1955 case QCborStreamReader::NegativeInteger:
1956 case QCborStreamReader::SimpleType:
1957 case QCborStreamReader::Float16:
1958 case QCborStreamReader::Float:
1959 case QCborStreamReader::Double:
1960 elements.append(decodeBasicValueFromCbor(reader));
1961 break;
1962
1963 case QCborStreamReader::ByteArray:
1964 case QCborStreamReader::String:
1965 decodeStringFromCbor(reader);
1966 break;
1967
1968 case QCborStreamReader::Array:
1969 case QCborStreamReader::Map:
1970 return append(makeValue(t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, -1,
1971 createContainerFromCbor(reader, remainingRecursionDepth),
1972 MoveContainer));
1973
1974 case QCborStreamReader::Tag:
1975 return append(taggedValueFromCbor(reader, remainingRecursionDepth));
1976
1977 case QCborStreamReader::Invalid:
1978 return; // probably a decode error
1979 }
1980}
1981#endif // QT_CONFIG(cborstreamreader)
1982
1983/*!
1984 Creates a QCborValue with byte array value \a ba. The value can later be
1985 retrieved using toByteArray().
1986
1987 \sa toByteArray(), isByteArray(), isString()
1988 */
1989QCborValue::QCborValue(const QByteArray &ba)
1990 : n(0), container(new QCborContainerPrivate), t(ByteArray)
1991{
1992 container->appendByteData(ba.constData(), ba.size(), t);
1993 container->ref.storeRelaxed(1);
1994}
1995
1996/*!
1997 Creates a QCborValue with string value \a s. The value can later be
1998 retrieved using toString().
1999
2000 \sa toString(), isString(), isByteArray()
2001 */
2002QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {}
2003
2004/*!
2005 Creates a QCborValue with string value \a s. The value can later be
2006 retrieved using toString().
2007
2008 \sa toString(), isString(), isByteArray()
2009*/
2010QCborValue::QCborValue(QStringView s)
2011 : n(0), container(new QCborContainerPrivate), t(String)
2012{
2013 container->append(s);
2014 container->ref.storeRelaxed(1);
2015}
2016
2017/*!
2018 \overload
2019
2020 Creates a QCborValue with the Latin-1 string viewed by \a s.
2021 The value can later be retrieved using toString().
2022
2023 \sa toString(), isString(), isByteArray()
2024 */
2025QCborValue::QCborValue(QLatin1StringView s)
2026 : n(0), container(new QCborContainerPrivate), t(String)
2027{
2028 container->append(s);
2029 container->ref.storeRelaxed(1);
2030}
2031
2032/*!
2033 \fn QCborValue::QCborValue(const QCborArray &a)
2034 \fn QCborValue::QCborValue(QCborArray &&a)
2035
2036 Creates a QCborValue with the array \a a. The array can later be retrieved
2037 using toArray().
2038
2039 \sa toArray(), isArray(), isMap()
2040 */
2041QCborValue::QCborValue(const QCborArray &a)
2042 : n(-1), container(a.d.data()), t(Array)
2043{
2044 if (container)
2045 container->ref.ref();
2046}
2047
2048/*!
2049 \fn QCborValue::QCborValue(const QCborMap &m)
2050 \fn QCborValue::QCborValue(QCborMap &&m)
2051
2052 Creates a QCborValue with the map \a m. The map can later be retrieved
2053 using toMap().
2054
2055 \sa toMap(), isMap(), isArray()
2056 */
2057QCborValue::QCborValue(const QCborMap &m)
2058 : n(-1), container(m.d.data()), t(Map)
2059{
2060 if (container)
2061 container->ref.ref();
2062}
2063
2064/*!
2065 \fn QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2066 \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &tv)
2067
2068 Creates a QCborValue for the extended type represented by the tag value \a
2069 tag, tagging value \a tv. The tag can later be retrieved using tag() and
2070 the tagged value using taggedValue().
2071
2072 \sa isTag(), tag(), taggedValue(), QCborKnownTags
2073 */
2074QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
2075 : n(-1), container(new QCborContainerPrivate), t(Tag)
2076{
2077 container->ref.storeRelaxed(1);
2078 container->append(tag);
2079 container->append(tv);
2080 t = convertToExtendedType(container);
2081}
2082
2083/*!
2084 Copies the contents of \a other into this object.
2085 */
2086QCborValue::QCborValue(const QCborValue &other) noexcept
2087 : n(other.n), container(other.container), t(other.t)
2088{
2089 if (container)
2090 container->ref.ref();
2091}
2092
2093#if QT_CONFIG(datestring)
2094static QCborValue::Type setToExtendedDateTimeType(QCborContainerPrivate *d, QStringView text)
2095{
2096 // when called from convertToExtendedType(), *d isn't pristine
2097 d->data.resize(0);
2098 d->elements.resize(0);
2099 d->elements.reserve(2);
2100
2101 d->append(QCborTag(QCborKnownTags::DateTimeString));
2102 d->appendAsciiString(text);
2103 return text.isEmpty() ? QCborValue::Tag : QCborValue::DateTime;
2104}
2105
2106/*!
2107 Creates a QCborValue object of the date/time extended type and containing
2108 the value represented by \a dt. The value can later be retrieved using
2109 toDateTime().
2110
2111 The CBOR date/time types are extension types using tags: either a string
2112 (in ISO date format) tagged as a \l{QCborKnownTags}{DateTime} or a number
2113 (of seconds since the start of 1970, UTC) tagged as a
2114 \l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will
2115 convert \l{QCborKnownTags}{UnixTime_t} to the string-based type.
2116
2117 \sa toDateTime(), isDateTime(), taggedValue()
2118 */
2119QCborValue::QCborValue(const QDateTime &dt)
2120 : n(-1), container(new QCborContainerPrivate),
2121 t(setToExtendedDateTimeType(container, dt.toString(Qt::ISODateWithMs)))
2122{
2123 container->ref.storeRelaxed(1);
2124}
2125#endif
2126
2127#ifndef QT_BOOTSTRAPPED
2128/*!
2129 Creates a QCborValue object of the URL extended type and containing the
2130 value represented by \a url. The value can later be retrieved using toUrl().
2131
2132 The CBOR URL type is an extended type represented by a string tagged as an
2133 \l{QCborKnownTags}{Url}.
2134
2135 \sa toUrl(), isUrl(), taggedValue()
2136 */
2137QCborValue::QCborValue(const QUrl &url)
2138 : QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8())
2139{
2140 // change types
2141 t = Url;
2142 container->elements[1].type = String;
2143}
2144
2145#if QT_CONFIG(regularexpression)
2146/*!
2147 Creates a QCborValue object of the regular expression pattern extended type
2148 and containing the value represented by \a rx. The value can later be retrieved
2149 using toRegularExpression().
2150
2151 The CBOR regular expression type is an extended type represented by a
2152 string tagged as an \l{QCborKnownTags}{RegularExpression}. Note that CBOR
2153 regular expressions only store the patterns, so any flags that the
2154 QRegularExpression object may carry will be lost.
2155
2156 \sa toRegularExpression(), isRegularExpression(), taggedValue()
2157 */
2158QCborValue::QCborValue(const QRegularExpression &rx)
2159 : QCborValue(QCborKnownTags::RegularExpression, rx.pattern())
2160{
2161 // change type
2162 t = RegularExpression;
2163}
2164#endif // QT_CONFIG(regularexpression)
2165
2166/*!
2167 Creates a QCborValue object of the UUID extended type and containing the
2168 value represented by \a uuid. The value can later be retrieved using
2169 toUuid().
2170
2171 The CBOR UUID type is an extended type represented by a byte array tagged
2172 as an \l{QCborKnownTags}{Uuid}.
2173
2174 \sa toUuid(), isUuid(), taggedValue()
2175 */
2176QCborValue::QCborValue(const QUuid &uuid)
2177 : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
2178{
2179 // change our type
2180 t = Uuid;
2181}
2182#endif
2183
2184/*!
2185 \internal
2186
2187 Completes construction of a QCborValue whose Type constructor requested a
2188 tagged or extended type (see isTag_helper()). Such types keep their value in
2189 a container holding the tag and the tagged value, so a bare QCborValue(Type)
2190 would otherwise be an empty, container-less object that does not compare
2191 equal to one built from a default-constructed value (QTBUG-149398).
2192 */
2193void QCborValue::adjustDefaultConstructedExtendedType()
2194{
2195 switch (t) {
2196 case Tag:
2197 *this = QCborValue(QCborTag(-1), QCborValue());
2198 return;
2199 case DateTime:
2200 // same as:
2201 //*this = QCborValue(QDateTime());
2202 *this = QCborValue(QCborKnownTags::DateTimeString, QString());
2203 return;
2204 case Url:
2205 // same as:
2206 //*this = QCborValue(QUrl());
2207 *this = QCborValue(QCborKnownTags::Url, QString());
2208 return;
2209 case RegularExpression:
2210 // same as:
2211 //*this = QCborValue(QRegularExpression());
2212 *this = QCborValue(QCborKnownTags::RegularExpression, QString());
2213 return;
2214 case Uuid:
2215 // same as:
2216 //*this = QCborValue(QUuid());
2217 *this = QCborValue(QCborKnownTags::Uuid, QByteArray(sizeof(QUuid), '\0'));
2218 return;
2219
2220 // not extended types:
2221 case Integer:
2222 case ByteArray:
2223 case String:
2224 case Array:
2225 case Map:
2226 case SimpleType:
2227 case False:
2228 case True:
2229 case Null:
2230 case Undefined:
2231 case Double:
2232 case Invalid:
2233 Q_UNREACHABLE();
2234 }
2235}
2236
2237// destructor
2238void QCborValue::dispose()
2239{
2240 container->deref();
2241}
2242
2243/*!
2244 Replaces the contents of this QCborObject with a copy of \a other.
2245 */
2246QCborValue &QCborValue::operator=(const QCborValue &other) noexcept
2247{
2248 n = other.n;
2249 assignContainer(container, other.container);
2250 t = other.t;
2251 return *this;
2252}
2253
2254/*!
2255 Returns the tag of this extended QCborValue object, if it is of the tag
2256 type, \a defaultValue otherwise.
2257
2258 CBOR represents extended types by associating a number (the tag) with a
2259 stored representation. This function returns that number. To retrieve the
2260 representation, use taggedValue().
2261
2262 \sa isTag(), taggedValue(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2263 */
2264QCborTag QCborValue::tag(QCborTag defaultValue) const
2265{
2266 return isTag() && container && container->elements.size() == 2 ?
2267 QCborTag(container->elements.at(0).value) : defaultValue;
2268}
2269
2270/*!
2271 Returns the tagged value of this extended QCborValue object, if it is of
2272 the tag type, \a defaultValue otherwise.
2273
2274 CBOR represents extended types by associating a number (the tag) with a
2275 stored representation. This function returns that representation. To
2276 retrieve the tag, use tag().
2277
2278 \sa isTag(), tag(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
2279 */
2280QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
2281{
2282 return isTag() && container && container->elements.size() == 2 ?
2283 container->valueAt(1) : defaultValue;
2284}
2285
2286/*!
2287 Returns the byte array value stored in this QCborValue, if it is of the byte
2288 array type. Otherwise, it returns \a defaultValue.
2289
2290 Note that this function performs no conversion from other types to
2291 QByteArray.
2292
2293 \sa isByteArray(), isString(), toString()
2294 */
2295QByteArray QCborValue::toByteArray(const QByteArray &defaultValue) const
2296{
2297 if (!container || !isByteArray())
2298 return defaultValue;
2299
2300 Q_ASSERT(n >= 0);
2301 return container->byteArrayAt(n);
2302}
2303
2304/*!
2305 Returns the string value stored in this QCborValue, if it is of the string
2306 type. Otherwise, it returns \a defaultValue.
2307
2308 Note that this function performs no conversion from other types to
2309 QString.
2310
2311 \sa toStringView(), isString(), isByteArray(), toByteArray()
2312 */
2313QString QCborValue::toString(const QString &defaultValue) const
2314{
2315 if (!container || !isString())
2316 return defaultValue;
2317
2318 Q_ASSERT(n >= 0);
2319 return container->stringAt(n);
2320}
2321
2322/*!
2323 \since 6.10
2324
2325 Returns the string value stored in this QCborValue, if it is of the string
2326 type. Otherwise, it returns \a defaultValue. Since QCborValue stores
2327 strings in either US-ASCII, UTF-8 or UTF-16, the returned QAnyStringView
2328 may be in any of these encodings.
2329
2330 This function does not allocate memory. The return value is valid until the
2331 next call to a non-const member function on this object. If this object goes
2332 out of scope, the return value is valid until the next call to a non-const
2333 member function on the parent CBOR object (map or array).
2334
2335 Note that this function performs no conversion from other types to
2336 QString.
2337
2338 \sa toString(), isString(), isByteArray(), toByteArray()
2339*/
2340QAnyStringView QCborValue::toStringView(QAnyStringView defaultValue) const
2341{
2342 if (!container || !isString())
2343 return defaultValue;
2344
2345 Q_ASSERT(n >= 0);
2346 return container->anyStringViewAt(n);
2347}
2348
2349#if QT_CONFIG(datestring)
2350/*!
2351 Returns the date/time value stored in this QCborValue, if it is of the
2352 date/time extended type. Otherwise, it returns \a defaultValue.
2353
2354 Note that this function performs no conversion from other types to
2355 QDateTime.
2356
2357 \sa isDateTime(), isTag(), taggedValue()
2358 */
2359QDateTime QCborValue::toDateTime(const QDateTime &defaultValue) const
2360{
2361 if (!container || !isDateTime() || container->elements.size() != 2)
2362 return defaultValue;
2363
2364 Q_ASSERT(n == -1);
2365 const ByteData *byteData = container->byteData(1);
2366 if (!byteData)
2367 return defaultValue; // date/times are never empty, so this must be invalid
2368
2369 // Our data must be US-ASCII.
2370 Q_ASSERT((container->elements.at(1).flags & Element::StringIsUtf16) == 0);
2371 return QDateTime::fromString(byteData->asLatin1(), Qt::ISODateWithMs);
2372}
2373#endif
2374
2375#ifndef QT_BOOTSTRAPPED
2376/*!
2377 Returns the URL value stored in this QCborValue, if it is of the URL
2378 extended type. Otherwise, it returns \a defaultValue.
2379
2380 Note that this function performs no conversion from other types to QUrl.
2381
2382 \sa isUrl(), isTag(), taggedValue()
2383 */
2384QUrl QCborValue::toUrl(const QUrl &defaultValue) const
2385{
2386 if (!container || !isUrl() || container->elements.size() != 2)
2387 return defaultValue;
2388
2389 Q_ASSERT(n == -1);
2390 const ByteData *byteData = container->byteData(1);
2391 if (!byteData)
2392 return QUrl(); // valid, empty URL
2393
2394 return QUrl::fromEncoded(byteData->asByteArrayView());
2395}
2396
2397#if QT_CONFIG(regularexpression)
2398/*!
2399 Returns the regular expression value stored in this QCborValue, if it is of
2400 the regular expression pattern extended type. Otherwise, it returns \a
2401 defaultValue.
2402
2403 Note that this function performs no conversion from other types to
2404 QRegularExpression.
2405
2406 \sa isRegularExpression(), isTag(), taggedValue()
2407 */
2408QRegularExpression QCborValue::toRegularExpression(const QRegularExpression &defaultValue) const
2409{
2410 if (!container || !isRegularExpression() || container->elements.size() != 2)
2411 return defaultValue;
2412
2413 Q_ASSERT(n == -1);
2414 return QRegularExpression(container->stringAt(1));
2415}
2416#endif // QT_CONFIG(regularexpression)
2417
2418/*!
2419 Returns the UUID value stored in this QCborValue, if it is of the UUID
2420 extended type. Otherwise, it returns \a defaultValue.
2421
2422 Note that this function performs no conversion from other types to QUuid.
2423
2424 \sa isUuid(), isTag(), taggedValue()
2425 */
2426QUuid QCborValue::toUuid(const QUuid &defaultValue) const
2427{
2428 if (!container || !isUuid() || container->elements.size() != 2)
2429 return defaultValue;
2430
2431 Q_ASSERT(n == -1);
2432 const ByteData *byteData = container->byteData(1);
2433 if (!byteData)
2434 return defaultValue; // UUIDs must always be 16 bytes, so this must be invalid
2435
2436 return QUuid::fromRfc4122(byteData->asByteArrayView());
2437}
2438#endif
2439
2440/*!
2441 \fn QCborArray QCborValue::toArray() const
2442 \fn QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
2443
2444 Returns the array value stored in this QCborValue, if it is of the array
2445 type. Otherwise, it returns \a defaultValue.
2446
2447 Note that this function performs no conversion from other types to
2448 QCborArray.
2449
2450 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2451 */
2452
2453/*!
2454 \fn QCborArray QCborValueRef::toArray() const
2455 \fn QCborArray QCborValueRef::toArray(const QCborArray &defaultValue) const
2456 \internal
2457
2458 Returns the array value stored in this QCborValue, if it is of the array
2459 type. Otherwise, it returns \a defaultValue.
2460
2461 Note that this function performs no conversion from other types to
2462 QCborArray.
2463
2464 \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
2465 */
2466QCborArray QCborValue::toArray() const
2467{
2468 return toArray(QCborArray());
2469}
2470
2471QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
2472{
2473 if (!isArray())
2474 return defaultValue;
2475 QCborContainerPrivate *dd = nullptr;
2476 Q_ASSERT(n == -1 || container == nullptr);
2477 if (n < 0)
2478 dd = container;
2479 // return QCborArray(*dd); but that's UB if dd is nullptr
2480 return dd ? QCborArray(*dd) : QCborArray();
2481}
2482
2483/*!
2484 \fn QCborMap QCborValue::toMap() const
2485 \fn QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2486
2487 Returns the map value stored in this QCborValue, if it is of the map type.
2488 Otherwise, it returns \a defaultValue.
2489
2490 Note that this function performs no conversion from other types to
2491 QCborMap.
2492
2493 \sa isMap(), isArray(), isContainer(), toArray()
2494 */
2495
2496/*!
2497 \fn QCborMap QCborValueRef::toMap() const
2498 \fn QCborMap QCborValueRef::toMap(const QCborMap &defaultValue) const
2499 \internal
2500
2501 Returns the map value stored in this QCborValue, if it is of the map type.
2502 Otherwise, it returns \a defaultValue.
2503
2504 Note that this function performs no conversion from other types to
2505 QCborMap.
2506
2507 \sa isMap(), isArray(), isContainer(), toArray()
2508 */
2509QCborMap QCborValue::toMap() const
2510{
2511 return toMap(QCborMap());
2512}
2513
2514QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
2515{
2516 if (!isMap())
2517 return defaultValue;
2518 QCborContainerPrivate *dd = nullptr;
2519 Q_ASSERT(n == -1 || container == nullptr);
2520 if (n < 0)
2521 dd = container;
2522 // return QCborMap(*dd); but that's UB if dd is nullptr
2523 return dd ? QCborMap(*dd) : QCborMap();
2524}
2525
2526/*!
2527 If this QCborValue is a QCborMap, searches elements for the value whose key
2528 matches \a key. If there's no key matching \a key in the map or if this
2529 QCborValue object is not a map, returns the undefined value.
2530
2531 This function is equivalent to:
2532
2533 \snippet code/src_corelib_serialization_qcborvalue.cpp 4
2534
2535 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2536 QCborMap::find()
2537 */
2538const QCborValue QCborValue::operator[](const QString &key) const
2539{
2540 return QCborContainerPrivate::findCborMapKey(*this, qToStringViewIgnoringNull(key));
2541}
2542
2543/*!
2544 \overload
2545
2546 If this QCborValue is a QCborMap, searches elements for the value whose key
2547 matches \a key. If there's no key matching \a key in the map or if this
2548 QCborValue object is not a map, returns the undefined value.
2549
2550 This function is equivalent to:
2551
2552 \snippet code/src_corelib_serialization_qcborvalue.cpp 5
2553
2554 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2555 QCborMap::find()
2556 */
2557const QCborValue QCborValue::operator[](QLatin1StringView key) const
2558{
2559 return QCborContainerPrivate::findCborMapKey(*this, key);
2560}
2561
2562/*!
2563 \overload
2564
2565 If this QCborValue is a QCborMap, searches elements for the value whose key
2566 matches \a key. If this is a QCborArray, returns the element whose index is
2567 \a key. If there's no matching value in the array or map, or if this
2568 QCborValue object is not an array or map, returns the undefined value.
2569
2570 \sa operator[], QCborMap::operator[], QCborMap::value(),
2571 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2572 */
2573const QCborValue QCborValue::operator[](qint64 key) const
2574{
2575 if (isArray() && container && quint64(key) < quint64(container->elements.size()))
2576 return container->valueAt(key);
2577 return QCborContainerPrivate::findCborMapKey(*this, key);
2578}
2579
2580static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
2581{
2582 constexpr qint64 LargeKey = 0x10000;
2583 if (t != QCborValue::Array)
2584 return false;
2585 if (key < 0)
2586 return false; // negative keys can't be an array index
2587 if (key < LargeKey)
2588 return true;
2589
2590 // Only convert to map if key is greater than array size + 1
2591 qsizetype currentSize = container ? container->elements.size() : 0;
2592 return key <= currentSize;
2593}
2594
2595/*!
2596 \internal
2597 */
2599{
2600 if (Q_LIKELY(!array || array->elements.isEmpty()))
2601 return;
2602
2603 // The Q_LIKELY and the qWarning mark the rest of this function as unlikely
2604 qWarning("Using CBOR array as map forced conversion");
2605
2606 qsizetype size = array->elements.size();
2607 QCborContainerPrivate *map = QCborContainerPrivate::detach(array, size * 2);
2608 map->elements.resize(size * 2);
2609
2610 // this may be an in-place copy, so we have to do it from the end
2611 auto dst = map->elements.begin();
2612 auto src = array->elements.constBegin();
2613 for (qsizetype i = size - 1; i >= 0; --i) {
2614 Q_ASSERT(src->type != QCborValue::Invalid);
2615 dst[i * 2 + 1] = src[i];
2616 }
2617 for (qsizetype i = 0; i < size; ++i)
2618 dst[i * 2] = { i, QCborValue::Integer };
2619
2620 // update reference counts
2621 assignContainer(array, map);
2622}
2623
2624/*!
2625 \internal
2626 */
2627static QCborContainerPrivate *maybeGrow(QCborContainerPrivate *container, qsizetype index)
2628{
2629 auto replace = QCborContainerPrivate::grow(container, index);
2630 Q_ASSERT(replace);
2631 if (replace->elements.size() == index)
2632 replace->append(Undefined());
2633 else
2634 Q_ASSERT(replace->elements.size() > index);
2635 return assignContainer(container, replace);
2636}
2637
2638template <typename KeyType> inline QCborValueRef
2639QCborContainerPrivate::findOrAddMapKey(QCborValue &self, KeyType key)
2640{
2641 // we need a map, so convert if necessary
2642 if (self.isArray())
2643 convertArrayToMap(self.container);
2644 else if (!self.isMap())
2645 self = QCborValue(QCborValue::Map);
2646 self.t = QCborValue::Map;
2647 self.n = -1;
2648
2649 QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
2650 assignContainer(self.container, result.d);
2651 return result;
2652}
2653
2654template<typename KeyType> QCborValueRef
2655QCborContainerPrivate::findOrAddMapKey(QCborValueRef self, KeyType key)
2656{
2657 auto &e = self.d->elements[self.i];
2658
2659 // we need a map, so convert if necessary
2660 if (e.type == QCborValue::Array) {
2661 convertArrayToMap(e.container);
2662 } else if (e.type != QCborValue::Map) {
2663 if (e.flags & QtCbor::Element::IsContainer)
2664 e.container->deref();
2665 e.container = nullptr;
2666 }
2668 e.type = QCborValue::Map;
2669
2670 QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
2671 assignContainer(e.container, result.d);
2672 return result;
2673}
2674
2675/*!
2676 Returns a QCborValueRef that can be used to read or modify the entry in
2677 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2678 this function is equivalent to the matching operator[] on that map.
2679
2680 Before returning the reference: if this QCborValue was an array, it is first
2681 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2682 with valid \c{array[i]}); otherwise, if it was not a map it will be
2683 over-written with an empty map.
2684
2685 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2686 QCborMap::find()
2687 */
2688QCborValueRef QCborValue::operator[](const QString &key)
2689{
2690 return QCborContainerPrivate::findOrAddMapKey(*this, qToStringViewIgnoringNull(key));
2691}
2692
2693/*!
2694 \overload
2695
2696 Returns a QCborValueRef that can be used to read or modify the entry in
2697 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
2698 this function is equivalent to the matching operator[] on that map.
2699
2700 Before returning the reference: if this QCborValue was an array, it is first
2701 converted to a map (so that \c{map[i]} is \c{array[i]} for each index, \c i,
2702 with valid \c{array[i]}); otherwise, if it was not a map it will be
2703 over-written with an empty map.
2704
2705 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
2706 QCborMap::find()
2707 */
2708QCborValueRef QCborValue::operator[](QLatin1StringView key)
2709{
2710 return QCborContainerPrivate::findOrAddMapKey(*this, key);
2711}
2712
2713/*!
2714 \overload
2715
2716 Returns a QCborValueRef that can be used to read or modify the entry in
2717 this, as a map or array, with the given \a key. When this QCborValue is a
2718 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
2719 equivalent to the matching operator[] on that map or array.
2720
2721 Before returning the reference: if this QCborValue was an array but the key
2722 is out of range, the array is first converted to a map (so that \c{map[i]}
2723 is \c{array[i]} for each index, \c i, with valid \c{array[i]}); otherwise,
2724 if it was not a map it will be over-written with an empty map.
2725
2726 \sa operator[], QCborMap::operator[], QCborMap::value(),
2727 QCborMap::find(), QCborArray::operator[], QCborArray::at()
2728 */
2729QCborValueRef QCborValue::operator[](qint64 key)
2730{
2731 if (shouldArrayRemainArray(key, t, container)) {
2732 container = maybeGrow(container, key);
2733 return { container, qsizetype(key) };
2734 }
2735 return QCborContainerPrivate::findOrAddMapKey(*this, key);
2736}
2737
2738#if QT_CONFIG(cborstreamreader)
2739/*!
2740 Decodes one item from the CBOR stream found in \a reader and returns the
2741 equivalent representation. This function is recursive: if the item is a map
2742 or array, it will decode all items found in that map or array, until the
2743 outermost object is finished.
2744
2745 This function need not be used on the root element of a \l
2746 QCborStreamReader. For example, the following code illustrates how to skip
2747 the CBOR signature tag from the beginning of a file:
2748
2749 \snippet code/src_corelib_serialization_qcborvalue.cpp 6
2750
2751 The returned value may be partially complete and indistinguishable from a
2752 valid QCborValue even if the decoding failed. To determine if there was an
2753 error, check if \l{QCborStreamReader::lastError()}{reader.lastError()} is
2754 indicating an error condition. This function stops decoding immediately
2755 after the first error.
2756
2757 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2758 */
2759QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
2760{
2761 QCborValue result;
2762 auto t = reader.type();
2763 if (reader.lastError() != QCborError::NoError)
2764 t = QCborStreamReader::Invalid;
2765
2766 switch (t) {
2767 // basic types, no container needed:
2768 case QCborStreamReader::UnsignedInteger:
2769 case QCborStreamReader::NegativeInteger:
2770 case QCborStreamReader::SimpleType:
2771 case QCborStreamReader::Float16:
2772 case QCborStreamReader::Float:
2773 case QCborStreamReader::Double: {
2774 Element e = decodeBasicValueFromCbor(reader);
2775 result.n = e.value;
2776 result.t = e.type;
2777 break;
2778 }
2779
2780 case QCborStreamReader::Invalid:
2781 result.t = QCborValue::Invalid;
2782 break; // probably a decode error
2783
2784 // strings
2785 case QCborStreamReader::ByteArray:
2786 case QCborStreamReader::String:
2787 result.n = 0;
2788 result.t = reader.isString() ? String : ByteArray;
2789 result.container = new QCborContainerPrivate;
2790 result.container->ref.ref();
2791 result.container->decodeStringFromCbor(reader);
2792 break;
2793
2794 // containers
2795 case QCborStreamReader::Array:
2796 case QCborStreamReader::Map:
2797 result.n = -1;
2798 result.t = reader.isArray() ? Array : Map;
2799 result.container = createContainerFromCbor(reader, MaximumRecursionDepth);
2800 break;
2801
2802 // tag
2803 case QCborStreamReader::Tag:
2804 result = taggedValueFromCbor(reader, MaximumRecursionDepth);
2805 break;
2806 }
2807
2808 return result;
2809}
2810
2811/*!
2812 \overload
2813
2814 Decodes one item from the CBOR stream found in the byte array \a ba and
2815 returns the equivalent representation. This function is recursive: if the
2816 item is a map or array, it will decode all items found in that map or
2817 array, until the outermost object is finished.
2818
2819 This function stores the error state, if any, in the object pointed to by
2820 \a error, along with the offset of where the error occurred. If no error
2821 happened, it stores \l{QCborError}{NoError} in the error state and the
2822 number of bytes that it consumed (that is, it stores the offset for the
2823 first unused byte). Using that information makes it possible to parse
2824 further data that may exist in the same byte array.
2825
2826 The returned value may be partially complete and indistinguishable from a
2827 valid QCborValue even if the decoding failed. To determine if there was an
2828 error, check if there was an error stored in \a error. This function stops
2829 decoding immediately after the first error.
2830
2831 \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
2832 */
2833QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
2834{
2835 QCborStreamReader reader(ba);
2836 QCborValue result = fromCbor(reader);
2837 if (error) {
2838 error->error = reader.lastError();
2839 error->offset = reader.currentOffset();
2840 }
2841 return result;
2842}
2843
2844/*!
2845 \fn QCborValue QCborValue::fromCbor(const char *data, qsizetype len, QCborParserError *error)
2846 \fn QCborValue QCborValue::fromCbor(const quint8 *data, qsizetype len, QCborParserError *error)
2847 \overload
2848
2849 Converts \a len bytes of \a data to a QByteArray and then calls the
2850 overload of this function that accepts a QByteArray, also passing \a error,
2851 if provided.
2852*/
2853#endif // QT_CONFIG(cborstreamreader)
2854
2855#if QT_CONFIG(cborstreamwriter) && !defined(QT_BOOTSTRAPPED)
2856/*!
2857 Encodes this QCborValue object to its CBOR representation, using the
2858 options specified in \a opt, and return the byte array containing that
2859 representation.
2860
2861 This function will not fail, except if this QCborValue or any of the
2862 contained items, if this is a map or array, are invalid. Invalid types are
2863 not produced normally by the API, but can result from decoding errors.
2864
2865 By default, this function performs no transformation on the values in the
2866 QCborValue, writing all floating point directly as double-precision (\c
2867 double) types. If the \l{EncodingOption}{UseFloat} option is specified, it
2868 will use single precision (\c float) for any floating point value for which
2869 there's no loss of precision in using that representation. That includes
2870 infinities and NaN values.
2871
2872 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2873 will try to use half-precision (\c qfloat16) floating point if the
2874 conversion to that results in no loss of precision. This is always true for
2875 infinities and NaN.
2876
2877 If \l{EncodingOption}{UseIntegers} is specified, it will use integers for
2878 any floating point value that contains an actual integer.
2879
2880 \sa fromCbor(), fromVariant(), fromJsonValue()
2881 */
2882QByteArray QCborValue::toCbor(EncodingOptions opt) const
2883{
2884 QByteArray result;
2885 QCborStreamWriter writer(&result);
2886 toCbor(writer, opt);
2887 return result;
2888}
2889
2890/*!
2891 \overload
2892
2893 Encodes this QCborValue object to its CBOR representation, using the
2894 options specified in \a opt, to the writer specified by \a writer. The same
2895 writer can be used by multiple QCborValues, for example, in order to encode
2896 different elements in a larger array.
2897
2898 This function will not fail, except if this QCborValue or any of the
2899 contained items, if this is a map or array, are invalid. Invalid types are
2900 not produced normally by the API, but can result from decoding errors.
2901
2902 By default, this function performs no transformation on the values in the
2903 QCborValue, writing all floating point directly as double-precision
2904 (binary64) types. If the \l{EncodingOption}{UseFloat} option is
2905 specified, it will use single precision (binary32) for any floating point
2906 value for which there's no loss of precision in using that representation.
2907 That includes infinities and NaN values.
2908
2909 Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
2910 will try to use half-precision (binary16) floating point if the conversion
2911 to that results in no loss of precision. This is always true for infinities
2912 and NaN.
2913
2914 If \l{EncodingOption}{UseIntegers} is specified, it will use integers
2915 for any floating point value that contains an actual integer.
2916
2917 \sa fromCbor(), fromVariant(), fromJsonValue()
2918 */
2919Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt) const
2920{
2921 if (isContainer() || isTag())
2922 return encodeToCbor(writer, container, -type(), opt);
2923 if (container)
2924 return encodeToCbor(writer, container, n, opt);
2925
2926 // very simple types
2927 if (isSimpleType())
2928 return writer.append(toSimpleType());
2929
2930 switch (type()) {
2931 case Integer:
2932 return writer.append(n);
2933
2934 case Double:
2935 return writeDoubleToCbor(writer, fp_helper(), opt);
2936
2937 case Invalid:
2938 return;
2939
2940 case SimpleType:
2941 case False:
2942 case True:
2943 case Null:
2944 case Undefined:
2945 // handled by "if (isSimpleType())"
2946 Q_UNREACHABLE();
2947 break;
2948
2949 case ByteArray:
2950 // Byte array with no container is empty
2951 return writer.appendByteString("", 0);
2952
2953 case String:
2954 // String with no container is empty
2955 return writer.appendTextString("", 0);
2956
2957 case Array:
2958 case Map:
2959 case Tag:
2960 // handled by "if (isContainer() || isTag())"
2961 Q_UNREACHABLE();
2962 break;
2963
2964 case DateTime:
2965 case Url:
2966 case RegularExpression:
2967 case Uuid:
2968 // not possible
2969 Q_UNREACHABLE();
2970 break;
2971 }
2972}
2973
2974# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2975void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
2976{
2977 concrete().toCbor(writer, opt);
2978}
2979# endif
2980#endif // QT_CONFIG(cborstreamwriter) && !QT_BOOTSTRAPPED
2981
2982void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
2983{
2984 that.d->replaceAt(that.i, other);
2985}
2986
2987void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
2988{
2989 that.d->replaceAt(that.i, other, QCborContainerPrivate::MoveContainer);
2990}
2991
2992void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
2993{
2994 // ### optimize?
2995 that = other.concrete();
2996}
2997
2998bool QCborValueConstRef::concreteBoolean(QCborValueConstRef self, bool defaultValue) noexcept
2999{
3000 QtCbor::Element e = self.d->elements.at(self.i);
3001 if (e.type != QCborValue::False && e.type != QCborValue::True)
3002 return defaultValue;
3003 return e.type == QCborValue::True;
3004}
3005
3006double QCborValueConstRef::concreteDouble(QCborValueConstRef self, double defaultValue) noexcept
3007{
3008 QtCbor::Element e = self.d->elements.at(self.i);
3009 if (e.type == QCborValue::Integer)
3010 return e.value;
3011 if (e.type != QCborValue::Double)
3012 return defaultValue;
3013 return e.fpvalue();
3014}
3015
3016qint64 QCborValueConstRef::concreteIntegral(QCborValueConstRef self, qint64 defaultValue) noexcept
3017{
3018 QtCbor::Element e = self.d->elements.at(self.i);
3019 QCborValue::Type t = e.type;
3020 if (t == QCborValue::Double)
3021 return e.fpvalue();
3022 if (t != QCborValue::Integer)
3023 return defaultValue;
3024 return e.value;
3025}
3026
3028 const QByteArray &defaultValue)
3029{
3030 QtCbor::Element e = self.d->elements.at(self.i);
3031 if (e.type != QCborValue::ByteArray)
3032 return defaultValue;
3033 return self.d->byteArrayAt(self.i);
3034}
3035
3036QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QString &defaultValue)
3037{
3038 QtCbor::Element e = self.d->elements.at(self.i);
3039 if (e.type != QCborValue::String)
3040 return defaultValue;
3041 return self.d->stringAt(self.i);
3042}
3043
3044QAnyStringView QCborValueConstRef::concreteStringView(QCborValueConstRef self, QAnyStringView defaultValue)
3045{
3046 QtCbor::Element e = self.d->elements.at(self.i);
3047 if (e.type != QCborValue::String)
3048 return defaultValue;
3049 return self.d->anyStringViewAt(self.i);
3050}
3051
3052bool
3053QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
3054{
3055 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
3056 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3058}
3059
3060Qt::strong_ordering
3061QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
3062{
3063 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
3064 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3066 return Qt::compareThreeWay(c, 0);
3067}
3068
3069bool
3070QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
3071{
3072 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
3073 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
3074 return compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForEquality) == 0;
3075}
3076
3077Qt::strong_ordering
3078QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
3079{
3080 QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
3081 QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
3082 int c = compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForOrdering);
3083 return Qt::compareThreeWay(c, 0);
3084}
3085
3086bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
3087{
3088 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3089 if (typeOrder(QCborValue::Array, e2.type))
3090 return false;
3091 return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
3092}
3093
3094Qt::strong_ordering
3095QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
3096{
3097 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3098 int c = typeOrder(QCborValue::Array, e2.type);
3099 if (c == 0)
3100 c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
3101 return Qt::compareThreeWay(c, 0);
3102}
3103
3104bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
3105{
3106 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3107 if (typeOrder(QCborValue::Array, e2.type))
3108 return false;
3109 return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
3110}
3111
3112Qt::strong_ordering
3113QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
3114{
3115 QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
3116 int c = typeOrder(QCborValue::Map, e2.type);
3117 if (c == 0)
3118 c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
3119 return Qt::compareThreeWay(c, 0);
3120}
3121
3122QCborValue QCborValueConstRef::concrete(QCborValueConstRef self) noexcept
3123{
3124 return self.d->valueAt(self.i);
3125}
3126
3127QCborValue::Type QCborValueConstRef::concreteType(QCborValueConstRef self) noexcept
3128{
3129 return self.d->elements.at(self.i).type;
3130}
3131
3132const QCborValue QCborValueConstRef::operator[](const QString &key) const
3133{
3134 const QCborValue item = d->valueAt(i);
3135 return item[key];
3136}
3137
3138const QCborValue QCborValueConstRef::operator[](const QLatin1StringView key) const
3139{
3140 const QCborValue item = d->valueAt(i);
3141 return item[key];
3142}
3143
3144const QCborValue QCborValueConstRef::operator[](qint64 key) const
3145{
3146 const QCborValue item = d->valueAt(i);
3147 return item[key];
3148}
3149
3150#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
3151QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
3152{
3153 return self.d->valueAt(self.i);
3154}
3155
3156QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
3157{
3158 return self.d->elements.at(self.i).type;
3159}
3160
3161/*!
3162 If this QCborValueRef refers to a QCborMap, searches elements for the value
3163 whose key matches \a key. If there's no key matching \a key in the map or if
3164 this QCborValueRef object is not a map, returns the undefined value.
3165
3166 This function is equivalent to:
3167
3168 \code
3169 value.toMap().value(key);
3170 \endcode
3171
3172 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3173 QCborMap::find()
3174 */
3175const QCborValue QCborValueRef::operator[](const QString &key) const
3176{
3177 return QCborValueConstRef::operator[](key);
3178}
3179
3180/*!
3181 \overload
3182
3183 If this QCborValueRef refers to a QCborMap, searches elements for the value
3184 whose key matches \a key. If there's no key matching \a key in the map or if
3185 this QCborValueRef object is not a map, returns the undefined value.
3186
3187 This function is equivalent to:
3188
3189 \code
3190 value.toMap().value(key);
3191 \endcode
3192
3193 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3194 QCborMap::find()
3195 */
3196const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
3197{
3198 return QCborValueConstRef::operator[](key);
3199}
3200
3201/*!
3202 \overload
3203
3204 If this QCborValueRef refers to a QCborMap, searches elements for the value
3205 whose key matches \a key. If this is a QCborArray, returns the element whose
3206 index is \a key. If there's no matching value in the array or map, or if
3207 this QCborValueRef object is not an array or map, returns the undefined
3208 value.
3209
3210 \sa operator[], QCborMap::operator[], QCborMap::value(),
3211 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3212 */
3213const QCborValue QCborValueRef::operator[](qint64 key) const
3214{
3215 return QCborValueConstRef::operator[](key);
3216}
3217
3218/*!
3219 Returns a QCborValueRef that can be used to read or modify the entry in
3220 this, as a map, with the given \a key. When this QCborValueRef refers to a
3221 QCborMap, this function is equivalent to the matching operator[] on that
3222 map.
3223
3224 Before returning the reference: if the QCborValue referenced was an array,
3225 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3226 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3227 will be over-written with an empty map.
3228
3229 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3230 QCborMap::find()
3231 */
3232QCborValueRef QCborValueRef::operator[](const QString &key)
3233{
3234 return QCborContainerPrivate::findOrAddMapKey(*this, qToStringViewIgnoringNull(key));
3235}
3236
3237/*!
3238 \overload
3239
3240 Returns a QCborValueRef that can be used to read or modify the entry in
3241 this, as a map, with the given \a key. When this QCborValue is a QCborMap,
3242 this function is equivalent to the matching operator[] on that map.
3243
3244 Before returning the reference: if the QCborValue referenced was an array,
3245 it is first converted to a map (so that \c{map[i]} is \c{array[i]} for each
3246 index, \c i, with valid \c{array[i]}); otherwise, if it was not a map it
3247 will be over-written with an empty map.
3248
3249 \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
3250 QCborMap::find()
3251 */
3252QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
3253{
3254 return QCborContainerPrivate::findOrAddMapKey(*this, key);
3255}
3256
3257/*!
3258 \overload
3259
3260 Returns a QCborValueRef that can be used to read or modify the entry in
3261 this, as a map or array, with the given \a key. When this QCborValue is a
3262 QCborMap or, for 0 <= key < 0x10000, a QCborArray, this function is
3263 equivalent to the matching operator[] on that map or array.
3264
3265 Before returning the reference: if the QCborValue referenced was an array
3266 but the key is out of range, the array is first converted to a map (so that
3267 \c{map[i]} is \c{array[i]} for each index, \c i, with valid \c{array[i]});
3268 otherwise, if it was not a map it will be over-written with an empty map.
3269
3270 \sa operator[], QCborMap::operator[], QCborMap::value(),
3271 QCborMap::find(), QCborArray::operator[], QCborArray::at()
3272 */
3273QCborValueRef QCborValueRef::operator[](qint64 key)
3274{
3275 auto &e = d->elements[i];
3276 if (shouldArrayRemainArray(key, e.type, e.container)) {
3277 e.container = maybeGrow(e.container, key);
3278 e.flags |= QtCbor::Element::IsContainer;
3279 return { e.container, qsizetype(key) };
3280 }
3281 return QCborContainerPrivate::findOrAddMapKey(*this, key);
3282}
3283#endif // < Qt 7
3284
3285inline QCborArray::QCborArray(QCborContainerPrivate &dd) noexcept
3286 : d(&dd)
3287{
3288}
3289
3290inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept
3291 : d(&dd)
3292{
3293}
3294
3295size_t qHash(const QCborValue &value, size_t seed)
3296{
3297 switch (value.type()) {
3298 case QCborValue::Integer:
3299 return qHash(value.toInteger(), seed);
3300 case QCborValue::ByteArray:
3301 return qHash(value.toByteArray(), seed);
3302 case QCborValue::String:
3303 return qHash(value.toString(), seed);
3304 case QCborValue::Array:
3305 return qHash(value.toArray(), seed);
3306 case QCborValue::Map:
3307 return qHash(value.toMap(), seed);
3308 case QCborValue::Tag:
3309 return qHashMulti(seed, value.tag(), value.taggedValue());
3310 case QCborValue::SimpleType:
3311 break;
3312 case QCborValue::False:
3313 return qHash(false, seed);
3314 case QCborValue::True:
3315 return qHash(true, seed);
3316 case QCborValue::Null:
3317 return qHash(nullptr, seed);
3318 case QCborValue::Undefined:
3319 return seed;
3320 case QCborValue::Double:
3321 return qHash(value.toDouble(), seed);
3322#if QT_CONFIG(datestring)
3323 case QCborValue::DateTime:
3324 return qHash(value.toDateTime(), seed);
3325#endif
3326#ifndef QT_BOOTSTRAPPED
3327 case QCborValue::Url:
3328 return qHash(value.toUrl(), seed);
3329# if QT_CONFIG(regularexpression)
3330 case QCborValue::RegularExpression:
3331 return qHash(value.toRegularExpression(), seed);
3332# endif
3333 case QCborValue::Uuid:
3334 return qHash(value.toUuid(), seed);
3335#endif
3336 case QCborValue::Invalid:
3337 return seed;
3338 default:
3339 break;
3340 }
3341
3342 Q_ASSERT(value.isSimpleType());
3343 return qHash(value.toSimpleType(), seed);
3344}
3345
3346Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
3347{
3348 switch (st) {
3349 case QCborSimpleType::False:
3350 return "False";
3351 case QCborSimpleType::True:
3352 return "True";
3353 case QCborSimpleType::Null:
3354 return "Null";
3355 case QCborSimpleType::Undefined:
3356 return "Undefined";
3357 }
3358 return nullptr;
3359}
3360
3361Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
3362{
3363 // Casting to QCborKnownTags's underlying type will make the comparison
3364 // below fail if the tag value is out of range.
3365 auto n = std::underlying_type<QCborKnownTags>::type(tag);
3366 if (QCborTag(n) == tag) {
3367 switch (QCborKnownTags(n)) {
3368 case QCborKnownTags::DateTimeString:
3369 return "DateTimeString";
3370 case QCborKnownTags::UnixTime_t:
3371 return "UnixTime_t";
3372 case QCborKnownTags::PositiveBignum:
3373 return "PositiveBignum";
3374 case QCborKnownTags::NegativeBignum:
3375 return "NegativeBignum";
3376 case QCborKnownTags::Decimal:
3377 return "Decimal";
3378 case QCborKnownTags::Bigfloat:
3379 return "Bigfloat";
3380 case QCborKnownTags::COSE_Encrypt0:
3381 return "COSE_Encrypt0";
3382 case QCborKnownTags::COSE_Mac0:
3383 return "COSE_Mac0";
3384 case QCborKnownTags::COSE_Sign1:
3385 return "COSE_Sign1";
3386 case QCborKnownTags::ExpectedBase64url:
3387 return "ExpectedBase64url";
3388 case QCborKnownTags::ExpectedBase64:
3389 return "ExpectedBase64";
3390 case QCborKnownTags::ExpectedBase16:
3391 return "ExpectedBase16";
3392 case QCborKnownTags::EncodedCbor:
3393 return "EncodedCbor";
3394 case QCborKnownTags::Url:
3395 return "Url";
3396 case QCborKnownTags::Base64url:
3397 return "Base64url";
3398 case QCborKnownTags::Base64:
3399 return "Base64";
3400 case QCborKnownTags::RegularExpression:
3401 return "RegularExpression";
3402 case QCborKnownTags::MimeMessage:
3403 return "MimeMessage";
3404 case QCborKnownTags::Uuid:
3405 return "Uuid";
3406 case QCborKnownTags::COSE_Encrypt:
3407 return "COSE_Encrypt";
3408 case QCborKnownTags::COSE_Mac:
3409 return "COSE_Mac";
3410 case QCborKnownTags::COSE_Sign:
3411 return "COSE_Sign";
3412 case QCborKnownTags::Signature:
3413 return "Signature";
3414 }
3415 }
3416 return nullptr;
3417}
3418
3419#if !defined(QT_NO_DEBUG_STREAM)
3420static QDebug debugContents(QDebug &dbg, const QCborValue &v)
3421{
3422 switch (v.type()) {
3423 case QCborValue::Integer:
3424 return dbg << v.toInteger();
3425 case QCborValue::ByteArray:
3426 return dbg << "QByteArray(" << v.toByteArray() << ')';
3427 case QCborValue::String:
3428 return dbg << v.toString();
3429 case QCborValue::Array:
3430 return dbg << v.toArray();
3431 case QCborValue::Map:
3432 return dbg << v.toMap();
3433 case QCborValue::Tag: {
3434 QCborTag tag = v.tag();
3435 const char *id = qt_cbor_tag_id(tag);
3436 if (id)
3437 dbg.nospace() << "QCborKnownTags::" << id << ", ";
3438 else
3439 dbg.nospace() << "QCborTag(" << quint64(tag) << "), ";
3440 return dbg << v.taggedValue();
3441 }
3442 case QCborValue::SimpleType:
3443 break;
3444 case QCborValue::True:
3445 return dbg << true;
3446 case QCborValue::False:
3447 return dbg << false;
3448 case QCborValue::Null:
3449 return dbg << "nullptr";
3450 case QCborValue::Undefined:
3451 return dbg;
3452 case QCborValue::Double: {
3453 qint64 i;
3454 if (convertDoubleTo(v.toDouble(), &i))
3455 return dbg << i << ".0";
3456 else
3457 return dbg << v.toDouble();
3458 }
3459#if QT_CONFIG(datestring)
3460 case QCborValue::DateTime:
3461 return dbg << v.toDateTime();
3462#endif
3463#ifndef QT_BOOTSTRAPPED
3464 case QCborValue::Url:
3465 return dbg << v.toUrl();
3466#if QT_CONFIG(regularexpression)
3467 case QCborValue::RegularExpression:
3468 return dbg << v.toRegularExpression();
3469#endif
3470 case QCborValue::Uuid:
3471 return dbg << v.toUuid();
3472#endif
3473 case QCborValue::Invalid:
3474 return dbg << "<invalid>";
3475 default:
3476 break;
3477 }
3478 if (v.isSimpleType())
3479 return dbg << v.toSimpleType();
3480 return dbg << "<unknown type 0x" << Qt::hex << int(v.type()) << Qt::dec << '>';
3481}
3482QDebug operator<<(QDebug dbg, const QCborValue &v)
3483{
3484 QDebugStateSaver saver(dbg);
3485 dbg.nospace() << "QCborValue(";
3486 return debugContents(dbg, v) << ')';
3487}
3488
3489QDebug operator<<(QDebug dbg, QCborSimpleType st)
3490{
3491 QDebugStateSaver saver(dbg);
3492 const char *id = qt_cbor_simpletype_id(st);
3493 if (id)
3494 return dbg.nospace() << "QCborSimpleType::" << id;
3495
3496 return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
3497}
3498
3499QDebug operator<<(QDebug dbg, QCborTag tag)
3500{
3501 QDebugStateSaver saver(dbg);
3502 const char *id = qt_cbor_tag_id(tag);
3503 dbg.nospace() << "QCborTag(";
3504 if (id)
3505 dbg.nospace() << "QCborKnownTags::" << id;
3506 else
3507 dbg.nospace() << quint64(tag);
3508
3509 return dbg << ')';
3510}
3511
3512QDebug operator<<(QDebug dbg, QCborKnownTags tag)
3513{
3514 QDebugStateSaver saver(dbg);
3515 const char *id = qt_cbor_tag_id(QCborTag(int(tag)));
3516 if (id)
3517 return dbg.nospace() << "QCborKnownTags::" << id;
3518
3519 return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
3520}
3521#endif
3522
3523#ifndef QT_NO_DATASTREAM
3524#if QT_CONFIG(cborstreamwriter)
3525QDataStream &operator<<(QDataStream &stream, const QCborValue &value)
3526{
3527 stream << QCborValue(value).toCbor();
3528 return stream;
3529}
3530#endif
3531
3532#if QT_CONFIG(cborstreamreader)
3533QDataStream &operator>>(QDataStream &stream, QCborValue &value)
3534{
3535 QByteArray buffer;
3536 stream >> buffer;
3537 QCborParserError parseError{};
3538 value = QCborValue::fromCbor(buffer, &parseError);
3539 if (parseError.error)
3540 stream.setStatus(QDataStream::ReadCorruptData);
3541 return stream;
3542}
3543#endif
3544#endif // QT_NO_DATASTREAM
3545
3546
3547QT_END_NAMESPACE
3548
3549#include "qcborarray.cpp"
3550#include "qcbormap.cpp"
3551
3552#ifndef QT_NO_QOBJECT
3553#include "moc_qcborvalue.cpp"
3554#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:464
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