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

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