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

source code of qtbase/src/corelib/serialization/qcborvalue.cpp