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