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