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