Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsoncbor.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qcborvalue.h"
6#include "qcborvalue_p.h"
7
8#include "qcborarray.h"
9#include "qcbormap.h"
10
11#include "qjsonarray.h"
12#include "qjsonobject.h"
13#include "qjsondocument.h"
14#include "qjson_p.h"
15
16#include <qmap.h>
17#include <qhash.h>
18
19#include <private/qnumeric_p.h>
20#include <quuid.h>
21
23
24using namespace QtCbor;
25
27
28static QJsonValue fpToJson(double v)
29{
30 return qt_is_finite(v) ? QJsonValue(v) : QJsonValue();
31}
32
33static QString simpleTypeString(QCborValue::Type t)
34{
35 int simpleType = t - QCborValue::SimpleType;
36 if (unsigned(simpleType) < 0x100)
37 return QString::fromLatin1("simple(%1)").arg(simpleType);
38
39 // if we got here, we got an unknown type
40 qWarning("QCborValue: found unknown type 0x%x", t);
41 return QString();
42
43}
44
45static QString encodeByteArray(const QCborContainerPrivate *d, qsizetype idx, QCborTag encoding)
46{
47 const ByteData *b = d->byteData(idx);
48 if (!b)
49 return QString();
50
51 QByteArray data = QByteArray::fromRawData(b->byte(), b->len);
52 if (encoding == QCborKnownTags::ExpectedBase16)
53 data = data.toHex();
54 else if (encoding == QCborKnownTags::ExpectedBase64)
55 data = data.toBase64();
56 else
57 data = data.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
58
59 return QString::fromLatin1(data);
60}
61
62static QString makeString(const QCborContainerPrivate *d, qsizetype idx,
64
66{
67 qint64 tag = d->elements.at(0).value;
68 const Element &e = d->elements.at(1);
69
70 switch (tag) {
71 case qint64(QCborKnownTags::DateTimeString):
72 case qint64(QCborKnownTags::Url):
73 if (e.type == QCborValue::String)
74 return makeString(d, 1);
75 break;
76
77 case qint64(QCborKnownTags::ExpectedBase64url):
78 case qint64(QCborKnownTags::ExpectedBase64):
79 case qint64(QCborKnownTags::ExpectedBase16):
80 if (e.type == QCborValue::ByteArray)
81 return encodeByteArray(d, 1, QCborTag(tag));
82 break;
83
84 case qint64(QCborKnownTags::Uuid):
85#ifndef QT_BOOTSTRAPPED
86 if (const ByteData *b = d->byteData(e); e.type == QCborValue::ByteArray && b
87 && b->len == sizeof(QUuid))
88 return QUuid::fromRfc4122(b->asByteArrayView()).toString(QUuid::WithoutBraces);
89#endif
90 break;
91 }
92
93 // don't know what to do, bail out
94 return QString();
95}
96
98{
99 QString s;
100 if (!d || d->elements.size() != 2)
101 return s; // invalid (incomplete?) tag state
102
103 s = maybeEncodeTag(d);
104 if (s.isNull()) {
105 // conversion failed, ignore the tag and convert the tagged value
106 s = makeString(d, 1);
107 }
108 return s;
109}
110
111Q_NEVER_INLINE static QString makeString(const QCborContainerPrivate *d, qsizetype idx,
112 ConversionMode mode)
113{
114 const auto &e = d->elements.at(idx);
115
116 switch (e.type) {
117 case QCborValue::Integer:
118 return QString::number(qint64(e.value));
119
120 case QCborValue::Double:
121 return QString::number(e.fpvalue());
122
123 case QCborValue::ByteArray:
124 return mode == ConversionMode::FromVariantToJson
125 ? d->stringAt(idx)
126 : encodeByteArray(d, idx, QCborTag(QCborKnownTags::ExpectedBase64url));
127
128 case QCborValue::String:
129 return d->stringAt(idx);
130
131 case QCborValue::Array:
132 case QCborValue::Map:
133#if defined(QT_BOOTSTRAPPED)
134 Q_UNREACHABLE_RETURN(QString());
135#else
136 return d->valueAt(idx).toDiagnosticNotation(QCborValue::Compact);
137#endif
138
139 case QCborValue::SimpleType:
140 break;
141
142 case QCborValue::False:
143 return QStringLiteral("false");
144
145 case QCborValue::True:
146 return QStringLiteral("true");
147
148 case QCborValue::Null:
149 return QStringLiteral("null");
150
151 case QCborValue::Undefined:
152 return QStringLiteral("undefined");
153
154 case QCborValue::Invalid:
155 return QString();
156
157 case QCborValue::Tag:
158 case QCborValue::DateTime:
159 case QCborValue::Url:
160 case QCborValue::RegularExpression:
161 case QCborValue::Uuid:
162 return encodeTag(e.flags & Element::IsContainer ? e.container : nullptr);
163 }
164
165 // maybe it's a simple type
166 return simpleTypeString(e.type);
167}
168
169QJsonValue qt_convertToJson(QCborContainerPrivate *d, qsizetype idx,
171
173{
174 qint64 tag = d->elements.at(0).value;
175
176 switch (tag) {
177 case qint64(QCborKnownTags::Url):
178#ifdef QT_BOOTSTRAPPED
179 break;
180#else
181 // use the fully-encoded URL form
182 if (d->elements.at(1).type == QCborValue::String)
183 return QUrl::fromEncoded(d->byteData(1)->asByteArrayView()).toString(QUrl::FullyEncoded);
184 Q_FALLTHROUGH();
185#endif
186
187 case qint64(QCborKnownTags::DateTimeString):
188 case qint64(QCborKnownTags::ExpectedBase64url):
189 case qint64(QCborKnownTags::ExpectedBase64):
190 case qint64(QCborKnownTags::ExpectedBase16):
191 case qint64(QCborKnownTags::Uuid): {
192 // use the string conversion
193 QString s = maybeEncodeTag(d);
194 if (!s.isNull())
195 return s;
196 }
197 }
198
199 // for all other tags, ignore it and return the converted tagged item
200 return qt_convertToJson(d, 1);
201}
202
203// We need to do this because sub-objects may need conversion.
206{
207 QJsonArray a;
208 if (d) {
209 for (qsizetype idx = 0; idx < d->elements.size(); ++idx)
210 a.append(qt_convertToJson(d, idx, mode));
211 }
212 return a;
213}
214
215// We need to do this because the keys need to be sorted and converted to strings
216// and sub-objects may need recursive conversion.
219{
220 QJsonObject o;
221 if (d) {
222 for (qsizetype idx = 0; idx < d->elements.size(); idx += 2)
223 o.insert(makeString(d, idx), qt_convertToJson(d, idx + 1, mode));
224 }
225 return o;
226}
227
228QJsonValue qt_convertToJson(QCborContainerPrivate *d, qsizetype idx, ConversionMode mode)
229{
230 // encoding the container itself
231 if (idx == -QCborValue::Array)
232 return convertToJsonArray(d, mode);
233 if (idx == -QCborValue::Map)
234 return convertToJsonObject(d, mode);
235 if (idx < 0) {
236 // tag-like type
237 if (!d || d->elements.size() != 2)
238 return QJsonValue::Undefined; // invalid state
239 return convertExtendedTypeToJson(d);
240 }
241
242 // an element in the container
243 const auto &e = d->elements.at(idx);
244 switch (e.type) {
245 case QCborValue::Integer:
246 return QJsonValue(e.value);
247 case QCborValue::ByteArray:
249 const auto value = makeString(d, idx, mode);
250 return value.isEmpty() ? QJsonValue() : QJsonPrivate::Value::fromTrustedCbor(value);
251 }
252 break;
253 case QCborValue::RegularExpression:
255 return QJsonValue();
256 break;
257 case QCborValue::String:
258 case QCborValue::SimpleType:
259 // make string
260 break;
261
262 case QCborValue::Array:
263 case QCborValue::Map:
264 case QCborValue::Tag:
265 case QCborValue::DateTime:
266 case QCborValue::Url:
267 case QCborValue::Uuid:
268 // recurse
269 return qt_convertToJson(e.flags & Element::IsContainer ? e.container : nullptr, -e.type,
270 mode);
271
272 case QCborValue::Null:
273 case QCborValue::Undefined:
274 case QCborValue::Invalid:
275 return QJsonValue();
276
277 case QCborValue::False:
278 return false;
279
280 case QCborValue::True:
281 return true;
282
283 case QCborValue::Double:
284 return fpToJson(e.fpvalue());
285 }
286
287 return QJsonPrivate::Value::fromTrustedCbor(makeString(d, idx, mode));
288}
289
290/*!
291 Converts this QCborValue object to an equivalent representation in JSON and
292 returns it as a QJsonValue.
293
294 Please note that CBOR contains a richer and wider type set than JSON, so
295 some information may be lost in this conversion. The following table
296 compares CBOR types to JSON types and indicates whether information may be
297 lost or not.
298
299 \table
300 \header \li CBOR Type \li JSON Type \li Comments
301 \row \li Bool \li Bool \li No data loss possible
302 \row \li Double \li Number \li Infinities and NaN will be converted to Null;
303 no data loss for other values
304 \row \li Integer \li Number \li Data loss possible in the conversion if the
305 integer is larger than 2\sup{53} or smaller
306 than -2\sup{53}.
307 \row \li Null \li Null \li No data loss possible
308 \row \li Undefined \li Null \li Type information lost
309 \row \li String \li String \li No data loss possible
310 \row \li Byte Array \li String \li Converted to a lossless encoding like Base64url,
311 but the distinction between strings and byte
312 arrays is lost
313 \row \li Other simple types \li String \li Type information lost
314 \row \li Array \li Array \li Conversion applies to each contained value
315 \row \li Map \li Object \li Keys are converted to string; values converted
316 according to this table
317 \row \li Tags and extended types \li Special \li The tag number itself is lost and the tagged
318 value is converted to JSON
319 \endtable
320
321 For information on the conversion of CBOR map keys to string, see
322 QCborMap::toJsonObject().
323
324 If this QCborValue contains the undefined value, this function will return
325 an undefined QJsonValue too. Note that JSON does not support undefined
326 values and undefined QJsonValues are an extension to the specification.
327 They cannot be held in a QJsonArray or QJsonObject, but can be returned
328 from functions to indicate a failure. For all other intents and purposes,
329 they are the same as null.
330
331 \section3 Special handling of tags and extended types
332
333 Some tags are handled specially and change the transformation of the tagged
334 value from CBOR to JSON. The following table lists those special cases:
335
336 \table
337 \header \li Tag \li CBOR type \li Transformation
338 \row \li ExpectedBase64url \li Byte array \li Encodes the byte array as Base64url
339 \row \li ExpectedBase64 \li Byte array \li Encodes the byte array as Base64
340 \row \li ExpectedBase16 \li Byte array \li Encodes the byte array as hex
341 \row \li Url \li Url and String \li Uses QUrl::toEncoded() to normalize the
342 encoding to the URL's fully encoded format
343 \row \li Uuid \li Uuid and Byte array \li Uses QUuid::toString() to create
344 the string representation
345 \endtable
346
347 \sa fromJsonValue(), toVariant(), QCborArray::toJsonArray(), QCborMap::toJsonObject()
348 */
349QJsonValue QCborValue::toJsonValue() const
350{
351 if (container)
352 return qt_convertToJson(container, n < 0 ? -type() : n);
353
354 // simple values
355 switch (type()) {
356 case False:
357 return false;
358
359 case Integer:
360 return QJsonPrivate::Value::fromTrustedCbor(*this);
361
362 case True:
363 return true;
364
365 case Null:
366 case Undefined:
367 case Invalid:
368 return QJsonValue();
369
370 case Double:
371 return fpToJson(fp_helper());
372
373 case SimpleType:
374 break;
375
376 case ByteArray:
377 case String:
378 // empty strings
379 return QJsonValue::String;
380
381 case Array:
382 // empty array
383 return QJsonArray();
384
385 case Map:
386 // empty map
387 return QJsonObject();
388
389 case Tag:
390 case DateTime:
391 case Url:
392 case RegularExpression:
393 case Uuid:
394 // Reachable, but invalid in Json
395 return QJsonValue::Undefined;
396 }
397
398 return QJsonPrivate::Value::fromTrustedCbor(simpleTypeString(type()));
399}
400
401#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
402QJsonValue QCborValueRef::toJsonValue() const
403{
404 return qt_convertToJson(d, i);
405}
406#endif
407
408/*!
409 Recursively converts every \l QCborValue element in this array to JSON
410 using QCborValue::toJsonValue() and returns the corresponding QJsonArray
411 composed of those elements.
412
413 Please note that CBOR contains a richer and wider type set than JSON, so
414 some information may be lost in this conversion. For more details on what
415 conversions are applied, see QCborValue::toJsonValue().
416
417 \sa fromJsonArray(), QCborValue::toJsonValue(), QCborMap::toJsonObject(), toVariantList()
418 */
419QJsonArray QCborArray::toJsonArray() const
420{
421 return convertToJsonArray(d.data());
422}
423
424#ifndef QT_NO_VARIANT
426{
427 const auto cborArray = QCborArray::fromVariantList(list);
428 return convertToJsonArray(cborArray.d.data(), ConversionMode::FromVariantToJson);
429}
430#endif // !QT_NO_VARIANT
431
432/*!
433 Recursively converts every \l QCborValue value in this map to JSON using
434 QCborValue::toJsonValue() and creates a string key for all keys that aren't
435 strings, then returns the corresponding QJsonObject composed of those
436 associations.
437
438 Please note that CBOR contains a richer and wider type set than JSON, so
439 some information may be lost in this conversion. For more details on what
440 conversions are applied, see QCborValue::toJsonValue().
441
442 \section3 Map key conversion to string
443
444 JSON objects are defined as having string keys, unlike CBOR, so the
445 conversion of a QCborMap to QJsonObject will imply a step of
446 "stringification" of the key values. The conversion will use the special
447 handling of tags and extended types from above and will also convert the
448 rest of the types as follows:
449
450 \table
451 \header \li Type \li Transformation
452 \row \li Bool \li "true" and "false"
453 \row \li Null \li "null"
454 \row \li Undefined \li "undefined"
455 \row \li Integer \li The decimal string form of the number
456 \row \li Double \li The decimal string form of the number
457 \row \li Byte array \li Unless tagged differently (see above), encoded as
458 Base64url
459 \row \li Array \li Replaced by the compact form of its
460 \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
461 \row \li Map \li Replaced by the compact form of its
462 \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
463 \row \li Tags and extended types \li Tag number is dropped and the tagged value is converted
464 to string
465 \endtable
466
467 \sa fromJsonObject(), QCborValue::toJsonValue(), QCborArray::toJsonArray(), toVariantMap()
468 */
469QJsonObject QCborMap::toJsonObject() const
470{
471 return convertToJsonObject(d.data());
472}
473
474#ifndef QT_NO_VARIANT
475QJsonObject QJsonPrivate::Variant::toJsonObject(const QVariantMap &map)
476{
477 const auto cborMap = QCborMap::fromVariantMap(map);
478 return convertToJsonObject(cborMap.d.data(), ConversionMode::FromVariantToJson);
479}
480
481/*!
482 Converts this value to a native Qt type and returns the corresponding QVariant.
483
484 The following table lists the mapping performed between \l{Type}{QCborValue
485 types} and \l{QMetaType::Type}{Qt meta types}.
486
487 \table
488 \header \li CBOR Type \li Qt or C++ type \li Notes
489 \row \li Integer \li \l qint64 \li
490 \row \li Double \li \c double \li
491 \row \li Bool \li \c bool \li
492 \row \li Null \li \c std::nullptr_t \li
493 \row \li Undefined \li no type (QVariant()) \li
494 \row \li Byte array \li \l QByteArray \li
495 \row \li String \li \l QString \li
496 \row \li Array \li \l QVariantList \li Recursively converts all values
497 \row \li Map \li \l QVariantMap \li Key types are "stringified"
498 \row \li Other simple types \li \l QCborSimpleType \li
499 \row \li DateTime \li \l QDateTime \li
500 \row \li Url \li \l QUrl \li
501 \row \li RegularExpression \li \l QRegularExpression \li
502 \row \li Uuid \li \l QUuid \li
503 \row \li Other tags \li Special \li The tag is ignored and the tagged
504 value is converted using this
505 function
506 \endtable
507
508 Note that values in both CBOR Maps and Arrays are converted recursively
509 using this function too and placed in QVariantMap and QVariantList instead.
510 You will not find QCborMap and QCborArray stored inside the QVariants.
511
512 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
513 to QVariantMap will imply a step of "stringification" of the key values.
514 See QCborMap::toJsonObject() for details.
515
516 \sa fromVariant(), toJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap()
517 */
518QVariant QCborValue::toVariant() const
519{
520 switch (type()) {
521 case Integer:
522 return toInteger();
523
524 case Double:
525 return toDouble();
526
527 case SimpleType:
528 break;
529
530 case False:
531 case True:
532 return isTrue();
533
534 case Null:
535 return QVariant::fromValue(nullptr);
536
537 case Undefined:
538 return QVariant();
539
540 case ByteArray:
541 return toByteArray();
542
543 case String:
544 return toString();
545
546 case Array:
547 return toArray().toVariantList();
548
549 case Map:
550 return toMap().toVariantMap();
551
552 case Tag:
553 // ignore tags
554 return taggedValue().toVariant();
555
556#if QT_CONFIG(datestring)
557 case DateTime:
558 return toDateTime();
559#endif
560
561#ifndef QT_BOOTSTRAPPED
562 case Url:
563 return toUrl();
564
565# if QT_CONFIG(regularexpression)
566 case RegularExpression:
567 return toRegularExpression();
568# endif
569
570 case Uuid:
571 return toUuid();
572#endif
573
574 case Invalid:
575 return QVariant();
576
577 default:
578 break;
579 }
580
581 if (isSimpleType())
582 return QVariant::fromValue(toSimpleType());
583
584 Q_UNREACHABLE_RETURN(QVariant());
585}
586#endif // !QT_NO_VARIANT
587
588/*!
589 Converts the JSON value contained in \a v into its corresponding CBOR value
590 and returns it. There is no data loss in converting from JSON to CBOR, as
591 the CBOR type set is richer than JSON's. Additionally, values converted to
592 CBOR using this function can be converted back to JSON using toJsonValue()
593 with no data loss.
594
595 The following table lists the mapping of JSON types to CBOR types:
596
597 \table
598 \header \li JSON Type \li CBOR Type
599 \row \li Bool \li Bool
600 \row \li Number \li Integer (if the number has no fraction and is in the \l qint64
601 range) or Double
602 \row \li String \li String
603 \row \li Array \li Array
604 \row \li Object \li Map
605 \row \li Null \li Null
606 \endtable
607
608 \l QJsonValue can also be undefined, indicating a previous operation that
609 failed to complete (for example, searching for a key not present in an
610 object). Undefined values are not JSON types and may not appear in JSON
611 arrays and objects, but this function does return the QCborValue undefined
612 value if the corresponding QJsonValue is undefined.
613
614 \sa toJsonValue(), fromVariant(), QCborArray::fromJsonArray(), QCborMap::fromJsonObject()
615 */
616QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
617{
618 switch (v.type()) {
619 case QJsonValue::Bool:
620 return v.toBool();
621 case QJsonValue::Double: {
622 if (v.value.t == Integer)
623 return v.toInteger();
624 return v.toDouble();
625 }
626 case QJsonValue::String:
627 return v.toString();
628 case QJsonValue::Array:
629 return QCborArray::fromJsonArray(v.toArray());
630 case QJsonValue::Object:
631 return QCborMap::fromJsonObject(v.toObject());
632 case QJsonValue::Null:
633 return nullptr;
634 case QJsonValue::Undefined:
635 break;
636 }
637 return QCborValue();
638}
639
640#ifndef QT_NO_VARIANT
641static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
642{
643 // Handle strings and byte arrays directly, to avoid creating a temporary
644 // dummy container to hold their data.
645 int type = variant.metaType().id();
646 if (type == QMetaType::QString) {
647 d->append(variant.toString());
648 } else if (type == QMetaType::QByteArray) {
649 QByteArray ba = variant.toByteArray();
650 d->appendByteData(ba.constData(), ba.size(), QCborValue::ByteArray);
651 } else {
652 // For everything else, use the function below.
653 d->append(QCborValue::fromVariant(variant));
654 }
655}
656
657/*!
658 Converts the QVariant \a variant into QCborValue and returns it.
659
660 QVariants may contain a large list of different meta types, many of which
661 have no corresponding representation in CBOR. That includes all
662 user-defined meta types. When preparing transmission using CBOR, it is
663 suggested to encode carefully each value to prevent loss of representation.
664
665 The following table lists the conversion this function will apply:
666
667 \table
668 \header \li Qt (C++) type \li CBOR type
669 \row \li invalid (QVariant()) \li Undefined
670 \row \li \c bool \li Bool
671 \row \li \c std::nullptr_t \li Null
672 \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
673 \row \li \l quint64 \li Integer, or Double if outside the range of qint64
674 \row \li \c float, \c double \li Double
675 \row \li \l QByteArray \li ByteArray
676 \row \li \l QDateTime \li DateTime
677 \row \li \l QCborSimpleType \li Simple type
678 \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
679 \row \li \l QJsonDocument \li Array or Map
680 \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
681 \row \li \l QJsonValue \li converted using fromJsonValue()
682 \row \li \l QRegularExpression \li RegularExpression
683 \row \li \l QString \li String
684 \row \li \l QStringList \li Array
685 \row \li \l QVariantHash \li Map
686 \row \li \l QVariantList \li Array
687 \row \li \l QVariantMap \li Map
688 \row \li \l QUrl \li Url
689 \row \li \l QUuid \li Uuid
690 \endtable
691
692 If QVariant::isNull() returns true, a null QCborValue is returned or
693 inserted into the list or object, regardless of the type carried by
694 QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
695 also affects this function.
696
697 For other types not listed above, a conversion to string will be attempted,
698 usually but not always by calling QVariant::toString(). If the conversion
699 fails the value is replaced by an Undefined CBOR value. Note that
700 QVariant::toString() is also lossy for the majority of types.
701
702 Please note that the conversions via QVariant::toString() are subject to
703 change at any time. Both QVariant and QCborValue may be extended in the
704 future to support more types, which will result in a change in how this
705 function performs conversions.
706
707 \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap(), QJsonValue::fromVariant()
708 */
709QCborValue QCborValue::fromVariant(const QVariant &variant)
710{
711 switch (variant.metaType().id()) {
712 case QMetaType::UnknownType:
713 return {};
714 case QMetaType::Nullptr:
715 return nullptr;
716 case QMetaType::Bool:
717 return variant.toBool();
718 case QMetaType::Short:
719 case QMetaType::UShort:
720 case QMetaType::Int:
721 case QMetaType::LongLong:
722 case QMetaType::Long:
723 case QMetaType::UInt:
724 return variant.toLongLong();
725 case QMetaType::ULong:
726 case QMetaType::ULongLong:
727 if (variant.toULongLong() <= static_cast<uint64_t>(std::numeric_limits<qint64>::max()))
728 return variant.toLongLong();
729 Q_FALLTHROUGH();
730 case QMetaType::Float16:
731 case QMetaType::Float:
732 case QMetaType::Double:
733 return variant.toDouble();
734 case QMetaType::QString:
735 return variant.toString();
736 case QMetaType::QStringList:
737 return QCborArray::fromStringList(variant.toStringList());
738 case QMetaType::QByteArray:
739 return variant.toByteArray();
740#if QT_CONFIG(datestring)
741 case QMetaType::QDateTime:
742 return QCborValue(variant.toDateTime());
743#endif
744#ifndef QT_BOOTSTRAPPED
745 case QMetaType::QUrl:
746 return QCborValue(variant.toUrl());
747 case QMetaType::QUuid:
748 return QCborValue(variant.toUuid());
749#endif
750 case QMetaType::QVariantList:
751 return QCborArray::fromVariantList(variant.toList());
752 case QMetaType::QVariantMap:
753 return QCborMap::fromVariantMap(variant.toMap());
754 case QMetaType::QVariantHash:
755 return QCborMap::fromVariantHash(variant.toHash());
756#ifndef QT_BOOTSTRAPPED
757#if QT_CONFIG(regularexpression)
758 case QMetaType::QRegularExpression:
759 return QCborValue(variant.toRegularExpression());
760#endif
761 case QMetaType::QJsonValue:
762 return fromJsonValue(variant.toJsonValue());
763 case QMetaType::QJsonObject:
764 return QCborMap::fromJsonObject(variant.toJsonObject());
765 case QMetaType::QJsonArray:
766 return QCborArray::fromJsonArray(variant.toJsonArray());
767 case QMetaType::QJsonDocument: {
768 QJsonDocument doc = variant.toJsonDocument();
769 if (doc.isArray())
770 return QCborArray::fromJsonArray(doc.array());
771 return QCborMap::fromJsonObject(doc.object());
772 }
773 case QMetaType::QCborValue:
774 return qvariant_cast<QCborValue>(variant);
775 case QMetaType::QCborArray:
776 return qvariant_cast<QCborArray>(variant);
777 case QMetaType::QCborMap:
778 return qvariant_cast<QCborMap>(variant);
779 case QMetaType::QCborSimpleType:
780 return qvariant_cast<QCborSimpleType>(variant);
781#endif
782 default:
783 break;
784 }
785
786 if (variant.isNull())
787 return QCborValue(nullptr);
788
789 QString string = variant.toString();
790 if (string.isNull())
791 return QCborValue(); // undefined
792 return string;
793}
794
795/*!
796 Recursively converts each \l QCborValue in this array using
797 QCborValue::toVariant() and returns the QVariantList composed of the
798 converted items.
799
800 Conversion to \l QVariant is not completely lossless. Please see the
801 documentation in QCborValue::toVariant() for more information.
802
803 \sa fromVariantList(), fromStringList(), toJsonArray(),
804 QCborValue::toVariant(), QCborMap::toVariantMap()
805 */
806QVariantList QCborArray::toVariantList() const
807{
808 QVariantList retval;
809 retval.reserve(size());
810 for (qsizetype i = 0; i < size(); ++i)
811 retval.append(d->valueAt(i).toVariant());
812 return retval;
813}
814
815/*!
816 Returns a QCborArray containing all the strings found in the \a list list.
817
818 \sa fromVariantList(), fromJsonArray()
819 */
820QCborArray QCborArray::fromStringList(const QStringList &list)
821{
822 QCborArray a;
823 a.detach(list.size());
824 for (const QString &s : list)
825 a.d->append(s);
826 return a;
827}
828
829/*!
830 Converts all the items in the \a list to CBOR using
831 QCborValue::fromVariant() and returns the array composed of those elements.
832
833 Conversion from \l QVariant is not completely lossless. Please see the
834 documentation in QCborValue::fromVariant() for more information.
835
836 \sa toVariantList(), fromStringList(), fromJsonArray(), QCborMap::fromVariantMap()
837 */
838QCborArray QCborArray::fromVariantList(const QVariantList &list)
839{
840 QCborArray a;
841 a.detach(list.size());
842 for (const QVariant &v : list)
843 appendVariant(a.d.data(), v);
844 return a;
845}
846#endif // !QT_NO_VARIANT
847
848/*!
849 Converts all JSON items found in the \a array array to CBOR using
850 QCborValue::fromJson(), and returns the CBOR array composed of those
851 elements.
852
853 This conversion is lossless, as the CBOR type system is a superset of
854 JSON's. Moreover, the array returned by this function can be converted back
855 to the original \a array by using toJsonArray().
856
857 \sa toJsonArray(), toVariantList(), QCborValue::fromJsonValue(), QCborMap::fromJsonObject()
858 */
859QCborArray QCborArray::fromJsonArray(const QJsonArray &array)
860{
861 QCborArray result;
862 result.d = array.a;
863 return result;
864}
865
866/*!
867 \overload
868 \since 6.3
869 */
870QCborArray QCborArray::fromJsonArray(QJsonArray &&array) noexcept
871{
872 QCborArray result;
873 result.d = std::exchange(array.a, {});
874 return result;
875
876}
877
878#ifndef QT_NO_VARIANT
879/*!
880 Converts the CBOR values to QVariant using QCborValue::toVariant() and
881 "stringifies" all the CBOR keys in this map, returning the QVariantMap that
882 results from that association list.
883
884 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
885 to QVariantMap will imply a step of "stringification" of the key values.
886 See QCborMap::toJsonObject() for details.
887
888 In addition, the conversion to \l QVariant is not completely lossless.
889 Please see the documentation in QCborValue::toVariant() for more
890 information.
891
892 \sa fromVariantMap(), toVariantHash(), toJsonObject(), QCborValue::toVariant(),
893 QCborArray::toVariantList()
894 */
895QVariantMap QCborMap::toVariantMap() const
896{
897 QVariantMap retval;
898 for (qsizetype i = 0; i < 2 * size(); i += 2)
899 retval.insert(makeString(d.data(), i), d->valueAt(i + 1).toVariant());
900 return retval;
901}
902
903/*!
904 Converts the CBOR values to QVariant using QCborValue::toVariant() and
905 "stringifies" all the CBOR keys in this map, returning the QVariantHash that
906 results from that association list.
907
908 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
909 to QVariantMap will imply a step of "stringification" of the key values.
910 See QCborMap::toJsonObject() for details.
911
912 In addition, the conversion to \l QVariant is not completely lossless.
913 Please see the documentation in QCborValue::toVariant() for more
914 information.
915
916 \sa fromVariantHash(), toVariantMap(), toJsonObject(), QCborValue::toVariant(),
917 QCborArray::toVariantList()
918 */
919QVariantHash QCborMap::toVariantHash() const
920{
921 QVariantHash retval;
922 retval.reserve(size());
923 for (qsizetype i = 0; i < 2 * size(); i += 2)
924 retval.insert(makeString(d.data(), i), d->valueAt(i + 1).toVariant());
925 return retval;
926}
927
928/*!
929 Converts all the items in \a map to CBOR using QCborValue::fromVariant()
930 and returns the map composed of those elements.
931
932 Conversion from \l QVariant is not completely lossless. Please see the
933 documentation in QCborValue::fromVariant() for more information.
934
935 \sa toVariantMap(), fromVariantHash(), fromJsonObject(), QCborValue::fromVariant()
936 */
937QCborMap QCborMap::fromVariantMap(const QVariantMap &map)
938{
939 QCborMap m;
940 m.detach(map.size());
941 QCborContainerPrivate *d = m.d.data();
942
943 auto it = map.begin();
944 auto end = map.end();
945 for ( ; it != end; ++it) {
946 d->append(it.key());
947 appendVariant(d, it.value());
948 }
949 return m;
950}
951
952/*!
953 Converts all the items in \a hash to CBOR using QCborValue::fromVariant()
954 and returns the map composed of those elements.
955
956 Conversion from \l QVariant is not completely lossless. Please see the
957 documentation in QCborValue::fromVariant() for more information.
958
959 \sa toVariantHash(), fromVariantMap(), fromJsonObject(), QCborValue::fromVariant()
960 */
961QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
962{
963 QCborMap m;
964 m.detach(hash.size());
965 QCborContainerPrivate *d = m.d.data();
966
967 auto it = hash.begin();
968 auto end = hash.end();
969 for ( ; it != end; ++it) {
970 d->append(it.key());
971 appendVariant(d, it.value());
972 }
973 return m;
974}
975#endif // !QT_NO_VARIANT
976
977/*!
978 Converts all JSON items found in the \a obj object to CBOR using
979 QCborValue::fromJson(), and returns the map composed of those elements.
980
981 This conversion is lossless, as the CBOR type system is a superset of
982 JSON's. Moreover, the map returned by this function can be converted back
983 to the original \a obj by using toJsonObject().
984
985 \sa toJsonObject(), toVariantMap(), QCborValue::fromJsonValue(), QCborArray::fromJsonArray()
986 */
987QCborMap QCborMap::fromJsonObject(const QJsonObject &obj)
988{
989 QCborMap result;
990 result.d = obj.o;
991 return result;
992}
993
994/*!
995 \overload
996 \since 6.3
997 */
998QCborMap QCborMap::fromJsonObject(QJsonObject &&obj) noexcept
999{
1000 QCborMap result;
1001 result.d = std::exchange(obj.o, {});
1002 return result;
1003}
1004
1005QT_END_NAMESPACE
const QtCbor::ByteData * byteData(QtCbor::Element e) const
void append(QtCbor::Undefined)
static QJsonArray toJsonArray(const QVariantList &list)
QList< QVariant > QVariantList
Definition qjsonarray.h:16
static QString simpleTypeString(QCborValue::Type t)
Definition qjsoncbor.cpp:33
static QString makeString(const QCborContainerPrivate *d, qsizetype idx, ConversionMode mode=ConversionMode::FromRaw)
static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
QJsonValue qt_convertToJson(QCborContainerPrivate *d, qsizetype idx, ConversionMode mode=ConversionMode::FromRaw)
static QString encodeByteArray(const QCborContainerPrivate *d, qsizetype idx, QCborTag encoding)
Definition qjsoncbor.cpp:45
ConversionMode
Definition qjsoncbor.cpp:26
static QJsonArray convertToJsonArray(QCborContainerPrivate *d, ConversionMode mode=ConversionMode::FromRaw)
static QJsonValue convertExtendedTypeToJson(QCborContainerPrivate *d)
static QJsonObject convertToJsonObject(QCborContainerPrivate *d, ConversionMode mode=ConversionMode::FromRaw)
static QJsonValue fpToJson(double v)
Definition qjsoncbor.cpp:28
static QString encodeTag(const QCborContainerPrivate *d)
Definition qjsoncbor.cpp:97
static QString maybeEncodeTag(const QCborContainerPrivate *d)
Definition qjsoncbor.cpp:65