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

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