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
4#include "qcborvalue.h"
5#include "qcborvalue_p.h"
6
7#include "qcborarray.h"
8#include "qcbormap.h"
9
10#include "qjsonarray.h"
11#include "qjsonobject.h"
12#include "qjsondocument.h"
13#include "qjson_p.h"
14
15#include <qmap.h>
16#include <qhash.h>
17
18#include <private/qnumeric_p.h>
19#include <quuid.h>
20
21QT_BEGIN_NAMESPACE
22
23using namespace QtCbor;
24
25enum class ConversionMode { FromRaw, FromVariantToJson };
26
27static QJsonValue fpToJson(double v)
28{
29 return qt_is_finite(d: v) ? QJsonValue(v) : QJsonValue();
30}
31
32static QString simpleTypeString(QCborValue::Type t)
33{
34 int simpleType = t - QCborValue::SimpleType;
35 if (unsigned(simpleType) < 0x100)
36 return QString::fromLatin1(ba: "simple(%1)").arg(a: simpleType);
37
38 // if we got here, we got an unknown type
39 qWarning(msg: "QCborValue: found unknown type 0x%x", t);
40 return QString();
41
42}
43
44static QString encodeByteArray(const QCborContainerPrivate *d, qsizetype idx, QCborTag encoding)
45{
46 const ByteData *b = d->byteData(idx);
47 if (!b)
48 return QString();
49
50 QByteArray data = QByteArray::fromRawData(data: b->byte(), size: b->len);
51 if (encoding == QCborKnownTags::ExpectedBase16)
52 data = data.toHex();
53 else if (encoding == QCborKnownTags::ExpectedBase64)
54 data = data.toBase64();
55 else
56 data = data.toBase64(options: QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
57
58 return QString::fromLatin1(str: data, size: data.size());
59}
60
61static QString makeString(const QCborContainerPrivate *d, qsizetype idx,
62 ConversionMode mode = ConversionMode::FromRaw);
63
64static QString maybeEncodeTag(const QCborContainerPrivate *d)
65{
66 qint64 tag = d->elements.at(i: 0).value;
67 const Element &e = d->elements.at(i: 1);
68
69 switch (tag) {
70 case qint64(QCborKnownTags::DateTimeString):
71 case qint64(QCborKnownTags::Url):
72 if (e.type == QCborValue::String)
73 return makeString(d, idx: 1);
74 break;
75
76 case qint64(QCborKnownTags::ExpectedBase64url):
77 case qint64(QCborKnownTags::ExpectedBase64):
78 case qint64(QCborKnownTags::ExpectedBase16):
79 if (e.type == QCborValue::ByteArray)
80 return encodeByteArray(d, idx: 1, encoding: QCborTag(tag));
81 break;
82
83 case qint64(QCborKnownTags::Uuid):
84#ifndef QT_BOOTSTRAPPED
85 if (const ByteData *b = d->byteData(e); e.type == QCborValue::ByteArray && b
86 && b->len == sizeof(QUuid))
87 return QUuid::fromRfc4122(b->asByteArrayView()).toString(mode: QUuid::WithoutBraces);
88#endif
89 break;
90 }
91
92 // don't know what to do, bail out
93 return QString();
94}
95
96static QString encodeTag(const QCborContainerPrivate *d)
97{
98 QString s;
99 if (!d || d->elements.size() != 2)
100 return s; // invalid (incomplete?) tag state
101
102 s = maybeEncodeTag(d);
103 if (s.isNull()) {
104 // conversion failed, ignore the tag and convert the tagged value
105 s = makeString(d, idx: 1);
106 }
107 return s;
108}
109
110static Q_NEVER_INLINE QString makeString(const QCborContainerPrivate *d, qsizetype idx,
111 ConversionMode mode)
112{
113 const auto &e = d->elements.at(i: idx);
114
115 switch (e.type) {
116 case QCborValue::Integer:
117 return QString::number(qint64(e.value));
118
119 case QCborValue::Double:
120 return QString::number(e.fpvalue());
121
122 case QCborValue::ByteArray:
123 return mode == ConversionMode::FromVariantToJson
124 ? d->stringAt(idx)
125 : encodeByteArray(d, idx, encoding: QCborTag(QCborKnownTags::ExpectedBase64url));
126
127 case QCborValue::String:
128 return d->stringAt(idx);
129
130 case QCborValue::Array:
131 case QCborValue::Map:
132#if defined(QT_JSON_READONLY) || defined(QT_BOOTSTRAPPED)
133 qFatal("Writing JSON is disabled.");
134 return QString();
135#else
136 return d->valueAt(idx).toDiagnosticNotation(opts: 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(d: e.flags & Element::IsContainer ? e.container : nullptr);
163 }
164
165 // maybe it's a simple type
166 return simpleTypeString(t: e.type);
167}
168
169QJsonValue qt_convertToJson(QCborContainerPrivate *d, qsizetype idx,
170 ConversionMode mode = ConversionMode::FromRaw);
171
172static QJsonValue convertExtendedTypeToJson(QCborContainerPrivate *d)
173{
174 qint64 tag = d->elements.at(i: 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(i: 1).type == QCborValue::String)
183 return QUrl::fromEncoded(url: d->byteData(idx: 1)->asByteArrayView()).toString(options: 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, idx: 1);
201}
202
203// We need to do this because sub-objects may need conversion.
204static QJsonArray convertToJsonArray(QCborContainerPrivate *d,
205 ConversionMode mode = ConversionMode::FromRaw)
206{
207 QJsonArray a;
208 if (d) {
209 for (qsizetype idx = 0; idx < d->elements.size(); ++idx)
210 a.append(value: 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.
217static QJsonObject convertToJsonObject(QCborContainerPrivate *d,
218 ConversionMode mode = ConversionMode::FromRaw)
219{
220 QJsonObject o;
221 if (d) {
222 for (qsizetype idx = 0; idx < d->elements.size(); idx += 2)
223 o.insert(key: makeString(d, idx), value: qt_convertToJson(d, idx: 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(i: idx);
244 switch (e.type) {
245 case QCborValue::Integer:
246 return QJsonValue(e.value);
247 case QCborValue::ByteArray:
248 if (mode == ConversionMode::FromVariantToJson) {
249 const auto value = makeString(d, idx, mode);
250 return value.isEmpty() ? QJsonValue() : QJsonPrivate::Value::fromTrustedCbor(v: value);
251 }
252 break;
253 case QCborValue::RegularExpression:
254 if (mode == ConversionMode::FromVariantToJson)
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(d: e.flags & Element::IsContainer ? e.container : nullptr, idx: -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(v: e.fpvalue());
285 }
286
287 return QJsonPrivate::Value::fromTrustedCbor(v: 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(d: container, idx: 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(v: *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(v: 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(v: simpleTypeString(t: 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, idx: 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: d.data());
422}
423
424QJsonArray QJsonPrivate::Variant::toJsonArray(const QVariantList &list)
425{
426 const auto cborArray = QCborArray::fromVariantList(list);
427 return convertToJsonArray(d: cborArray.d.data(), mode: ConversionMode::FromVariantToJson);
428}
429
430/*!
431 Recursively converts every \l QCborValue value in this map to JSON using
432 QCborValue::toJsonValue() and creates a string key for all keys that aren't
433 strings, then returns the corresponding QJsonObject composed of those
434 associations.
435
436 Please note that CBOR contains a richer and wider type set than JSON, so
437 some information may be lost in this conversion. For more details on what
438 conversions are applied, see QCborValue::toJsonValue().
439
440 \section3 Map key conversion to string
441
442 JSON objects are defined as having string keys, unlike CBOR, so the
443 conversion of a QCborMap to QJsonObject will imply a step of
444 "stringification" of the key values. The conversion will use the special
445 handling of tags and extended types from above and will also convert the
446 rest of the types as follows:
447
448 \table
449 \header \li Type \li Transformation
450 \row \li Bool \li "true" and "false"
451 \row \li Null \li "null"
452 \row \li Undefined \li "undefined"
453 \row \li Integer \li The decimal string form of the number
454 \row \li Double \li The decimal string form of the number
455 \row \li Byte array \li Unless tagged differently (see above), encoded as
456 Base64url
457 \row \li Array \li Replaced by the compact form of its
458 \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
459 \row \li Map \li Replaced by the compact form of its
460 \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
461 \row \li Tags and extended types \li Tag number is dropped and the tagged value is converted
462 to string
463 \endtable
464
465 \sa fromJsonObject(), QCborValue::toJsonValue(), QCborArray::toJsonArray(), toVariantMap()
466 */
467QJsonObject QCborMap::toJsonObject() const
468{
469 return convertToJsonObject(d: d.data());
470}
471
472QJsonObject QJsonPrivate::Variant::toJsonObject(const QVariantMap &map)
473{
474 const auto cborMap = QCborMap::fromVariantMap(map);
475 return convertToJsonObject(d: cborMap.d.data(), mode: ConversionMode::FromVariantToJson);
476}
477
478/*!
479 Converts this value to a native Qt type and returns the corresponding QVariant.
480
481 The following table lists the mapping performed between \l{Type}{QCborValue
482 types} and \l{QMetaType::Type}{Qt meta types}.
483
484 \table
485 \header \li CBOR Type \li Qt or C++ type \li Notes
486 \row \li Integer \li \l qint64 \li
487 \row \li Double \li \c double \li
488 \row \li Bool \li \c bool \li
489 \row \li Null \li \c std::nullptr_t \li
490 \row \li Undefined \li no type (QVariant()) \li
491 \row \li Byte array \li \l QByteArray \li
492 \row \li String \li \l QString \li
493 \row \li Array \li \l QVariantList \li Recursively converts all values
494 \row \li Map \li \l QVariantMap \li Key types are "stringified"
495 \row \li Other simple types \li \l QCborSimpleType \li
496 \row \li DateTime \li \l QDateTime \li
497 \row \li Url \li \l QUrl \li
498 \row \li RegularExpression \li \l QRegularExpression \li
499 \row \li Uuid \li \l QUuid \li
500 \row \li Other tags \li Special \li The tag is ignored and the tagged
501 value is converted using this
502 function
503 \endtable
504
505 Note that values in both CBOR Maps and Arrays are converted recursively
506 using this function too and placed in QVariantMap and QVariantList instead.
507 You will not find QCborMap and QCborArray stored inside the QVariants.
508
509 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
510 to QVariantMap will imply a step of "stringification" of the key values.
511 See QCborMap::toJsonObject() for details.
512
513 \sa fromVariant(), toJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap()
514 */
515QVariant QCborValue::toVariant() const
516{
517 switch (type()) {
518 case Integer:
519 return toInteger();
520
521 case Double:
522 return toDouble();
523
524 case SimpleType:
525 break;
526
527 case False:
528 case True:
529 return isTrue();
530
531 case Null:
532 return QVariant::fromValue(value: nullptr);
533
534 case Undefined:
535 return QVariant();
536
537 case ByteArray:
538 return toByteArray();
539
540 case String:
541 return toString();
542
543 case Array:
544 return toArray().toVariantList();
545
546 case Map:
547 return toMap().toVariantMap();
548
549 case Tag:
550 // ignore tags
551 return taggedValue().toVariant();
552
553 case DateTime:
554 return toDateTime();
555
556#ifndef QT_BOOTSTRAPPED
557 case Url:
558 return toUrl();
559
560# if QT_CONFIG(regularexpression)
561 case RegularExpression:
562 return toRegularExpression();
563# endif
564
565 case Uuid:
566 return toUuid();
567#endif
568
569 case Invalid:
570 return QVariant();
571
572 default:
573 break;
574 }
575
576 if (isSimpleType())
577 return QVariant::fromValue(value: toSimpleType());
578
579 Q_UNREACHABLE_RETURN(QVariant());
580}
581
582/*!
583 Converts the JSON value contained in \a v into its corresponding CBOR value
584 and returns it. There is no data loss in converting from JSON to CBOR, as
585 the CBOR type set is richer than JSON's. Additionally, values converted to
586 CBOR using this function can be converted back to JSON using toJsonValue()
587 with no data loss.
588
589 The following table lists the mapping of JSON types to CBOR types:
590
591 \table
592 \header \li JSON Type \li CBOR Type
593 \row \li Bool \li Bool
594 \row \li Number \li Integer (if the number has no fraction and is in the \l qint64
595 range) or Double
596 \row \li String \li String
597 \row \li Array \li Array
598 \row \li Object \li Map
599 \row \li Null \li Null
600 \endtable
601
602 \l QJsonValue can also be undefined, indicating a previous operation that
603 failed to complete (for example, searching for a key not present in an
604 object). Undefined values are not JSON types and may not appear in JSON
605 arrays and objects, but this function does return the QCborValue undefined
606 value if the corresponding QJsonValue is undefined.
607
608 \sa toJsonValue(), fromVariant(), QCborArray::fromJsonArray(), QCborMap::fromJsonObject()
609 */
610QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
611{
612 switch (v.type()) {
613 case QJsonValue::Bool:
614 return v.toBool();
615 case QJsonValue::Double: {
616 if (v.value.t == Integer)
617 return v.toInteger();
618 return v.toDouble();
619 }
620 case QJsonValue::String:
621 return v.toString();
622 case QJsonValue::Array:
623 return QCborArray::fromJsonArray(array: v.toArray());
624 case QJsonValue::Object:
625 return QCborMap::fromJsonObject(o: v.toObject());
626 case QJsonValue::Null:
627 return nullptr;
628 case QJsonValue::Undefined:
629 break;
630 }
631 return QCborValue();
632}
633
634static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
635{
636 // Handle strings and byte arrays directly, to avoid creating a temporary
637 // dummy container to hold their data.
638 int type = variant.metaType().id();
639 if (type == QMetaType::QString) {
640 d->append(s: variant.toString());
641 } else if (type == QMetaType::QByteArray) {
642 QByteArray ba = variant.toByteArray();
643 d->appendByteData(data: ba.constData(), len: ba.size(), type: QCborValue::ByteArray);
644 } else {
645 // For everything else, use the function below.
646 d->append(v: QCborValue::fromVariant(variant));
647 }
648}
649
650/*!
651 Converts the QVariant \a variant into QCborValue and returns it.
652
653 QVariants may contain a large list of different meta types, many of which
654 have no corresponding representation in CBOR. That includes all
655 user-defined meta types. When preparing transmission using CBOR, it is
656 suggested to encode carefully each value to prevent loss of representation.
657
658 The following table lists the conversion this function will apply:
659
660 \table
661 \header \li Qt (C++) type \li CBOR type
662 \row \li invalid (QVariant()) \li Undefined
663 \row \li \c bool \li Bool
664 \row \li \c std::nullptr_t \li Null
665 \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
666 \row \li \l quint64 \li Integer, or Double if outside the range of qint64
667 \row \li \c float, \c double \li Double
668 \row \li \l QByteArray \li ByteArray
669 \row \li \l QDateTime \li DateTime
670 \row \li \l QCborSimpleType \li Simple type
671 \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
672 \row \li \l QJsonDocument \li Array or Map
673 \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
674 \row \li \l QJsonValue \li converted using fromJsonValue()
675 \row \li \l QRegularExpression \li RegularExpression
676 \row \li \l QString \li String
677 \row \li \l QStringList \li Array
678 \row \li \l QVariantHash \li Map
679 \row \li \l QVariantList \li Array
680 \row \li \l QVariantMap \li Map
681 \row \li \l QUrl \li Url
682 \row \li \l QUuid \li Uuid
683 \endtable
684
685 If QVariant::isNull() returns true, a null QCborValue is returned or
686 inserted into the list or object, regardless of the type carried by
687 QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
688 also affects this function.
689
690 For other types not listed above, a conversion to string will be attempted,
691 usually but not always by calling QVariant::toString(). If the conversion
692 fails the value is replaced by an Undefined CBOR value. Note that
693 QVariant::toString() is also lossy for the majority of types.
694
695 Please note that the conversions via QVariant::toString() are subject to
696 change at any time. Both QVariant and QCborValue may be extended in the
697 future to support more types, which will result in a change in how this
698 function performs conversions.
699
700 \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap(), QJsonValue::fromVariant()
701 */
702QCborValue QCborValue::fromVariant(const QVariant &variant)
703{
704 switch (variant.metaType().id()) {
705 case QMetaType::UnknownType:
706 return {};
707 case QMetaType::Nullptr:
708 return nullptr;
709 case QMetaType::Bool:
710 return variant.toBool();
711 case QMetaType::Short:
712 case QMetaType::UShort:
713 case QMetaType::Int:
714 case QMetaType::LongLong:
715 case QMetaType::UInt:
716 return variant.toLongLong();
717 case QMetaType::ULongLong:
718 if (variant.toULongLong() <= static_cast<uint64_t>(std::numeric_limits<qint64>::max()))
719 return variant.toLongLong();
720 Q_FALLTHROUGH();
721 case QMetaType::Float:
722 case QMetaType::Double:
723 return variant.toDouble();
724 case QMetaType::QString:
725 return variant.toString();
726 case QMetaType::QStringList:
727 return QCborArray::fromStringList(list: variant.toStringList());
728 case QMetaType::QByteArray:
729 return variant.toByteArray();
730 case QMetaType::QDateTime:
731 return QCborValue(variant.toDateTime());
732#ifndef QT_BOOTSTRAPPED
733 case QMetaType::QUrl:
734 return QCborValue(variant.toUrl());
735 case QMetaType::QUuid:
736 return QCborValue(variant.toUuid());
737#endif
738 case QMetaType::QVariantList:
739 return QCborArray::fromVariantList(list: variant.toList());
740 case QMetaType::QVariantMap:
741 return QCborMap::fromVariantMap(map: variant.toMap());
742 case QMetaType::QVariantHash:
743 return QCborMap::fromVariantHash(hash: variant.toHash());
744#ifndef QT_BOOTSTRAPPED
745#if QT_CONFIG(regularexpression)
746 case QMetaType::QRegularExpression:
747 return QCborValue(variant.toRegularExpression());
748#endif
749 case QMetaType::QJsonValue:
750 return fromJsonValue(v: variant.toJsonValue());
751 case QMetaType::QJsonObject:
752 return QCborMap::fromJsonObject(o: variant.toJsonObject());
753 case QMetaType::QJsonArray:
754 return QCborArray::fromJsonArray(array: variant.toJsonArray());
755 case QMetaType::QJsonDocument: {
756 QJsonDocument doc = variant.toJsonDocument();
757 if (doc.isArray())
758 return QCborArray::fromJsonArray(array: doc.array());
759 return QCborMap::fromJsonObject(o: doc.object());
760 }
761 case QMetaType::QCborValue:
762 return qvariant_cast<QCborValue>(v: variant);
763 case QMetaType::QCborArray:
764 return qvariant_cast<QCborArray>(v: variant);
765 case QMetaType::QCborMap:
766 return qvariant_cast<QCborMap>(v: variant);
767 case QMetaType::QCborSimpleType:
768 return qvariant_cast<QCborSimpleType>(v: variant);
769#endif
770 default:
771 break;
772 }
773
774 if (variant.isNull())
775 return QCborValue(nullptr);
776
777 QString string = variant.toString();
778 if (string.isNull())
779 return QCborValue(); // undefined
780 return string;
781}
782
783/*!
784 Recursively converts each \l QCborValue in this array using
785 QCborValue::toVariant() and returns the QVariantList composed of the
786 converted items.
787
788 Conversion to \l QVariant is not completely lossless. Please see the
789 documentation in QCborValue::toVariant() for more information.
790
791 \sa fromVariantList(), fromStringList(), toJsonArray(),
792 QCborValue::toVariant(), QCborMap::toVariantMap()
793 */
794QVariantList QCborArray::toVariantList() const
795{
796 QVariantList retval;
797 retval.reserve(asize: size());
798 for (qsizetype i = 0; i < size(); ++i)
799 retval.append(t: d->valueAt(idx: i).toVariant());
800 return retval;
801}
802
803/*!
804 Returns a QCborArray containing all the strings found in the \a list list.
805
806 \sa fromVariantList(), fromJsonArray()
807 */
808QCborArray QCborArray::fromStringList(const QStringList &list)
809{
810 QCborArray a;
811 a.detach(reserve: list.size());
812 for (const QString &s : list)
813 a.d->append(s);
814 return a;
815}
816
817/*!
818 Converts all the items in the \a list to CBOR using
819 QCborValue::fromVariant() and returns the array composed of those elements.
820
821 Conversion from \l QVariant is not completely lossless. Please see the
822 documentation in QCborValue::fromVariant() for more information.
823
824 \sa toVariantList(), fromStringList(), fromJsonArray(), QCborMap::fromVariantMap()
825 */
826QCborArray QCborArray::fromVariantList(const QVariantList &list)
827{
828 QCborArray a;
829 a.detach(reserve: list.size());
830 for (const QVariant &v : list)
831 appendVariant(d: a.d.data(), variant: v);
832 return a;
833}
834
835/*!
836 Converts all JSON items found in the \a array array to CBOR using
837 QCborValue::fromJson(), and returns the CBOR array composed of those
838 elements.
839
840 This conversion is lossless, as the CBOR type system is a superset of
841 JSON's. Moreover, the array returned by this function can be converted back
842 to the original \a array by using toJsonArray().
843
844 \sa toJsonArray(), toVariantList(), QCborValue::fromJsonValue(), QCborMap::fromJsonObject()
845 */
846QCborArray QCborArray::fromJsonArray(const QJsonArray &array)
847{
848 QCborArray result;
849 result.d = array.a;
850 return result;
851}
852
853/*!
854 \overload
855 \since 6.3
856 */
857QCborArray QCborArray::fromJsonArray(QJsonArray &&array) noexcept
858{
859 QCborArray result;
860 result.d = std::exchange(obj&: array.a, new_val: {});
861 return result;
862
863}
864
865/*!
866 Converts the CBOR values to QVariant using QCborValue::toVariant() and
867 "stringifies" all the CBOR keys in this map, returning the QVariantMap that
868 results from that association list.
869
870 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
871 to QVariantMap will imply a step of "stringification" of the key values.
872 See QCborMap::toJsonObject() for details.
873
874 In addition, the conversion to \l QVariant is not completely lossless.
875 Please see the documentation in QCborValue::toVariant() for more
876 information.
877
878 \sa fromVariantMap(), toVariantHash(), toJsonObject(), QCborValue::toVariant(),
879 QCborArray::toVariantList()
880 */
881QVariantMap QCborMap::toVariantMap() const
882{
883 QVariantMap retval;
884 for (qsizetype i = 0; i < 2 * size(); i += 2)
885 retval.insert(key: makeString(d: d.data(), idx: i), value: d->valueAt(idx: i + 1).toVariant());
886 return retval;
887}
888
889/*!
890 Converts the CBOR values to QVariant using QCborValue::toVariant() and
891 "stringifies" all the CBOR keys in this map, returning the QVariantHash that
892 results from that association list.
893
894 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
895 to QVariantMap will imply a step of "stringification" of the key values.
896 See QCborMap::toJsonObject() for details.
897
898 In addition, the conversion to \l QVariant is not completely lossless.
899 Please see the documentation in QCborValue::toVariant() for more
900 information.
901
902 \sa fromVariantHash(), toVariantMap(), toJsonObject(), QCborValue::toVariant(),
903 QCborArray::toVariantList()
904 */
905QVariantHash QCborMap::toVariantHash() const
906{
907 QVariantHash retval;
908 retval.reserve(size: size());
909 for (qsizetype i = 0; i < 2 * size(); i += 2)
910 retval.insert(key: makeString(d: d.data(), idx: i), value: d->valueAt(idx: i + 1).toVariant());
911 return retval;
912}
913
914/*!
915 Converts all the items in \a map to CBOR using QCborValue::fromVariant()
916 and returns the map composed of those elements.
917
918 Conversion from \l QVariant is not completely lossless. Please see the
919 documentation in QCborValue::fromVariant() for more information.
920
921 \sa toVariantMap(), fromVariantHash(), fromJsonObject(), QCborValue::fromVariant()
922 */
923QCborMap QCborMap::fromVariantMap(const QVariantMap &map)
924{
925 QCborMap m;
926 m.detach(reserve: map.size());
927 QCborContainerPrivate *d = m.d.data();
928
929 auto it = map.begin();
930 auto end = map.end();
931 for ( ; it != end; ++it) {
932 d->append(s: it.key());
933 appendVariant(d, variant: it.value());
934 }
935 return m;
936}
937
938/*!
939 Converts all the items in \a hash to CBOR using QCborValue::fromVariant()
940 and returns the map composed of those elements.
941
942 Conversion from \l QVariant is not completely lossless. Please see the
943 documentation in QCborValue::fromVariant() for more information.
944
945 \sa toVariantHash(), fromVariantMap(), fromJsonObject(), QCborValue::fromVariant()
946 */
947QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
948{
949 QCborMap m;
950 m.detach(reserve: hash.size());
951 QCborContainerPrivate *d = m.d.data();
952
953 auto it = hash.begin();
954 auto end = hash.end();
955 for ( ; it != end; ++it) {
956 d->append(s: it.key());
957 appendVariant(d, variant: it.value());
958 }
959 return m;
960}
961
962/*!
963 Converts all JSON items found in the \a obj object to CBOR using
964 QCborValue::fromJson(), and returns the map composed of those elements.
965
966 This conversion is lossless, as the CBOR type system is a superset of
967 JSON's. Moreover, the map returned by this function can be converted back
968 to the original \a obj by using toJsonObject().
969
970 \sa toJsonObject(), toVariantMap(), QCborValue::fromJsonValue(), QCborArray::fromJsonArray()
971 */
972QCborMap QCborMap::fromJsonObject(const QJsonObject &obj)
973{
974 QCborMap result;
975 result.d = obj.o;
976 return result;
977}
978
979/*!
980 \overload
981 \since 6.3
982 */
983QCborMap QCborMap::fromJsonObject(QJsonObject &&obj) noexcept
984{
985 QCborMap result;
986 result.d = std::exchange(obj&: obj.o, new_val: {});
987 return result;
988}
989
990QT_END_NAMESPACE
991

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