1 | // Copyright (C) 2020 The Qt Company Ltd. |
---|---|
2 | // Copyright (C) 2022 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include <qjsonobject.h> |
6 | #include <qjsonvalue.h> |
7 | #include <qjsonarray.h> |
8 | #include <qjsondocument.h> |
9 | #include <qurl.h> |
10 | #include <quuid.h> |
11 | #include <qvariant.h> |
12 | #include <qstringlist.h> |
13 | #include <qmap.h> |
14 | #include <qhash.h> |
15 | #include <qdebug.h> |
16 | #include "qdatastream.h" |
17 | |
18 | #include <private/qnumeric_p.h> |
19 | #include <private/qcborvalue_p.h> |
20 | |
21 | #include <qcborarray.h> |
22 | #include <qcbormap.h> |
23 | |
24 | #include "qjson_p.h" |
25 | |
26 | QT_BEGIN_NAMESPACE |
27 | |
28 | static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept |
29 | { |
30 | switch (type) { |
31 | case QCborValue::Null: |
32 | return QJsonValue::Null; |
33 | case QCborValue::True: |
34 | case QCborValue::False: |
35 | return QJsonValue::Bool; |
36 | case QCborValue::Double: |
37 | case QCborValue::Integer: |
38 | return QJsonValue::Double; |
39 | case QCborValue::String: |
40 | return QJsonValue::String; |
41 | case QCborValue::Array: |
42 | return QJsonValue::Array; |
43 | case QCborValue::Map: |
44 | return QJsonValue::Object; |
45 | case QCborValue::Undefined: |
46 | default: |
47 | return QJsonValue::Undefined; |
48 | } |
49 | } |
50 | |
51 | /*! |
52 | \class QJsonValue |
53 | \inmodule QtCore |
54 | \ingroup json |
55 | \ingroup shared |
56 | \ingroup qtserialization |
57 | \reentrant |
58 | \since 5.0 |
59 | |
60 | \brief The QJsonValue class encapsulates a value in JSON. |
61 | |
62 | \compares equality |
63 | \compareswith equality QJsonValueConstRef QJsonValueRef |
64 | \endcompareswith |
65 | |
66 | A value in JSON can be one of 6 basic types: |
67 | |
68 | JSON is a format to store structured data. It has 6 basic data types: |
69 | |
70 | \list |
71 | \li bool QJsonValue::Bool |
72 | \li double QJsonValue::Double |
73 | \li string QJsonValue::String |
74 | \li array QJsonValue::Array |
75 | \li object QJsonValue::Object |
76 | \li null QJsonValue::Null |
77 | \endlist |
78 | |
79 | A value can represent any of the above data types. In addition, QJsonValue has one special |
80 | flag to represent undefined values. This can be queried with isUndefined(). |
81 | |
82 | The type of the value can be queried with type() or accessors like isBool(), isString(), and so on. |
83 | Likewise, the value can be converted to the type stored in it using the toBool(), toString() and so on. |
84 | |
85 | Values are strictly typed internally and contrary to QVariant will not attempt to do any implicit type |
86 | conversions. This implies that converting to a type that is not stored in the value will return a default |
87 | constructed return value. |
88 | |
89 | \section1 QJsonValueRef |
90 | |
91 | QJsonValueRef is a helper class for QJsonArray and QJsonObject. |
92 | When you get an object of type QJsonValueRef, you can |
93 | use it as if it were a reference to a QJsonValue. If you assign to it, |
94 | the assignment will apply to the element in the QJsonArray or QJsonObject |
95 | from which you got the reference. |
96 | |
97 | The following methods return QJsonValueRef: |
98 | \list |
99 | \li \l {QJsonArray}::operator[](qsizetype i) |
100 | \li \l {QJsonObject}::operator[](const QString & key) const |
101 | \endlist |
102 | |
103 | \sa {JSON Support in Qt}, {Saving and Loading a Game} |
104 | */ |
105 | |
106 | /*! |
107 | Creates a QJsonValue of type \a type. |
108 | |
109 | The default is to create a Null value. |
110 | */ |
111 | QJsonValue::QJsonValue(Type type) |
112 | { |
113 | switch (type) { |
114 | case Null: |
115 | value = QCborValue::Null; |
116 | break; |
117 | case Bool: |
118 | value = QCborValue::False; |
119 | break; |
120 | case Double: |
121 | value = QCborValue::Double; |
122 | break; |
123 | case String: |
124 | value = QCborValue::String; |
125 | break; |
126 | case Array: |
127 | value = QCborValue::Array; |
128 | break; |
129 | case Object: |
130 | value = QCborValue::Map; |
131 | break; |
132 | case Undefined: |
133 | break; |
134 | } |
135 | } |
136 | |
137 | /*! |
138 | Creates a value of type Bool, with value \a b. |
139 | */ |
140 | QJsonValue::QJsonValue(bool b) |
141 | : value(b) |
142 | { |
143 | } |
144 | |
145 | static inline QCborValue doubleValueHelper(double v) |
146 | { |
147 | qint64 n = 0; |
148 | // Convert to integer if the number is an integer and changing wouldn't |
149 | // introduce additional digit precision not present in the double. |
150 | if (convertDoubleTo<qint64>(v, value: &n, allow_precision_upgrade: false /* allow_precision_upgrade */)) |
151 | return n; |
152 | else |
153 | return v; |
154 | } |
155 | |
156 | /*! |
157 | Creates a value of type Double, with value \a v. |
158 | */ |
159 | QJsonValue::QJsonValue(double v) |
160 | : value(doubleValueHelper(v)) |
161 | { |
162 | } |
163 | |
164 | /*! |
165 | \overload |
166 | Creates a value of type Double, with value \a v. |
167 | */ |
168 | QJsonValue::QJsonValue(int v) |
169 | : value(v) |
170 | { |
171 | } |
172 | |
173 | /*! |
174 | \overload |
175 | Creates a value of type Double, with value \a v. |
176 | NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992). |
177 | If you pass in values outside this range expect a loss of precision to occur. |
178 | */ |
179 | QJsonValue::QJsonValue(qint64 v) |
180 | : value(v) |
181 | { |
182 | } |
183 | |
184 | /*! |
185 | Creates a value of type String, with value \a s. |
186 | */ |
187 | QJsonValue::QJsonValue(const QString &s) |
188 | : value(s) |
189 | { |
190 | } |
191 | |
192 | /*! |
193 | \fn QJsonValue::QJsonValue(const char *s) |
194 | |
195 | Creates a value of type String with value \a s, assuming |
196 | UTF-8 encoding of the input. |
197 | |
198 | You can disable this constructor by defining \c |
199 | QT_NO_CAST_FROM_ASCII when you compile your applications. |
200 | |
201 | \since 5.3 |
202 | */ |
203 | |
204 | /*! |
205 | Creates a value of type String, with the Latin-1 string viewed by \a s. |
206 | */ |
207 | QJsonValue::QJsonValue(QLatin1StringView s) |
208 | : value(s) |
209 | { |
210 | } |
211 | |
212 | /*! |
213 | Creates a value of type Array, with value \a a. |
214 | */ |
215 | QJsonValue::QJsonValue(const QJsonArray &a) |
216 | : value(QCborArray::fromJsonArray(array: a)) |
217 | { |
218 | } |
219 | |
220 | /*! |
221 | \overload |
222 | \since 6.3 |
223 | */ |
224 | QJsonValue::QJsonValue(QJsonArray &&a) noexcept |
225 | : value(QCborArray::fromJsonArray(array: std::move(a))) |
226 | { |
227 | } |
228 | |
229 | /*! |
230 | Creates a value of type Object, with value \a o. |
231 | */ |
232 | QJsonValue::QJsonValue(const QJsonObject &o) |
233 | : value(QCborMap::fromJsonObject(o)) |
234 | { |
235 | } |
236 | |
237 | /*! |
238 | \overload |
239 | \since 6.3 |
240 | */ |
241 | QJsonValue::QJsonValue(QJsonObject &&o) noexcept |
242 | : value(QCborMap::fromJsonObject(o: std::move(o))) |
243 | { |
244 | } |
245 | |
246 | |
247 | /*! |
248 | Destroys the value. |
249 | */ |
250 | QJsonValue::~QJsonValue() = default; |
251 | |
252 | /*! |
253 | Creates a copy of \a other. |
254 | */ |
255 | QJsonValue::QJsonValue(const QJsonValue &other) noexcept = default; |
256 | |
257 | /*! |
258 | Assigns the value stored in \a other to this object. |
259 | */ |
260 | QJsonValue &QJsonValue::operator =(const QJsonValue &other) noexcept |
261 | { |
262 | QJsonValue copy(other); |
263 | swap(other&: copy); |
264 | return *this; |
265 | } |
266 | |
267 | QJsonValue::QJsonValue(QJsonValue &&other) noexcept |
268 | : value(std::move(other.value)) |
269 | { |
270 | other.value = QCborValue(nullptr); |
271 | } |
272 | |
273 | void QJsonValue::swap(QJsonValue &other) noexcept |
274 | { |
275 | value.swap(other&: other.value); |
276 | } |
277 | |
278 | /*! |
279 | \fn QJsonValue::QJsonValue(QJsonValue &&other) |
280 | \since 5.10 |
281 | |
282 | Move-constructs a QJsonValue from \a other. |
283 | */ |
284 | |
285 | /*! |
286 | \fn QJsonValue &QJsonValue::operator =(QJsonValue &&other) |
287 | \since 5.10 |
288 | |
289 | Move-assigns \a other to this value. |
290 | */ |
291 | |
292 | /*! |
293 | \fn void QJsonValue::swap(QJsonValue &other) |
294 | \since 5.10 |
295 | |
296 | Swaps the value \a other with this. This operation is very fast and never fails. |
297 | */ |
298 | |
299 | /*! |
300 | \fn bool QJsonValue::isNull() const |
301 | |
302 | Returns \c true if the value is null. |
303 | */ |
304 | |
305 | /*! |
306 | \fn bool QJsonValue::isBool() const |
307 | |
308 | Returns \c true if the value contains a boolean. |
309 | |
310 | \sa toBool() |
311 | */ |
312 | |
313 | /*! |
314 | \fn bool QJsonValue::isDouble() const |
315 | |
316 | Returns \c true if the value contains a double. |
317 | |
318 | \sa toDouble() |
319 | */ |
320 | |
321 | /*! |
322 | \fn bool QJsonValue::isString() const |
323 | |
324 | Returns \c true if the value contains a string. |
325 | |
326 | \sa toString() |
327 | */ |
328 | |
329 | /*! |
330 | \fn bool QJsonValue::isArray() const |
331 | |
332 | Returns \c true if the value contains an array. |
333 | |
334 | \sa toArray() |
335 | */ |
336 | |
337 | /*! |
338 | \fn bool QJsonValue::isObject() const |
339 | |
340 | Returns \c true if the value contains an object. |
341 | |
342 | \sa toObject() |
343 | */ |
344 | |
345 | /*! |
346 | \fn bool QJsonValue::isUndefined() const |
347 | |
348 | Returns \c true if the value is undefined. This can happen in certain |
349 | error cases as e.g. accessing a non existing key in a QJsonObject. |
350 | */ |
351 | |
352 | #ifndef QT_NO_VARIANT |
353 | /*! |
354 | Converts \a variant to a QJsonValue and returns it. |
355 | |
356 | The conversion will convert QVariant types as follows: |
357 | |
358 | \table |
359 | \header |
360 | \li Source type |
361 | \li Destination type |
362 | \row |
363 | \li |
364 | \list |
365 | \li QMetaType::Nullptr |
366 | \endlist |
367 | \li QJsonValue::Null |
368 | \row |
369 | \li |
370 | \list |
371 | \li QMetaType::Bool |
372 | \endlist |
373 | \li QJsonValue::Bool |
374 | \row |
375 | \li |
376 | \list |
377 | \li QMetaType::Int |
378 | \li QMetaType::UInt |
379 | \li QMetaType::LongLong |
380 | \li QMetaType::ULongLong |
381 | \li QMetaType::Float |
382 | \li QMetaType::Double |
383 | \endlist |
384 | \li QJsonValue::Double |
385 | \row |
386 | \li |
387 | \list |
388 | \li QMetaType::QString |
389 | \endlist |
390 | \li QJsonValue::String |
391 | \row |
392 | \li |
393 | \list |
394 | \li QMetaType::QStringList |
395 | \li QMetaType::QVariantList |
396 | \endlist |
397 | \li QJsonValue::Array |
398 | \row |
399 | \li |
400 | \list |
401 | \li QMetaType::QVariantMap |
402 | \li QMetaType::QVariantHash |
403 | \endlist |
404 | \li QJsonValue::Object |
405 | |
406 | \row |
407 | \li |
408 | \list |
409 | \li QMetaType::QUrl |
410 | \endlist |
411 | \li QJsonValue::String. The conversion will use QUrl::toString() with flag |
412 | QUrl::FullyEncoded, so as to ensure maximum compatibility in parsing the URL |
413 | \row |
414 | \li |
415 | \list |
416 | \li QMetaType::QUuid |
417 | \endlist |
418 | \li QJsonValue::String. Since Qt 5.11, the resulting string will not include braces |
419 | \row |
420 | \li |
421 | \list |
422 | \li QMetaType::QCborValue |
423 | \endlist |
424 | \li Whichever type QCborValue::toJsonValue() returns. |
425 | \row |
426 | \li |
427 | \list |
428 | \li QMetaType::QCborArray |
429 | \endlist |
430 | \li QJsonValue::Array. See QCborValue::toJsonValue() for conversion restrictions. |
431 | \row |
432 | \li |
433 | \list |
434 | \li QMetaType::QCborMap |
435 | \endlist |
436 | \li QJsonValue::Map. See QCborValue::toJsonValue() for conversion restrictions and the |
437 | "stringification" of map keys. |
438 | \endtable |
439 | |
440 | \section2 Loss of information and other types |
441 | |
442 | QVariant can carry more information than is representable in JSON. If the |
443 | QVariant is not one of the types above, the conversion is not guaranteed |
444 | and is subject to change in future versions of Qt, as the UUID one did. |
445 | Code should strive not to use any other types than those listed above. |
446 | |
447 | If QVariant::isNull() returns true, a null QJsonValue is returned or |
448 | inserted into the list or object, regardless of the type carried by |
449 | QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull() |
450 | also affects this function. |
451 | |
452 | A floating point value that is either an infinity or NaN will be converted |
453 | to a null JSON value. Since Qt 6.0, QJsonValue can store the full precision |
454 | of any 64-bit signed integer without loss, but in previous versions values |
455 | outside the range of ±2^53 may lose precision. Unsigned 64-bit values |
456 | greater than or equal to 2^63 will either lose precision or alias to |
457 | negative values, so QMetaType::ULongLong should be avoided. |
458 | |
459 | For other types not listed above, a conversion to string will be attempted, |
460 | usually but not always by calling QVariant::toString(). If the conversion |
461 | fails the value is replaced by a null JSON value. Note that |
462 | QVariant::toString() is also lossy for the majority of types. For example, |
463 | if the passed QVariant is representing raw byte array data, it is recommended |
464 | to pre-encode it to \l {RFC 4686}{Base64} (or |
465 | another lossless encoding), otherwise a lossy conversion using QString::fromUtf8() |
466 | will be used. |
467 | |
468 | Please note that the conversions via QVariant::toString() are subject to |
469 | change at any time. Both QVariant and QJsonValue may be extended in the |
470 | future to support more types, which will result in a change in how this |
471 | function performs conversions. |
472 | |
473 | \sa toVariant(), QCborValue::fromVariant() |
474 | */ |
475 | QJsonValue QJsonValue::fromVariant(const QVariant &variant) |
476 | { |
477 | switch (variant.metaType().id()) { |
478 | case QMetaType::Nullptr: |
479 | return QJsonValue(Null); |
480 | case QMetaType::Bool: |
481 | return QJsonValue(variant.toBool()); |
482 | case QMetaType::Short: |
483 | case QMetaType::UShort: |
484 | case QMetaType::Int: |
485 | case QMetaType::UInt: |
486 | case QMetaType::LongLong: |
487 | return QJsonValue(variant.toLongLong()); |
488 | case QMetaType::ULongLong: |
489 | if (variant.toULongLong() <= static_cast<uint64_t>(std::numeric_limits<qint64>::max())) |
490 | return QJsonValue(variant.toLongLong()); |
491 | Q_FALLTHROUGH(); |
492 | case QMetaType::Float: |
493 | case QMetaType::Double: { |
494 | double v = variant.toDouble(); |
495 | return qt_is_finite(d: v) ? QJsonValue(v) : QJsonValue(); |
496 | } |
497 | case QMetaType::QString: |
498 | return QJsonValue(variant.toString()); |
499 | case QMetaType::QStringList: |
500 | return QJsonValue(QJsonArray::fromStringList(list: variant.toStringList())); |
501 | case QMetaType::QVariantList: |
502 | return QJsonValue(QJsonArray::fromVariantList(list: variant.toList())); |
503 | case QMetaType::QVariantMap: |
504 | return QJsonValue(QJsonObject::fromVariantMap(map: variant.toMap())); |
505 | case QMetaType::QVariantHash: |
506 | return QJsonValue(QJsonObject::fromVariantHash(map: variant.toHash())); |
507 | #ifndef QT_BOOTSTRAPPED |
508 | case QMetaType::QUrl: |
509 | return QJsonValue(variant.toUrl().toString(options: QUrl::FullyEncoded)); |
510 | case QMetaType::QUuid: |
511 | return variant.toUuid().toString(mode: QUuid::WithoutBraces); |
512 | case QMetaType::QJsonValue: |
513 | return variant.toJsonValue(); |
514 | case QMetaType::QJsonObject: |
515 | return variant.toJsonObject(); |
516 | case QMetaType::QJsonArray: |
517 | return variant.toJsonArray(); |
518 | case QMetaType::QJsonDocument: { |
519 | QJsonDocument doc = variant.toJsonDocument(); |
520 | return doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object()); |
521 | } |
522 | case QMetaType::QCborValue: |
523 | return qvariant_cast<QCborValue>(v: variant).toJsonValue(); |
524 | case QMetaType::QCborArray: |
525 | return qvariant_cast<QCborArray>(v: variant).toJsonArray(); |
526 | case QMetaType::QCborMap: |
527 | return qvariant_cast<QCborMap>(v: variant).toJsonObject(); |
528 | #endif |
529 | default: |
530 | break; |
531 | } |
532 | QString string = variant.toString(); |
533 | if (string.isEmpty()) |
534 | return QJsonValue(); |
535 | return QJsonValue(string); |
536 | } |
537 | |
538 | /*! |
539 | Converts the value to a \l {QVariant::}{QVariant()}. |
540 | |
541 | The QJsonValue types will be converted as follows: |
542 | |
543 | \value Null QMetaType::Nullptr |
544 | \value Bool QMetaType::Bool |
545 | \value Double QMetaType::Double or QMetaType::LongLong |
546 | \value String QString |
547 | \value Array QVariantList |
548 | \value Object QVariantMap |
549 | \value Undefined \l {QVariant::}{QVariant()} |
550 | |
551 | \sa fromVariant() |
552 | */ |
553 | QVariant QJsonValue::toVariant() const |
554 | { |
555 | switch (value.type()) { |
556 | case QCborValue::True: |
557 | return true; |
558 | case QCborValue::False: |
559 | return false; |
560 | case QCborValue::Integer: |
561 | return toInteger(); |
562 | case QCborValue::Double: |
563 | return toDouble(); |
564 | case QCborValue::String: |
565 | return toString(); |
566 | case QCborValue::Array: |
567 | return toArray().toVariantList(); |
568 | case QCborValue::Map: |
569 | return toObject().toVariantMap(); |
570 | case QCborValue::Null: |
571 | return QVariant::fromValue(value: nullptr); |
572 | case QCborValue::Undefined: |
573 | default: |
574 | break; |
575 | } |
576 | return QVariant(); |
577 | } |
578 | |
579 | /*! |
580 | \enum QJsonValue::Type |
581 | |
582 | This enum describes the type of the JSON value. |
583 | |
584 | \value Null A Null value |
585 | \value Bool A boolean value. Use toBool() to convert to a bool. |
586 | \value Double A number value. Use toDouble() to convert to a double, |
587 | or toInteger() to convert to a qint64. |
588 | \value String A string. Use toString() to convert to a QString. |
589 | \value Array An array. Use toArray() to convert to a QJsonArray. |
590 | \value Object An object. Use toObject() to convert to a QJsonObject. |
591 | \value Undefined The value is undefined. This is usually returned as an |
592 | error condition, when trying to read an out of bounds value |
593 | in an array or a non existent key in an object. |
594 | */ |
595 | #endif // !QT_NO_VARIANT |
596 | |
597 | /*! |
598 | Returns the type of the value. |
599 | |
600 | \sa QJsonValue::Type |
601 | */ |
602 | QJsonValue::Type QJsonValue::type() const |
603 | { |
604 | return convertFromCborType(type: value.type()); |
605 | } |
606 | |
607 | /*! |
608 | Converts the value to a bool and returns it. |
609 | |
610 | If type() is not bool, the \a defaultValue will be returned. |
611 | */ |
612 | bool QJsonValue::toBool(bool defaultValue) const |
613 | { |
614 | switch (value.type()) { |
615 | case QCborValue::True: |
616 | return true; |
617 | case QCborValue::False: |
618 | return false; |
619 | default: |
620 | return defaultValue; |
621 | } |
622 | } |
623 | |
624 | /*! |
625 | \since 5.2 |
626 | Converts the value to an int and returns it. |
627 | |
628 | If type() is not Double or the value is not a whole number, |
629 | the \a defaultValue will be returned. |
630 | */ |
631 | int QJsonValue::toInt(int defaultValue) const |
632 | { |
633 | switch (value.type()) { |
634 | case QCborValue::Double: { |
635 | int dblInt; |
636 | if (convertDoubleTo<int>(v: toDouble(), value: &dblInt)) |
637 | return dblInt; |
638 | break; |
639 | } |
640 | case QCborValue::Integer: { |
641 | const auto n = value.toInteger(); |
642 | if (qint64(int(n)) == n) |
643 | return int(n); |
644 | break; |
645 | } |
646 | default: |
647 | break; |
648 | } |
649 | return defaultValue; |
650 | } |
651 | |
652 | /*! |
653 | \since 6.0 |
654 | Converts the value to an integer and returns it. |
655 | |
656 | If type() is not Double or the value is not a whole number |
657 | representable as qint64, the \a defaultValue will be returned. |
658 | */ |
659 | qint64 QJsonValue::toInteger(qint64 defaultValue) const |
660 | { |
661 | switch (value.type()) { |
662 | case QCborValue::Integer: |
663 | return value.toInteger(); |
664 | case QCborValue::Double: { |
665 | qint64 dblInt; |
666 | if (convertDoubleTo<qint64>(v: toDouble(), value: &dblInt)) |
667 | return dblInt; |
668 | break; |
669 | } |
670 | default: |
671 | break; |
672 | } |
673 | return defaultValue; |
674 | } |
675 | |
676 | /*! |
677 | Converts the value to a double and returns it. |
678 | |
679 | If type() is not Double, the \a defaultValue will be returned. |
680 | */ |
681 | double QJsonValue::toDouble(double defaultValue) const |
682 | { |
683 | return value.toDouble(defaultValue); |
684 | } |
685 | |
686 | /*! |
687 | Converts the value to a QString and returns it. |
688 | |
689 | If type() is not String, the \a defaultValue will be returned. |
690 | */ |
691 | QString QJsonValue::toString(const QString &defaultValue) const |
692 | { |
693 | return value.toString(defaultValue); |
694 | } |
695 | |
696 | /*! |
697 | Converts the value to a QString and returns it. |
698 | |
699 | If type() is not String, a null QString will be returned. |
700 | |
701 | \sa QString::isNull() |
702 | */ |
703 | QString QJsonValue::toString() const |
704 | { |
705 | return value.toString(); |
706 | } |
707 | |
708 | /*! |
709 | Converts the value to an array and returns it. |
710 | |
711 | If type() is not Array, the \a defaultValue will be returned. |
712 | */ |
713 | QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const |
714 | { |
715 | if (!isArray()) |
716 | return defaultValue; |
717 | QCborContainerPrivate *dd = nullptr; |
718 | const auto n = QJsonPrivate::Value::valueHelper(v: value); |
719 | const auto container = QJsonPrivate::Value::container(v: value); |
720 | Q_ASSERT(n == -1 || container == nullptr); |
721 | if (n < 0) |
722 | dd = container; |
723 | return QJsonArray(dd); |
724 | } |
725 | |
726 | /*! |
727 | \overload |
728 | |
729 | Converts the value to an array and returns it. |
730 | |
731 | If type() is not Array, a \l{QJsonArray::}{QJsonArray()} will be returned. |
732 | */ |
733 | QJsonArray QJsonValue::toArray() const |
734 | { |
735 | return toArray(defaultValue: QJsonArray()); |
736 | } |
737 | |
738 | /*! |
739 | Converts the value to an object and returns it. |
740 | |
741 | If type() is not Object, the \a defaultValue will be returned. |
742 | */ |
743 | QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const |
744 | { |
745 | if (!isObject()) |
746 | return defaultValue; |
747 | QCborContainerPrivate *dd = nullptr; |
748 | const auto container = QJsonPrivate::Value::container(v: value); |
749 | const auto n = QJsonPrivate::Value::valueHelper(v: value); |
750 | Q_ASSERT(n == -1 || container == nullptr); |
751 | if (n < 0) |
752 | dd = container; |
753 | return QJsonObject(dd); |
754 | } |
755 | |
756 | /*! |
757 | \overload |
758 | |
759 | Converts the value to an object and returns it. |
760 | |
761 | If type() is not Object, the \l {QJsonObject::}{QJsonObject()} will be returned. |
762 | */ |
763 | QJsonObject QJsonValue::toObject() const |
764 | { |
765 | return toObject(defaultValue: QJsonObject()); |
766 | } |
767 | |
768 | /*! |
769 | Returns a QJsonValue representing the value for the key \a key. |
770 | |
771 | Equivalent to calling toObject().value(key). |
772 | |
773 | The returned QJsonValue is QJsonValue::Undefined if the key does not exist, |
774 | or if isObject() is false. |
775 | |
776 | \since 5.10 |
777 | |
778 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject |
779 | */ |
780 | const QJsonValue QJsonValue::operator[](const QString &key) const |
781 | { |
782 | return (*this)[QStringView(key)]; |
783 | } |
784 | |
785 | /*! |
786 | \overload |
787 | \since 5.14 |
788 | */ |
789 | const QJsonValue QJsonValue::operator[](QStringView key) const |
790 | { |
791 | if (!isObject()) |
792 | return QJsonValue(QJsonValue::Undefined); |
793 | |
794 | return toObject().value(key); |
795 | } |
796 | |
797 | /*! |
798 | \overload |
799 | \since 5.10 |
800 | */ |
801 | const QJsonValue QJsonValue::operator[](QLatin1StringView key) const |
802 | { |
803 | if (!isObject()) |
804 | return QJsonValue(QJsonValue::Undefined); |
805 | |
806 | return toObject().value(key); |
807 | } |
808 | |
809 | /*! |
810 | Returns a QJsonValue representing the value for index \a i. |
811 | |
812 | Equivalent to calling toArray().at(i). |
813 | |
814 | The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds, |
815 | or if isArray() is false. |
816 | |
817 | \since 5.10 |
818 | |
819 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray |
820 | */ |
821 | const QJsonValue QJsonValue::operator[](qsizetype i) const |
822 | { |
823 | if (!isArray()) |
824 | return QJsonValue(QJsonValue::Undefined); |
825 | |
826 | return toArray().at(i); |
827 | } |
828 | |
829 | /*! |
830 | \fn bool QJsonValue::operator==(const QJsonValue &lhs, const QJsonValue &rhs) |
831 | |
832 | Returns \c true if the \a lhs value is equal to \a rhs value, \c false otherwise. |
833 | */ |
834 | bool comparesEqual(const QJsonValue &lhs, const QJsonValue &rhs) |
835 | { |
836 | if (lhs.value.type() != rhs.value.type()) { |
837 | if (lhs.isDouble() && rhs.isDouble()) { |
838 | // One value Cbor integer, one Cbor double, should interact as doubles. |
839 | return lhs.toDouble() == rhs.toDouble(); |
840 | } |
841 | return false; |
842 | } |
843 | |
844 | switch (lhs.value.type()) { |
845 | case QCborValue::Undefined: |
846 | case QCborValue::Null: |
847 | case QCborValue::True: |
848 | case QCborValue::False: |
849 | break; |
850 | case QCborValue::Double: |
851 | return lhs.toDouble() == rhs.toDouble(); |
852 | case QCborValue::Integer: |
853 | return QJsonPrivate::Value::valueHelper(v: lhs.value) |
854 | == QJsonPrivate::Value::valueHelper(v: rhs.value); |
855 | case QCborValue::String: |
856 | return lhs.toString() == rhs.toString(); |
857 | case QCborValue::Array: |
858 | return lhs.toArray() == rhs.toArray(); |
859 | case QCborValue::Map: |
860 | return lhs.toObject() == rhs.toObject(); |
861 | default: |
862 | return false; |
863 | } |
864 | return true; |
865 | } |
866 | |
867 | /*! |
868 | \fn bool QJsonValue::operator!=(const QJsonValue &lhs, const QJsonValue &rhs) |
869 | |
870 | Returns \c true if the \a lhs value is not equal to \a rhs value, \c false otherwise. |
871 | */ |
872 | |
873 | /*! |
874 | \class QJsonValueRef |
875 | \inmodule QtCore |
876 | \reentrant |
877 | \brief The QJsonValueRef class is a helper class for QJsonValue. |
878 | |
879 | \internal |
880 | |
881 | \ingroup json |
882 | |
883 | When you get an object of type QJsonValueRef, if you can assign to it, |
884 | the assignment will apply to the character in the string from |
885 | which you got the reference. That is its whole purpose in life. |
886 | |
887 | You can use it exactly in the same way as a reference to a QJsonValue. |
888 | |
889 | The QJsonValueRef becomes invalid once modifications are made to the |
890 | string: if you want to keep the character, copy it into a QJsonValue. |
891 | |
892 | Most of the QJsonValue member functions also exist in QJsonValueRef. |
893 | However, they are not explicitly documented here. |
894 | */ |
895 | |
896 | void QJsonValueRef::detach() |
897 | { |
898 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) |
899 | QCborContainerPrivate *d = QJsonPrivate::Value::container(r: *this); |
900 | d = QCborContainerPrivate::detach(d, reserved: d->elements.size()); |
901 | |
902 | if (is_object) |
903 | o->o.reset(ptr: d); |
904 | else |
905 | a->a.reset(ptr: d); |
906 | #else |
907 | d = QCborContainerPrivate::detach(d, d->elements.size()); |
908 | #endif |
909 | } |
910 | |
911 | static QJsonValueRef &assignToRef(QJsonValueRef &ref, const QCborValue &value, bool is_object) |
912 | { |
913 | QCborContainerPrivate *d = QJsonPrivate::Value::container(r: ref); |
914 | qsizetype index = QJsonPrivate::Value::indexHelper(r: ref); |
915 | if (is_object && value.isUndefined()) { |
916 | d->removeAt(idx: index); |
917 | d->removeAt(idx: index - 1); |
918 | } else { |
919 | d->replaceAt(idx: index, value); |
920 | } |
921 | |
922 | return ref; |
923 | } |
924 | |
925 | QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val) |
926 | { |
927 | detach(); |
928 | return assignToRef(ref&: *this, value: QCborValue::fromJsonValue(v: val), is_object); |
929 | } |
930 | |
931 | QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref) |
932 | { |
933 | // ### optimize more? |
934 | const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: ref); |
935 | qsizetype index = QJsonPrivate::Value::indexHelper(r: ref); |
936 | |
937 | if (d == QJsonPrivate::Value::container(r: *this) && |
938 | index == QJsonPrivate::Value::indexHelper(r: *this)) |
939 | return *this; // self assignment |
940 | |
941 | detach(); |
942 | return assignToRef(ref&: *this, value: d->valueAt(idx: index), is_object); |
943 | } |
944 | |
945 | #ifndef QT_NO_VARIANT |
946 | QVariant QJsonValueConstRef::toVariant() const |
947 | { |
948 | return concrete(self: *this).toVariant(); |
949 | } |
950 | #endif // !QT_NO_VARIANT |
951 | |
952 | QJsonArray QJsonValueConstRef::toArray() const |
953 | { |
954 | return concrete(self: *this).toArray(); |
955 | } |
956 | |
957 | QJsonObject QJsonValueConstRef::toObject() const |
958 | { |
959 | return concrete(self: *this).toObject(); |
960 | } |
961 | |
962 | QJsonValue::Type QJsonValueConstRef::concreteType(QJsonValueConstRef self) noexcept |
963 | { |
964 | return convertFromCborType(type: QJsonPrivate::Value::elementHelper(r: self).type); |
965 | } |
966 | |
967 | bool QJsonValueConstRef::concreteBool(QJsonValueConstRef self, bool defaultValue) noexcept |
968 | { |
969 | auto &e = QJsonPrivate::Value::elementHelper(r: self); |
970 | if (e.type == QCborValue::False) |
971 | return false; |
972 | if (e.type == QCborValue::True) |
973 | return true; |
974 | return defaultValue; |
975 | } |
976 | |
977 | qint64 QJsonValueConstRef::concreteInt(QJsonValueConstRef self, qint64 defaultValue, bool clamp) noexcept |
978 | { |
979 | auto &e = QJsonPrivate::Value::elementHelper(r: self); |
980 | qint64 v = defaultValue; |
981 | if (e.type == QCborValue::Double) { |
982 | // convertDoubleTo modifies the output even on returning false |
983 | if (!convertDoubleTo<qint64>(v: e.fpvalue(), value: &v)) |
984 | v = defaultValue; |
985 | } else if (e.type == QCborValue::Integer) { |
986 | v = e.value; |
987 | } |
988 | if (clamp && qint64(int(v)) != v) |
989 | return defaultValue; |
990 | return v; |
991 | } |
992 | |
993 | double QJsonValueConstRef::concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept |
994 | { |
995 | auto &e = QJsonPrivate::Value::elementHelper(r: self); |
996 | if (e.type == QCborValue::Double) |
997 | return e.fpvalue(); |
998 | if (e.type == QCborValue::Integer) |
999 | return e.value; |
1000 | return defaultValue; |
1001 | } |
1002 | |
1003 | QString QJsonValueConstRef::concreteString(QJsonValueConstRef self, const QString &defaultValue) |
1004 | { |
1005 | const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self); |
1006 | qsizetype index = QJsonPrivate::Value::indexHelper(r: self); |
1007 | if (d->elements.at(i: index).type != QCborValue::String) |
1008 | return defaultValue; |
1009 | return d->stringAt(idx: index); |
1010 | } |
1011 | |
1012 | QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept |
1013 | { |
1014 | const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self); |
1015 | qsizetype index = QJsonPrivate::Value::indexHelper(r: self); |
1016 | return QJsonPrivate::Value::fromTrustedCbor(v: d->valueAt(idx: index)); |
1017 | } |
1018 | |
1019 | QString QJsonValueConstRef::objectKey(QJsonValueConstRef self) |
1020 | { |
1021 | Q_ASSERT(self.is_object); |
1022 | Q_ASSERT(self.is_object); |
1023 | const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self); |
1024 | qsizetype index = QJsonPrivate::Value::indexHelper(r: self); |
1025 | |
1026 | Q_ASSERT(d); |
1027 | Q_ASSERT(index < d->elements.size()); |
1028 | return d->stringAt(idx: index - 1); |
1029 | } |
1030 | |
1031 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) |
1032 | QVariant QJsonValueRef::toVariant() const |
1033 | { |
1034 | return QJsonValueConstRef::toVariant(); |
1035 | } |
1036 | |
1037 | QJsonArray QJsonValueRef::toArray() const |
1038 | { |
1039 | return QJsonValueConstRef::toArray(); |
1040 | } |
1041 | |
1042 | QJsonObject QJsonValueRef::toObject() const |
1043 | { |
1044 | return QJsonValueConstRef::toObject(); |
1045 | } |
1046 | |
1047 | QJsonValue QJsonValueRef::toValue() const |
1048 | { |
1049 | return concrete(self: *this); |
1050 | } |
1051 | #else |
1052 | QJsonValueRef QJsonValueRef::operator[](qsizetype key) |
1053 | { |
1054 | if (d->elements.at(index).type != QCborValue::Array) |
1055 | d->replaceAt(index, QCborValue::Array); |
1056 | |
1057 | auto &e = d->elements[index]; |
1058 | e.container = QCborContainerPrivate::grow(e.container, key); // detaches |
1059 | e.flags |= QtCbor::Element::IsContainer; |
1060 | |
1061 | return QJsonValueRef(e.container, key, false); |
1062 | } |
1063 | |
1064 | QJsonValueRef QJsonValueRef::operator[](QAnyStringView key) |
1065 | { |
1066 | // must go through QJsonObject because some of the machinery is non-static |
1067 | // member or file-static in qjsonobject.cpp |
1068 | QJsonObject o = QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index)).toObject(); |
1069 | QJsonValueRef ret = key.visit([&](auto v) { |
1070 | if constexpr (std::is_same_v<decltype(v), QUtf8StringView>) |
1071 | return o[QString::fromUtf8(v)]; |
1072 | else |
1073 | return o[v]; |
1074 | }); |
1075 | |
1076 | // ### did the QJsonObject::operator[] above detach? |
1077 | QCborContainerPrivate *x = o.o.take(); |
1078 | Q_ASSERT(x->ref.loadRelaxed() == 1); |
1079 | |
1080 | auto &e = d->elements[index]; |
1081 | if (e.flags & QtCbor::Element::IsContainer && e.container != x) |
1082 | o.o.reset(e.container); // might not an object! |
1083 | |
1084 | e.flags |= QtCbor::Element::IsContainer; |
1085 | e.container = x; |
1086 | |
1087 | return ret; |
1088 | } |
1089 | #endif |
1090 | |
1091 | size_t qHash(const QJsonValue &value, size_t seed) |
1092 | { |
1093 | switch (value.type()) { |
1094 | case QJsonValue::Null: |
1095 | return qHash(nullptr, seed); |
1096 | case QJsonValue::Bool: |
1097 | return qHash(t: value.toBool(), seed); |
1098 | case QJsonValue::Double: |
1099 | return qHash(key: value.toDouble(), seed); |
1100 | case QJsonValue::String: |
1101 | return qHash(key: value.toString(), seed); |
1102 | case QJsonValue::Array: |
1103 | return qHash(array: value.toArray(), seed); |
1104 | case QJsonValue::Object: |
1105 | return qHash(object: value.toObject(), seed); |
1106 | case QJsonValue::Undefined: |
1107 | return seed; |
1108 | } |
1109 | Q_UNREACHABLE_RETURN(0); |
1110 | } |
1111 | |
1112 | #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) |
1113 | QDebug operator<<(QDebug dbg, const QJsonValue &o) |
1114 | { |
1115 | QDebugStateSaver saver(dbg); |
1116 | switch (o.value.type()) { |
1117 | case QCborValue::Undefined: |
1118 | dbg << "QJsonValue(undefined)"; |
1119 | break; |
1120 | case QCborValue::Null: |
1121 | dbg << "QJsonValue(null)"; |
1122 | break; |
1123 | case QCborValue::True: |
1124 | case QCborValue::False: |
1125 | dbg.nospace() << "QJsonValue(bool, "<< o.toBool() << ')'; |
1126 | break; |
1127 | case QCborValue::Integer: |
1128 | dbg.nospace() << "QJsonValue(double, "<< o.toInteger() << ')'; |
1129 | break; |
1130 | case QCborValue::Double: |
1131 | dbg.nospace() << "QJsonValue(double, "<< o.toDouble() << ')'; |
1132 | break; |
1133 | case QCborValue::String: |
1134 | dbg.nospace() << "QJsonValue(string, "<< o.toString() << ')'; |
1135 | break; |
1136 | case QCborValue::Array: |
1137 | dbg.nospace() << "QJsonValue(array, "; |
1138 | dbg << o.toArray(); |
1139 | dbg << ')'; |
1140 | break; |
1141 | case QCborValue::Map: |
1142 | dbg.nospace() << "QJsonValue(object, "; |
1143 | dbg << o.toObject(); |
1144 | dbg << ')'; |
1145 | break; |
1146 | default: |
1147 | Q_UNREACHABLE(); |
1148 | } |
1149 | return dbg; |
1150 | } |
1151 | #endif |
1152 | |
1153 | #ifndef QT_NO_DATASTREAM |
1154 | QDataStream &operator<<(QDataStream &stream, const QJsonValue &v) |
1155 | { |
1156 | quint8 type = v.type(); |
1157 | stream << type; |
1158 | switch (type) { |
1159 | case QJsonValue::Undefined: |
1160 | case QJsonValue::Null: |
1161 | break; |
1162 | case QJsonValue::Bool: |
1163 | stream << v.toBool(); |
1164 | break; |
1165 | case QJsonValue::Double: |
1166 | stream << v.toDouble(); |
1167 | break; |
1168 | case QJsonValue::String: |
1169 | stream << v.toString(); |
1170 | break; |
1171 | case QJsonValue::Array: |
1172 | stream << v.toArray(); |
1173 | break; |
1174 | case QJsonValue::Object: |
1175 | stream << v.toObject(); |
1176 | break; |
1177 | } |
1178 | return stream; |
1179 | } |
1180 | |
1181 | QDataStream &operator>>(QDataStream &stream, QJsonValue &v) |
1182 | { |
1183 | quint8 type; |
1184 | stream >> type; |
1185 | switch (type) { |
1186 | case QJsonValue::Undefined: |
1187 | case QJsonValue::Null: |
1188 | v = QJsonValue{QJsonValue::Type(type)}; |
1189 | break; |
1190 | case QJsonValue::Bool: { |
1191 | bool b; |
1192 | stream >> b; |
1193 | v = QJsonValue(b); |
1194 | break; |
1195 | } case QJsonValue::Double: { |
1196 | double d; |
1197 | stream >> d; |
1198 | v = QJsonValue{d}; |
1199 | break; |
1200 | } case QJsonValue::String: { |
1201 | QString s; |
1202 | stream >> s; |
1203 | v = QJsonValue{s}; |
1204 | break; |
1205 | } |
1206 | case QJsonValue::Array: { |
1207 | QJsonArray a; |
1208 | stream >> a; |
1209 | v = QJsonValue{a}; |
1210 | break; |
1211 | } |
1212 | case QJsonValue::Object: { |
1213 | QJsonObject o; |
1214 | stream >> o; |
1215 | v = QJsonValue{o}; |
1216 | break; |
1217 | } |
1218 | default: { |
1219 | stream.setStatus(QDataStream::ReadCorruptData); |
1220 | v = QJsonValue{QJsonValue::Undefined}; |
1221 | } |
1222 | } |
1223 | return stream; |
1224 | } |
1225 | #endif |
1226 | |
1227 | QT_END_NAMESPACE |
1228 |
Definitions
- convertFromCborType
- QJsonValue
- QJsonValue
- doubleValueHelper
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- QJsonValue
- ~QJsonValue
- QJsonValue
- operator =
- QJsonValue
- swap
- fromVariant
- toVariant
- type
- toBool
- toInt
- toInteger
- toDouble
- toString
- toString
- toArray
- toArray
- toObject
- toObject
- operator[]
- operator[]
- operator[]
- operator[]
- comparesEqual
- detach
- assignToRef
- operator =
- operator =
- toVariant
- toArray
- toObject
- concreteType
- concreteBool
- concreteInt
- concreteDouble
- concreteString
- concrete
- objectKey
- toVariant
- toArray
- toObject
- toValue
- qHash
- operator<<
- operator<<
Start learning QML with our Intro Training
Find out more