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