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