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(input: 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
424#ifndef QT_NO_VARIANT
425QJsonArray QJsonPrivate::Variant::toJsonArray(const QVariantList &list)
426{
427 const auto cborArray = QCborArray::fromVariantList(list);
428 return convertToJsonArray(d: cborArray.d.data(), mode: 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: 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(d: cborMap.d.data(), mode: 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(value: 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 case DateTime:
557 return toDateTime();
558
559#ifndef QT_BOOTSTRAPPED
560 case Url:
561 return toUrl();
562
563# if QT_CONFIG(regularexpression)
564 case RegularExpression:
565 return toRegularExpression();
566# endif
567
568 case Uuid:
569 return toUuid();
570#endif
571
572 case Invalid:
573 return QVariant();
574
575 default:
576 break;
577 }
578
579 if (isSimpleType())
580 return QVariant::fromValue(value: toSimpleType());
581
582 Q_UNREACHABLE_RETURN(QVariant());
583}
584#endif // !QT_NO_VARIANT
585
586/*!
587 Converts the JSON value contained in \a v into its corresponding CBOR value
588 and returns it. There is no data loss in converting from JSON to CBOR, as
589 the CBOR type set is richer than JSON's. Additionally, values converted to
590 CBOR using this function can be converted back to JSON using toJsonValue()
591 with no data loss.
592
593 The following table lists the mapping of JSON types to CBOR types:
594
595 \table
596 \header \li JSON Type \li CBOR Type
597 \row \li Bool \li Bool
598 \row \li Number \li Integer (if the number has no fraction and is in the \l qint64
599 range) or Double
600 \row \li String \li String
601 \row \li Array \li Array
602 \row \li Object \li Map
603 \row \li Null \li Null
604 \endtable
605
606 \l QJsonValue can also be undefined, indicating a previous operation that
607 failed to complete (for example, searching for a key not present in an
608 object). Undefined values are not JSON types and may not appear in JSON
609 arrays and objects, but this function does return the QCborValue undefined
610 value if the corresponding QJsonValue is undefined.
611
612 \sa toJsonValue(), fromVariant(), QCborArray::fromJsonArray(), QCborMap::fromJsonObject()
613 */
614QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
615{
616 switch (v.type()) {
617 case QJsonValue::Bool:
618 return v.toBool();
619 case QJsonValue::Double: {
620 if (v.value.t == Integer)
621 return v.toInteger();
622 return v.toDouble();
623 }
624 case QJsonValue::String:
625 return v.toString();
626 case QJsonValue::Array:
627 return QCborArray::fromJsonArray(array: v.toArray());
628 case QJsonValue::Object:
629 return QCborMap::fromJsonObject(o: v.toObject());
630 case QJsonValue::Null:
631 return nullptr;
632 case QJsonValue::Undefined:
633 break;
634 }
635 return QCborValue();
636}
637
638#ifndef QT_NO_VARIANT
639static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
640{
641 // Handle strings and byte arrays directly, to avoid creating a temporary
642 // dummy container to hold their data.
643 int type = variant.metaType().id();
644 if (type == QMetaType::QString) {
645 d->append(s: variant.toString());
646 } else if (type == QMetaType::QByteArray) {
647 QByteArray ba = variant.toByteArray();
648 d->appendByteData(data: ba.constData(), len: ba.size(), type: QCborValue::ByteArray);
649 } else {
650 // For everything else, use the function below.
651 d->append(v: QCborValue::fromVariant(variant));
652 }
653}
654
655/*!
656 Converts the QVariant \a variant into QCborValue and returns it.
657
658 QVariants may contain a large list of different meta types, many of which
659 have no corresponding representation in CBOR. That includes all
660 user-defined meta types. When preparing transmission using CBOR, it is
661 suggested to encode carefully each value to prevent loss of representation.
662
663 The following table lists the conversion this function will apply:
664
665 \table
666 \header \li Qt (C++) type \li CBOR type
667 \row \li invalid (QVariant()) \li Undefined
668 \row \li \c bool \li Bool
669 \row \li \c std::nullptr_t \li Null
670 \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
671 \row \li \l quint64 \li Integer, or Double if outside the range of qint64
672 \row \li \c float, \c double \li Double
673 \row \li \l QByteArray \li ByteArray
674 \row \li \l QDateTime \li DateTime
675 \row \li \l QCborSimpleType \li Simple type
676 \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
677 \row \li \l QJsonDocument \li Array or Map
678 \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
679 \row \li \l QJsonValue \li converted using fromJsonValue()
680 \row \li \l QRegularExpression \li RegularExpression
681 \row \li \l QString \li String
682 \row \li \l QStringList \li Array
683 \row \li \l QVariantHash \li Map
684 \row \li \l QVariantList \li Array
685 \row \li \l QVariantMap \li Map
686 \row \li \l QUrl \li Url
687 \row \li \l QUuid \li Uuid
688 \endtable
689
690 If QVariant::isNull() returns true, a null QCborValue is returned or
691 inserted into the list or object, regardless of the type carried by
692 QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
693 also affects this function.
694
695 For other types not listed above, a conversion to string will be attempted,
696 usually but not always by calling QVariant::toString(). If the conversion
697 fails the value is replaced by an Undefined CBOR value. Note that
698 QVariant::toString() is also lossy for the majority of types.
699
700 Please note that the conversions via QVariant::toString() are subject to
701 change at any time. Both QVariant and QCborValue may be extended in the
702 future to support more types, which will result in a change in how this
703 function performs conversions.
704
705 \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap(), QJsonValue::fromVariant()
706 */
707QCborValue QCborValue::fromVariant(const QVariant &variant)
708{
709 switch (variant.metaType().id()) {
710 case QMetaType::UnknownType:
711 return {};
712 case QMetaType::Nullptr:
713 return nullptr;
714 case QMetaType::Bool:
715 return variant.toBool();
716 case QMetaType::Short:
717 case QMetaType::UShort:
718 case QMetaType::Int:
719 case QMetaType::LongLong:
720 case QMetaType::UInt:
721 return variant.toLongLong();
722 case QMetaType::ULongLong:
723 if (variant.toULongLong() <= static_cast<uint64_t>(std::numeric_limits<qint64>::max()))
724 return variant.toLongLong();
725 Q_FALLTHROUGH();
726 case QMetaType::Float:
727 case QMetaType::Double:
728 return variant.toDouble();
729 case QMetaType::QString:
730 return variant.toString();
731 case QMetaType::QStringList:
732 return QCborArray::fromStringList(list: variant.toStringList());
733 case QMetaType::QByteArray:
734 return variant.toByteArray();
735 case QMetaType::QDateTime:
736 return QCborValue(variant.toDateTime());
737#ifndef QT_BOOTSTRAPPED
738 case QMetaType::QUrl:
739 return QCborValue(variant.toUrl());
740 case QMetaType::QUuid:
741 return QCborValue(variant.toUuid());
742#endif
743 case QMetaType::QVariantList:
744 return QCborArray::fromVariantList(list: variant.toList());
745 case QMetaType::QVariantMap:
746 return QCborMap::fromVariantMap(map: variant.toMap());
747 case QMetaType::QVariantHash:
748 return QCborMap::fromVariantHash(hash: variant.toHash());
749#ifndef QT_BOOTSTRAPPED
750#if QT_CONFIG(regularexpression)
751 case QMetaType::QRegularExpression:
752 return QCborValue(variant.toRegularExpression());
753#endif
754 case QMetaType::QJsonValue:
755 return fromJsonValue(v: variant.toJsonValue());
756 case QMetaType::QJsonObject:
757 return QCborMap::fromJsonObject(o: variant.toJsonObject());
758 case QMetaType::QJsonArray:
759 return QCborArray::fromJsonArray(array: variant.toJsonArray());
760 case QMetaType::QJsonDocument: {
761 QJsonDocument doc = variant.toJsonDocument();
762 if (doc.isArray())
763 return QCborArray::fromJsonArray(array: doc.array());
764 return QCborMap::fromJsonObject(o: doc.object());
765 }
766 case QMetaType::QCborValue:
767 return qvariant_cast<QCborValue>(v: variant);
768 case QMetaType::QCborArray:
769 return qvariant_cast<QCborArray>(v: variant);
770 case QMetaType::QCborMap:
771 return qvariant_cast<QCborMap>(v: variant);
772 case QMetaType::QCborSimpleType:
773 return qvariant_cast<QCborSimpleType>(v: variant);
774#endif
775 default:
776 break;
777 }
778
779 if (variant.isNull())
780 return QCborValue(nullptr);
781
782 QString string = variant.toString();
783 if (string.isNull())
784 return QCborValue(); // undefined
785 return string;
786}
787
788/*!
789 Recursively converts each \l QCborValue in this array using
790 QCborValue::toVariant() and returns the QVariantList composed of the
791 converted items.
792
793 Conversion to \l QVariant is not completely lossless. Please see the
794 documentation in QCborValue::toVariant() for more information.
795
796 \sa fromVariantList(), fromStringList(), toJsonArray(),
797 QCborValue::toVariant(), QCborMap::toVariantMap()
798 */
799QVariantList QCborArray::toVariantList() const
800{
801 QVariantList retval;
802 retval.reserve(asize: size());
803 for (qsizetype i = 0; i < size(); ++i)
804 retval.append(t: d->valueAt(idx: i).toVariant());
805 return retval;
806}
807
808/*!
809 Returns a QCborArray containing all the strings found in the \a list list.
810
811 \sa fromVariantList(), fromJsonArray()
812 */
813QCborArray QCborArray::fromStringList(const QStringList &list)
814{
815 QCborArray a;
816 a.detach(reserve: list.size());
817 for (const QString &s : list)
818 a.d->append(s);
819 return a;
820}
821
822/*!
823 Converts all the items in the \a list to CBOR using
824 QCborValue::fromVariant() and returns the array composed of those elements.
825
826 Conversion from \l QVariant is not completely lossless. Please see the
827 documentation in QCborValue::fromVariant() for more information.
828
829 \sa toVariantList(), fromStringList(), fromJsonArray(), QCborMap::fromVariantMap()
830 */
831QCborArray QCborArray::fromVariantList(const QVariantList &list)
832{
833 QCborArray a;
834 a.detach(reserve: list.size());
835 for (const QVariant &v : list)
836 appendVariant(d: a.d.data(), variant: v);
837 return a;
838}
839#endif // !QT_NO_VARIANT
840
841/*!
842 Converts all JSON items found in the \a array array to CBOR using
843 QCborValue::fromJson(), and returns the CBOR array composed of those
844 elements.
845
846 This conversion is lossless, as the CBOR type system is a superset of
847 JSON's. Moreover, the array returned by this function can be converted back
848 to the original \a array by using toJsonArray().
849
850 \sa toJsonArray(), toVariantList(), QCborValue::fromJsonValue(), QCborMap::fromJsonObject()
851 */
852QCborArray QCborArray::fromJsonArray(const QJsonArray &array)
853{
854 QCborArray result;
855 result.d = array.a;
856 return result;
857}
858
859/*!
860 \overload
861 \since 6.3
862 */
863QCborArray QCborArray::fromJsonArray(QJsonArray &&array) noexcept
864{
865 QCborArray result;
866 result.d = std::exchange(obj&: array.a, new_val: {});
867 return result;
868
869}
870
871#ifndef QT_NO_VARIANT
872/*!
873 Converts the CBOR values to QVariant using QCborValue::toVariant() and
874 "stringifies" all the CBOR keys in this map, returning the QVariantMap that
875 results from that association list.
876
877 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
878 to QVariantMap will imply a step of "stringification" of the key values.
879 See QCborMap::toJsonObject() for details.
880
881 In addition, the conversion to \l QVariant is not completely lossless.
882 Please see the documentation in QCborValue::toVariant() for more
883 information.
884
885 \sa fromVariantMap(), toVariantHash(), toJsonObject(), QCborValue::toVariant(),
886 QCborArray::toVariantList()
887 */
888QVariantMap QCborMap::toVariantMap() const
889{
890 QVariantMap retval;
891 for (qsizetype i = 0; i < 2 * size(); i += 2)
892 retval.insert(key: makeString(d: d.data(), idx: i), value: d->valueAt(idx: i + 1).toVariant());
893 return retval;
894}
895
896/*!
897 Converts the CBOR values to QVariant using QCborValue::toVariant() and
898 "stringifies" all the CBOR keys in this map, returning the QVariantHash that
899 results from that association list.
900
901 QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
902 to QVariantMap will imply a step of "stringification" of the key values.
903 See QCborMap::toJsonObject() for details.
904
905 In addition, the conversion to \l QVariant is not completely lossless.
906 Please see the documentation in QCborValue::toVariant() for more
907 information.
908
909 \sa fromVariantHash(), toVariantMap(), toJsonObject(), QCborValue::toVariant(),
910 QCborArray::toVariantList()
911 */
912QVariantHash QCborMap::toVariantHash() const
913{
914 QVariantHash retval;
915 retval.reserve(size: size());
916 for (qsizetype i = 0; i < 2 * size(); i += 2)
917 retval.insert(key: makeString(d: d.data(), idx: i), value: d->valueAt(idx: i + 1).toVariant());
918 return retval;
919}
920
921/*!
922 Converts all the items in \a map to CBOR using QCborValue::fromVariant()
923 and returns the map composed of those elements.
924
925 Conversion from \l QVariant is not completely lossless. Please see the
926 documentation in QCborValue::fromVariant() for more information.
927
928 \sa toVariantMap(), fromVariantHash(), fromJsonObject(), QCborValue::fromVariant()
929 */
930QCborMap QCborMap::fromVariantMap(const QVariantMap &map)
931{
932 QCborMap m;
933 m.detach(reserve: map.size());
934 QCborContainerPrivate *d = m.d.data();
935
936 auto it = map.begin();
937 auto end = map.end();
938 for ( ; it != end; ++it) {
939 d->append(s: it.key());
940 appendVariant(d, variant: it.value());
941 }
942 return m;
943}
944
945/*!
946 Converts all the items in \a hash to CBOR using QCborValue::fromVariant()
947 and returns the map composed of those elements.
948
949 Conversion from \l QVariant is not completely lossless. Please see the
950 documentation in QCborValue::fromVariant() for more information.
951
952 \sa toVariantHash(), fromVariantMap(), fromJsonObject(), QCborValue::fromVariant()
953 */
954QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
955{
956 QCborMap m;
957 m.detach(reserve: hash.size());
958 QCborContainerPrivate *d = m.d.data();
959
960 auto it = hash.begin();
961 auto end = hash.end();
962 for ( ; it != end; ++it) {
963 d->append(s: it.key());
964 appendVariant(d, variant: it.value());
965 }
966 return m;
967}
968#endif // !QT_NO_VARIANT
969
970/*!
971 Converts all JSON items found in the \a obj object to CBOR using
972 QCborValue::fromJson(), and returns the map composed of those elements.
973
974 This conversion is lossless, as the CBOR type system is a superset of
975 JSON's. Moreover, the map returned by this function can be converted back
976 to the original \a obj by using toJsonObject().
977
978 \sa toJsonObject(), toVariantMap(), QCborValue::fromJsonValue(), QCborArray::fromJsonArray()
979 */
980QCborMap QCborMap::fromJsonObject(const QJsonObject &obj)
981{
982 QCborMap result;
983 result.d = obj.o;
984 return result;
985}
986
987/*!
988 \overload
989 \since 6.3
990 */
991QCborMap QCborMap::fromJsonObject(QJsonObject &&obj) noexcept
992{
993 QCborMap result;
994 result.d = std::exchange(obj&: obj.o, new_val: {});
995 return result;
996}
997
998QT_END_NAMESPACE
999

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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