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