summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization')
-rw-r--r--src/corelib/serialization/qcborarray.cpp1221
-rw-r--r--src/corelib/serialization/qcborarray.h303
-rw-r--r--src/corelib/serialization/qcborcommon.h147
-rw-r--r--src/corelib/serialization/qcbordiagnostic.cpp347
-rw-r--r--src/corelib/serialization/qcbormap.cpp1766
-rw-r--r--src/corelib/serialization/qcbormap.h357
-rw-r--r--src/corelib/serialization/qcborstream.cpp2705
-rw-r--r--src/corelib/serialization/qcborstream.h267
-rw-r--r--src/corelib/serialization/qcborvalue.cpp2477
-rw-r--r--src/corelib/serialization/qcborvalue.h467
-rw-r--r--src/corelib/serialization/qcborvalue_p.h399
-rw-r--r--src/corelib/serialization/qdatastream.cpp11
-rw-r--r--src/corelib/serialization/qdatastream.h5
-rw-r--r--src/corelib/serialization/qjson.cpp1
-rw-r--r--src/corelib/serialization/qjson_p.h32
-rw-r--r--src/corelib/serialization/qjsonarray.cpp4
-rw-r--r--src/corelib/serialization/qjsonarray.h2
-rw-r--r--src/corelib/serialization/qjsoncbor.cpp954
-rw-r--r--src/corelib/serialization/qjsondocument.cpp16
-rw-r--r--src/corelib/serialization/qjsonobject.cpp11
-rw-r--r--src/corelib/serialization/qjsonobject.h2
-rw-r--r--src/corelib/serialization/qjsonparser.cpp1
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp52
-rw-r--r--src/corelib/serialization/qjsonvalue.h3
-rw-r--r--src/corelib/serialization/qtextstream.cpp15
-rw-r--r--src/corelib/serialization/qtextstream.h1
-rw-r--r--src/corelib/serialization/qxmlstream.cpp2
-rw-r--r--src/corelib/serialization/serialization.pri16
28 files changed, 11534 insertions, 50 deletions
diff --git a/src/corelib/serialization/qcborarray.cpp b/src/corelib/serialization/qcborarray.cpp
new file mode 100644
index 0000000000..c56536cdb1
--- /dev/null
+++ b/src/corelib/serialization/qcborarray.cpp
@@ -0,0 +1,1221 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborarray.h"
+#include "qcborvalue_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtCbor;
+
+/*!
+ \class QCborArray
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborArray class is used to hold an array of CBOR elements.
+
+ This class can be used to hold one sequential container in CBOR (an array).
+ CBOR is the Concise Binary Object Representation, a very compact form of
+ binary data encoding that is a superset of JSON. It was created by the IETF
+ Constrained RESTful Environments (CoRE) WG, which has used it in many new
+ RFCs. It is meant to be used alongside the
+ \l{https://tools.ietf.org/html/rfc7252}{CoAP protocol}.
+
+ QCborArray is very similar to \l QVariantList and \l QJsonArray and its API
+ is almost identical to those two classes. It can also be converted to and
+ from those two, though there may be loss of information in some
+ conversions.
+
+ \sa QCborValue, QCborMap, QJsonArray, QList, QVector
+ */
+
+/*!
+ \typedef QCborArray::size_type
+
+ A typedef to qsizetype.
+ */
+
+/*!
+ \typedef QCborArray::difference_type
+
+ A typedef to qsizetype.
+ */
+
+/*!
+ \typedef QCborArray::value_type
+
+ The type of values that can be held in a QCborArray: that is, QCborValue.
+ */
+
+/*!
+ \typedef QCborArray::pointer
+
+ A typedef to \c{QCborValue *}, for compatibility with generic algorithms.
+ */
+
+/*!
+ \typedef QCborArray::const_pointer
+
+ A typedef to \c{const QCborValue *}, for compatibility with generic algorithms.
+ */
+
+/*!
+ \typedef QCborArray::reference
+
+ A typedef to \c{QCborValue &}, for compatibility with generic algorithms.
+ */
+
+/*!
+ \typedef QCborArray::const_reference
+
+ A typedef to \c{const QCborValue &}, for compatibility with generic algorithms.
+ */
+
+/*!
+ Constructs an empty QCborArray.
+ */
+QCborArray::QCborArray() noexcept
+ : d(nullptr)
+{
+}
+
+/*!
+ Copies the contents of \a other into this object.
+ */
+QCborArray::QCborArray(const QCborArray &other) noexcept
+ : d(other.d)
+{
+}
+
+/*!
+ \fn QCborArray::QCborArray(std::initializer_list<QCborValue> args)
+
+ Initializes this QCborArray from the C++ brace-enclosed list found in \a
+ args, as in the following example:
+
+ \code
+ QCborArray a = { null, 0, 1, 1.5, 2, "Hello", QByteArray("World") };
+ \endcode
+ */
+
+/*!
+ Destroys this QCborArray and frees any associated resources.
+ */
+QCborArray::~QCborArray()
+{
+}
+
+/*!
+ Replaces the contents of this array with that found in \a other, then
+ returns a reference to this object.
+ */
+QCborArray &QCborArray::operator=(const QCborArray &other) noexcept
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn void QCborArray::swap(QCborArray &other)
+
+ Swaps the contents of this object and \a other.
+ */
+
+/*!
+ \fn QCborValue QCborArray::toCborValue() const
+
+ Explicitly construcuts a \l QCborValue object that represents this array.
+ This function is usually not necessary since QCborValue has a constructor
+ for QCborArray, so the conversion is implicit.
+
+ Converting QCborArray to QCborValue allows it to be used in any context
+ where QCborValues can be used, including as items in QCborArrays and as keys
+ and mapped types in QCborMap. Converting an array to QCborValue allows
+ access to QCborValue::toCbor().
+
+ \sa QCborValue::QCborValue(const QCborArray &)
+ */
+
+/*!
+ Returns the size of this array.
+
+ \sa isEmpty()
+ */
+qsizetype QCborArray::size() const noexcept
+{
+ return d ? d->elements.size() : 0;
+}
+
+/*!
+ Empties this array.
+
+ \sa isEmpty()
+ */
+void QCborArray::clear()
+{
+ d.reset();
+}
+
+/*!
+ \fn bool QCborArray::isEmpty() const
+
+ Returns true if this QCborArray is empty (that is if size() is 0).
+
+ \sa size(), clear()
+ */
+
+/*!
+ Returns the QCborValue element at position \a i in the array.
+
+ If the array is smaller than \a i elements, this function returns a
+ QCborValue containing an undefined value. For that reason, it is not
+ possible with this function to tell apart the situation where the array is
+ not large enough from the case where the array starts with an undefined
+ value.
+
+ \sa operator[](), first(), last(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+QCborValue QCborArray::at(qsizetype i) const
+{
+ if (!d || size_t(i) >= size_t(size()))
+ return QCborValue();
+ return d->valueAt(i);
+}
+
+/*!
+ \fn QCborValue QCborArray::first() const
+
+ Returns the first QCborValue of this array.
+
+ If the array is empty, this function returns a QCborValue containing an
+ undefined value. For that reason, it is not possible with this function to
+ tell apart the situation where the array is not large enough from the case
+ where the array ends with an undefined value.
+
+ \sa operator[](), at(), last(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn QCborValue QCborArray::last() const
+
+ Returns the last QCborValue of this array.
+
+ If the array is empty, this function returns a QCborValue containing an
+ undefined value. For that reason, it is not possible with this function to
+ tell apart the situation where the array is not large enough from the case
+ where the array ends with an undefined value.
+
+ \sa operator[](), at(), first(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn QCborValue QCborArray::operator[](qsizetype i) const
+
+ Returns the QCborValue element at position \a i in the array.
+
+ If the array is smaller than \a i elements, this function returns a
+ QCborValue containing an undefined value. For that reason, it is not
+ possible with this function to tell apart the situation where the array is
+ not large enough from the case where the array contains an undefined value
+ at position \a i.
+
+ \sa at(), first(), last(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn QCborValueRef QCborArray::first()
+
+ Returns a reference to the first QCborValue of this array. The array must
+ not be empty.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ \sa operator[](), at(), last(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn QCborValueRef QCborArray::last()
+
+ Returns a reference to the last QCborValue of this array. The array must
+ not be empty.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ \sa operator[](), at(), first(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn QCborValueRef QCborArray::operator[](qsizetype i)
+
+ Returns a reference to the QCborValue element at position \a i in the
+ array. Indices beyond the end of the array will grow the array, filling
+ with undefined entries, until it has an entry at the specified index.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ \sa at(), first(), last(), insert(), prepend(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn void QCborArray::insert(qsizetype i, const QCborValue &value)
+ \fn void QCborArray::insert(qsizetype i, QCborValue &&value)
+
+ Inserts \a value into the array at position \a i in this array. If \a i is
+ -1, the entry is appended to the array. Pads the array with invalid entries
+ if \a i is greater than the prior size of the array.
+
+ \sa at(), operator[](), first(), last(), prepend(), append(),
+ removeAt(), takeAt(), extract()
+ */
+void QCborArray::insert(qsizetype i, const QCborValue &value)
+{
+ if (i < 0) {
+ Q_ASSERT(i == -1);
+ i = size();
+ detach(i + 1);
+ } else {
+ d = QCborContainerPrivate::grow(d.data(), i); // detaches
+ }
+ d->insertAt(i, value);
+}
+
+void QCborArray::insert(qsizetype i, QCborValue &&value)
+{
+ if (i < 0) {
+ Q_ASSERT(i == -1);
+ i = size();
+ detach(i + 1);
+ } else {
+ d = QCborContainerPrivate::grow(d.data(), i); // detaches
+ }
+ d->insertAt(i, value, QCborContainerPrivate::MoveContainer);
+ QCborContainerPrivate::resetValue(value);
+}
+
+/*!
+ \fn QCborValue QCborArray::extract(Iterator it)
+ \fn QCborValue QCborArray::extract(ConstIterator it)
+
+ Extracts a value from the array at the position indicated by iterator \a it
+ and returns the value so extracted.
+
+ \sa insert(), erase(), takeAt(), removeAt()
+ */
+QCborValue QCborArray::extract(iterator it)
+{
+ detach();
+
+ QCborValue v = d->extractAt(it.item.i);
+ d->removeAt(it.item.i);
+ return v;
+}
+
+/*!
+ \fn void QCborArray::prepend(const QCborValue &value)
+ \fn void QCborArray::prepend(QCborValue &&value)
+
+ Prepends \a value into the array before any other elements it may already
+ contain.
+
+ \sa at(), operator[](), first(), last(), insert(), append(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ \fn void QCborArray::append(const QCborValue &value)
+ \fn void QCborArray::append(QCborValue &&value)
+
+ Appends \a value into the array after all other elements it may already
+ contain.
+
+ \sa at(), operator[](), first(), last(), insert(), prepend(),
+ removeAt(), takeAt()
+ */
+
+/*!
+ Removes the item at position \a i from the array. The array must have more
+ than \a i elements before the removal.
+
+ \sa takeAt(), removeFirst(), removeLast(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+void QCborArray::removeAt(qsizetype i)
+{
+ detach(size());
+ d->removeAt(i);
+}
+
+/*!
+ \fn QCborValue QCborArray::takeAt(qsizetype i)
+
+ Removes the item at position \a i from the array and returns it. The array
+ must have more than \a i elements before the removal.
+
+ \sa removeAt(), removeFirst(), removeLast(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+
+/*!
+ \fn void QCborArray::removeFirst()
+
+ Removes the first item in the array, making the second element become the
+ first. The array must not be empty before this call.
+
+ \sa removeAt(), takeFirst(), removeLast(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+
+/*!
+ \fn void QCborArray::removeLast()
+
+ Removes the last item in the array. The array must not be empty before this
+ call.
+
+ \sa removeAt(), takeLast(), removeFirst(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+
+/*!
+ \fn void QCborArray::takeFirst()
+
+ Removes the first item in the array and returns it, making the second
+ element become the first. The array must not be empty before this call.
+
+ \sa takeAt(), removeFirst(), removeLast(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+
+/*!
+ \fn void QCborArray::takeLast()
+
+ Removes the last item in the array and returns it. The array must not be
+ empty before this call.
+
+ \sa takeAt(), removeLast(), removeFirst(), at(), operator[](), insert(),
+ prepend(), append()
+ */
+
+/*!
+ Returns true if this array contains an element that is equal to \a value.
+ */
+bool QCborArray::contains(const QCborValue &value) const
+{
+ for (qsizetype i = 0; i < size(); ++i) {
+ int cmp = d->compareElement(i, value);
+ if (cmp == 0)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \fn int QCborArray::compare(const QCborArray &other) const
+
+ Compares this array and \a other, comparing each element in sequence, and
+ returns an integer that indicates whether this array should be sorted
+ before (if the result is negative) or after \a other (if the result is
+ positive). If this function returns 0, the two arrays are equal and contain
+ the same elements.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa QCborValue::compare(), QCborMap::compare(), operator==()
+ */
+
+/*!
+ \fn bool QCborArray::operator==(const QCborArray &other) const
+
+ Compares this array and \a other, comparing each element in sequence, and
+ returns true if both arrays contains the same elements, false otherwise.
+
+ For more information on CBOR equality in Qt, see, QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator!=(), operator<()
+ */
+
+/*!
+ \fn bool QCborArray::operator!=(const QCborArray &other) const
+
+ Compares this array and \a other, comparing each element in sequence, and
+ returns true if the two arrays' contents are different, false otherwise.
+
+ For more information on CBOR equality in Qt, see, QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator<()
+ */
+
+/*!
+ \fn bool QCborArray::operator<(const QCborArray &other) const
+
+ Compares this array and \a other, comparing each element in sequence, and
+ returns true if this array should be sorted before \a other, false
+ otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+ */
+
+/*!
+ \typedef QCborArray::iterator
+
+ A synonym to QCborArray::Iterator.
+ */
+
+/*!
+ \typedef QCborArray::const_iterator
+
+ A synonym to QCborArray::ConstIterator.
+ */
+
+/*!
+ \fn QCborArray::iterator QCborArray::begin()
+
+ Returns an array iterator pointing to the first item in this array. If the
+ array is empty, then this function returns the same as end().
+
+ \sa constBegin(), end()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::begin() const
+
+ Returns an array iterator pointing to the first item in this array. If the
+ array is empty, then this function returns the same as end().
+
+ \sa constBegin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::cbegin() const
+
+ Returns an array iterator pointing to the first item in this array. If the
+ array is empty, then this function returns the same as end().
+
+ \sa constBegin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::constBegin() const
+
+ Returns an array iterator pointing to the first item in this array. If the
+ array is empty, then this function returns the same as end().
+
+ \sa begin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::iterator QCborArray::end()
+
+ Returns an array iterator pointing to just after the last element in this
+ array.
+
+ \sa begin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::end() const
+
+ Returns an array iterator pointing to just after the last element in this
+ array.
+
+ \sa constBegin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::cend() const
+
+ Returns an array iterator pointing to just after the last element in this
+ array.
+
+ \sa constBegin(), constEnd()
+ */
+
+/*!
+ \fn QCborArray::const_iterator QCborArray::constEnd() const
+
+ Returns an array iterator pointing to just after the last element in this
+ array.
+
+ \sa constBegin(), end()
+ */
+
+/*!
+ \fn QCborArray::iterator QCborArray::insert(iterator before, const QCborValue &value)
+ \fn QCborArray::iterator QCborArray::insert(const_iterator before, const QCborValue &value)
+ \overload
+
+ Inserts \a value into this array before element \a before and returns an
+ array iterator pointing to the just-inserted element.
+
+ \sa erase(), removeAt(), prepend(), append()
+ */
+
+/*!
+ \fn QCborArray::iterator QCborArray::erase(iterator it)
+ \fn QCborArray::iterator QCborArray::erase(const_iterator it)
+
+ Removes the element pointed to by the array iterator \a it from this array,
+ then returns an iterator to the next element (the one that took the same
+ position in the array that \a it used to occupy).
+
+ \sa insert(), removeAt(), takeAt(), takeFirst(), takeLast()
+ */
+
+/*!
+ \fn void QCborArray::push_back(const QCborValue &t)
+
+ Synonym for append(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Appends the element \a t to this array.
+
+ \sa append(), push_front(), pop_back(), prepend(), insert()
+ */
+
+/*!
+ \fn void QCborArray::push_front(const QCborValue &t)
+
+ Synonym for prepend(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Prepends the element \a t to this array.
+
+ \sa prepend(), push_back(), pop_front(), append(), insert()
+ */
+
+/*!
+ \fn void QCborArray::pop_front()
+
+ Synonym for removeFirst(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Removes the first element of this array. The array must not be empty before
+ the removal
+
+ \sa removeFirst(), takeFirst(), pop_back(), push_front(), prepend(), insert()
+ */
+
+/*!
+ \fn void QCborArray::pop_back()
+
+ Synonym for removeLast(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Removes the last element of this array. The array must not be empty before
+ the removal
+
+ \sa removeLast(), takeLast(), pop_front(), push_back(), append(), insert()
+ */
+
+/*!
+ \fn bool QCborArray::empty() const
+
+ Synonym for isEmpty(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Returns true if this array is empty (size() == 0).
+
+ \sa isEmpty(), size()
+ */
+
+/*!
+ \fn QCborArray QCborArray::operator+(const QCborValue &v) const
+
+ Returns a new QCborArray containing the same elements as this array, plus
+ \a v appended as the last element.
+
+ \sa operator+=(), operator<<(), append()
+ */
+
+/*!
+ \fn QCborArray &QCborArray::operator+=(const QCborValue &v)
+
+ Appends \a v to this array and returns a reference to this array.
+
+ \sa append(), insert(), operator+(), operator<<()
+ */
+
+/*!
+ \fn QCborArray &QCborArray::operator<<(const QCborValue &v)
+
+ Appends \a v to this array and returns a reference to this array.
+
+ \sa append(), insert(), operator+(), operator+=()
+ */
+
+void QCborArray::detach(qsizetype reserved)
+{
+ d = QCborContainerPrivate::detach(d.data(), reserved ? reserved : size());
+}
+
+/*!
+ \class QCborArray::Iterator
+ \inmodule QtCore
+ \ingroup cbor
+ \since 5.12
+
+ \brief The QCborArray::Iterator class provides an STL-style non-const iterator for QCborArray.
+
+ QCborArray::Iterator allows you to iterate over a QCborArray and to modify
+ the array item associated with the iterator. If you want to iterate over a
+ const QCborArray, use QCborArray::ConstIterator instead. It is generally a
+ good practice to use QCborArray::ConstIterator on a non-const QCborArray as
+ well, unless you need to change the QCborArray through the iterator. Const
+ iterators are slightly faster and improve code readability.
+
+ Iterators are initialized by using a QCborArray function like
+ QCborArray::begin(), QCborArray::end(), or QCborArray::insert(). Iteration
+ is only possible after that.
+
+ Most QCborArray functions accept an integer index rather than an iterator.
+ For that reason, iterators are rarely useful in connection with QCborArray.
+ One place where STL-style iterators do make sense is as arguments to
+ \l{generic algorithms}.
+
+ Multiple iterators can be used on the same array. However, be aware that
+ any non-const function call performed on the QCborArray will render all
+ existing iterators undefined.
+
+ \sa QCborArray::ConstIterator
+*/
+
+/*!
+ \typedef QCborArray::Iterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating this iterator
+ is a random access iterator.
+ */
+
+/*!
+ \typedef QCborArray::Iterator::difference_type
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::Iterator::value_type
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::Iterator::reference
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::Iterator::pointer
+ \internal
+*/
+
+/*!
+ \fn QCborArray::Iterator::Iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like operator*() and operator++() should not be called on an
+ uninitialized iterator. Use operator=() to assign a value to it before
+ using it.
+
+ \sa QCborArray::begin(), QCborArray::end()
+*/
+
+/*!
+ \fn QCborArray::Iterator::Iterator(const Iterator &other)
+
+ Makes a copy of \a other.
+ */
+
+/*!
+ \fn QCborArray::Iterator &QCborArray::Iterator::operator=(const Iterator &other)
+
+ Makes this iterator a copy of \a other and returns a reference to this iterator.
+ */
+
+/*!
+ \fn QCborValueRef QCborArray::Iterator::operator*() const
+
+ Returns a modifiable reference to the current item.
+
+ You can change the value of an item by using operator*() on the left side
+ of an assignment.
+
+ The return value is of type QCborValueRef, a helper class for QCborArray
+ and QCborMap. When you get an object of type QCborValueRef, you can use it
+ as if it were a reference to a QCborValue. If you assign to it, the
+ assignment will apply to the element in the QCborArray or QCborMap from
+ which you got the reference.
+*/
+
+/*!
+ \fn QCborValueRef *QCborArray::Iterator::operator->() const
+
+ Returns a pointer to a modifiable reference to the current item.
+*/
+
+/*!
+ \fn QCborValueRef QCborArray::Iterator::operator[](qsizetype j)
+
+ Returns a modifiable reference to the item at a position \a j steps forward
+ from the item pointed to by this iterator.
+
+ This function is provided to make QCborArray iterators behave like C++
+ pointers.
+
+ The return value is of type QCborValueRef, a helper class for QCborArray
+ and QCborMap. When you get an object of type QCborValueRef, you can use it
+ as if it were a reference to a QCborValue. If you assign to it, the
+ assignment will apply to the element in the QCborArray or QCborMap from
+ which you got the reference.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn bool QCborArray::Iterator::operator==(const Iterator &other) const
+ \fn bool QCborArray::Iterator::operator==(const ConstIterator &other) const
+
+ Returns \c true if \a other points to the same entry in the array as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QCborArray::Iterator::operator!=(const Iterator &other) const
+ \fn bool QCborArray::Iterator::operator!=(const ConstIterator &other) const
+
+ Returns \c true if \a other points to a different entry in the array than
+ this iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool QCborArray::Iterator::operator<(const Iterator& other) const
+ \fn bool QCborArray::Iterator::operator<(const ConstIterator& other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs before the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborArray::Iterator::operator<=(const Iterator& other) const
+ \fn bool QCborArray::Iterator::operator<=(const ConstIterator& other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs before or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn bool QCborArray::Iterator::operator>(const Iterator& other) const
+ \fn bool QCborArray::Iterator::operator>(const ConstIterator& other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs after the entry pointed to by the \a other iterator.
+ */
+
+/*!
+ \fn bool QCborArray::Iterator::operator>=(const Iterator& other) const
+ \fn bool QCborArray::Iterator::operator>=(const ConstIterator& other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs after or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn QCborArray::Iterator &QCborArray::Iterator::operator++()
+
+ The prefix ++ operator, \c{++it}, advances the iterator to the next item in
+ the array and returns this iterator.
+
+ Calling this function on QCborArray::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*!
+ \fn QCborArray::Iterator QCborArray::Iterator::operator++(int)
+ \overload
+
+ The postfix ++ operator, \c{it++}, advances the iterator to the next item
+ in the array and returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QCborArray::Iterator &QCborArray::Iterator::operator--()
+
+ The prefix -- operator, \c{--it}, makes the preceding item current and
+ returns this iterator.
+
+ Calling this function on QCborArray::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*!
+ \fn QCborArray::Iterator QCborArray::Iterator::operator--(int)
+ \overload
+
+ The postfix -- operator, \c{it--}, makes the preceding item current and
+ returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QCborArray::Iterator &QCborArray::Iterator::operator+=(qsizetype j)
+
+ Advances the iterator by \a j positions. If \a j is negative, the iterator
+ goes backward. Returns a reference to this iterator.
+
+ \sa operator-=(), operator+()
+*/
+
+/*!
+ \fn QCborArray::Iterator &QCborArray::Iterator::operator-=(qsizetype j)
+
+ Makes the iterator go back by \a j positions. If \a j is negative, the
+ iterator goes forward. Returns a reference to this iterator.
+
+ \sa operator+=(), operator-()
+*/
+
+/*!
+ \fn QCborArray::Iterator QCborArray::Iterator::operator+(qsizetype j) const
+
+ Returns an iterator to the item at position \a j steps forward from this
+ iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-(), operator+=()
+*/
+
+/*!
+ \fn QCborArray::Iterator QCborArray::Iterator::operator-(qsizetype j) const
+
+ Returns an iterator to the item at position \a j steps backward from this
+ iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+(), operator-=()
+*/
+
+/*!
+ \fn qsizetype QCborArray::Iterator::operator-(Iterator other) const
+
+ Returns the offset of this iterator relative to \a other.
+*/
+
+/*!
+ \class QCborArray::ConstIterator
+ \inmodule QtCore
+ \ingroup cbor
+ \since 5.12
+
+ \brief The QCborArray::ConstIterator class provides an STL-style const iterator for QCborArray.
+
+ QCborArray::ConstIterator allows you to iterate over a QCborArray. If you
+ want to modify the QCborArray as you iterate over it, use
+ QCborArray::Iterator instead. It is generally good practice to use
+ QCborArray::ConstIterator, even on a non-const QCborArray, when you don't
+ need to change the QCborArray through the iterator. Const iterators are
+ slightly faster and improves code readability.
+
+ Iterators are initialized by using a QCborArray function like
+ QCborArray::begin() or QCborArray::end(). Iteration is only possible after
+ that.
+
+ Most QCborArray functions accept an integer index rather than an iterator.
+ For that reason, iterators are rarely useful in connection with QCborArray.
+ One place where STL-style iterators do make sense is as arguments to
+ \l{generic algorithms}.
+
+ Multiple iterators can be used on the same array. However, be aware that
+ any non-const function call performed on the QCborArray will render all
+ existing iterators undefined.
+
+ \sa QCborArray::Iterator
+*/
+
+/*!
+ \fn QCborArray::ConstIterator::ConstIterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like operator*() and operator++() should not be called on an
+ uninitialized iterator. Use operator=() to assign a value to it before
+ using it.
+
+ \sa QCborArray::constBegin(), QCborArray::constEnd()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator=(const ConstIterator &other)
+
+ Makes this iterator a copy of \a other and returns a reference to this iterator.
+*/
+
+/*!
+ \typedef QCborArray::ConstIterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating this iterator
+ is a random access iterator.
+*/
+
+/*!
+ \typedef QCborArray::ConstIterator::difference_type
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::ConstIterator::value_type
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::ConstIterator::reference
+ \internal
+*/
+
+/*!
+ \typedef QCborArray::ConstIterator::pointer
+ \internal
+*/
+
+/*!
+ \fn QCborArray::ConstIterator::ConstIterator(const ConstIterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn QCborValue QCborArray::ConstIterator::operator*() const
+
+ Returns the current item.
+*/
+
+/*!
+ \fn const QCborValue *QCborArray::ConstIterator::operator->() const
+
+ Returns a pointer to the current item.
+*/
+
+/*!
+ \fn const QCborValueRef QCborArray::ConstIterator::operator[](qsizetype j)
+
+ Returns the item at a position \a j steps forward from the item pointed to
+ by this iterator.
+
+ This function is provided to make QCborArray iterators behave like C++
+ pointers.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator==(const Iterator &other) const
+ \fn bool QCborArray::ConstIterator::operator==(const ConstIterator &other) const
+
+ Returns \c true if \a other points to the same entry in the array as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator!=(const Iterator &o) const
+ \fn bool QCborArray::ConstIterator::operator!=(const ConstIterator &o) const
+
+ Returns \c true if \a o points to a different entry in the array than
+ this iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator<(const Iterator &other) const
+ \fn bool QCborArray::ConstIterator::operator<(const ConstIterator &other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs before the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator<=(const Iterator &other) const
+ \fn bool QCborArray::ConstIterator::operator<=(const ConstIterator &other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs before or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator>(const Iterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>(const ConstIterator &other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs after the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborArray::ConstIterator::operator>=(const Iterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>=(const ConstIterator &other) const
+
+ Returns \c true if the entry in the array pointed to by this iterator
+ occurs after or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator++()
+
+ The prefix ++ operator, \c{++it}, advances the iterator to the next item in
+ the array and returns this iterator.
+
+ Calling this function on QCborArray::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator QCborArray::ConstIterator::operator++(int)
+ \overload
+
+ The postfix ++ operator, \c{it++}, advances the iterator to the next item
+ in the array and returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator--()
+
+ The prefix -- operator, \c{--it}, makes the preceding item current and
+ returns this iterator.
+
+ Calling this function on QCborArray::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator QCborArray::ConstIterator::operator--(int)
+ \overload
+
+ The postfix -- operator, \c{it--}, makes the preceding item current and
+ returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator+=(qsizetype j)
+
+ Advances the iterator by \a j positions. If \a j is negative, the iterator
+ goes backward. Returns a reference to this iterator.
+
+ \sa operator-=(), operator+()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator-=(qsizetype j)
+
+ Makes the iterator go back by \a j positions. If \a j is negative, the
+ iterator goes forward. Returns a reference to this iterator.
+
+ \sa operator+=(), operator-()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator QCborArray::ConstIterator::operator+(qsizetype j) const
+
+ Returns an iterator to the item at a position \a j steps forward from this
+ iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-(), operator+=()
+*/
+
+/*!
+ \fn QCborArray::ConstIterator QCborArray::ConstIterator::operator-(qsizetype j) const
+
+ Returns an iterator to the item at a position \a j steps backward from this
+ iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+(), operator-=()
+*/
+
+/*!
+ \fn qsizetype QCborArray::ConstIterator::operator-(ConstIterator other) const
+
+ Returns the offset of this iterator relative to \a other.
+*/
+
+uint qHash(const QCborArray &array, uint seed)
+{
+ return qHashRange(array.begin(), array.end(), seed);
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug dbg, const QCborArray &a)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QCborArray{";
+ const char *comma = "";
+ for (auto v : a) {
+ dbg << comma << v;
+ comma = ", ";
+ }
+ return dbg << '}';
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h
new file mode 100644
index 0000000000..ed0f4912ba
--- /dev/null
+++ b/src/corelib/serialization/qcborarray.h
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORARRAY_H
+#define QCBORARRAY_H
+
+#include <QtCore/qcborvalue.h>
+
+#include <initializer_list>
+
+QT_BEGIN_NAMESPACE
+
+class QJsonArray;
+
+class QCborContainerPrivate;
+class Q_CORE_EXPORT QCborArray
+{
+public:
+ class ConstIterator;
+ class Iterator {
+ mutable QCborValueRef item;
+ friend class ConstIterator;
+ friend class QCborArray;
+ Iterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef qsizetype difference_type;
+ typedef QCborValue value_type;
+ typedef QCborValueRef reference;
+ typedef QCborValueRef *pointer;
+
+ Q_DECL_CONSTEXPR Iterator() = default;
+ Q_DECL_CONSTEXPR Iterator(const Iterator &) = default;
+ Iterator &operator=(const Iterator &other)
+ {
+ // rebind the reference
+ item.d = other.item.d;
+ item.i = other.item.i;
+ return *this;
+ }
+
+ QCborValueRef operator*() const { return item; }
+ QCborValueRef *operator->() const { return &item; }
+ QCborValueRef operator[](qsizetype j) { return { item.d, item.i + j }; }
+
+ bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ Iterator &operator++() { ++item.i; return *this; }
+ Iterator operator++(int) { Iterator n = *this; ++item.i; return n; }
+ Iterator &operator--() { item.i--; return *this; }
+ Iterator operator--(int) { Iterator n = *this; item.i--; return n; }
+ Iterator &operator+=(qsizetype j) { item.i += j; return *this; }
+ Iterator &operator-=(qsizetype j) { item.i -= j; return *this; }
+ Iterator operator+(qsizetype j) const { return Iterator({ item.d, item.i + j }); }
+ Iterator operator-(qsizetype j) const { return Iterator({ item.d, item.i - j }); }
+ qsizetype operator-(Iterator j) const { return item.i - j.item.i; }
+ };
+
+ class ConstIterator {
+ QCborValueRef item;
+ friend class Iterator;
+ friend class QCborArray;
+ ConstIterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef qsizetype difference_type;
+ typedef const QCborValue value_type;
+ typedef const QCborValueRef reference;
+ typedef const QCborValueRef *pointer;
+
+ Q_DECL_CONSTEXPR ConstIterator() = default;
+ Q_DECL_CONSTEXPR ConstIterator(const ConstIterator &) = default;
+ ConstIterator &operator=(const ConstIterator &other)
+ {
+ // rebind the reference
+ item.d = other.item.d;
+ item.i = other.item.i;
+ return *this;
+ }
+
+ const QCborValueRef operator*() const { return item; }
+ const QCborValueRef *operator->() const { return &item; }
+ const QCborValueRef operator[](qsizetype j) { return { item.d, item.i + j }; }
+
+ bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ ConstIterator &operator++() { ++item.i; return *this; }
+ ConstIterator operator++(int) { ConstIterator n = *this; ++item.i; return n; }
+ ConstIterator &operator--() { item.i--; return *this; }
+ ConstIterator operator--(int) { ConstIterator n = *this; item.i--; return n; }
+ ConstIterator &operator+=(qsizetype j) { item.i += j; return *this; }
+ ConstIterator &operator-=(qsizetype j) { item.i -= j; return *this; }
+ ConstIterator operator+(qsizetype j) const { return ConstIterator({ item.d, item.i + j }); }
+ ConstIterator operator-(qsizetype j) const { return ConstIterator({ item.d, item.i - j }); }
+ qsizetype operator-(ConstIterator j) const { return item.i - j.item.i; }
+ };
+
+ typedef qsizetype size_type;
+ typedef QCborValue value_type;
+ typedef value_type *pointer;
+ typedef const value_type *const_pointer;
+ typedef QCborValue &reference;
+ typedef const QCborValue &const_reference;
+ typedef qsizetype difference_type;
+
+ QCborArray() noexcept;
+ QCborArray(const QCborArray &other) noexcept;
+ QCborArray &operator=(const QCborArray &other) noexcept;
+ QCborArray(std::initializer_list<QCborValue> args)
+ : QCborArray()
+ {
+ detach(qsizetype(args.size()));
+ for (const QCborValue &v : args)
+ append(v);
+ }
+ ~QCborArray();
+
+ void swap(QCborArray &other) noexcept
+ {
+ qSwap(d, other.d);
+ }
+
+ QCborValue toCborValue() const { return *this; }
+
+ qsizetype size() const noexcept;
+ bool isEmpty() const { return size() == 0; }
+ void clear();
+
+ QCborValue at(qsizetype i) const;
+ QCborValue first() const { return at(0); }
+ QCborValue last() const { return at(size() - 1); }
+ const QCborValue operator[](qsizetype i) const { return at(i); }
+ QCborValueRef first() { Q_ASSERT(!isEmpty()); return begin()[0]; }
+ QCborValueRef last() { Q_ASSERT(!isEmpty()); return begin()[size() - 1]; }
+ QCborValueRef operator[](qsizetype i)
+ {
+ if (i >= size())
+ insert(i, QCborValue());
+ return begin()[i];
+ }
+
+ void insert(qsizetype i, const QCborValue &value);
+ void insert(qsizetype i, QCborValue &&value);
+ void prepend(const QCborValue &value) { insert(0, value); }
+ void prepend(QCborValue &&value) { insert(0, std::move(value)); }
+ void append(const QCborValue &value) { insert(-1, value); }
+ void append(QCborValue &&value) { insert(-1, std::move(value)); }
+ QCborValue extract(ConstIterator it) { return extract(Iterator{ it.item.d, it.item.i }); }
+ QCborValue extract(Iterator it);
+ void removeAt(qsizetype i);
+ QCborValue takeAt(qsizetype i) { Q_ASSERT(i < size()); return extract(begin() + i); }
+ void removeFirst() { removeAt(0); }
+ void removeLast() { removeAt(size() - 1); }
+ QCborValue takeFirst() { return takeAt(0); }
+ QCborValue takeLast() { return takeAt(size() - 1); }
+
+ bool contains(const QCborValue &value) const;
+
+ int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION;
+#if 0 && QT_HAS_INCLUDE(<compare>)
+ std::strong_ordering operator<=>(const QCborArray &other) const
+ {
+ int c = compare(other);
+ if (c > 0) return std::strong_ordering::greater;
+ if (c == 0) return std::strong_ordering::equivalent;
+ return std::strong_ordering::less;
+ }
+#else
+ bool operator==(const QCborArray &other) const noexcept
+ { return compare(other) == 0; }
+ bool operator!=(const QCborArray &other) const noexcept
+ { return !(*this == other); }
+ bool operator<(const QCborArray &other) const
+ { return compare(other) < 0; }
+#endif
+
+ typedef Iterator iterator;
+ typedef ConstIterator const_iterator;
+ iterator begin() { detach(); return iterator{d.data(), 0}; }
+ const_iterator constBegin() const { return const_iterator{d.data(), 0}; }
+ const_iterator begin() const { return constBegin(); }
+ const_iterator cbegin() const { return constBegin(); }
+ iterator end() { detach(); return iterator{d.data(), size()}; }
+ const_iterator constEnd() const { return const_iterator{d.data(), size()}; }
+ const_iterator end() const { return constEnd(); }
+ const_iterator cend() const { return constEnd(); }
+ iterator insert(iterator before, const QCborValue &value)
+ { insert(before.item.i, value); return iterator{d.data(), before.item.i}; }
+ iterator insert(const_iterator before, const QCborValue &value)
+ { insert(before.item.i, value); return iterator{d.data(), before.item.i}; }
+ iterator erase(iterator it) { removeAt(it.item.i); return iterator{d.data(), it.item.i}; }
+ iterator erase(const_iterator it) { removeAt(it.item.i); return iterator{d.data(), it.item.i}; }
+
+ void push_back(const QCborValue &t) { append(t); }
+ void push_front(const QCborValue &t) { prepend(t); }
+ void pop_front() { removeFirst(); }
+ void pop_back() { removeLast(); }
+ bool empty() const { return isEmpty(); }
+
+ // convenience
+ QCborArray operator+(const QCborValue &v) const
+ { QCborArray n = *this; n += v; return n; }
+ QCborArray &operator+=(const QCborValue &v)
+ { append(v); return *this; }
+ QCborArray &operator<<(const QCborValue &v)
+ { append(v); return *this; }
+
+ static QCborArray fromStringList(const QStringList &list);
+ static QCborArray fromVariantList(const QVariantList &list);
+ static QCborArray fromJsonArray(const QJsonArray &array);
+ QVariantList toVariantList() const;
+ QJsonArray toJsonArray() const;
+
+private:
+ void detach(qsizetype reserve = 0);
+
+ friend QCborValue;
+ explicit QCborArray(QCborContainerPrivate &dd) noexcept;
+ QExplicitlySharedDataPointer<QCborContainerPrivate> d;
+};
+
+Q_DECLARE_SHARED(QCborArray)
+
+inline QCborValue::QCborValue(QCborArray &&a)
+ : n(-1), container(a.d.take()), t(Array)
+{
+}
+
+inline QCborArray QCborValueRef::toArray() const
+{
+ return concrete().toArray();
+}
+
+inline QCborArray QCborValueRef::toArray(const QCborArray &a) const
+{
+ return concrete().toArray(a);
+}
+
+Q_CORE_EXPORT uint qHash(const QCborArray &array, uint seed = 0);
+
+#if !defined(QT_NO_DEBUG_STREAM)
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborArray &a);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QCBORARRAY_H
diff --git a/src/corelib/serialization/qcborcommon.h b/src/corelib/serialization/qcborcommon.h
new file mode 100644
index 0000000000..9661cd70bb
--- /dev/null
+++ b/src/corelib/serialization/qcborcommon.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORCOMMON_H
+#define QCBORCOMMON_H
+
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qdebug.h>
+
+#if 0
+#pragma qt_class(QtCborCommon)
+#endif
+
+/* X11 headers use these values too, but as defines */
+#if defined(False) && defined(True)
+# define QT_X11_DEFINES_FOUND 1
+# undef True
+# undef False
+#endif
+
+QT_BEGIN_NAMESPACE
+
+enum class QCborSimpleType : quint8 {
+ False = 20,
+ True = 21,
+ Null = 22,
+ Undefined = 23
+};
+
+enum class QCborTag : quint64 {};
+enum class QCborKnownTags {
+ DateTimeString = 0,
+ UnixTime_t = 1,
+ PositiveBignum = 2,
+ NegativeBignum = 3,
+ Decimal = 4,
+ Bigfloat = 5,
+ COSE_Encrypt0 = 16,
+ COSE_Mac0 = 17,
+ COSE_Sign1 = 18,
+ ExpectedBase64url = 21,
+ ExpectedBase64 = 22,
+ ExpectedBase16 = 23,
+ EncodedCbor = 24,
+ Url = 32,
+ Base64url = 33,
+ Base64 = 34,
+ RegularExpression = 35,
+ MimeMessage = 36,
+ Uuid = 37,
+ COSE_Encrypt = 96,
+ COSE_Mac = 97,
+ COSE_Sign = 98,
+ Signature = 55799
+};
+
+inline bool operator==(QCborTag t, QCborKnownTags kt) { return quint64(t) == quint64(kt); }
+inline bool operator==(QCborKnownTags kt, QCborTag t) { return quint64(t) == quint64(kt); }
+inline bool operator!=(QCborTag t, QCborKnownTags kt) { return quint64(t) != quint64(kt); }
+inline bool operator!=(QCborKnownTags kt, QCborTag t) { return quint64(t) != quint64(kt); }
+
+struct Q_CORE_EXPORT QCborError
+{
+ Q_GADGET
+public:
+ enum Code : int {
+ UnknownError = 1,
+ AdvancePastEnd = 3,
+ InputOutputError = 4,
+ GarbageAtEnd = 256,
+ EndOfFile,
+ UnexpectedBreak,
+ UnknownType,
+ IllegalType,
+ IllegalNumber,
+ IllegalSimpleType,
+
+ InvalidUtf8String = 516,
+
+ DataTooLarge = 1024,
+ NestingTooDeep,
+ UnsupportedType,
+
+ NoError = 0
+ };
+ Q_ENUM(Code)
+
+ Code c;
+ operator Code() const { return c; }
+ QString toString() const;
+};
+
+#if !defined(QT_NO_DEBUG_STREAM)
+Q_CORE_EXPORT QDebug operator<<(QDebug, QCborSimpleType st);
+Q_CORE_EXPORT QDebug operator<<(QDebug, QCborKnownTags tg);
+Q_CORE_EXPORT QDebug operator<<(QDebug, QCborTag tg);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QCborTag)
+
+// To avoid changing namespace we need to reinstate defines, even though our .cpp
+// will then have to remove them again.
+#if defined(QT_X11_DEFINES_FOUND)
+# define True 1
+# define False 0
+#endif
+
+#endif // QCBORSTREAM_H
diff --git a/src/corelib/serialization/qcbordiagnostic.cpp b/src/corelib/serialization/qcbordiagnostic.cpp
new file mode 100644
index 0000000000..75feaded17
--- /dev/null
+++ b/src/corelib/serialization/qcbordiagnostic.cpp
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborvalue.h"
+#include "qcborvalue_p.h"
+
+#include "qcborarray.h"
+#include "qcbormap.h"
+
+#include <private/qnumeric_p.h>
+#include <qstack.h>
+#include <private/qtools_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+class DiagnosticNotation
+{
+public:
+ static QString create(const QCborValue &v, QCborValue::DiagnosticNotationOptions opts)
+ {
+ DiagnosticNotation dn(opts);
+ dn.appendValue(v);
+ return dn.result;
+ }
+
+private:
+ QStack<int> byteArrayFormatStack;
+ QString separator;
+ QString result;
+ QCborValue::DiagnosticNotationOptions opts;
+ int nestingLevel = 0;
+
+ struct Nest {
+ enum { IndentationWidth = 4 };
+ DiagnosticNotation *dn;
+ Nest(DiagnosticNotation *that) : dn(that)
+ {
+ ++dn->nestingLevel;
+ static const char indent[IndentationWidth + 1] = " ";
+ if (dn->opts & QCborValue::LineWrapped)
+ dn->separator += QLatin1String(indent, IndentationWidth);
+ }
+ ~Nest()
+ {
+ --dn->nestingLevel;
+ if (dn->opts & QCborValue::LineWrapped)
+ dn->separator.chop(IndentationWidth);
+ }
+ };
+
+ DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
+ : separator(QLatin1String(opts_ & QCborValue::LineWrapped ? "\n" : "")), opts(opts_)
+ {
+ byteArrayFormatStack.push(int(QCborKnownTags::ExpectedBase16));
+ }
+
+ void appendString(const QString &s);
+ void appendArray(const QCborArray &a);
+ void appendMap(const QCborMap &m);
+ void appendValue(const QCborValue &v);
+};
+}
+
+static QString makeFpString(double d)
+{
+ QString s;
+ quint64 v;
+ if (qt_is_inf(d)) {
+ s = (d < 0) ? QStringLiteral("-inf") : QStringLiteral("inf");
+ } else if (qt_is_nan(d)) {
+ s = QStringLiteral("nan");
+ } else if (convertDoubleTo(d, &v)) {
+ s = QString::fromLatin1("%1.0").arg(v);
+ if (d < 0)
+ s.prepend(QLatin1Char('-'));
+ } else {
+ s = QString::number(d, 'g', QLocale::FloatingPointShortest);
+ if (!s.contains(QLatin1Char('.')) && !s.contains('e'))
+ s += QLatin1Char('.');
+ }
+ return s;
+}
+
+static bool isByteArrayEncodingTag(QCborTag tag)
+{
+ switch (quint64(tag)) {
+ case quint64(QCborKnownTags::ExpectedBase16):
+ case quint64(QCborKnownTags::ExpectedBase64):
+ case quint64(QCborKnownTags::ExpectedBase64url):
+ return true;
+ }
+ return false;
+}
+
+void DiagnosticNotation::appendString(const QString &s)
+{
+ result += QLatin1Char('"');
+
+ const QChar *begin = s.begin();
+ const QChar *end = s.end();
+ while (begin < end) {
+ // find the longest span comprising only non-escaped characters
+ const QChar *ptr = begin;
+ for ( ; ptr < end; ++ptr) {
+ ushort uc = ptr->unicode();
+ if (uc == '\\' || uc == '"' || uc < ' ' || uc >= 0x7f)
+ break;
+ }
+
+ if (ptr != begin)
+ result.append(begin, ptr - begin);
+
+ if (ptr == end)
+ break;
+
+ // there's an escaped character
+ static const char escapeMap[16] = {
+ // The C escape characters \a \b \t \n \v \f and \r indexed by
+ // their ASCII values
+ 0, 0, 0, 0,
+ 0, 0, 0, 'a',
+ 'b', 't', 'n', 'v',
+ 'f', 'r', 0, 0
+ };
+ int buflen = 2;
+ QChar buf[10];
+ buf[0] = QLatin1Char('\\');
+ buf[1] = QChar::Null;
+ char16_t uc = ptr->unicode();
+
+ if (uc < sizeof(escapeMap))
+ buf[1] = QLatin1Char(escapeMap[uc]);
+ else if (uc == '"' || uc == '\\')
+ buf[1] = QChar(uc);
+
+ if (buf[1] == QChar::Null) {
+ using QtMiscUtils::toHexUpper;
+ if (ptr->isHighSurrogate() && (ptr + 1) != end && ptr[1].isLowSurrogate()) {
+ // properly-paired surrogates
+ ++ptr;
+ char32_t ucs4 = QChar::surrogateToUcs4(uc, ptr->unicode());
+ buf[1] = 'U';
+ buf[2] = '0'; // toHexUpper(ucs4 >> 28);
+ buf[3] = '0'; // toHexUpper(ucs4 >> 24);
+ buf[4] = toHexUpper(ucs4 >> 20);
+ buf[5] = toHexUpper(ucs4 >> 16);
+ buf[6] = toHexUpper(ucs4 >> 12);
+ buf[7] = toHexUpper(ucs4 >> 8);
+ buf[8] = toHexUpper(ucs4 >> 4);
+ buf[9] = toHexUpper(ucs4);
+ buflen = 10;
+ } else {
+ buf[1] = 'u';
+ buf[2] = toHexUpper(uc >> 12);
+ buf[3] = toHexUpper(uc >> 8);
+ buf[4] = toHexUpper(uc >> 4);
+ buf[5] = toHexUpper(uc);
+ buflen = 6;
+ }
+ }
+
+ result.append(buf, buflen);
+ begin = ptr + 1;
+ }
+
+ result += QLatin1Char('"');
+}
+
+void DiagnosticNotation::appendArray(const QCborArray &a)
+{
+ result += QLatin1Char('[');
+
+ // length 2 (including the space) when not line wrapping
+ QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ {
+ Nest n(this);
+ QLatin1String comma;
+ for (auto v : a) {
+ result += comma + separator;
+ comma = commaValue;
+ appendValue(v);
+ }
+ }
+
+ result += separator + QLatin1Char(']');
+}
+
+void DiagnosticNotation::appendMap(const QCborMap &m)
+{
+ result += QLatin1Char('{');
+
+ // length 2 (including the space) when not line wrapping
+ QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ {
+ Nest n(this);
+ QLatin1String comma;
+ for (auto v : m) {
+ result += comma + separator;
+ comma = commaValue;
+ appendValue(v.first);
+ result += QLatin1String(": ");
+ appendValue(v.second);
+ }
+ }
+
+ result += separator + QLatin1Char('}');
+};
+
+void DiagnosticNotation::appendValue(const QCborValue &v)
+{
+ switch (v.type()) {
+ case QCborValue::Integer:
+ result += QString::number(v.toInteger());
+ return;
+ case QCborValue::ByteArray:
+ switch (byteArrayFormatStack.top()) {
+ case int(QCborKnownTags::ExpectedBase16):
+ result += QString::fromLatin1("h'" +
+ v.toByteArray().toHex(opts & QCborValue::ExtendedFormat ? ' ' : '\0') +
+ '\'');
+ return;
+ case int(QCborKnownTags::ExpectedBase64):
+ result += QString::fromLatin1("b64'" + v.toByteArray().toBase64() + '\'');
+ return;
+ default:
+ case int(QCborKnownTags::ExpectedBase64url):
+ result += QString::fromLatin1("b64'" +
+ v.toByteArray().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals) +
+ '\'');
+ return;
+ }
+ case QCborValue::String:
+ return appendString(v.toString());
+ case QCborValue::Array:
+ return appendArray(v.toArray());
+ case QCborValue::Map:
+ return appendMap(v.toMap());
+ case QCborValue::False:
+ result += QLatin1String("false");
+ return;
+ case QCborValue::True:
+ result += QLatin1String("true");
+ return;
+ case QCborValue::Null:
+ result += QLatin1String("null");
+ return;
+ case QCborValue::Undefined:
+ result += QLatin1String("undefined");
+ return;
+ case QCborValue::Double:
+ result += makeFpString(v.toDouble());
+ return;
+ case QCborValue::Invalid:
+ result += QStringLiteral("<invalid>");
+ return;
+
+ default:
+ // Only tags, extended types, and simple types remain; see below.
+ break;
+ }
+
+ if (v.isTag()) {
+ // We handle all extended types as regular tags, so it won't matter
+ // whether we understand that tag or not.
+ bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
+ if (byteArrayFormat)
+ byteArrayFormatStack.push(int(v.tag()));
+ result += QString::number(quint64(v.tag())) + QLatin1Char('(');
+ appendValue(v.taggedValue());
+ result += QLatin1Char(')');
+ if (byteArrayFormat)
+ byteArrayFormatStack.pop();
+ } else {
+ // must be a simple type
+ result += QString::fromLatin1("simple(%1)").arg(quint8(v.toSimpleType()));
+ }
+}
+
+/*!
+ Creates the diagnostic notation equivalent of this CBOR object and returns
+ it. The \a opts parameter controls the dialect of the notation. Diagnostic
+ notation is useful in debugging, to aid the developer in understanding what
+ value is stored in the QCborValue or in a CBOR stream. For that reason, the
+ Qt API provides no support for parsing the diagnostic back into the
+ in-memory format or CBOR stream, though the representation is unique and it
+ would be possible.
+
+ CBOR diagnostic notation is specified by
+ \l{https://tools.ietf.org/html/rfc7049#section-6}{section 6} of RFC 7049.
+ It is a text representation of the CBOR stream and it is very similar to
+ JSON, but it supports the CBOR types not found in JSON. The extended format
+ enabled by the \l{DiagnosticNotationOption}{ExtendedFormat} flag is
+ currently in some IETF drafts and its format is subject to change.
+
+ This function produces the equivalent representation of the stream that
+ toCbor() would produce, without any transformation option provided there.
+ This also implies this function may not produce a representation of the
+ stream that was used to create the object, if it was created using
+ fromCbor(), as that function may have applied transformations. For a
+ high-fidelity notation of a stream, without transformation, see the \c
+ cbordump example.
+
+ \sa toCbor(), QJsonDocument::toJson()
+ */
+QString QCborValue::toDiagnosticNotation(DiagnosticNotationOptions opts) const
+{
+ return DiagnosticNotation::create(*this, opts);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcbormap.cpp b/src/corelib/serialization/qcbormap.cpp
new file mode 100644
index 0000000000..33f9249993
--- /dev/null
+++ b/src/corelib/serialization/qcbormap.cpp
@@ -0,0 +1,1766 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcbormap.h"
+#include "qcborvalue_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtCbor;
+
+/*!
+ \class QCborMap
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborMap class is used to hold an associative container representable in CBOR.
+
+ This class can be used to hold an associative container in CBOR, a map
+ between a key and a value type. CBOR is the Concise Binary Object
+ Representation, a very compact form of binary data encoding that is a
+ superset of JSON. It was created by the IETF Constrained RESTful
+ Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
+ be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
+ protocol}.
+
+ Unlike JSON and \l QVariantMap, CBOR map keys can be of any type, not just
+ strings. For that reason, QCborMap is effectively a map between QCborValue
+ keys to QCborValue value elements.
+
+ However, for all member functions that take a key parameter, QCborMap
+ provides overloads that will work efficiently with integers and strings. In
+ fact, the use of integer keys is encouraged, since they occupy fewer bytes
+ to transmit and are simpler to encode and decode. Newer protocols designed
+ by the IETF CoRE WG to work specifically with CBOR are known to use them.
+
+ QCborMap is not sorted, because of that, searching for keys has linear
+ complexity (O(n)). QCborMap actually keeps the elements in the order that
+ they were inserted, which means that it is possible to make sorted
+ QCborMaps by carefully inserting elements in sorted order. CBOR does not
+ require sorting, but recommends it.
+
+ QCborMap can also be converted to and from QVariantMap and QJsonObject.
+ However, when performing the conversion, any non-string keys will be
+ stringified using a one-way method that the conversion back to QCborMap
+ will not undo.
+
+ \sa QCborArray, QCborValue, QJsonDocument, QVariantMap
+ */
+
+/*!
+ \typedef QCborMap::value_type
+
+ The value that is stored in this container: a pair of QCborValues
+ */
+
+/*!
+ \typedef QCborMap::key_type
+
+ The key type for this map. Since QCborMap keys can be any CBOR type, this
+ is a QCborValue.
+ */
+
+/*!
+ \typedef QCborMap::mapped_type
+
+ The type that is mapped to (the value), that is, a QCborValue.
+ */
+
+/*!
+ \typedef QCborMap::size_type
+
+ The type that QCborMap uses for sizes.
+ */
+
+/*!
+ \typedef QCborMap::iterator
+
+ A synonym for QCborMap::Iterator.
+ */
+
+/*!
+ \typedef QCborMap::const_iterator
+
+ A synonym for QCborMap::ConstIterator
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::begin()
+
+ Returns a map iterator pointing to the first key-value pair of this map. If
+ this map is empty, the returned iterator will be the same as end().
+
+ \sa constBegin(), end()
+ */
+
+/*!
+ \fn QCborMap::const_iterator QCborMap::constBegin() const
+
+ Returns a map iterator pointing to the first key-value pair of this map. If
+ this map is empty, the returned iterator will be the same as constEnd().
+
+ \sa begin(), constEnd()
+ */
+
+/*!
+ \fn QCborMap::const_iterator QCborMap::begin() const
+
+ Returns a map iterator pointing to the first key-value pair of this map. If
+ this map is empty, the returned iterator will be the same as constEnd().
+
+ \sa begin(), constEnd()
+ */
+
+/*!
+ \fn QCborMap::const_iterator QCborMap::cbegin() const
+
+ Returns a map iterator pointing to the first key-value pair of this map. If
+ this map is empty, the returned iterator will be the same as constEnd().
+
+ \sa begin(), constEnd()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::end()
+
+ Returns a map iterator representing an element just past the last element
+ in the map.
+
+ \sa begin(), constBegin(), find(), constFind()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::constEnd() const
+
+ Returns a map iterator representing an element just past the last element
+ in the map.
+
+ \sa begin(), constBegin(), find(), constFind()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::end() const
+
+ Returns a map iterator representing an element just past the last element
+ in the map.
+
+ \sa begin(), constBegin(), find(), constFind()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::cend() const
+
+ Returns a map iterator representing an element just past the last element
+ in the map.
+
+ \sa begin(), constBegin(), find(), constFind()
+ */
+
+/*!
+ Constructs an empty CBOR Map object.
+
+ \sa isEmpty()
+ */
+QCborMap::QCborMap() noexcept
+ : d(nullptr)
+{
+}
+
+/*!
+ Creates a QCborMap object that is a copy of \a other.
+ */
+QCborMap::QCborMap(const QCborMap &other) noexcept
+ : d(other.d)
+{
+}
+
+/*!
+ \fn QCborMap::QCborMap(std::initializer_list<value_type> args)
+
+ Constructs a QCborMap with items from a brace-initialization list found in
+ \a args, as in the following example:
+
+ \code
+ QCborMap map = {
+ {0, "Hello"},
+ {1, "World"},
+ {"foo", nullptr},
+ {"bar", QCborArray{0, 1, 2, 3, 4}}
+ };
+ \endcode
+ */
+
+/*!
+ Destroys this QCborMap object and frees any associated resources it owns.
+ */
+QCborMap::~QCborMap()
+{
+}
+
+/*!
+ Replaces the contents of this object with a copy of \a other, then returns
+ a reference to this object.
+ */
+QCborMap &QCborMap::operator=(const QCborMap &other) noexcept
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn void QCborMap::swap(QCborMap &other)
+
+ Swaps the contents of this map and \a other.
+ */
+
+/*!
+ \fn QCborValue QCborMap::toCborValue() const
+
+ Explicitly constructs a \l QCborValue object that represents this map.
+ This function is usually not necessary since QCborValue has a constructor
+ for QCborMap, so the conversion is implicit.
+
+ Converting QCborMap to QCborValue allows it to be used in any context where
+ QCborValues can be used, including as keys and mapped types in QCborMap, as
+ well as QCborValue::toCbor().
+
+ \sa QCborValue::QCborValue(const QCborMap &)
+ */
+
+/*!
+ \fn bool QCborMap::isEmpty() const
+
+ Returns true if this map is empty (that is, size() is 0).
+
+ \sa size(), clear()
+ */
+
+/*!
+ Returns the number of elements in this map.
+
+ \sa isEmpty()
+ */
+qsizetype QCborMap::size() const noexcept
+{
+ return d ? d->elements.size() / 2 : 0;
+}
+
+/*!
+ Empties this map.
+
+ \sa isEmpty()
+ */
+void QCborMap::clear()
+{
+ d.reset();
+}
+
+/*!
+ Returns a list of all keys in this map.
+
+ \sa QMap::keys(), QHash::keys()
+ */
+QVector<QCborValue> QCborMap::keys() const
+{
+ QVector<QCborValue> result;
+ if (d) {
+ result.reserve(size());
+ for (qsizetype i = 0; i < d->elements.size(); i += 2)
+ result << d->valueAt(i);
+ }
+ return result;
+}
+
+/*!
+ \fn QCborValue QCborMap::value(qint64 key) const
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one. CBOR recommends using integer keys, since they occupy less
+ space and are simpler to encode and decode.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one the return from function will reference. QCborMap does not allow
+ inserting duplicate keys, but it is possible to create such a map by
+ decoding a CBOR stream with them. They are usually not permitted and having
+ duplicate keys is usually an indication of a problem in the sender.
+
+ \sa operator[](qint64), find(qint64), constFind(qint64), remove(qint64), contains(qint64)
+ value(QLatin1String), value(const QString &), value(const QCborValue &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::operator[](qint64 key) const
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one. CBOR recommends using integer keys, since they occupy less
+ space and are simpler to encode and decode.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), find(qint64), constFind(qint64), remove(qint64), contains(qint64)
+ operator[](QLatin1String), operator[](const QString &), operator[](const QCborOperator[] &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::take(qint64 key)
+
+ Removes the key \a key and the corresponding value from the map and returns
+ the value, if it is found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), operator[](qint64), find(qint64), contains(qint64),
+ take(QLatin1String), take(const QString &), take(const QCborValue &), insert()
+ */
+
+/*!
+ \fn void QCborMap::remove(qint64 key)
+
+ Removes the key \a key and the corresponding value from the map, if it is
+ found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), operator[](qint64), find(qint64), contains(qint64)
+ remove(QLatin1String), remove(const QString &), remove(const QCborValue &)
+ */
+
+/*!
+ \fn bool QCborMap::contains(qint64 key) const
+
+ Returns true if this map contains a key-value pair identified by key \a
+ key. CBOR recommends using integer keys, since they occupy less space and
+ are simpler to encode and decode.
+
+ \sa value(qint64), operator[](qint64), find(qint64), remove(qint64),
+ contains(QLatin1String), remove(const QString &), remove(const QCborValue &)
+ */
+
+/*!
+ Returns a QCborValueRef to the value in this map that corresponds to key \a
+ key. CBOR recommends using integer keys, since they occupy less space and
+ are simpler to encode and decode.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ If the map did not have a key equal to \a key, one is inserted and this
+ function returns a reference to the new value, which will be a QCborValue
+ with an undefined value. For that reason, it is not possible with this
+ function to tell apart the situation where the key was not present from the
+ situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one the return will reference. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), find(qint64), contains(qint64), remove(qint64),
+ operator[](QLatin1String), operator[](const QString &), operator[](const QCborValue &)
+ */
+QCborValueRef QCborMap::operator[](qint64 key)
+{
+ auto it = find(key);
+ if (it == constEnd()) {
+ // insert element
+ detach(it.item.i + 2);
+ d->append(key);
+ d->append(Undefined{});
+ }
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborValue QCborMap::value(QLatin1String key) const
+ \overload
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa operator[](QLatin1String), find(QLatin1String), constFind(QLatin1String),
+ remove(QLatin1String), contains(QLatin1String)
+ value(qint64), value(const QString &), value(const QCborValue &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::operator[](QLatin1String key) const
+ \overload
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), find(QLatin1String), constFind(QLatin1String),
+ remove(QLatin1String), contains(QLatin1String)
+ operator[](qint64), operator[](const QString &), operator[](const QCborOperator[] &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::take(QLatin1String key)
+
+ Removes the key \a key and the corresponding value from the map and returns
+ the value, if it is found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), operator[](QLatin1String), find(QLatin1String), contains(QLatin1String),
+ take(qint64), take(const QString &), take(const QCborValue &), insert()
+ */
+
+/*!
+ \fn void QCborMap::remove(QLatin1String key)
+ \overload
+
+ Removes the key \a key and the corresponding value from the map, if it is
+ found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), operator[](QLatin1String), find(QLatin1String), contains(QLatin1String)
+ remove(qint64), remove(const QString &), remove(const QCborValue &)
+ */
+
+/*!
+ \fn bool QCborMap::contains(QLatin1String key) const
+ \overload
+
+ Returns true if this map contains a key-value pair identified by key \a
+ key.
+
+ \sa value(QLatin1String), operator[](QLatin1String), find(QLatin1String), remove(QLatin1String),
+ contains(qint64), remove(const QString &), remove(const QCborValue &)
+ */
+
+/*!
+ \overload
+
+ Returns a QCborValueRef to the value in this map that corresponds to key \a
+ key.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ If the map did not have a key equal to \a key, one is inserted and this
+ function returns a reference to the new value, which will be a QCborValue
+ with an undefined value. For that reason, it is not possible with this
+ function to tell apart the situation where the key was not present from the
+ situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one the return will reference. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), find(QLatin1String), contains(QLatin1String), remove(QLatin1String),
+ operator[](qint64), operator[](const QString &), operator[](const QCborValue &)
+ */
+QCborValueRef QCborMap::operator[](QLatin1String key)
+{
+ auto it = find(key);
+ if (it == constEnd()) {
+ // insert element
+ detach(it.item.i + 2);
+ d->append(key);
+ d->append(Undefined{});
+ }
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborValue QCborMap::value(const QString &key) const
+ \overload
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa operator[](const QString &), find(const QString &), constFind(const QString &),
+ remove(const QString &), contains(const QString &)
+ value(qint64), value(QLatin1String), value(const QCborValue &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::operator[](const QString &key) const
+ \overload
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), find(const QString &), constFind(const QString &),
+ remove(const QString &), contains(const QString &)
+ operator[](qint64), operator[](QLatin1String), operator[](const QCborOperator[] &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::take(const QString &key)
+
+ Removes the key \a key and the corresponding value from the map and returns
+ the value, if it is found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), operator[](const QString &), find(const QString &), contains(const QString &),
+ take(QLatin1String), take(qint64), take(const QCborValue &), insert()
+ */
+
+/*!
+ \fn void QCborMap::remove(const QString &key)
+ \overload
+
+ Removes the key \a key and the corresponding value from the map, if it is
+ found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), operator[](const QString &), find(const QString &),
+ contains(const QString &)
+ remove(qint64), remove(QLatin1String), remove(const QCborValue &)
+ */
+
+/*!
+ \fn bool QCborMap::contains(const QString &key) const
+ \overload
+
+ Returns true if this map contains a key-value pair identified by key \a
+ key.
+
+ \sa value(const QString &), operator[](const QString &), find(const QString &),
+ remove(const QString &),
+ contains(qint64), remove(QLatin1String), remove(const QCborValue &)
+ */
+
+/*!
+ \overload
+
+ Returns a QCborValueRef to the value in this map that corresponds to key \a
+ key.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ If the map did not have a key equal to \a key, one is inserted and this
+ function returns a reference to the new value, which will be a QCborValue
+ with an undefined value. For that reason, it is not possible with this
+ function to tell apart the situation where the key was not present from the
+ situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one the return will reference. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), find(const QString &), contains(const QString &), remove(const QString &),
+ operator[](qint64), operator[](QLatin1String), operator[](const QCborValue &)
+ */
+QCborValueRef QCborMap::operator[](const QString & key)
+{
+ auto it = find(key);
+ if (it == constEnd()) {
+ // insert element
+ detach(it.item.i + 2);
+ d->append(key);
+ d->append(Undefined{});
+ }
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborValue QCborMap::value(const QCborValue &key) const
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa operator[](const QCborValue &), find(const QCborValue &), constFind(const QCborValue &),
+ remove(const QCborValue &), contains(const QCborValue &)
+ value(qint64), value(QLatin1String), value(const QString &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::operator[](const QCborValue &key) const
+
+ Returns the QCborValue element in this map that corresponds to key \a key,
+ if there is one.
+
+ If the map does not contain key \a key, this function returns a QCborValue
+ containing an undefined value. For that reason, it is not possible with
+ this function to tell apart the situation where the key was not present
+ from the situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will return. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), find(const QCborValue &), constFind(const QCborValue &),
+ remove(const QCborValue &), contains(const QCborValue &)
+ operator[](qint64), operator[](QLatin1String), operator[](const QCborOperator[] &)
+ */
+
+/*!
+ \fn QCborValue QCborMap::take(const QCborValue &key)
+
+ Removes the key \a key and the corresponding value from the map and returns
+ the value, if it is found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &), contains(const QCborValue &),
+ take(QLatin1String), take(const QString &), take(qint64), insert()
+ */
+
+/*!
+ \fn void QCborMap::remove(const QCborValue &key)
+
+ Removes the key \a key and the corresponding value from the map, if it is
+ found. If the map contains no such key, this function does nothing.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will remove. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
+ contains(const QCborValue &)
+ remove(qint64), remove(QLatin1String), remove(const QString &)
+ */
+
+/*!
+ \fn bool QCborMap::contains(const QCborValue &key) const
+
+ Returns true if this map contains a key-value pair identified by key \a
+ key.
+
+ \sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
+ remove(const QCborValue &),
+ contains(qint64), remove(QLatin1String), remove(const QString &)
+ */
+
+/*!
+ \overload
+
+ Returns a QCborValueRef to the value in this map that corresponds to key \a
+ key.
+
+ QCborValueRef has the exact same API as \l QCborValue, with one important
+ difference: if you assign new values to it, this map will be updated with
+ that new value.
+
+ If the map did not have a key equal to \a key, one is inserted and this
+ function returns a reference to the new value, which will be a QCborValue
+ with an undefined value. For that reason, it is not possible with this
+ function to tell apart the situation where the key was not present from the
+ situation where the key was mapped to an undefined value.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one the return will reference. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), find(const QCborValue &), contains(const QCborValue &), remove(const QCborValue &),
+ operator[](qint64), operator[](QLatin1String), operator[](const QString &)
+ */
+QCborValueRef QCborMap::operator[](const QCborValue &key)
+{
+ auto it = find(key);
+ if (it == constEnd()) {
+ // insert element
+ detach(it.item.i + 2);
+ d->append(key);
+ d->append(Undefined{});
+ }
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborMap::iterator QCborMap::find(qint64 key)
+ \fn QCborMap::const_iterator QCborMap::find(qint64 key) const
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns end().
+
+ CBOR recommends using integer keys, since they occupy less
+ space and are simpler to encode and decode.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), operator[](qint64), constFind(qint64), remove(qint64), contains(qint64)
+ value(QLatin1String), value(const QString &), value(const QCborValue &)
+ */
+QCborMap::iterator QCborMap::find(qint64 key)
+{
+ auto it = constFind(key);
+ if (it != constEnd())
+ detach();
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborMap::iterator QCborMap::find(QLatin1String key)
+ \fn QCborMap::const_iterator QCborMap::find(QLatin1String key) const
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns end().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), operator[](QLatin1String), constFind(QLatin1String),
+ remove(QLatin1String), contains(QLatin1String)
+ value(qint64), value(const QString &), value(const QCborValue &)
+ */
+QCborMap::iterator QCborMap::find(QLatin1String key)
+{
+ auto it = constFind(key);
+ if (it != constEnd())
+ detach();
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborMap::iterator QCborMap::find(const QString & key)
+ \fn QCborMap::const_iterator QCborMap::find(const QString & key) const
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns end().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), operator[](const QString &), constFind(const QString &),
+ remove(const QString &), contains(const QString &)
+ value(qint64), value(QLatin1String), value(const QCborValue &)
+ */
+QCborMap::iterator QCborMap::find(const QString & key)
+{
+ auto it = constFind(key);
+ if (it != constEnd())
+ detach();
+ return { d.data(), it.item.i };
+}
+
+/*!
+ \fn QCborMap::iterator QCborMap::find(const QCborValue &key)
+ \fn QCborMap::const_iterator QCborMap::find(const QCborValue &key) const
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns end().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), operator[](const QCborValue &), constFind(const QCborValue &),
+ remove(const QCborValue &), contains(const QCborValue &)
+ value(qint64), value(QLatin1String), value(const QString &)
+ */
+QCborMap::iterator QCborMap::find(const QCborValue &key)
+{
+ auto it = constFind(key);
+ if (it != constEnd())
+ detach();
+ return { d.data(), it.item.i };
+}
+
+/*!
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns constEnd().
+
+ CBOR recommends using integer keys, since they occupy less
+ space and are simpler to encode and decode.
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(qint64), operator[](qint64), find(qint64), remove(qint64), contains(qint64)
+ value(QLatin1String), value(const QString &), value(const QCborValue &)
+ */
+QCborMap::const_iterator QCborMap::constFind(qint64 key) const
+{
+ for (qsizetype i = 0; i < 2 * size(); i += 2) {
+ const auto &e = d->elements.at(i);
+ if (e.type == QCborValue::Integer && e.value == key)
+ return { d.data(), i + 1 };
+ }
+ return constEnd();
+}
+
+/*!
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns constEnd().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(QLatin1String), operator[](QLatin1String), find(QLatin1String),
+ remove(QLatin1String), contains(QLatin1String)
+ value(qint64), value(const QString &), value(const QCborValue &)
+ */
+QCborMap::const_iterator QCborMap::constFind(QLatin1String key) const
+{
+ for (qsizetype i = 0; i < 2 * size(); i += 2) {
+ if (d->stringEqualsElement(i, key))
+ return { d.data(), i + 1 };
+ }
+ return constEnd();
+}
+
+/*!
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns constEnd().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QString &), operator[](const QString &), find(const QString &),
+ remove(const QString &), contains(const QString &)
+ value(qint64), value(QLatin1String), value(const QCborValue &)
+ */
+QCborMap::const_iterator QCborMap::constFind(const QString & key) const
+{
+ for (qsizetype i = 0; i < 2 * size(); i += 2) {
+ if (d->stringEqualsElement(i, key))
+ return { d.data(), i + 1 };
+ }
+ return constEnd();
+}
+
+/*!
+ \overload
+
+ Returns a map iterator to the key-value pair whose key is \a key, if the
+ map contains such a pair. If it doesn't, this function returns constEnd().
+
+ If the map contains more than one key equal to \a key, it is undefined
+ which one this function will find. QCborMap does not allow inserting
+ duplicate keys, but it is possible to create such a map by decoding a CBOR
+ stream with them. They are usually not permitted and having duplicate keys
+ is usually an indication of a problem in the sender.
+
+ \sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
+ remove(const QCborValue &), contains(const QCborValue &),
+ value(qint64), value(QLatin1String), value(const QString &)
+ */
+QCborMap::const_iterator QCborMap::constFind(const QCborValue &key) const
+{
+ for (qsizetype i = 0; i < 2 * size(); i += 2) {
+ int cmp = d->compareElement(i, key);
+ if (cmp == 0)
+ return { d.data(), i + 1 };
+ }
+ return constEnd();
+}
+
+/*!
+ \fn QCborMap::iterator QCborMap::insert(qint64 key, const QCborValue &value)
+ \overload
+
+ Inserts the key \a key and value \a value into this map and returns a map
+ iterator pointing to the newly inserted pair.
+
+ If the map already had a key equal to \a key, its value will be overwritten
+ by \a value.
+
+ \sa erase(), remove(qint64), value(qint64), operator[](qint64), find(qint64),
+ contains(qint64), take(qint64), extract()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::insert(QLatin1String key, const QCborValue &value)
+ \overload
+
+ Inserts the key \a key and value \a value into this map and returns a map
+ iterator pointing to the newly inserted pair.
+
+ If the map already had a key equal to \a key, its value will be overwritten
+ by \a value.
+
+ \sa erase(), remove(QLatin1String), value(QLatin1String), operator[](QLatin1String),
+ find(QLatin1String), contains(QLatin1String), take(QLatin1String), extract()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::insert(const QString &key, const QCborValue &value)
+ \overload
+
+ Inserts the key \a key and value \a value into this map and returns a map
+ iterator pointing to the newly inserted pair.
+
+ If the map already had a key equal to \a key, its value will be overwritten
+ by \a value.
+
+ \sa erase(), remove(const QString &), value(const QString &), operator[](const QString &),
+ find(const QString &), contains(const QString &), take(const QString &), extract()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::insert(const QCborValue &key, const QCborValue &value)
+ \overload
+
+ Inserts the key \a key and value \a value into this map and returns a map
+ iterator pointing to the newly inserted pair.
+
+ If the map already had a key equal to \a key, its value will be overwritten
+ by \a value.
+
+ \sa erase(), remove(const QCborValue &), value(const QCborValue &), operator[](const QCborValue &),
+ find(const QCborValue &), contains(const QCborValue &), take(const QCborValue &), extract()
+ */
+
+/*!
+ \fn QCborMap::iterator QCborMap::insert(value_type v)
+ \overload
+
+ Inserts the key-value pair in \a v into this map and returns a map iterator
+ pointing to the newly inserted pair.
+
+ If the map already had a key equal to \c{v.first}, its value will be
+ overwritten by \c{v.second}.
+
+ \sa operator[], erase(), extract()
+ */
+
+
+/*!
+ \fn QCborMap::iterator QCborMap::erase(const_iterator it)
+
+ Removes the key-value pair pointed to by the map iterator \a it and returns a
+ pointer to the next element, after removal.
+
+ \sa remove(), begin(), end(), insert(), extract()
+ */
+
+/*!
+ \overload
+
+ Removes the key-value pair pointed to by the map iterator \a it and returns a
+ pointer to the next element, after removal.
+
+ \sa remove(), begin(), end(), insert()
+ */
+QCborMap::iterator QCborMap::erase(QCborMap::iterator it)
+{
+ detach();
+
+ // remove both key and value
+ // ### optimize?
+ d->removeAt(it.item.i - 1);
+ d->removeAt(it.item.i - 1);
+ return it;
+}
+
+/*!
+ \fn QCborValue QCborMap::extract(iterator it)
+ \fn QCborValue QCborMap::extract(const_iterator it)
+
+ Extracts a value from the map at the position indicated by iterator \a it
+ and returns the value so extracted.
+
+ \sa insert(), erase(), take(), remove()
+ */
+QCborValue QCborMap::extract(iterator it)
+{
+ detach();
+ QCborValue v = d->extractAt(it.item.i);
+ // remove both key and value
+ // ### optimize?
+ d->removeAt(it.item.i - 1);
+ d->removeAt(it.item.i - 1);
+
+ return v;
+}
+
+/*!
+ \fn bool QCborMap::empty() const
+
+ Synonym for isEmpty(). This function is provided for compatibility with
+ generic code that uses the Standard Library API.
+
+ Returns true if this map is empty (size() == 0).
+
+ \sa isEmpty(), size()
+ */
+
+/*!
+ \fn int QCborMap::compare(const QCborMap &other) const
+
+ Compares this map and \a other, comparing each element in sequence, and
+ returns an integer that indicates whether this map should be sorted prior
+ to (if the result is negative) or after \a other (if the result is
+ positive). If this function returns 0, the two maps are equal and contain
+ the same elements.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa QCborValue::compare(), QCborArray::compare(), operator==()
+ */
+
+/*!
+ \fn bool QCborMap::operator==(const QCborMap &other) const
+
+ Compares this map and \a other, comparing each element in sequence, and
+ returns true if the two maps contains the same elements in the same order,
+ false otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR equality in Qt, see, QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator!=(), operator<()
+ */
+
+/*!
+ \fn bool QCborMap::operator!=(const QCborMap &other) const
+
+ Compares this map and \a other, comparing each element in sequence, and
+ returns true if the two maps contains any different elements or elements in
+ different orders, false otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR equality in Qt, see, QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator<()
+ */
+
+/*!
+ \fn bool QCborMap::operator<(const QCborMap &other) const
+
+ Compares this map and \a other, comparing each element in sequence, and
+ returns true if this map should be sorted before \a other, false
+ otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+ */
+
+void QCborMap::detach(qsizetype reserved)
+{
+ d = QCborContainerPrivate::detach(d.data(), reserved ? reserved : size() * 2);
+}
+
+/*!
+ \class QCborMap::Iterator
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborMap::Iterator class provides an STL-style non-const iterator for QCborMap.
+
+ QCborMap::Iterator allows you to iterate over a QCborMap and to modify the
+ value (but not the key) stored under a particular key. If you want to
+ iterate over a const QCborMap, you should use QCborMap::ConstIterator. It
+ is generally good practice to use QCborMap::ConstIterator on a non-const
+ QCborMap as well, unless you need to change the QCborMap through the
+ iterator. Const iterators are slightly faster, and improve code
+ readability.
+
+ You must initialize the iterator using a QCborMap function like
+ QCborMap::begin(), QCborMap::end(), or QCborMap::find() before you can
+ start iterating..
+
+ Multiple iterators can be used on the same object. Existing iterators will however
+ become dangling once the object gets modified.
+
+ \sa QCborMap::ConstIterator
+*/
+
+/*!
+ \typedef QCborMap::Iterator::difference_type
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::Iterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating
+ this iterator is a random-access iterator.
+*/
+
+/*!
+ \typedef QCborMap::Iterator::reference
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::Iterator::value_type
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::Iterator::pointer
+ \internal
+*/
+
+/*!
+ \fn QCborMap::Iterator::Iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QCborMap::begin(), QCborMap::end()
+*/
+
+/*!
+ \fn QCborMap::Iterator::Iterator(const Iterator &other)
+
+ Constructs an iterator as a copy of \a other.
+ */
+
+/*!
+ \fn QCborMap::Iterator &QCborMap::Iterator::operator=(const Iterator &other)
+
+ Makes this iterator a copy of \a other and returns a reference to this
+ iterator.
+ */
+
+/*!
+ \fn QCborValue QCborMap::Iterator::key() const
+
+ Returns the current item's key.
+
+ There is no direct way of changing an item's key through an iterator,
+ although it can be done by calling QCborMap::erase() followed by
+ QCborMap::insert().
+
+ \sa value()
+*/
+
+/*!
+ \fn QCborValueRef QCborMap::Iterator::value() const
+
+ Returns a modifiable reference to the current item's value.
+
+ You can change the value for a key by using value() on the left side of an
+ assignment.
+
+ The return value is of type QCborValueRef, a helper class for QCborArray
+ and QCborMap. When you get an object of type QCborValueRef, you can use it
+ as if it were a reference to a QCborValue. If you assign to it, the
+ assignment will apply to the element in the QCborArray or QCborMap from
+ which you got the reference.
+
+ \sa key(), operator*()
+*/
+
+/*!
+ \fn QCborMap::Iterator::value_type QCborMap::Iterator::operator*() const
+
+ Returns a pair containing the current item's key and a modifiable reference
+ to the current item's value.
+
+ The second element of the pair is of type QCborValueRef, a helper class for
+ QCborArray and QCborMap. When you get an object of type QCborValueRef, you
+ can use it as if it were a reference to a QCborValue. If you assign to it,
+ the assignment will apply to the element in the QCborArray or QCborMap from
+ which you got the reference.
+
+ \sa key(), value()
+*/
+
+/*!
+ \fn QCborValueRef *QCborMap::Iterator::operator->() const
+
+ Returns a pointer to a modifiable reference to the current pair's value.
+*/
+
+/*!
+ \fn bool QCborMap::Iterator::operator==(const Iterator &other) const
+ \fn bool QCborMap::Iterator::operator==(const ConstIterator &other) const
+
+ Returns \c true if \a other points to the same entry in the map as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::Iterator::operator!=(const Iterator &other) const
+ \fn bool QCborMap::Iterator::operator!=(const ConstIterator &other) const
+
+ Returns \c true if \a other points to a different entry in the map than
+ this iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool QCborMap::Iterator::operator<(const Iterator& other) const
+ \fn bool QCborMap::Iterator::operator<(const ConstIterator& other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs before the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborMap::Iterator::operator<=(const Iterator& other) const
+ \fn bool QCborMap::Iterator::operator<=(const ConstIterator& other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs before or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn bool QCborMap::Iterator::operator>(const Iterator& other) const
+ \fn bool QCborMap::Iterator::operator>(const ConstIterator& other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs after the entry pointed to by the \a other iterator.
+ */
+
+/*!
+ \fn bool QCborMap::Iterator::operator>=(const Iterator& other) const
+ \fn bool QCborMap::Iterator::operator>=(const ConstIterator& other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs after or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn QCborMap::Iterator &QCborMap::Iterator::operator++()
+
+ The prefix ++ operator, \c{++i}, advances the iterator to the next item in
+ the map and returns this iterator.
+
+ Calling this function on QCborMap::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*!
+ \fn QCborMap::Iterator QCborMap::Iterator::operator++(int)
+ \overload
+
+ The postfix ++ operator, \c{i++}, advances the iterator to the next item in
+ the map and returns an iterator to the previously current item.
+*/
+
+/*!
+ \fn QCborMap::Iterator QCborMap::Iterator::operator--()
+
+ The prefix -- operator, \c{--i}, makes the preceding item current and
+ returns this iterator.
+
+ Calling this function on QCborMap::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*!
+ \fn QCborMap::Iterator QCborMap::Iterator::operator--(int)
+ \overload
+
+ The postfix -- operator, \c{i--}, makes the preceding item current and
+ returns an iterator pointing to the previously current item.
+*/
+
+/*!
+ \fn QCborMap::Iterator QCborMap::Iterator::operator+(qsizetype j) const
+
+ Returns an iterator to the item at \a j positions forward from this
+ iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-()
+*/
+
+/*!
+ \fn QCborMap::Iterator QCborMap::Iterator::operator-(qsizetype j) const
+
+ Returns an iterator to the item at \a j positions backward from this
+ iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn qsizetype QCborMap::Iterator::operator-(QCborMap::Iterator j) const
+
+ Returns the position of the item at iterator \a j relative to the item
+ at this iterator. If the item at \a j is forward of this time, the returned
+ value is negative.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn QCborMap::Iterator &QCborMap::Iterator::operator+=(qsizetype j)
+
+ Advances the iterator by \a j items. If \a j is negative, the iterator goes
+ backward. Returns a reference to this iterator.
+
+ \sa operator-=(), operator+()
+*/
+
+/*!
+ \fn QCborMap::Iterator &QCborMap::Iterator::operator-=(qsizetype j)
+
+ Makes the iterator go back by \a j items. If \a j is negative, the iterator
+ goes forward. Returns a reference to this iterator.
+
+ \sa operator+=(), operator-()
+*/
+
+/*!
+ \class QCborMap::ConstIterator
+ \inmodule QtCore
+ \ingroup cbor
+ \since 5.12
+
+ \brief The QCborMap::ConstIterator class provides an STL-style const iterator for QCborMap.
+
+ QCborMap::ConstIterator allows you to iterate over a QCborMap. If you want
+ to modify the QCborMap as you iterate over it, you must use
+ QCborMap::Iterator instead. It is generally good practice to use
+ QCborMap::ConstIterator, even on a non-const QCborMap, when you don't need
+ to change the QCborMap through the iterator. Const iterators are slightly
+ faster and improve code readability.
+
+ You must initialize the iterator using a QCborMap function like
+ QCborMap::begin(), QCborMap::end(), or QCborMap::find() before you can
+ start iterating..
+
+ Multiple iterators can be used on the same object. Existing iterators
+ will however become dangling if the object gets modified.
+
+ \sa QCborMap::Iterator
+*/
+
+/*!
+ \typedef QCborMap::ConstIterator::difference_type
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::ConstIterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating
+ this iterator is a random-access iterator.
+*/
+
+/*!
+ \typedef QCborMap::ConstIterator::reference
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::ConstIterator::value_type
+ \internal
+*/
+
+/*!
+ \typedef QCborMap::ConstIterator::pointer
+ \internal
+*/
+
+/*!
+ \fn QCborMap::ConstIterator::ConstIterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QCborMap::constBegin(), QCborMap::constEnd()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator::ConstIterator(const ConstIterator &other)
+
+ Constructs an iterator as a copy of \a other.
+ */
+
+/*!
+ \fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator=(const ConstIterator &other)
+
+ Makes this iterator a copy of \a other and returns a reference to this
+ iterator.
+ */
+
+/*!
+ \fn QString QCborMap::ConstIterator::key() const
+
+ Returns the current item's key.
+
+ \sa value()
+*/
+
+/*!
+ \fn QCborValue QCborMap::ConstIterator::value() const
+
+ Returns the current item's value.
+
+ \sa key(), operator*()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator::value_type QCborMap::ConstIterator::operator*() const
+
+ Returns a pair containing the curent item's key and value.
+
+ \sa key(), value()
+ */
+
+/*!
+ \fn const QCborValueRef *QCborMap::ConstIterator::operator->() const
+
+ Returns a pointer to the current pair's value.
+ */
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator==(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator==(const Iterator &other) const
+
+ Returns \c true if \a other points to the same entry in the map as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator!=(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator!=(const Iterator &other) const
+
+ Returns \c true if \a other points to a different entry in the map than
+ this iterator; otherwise returns \c false.
+
+ \sa operator==()
+ */
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator<(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator<(const ConstIterator &other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs before the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator<=(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator<=(const ConstIterator &other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs before or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator>(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>(const ConstIterator &other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs after the entry pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QCborMap::ConstIterator::operator>=(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>=(const ConstIterator &other) const
+
+ Returns \c true if the entry in the map pointed to by this iterator
+ occurs after or is the same entry as is pointed to by the \a other
+ iterator.
+*/
+
+/*!
+ \fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator++()
+
+ The prefix ++ operator, \c{++i}, advances the iterator to the next item in
+ the map and returns this iterator.
+
+ Calling this function on QCborMap::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator QCborMap::ConstIterator::operator++(int)
+ \overload
+
+ The postfix ++ operator, \c{i++}, advances the iterator to the next item in
+ the map and returns an iterator to the previously current item.
+ */
+
+/*!
+ \fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator--()
+
+ The prefix -- operator, \c{--i}, makes the preceding item current and
+ returns this iterator.
+
+ Calling this function on QCborMap::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator QCborMap::ConstIterator::operator--(int)
+ \overload
+
+ The postfix -- operator, \c{i--}, makes the preceding item current and
+ returns an iterator pointing to the previously current item.
+ */
+
+/*!
+ \fn QCborMap::ConstIterator QCborMap::ConstIterator::operator+(qsizetype j) const
+
+ Returns an iterator to the item at \a j positions forward from this
+ iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator QCborMap::ConstIterator::operator-(qsizetype j) const
+
+ Returns an iterator to the item at \a j positions backward from this
+ iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn qsizetype QCborMap::ConstIterator::operator-(QCborMap::ConstIterator j) const
+
+ Returns the position of the item at iterator \a j relative to the item
+ at this iterator. If the item at \a j is forward of this time, the returned
+ value is negative.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator+=(qsizetype j)
+
+ Advances the iterator by \a j items. If \a j is negative, the iterator goes
+ backward. Returns a reference to this iterator.
+
+ \sa operator-=(), operator+()
+*/
+
+/*!
+ \fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator-=(qsizetype j)
+
+ Makes the iterator go back by \a j items. If \a j is negative, the iterator
+ goes forward. Returns a reference to this iterator.
+
+ \sa operator+=(), operator-()
+*/
+
+uint qHash(const QCborMap &map, uint seed)
+{
+ return qHashRange(map.begin(), map.end(), seed);
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug dbg, const QCborMap &m)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QCborMap{";
+ const char *open = "{";
+ for (auto pair : m) {
+ dbg << open << pair.first << ", " << pair.second << '}';
+ open = ", {";
+ }
+ return dbg << '}';
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h
new file mode 100644
index 0000000000..3eb2107691
--- /dev/null
+++ b/src/corelib/serialization/qcbormap.h
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORMAP_H
+#define QCBORMAP_H
+
+#include <QtCore/qcborvalue.h>
+#include <QtCore/qpair.h>
+
+#include <initializer_list>
+
+QT_BEGIN_NAMESPACE
+
+template <class Key, class T> class QMap;
+typedef QMap<QString, QVariant> QVariantMap;
+template <class Key, class T> class QHash;
+typedef QHash<QString, QVariant> QVariantHash;
+class QJsonObject;
+
+class QCborContainerPrivate;
+class Q_CORE_EXPORT QCborMap
+{
+public:
+ typedef QPair<QCborValue, QCborValue> value_type;
+ typedef QCborValue key_type;
+ typedef QCborValue mapped_type;
+ typedef qsizetype size_type;
+
+ class ConstIterator;
+ class Iterator {
+ mutable QCborValueRef item; // points to the value
+ friend class ConstIterator;
+ friend class QCborMap;
+ Iterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef qsizetype difference_type;
+ typedef QPair<const QCborValueRef, QCborValueRef> value_type;
+ typedef QPair<const QCborValueRef, QCborValueRef> reference;
+ typedef QPair<const QCborValueRef, QCborValueRef> pointer;
+
+ Q_DECL_CONSTEXPR Iterator() = default;
+ Q_DECL_CONSTEXPR Iterator(const Iterator &) = default;
+ Iterator &operator=(const Iterator &other)
+ {
+ // rebind the reference
+ item.d = other.item.d;
+ item.i = other.item.i;
+ return *this;
+ }
+
+ value_type operator*() const { return { {item.d, item.i - 1}, item }; }
+ QCborValueRef *operator->() const { return &item; }
+ QCborValue key() const { return QCborValueRef(item.d, item.i - 1); }
+ QCborValueRef value() const { return item; }
+
+ bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ Iterator &operator++() { item.i += 2; return *this; }
+ Iterator operator++(int) { Iterator n = *this; item.i += 2; return n; }
+ Iterator &operator--() { item.i -= 2; return *this; }
+ Iterator operator--(int) { Iterator n = *this; item.i -= 2; return n; }
+ Iterator &operator+=(qsizetype j) { item.i += 2 * j; return *this; }
+ Iterator &operator-=(qsizetype j) { item.i -= 2 * j; return *this; }
+ Iterator operator+(qsizetype j) const { return Iterator({ item.d, item.i + 2 * j }); }
+ Iterator operator-(qsizetype j) const { return Iterator({ item.d, item.i - 2 * j }); }
+ qsizetype operator-(Iterator j) const { return (item.i - j.item.i) / 2; }
+ };
+
+ class ConstIterator {
+ QCborValueRef item; // points to the value
+ friend class Iterator;
+ friend class QCborMap;
+ ConstIterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef qsizetype difference_type;
+ typedef QPair<const QCborValueRef, const QCborValueRef> value_type;
+ typedef QPair<const QCborValueRef, const QCborValueRef> reference;
+ typedef QPair<const QCborValueRef, const QCborValueRef> pointer;
+
+ Q_DECL_CONSTEXPR ConstIterator() = default;
+ Q_DECL_CONSTEXPR ConstIterator(const ConstIterator &) = default;
+ ConstIterator &operator=(const ConstIterator &other)
+ {
+ // rebind the reference
+ item.d = other.item.d;
+ item.i = other.item.i;
+ return *this;
+ }
+
+ value_type operator*() const { return { {item.d, item.i - 1}, item }; }
+ const QCborValueRef *operator->() const { return &item; }
+ QCborValue key() const { return QCborValueRef(item.d, item.i - 1); }
+ QCborValueRef value() const { return item; }
+
+ bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
+ bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
+ bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
+ bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
+ bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+ ConstIterator &operator++() { item.i += 2; return *this; }
+ ConstIterator operator++(int) { ConstIterator n = *this; item.i += 2; return n; }
+ ConstIterator &operator--() { item.i -= 2; return *this; }
+ ConstIterator operator--(int) { ConstIterator n = *this; item.i -= 2; return n; }
+ ConstIterator &operator+=(qsizetype j) { item.i += 2 * j; return *this; }
+ ConstIterator &operator-=(qsizetype j) { item.i -= 2 * j; return *this; }
+ ConstIterator operator+(qsizetype j) const { return ConstIterator({ item.d, item.i + 2 * j }); }
+ ConstIterator operator-(qsizetype j) const { return ConstIterator({ item.d, item.i - 2 * j }); }
+ qsizetype operator-(ConstIterator j) const { return (item.i - j.item.i) / 2; }
+ };
+
+ QCborMap() noexcept;
+ QCborMap(const QCborMap &other) noexcept;
+ QCborMap &operator=(const QCborMap &other) noexcept;
+ QCborMap(std::initializer_list<value_type> args)
+ : QCborMap()
+ {
+ detach(args.size());
+ for (auto pair : args)
+ insert(pair.first, pair.second);
+ }
+ ~QCborMap();
+
+ void swap(QCborMap &other) noexcept
+ {
+ qSwap(d, other.d);
+ }
+
+ QCborValue toCborValue() const { return *this; }
+
+ qsizetype size() const noexcept Q_DECL_PURE_FUNCTION;
+ bool isEmpty() const { return size() == 0; }
+ void clear();
+ QVector<QCborValue> keys() const;
+
+ QCborValue value(qint64 key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ QCborValue value(QLatin1String key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ QCborValue value(const QString & key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ QCborValue value(const QCborValue &key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ template<size_t N> QT_ASCII_CAST_WARN const QCborValue value(const char (&key)[N]) const
+ { return value(QString::fromUtf8(key, N - 1)); }
+#endif
+ const QCborValue operator[](qint64 key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ const QCborValue operator[](QLatin1String key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ const QCborValue operator[](const QString & key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ const QCborValue operator[](const QCborValue &key) const
+ { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ template<size_t N> QT_ASCII_CAST_WARN const QCborValue operator[](const char (&key)[N]) const
+ { return operator[](QString::fromUtf8(key, N - 1)); }
+#endif
+ QCborValueRef operator[](qint64 key);
+ QCborValueRef operator[](QLatin1String key);
+ QCborValueRef operator[](const QString & key);
+ QCborValueRef operator[](const QCborValue &key);
+
+ QCborValue take(qint64 key)
+ { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ QCborValue take(QLatin1String key)
+ { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ QCborValue take(const QString &key)
+ { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ QCborValue take(const QCborValue &key)
+ { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ void remove(qint64 key)
+ { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ void remove(QLatin1String key)
+ { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ void remove(const QString & key)
+ { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ void remove(const QCborValue &key)
+ { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ bool contains(qint64 key) const
+ { const_iterator it = find(key); return it != end(); }
+ bool contains(QLatin1String key) const
+ { const_iterator it = find(key); return it != end(); }
+ bool contains(const QString & key) const
+ { const_iterator it = find(key); return it != end(); }
+ bool contains(const QCborValue &key) const
+ { const_iterator it = find(key); return it != end(); }
+
+ int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION;
+#if 0 && QT_HAS_INCLUDE(<compare>)
+ std::strong_ordering operator<=>(const QCborMap &other) const
+ {
+ int c = compare(other);
+ if (c > 0) return std::strong_ordering::greater;
+ if (c == 0) return std::strong_ordering::equivalent;
+ return std::strong_ordering::less;
+ }
+#else
+ bool operator==(const QCborMap &other) const noexcept
+ { return compare(other) == 0; }
+ bool operator!=(const QCborMap &other) const noexcept
+ { return !(*this == other); }
+ bool operator<(const QCborMap &other) const
+ { return compare(other) < 0; }
+#endif
+
+ typedef Iterator iterator;
+ typedef ConstIterator const_iterator;
+ iterator begin() { detach(); return iterator{d.data(), 1}; }
+ const_iterator constBegin() const { return const_iterator{d.data(), 1}; }
+ const_iterator begin() const { return constBegin(); }
+ const_iterator cbegin() const { return constBegin(); }
+ iterator end() { detach(); return iterator{d.data(), 2 * size() + 1}; }
+ const_iterator constEnd() const { return const_iterator{d.data(), 2 * size() + 1}; }
+ const_iterator end() const { return constEnd(); }
+ const_iterator cend() const { return constEnd(); }
+ iterator erase(iterator it);
+ iterator erase(const_iterator it) { return erase(iterator{ it.item.d, it.item.i }); }
+ QCborValue extract(iterator it);
+ QCborValue extract(const_iterator it) { return extract(iterator{ it.item.d, it.item.i }); }
+ bool empty() const { return isEmpty(); }
+
+ iterator find(qint64 key);
+ iterator find(QLatin1String key);
+ iterator find(const QString & key);
+ iterator find(const QCborValue &key);
+ const_iterator constFind(qint64 key) const;
+ const_iterator constFind(QLatin1String key) const;
+ const_iterator constFind(const QString & key) const;
+ const_iterator constFind(const QCborValue &key) const;
+ const_iterator find(qint64 key) const { return constFind(key); }
+ const_iterator find(QLatin1String key) const { return constFind(key); }
+ const_iterator find(const QString & key) const { return constFind(key); }
+ const_iterator find(const QCborValue &key) const { return constFind(key); }
+
+ iterator insert(qint64 key, const QCborValue &value_)
+ {
+ QCborValueRef v = operator[](key); // detaches
+ v = value_;
+ return { d.data(), v.i };
+ }
+ iterator insert(QLatin1String key, const QCborValue &value_)
+ {
+ QCborValueRef v = operator[](key); // detaches
+ v = value_;
+ return { d.data(), v.i };
+ }
+ iterator insert(const QString &key, const QCborValue &value_)
+ {
+ QCborValueRef v = operator[](key); // detaches
+ v = value_;
+ return { d.data(), v.i };
+ }
+ iterator insert(const QCborValue &key, const QCborValue &value_)
+ {
+ QCborValueRef v = operator[](key); // detaches
+ v = value_;
+ return { d.data(), v.i };
+ }
+ iterator insert(value_type v) { return insert(v.first, v.second); }
+
+ static QCborMap fromVariantMap(const QVariantMap &map);
+ static QCborMap fromVariantHash(const QVariantHash &hash);
+ static QCborMap fromJsonObject(const QJsonObject &o);
+ QVariantMap toVariantMap() const;
+ QVariantHash toVariantHash() const;
+ QJsonObject toJsonObject() const;
+
+private:
+ void detach(qsizetype reserve = 0);
+
+ friend QCborValue;
+ explicit QCborMap(QCborContainerPrivate &dd) noexcept;
+ QExplicitlySharedDataPointer<QCborContainerPrivate> d;
+};
+
+Q_DECLARE_SHARED(QCborMap)
+
+inline QCborValue::QCborValue(QCborMap &&m)
+ : n(-1), container(m.d.take()), t(Map)
+{
+}
+
+inline QCborMap QCborValueRef::toMap() const
+{
+ return concrete().toMap();
+}
+
+inline QCborMap QCborValueRef::toMap(const QCborMap &m) const
+{
+ return concrete().toMap(m);
+}
+
+Q_CORE_EXPORT uint qHash(const QCborMap &map, uint seed = 0);
+
+#if !defined(QT_NO_DEBUG_STREAM)
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborMap &m);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QCBORMAP_H
diff --git a/src/corelib/serialization/qcborstream.cpp b/src/corelib/serialization/qcborstream.cpp
new file mode 100644
index 0000000000..22286188b8
--- /dev/null
+++ b/src/corelib/serialization/qcborstream.cpp
@@ -0,0 +1,2705 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborstream.h"
+
+#include <private/qnumeric_p.h>
+#include <private/qutfcodec_p.h>
+#include <qbuffer.h>
+#include <qdebug.h>
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_NO_DEBUG
+# define NDEBUG 1
+#endif
+#undef assert
+#define assert Q_ASSERT
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
+QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+
+#define CBOR_ENCODER_NO_CHECK_USER
+
+#define CBOR_NO_VALIDATION_API 1
+#define CBOR_NO_PRETTY_API 1
+#define CBOR_API static inline
+#define CBOR_PRIVATE_API static inline
+#define CBOR_INLINE_API static inline
+
+#include <cbor.h>
+
+static CborError qt_cbor_encoder_write_callback(void *token, const void *data, size_t len, CborEncoderAppendType);
+static bool qt_cbor_decoder_can_read(void *token, size_t len);
+static void qt_cbor_decoder_advance(void *token, size_t len);
+static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len);
+static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len);
+
+#define CBOR_ENCODER_WRITER_CONTROL 1
+#define CBOR_ENCODER_WRITE_FUNCTION qt_cbor_encoder_write_callback
+
+#define CBOR_PARSER_READER_CONTROL 1
+#define CBOR_PARSER_CAN_READ_BYTES_FUNCTION qt_cbor_decoder_can_read
+#define CBOR_PARSER_ADVANCE_BYTES_FUNCTION qt_cbor_decoder_advance
+#define CBOR_PARSER_TRANSFER_STRING_FUNCTION qt_cbor_decoder_transfer_string
+#define CBOR_PARSER_READ_BYTES_FUNCTION qt_cbor_decoder_read
+
+#include "../3rdparty/tinycbor/src/cborencoder.c"
+#include "../3rdparty/tinycbor/src/cborerrorstrings.c"
+#include "../3rdparty/tinycbor/src/cborparser.c"
+
+// silence compilers that complain about this being a static function declared
+// but never defined
+static CborError cbor_encoder_close_container_checked(CborEncoder*, const CborEncoder*)
+{
+ Q_UNREACHABLE();
+ return CborErrorInternalError;
+}
+static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, CborValue *)
+{
+ Q_UNREACHABLE();
+ return CborErrorInternalError;
+}
+QT_WARNING_POP
+
+Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(CborValue, Q_PRIMITIVE_TYPE);
+
+// confirm our constants match TinyCBOR's
+Q_STATIC_ASSERT(int(QCborStreamReader::UnsignedInteger) == CborIntegerType);
+Q_STATIC_ASSERT(int(QCborStreamReader::ByteString) == CborByteStringType);
+Q_STATIC_ASSERT(int(QCborStreamReader::TextString) == CborTextStringType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Array) == CborArrayType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Map) == CborMapType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Tag) == CborTagType);
+Q_STATIC_ASSERT(int(QCborStreamReader::SimpleType) == CborSimpleType);
+Q_STATIC_ASSERT(int(QCborStreamReader::HalfFloat) == CborHalfFloatType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Float) == CborFloatType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Double) == CborDoubleType);
+Q_STATIC_ASSERT(int(QCborStreamReader::Invalid) == CborInvalidType);
+
+/*!
+ \headerfile <QtCborCommon>
+
+ \brief The <QtCborCommon> header contains definitions common to both the
+ streaming classes (QCborStreamReader and QCborStreamWriter) and to
+ QCborValue.
+ */
+
+/*!
+ \enum QCborSimpleType
+ \relates <QtCborCommon>
+
+ This enum contains the possible "Simple Types" for CBOR. Simple Types range
+ from 0 to 255 and are types that carry no further value.
+
+ The following values are currently known:
+
+ \value False A "false" boolean.
+ \value True A "true" boolean.
+ \value Null Absence of value (null).
+ \value Undefined Missing or deleted value, usually an error.
+
+ Qt CBOR API supports encoding and decoding any Simple Type, whether one of
+ those above or any other value.
+
+ Applications should only use further values if a corresponding specification
+ has been published, otherwise interpretation and validation by the remote
+ may fail. Values 24 to 31 are reserved and must not be used.
+
+ The current authoritative list is maintained by IANA in the
+ \l{https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xml}{Simple
+ Values registry}.
+
+ \sa QCborStreamWriter::append(QCborSimpleType), QCborStreamReader::isSimpleType(),
+ QCborStreamReader::toSimpleType(), QCborValue::isSimpleType(), QCborValue::toSimpleType()
+ */
+
+Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
+{
+ switch (st) {
+ case QCborSimpleType::False:
+ return "False";
+ case QCborSimpleType::True:
+ return "True";
+ case QCborSimpleType::Null:
+ return "Null";
+ case QCborSimpleType::Undefined:
+ return "Undefined";
+ }
+ return nullptr;
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug dbg, QCborSimpleType st)
+{
+ QDebugStateSaver saver(dbg);
+ const char *id = qt_cbor_simpletype_id(st);
+ if (id)
+ return dbg.nospace() << "QCborSimpleType::" << id;
+
+ return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
+}
+#endif
+
+/*!
+ \enum QCborTag
+ \relates <QtCborCommon>
+
+ This enum contains no enumeration and is used only to provide type-safe
+ access to a CBOR tag.
+
+ CBOR tags are 64-bit numbers that are attached to generic CBOR types to
+ provide further semantic meaning. QCborTag may be constructed from an
+ enumeration found in QCborKnownTags or directly by providing the numeric
+ representation.
+
+ For example, the following creates a QCborValue containing a byte array
+ tagged with a tag 2.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 0
+
+ \sa QCborKnownTags, QCborStreamWriter::append(QCborTag),
+ QCborStreamReader::isTag(), QCborStreamReader::toTag(),
+ QCborValue::isTag(), QCborValue::tag()
+ */
+
+Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
+{
+ // Casting to QCborKnownTags's underlying type will make the comparison
+ // below fail if the tag value is out of range.
+ auto n = std::underlying_type<QCborKnownTags>::type(tag);
+ if (QCborTag(n) == tag) {
+ switch (QCborKnownTags(n)) {
+ case QCborKnownTags::DateTimeString:
+ return "DateTimeString";
+ case QCborKnownTags::UnixTime_t:
+ return "UnixTime_t";
+ case QCborKnownTags::PositiveBignum:
+ return "PositiveBignum";
+ case QCborKnownTags::NegativeBignum:
+ return "NegativeBignum";
+ case QCborKnownTags::Decimal:
+ return "Decimal";
+ case QCborKnownTags::Bigfloat:
+ return "Bigfloat";
+ case QCborKnownTags::COSE_Encrypt0:
+ return "COSE_Encrypt0";
+ case QCborKnownTags::COSE_Mac0:
+ return "COSE_Mac0";
+ case QCborKnownTags::COSE_Sign1:
+ return "COSE_Sign1";
+ case QCborKnownTags::ExpectedBase64url:
+ return "ExpectedBase64url";
+ case QCborKnownTags::ExpectedBase64:
+ return "ExpectedBase64";
+ case QCborKnownTags::ExpectedBase16:
+ return "ExpectedBase16";
+ case QCborKnownTags::EncodedCbor:
+ return "EncodedCbor";
+ case QCborKnownTags::Url:
+ return "Url";
+ case QCborKnownTags::Base64url:
+ return "Base64url";
+ case QCborKnownTags::Base64:
+ return "Base64";
+ case QCborKnownTags::RegularExpression:
+ return "RegularExpression";
+ case QCborKnownTags::MimeMessage:
+ return "MimeMessage";
+ case QCborKnownTags::Uuid:
+ return "Uuid";
+ case QCborKnownTags::COSE_Encrypt:
+ return "COSE_Encrypt";
+ case QCborKnownTags::COSE_Mac:
+ return "COSE_Mac";
+ case QCborKnownTags::COSE_Sign:
+ return "COSE_Sign";
+ case QCborKnownTags::Signature:
+ return "Signature";
+ }
+ }
+ return nullptr;
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug dbg, QCborTag tag)
+{
+ QDebugStateSaver saver(dbg);
+ const char *id = qt_cbor_tag_id(tag);
+ dbg.nospace() << "QCborTag(";
+ if (id)
+ dbg.nospace() << "QCborKnownTags::" << id;
+ else
+ dbg.nospace() << quint64(tag);
+
+ return dbg << ')';
+}
+#endif
+
+/*!
+ \enum QCborKnownTags
+ \relates <QtCborCommon>
+
+ This enum contains a list of CBOR tags, known at the time of the Qt
+ implementation. This list is not meant to be complete and contains only
+ tags that are either backed by an RFC or specifically used by the Qt
+ implementation.
+
+ The authoritative list is maintained by IANA in the
+ \l{https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml}{CBOR tag
+ registry}.
+
+ \value DateTimeString A date and time string, formatted according to RFC 3339, as refined
+ by RFC 4287. It is the same format as Qt::ISODate and
+ Qt::ISODateWithMs.
+ \value UnixTime_t A numerical representation of seconds elapsed since
+ 1970-01-01T00:00Z.
+ \value PositiveBignum A positive number of arbitrary length, encoded as a byte array in
+ network byte order. For example, the number 2\sup{64} is represented by
+ a byte array containing the byte value 0x01 followed by 8 zero bytes.
+ \value NegativeBignum A negative number of arbirary length, encoded as the absolute value
+ of that number, minus one. For example, a byte array containing
+ byte value 0x02 followed by 8 zero bytes represents the number
+ -2\sup{65} - 1.
+ \value Decimal A decimal fraction, encoded as an array of two integers: the first
+ is the exponent of the power of 10, the second the integral
+ mantissa. The value 273.15 would be encoded as array \c{[-2, 27315]}.
+ \value Bigfloat Similar to Decimal, but the exponent is a power of 2 instead.
+ \value COSE_Encrypt0 An \c Encrypt0 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value COSE_Mac0 A \c Mac0 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value COSE_Sign1 A \c Sign1 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value ExpectedBase64url Indicates that the byte array should be encoded using Base64url
+ if the stream is converted to JSON.
+ \value ExpectedBase64 Indicates that the byte array should be encoded using Base64
+ if the stream is converted to JSON.
+ \value ExpectedBase16 Indicates that the byte array should be encoded using Base16 (hex)
+ if the stream is converted to JSON.
+ \value EncodedCbor Indicates that the byte array contains a CBOR stream.
+ \value Url Indicates that the string contains a URL.
+ \value Base64url Indicates that the string contains data encoded using Base64url.
+ \value Base64 Indicates that the string contains data encoded using Base64.
+ \value RegularExpression Indicates that the string contains a Perl-Compatible Regular
+ Expression pattern.
+ \value MimeMessage Indicates that the string contains a MIME message (according to
+ \l{https://tools.ietf.org/html/rfc2045}){RFC 2045}.
+ \value Uuid Indicates that the byte array contains a UUID.
+ \value COSE_Encrypt An \c Encrypt map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value COSE_Mac A \c Mac map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value COSE_Sign A \c Sign map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
+ (CBOR Object Signing and Encryption).
+ \value Signature No change in interpretation; this tag can be used as the outermost
+ tag in a CBOR stream as the file header.
+
+ The following tags are interpreted by QCborValue during decoding and will
+ produce objects with extended Qt types, and it will use those tags when
+ encoding the same extended types.
+
+ \value DateTimeString \l QDateTime
+ \value UnixTime_t \l QDateTime (only in decoding)
+ \value Url \l QUrl
+ \value Uuid \l QUuid
+
+ Additionally, if a QCborValue containing a QByteArray is tagged using one of
+ \c ExpectedBase64url, \c ExpectedBase64 or \c ExpectedBase16, QCborValue
+ will use the expected encoding when converting to JSON (see
+ QCborValue::toJsonValue).
+
+ \sa QCborTag, QCborStreamWriter::append(QCborTag),
+ QCborStreamReader::isTag(), QCborStreamReader::toTag(),
+ QCborValue::isTag(), QCborValue::tag()
+ */
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug dbg, QCborKnownTags tag)
+{
+ QDebugStateSaver saver(dbg);
+ const char *id = qt_cbor_tag_id(QCborTag(int(tag)));
+ if (id)
+ return dbg.nospace() << "QCborKnownTags::" << id;
+
+ return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
+}
+#endif
+
+/*!
+ \class QCborError
+ \inmodule QtCore
+ \relates <QtCborCommon>
+ \reentrant
+ \since 5.12
+
+ \brief The QCborError class holds the error condition found while parsing or
+ validating a CBOR stream.
+
+ \sa QCborStreamReader, QCborValue, QCborParserError
+ */
+
+/*!
+ \enum QCborError::Code
+
+ This enum contains the possible error condition codes.
+
+ \value NoError No error was detected.
+ \value UnknownError An unknown error occurred and no further details are available.
+ \value AdvancePastEnd QCborStreamReader::next() was called but there are no more elements in
+ the current context.
+ \value InputOutputError An I/O error with the QIODevice occurred.
+ \value GarbageAtEnd Data was found in the input stream after the last element.
+ \value EndOfFile The end of the input stream was unexpectedly reached while processing an
+ element.
+ \value UnexpectedBreak The CBOR stream contains a Break where it is not allowed (data is
+ corrupt and the error is not recoverable).
+ \value UnknownType The CBOR stream contains an unknown/unparseable Type (data is corrupt
+ and the and the error is not recoverable).
+ \value IllegalType The CBOR stream contains a known type in a position it is not allowed
+ to exist (data is corrupt and the error is not recoverable).
+ \value IllegalNumber The CBOR stream appears to be encoding a number larger than 64-bit
+ (data is corrupt and the error is not recoverable).
+ \value IllegalSimpleType The CBOR stream contains a Simple Type encoded incorrectly (data is
+ corrupt and the error is not recoverable).
+ \value InvalidUtf8String The CBOR stream contains a text string that does not decode properly
+ as UTF (data is corrupt and the error is not recoverable).
+ \value DataTooLarge CBOR string, map or array is too big and cannot be parsed by Qt
+ (internal limitation, but the error is not recoverable).
+ \value NestingTooDeep Too many levels of arrays or maps encountered while processing the
+ input (internal limitation, but the error is not recoverable).
+ \value UnsupportedType The CBOR stream contains a known type that the implementation does not
+ support (internal limitation, but the error is not recoverable).
+ */
+
+/*!
+ \variable QCborError::c
+ \internal
+ */
+
+/*!
+ \fn QCborError::operator Code() const
+
+ Returns the error code that this QCborError object stores.
+ */
+
+/*!
+ Returns a text string that matches the error code in this QCborError object.
+
+ Note: the string is not translated. Applications whose interface allow users
+ to parse CBOR streams need to provide their own, translated strings.
+
+ \sa QCborError::Code
+ */
+QString QCborError::toString() const
+{
+ switch (c) {
+ case NoError:
+ Q_STATIC_ASSERT(int(NoError) == int(CborNoError));
+ return QString();
+
+ case UnknownError:
+ Q_STATIC_ASSERT(int(UnknownError) == int(CborUnknownError));
+ return QStringLiteral("Unknown error");
+ case AdvancePastEnd:
+ Q_STATIC_ASSERT(int(AdvancePastEnd) == int(CborErrorAdvancePastEOF));
+ return QStringLiteral("Read past end of buffer (more bytes needed)");
+ case InputOutputError:
+ Q_STATIC_ASSERT(int(InputOutputError) == int(CborErrorIO));
+ return QStringLiteral("Input/Output error");
+ case GarbageAtEnd:
+ Q_STATIC_ASSERT(int(GarbageAtEnd) == int(CborErrorGarbageAtEnd));
+ return QStringLiteral("Data found after the end of the stream");
+ case EndOfFile:
+ Q_STATIC_ASSERT(int(EndOfFile) == int(CborErrorUnexpectedEOF));
+ return QStringLiteral("Unexpected end of input data (more bytes needed)");
+ case UnexpectedBreak:
+ Q_STATIC_ASSERT(int(UnexpectedBreak) == int(CborErrorUnexpectedBreak));
+ return QStringLiteral("Invalid CBOR stream: unexpected 'break' byte");
+ case UnknownType:
+ Q_STATIC_ASSERT(int(UnknownType) == int(CborErrorUnknownType));
+ return QStringLiteral("Invalid CBOR stream: unknown type");
+ case IllegalType:
+ Q_STATIC_ASSERT(int(IllegalType) == int(CborErrorIllegalType));
+ return QStringLiteral("Invalid CBOR stream: illegal type found");
+ case IllegalNumber:
+ Q_STATIC_ASSERT(int(IllegalNumber) == int(CborErrorIllegalNumber));
+ return QStringLiteral("Invalid CBOR stream: illegal number encoding (future extension)");
+ case IllegalSimpleType:
+ Q_STATIC_ASSERT(int(IllegalSimpleType) == int(CborErrorIllegalSimpleType));
+ return QStringLiteral("Invalid CBOR stream: illegal simple type");
+ case InvalidUtf8String:
+ Q_STATIC_ASSERT(int(InvalidUtf8String) == int(CborErrorInvalidUtf8TextString));
+ return QStringLiteral("Invalid CBOR stream: invalid UTF-8 text string");
+ case DataTooLarge:
+ Q_STATIC_ASSERT(int(DataTooLarge) == int(CborErrorDataTooLarge));
+ return QStringLiteral("Internal limitation: data set too large");
+ case NestingTooDeep:
+ Q_STATIC_ASSERT(int(NestingTooDeep) == int(CborErrorNestingTooDeep));
+ return QStringLiteral("Internal limitation: data nesting too deep");
+ case UnsupportedType:
+ Q_STATIC_ASSERT(int(UnsupportedType) == int(CborErrorUnsupportedType));
+ return QStringLiteral("Internal limitation: unsupported type");
+ }
+
+ // get the error from TinyCBOR
+ CborError err = CborError(int(c));
+ return QString::fromLatin1(cbor_error_string(err));
+}
+
+/*!
+ \class QCborStreamWriter
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborStreamWriter class is a simple CBOR encoder operating on a
+ one-way stream.
+
+ This class can be used to quickly encode a stream of CBOR content directly
+ to either a QByteArray or QIODevice. CBOR is the Concise Binary Object
+ Representation, a very compact form of binary data encoding that is
+ compatible with JSON. It was created by the IETF Constrained RESTful
+ Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
+ be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
+ protocol}.
+
+ QCborStreamWriter provides a StAX-like API, similar to that of
+ \l{QXmlStreamWriter}. It is rather low-level and requires a bit of knowledge
+ of CBOR encoding. For a simpler API, see \l{QCborValue} and especially the
+ encoding function QCborValue::toCbor().
+
+ The typical use of QCborStreamWriter is to create the object on the target
+ QByteArray or QIODevice, then call one of the append() overloads with the
+ desired type to be encoded. To create arrays and maps, QCborStreamWriter
+ provides startArray() and startMap() overloads, which must be terminated by
+ the corresponding endArray() and endMap() functions.
+
+ The following example encodes the equivalent of this JSON content:
+
+ \div{class="pre"}
+ {
+ "label": "journald",
+ "autoDetect": false,
+ "condition": "libs.journald",
+ "output": [ "privateFeature" ]
+ }
+ \enddiv
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 1
+
+ \section1 CBOR support
+
+ QCborStreamWriter supports all CBOR features required to create canonical
+ and strict streams. It implements almost all of the features specified in
+ \l {https://tools.ietf.org/html/rfc7049}{RFC 7049}.
+
+ The following table lists the CBOR features that QCborStreamWriter supports.
+
+ \table
+ \header \li Feature \li Support
+ \row \li Unsigned numbers \li Yes (full range)
+ \row \li Negative numbers \li Yes (full range)
+ \row \li Byte strings \li Yes
+ \row \li Text strings \li Yes
+ \row \li Chunked strings \li No
+ \row \li Tags \li Yes (arbitrary)
+ \row \li Booleans \li Yes
+ \row \li Null \li Yes
+ \row \li Undefined \li Yes
+ \row \li Arbitrary simple values \li Yes
+ \row \li Half-precision float (16-bit) \li Yes
+ \row \li Single-precision float (32-bit) \li Yes
+ \row \li Double-precision float (64-bit) \li Yes
+ \row \li Infinities and NaN floating point \li Yes
+ \row \li Determinate-length arrays and maps \li Yes
+ \row \li Indeterminate-length arrays and maps \li Yes
+ \row \li Map key types other than strings and integers \li Yes (arbitrary)
+ \endtable
+
+ \section2 Canonical CBOR encoding
+
+ Canonical CBOR encoding is defined by
+ \l{https://tools.ietf.org/html/rfc7049#section-3.9}{Section 3.9 of RFC
+ 7049}. Canonical encoding is not a requirement for Qt's CBOR decoding
+ functionality, but it may be required for some protocols. In particular,
+ protocols that require the ability to reproduce the same stream identically
+ may require this.
+
+ In order to be considered "canonical", a CBOR stream must meet the
+ following requirements:
+
+ \list
+ \li Integers must be as small as possible. QCborStreamWriter always
+ does this (no user action is required and it is not possible
+ to write overlong integers).
+ \li Array, map and string lengths must be as short as possible. As
+ above, QCborStreamWriter automatically does this.
+ \li Arrays, maps and strings must use explicit length. QCborStreamWriter
+ always does this for strings; for arrays and maps, be sure to call
+ startArray() and startMap() overloads with explicit length.
+ \li Keys in every map must be sorted in ascending order. QCborStreamWriter
+ offers no help in this item: the developer must ensure that before
+ calling append() for the map pairs.
+ \li Floating point values should be as small as possible. QCborStreamWriter
+ will not convert floating point values; it is up to the developer
+ to perform this check prior to calling append() (see those functions'
+ examples).
+ \endlist
+
+ \section2 Strict CBOR mode
+
+ Strict mode is defined by
+ \l{https://tools.ietf.org/html/rfc7049#section-3.10}{Section 3.10 of RFC
+ 7049}. As for Canonical encoding above, QCborStreamWriter makes it possible
+ to create strict CBOR streams, but does not require them or validate that
+ the output is so.
+
+ \list
+ \li Keys in a map must be unique. QCborStreamWriter performs no validation
+ of map keys.
+ \li Tags may be required to be paired only with the correct types,
+ according to their specification. QCborStreamWriter performs no
+ validation of tag usage.
+ \li Text Strings must be properly-encoded UTF-8. QCborStreamWriter always
+ writes proper UTF-8 for strings added with append(), but performs no
+ validation for strings added with appendTextString().
+ \endlist
+
+ \section2 Invalid CBOR stream
+
+ It is also possible to misuse QCborStreamWriter and produce invalid CBOR
+ streams that will fail to be decoded by a receiver. The following actions
+ will produce invalid streams:
+
+ \list
+ \li Append a tag and not append the corresponding tagged value
+ (QCborStreamWriter produces no diagnostic).
+ \li Append too many or too few items to an array or map with explicit
+ length (endMap() and endArray() will return false and
+ QCborStreamWriter will log with qWarning()).
+ \endlist
+
+ \sa QCborStreamReader, QCborValue, QXmlStreamWriter
+ */
+
+class QCborStreamWriterPrivate
+{
+public:
+ static Q_CONSTEXPR quint64 IndefiniteLength = (std::numeric_limits<quint64>::max)();
+
+ QIODevice *device;
+ CborEncoder encoder;
+ QStack<CborEncoder> containerStack;
+ bool deleteDevice = false;
+
+ QCborStreamWriterPrivate(QIODevice *device)
+ : device(device)
+ {
+ cbor_encoder_init_writer(&encoder, qt_cbor_encoder_write_callback, this);
+ }
+
+ ~QCborStreamWriterPrivate()
+ {
+ if (deleteDevice)
+ delete device;
+ }
+
+ template <typename... Args> void executeAppend(CborError (*f)(CborEncoder *, Args...), Args... args)
+ {
+ f(&encoder, std::forward<Args>(args)...);
+ }
+
+ void createContainer(CborError (*f)(CborEncoder *, CborEncoder *, size_t), quint64 len = IndefiniteLength)
+ {
+ Q_STATIC_ASSERT(size_t(IndefiniteLength) == CborIndefiniteLength);
+ if (sizeof(len) != sizeof(size_t) && len != IndefiniteLength) {
+ if (Q_UNLIKELY(len >= CborIndefiniteLength)) {
+ // TinyCBOR can't do this in 32-bit mode
+ qWarning("QCborStreamWriter: container of size %llu is too big for a 32-bit build; "
+ "will use indeterminate length instead", len);
+ len = CborIndefiniteLength;
+ }
+ }
+
+ containerStack.push(encoder);
+ f(&containerStack.top(), &encoder, len);
+ }
+
+ bool closeContainer()
+ {
+ if (containerStack.isEmpty()) {
+ qWarning("QCborStreamWriter: closing map or array that wasn't open");
+ return false;
+ }
+
+ CborEncoder container = containerStack.pop();
+ CborError err = cbor_encoder_close_container(&container, &encoder);
+ encoder = container;
+
+ if (Q_UNLIKELY(err)) {
+ if (err == CborErrorTooFewItems)
+ qWarning("QCborStreamWriter: not enough items added to array or map");
+ else if (err == CborErrorTooManyItems)
+ qWarning("QCborStreamWriter: too many items added to array or map");
+ return false;
+ }
+
+ return true;
+ }
+};
+
+static CborError qt_cbor_encoder_write_callback(void *self, const void *data, size_t len, CborEncoderAppendType)
+{
+ auto that = static_cast<QCborStreamWriterPrivate *>(self);
+ if (!that->device)
+ return CborNoError;
+ qint64 written = that->device->write(static_cast<const char *>(data), len);
+ return (written == qsizetype(len) ? CborNoError : CborErrorIO);
+}
+
+/*!
+ Creates a QCborStreamWriter object that will write the stream to \a device.
+ The device must be opened before the first append() call is made. This
+ constructor can be used with any class that derives from QIODevice, such as
+ QFile, QProcess or QTcpSocket.
+
+ QCborStreamWriter has no buffering, so every append() call will result in
+ one or more calls to the device's \l {QIODevice::}{write()} method.
+
+ The following example writes an empty map to a file:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 2
+
+ QCborStreamWriter does not take ownership of \a device.
+
+ \sa device(), setDevice()
+ */
+QCborStreamWriter::QCborStreamWriter(QIODevice *device)
+ : d(new QCborStreamWriterPrivate(device))
+{
+}
+
+/*!
+ Creates a QCborStreamWriter object that will append the stream to \a data.
+ All streaming is done immediately to the byte array, without the need for
+ flushing any buffers.
+
+ The following example writes a number to a byte array then returns
+ it.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 3
+
+ QCborStreamWriter does not take ownership of \a data.
+ */
+QCborStreamWriter::QCborStreamWriter(QByteArray *data)
+ : d(new QCborStreamWriterPrivate(new QBuffer(data)))
+{
+ d->deleteDevice = true;
+ d->device->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+}
+
+/*!
+ Destroys this QCborStreamWriter object and frees any resources associated.
+
+ QCborStreamWriter does not perform error checking to see if all required
+ items were written to the stream prior to the object being destroyed. It is
+ the programmer's responsibility to ensure that it was done.
+ */
+QCborStreamWriter::~QCborStreamWriter()
+{
+}
+
+/*!
+ Replaces the device or byte array that this QCborStreamWriter object is
+ writing to with \a device.
+
+ \sa device()
+ */
+void QCborStreamWriter::setDevice(QIODevice *device)
+{
+ if (d->deleteDevice)
+ delete d->device;
+ d->device = device;
+ d->deleteDevice = false;
+}
+
+/*!
+ Returns the QIODevice that this QCborStreamWriter object is writing to. The
+ device must have previously been set with either the constructor or with
+ setDevice().
+
+ If this object was created by writing to a QByteArray, this function will
+ return an internal instance of QBuffer, which is owned by QCborStreamWriter.
+
+ \sa setDevice()
+ */
+QIODevice *QCborStreamWriter::device() const
+{
+ return d->device;
+}
+
+/*!
+ \overload
+
+ Appends the 64-bit unsigned value \a u to the CBOR stream, creating a CBOR
+ Unsigned Integer value. In the following example, we write the values 0,
+ 2\sup{32} and \c UINT64_MAX:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 4
+
+ \sa QCborStreamReader::isUnsignedInteger(), QCborStreamReader::toUnsignedInteger()
+ */
+void QCborStreamWriter::append(quint64 u)
+{
+ d->executeAppend(cbor_encode_uint, uint64_t(u));
+}
+
+/*!
+ \overload
+
+ Appends the 64-bit signed value \a i to the CBOR stream. This will create
+ either a CBOR Unsigned Integer or CBOR NegativeInteger value based on the
+ sign of the parameter. In the following example, we write the values 0, -1,
+ 2\sup{32} and \c INT64_MAX:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 5
+
+ \sa QCborStreamReader::isInteger(), QCborStreamReader::toInteger()
+ */
+void QCborStreamWriter::append(qint64 i)
+{
+ d->executeAppend(cbor_encode_int, int64_t(i));
+}
+
+/*!
+ \overload
+
+ Appends the 64-bit negative value \a n to the CBOR stream.
+ QCborNegativeInteger is a 64-bit enum that holds the absolute value of the
+ negative number we want to write. If n is zero, the value written will be
+ equivalent to 2\sup{64} (that is, -18,446,744,073,709,551,616).
+
+ In the following example, we write the values -1, -2\sup{32} and INT64_MIN:
+ \snippet code/src_corelib_serialization_qcborstream.cpp 6
+
+ Note how this function can be used to encode numbers that cannot fit a
+ standard computer's 64-bit signed integer like \l qint64. That is, if \a n
+ is larger than \c{std::numeric_limits<qint64>::max()} or is 0, this will
+ represent a negative number smaller than
+ \c{std::numeric_limits<qint64>::min()}.
+
+ \sa QCborStreamReader::isNegativeInteger(), QCborStreamReader::toNegativeInteger()
+ */
+void QCborStreamWriter::append(QCborNegativeInteger n)
+{
+ d->executeAppend(cbor_encode_negative_int, uint64_t(n));
+}
+
+/*!
+ \fn void QCborStreamWriter::append(const QByteArray &ba)
+ \overload
+
+ Appends the byte array \a ba to the stream, creating a CBOR Byte String
+ value. QCborStreamWriter will attempt to write the entire string in one
+ chunk.
+
+ The following example will load and append the contents of a file to the
+ stream:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 7
+
+ As the example shows, unlike JSON, CBOR requires no escaping for binary
+ content.
+
+ \sa appendByteString(), QCborStreamReader::isByteArray(),
+ QCborStreamReader::readByteArray()
+ */
+
+/*!
+ \overload
+
+ Appends the text string \a str to the stream, creating a CBOR Text String
+ value. QCborStreamWriter will attempt to write the entire string in one
+ chunk.
+
+ The following example appends a simple string to the stream:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 8
+
+ \b{Performance note}: CBOR requires that all Text Strings be encoded in
+ UTF-8, so this function will iterate over the characters in the string to
+ determine whether the contents are US-ASCII or not. If the string is found
+ to contain characters outside of US-ASCII, it will allocate memory and
+ convert to UTF-8. If this check is unnecessary, use appendTextString()
+ instead.
+
+ \sa QCborStreamReader::isString(), QCborStreamReader::readString()
+ */
+void QCborStreamWriter::append(QLatin1String str)
+{
+ // We've got Latin-1 but CBOR wants UTF-8, so check if the string is the
+ // common subset (US-ASCII).
+ if (QtPrivate::isAscii(str)) {
+ // it is plain US-ASCII
+ appendTextString(str.latin1(), str.size());
+ } else {
+ // non-ASCII, so we need a pass-through UTF-16
+ append(QString(str));
+ }
+}
+
+/*!
+ \overload
+
+ Appends the text string \a str to the stream, creating a CBOR Text String
+ value. QCborStreamWriter will attempt to write the entire string in one
+ chunk.
+
+ The following example writes an arbitrary QString to the stream:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 9
+
+ \sa QCborStreamReader::isString(), QCborStreamReader::readString()
+ */
+void QCborStreamWriter::append(QStringView str)
+{
+ QByteArray utf8 = str.toUtf8();
+ appendTextString(utf8.constData(), utf8.size());
+}
+
+/*!
+ \overload
+
+ Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
+ tags must be followed by another type which they provide meaning for.
+
+ In the following example, we append a CBOR Tag 36 (Regular Expression) and a
+ QRegularExpression's pattern to the stream:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 10
+
+ \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
+ */
+void QCborStreamWriter::append(QCborTag tag)
+{
+ d->executeAppend(cbor_encode_tag, CborTag(tag));
+}
+
+/*!
+ \fn void QCborStreamWriter::append(QCborKnownTags tag)
+ \overload
+
+ Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
+ tags must be followed by another type which they provide meaning for.
+
+ In the following example, we append a CBOR Tag 1 (Unix \c time_t) and an
+ integer representing the current time to the stream, obtained using the \c
+ time() function:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 11
+
+ \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
+ */
+
+/*!
+ \overload
+
+ Appends the CBOR simple type \a st to the stream, creating a CBOR Simple
+ Type value. In the following example, we write the simple type for Null as
+ well as for type 32, which Qt has no support for.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 12
+
+ \note Using Simple Types for which there is no specification can lead to
+ validation errors by the remote receiver. In addition, simple type values 24
+ through 31 (inclusive) are reserved and must not be used.
+
+ \sa QCborStreamReader::isSimpleType(), QCborStreamReader::toSimpleType()
+ */
+void QCborStreamWriter::append(QCborSimpleType st)
+{
+ d->executeAppend(cbor_encode_simple_value, uint8_t(st));
+}
+
+/*!
+ \overload
+
+ Appends the floating point number \a f to the stream, creating a CBOR 16-bit
+ Half-Precision Floating Point value. The following code can be used to convert
+ a C++ \tt float to \c qfloat16 if there's no loss of precision and append it, or
+ instead append the \tt float.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 13
+
+ \sa QCborStreamReader::isFloat16(), QCborStreamReader::toFloat16()
+ */
+void QCborStreamWriter::append(qfloat16 f)
+{
+ d->executeAppend(cbor_encode_half_float, static_cast<const void *>(&f));
+}
+
+/*!
+ \overload
+
+ Appends the floating point number \a f to the stream, creating a CBOR 32-bit
+ Single-Precision Floating Point value. The following code can be used to convert
+ a C++ \tt double to \tt float if there's no loss of precision and append it, or
+ instead append the \tt double.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 14
+
+ \sa QCborStreamReader::isFloat(), QCborStreamReader::toFloat()
+ */
+void QCborStreamWriter::append(float f)
+{
+ d->executeAppend(cbor_encode_float, f);
+}
+
+/*!
+ \overload
+
+ Appends the floating point number \a d to the stream, creating a CBOR 64-bit
+ Double-Precision Floating Point value. QCborStreamWriter always appends the
+ number as-is, performing no check for whether the number is the canonical
+ form for NaN, an infinite, whether it is denormal or if it could be written
+ with a shorter format.
+
+ The following code performs all those checks, except for the denormal one,
+ which is expected to be taken into account by the system FPU or floating
+ point emulation directly.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 15
+
+ Determining if a double can be converted to an integral with no loss of
+ precision is left as an exercise to the reader.
+
+ \sa QCborStreamReader::isDouble(), QCborStreamReader::toDouble()
+ */
+void QCborStreamWriter::append(double d)
+{
+ this->d->executeAppend(cbor_encode_double, d);
+}
+
+/*!
+ Appends \a len bytes of data starting from \a data to the stream, creating a
+ CBOR Byte String value. QCborStreamWriter will attempt to write the entire
+ string in one chunk.
+
+ Unlike the QByteArray overload of append(), this function is not limited by
+ QByteArray's size limits. However, note that neither
+ QCborStreamReader::readByteArray() nor QCborValue support reading CBOR
+ streams with byte arrays larger than 2 GB.
+
+ \sa append(), appendTextString(),
+ QCborStreamReader::isByteArray(), QCborStreamReader::readByteArray()
+ */
+void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
+{
+ d->executeAppend(cbor_encode_byte_string, reinterpret_cast<const uint8_t *>(data), size_t(len));
+}
+
+/*!
+ Appends \a len bytes of text starting from \a utf8 to the stream, creating a
+ CBOR Text String value. QCborStreamWriter will attempt to write the entire
+ string in one chunk.
+
+ The string pointed to by \a utf8 is expected to be properly encoded UTF-8.
+ QCborStreamWriter performs no validation that this is the case.
+
+ Unlike the QLatin1String overload of append(), this function is not limited
+ to 2 GB. However, note that neither QCborStreamReader::readString() nor
+ QCborValue support reading CBOR streams with text strings larger than 2 GB.
+
+ \sa append(QLatin1String), append(QStringView),
+ QCborStreamReader::isString(), QCborStreamReader::readString()
+ */
+void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
+{
+ d->executeAppend(cbor_encode_text_string, utf8, size_t(len));
+}
+
+/*!
+ \fn void QCborStreamWriter::append(const char *str, qsizetype size)
+ \overload
+
+ Appends \a size bytes of text starting from \a str to the stream, creating a
+ CBOR Text String value. QCborStreamWriter will attempt to write the entire
+ string in one chunk. If \a size is -1, this function will write \c strlen(\a
+ str) bytes.
+
+ The string pointed to by \a str is expected to be properly encoded UTF-8.
+ QCborStreamWriter performs no validation that this is the case.
+
+ Unlike the QLatin1String overload of append(), this function is not limited
+ to 2 GB. However, note that neither QCborStreamReader nor QCborValue support
+ reading CBOR streams with text strings larger than 2 GB.
+
+ \sa append(QLatin1String), append(QStringView),
+ QCborStreamReader::isString(), QCborStreamReader::readString()
+ */
+
+/*!
+ \fn void QCborStreamWriter::append(bool b)
+ \overload
+
+ Appends the boolean value \a b to the stream, creating either a CBOR False
+ value or a CBOR True value. This function is equivalent to (and implemented
+ as):
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 16
+
+ \sa appendNull(), appendUndefined(),
+ QCborStreamReader::isBool(), QCborStreamReader::toBool()
+ */
+
+/*!
+ \fn void QCborStreamWriter::append(std::nullptr_t)
+ \overload
+
+ Appends a CBOR Null value to the stream. This function is equivalent to (and
+ implemented as): The parameter is ignored.
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 17
+
+ \sa appendNull(), append(QCborSimpleType), QCborStreamReader::isNull()
+ */
+
+/*!
+ \fn void QCborStreamWriter::appendNull()
+
+ Appends a CBOR Null value to the stream. This function is equivalent to (and
+ implemented as):
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 18
+
+ \sa append(std::nullptr_t), append(QCborSimpleType), QCborStreamReader::isNull()
+ */
+
+/*!
+ \fn void QCborStreamWriter::appendUndefined()
+
+ Appends a CBOR Undefined value to the stream. This function is equivalent to (and
+ implemented as):
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 19
+
+ \sa append(QCborSimpleType), QCborStreamReader::isUndefined()
+ */
+
+/*!
+ Starts a CBOR Array with indeterminate length in the CBOR stream. Each
+ startArray() call must be paired with one endArray() call and the current
+ CBOR element extends until the end of the array.
+
+ The array created by this function has no explicit length. Instead, its
+ length is implied by the elements contained in it. Note, however, that use
+ of indeterminate-length arrays is not compliant with canonical CBOR encoding.
+
+ The following example appends elements from the linked list of strings
+ passed as input:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 20
+
+ \sa startArray(quint64), endArray(), startMap(), QCborStreamReader::isArray(),
+ QCborStreamReader::isLengthKnown()
+ */
+void QCborStreamWriter::startArray()
+{
+ d->createContainer(cbor_encoder_create_array);
+}
+
+/*!
+ \overload
+
+ Starts a CBOR Array with explicit length of \a count items in the CBOR
+ stream. Each startArray call must be paired with one endArray() call and the
+ current CBOR element extends until the end of the array.
+
+ The array created by this function has an explicit length and therefore
+ exactly \a count items must be added to the CBOR stream. Adding fewer or
+ more items will result in failure during endArray() and the CBOR stream will
+ be corrupt. However, explicit-length arrays are required by canonical CBOR
+ encoding.
+
+ The following example appends all strings found in the \l QStringList passed as input:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 21
+
+ \b{Size limitations}: The parameter to this function is quint64, which would
+ seem to allow up to 2\sup{64}-1 elements in the array. However, both
+ QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2
+ items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that
+ QCborArray is currently limited to 2\sup{27} elements in any platform.
+
+ \sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
+ QCborStreamReader::isLengthKnown()
+ */
+void QCborStreamWriter::startArray(quint64 count)
+{
+ d->createContainer(cbor_encoder_create_array, count);
+}
+
+/*!
+ Terminates the array started by either overload of startArray() and returns
+ true if the correct number of elements was added to the array. This function
+ must be called for every startArray() used.
+
+ A return of false indicates error in the application and an unrecoverable
+ error in this stream. QCborStreamWriter also writes a warning using
+ qWarning() if that happens.
+
+ Calling this function when the current container is not an array is also an
+ error, though QCborStreamWriter cannot currently detect this condition.
+
+ \sa startArray(), startArray(quint64), endMap()
+ */
+bool QCborStreamWriter::endArray()
+{
+ return d->closeContainer();
+}
+
+/*!
+ Starts a CBOR Map with indeterminate length in the CBOR stream. Each
+ startMap() call must be paired with one endMap() call and the current CBOR
+ element extends until the end of the map.
+
+ The map created by this function has no explicit length. Instead, its length
+ is implied by the elements contained in it. Note, however, that use of
+ indeterminate-length maps is not compliant with canonical CBOR encoding
+ (canonical encoding also requires keys to be unique and in sorted order).
+
+ The following example appends elements from the linked list of int and
+ string pairs passed as input:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 22
+
+ \sa startMap(quint64), endMap(), startArray(), QCborStreamReader::isMap(),
+ QCborStreamReader::isLengthKnown()
+ */
+void QCborStreamWriter::startMap()
+{
+ d->createContainer(cbor_encoder_create_map);
+}
+
+/*!
+ \overload
+
+ Starts a CBOR Map with explicit length of \a count items in the CBOR
+ stream. Each startMap call must be paired with one endMap() call and the
+ current CBOR element extends until the end of the map.
+
+ The map created by this function has an explicit length and therefore
+ exactly \a count pairs of items must be added to the CBOR stream. Adding
+ fewer or more items will result in failure during endMap() and the CBOR
+ stream will be corrupt. However, explicit-length map are required by
+ canonical CBOR encoding.
+
+ The following example appends all strings found in the \l QMap passed as input:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 23
+
+ \b{Size limitations}: The parameter to this function is quint64, which would
+ seem to allow up to 2\sup{64}-1 pairs in the map. However, both
+ QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1
+ items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that
+ QCborMap is currently limited to 2\sup{26} elements in any platform.
+
+ \sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
+ QCborStreamReader::isLengthKnown()
+ */
+void QCborStreamWriter::startMap(quint64 count)
+{
+ d->createContainer(cbor_encoder_create_map, count);
+}
+
+/*!
+ Terminates the map started by either overload of startMap() and returns
+ true if the correct number of elements was added to the array. This function
+ must be called for every startMap() used.
+
+ A return of false indicates error in the application and an unrecoverable
+ error in this stream. QCborStreamWriter also writes a warning using
+ qWarning() if that happens.
+
+ Calling this function when the current container is not a map is also an
+ error, though QCborStreamWriter cannot currently detect this condition.
+
+ \sa startMap(), startMap(quint64), endArray()
+ */
+bool QCborStreamWriter::endMap()
+{
+ return d->closeContainer();
+}
+
+/*!
+ \class QCborStreamReader
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborStreamReader class is a simple CBOR stream decoder, operating
+ on either a QByteArray or QIODevice.
+
+ This class can be used to decode a stream of CBOR content directly from
+ either a QByteArray or a QIODevice. CBOR is the Concise Binary Object
+ Representation, a very compact form of binary data encoding that is
+ compatible with JSON. It was created by the IETF Constrained RESTful
+ Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
+ be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
+ protocol}.
+
+ QCborStreamReader provides a StAX-like API, similar to that of
+ \l{QXmlStreamReader}. Using it requires a bit of knowledge of CBOR encoding.
+ For a simpler API, see \l{QCborValue} and especially the decoding function
+ QCborValue::fromCbor().
+
+ Typically, one creates a QCborStreamReader by passing the source QByteArray
+ or QIODevice as a parameter to the constructor, then pop elements off the
+ stream if there were no errors in decoding. There are three kinds of CBOR
+ types:
+
+ \table
+ \header \li Kind \li Types \li Behavior
+ \row \li Fixed-width \li Integers, Tags, Simple types, Floating point
+ \li Value is pre-parsed by QCborStreamReader, so accessor functions
+ are \c const. Must call next() to advance.
+ \row \li Strings \li Byte arrays, Text strings
+ \li Length (if known) is pre-parsed, but the string itself is not.
+ The accessor functions are not const and may allocate memory.
+ Once called, the accessor functions automatically advance to
+ the next element.
+ \row \li Containers \li Arrays, Maps
+ \li Length (if known) is pre-parsed. To access the elements, you
+ must call enterContainer(), read all elements, then call
+ leaveContainer(). That function advances to the next element.
+ \endtable
+
+ So a processor function typically looks like this:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 24
+
+ \section1 CBOR support
+
+ The following table lists the CBOR features that QCborStreamReader supports.
+
+ \table
+ \header \li Feature \li Support
+ \row \li Unsigned numbers \li Yes (full range)
+ \row \li Negative numbers \li Yes (full range)
+ \row \li Byte strings \li Yes
+ \row \li Text strings \li Yes
+ \row \li Chunked strings \li Yes
+ \row \li Tags \li Yes (arbitrary)
+ \row \li Booleans \li Yes
+ \row \li Null \li Yes
+ \row \li Undefined \li Yes
+ \row \li Arbitrary simple values \li Yes
+ \row \li Half-precision float (16-bit) \li Yes
+ \row \li Single-precision float (32-bit) \li Yes
+ \row \li Double-precision float (64-bit) \li Yes
+ \row \li Infinities and NaN floating point \li Yes
+ \row \li Determinate-length arrays and maps \li Yes
+ \row \li Indeterminate-length arrays and maps \li Yes
+ \row \li Map key types other than strings and integers \li Yes (arbitrary)
+ \endtable
+
+ \section1 Dealing with invalid or incomplete CBOR streams
+
+ QCborStreamReader is capable of detecting corrupt input on its own. The
+ library it uses has been extensively tested against invalid input of any
+ kind and is quite able to report errors. If any is detected,
+ QCborStreamReader will set lastError() to a value besides
+ QCborError::NoError, indicating which situation was detected.
+
+ Most errors detected by QCborStreamReader during normal item parsing are not
+ recoverable. The code using QCborStreamReader may opt to handle the data
+ that was properly decoded or it can opt to discard the entire data.
+
+ The only recoverable error is QCborError::EndOfFile, which indicates that
+ more data is required in order to complete the parsing. This situation is
+ useful when data is being read from an asynchronous source, such as a pipe
+ (QProcess) or a socket (QTcpSocket, QUdpSocket, QNetworkReply, etc.). When
+ more data arrives, the surrounding code needs to call either addData(), if
+ parsing from a QByteArray, or reparse(), if it is instead reading directly
+ a the QIDOevice that now has more data available (see setDevice()).
+
+ \sa QCborStreamWriter, QCborValue, QXmlStreamReader
+ */
+
+/*!
+ \enum QCborStreamReader::Type
+
+ This enumeration contains all possible CBOR types as decoded by
+ QCborStreamReader. CBOR has 7 major types, plus a number of simple types
+ carrying no value, and floating point values.
+
+ \value UnsignedInteger (Major type 0) Ranges from 0 to 2\sup{64} - 1
+ (18,446,744,073,709,551,616)
+ \value NegativeInteger (Major type 1) Ranges from -1 to -2\sup{64}
+ (-18,446,744,073,709,551,616)
+ \value ByteArray (Major type 2) Arbitrary binary data.
+ \value ByteString An alias to ByteArray.
+ \value String (Major type 3) Unicode text, possibly containing NULs.
+ \value TextString An alias to String
+ \value Array (Major type 4) Array of heterogeneous items.
+ \value Map (Major type 5) Map/dictionary of heterogeneous items.
+ \value Tag (Major type 6) Numbers giving further semantic value
+ to generic CBOR items. See \l QCborTag for more information.
+ \value SimpleType (Major type 7) Types carrying no further value. Includes
+ booleans (true and false), null, undefined.
+ \value Float16 IEEE 754 half-precision floating point (\c qfloat16).
+ \value HalfFloat An alias to Float16.
+ \value Float IEEE 754 single-precision floating point (\tt float).
+ \value Double IEEE 754 double-precision floating point (\tt double).
+ \value Invalid Not a valid type, either due to parsing error or due to
+ reaching the end of an array or map.
+ */
+
+/*!
+ \enum QCborStreamReader::StringResultCode
+
+ This enum is returned by readString() and readByteArray() and is used to
+ indicate what the status of the parsing is.
+
+ \value EndOfString The parsing for the string is complete, with no error.
+ \value Ok The function returned data; there was no error.
+ \value Error Parsing failed with an error.
+ */
+
+/*!
+ \class QCborStreamReader::StringResult
+
+ This class is returned by readString() and readByteArray(), with either the
+ contents of the string that was read or an indication that the parsing is
+ done or found an error.
+
+ The contents of \l data are valid only if \l status is
+ \l{StringResultCode}{Ok}. Otherwise, it should be null.
+ */
+
+/*!
+ \variable Container QCborStreamReader::StringResult::data
+ Contains the actual data from the string if \l status is \c Ok.
+ */
+
+/*!
+ \variable QCborStreamReader::StringResultCode QCborStreamReader::StringResult::status
+ Contains the status of the attempt of reading the string from the stream.
+ */
+
+/*!
+ \fn QCborStreamReader::Type QCborStreamReader::type() const
+
+ Returns the type of the current element. It is one of the valid types or
+ Invalid.
+
+ \sa isValid(), isUnsignedInteger(), isNegativeInteger(), isInteger(),
+ isByteArray(), isString(), isArray(), isMap(), isTag(), isSimpleType(),
+ isBool(), isFalse(), isTrue(), isNull(), isUndefined(), isFloat16(),
+ isFloat(), isDouble()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isValid() const
+
+ Returns true if the current element is valid, false otherwise. The current
+ element may be invalid if there was a decoding error or we've just parsed
+ the last element in an array or map.
+
+ \note This function is not the opposite of isNull(). Null is a normal CBOR
+ type that must be handled by the application.
+
+ \sa type(), isInvalid()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isInvalid() const
+
+ Returns true if the current element is invalid, false otherwise. The current
+ element may be invalid if there was a decoding error or we've just parsed
+ the last element in an array or map.
+
+ \note This function is not to be confused with isNull(). Null is a normal
+ CBOR type that must be handled by the application.
+
+ \sa type(), isValid()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isUnsignedInteger() const
+
+ Returns true if the type of the current element is an unsigned integer (that
+ is if type() returns QCborStreamReader::UnsignedInteger). If this function
+ returns true, you may call toUnsignedInteger() or toInteger() to read that value.
+
+ \sa type(), toUnsignedInteger(), toInteger(), isInteger(), isNegativeInteger()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isNegativeInteger() const
+
+ Returns true if the type of the current element is a negative integer (that
+ is if type() returns QCborStreamReader::NegativeInteger). If this function
+ returns true, you may call toNegativeInteger() or toInteger() to read that value.
+
+ \sa type(), toNegativeInteger(), toInteger(), isInteger(), isUnsignedInteger()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isInteger() const
+
+ Returns true if the type of the current element is either an unsigned
+ integer or a negative one (that is, if type() returns
+ QCborStreamReader::UnsignedInteger or QCborStreamReader::NegativeInteger).
+ If this function returns true, you may call toInteger() to read that
+ value.
+
+ \sa type(), toInteger(), toUnsignedInteger(), toNegativeInteger(),
+ isUnsignedInteger(), isNegativeInteger()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isByteArray() const
+
+ Returns true if the type of the current element is a byte array (that is,
+ if type() returns QCborStreamReader::ByteArray). If this function returns
+ true, you may call readByteArray() to read that data.
+
+ \sa type(), readByteArray(), isString()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isString() const
+
+ Returns true if the type of the current element is a text string (that is,
+ if type() returns QCborStreamReader::String). If this function returns
+ true, you may call readString() to read that data.
+
+ \sa type(), readString(), isByteArray()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isArray() const
+
+ Returns true if the type of the current element is an array (that is,
+ if type() returns QCborStreamReader::Array). If this function returns
+ true, you may call enterContainer() to begin parsing that container.
+
+ When the current element is an array, you may also call isLengthKnown() to
+ find out if the array's size is explicit in the CBOR stream. If it is, that
+ size can be obtained by calling length().
+
+ The following example pre-allocates a QVariantList given the array's size
+ for more efficient decoding:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 25
+
+ \note The code above does not validate that the length is a sensible value.
+ If the input stream reports that the length is 1 billion elements, the above
+ function will try to allocate some 16 GB or more of RAM, which can lead to a
+ crash.
+
+ \sa type(), isMap(), isLengthKnown(), length(), enterContainer(), leaveContainer()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isMap() const
+
+ Returns true if the type of the current element is a map (that is, if type()
+ returns QCborStreamReader::Map). If this function returns true, you may call
+ enterContainer() to begin parsing that container.
+
+ When the current element is a map, you may also call isLengthKnown() to
+ find out if the map's size is explicit in the CBOR stream. If it is, that
+ size can be obtained by calling length().
+
+ The following example pre-allocates a QVariantMap given the map's size
+ for more efficient decoding:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 26
+
+ The example above uses a function called \c readElementAsString to read the
+ map's keys and obtain a string. That is because CBOR maps may contain any
+ type as keys, not just strings. User code needs to either perform this
+ conversion, reject non-string keys, or instead use a different container
+ besides \l QVariantMap and \l QVariantHash. For example, if the map is
+ expected to contain integer keys, which is recommended as it reduces stream
+ size and parsing, the correct container would be \c{\l{QMap}<int, QVariant>}
+ or \c{\l{QHash}<int, QVariant>}.
+
+ \note The code above does not validate that the length is a sensible value.
+ If the input stream reports that the length is 1 billion elements, the above
+ function will try to allocate some 24 GB or more of RAM, which can lead to a
+ crash.
+
+ \sa type(), isArray(), isLengthKnown(), length(), enterContainer(), leaveContainer()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isTag() const
+
+ Returns true if the type of the current element is a CBOR tag (that is,
+ if type() returns QCborStreamReader::Tag). If this function returns
+ true, you may call toTag() to read that data.
+
+ \sa type(), toTag()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isFloat16() const
+
+ Returns true if the type of the current element is an IEEE 754
+ half-precision floating point (that is, if type() returns
+ QCborStreamReader::Float16). If this function returns true, you may call
+ toFloat16() to read that data.
+
+ \sa type(), toFloat16(), isFloat(), isDouble()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isFloat() const
+
+ Returns true if the type of the current element is an IEEE 754
+ single-precision floating point (that is, if type() returns
+ QCborStreamReader::Float). If this function returns true, you may call
+ toFloat() to read that data.
+
+ \sa type(), toFloat(), isFloat16(), isDouble()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isDouble() const
+
+ Returns true if the type of the current element is an IEEE 754
+ double-precision floating point (that is, if type() returns
+ QCborStreamReader::Double). If this function returns true, you may call
+ toDouble() to read that data.
+
+ \sa type(), toDouble(), isFloat16(), isFloat()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isSimpleType() const
+
+ Returns true if the type of the current element is any CBOR simple type,
+ including a boolean value (true and false) as well as null and undefined. To
+ find out which simple type this is, call toSimpleType(). Alternatively, to
+ test for one specific simple type, call the overload that takes a
+ QCborSimpleType parameter.
+
+ CBOR simple types are types that do not carry extra value. There are 255
+ possibilities, but there are currently only four values that have defined
+ meaning. Code is not expected to cope with unknown simple types and may
+ simply discard the stream as invalid if it finds an unknown one.
+
+ \sa QCborSimpleType, type(), isSimpleType(QCborSimpleType), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isSimpleType(QCborSimpleType st) const
+
+ Returns true if the type of the current element is the simple type \a st,
+ false otherwise. If this function returns true, then toSimpleType() will
+ return \a st.
+
+ CBOR simple types are types that do not carry extra value. There are 255
+ possibilities, but there are currently only four values that have defined
+ meaning. Code is not expected to cope with unknown simple types and may
+ simply discard the stream as invalid if it finds an unknown one.
+
+ \sa QCborSimpleType, type(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isFalse() const
+
+ Returns true if the current element is the \c false value, false if it is
+ anything else.
+
+ \sa type(), isTrue(), isBool(), toBool(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isTrue() const
+
+ Returns true if the current element is the \c true value, false if it is
+ anything else.
+
+ \sa type(), isFalse(), isBool(), toBool(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isBool() const
+
+ Returns true if the current element is a boolean value (\c true or \c
+ false), false if it is anything else. If this function returns true, you may
+ call toBool() to retrieve the value of the boolean. You may also call
+ toSimpleType() and compare to either QCborSimpleValue::True or
+ QCborSimpleValue::False.
+
+ \sa type(), isFalse(), isTrue(), toBool(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isNull() const
+
+ Returns true if the current element is the \c null value, false if it is
+ anything else. Null values may be used to indicate the absence of some
+ optional data.
+
+ \note This function is not the opposite of isValid(). A Null value is a
+ valid CBOR value.
+
+ \sa type(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isUndefined() const
+
+ Returns true if the current element is the \c undefined value, false if it
+ is anything else. Undefined values may be encoded to indicate that some
+ conversion failed or was not possible when creating the stream.
+ QCborStreamReader never performs any replacement and this function will only
+ return true if the stream contains an explicit undefined value.
+
+ \sa type(), isSimpleType(), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborStreamReader::isContainer() const
+
+ Returns true if the current element is a container (that is, an array or a
+ map), false if it is anything else. If the current element is a container,
+ the isLengthKnown() function may be used to find out if the container's size
+ is explicit in the stream and, if so, length() can be used to get that size.
+
+ More importantly, for a container, the enterContainer() function is
+ available to begin iterating through the elements contained therein.
+
+ \sa type(), isArray(), isMap(), isLengthKnown(), length(), enterContainer(),
+ leaveContainer(), containerDepth()
+ */
+
+class QCborStreamReaderPrivate
+{
+public:
+ enum {
+ // 9 bytes is the maximum size for any integer, floating point or
+ // length in CBOR.
+ MaxCborIndividualSize = 9,
+ IdealIoBufferSize = 256
+ };
+
+ QIODevice *device;
+ QByteArray buffer;
+ QStack<CborValue> containerStack;
+
+ CborParser parser;
+ CborValue currentElement;
+ QCborError lastError = {};
+
+ QByteArray::size_type bufferStart;
+ bool corrupt = false;
+
+ QCborStreamReaderPrivate(const QByteArray &data)
+ : device(nullptr), buffer(data)
+ {
+ initDecoder();
+ }
+
+ QCborStreamReaderPrivate(QIODevice *device)
+ {
+ setDevice(device);
+ }
+
+ ~QCborStreamReaderPrivate()
+ {
+ }
+
+ void setDevice(QIODevice *dev)
+ {
+ buffer.clear();
+ device = dev;
+ initDecoder();
+ }
+
+ void initDecoder()
+ {
+ containerStack.clear();
+ bufferStart = 0;
+ if (device) {
+ buffer.clear();
+ buffer.reserve(IdealIoBufferSize); // sets the CapacityReserved flag
+ }
+
+ preread();
+ if (CborError err = cbor_parser_init_reader(nullptr, &parser, &currentElement, this))
+ handleError(err);
+ }
+
+ char *bufferPtr()
+ {
+ Q_ASSERT(buffer.isDetached());
+ return const_cast<char *>(buffer.constData()) + bufferStart;
+ }
+
+ void preread()
+ {
+ if (device && buffer.size() - bufferStart < MaxCborIndividualSize) {
+ // load more, but only if there's more to be read
+ qint64 avail = device->bytesAvailable();
+ Q_ASSERT(avail >= buffer.size());
+ if (avail == buffer.size())
+ return;
+
+ if (bufferStart)
+ device->skip(bufferStart); // skip what we've already parsed
+
+ if (buffer.size() != IdealIoBufferSize)
+ buffer.resize(IdealIoBufferSize);
+
+ bufferStart = 0;
+ qint64 read = device->peek(bufferPtr(), IdealIoBufferSize);
+ if (read < 0)
+ buffer.clear();
+ else if (read != IdealIoBufferSize)
+ buffer.truncate(read);
+ }
+ }
+
+ void handleError(CborError err) noexcept
+ {
+ Q_ASSERT(err);
+
+ // is the error fatal?
+ if (err != CborErrorUnexpectedEOF)
+ corrupt = true;
+
+ // our error codes are the same (for now)
+ lastError = { QCborError::Code(err) };
+ }
+
+ void updateBufferAfterString(qsizetype offset, qsizetype size)
+ {
+ Q_ASSERT(device);
+
+ bufferStart += offset;
+ qsizetype newStart = bufferStart + size;
+ qsizetype remainingInBuffer = buffer.size() - newStart;
+
+ if (remainingInBuffer <= 0) {
+ // We've read from the QIODevice more than what was in the buffer.
+ buffer.truncate(0);
+ } else {
+ // There's still data buffered, but we need to move it around.
+ char *ptr = buffer.data();
+ memmove(ptr, ptr + newStart, remainingInBuffer);
+ buffer.truncate(remainingInBuffer);
+ }
+
+ bufferStart = 0;
+ }
+
+ bool ensureStringIteration();
+};
+
+void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error)
+{
+ d->handleError(CborError(error.c));
+}
+
+static inline bool qt_cbor_decoder_can_read(void *token, size_t len)
+{
+ Q_ASSERT(len <= QCborStreamReaderPrivate::MaxCborIndividualSize);
+ auto self = static_cast<QCborStreamReaderPrivate *>(token);
+
+ qint64 avail = self->buffer.size() - self->bufferStart;
+ return len <= quint64(avail);
+}
+
+static void qt_cbor_decoder_advance(void *token, size_t len)
+{
+ Q_ASSERT(len <= QCborStreamReaderPrivate::MaxCborIndividualSize);
+ auto self = static_cast<QCborStreamReaderPrivate *>(token);
+ Q_ASSERT(len <= size_t(self->buffer.size() - self->bufferStart));
+
+ self->bufferStart += int(len);
+ self->preread();
+}
+
+static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len)
+{
+ Q_ASSERT(len == 1 || len == 2 || len == 4 || len == 8);
+ Q_ASSERT(offset == 0 || offset == 1);
+ auto self = static_cast<const QCborStreamReaderPrivate *>(token);
+
+ // we must have pre-read the data
+ Q_ASSERT(len + offset <= size_t(self->buffer.size() - self->bufferStart));
+ return memcpy(userptr, self->buffer.constData() + self->bufferStart + offset, len);
+}
+
+static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len)
+{
+ auto self = static_cast<QCborStreamReaderPrivate *>(token);
+ Q_ASSERT(offset <= size_t(self->buffer.size()));
+ Q_STATIC_ASSERT(sizeof(size_t) >= sizeof(QByteArray::size_type));
+ Q_STATIC_ASSERT(sizeof(size_t) == sizeof(qsizetype));
+
+ // check that we will have enough data from the QIODevice before we advance
+ // (otherwise, we'd lose the length information)
+ qsizetype total;
+ if (len > size_t(std::numeric_limits<QByteArray::size_type>::max())
+ || add_overflow<qsizetype>(offset, len, &total))
+ return CborErrorDataTooLarge;
+
+ // our string transfer is just saving the offset to the userptr
+ *userptr = reinterpret_cast<void *>(offset);
+
+ qint64 avail = (self->device ? self->device->bytesAvailable() : self->buffer.size()) -
+ self->bufferStart;
+ return total > avail ? CborErrorUnexpectedEOF : CborNoError;
+}
+
+bool QCborStreamReaderPrivate::ensureStringIteration()
+{
+ if (currentElement.flags & CborIteratorFlag_IteratingStringChunks)
+ return true;
+
+ CborError err = cbor_value_begin_string_iteration(&currentElement);
+ if (!err)
+ return true;
+ handleError(err);
+ return false;
+}
+
+/*!
+ \internal
+ */
+inline void QCborStreamReader::preparse()
+{
+ if (lastError() == QCborError::NoError) {
+ type_ = cbor_value_get_type(&d->currentElement);
+
+ if (type_ != CborInvalidType) {
+ d->lastError = {};
+ // Undo the type mapping that TinyCBOR does (we have an explicit type
+ // for negative integer and we don't have separate types for Boolean,
+ // Null and Undefined).
+ if (type_ == CborBooleanType || type_ == CborNullType || type_ == CborUndefinedType) {
+ type_ = SimpleType;
+ value64 = quint8(d->buffer.at(d->bufferStart)) - CborSimpleType;
+ } else {
+ // Using internal TinyCBOR API!
+ value64 = _cbor_value_extract_int64_helper(&d->currentElement);
+
+ if (cbor_value_is_negative_integer(&d->currentElement))
+ type_ = quint8(QCborStreamReader::NegativeInteger);
+ }
+ }
+ } else {
+ type_ = Invalid;
+ }
+}
+
+/*!
+ Creates a QCborStreamReader object with no source data. After construction,
+ QCborStreamReader will report an error parsing.
+
+ You can add more data by calling addData() or by setting a different source
+ device using setDevice().
+
+ \sa addData(), isValid()
+ */
+QCborStreamReader::QCborStreamReader()
+ : QCborStreamReader(QByteArray())
+{
+}
+
+/*!
+ \overload
+
+ Creates a QCborStreamReader object with \a len bytes of data starting at \a
+ data. The pointer must remain valid until QCborStreamReader is destroyed.
+ */
+QCborStreamReader::QCborStreamReader(const char *data, qsizetype len)
+ : QCborStreamReader(QByteArray::fromRawData(data, len))
+{
+}
+
+/*!
+ \overload
+
+ Creates a QCborStreamReader object with \a len bytes of data starting at \a
+ data. The pointer must remain valid until QCborStreamReader is destroyed.
+ */
+QCborStreamReader::QCborStreamReader(const quint8 *data, qsizetype len)
+ : QCborStreamReader(QByteArray::fromRawData(reinterpret_cast<const char *>(data), len))
+{
+}
+
+/*!
+ \overload
+
+ Creates a QCborStreamReader object that will parse the CBOR stream found in
+ \a data.
+ */
+QCborStreamReader::QCborStreamReader(const QByteArray &data)
+ : d(new QCborStreamReaderPrivate(data))
+{
+ preparse();
+}
+
+/*!
+ \overload
+
+ Creates a QCborStreamReader object that will parse the CBOR stream found by
+ reading from \a device. QCborStreamReader does not take ownership of \a
+ device, so it must remain valid until this oject is destroyed.
+ */
+QCborStreamReader::QCborStreamReader(QIODevice *device)
+ : d(new QCborStreamReaderPrivate(device))
+{
+ preparse();
+}
+
+/*!
+ Destroys this QCborStreamReader object and frees any associated resources.
+ */
+QCborStreamReader::~QCborStreamReader()
+{
+}
+
+/*!
+ Sets the source of data to \a device, resetting the decoder to its initial
+ state.
+ */
+void QCborStreamReader::setDevice(QIODevice *device)
+{
+ d->setDevice(device);
+ preparse();
+}
+
+/*!
+ Returns the QIODevice that was set with either setDevice() or the
+ QCborStreamReader constructor. If this object was reading from a QByteArray,
+ this function returns nullptr instead.
+ */
+QIODevice *QCborStreamReader::device() const
+{
+ return d->device;
+}
+
+/*!
+ Adds \a data to the CBOR stream and reparses the current element. This
+ function is useful if the end of the data was previously reached while
+ processing the stream, but now more data is available.
+ */
+void QCborStreamReader::addData(const QByteArray &data)
+{
+ addData(data.constData(), data.size());
+}
+
+/*!
+ \fn void QCborStreamReader::addData(const quint8 *data, qsizetype len)
+ \overload
+
+ Adds \a len bytes of data starting at \a data to the CBOR stream and
+ reparses the current element. This function is useful if the end of the data
+ was previously reached while processing the stream, but now more data is
+ available.
+ */
+
+/*!
+ \overload
+
+ Adds \a len bytes of data starting at \a data to the CBOR stream and
+ reparses the current element. This function is useful if the end of the data
+ was previously reached while processing the stream, but now more data is
+ available.
+ */
+void QCborStreamReader::addData(const char *data, qsizetype len)
+{
+ if (!d->device) {
+ if (len > 0)
+ d->buffer.append(data, len);
+ reparse();
+ } else {
+ qWarning("QCborStreamReader: addData() with device()");
+ }
+}
+
+/*!
+ Reparses the current element. This function must be called when more data
+ becomes available in the source QIODevice after parsing failed due to
+ reaching the end of the input data before the end of the CBOR stream.
+
+ When reading from QByteArray(), the addData() function automatically calls
+ this function. Calling it when the reading had not failed is a no-op.
+ */
+void QCborStreamReader::reparse()
+{
+ d->lastError = {};
+ d->preread();
+ if (CborError err = cbor_value_reparse(&d->currentElement))
+ d->handleError(err);
+ else
+ preparse();
+}
+
+/*!
+ Clears the decoder state and resets the input source data to an empty byte
+ array. After this function is called, QCborStreamReader will be indicating
+ an error parsing.
+
+ Call addData() to add more data to be parsed.
+
+ \sa reset(), setDevice()
+ */
+void QCborStreamReader::clear()
+{
+ setDevice(nullptr);
+}
+
+/*!
+ Resets the source back to the beginning and clears the decoder state. If the
+ source data was a QByteArray, QCborStreamReader will restart from the
+ beginning of the array.
+
+ If the source data is a QIODevice, this function will call
+ QIODevice::reset(), which will seek to byte position 0. If the CBOR stream
+ is not found at the beginning of the device (e.g., beginning of a file),
+ then this function will likely do the wrong thing. Instead, position the
+ QIODevice to the right offset and call setDevice().
+
+ \sa clear(), setDevice()
+ */
+void QCborStreamReader::reset()
+{
+ if (d->device)
+ d->device->reset();
+ d->lastError = {};
+ d->initDecoder();
+ preparse();
+}
+
+/*!
+ Returns the last error in decoding the stream, if any. If no error
+ was encountered, this returns an QCborError::NoError.
+
+ \sa isValid()
+ */
+QCborError QCborStreamReader::lastError()
+{
+ return d->lastError;
+}
+
+/*!
+ Returns the offset in the input stream of the item currently being decoded.
+ The current offset is the number of decoded bytes so far only if the source
+ data is a QByteArray or it is a QIODevice that was positioned at its
+ beginning when decoding started.
+
+ \sa reset(), clear(), device()
+ */
+qint64 QCborStreamReader::currentOffset() const
+{
+ return (d->device ? d->device->pos() : 0) + d->bufferStart;
+}
+
+/*!
+ Returns the number of containers that this stream has entered with
+ enterContainer() but not yet left.
+
+ \sa enterContainer(), leaveContainer()
+ */
+int QCborStreamReader::containerDepth() const
+{
+ return d->containerStack.size();
+}
+
+/*!
+ Returns either QCborStreamReader::Array or QCborStreamReader::Map,
+ indicating whether the container that contains the current item was an array
+ or map, respectively. If we're currently parsing the root element, this
+ function returns QCborStreamReader::Invalid.
+
+ \sa containerDepth(), enterContainer()
+ */
+QCborStreamReader::Type QCborStreamReader::parentContainerType() const
+{
+ if (d->containerStack.isEmpty())
+ return Invalid;
+ return Type(cbor_value_get_type(&qAsConst(d->containerStack).top()));
+}
+
+/*!
+ Returns true if there are more items to be decoded in the current container
+ or false of we've reached its end. If we're parsing the root element,
+ hasNext() returning false indicates the parsing is complete; otherwise, if
+ the container depth is non-zero, then the outer code needs to call
+ leaveContainer().
+
+ \sa parentContainerType(), containerDepth(), leaveContainer()
+ */
+bool QCborStreamReader::hasNext() const noexcept
+{
+ return cbor_value_is_valid(&d->currentElement) &&
+ !cbor_value_at_end(&d->currentElement);
+}
+
+/*!
+ Advance the CBOR stream decoding one element. You should usually call this
+ function when parsing fixed-width basic elements (that is, integers, simple
+ values, tags and floating point values). But this function can be called
+ when the current item is a string, array or map too and it will skip over
+ that entire element, including all contained elements.
+
+ This function returns true if advancing was successful, false otherwise. It
+ may fail if the stream is corrupt, incomplete or if the nesting level of
+ arrays and maps exceeds \a maxRecursion. Calling this function when
+ hasNext() has returned false is also an error. If this function returns
+ false, lastError() will return the error code detailing what the failure
+ was.
+
+ \sa lastError(), isValid(), hasNext()
+ */
+bool QCborStreamReader::next(int maxRecursion)
+{
+ if (lastError() != QCborError::NoError)
+ return false;
+
+ if (!hasNext()) {
+ d->handleError(CborErrorAdvancePastEOF);
+ } else if (maxRecursion < 0) {
+ d->handleError(CborErrorNestingTooDeep);
+ } else if (isContainer()) {
+ // iterate over each element
+ enterContainer();
+ while (lastError() == QCborError::NoError && hasNext())
+ next(maxRecursion - 1);
+ if (lastError() == QCborError::NoError)
+ leaveContainer();
+ } else if (isString() || isByteArray()) {
+ auto r = _readByteArray_helper();
+ while (r.status == Ok) {
+ if (isString() && !QUtf8::isValidUtf8(r.data, r.data.size()).isValidUtf8) {
+ d->handleError(CborErrorInvalidUtf8TextString);
+ break;
+ }
+ r = _readByteArray_helper();
+ }
+ } else {
+ // fixed types
+ CborError err = cbor_value_advance_fixed(&d->currentElement);
+ if (err)
+ d->handleError(err);
+ }
+
+ preparse();
+ return d->lastError == QCborError::NoError;
+}
+
+/*!
+ Returns true if the length of the current array, map, byte array or string
+ is known (explicit in the CBOR stream), false otherwise. This function
+ should only be called if the element is one of those.
+
+ If the length is known, it may be obtained by calling length().
+
+ If the length of a map or an array is not known, it is implied by the number
+ of elements present in the stream. QCborStreamReader has no API to calculate
+ the length in that condition.
+
+ Strings and byte arrays may also have indeterminate length (that is, they
+ may be transmitted in multiple chunks). Those cannot currently be created
+ with QCborStreamWriter, but they could be with other encoders, so
+ QCborStreamReader supports them.
+
+ \sa length(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
+ */
+bool QCborStreamReader::isLengthKnown() const noexcept
+{
+ return cbor_value_is_length_known(&d->currentElement);
+}
+
+/*!
+ Returns the length of the string or byte array, or the number of items in an
+ array or the number, of item pairs in a map, if known. This function must
+ not be called if the length is unknown (that is, if isLengthKnown() returned
+ false). It is an error to do that and it will cause QCborStreamReader to
+ stop parsing the input stream.
+
+ \sa isLengthKnown(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
+ */
+quint64 QCborStreamReader::length() const
+{
+ CborError err;
+ switch (type()) {
+ case String:
+ case ByteArray:
+ case Map:
+ case Array:
+ if (isLengthKnown())
+ return value64;
+ err = CborErrorUnknownLength;
+ break;
+
+ default:
+ err = CborErrorIllegalType;
+ break;
+ }
+
+ d->handleError(err);
+ return quint64(-1);
+}
+
+/*!
+ \fn bool QCborStreamReader::enterContainer()
+
+ Enters the array or map that is the current item and prepares for iterating
+ the elements contained in the container. Returns true if entering the
+ container succeeded, false otherwise (usually, a parsing error). Each call
+ to enterContainer() must be paired with a call to leaveContainer().
+
+ This function may only be called if the current item is an array or a map
+ (that is, if isArray(), isMap() or isContainer() is true). Calling it in any
+ other condition is an error.
+
+ \sa leaveContainer(), isContainer(), isArray(), isMap()
+ */
+bool QCborStreamReader::_enterContainer_helper()
+{
+ d->containerStack.push(d->currentElement);
+ CborError err = cbor_value_enter_container(&d->containerStack.top(), &d->currentElement);
+ if (!err) {
+ preparse();
+ return true;
+ }
+ d->handleError(err);
+ return false;
+}
+
+/*!
+ Leaves the array or map whose items were being processed and positions the
+ decoder at the next item after the end of the container. Returns true if
+ leaving the container succeeded, false otherwise (usually, a parsing error).
+ Each call to enterContainer() must be paired with a call to
+ leaveContainer().
+
+ This function may only be called if hasNext() has returned false and
+ containerDepth() is not zero. Calling it in any other condition is an error.
+
+ \sa enterContainer(), parentContainerType(), containerDepth()
+ */
+bool QCborStreamReader::leaveContainer()
+{
+ if (d->containerStack.isEmpty()) {
+ qWarning("QCborStreamReader::leaveContainer: trying to leave top-level element");
+ return false;
+ }
+ if (d->corrupt)
+ return false;
+
+ CborValue container = d->containerStack.pop();
+ CborError err = cbor_value_leave_container(&container, &d->currentElement);
+ d->currentElement = container;
+ if (err) {
+ d->handleError(err);
+ return false;
+ }
+
+ preparse();
+ return true;
+}
+
+/*!
+ \fn bool QCborStreamReader::toBool() const
+
+ Returns the boolean value of the current element.
+
+ This function does not perform any type conversions, including from integer.
+ Therefore, it may only be called if isTrue(), isFalse() or isBool() returned
+ true; calling it in any other condition is an error.
+
+ \sa isBool(), isTrue(), isFalse(), toInteger()
+ */
+
+/*!
+ \fn QCborTag QCborStreamReader::toTag() const
+
+ Returns the tag value of the current element.
+
+ This function does not perform any type conversions, including from integer.
+ Therefore, it may only be called if isTag() is true; calling it in any other
+ condition is an error.
+
+ Tags are 64-bit numbers attached to generic CBOR types that give them
+ further meaning. For a list of known tags, see the \l QCborKnownTags
+ enumeration.
+
+ \sa isTag(), toInteger(), QCborKnownTags
+ */
+
+/*!
+ \fn quint64 QCborStreamReader::toUnsignedInteger() const
+
+ Returns the unsigned integer value of the current element.
+
+ This function does not perform any type conversions, including from boolean
+ or CBOR tag. Therefore, it may only be called if isUnsignedInteger() is
+ true; calling it in any other condition is an error.
+
+ This function may be used to obtain numbers beyond the range of the return
+ type of toInteger().
+
+ \sa type(), toInteger(), isUnsignedInteger(), isNegativeInteger()
+ */
+
+/*!
+ \fn QCborNegativeValue QCborStreamReader::toNegativeInteger() const
+
+ Returns the negative integer value of the current element.
+ QCborNegativeValue is a 64-bit unsigned integer containing the absolute
+ value of the negative number that was stored in the CBOR stream.
+ Additionally, QCborNegativeValue(0) represents the number -2\sup{64}.
+
+ This function does not perform any type conversions, including from boolean
+ or CBOR tag. Therefore, it may only be called if isNegativeInteger() is
+ true; calling it in any other condition is an error.
+
+ This function may be used to obtain numbers beyond the range of the return
+ type of toInteger(). However, use of negative numbers smaller than -2\sup{63}
+ is extremely discouraged.
+
+ \sa type(), toInteger(), isNegativeInteger(), isUnsignedInteger()
+ */
+
+/*!
+ \fn qint64 QCborStreamReader::toInteger() const
+
+ Returns the integer value of the current element, be it negative, positive
+ or zero. If the value is larger than 2\sup{63} - 1 or smaller than
+ -2\sup{63}, the returned value will overflow and will have an incorrect
+ sign. If handling those values is required, use toUnsignedInteger() or
+ toNegativeInteger() instead.
+
+ This function does not perform any type conversions, including from boolean
+ or CBOR tag. Therefore, it may only be called if isInteger() is true;
+ calling it in any other condition is an error.
+
+ \sa isInteger(), toUnsignedInteger(), toNegativeInteger()
+ */
+
+/*!
+ \fn QCborSimpleType QCborStreamReader::toSimpleType() const
+
+ Returns value of the current simple type.
+
+ This function does not perform any type conversions, including from integer.
+ Therefore, it may only be called if isSimpleType() is true; calling it in
+ any other condition is an error.
+
+ \sa isSimpleType(), isTrue(), isFalse(), isBool(), isNull(), isUndefined()
+ */
+
+/*!
+ \fn qfloat16 QCborStreamReader::toFloat16() const
+
+ Returns the 16-bit half-precision floating point value of the current element.
+
+ This function does not perform any type conversions, including from other
+ floating point types or from integer values. Therefore, it may only be
+ called if isFloat16() is true; calling it in any other condition is an
+ error.
+
+ \sa isFloat16(), toFloat(), toDouble()
+ */
+
+/*!
+ \fn float QCborStreamReader::toFloat() const
+
+ Returns the 32-bit single-precision floating point value of the current
+ element.
+
+ This function does not perform any type conversions, including from other
+ floating point types or from integer values. Therefore, it may only be
+ called if isFloat() is true; calling it in any other condition is an error.
+
+ \sa isFloat(), toFloat16(), toDouble()
+ */
+
+/*!
+ \fn double QCborStreamReader::toDouble() const
+
+ Returns the 64-bit double-precision floating point value of the current
+ element.
+
+ This function does not perform any type conversions, including from other
+ floating point types or from integer values. Therefore, it may only be
+ called if isDouble() is true; calling it in any other condition is an error.
+
+ \sa isDouble(), toFloat16(), toFloat()
+ */
+
+/*!
+ \fn QCborStreamReader::StringResult<QString> QCborStreamReader::readString()
+
+ Decodes one string chunk from the CBOR string and returns it. This function
+ is used for both regular and chunked string contents, so the caller must
+ always loop around calling this function, even if isLengthKnown() has
+ is true. The typical use of this function is as follows:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 27
+
+ This function does not perform any type conversions, including from integers
+ or from byte arrays. Therefore, it may only be called if isString() returned
+ true; calling it in any other condition is an error.
+
+ \sa readByteArray(), isString(), readStringChunk()
+ */
+QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
+{
+ auto r = _readByteArray_helper();
+ QCborStreamReader::StringResult<QString> result;
+ result.status = r.status;
+
+ if (r.status == Ok) {
+ QTextCodec::ConverterState cs;
+ result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
+ if (cs.invalidChars == 0 && cs.remainingChars == 0)
+ return result;
+
+ d->handleError(CborErrorInvalidUtf8TextString);
+ result.data.clear();
+ result.status = Error;
+ return result;
+ }
+ return result;
+}
+
+/*!
+ \fn QCborStreamReader::StringResult<QString> QCborStreamReader::readByteArray()
+
+ Decodes one byte array chunk from the CBOR string and returns it. This
+ function is used for both regular and chunked contents, so the caller must
+ always loop around calling this function, even if isLengthKnown() has
+ is true. The typical use of this function is as follows:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 28
+
+ This function does not perform any type conversions, including from integers
+ or from strings. Therefore, it may only be called if isByteArray() is true;
+ calling it in any other condition is an error.
+
+ \sa readString(), isByteArray(), readStringChunk()
+ */
+QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_helper()
+{
+ QCborStreamReader::StringResult<QByteArray> result;
+ result.status = Error;
+ qsizetype len = _currentStringChunkSize();
+ if (len < 0)
+ return result;
+
+ result.data.resize(len);
+ auto r = readStringChunk(result.data.data(), len);
+ Q_ASSERT(r.status != Ok || r.data == len);
+ result.status = r.status;
+ return result;
+}
+
+/*!
+ \fn qsizetype QCborStreamReader::currentStringChunkSize() const
+
+ Returns the size of the current text or byte string chunk. If the CBOR
+ stream contains a non-chunked string (that is, if isLengthKnown() returns
+ \c true), this function returns the size of the entire string, the same as
+ length().
+
+ This function is useful to pre-allocate the buffer whose pointer can be passed
+ to readStringChunk() later.
+
+ \sa readString(), readByteArray(), readStringChunk()
+ */
+qsizetype QCborStreamReader::_currentStringChunkSize() const
+{
+ if (!d->ensureStringIteration())
+ return -1;
+
+ size_t len;
+ CborError err = cbor_value_get_string_chunk_size(&d->currentElement, &len);
+ if (err == CborErrorNoMoreStringChunks)
+ return 0; // not a real error
+ else if (err)
+ d->handleError(err);
+ else if (qsizetype(len) < 0)
+ d->handleError(CborErrorDataTooLarge);
+ else
+ return qsizetype(len);
+ return -1;
+}
+
+/*!
+ Reads the current string chunk into the buffer pointed to by \a ptr, whose
+ size is \a maxlen. This function returns a \l StringResult object, with the
+ number of bytes copied into \a ptr saved in the \c \l StringResult::data
+ member. The \c \l StringResult::status member indicates whether there was
+ an error reading the string, whether data was copied or whether this was
+ the last chunk.
+
+ This function can be called for both \l String and \l ByteArray types.
+ For the latter, this function will read the same data that readByteArray()
+ would have returned. For strings, it returns the UTF-8 equivalent of the \l
+ QString that would have been returned.
+
+ This function is usually used alongside currentStringChunkSize() in a loop.
+ For example:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 29
+
+ Unlike readByteArray() and readString(), this function is not limited by
+ implementation limits of QByteArray and QString.
+
+ \note This function does not perform verification that the UTF-8 contents
+ are properly formatted. That means this function does not produce the
+ QCborError::InvalidUtf8String error, even when readString() does.
+
+ \sa currentStringChunkSize(), readString(), readByteArray(),
+ isString(), isByteArray()
+ */
+QCborStreamReader::StringResult<qsizetype>
+QCborStreamReader::readStringChunk(char *ptr, qsizetype maxlen)
+{
+ CborError err;
+ size_t len;
+ const void *content = nullptr;
+ QCborStreamReader::StringResult<qsizetype> result;
+ result.data = 0;
+ result.status = Error;
+
+ d->lastError = {};
+ if (!d->ensureStringIteration())
+ return result;
+
+#if 1
+ // Using internal TinyCBOR API!
+ err = _cbor_value_get_string_chunk(&d->currentElement, &content, &len, &d->currentElement);
+#else
+ // the above is effectively the same as:
+ if (cbor_value_is_byte_string(&currentElement))
+ err = cbor_value_get_byte_string_chunk(&d->currentElement, reinterpret_cast<const uint8_t **>(&content),
+ &len, &d->currentElement);
+ else
+ err = cbor_value_get_text_string_chunk(&d->currentElement, reinterpret_cast<const char **>(&content),
+ &len, &d->currentElement);
+#endif
+
+ // Range check: using implementation-defined behavior in converting an
+ // unsigned value out of range of the destination signed type (same as
+ // "len > size_t(std::numeric_limits<qsizetype>::max())", but generates
+ // better code with ICC and MSVC).
+ if (!err && qsizetype(len) < 0)
+ err = CborErrorDataTooLarge;
+
+ if (err) {
+ if (err == CborErrorNoMoreStringChunks) {
+ d->preread();
+ err = cbor_value_finish_string_iteration(&d->currentElement);
+ result.status = EndOfString;
+ }
+ if (err)
+ d->handleError(err);
+ else
+ preparse();
+ return result;
+ }
+
+ // Read the chunk into the user's buffer.
+ qint64 actuallyRead;
+ qptrdiff offset = qptrdiff(content);
+ qsizetype toRead = qsizetype(len);
+ qsizetype left = toRead - maxlen;
+ if (left < 0)
+ left = 0; // buffer bigger than string
+ else
+ toRead = maxlen; // buffer smaller than string
+
+ if (d->device) {
+ // This first skip can't fail because we've already read this many bytes.
+ d->device->skip(d->bufferStart + qptrdiff(content));
+ actuallyRead = d->device->read(ptr, toRead);
+
+ if (actuallyRead != toRead) {
+ actuallyRead = -1;
+ } else if (left) {
+ qint64 skipped = d->device->skip(left);
+ if (skipped != left)
+ actuallyRead = -1;
+ }
+
+ if (actuallyRead < 0) {
+ d->handleError(CborErrorIO);
+ return result;
+ }
+
+ d->updateBufferAfterString(offset, len);
+ } else {
+ actuallyRead = toRead;
+ memcpy(ptr, d->buffer.constData() + d->bufferStart + offset, toRead);
+ d->bufferStart += QByteArray::size_type(offset + len);
+ }
+
+ d->preread();
+ result.data = actuallyRead;
+ result.status = Ok;
+ return result;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qcborcommon.cpp"
+#include "moc_qcborstream.cpp"
diff --git a/src/corelib/serialization/qcborstream.h b/src/corelib/serialization/qcborstream.h
new file mode 100644
index 0000000000..3b13a309ab
--- /dev/null
+++ b/src/corelib/serialization/qcborstream.h
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORSTREAM_H
+#define QCBORSTREAM_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qcborcommon.h>
+#include <QtCore/qfloat16.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringview.h>
+
+// See qcborcommon.h for why we check
+#if defined(QT_X11_DEFINES_FOUND)
+# undef True
+# undef False
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+enum class QCborNegativeInteger : quint64 {};
+
+class QCborStreamWriterPrivate;
+class Q_CORE_EXPORT QCborStreamWriter
+{
+public:
+ explicit QCborStreamWriter(QIODevice *device);
+ explicit QCborStreamWriter(QByteArray *data);
+ ~QCborStreamWriter();
+ Q_DISABLE_COPY(QCborStreamWriter)
+
+ void setDevice(QIODevice *device);
+ QIODevice *device() const;
+
+ void append(quint64 u);
+ void append(qint64 i);
+ void append(QCborNegativeInteger n);
+ void append(const QByteArray &ba) { appendByteString(ba.constData(), ba.size()); }
+ void append(QLatin1String str);
+ void append(QStringView str);
+ void append(QCborTag tag);
+ void append(QCborKnownTags tag) { append(QCborTag(tag)); }
+ void append(QCborSimpleType st);
+ void append(std::nullptr_t) { append(QCborSimpleType::Null); }
+ void append(qfloat16 f);
+ void append(float f);
+ void append(double d);
+
+ void appendByteString(const char *data, qsizetype len);
+ void appendTextString(const char *utf8, qsizetype len);
+
+ // convenience
+ void append(bool b) { append(b ? QCborSimpleType::True : QCborSimpleType::False); }
+ void appendNull() { append(QCborSimpleType::Null); }
+ void appendUndefined() { append(QCborSimpleType::Undefined); }
+
+#ifndef Q_QDOC
+ // overloads to make normal code not complain
+ void append(int i) { append(qint64(i)); }
+ void append(uint u) { append(quint64(u)); }
+#endif
+#ifndef QT_NO_CAST_FROM_ASCII
+ void append(const char *str, qsizetype size = -1)
+ { appendTextString(str, (str && size == -1) ? int(strlen(str)) : size); }
+#endif
+
+ void startArray();
+ void startArray(quint64 count);
+ bool endArray();
+ void startMap();
+ void startMap(quint64 count);
+ bool endMap();
+
+ // no API for encoding chunked strings
+
+private:
+ QScopedPointer<QCborStreamWriterPrivate> d;
+};
+
+class QCborStreamReaderPrivate;
+class Q_CORE_EXPORT QCborStreamReader
+{
+ Q_GADGET
+public:
+ enum Type : quint8 {
+ UnsignedInteger = 0x00,
+ NegativeInteger = 0x20,
+ ByteString = 0x40,
+ ByteArray = ByteString,
+ TextString = 0x60,
+ String = TextString,
+ Array = 0x80,
+ Map = 0xa0,
+ Tag = 0xc0,
+ SimpleType = 0xe0,
+ HalfFloat = 0xf9,
+ Float16 = HalfFloat,
+ Float = 0xfa,
+ Double = 0xfb,
+
+ Invalid = 0xff
+ };
+ Q_ENUM(Type)
+
+ enum StringResultCode {
+ EndOfString = 0,
+ Ok = 1,
+ Error = -1
+ };
+ template <typename Container> struct StringResult {
+ Container data;
+ StringResultCode status = Error;
+ };
+ Q_ENUM(StringResultCode)
+
+ QCborStreamReader();
+ QCborStreamReader(const char *data, qsizetype len);
+ QCborStreamReader(const quint8 *data, qsizetype len);
+ explicit QCborStreamReader(const QByteArray &data);
+ explicit QCborStreamReader(QIODevice *device);
+ ~QCborStreamReader();
+ Q_DISABLE_COPY(QCborStreamReader)
+
+ void setDevice(QIODevice *device);
+ QIODevice *device() const;
+ void addData(const QByteArray &data);
+ void addData(const char *data, qsizetype len);
+ void addData(const quint8 *data, qsizetype len)
+ { addData(reinterpret_cast<const char *>(data), len); }
+ void reparse();
+ void clear();
+ void reset();
+
+ QCborError lastError();
+
+ qint64 currentOffset() const;
+
+ bool isValid() const { return !isInvalid(); }
+
+ int containerDepth() const;
+ QCborStreamReader::Type parentContainerType() const;
+ bool hasNext() const noexcept Q_DECL_PURE_FUNCTION;
+ bool next(int maxRecursion = 10000);
+
+ Type type() const { return QCborStreamReader::Type(type_); }
+ bool isUnsignedInteger() const { return type() == UnsignedInteger; }
+ bool isNegativeInteger() const { return type() == NegativeInteger; }
+ bool isInteger() const { return quint8(type()) <= quint8(NegativeInteger); }
+ bool isByteArray() const { return type() == ByteArray; }
+ bool isString() const { return type() == String; }
+ bool isArray() const { return type() == Array; }
+ bool isMap() const { return type() == Map; }
+ bool isTag() const { return type() == Tag; }
+ bool isSimpleType() const { return type() == SimpleType; }
+ bool isFloat16() const { return type() == Float16; }
+ bool isFloat() const { return type() == Float; }
+ bool isDouble() const { return type() == Double; }
+ bool isInvalid() const { return type() == Invalid; }
+
+ bool isSimpleType(QCborSimpleType st) const { return isSimpleType() && toSimpleType() == st; }
+ bool isFalse() const { return isSimpleType(QCborSimpleType::False); }
+ bool isTrue() const { return isSimpleType(QCborSimpleType::True); }
+ bool isBool() const { return isFalse() || isTrue(); }
+ bool isNull() const { return isSimpleType(QCborSimpleType::Null); }
+ bool isUndefined() const { return isSimpleType(QCborSimpleType::Undefined); }
+
+ bool isLengthKnown() const noexcept Q_DECL_PURE_FUNCTION;
+ quint64 length() const;
+
+ bool isContainer() const { return isMap() || isArray(); }
+ bool enterContainer() { Q_ASSERT(isContainer()); return _enterContainer_helper(); }
+ bool leaveContainer();
+
+ StringResult<QString> readString() { Q_ASSERT(isString()); return _readString_helper(); }
+ StringResult<QByteArray> readByteArray(){ Q_ASSERT(isByteArray()); return _readByteArray_helper(); }
+ qsizetype currentStringChunkSize() const{ Q_ASSERT(isString() || isByteArray()); return _currentStringChunkSize(); }
+ StringResult<qsizetype> readStringChunk(char *ptr, qsizetype maxlen);
+
+ bool toBool() const { Q_ASSERT(isBool()); return value64 - int(QCborSimpleType::False); }
+ QCborTag toTag() const { Q_ASSERT(isTag()); return QCborTag(value64); }
+ quint64 toUnsignedInteger() const { Q_ASSERT(isUnsignedInteger()); return value64; }
+ QCborNegativeInteger toNegativeInteger() const { Q_ASSERT(isNegativeInteger()); return QCborNegativeInteger(value64 + 1); }
+ QCborSimpleType toSimpleType() const{ Q_ASSERT(isSimpleType()); return QCborSimpleType(value64); }
+ qfloat16 toFloat16() const { Q_ASSERT(isFloat16()); return _toFloatingPoint<qfloat16>(); }
+ float toFloat() const { Q_ASSERT(isFloat()); return _toFloatingPoint<float>(); }
+ double toDouble() const { Q_ASSERT(isDouble()); return _toFloatingPoint<double>(); }
+
+ qint64 toInteger() const
+ {
+ Q_ASSERT(isInteger());
+ qint64 v = qint64(value64);
+ if (isNegativeInteger())
+ return -v - 1;
+ return v;
+ }
+
+private:
+ void preparse();
+ bool _enterContainer_helper();
+ StringResult<QString> _readString_helper();
+ StringResult<QByteArray> _readByteArray_helper();
+ qsizetype _currentStringChunkSize() const;
+
+ template <typename FP> FP _toFloatingPoint() const noexcept
+ {
+ using UInt = typename QIntegerForSizeof<FP>::Unsigned;
+ UInt u = UInt(value64);
+ FP f;
+ memcpy(static_cast<void *>(&f), &u, sizeof(f));
+ return f;
+ }
+
+ friend QCborStreamReaderPrivate;
+ friend class QCborContainerPrivate;
+ quint64 value64;
+ QScopedPointer<QCborStreamReaderPrivate> d;
+ quint8 type_;
+ quint8 reserved[3] = {};
+};
+
+QT_END_NAMESPACE
+
+#if defined(QT_X11_DEFINES_FOUND)
+# define True 1
+# define False 0
+#endif
+
+#endif // QCBORSTREAM_H
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
new file mode 100644
index 0000000000..5d97a6a06a
--- /dev/null
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -0,0 +1,2477 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborvalue.h"
+#include "qcborvalue_p.h"
+
+#include "qcborarray.h"
+#include "qcbormap.h"
+#include "qcborstream.h"
+
+#include <qendian.h>
+#include <qlocale.h>
+#include <private/qnumeric_p.h>
+#include <private/qsimd_p.h>
+
+#include <new>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QCborValue
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborValue class encapsulates a value in CBOR.
+
+ This class can be used to hold one of the many types available in CBOR.
+ CBOR is the Concise Binary Object Representation, a very compact form of
+ binary data encoding that is a superset of JSON. It was created by the IETF
+ Constrained RESTful Environments (CoRE) WG, which has used it in many
+ new RFCs. It is meant to be used alongside the
+ \l{https://tools.ietf.org/html/rfc7252}{CoAP protocol}.
+
+ CBOR has three groups of built-in types:
+
+ \list
+ \li Basic types: integers, floating point (double), boolean, null, etc.
+ \li String-like types: strings and byte arrays
+ \li Containers: arrays and maps
+ \endlist
+
+ Additionally, CBOR supports a form of type extensibility by associating a
+ "tag" to one of the above types to convey more information. For example, a
+ UUID is represented by a tag and a byte array containing the 16 bytes of
+ the UUID content. QCborValue supports creating and decoding several of those
+ extended types directly with Qt classes (like QUuid).
+
+ For the complete list, see \l QCborValue::Type. The type of a QCborValue can
+ be queried using type() or one of the "isXxxx" functions.
+
+ \section1 Extended types and tagged values
+
+ A tagged value is a normal QCborValue that is paired with a number that
+ is its tag. See \l QCborKnownTags for more information on what tags are in
+ the API as well as the full, official list. Such combinations form extended
+ types.
+
+ QCborValue has support for certain extended types in the API, like URL
+ (with \l QUrl) and UUID (with \l QUuid). Other extended types not supported
+ in the API are represented by a QCborValue of \l {Type}{Tag} type. The tag
+ can later be retrieved by tag() and the tagged value using taggedValue().
+
+ In order to support future compatibility, QCborValues containing extended
+ Qt types compare equal to the tag type of the same contents. In other
+ words, the following expression is true:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 0
+
+ \section1 Undefined and null values
+
+ QCborValue can contain a value of "null", which is not of any specific type.
+ It resembles the C++ \c {std::nullptr_t} type, whose only possible value is
+ \c nullptr. QCborValue has a constructor taking such a type and creates a
+ null QCborValue.
+
+ Null values are used to indicate that an optional value is not present. In
+ that aspect, it is similar to the C++ Standard Library type \c
+ {std::optional} when that is disengaged. Unlike the C++ type, CBOR nulls
+ are simply of type "Null" and it is not possible to determine what concrete
+ type it is replacing.
+
+ QCborValue can also be of the undefined type, which represents a value of
+ "undefined". In fact, that is what the QCborValue default constructor
+ creates.
+
+ Undefined values are different from null values. While nulls are used to
+ indicate an optional value that is not provided, Undefined is usually
+ used to indicate that an expected value could not be provided, usually due
+ to an error or a precondition that could not be satisfied.
+
+ Such values are completely valid and may appear in CBOR streams, unlike
+ JSON content and QJsonValue's undefined bit. But like QJsonValue's
+ Undefined, it is returned by QCborArray::value() when out of range or
+ QCborMap::operator[] when the key is not found in the container. It is not
+ possible to tell such a case apart from the value of Undefined, so if that
+ is required, check the QCborArray size and use the QCborMap iterator API.
+
+ \section1 Simple types
+
+ CBOR supports additional simple types that, like Null and Undefined, carry
+ no other value. They are called interchangeably "Simple Types" and "Simple
+ Values". CBOR encodes booleans as two distinct types (one for \c true and
+ one for \c false), but QCborValue has a convenience API for them.
+
+ There are currently no other defined CBOR simple types. QCborValue supports
+ them simply by their number with API like isSimpleType() and
+ toSimpleType(), available for compatibility with future specifications
+ before the Qt API can be updated. Their use before such a specification is
+ discouraged, as other CBOR implementations may not support them fully.
+
+ \section1 CBOR support
+
+ QCborValue supports all CBOR features required to create canonical and
+ strict streams. It implements almost all of the features specified in \l
+ {https://tools.ietf.org/html/rfc7049}{RFC 7049}.
+
+ The following table lists the CBOR features that QCborValue supports.
+
+ \table
+ \header \li Feature \li Support
+ \row \li Unsigned numbers \li Yes (\l qint64 range)
+ \row \li Negative numbers \li Yes (\l qint64 range)
+ \row \li Byte strings \li Yes
+ \row \li Text strings \li Yes
+ \row \li Chunked strings \li See below
+ \row \li Tags \li Yes (arbitrary)
+ \row \li Booleans \li Yes
+ \row \li Null \li Yes
+ \row \li Undefined \li Yes
+ \row \li Arbitrary simple values \li Yes
+ \row \li Half-precision float (16-bit) \li Yes
+ \row \li Single-precision float (32-bit) \li Yes
+ \row \li Double-precision float (64-bit) \li Yes
+ \row \li Infinities and NaN floating point \li Yes
+ \row \li Determinate-length arrays and maps \li Yes
+ \row \li Indeterminate-length arrays and maps \li Yes
+ \row \li Map key types other than strings and integers \li Yes (arbitrary)
+ \endtable
+
+ Integers in QCborValue are limited to the range of the \l qint64 type. That
+ is, from -9,223,372,036,854,775,808 (-2\sup{63}) to
+ 9,223,372,036,854,775,807 (2\sup{63} - 1). CBOR itself can represent integer
+ values outside of this range, which QCborValue does not support. When
+ decoding a stream using fromCbor() containing one of those values,
+ QCborValue will convert automatically to \l {Type}{Double}, but that may
+ lose up to 11 bits of precision.
+
+ fromCbor() is able to decode chunked strings, but will always merge the
+ chunks together into a single QCborValue. For that reason, it always writes
+ non-chunked strings when using toCbor() (which is required by the Canonical
+ format anyway).
+
+ QCborValue will always convert half- and single-precision floating point
+ values in the CBOR stream to double-precision. The toCbor() function can
+ take a parameter indicating to recreate them.
+
+ \section1 QCborValueRef
+
+ QCborValueRef is a helper class for QCborArray and QCborMap. It is the type
+ you get when using one of the mutating APIs in those classes. Unlike
+ QCborValue, new values can be assigned to that class. When that is done, the
+ array or map it refers to will be modified with the new value. In all other
+ aspects, its API is identical to QCborValue.
+
+ \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter
+ QJsonValue, QJsonDocument
+ */
+
+/*!
+ \class QCborParserError
+ \inmodule QtCore
+ \ingroup cbor
+ \reentrant
+ \since 5.12
+
+ \brief The QCborParserError is used by QCborValue to report a parsing error.
+
+ This class is used by \l {QCborValue::fromCbor(const QByteArray &ba,
+ QCborParserError *error)} to report a parser error and the byte offset
+ where the error was detected.
+
+ \sa QCborValue, QCborError
+ */
+
+/*!
+ \variable qint64 QCborParserError::offset
+
+ This field contains the offset from the beginning of the data where the
+ error was detected. The offset should point to the beginning of the item
+ that contained the error, even if the error itself was elsewhere (for
+ example, for UTF-8 decoding issues).
+
+ \sa QCborValue::fromCbor()
+ */
+
+/*!
+ \variable QCborError QCborParserError::error
+
+ This field contains the error code that indicates what decoding problem was
+ found.
+
+ \sa QCborValue::fromCbor()
+ */
+
+/*!
+ \fn QString QCborParserError::errorString() const
+
+ Returns a string representation of the error code. This string is not
+ translated.
+
+ \sa QCborError::toString(), QCborValue::fromCbor()
+ */
+
+/*!
+ \enum QCborValue::EncodingOption
+
+ This enum is used in the options argument to toCbor(), modifying the
+ behavior of the encoder.
+
+ \omitvalue SortKeysInMaps
+ \value NoTransformation (Default) Performs no transformations.
+ \value UseFloat Tells the encoder to use IEEE 754 single-precision floating point
+ (that is, \c float) whenever possible.
+ \value UseFloat16 Tells the encoder to use IEEE 754 half-precision floating point
+ (that is, \c qfloat16), whenever possible. Implies \c UseFloat.
+ \value UseIntegers Tells the encoder to use integers whenever a value of type \l
+ {Type}{Double} contains an integer.
+
+ The use of \c UseFloat16 is required to encode the stream in Canonical
+ Format, but is not otherwise necessary.
+
+ \sa toCbor()
+ */
+
+/*!
+ \enum QCborValue::DiagnosticNotationOption
+
+ This enum is used in the option argument to toDiagnosticNotation(), to
+ modify the output format.
+
+ \value Compact Does not use any line-breaks, producing a compact representation.
+ \value LineWrapped Uses line-breaks, one QCborValue per line.
+ \value ExtendedFormat Uses some different options to represent values, not found in
+ RFC 7049. Those options are subject to change.
+
+ Currently, \c ExtendedFormat will change how byte arrays are represented.
+ Without it, they are always hex-encoded and without spaces. With it,
+ QCborValue::toCbor() will either use hex with spaces, base64 or base64url
+ encoding, depending on the context.
+
+ \sa toDiagnosticNotation()
+ */
+
+/*!
+ \enum QCborValue::Type
+
+ This enum represents the QCborValue type. It is returned by the type()
+ function.
+
+ The CBOR built-in types are:
+
+ \value Integer \c qint64: An integer value
+ \value ByteArray \l QByteArray: a byte array ("byte string")
+ \value String \l QString: a Unicode string ("text string")
+ \value Array \l QCborArray: an array of QCborValues
+ \value Map \l QCborMap: an associative container of QCborValues
+ \value SimpleType \l QCborSimpleType: one of several simple types/values
+ \value False \c bool: the simple type for value \c false
+ \value True \c bool: the simple type for value \c true
+ \value Null \c std::nullptr_t: the simple type for the null value
+ \value Undefined (no type) the simple type for the undefined value
+ \value Double \c double: a double-precision floating point
+ \value Invalid Not a valid value, this usually indicates a CBOR decoding error
+
+ Additionally, QCborValue can represent extended types:
+
+ \value Tag An unknown or unrecognized extended type, represented by its
+ tag (a \l QCborTag) and the tagged value (a QCborValue)
+ \value DateTime \l QDateTime: a date and time stamp
+ \value Url \l QUrl: a URL or URI
+ \value RegularExpression \l QRegularExpression: the pattern of a regular expression
+ \value Uuid \l QUuid: a UUID
+
+ \sa type()
+ */
+
+/*!
+ \fn QCborValue::QCborValue()
+
+ Creates a QCborValue of the \l {Type}{Undefined} type.
+
+ CBOR undefined values are used to indicate missing information, usually as
+ a result of a previous operation that did not complete as expected. They
+ are also used by the QCborArray and QCborMap API to indicate the searched
+ item was not found.
+
+ Undefined values are represented by the \l {QCborSimpleType}{Undefined
+ simple type}. Because of that, QCborValues with undefined values will also
+ return true for isSimpleType() and
+ \c{isSimpleType(QCborSimpleType::Undefined)}.
+
+ Undefined values are different from null values.
+
+ QCborValue objects with undefined values are also different from invalid
+ QCborValue objects. The API will not create invalid QCborValues, but they
+ may exist as a result of a parsing error.
+
+ \sa isUndefined(), isNull(), isSimpleType()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(Type t_)
+
+ Creates a QCborValue of type \a t_. The value associated with such a type
+ (if any) will be default constructed.
+
+ \sa type()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(std::nullptr_t)
+
+ Creates a QCborValue of the \l {Type}{Null} type.
+
+ CBOR null values are used to indicate optional values that were not
+ provided. They are distinct from undefined values, in that null values are
+ usually not the result of an earlier error or problem.
+
+ \sa isNull(), isUndefined(), isSimpleType()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(bool b)
+
+ Creates a QCborValue with boolean value \a b. The value can later be
+ retrieved using toBool().
+
+ Internally, CBOR booleans are represented by a pair of types, one for true
+ and one for false. For that reason, boolean QCborValues will return true
+ for isSimpleType() and one of \c{isSimpleType(QCborSimpleType::False)} or
+ \c{isSimpleType(QCborSimpleType::True)}.
+
+ \sa toBool(), isBool(), isTrue(), isFalse(), isSimpleType()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(qint64 i)
+
+ Creates a QCborValue with integer value \a i. The value can later be
+ retrieved using toInteger().
+
+ CBOR integer values are distinct from floating point values. Therefore,
+ QCborValue objects with integers will compare differently to QCborValue
+ objects containing floating-point, even if the values contained in the
+ objects are equivalent.
+
+ \sa toInteger(), isInteger(), isDouble()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(double d)
+
+ Creates a QCborValue with floating point value \a d. The value can later be
+ retrieved using toDouble().
+
+ CBOR floating point values are distinct from integer values. Therefore,
+ QCborValue objects with integers will compare differently to QCborValue
+ objects containing floating-point, even if the values contained in the
+ objects are equivalent.
+
+ \sa toDouble(), isDouble(), isInteger()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(QCborSimpleType st)
+
+ Creates a QCborValue of simple type \a st. The type can later later be retrieved
+ using toSimpleType() as well as isSimpleType(st).
+
+ CBOR simple types are types that do not have any associated value, like
+ C++'s \c{std::nullptr_t} type, whose only possible value is \c nullptr.
+
+ If \a st is \c{QCborSimpleType::Null}, the resulting QCborValue will be of
+ the \l{Type}{Null} type and similarly for \c{QCborSimpleType::Undefined}.
+ If \a st is \c{QCborSimpleType::False} or \c{QCborSimpleType::True}, the
+ created QCborValue will be a boolean containing a value of false or true,
+ respectively.
+
+ This function can be used with simple types not defined in the API. For
+ example, to create a QCborValue with simple type 12, one could write:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 1
+
+ Simple types should not be used until a specification for them has been
+ published, since other implementations may not support them properly.
+ Simple type values 24 to 31 are reserved and must not be used.
+
+ isSimpleType(), isNull(), isUndefined(), isTrue(), isFalse()
+ */
+
+/*!
+ \fn QCborValue::QCborValue(QCborKnownTags tag, const QCborValue &taggedValue)
+ \overload
+
+ Creates a QCborValue for the extended type represented by the tag value \a
+ tag, tagging value \a taggedValue. The tag can later be retrieved using
+ tag() and the tagged value using taggedValue().
+
+ \sa isTag(), tag(), taggedValue(), QCborKnownTags
+ */
+
+/*!
+ \fn QCborValue::~QCborValue()
+
+ Disposes of the current QCborValue object and frees any associated resources.
+ */
+
+/*!
+ \fn QCborValue::QCborValue(QCborValue &&other)
+ \overload
+
+ Moves the contents of the \a other CBorValue object into this one and frees
+ the resources of this one.
+ */
+
+/*!
+ \fn QCborValue &&QCborValue::operator=(QCborValue &&other)
+ \overload
+
+ Moves the contents of the \a other CBorValue object into this one and frees
+ the resources of this one. Returns a reference to this object.
+ */
+
+/*!
+ \fn void QCborValue::swap(QCborValue &other)
+
+ Swaps the contents of this QCborValue object and \a other.
+ */
+
+/*!
+ \fn QCborValue::Type QCborValue::type() const
+
+ Returns the type of this QCborValue. The type can also later be retrieved by one
+ of the "isXxx" functions.
+
+ \sa isInteger(), isByteArray(), isString(), isArray(), isMap(),
+ isTag(), isFalse(), isTrue(), isBool(), isNull(), isUndefined, isDouble(),
+ isDateTime(), isUrl(), isRegularExpression(), isUuid()
+ */
+
+/*!
+ \fn bool QCborValue::isInteger() const
+
+ Returns true if this QCborValue is of the integer type. The integer value
+ can be retrieved using toInteger().
+
+ \sa type(), toInteger()
+ */
+
+/*!
+ \fn bool QCborValue::isByteArray() const
+
+ Returns true if this QCborValue is of the byte array type. The byte array
+ value can be retrieved using toByteArray().
+
+ \sa type(), toByteArray()
+ */
+
+/*!
+ \fn bool QCborValue::isString() const
+
+ Returns true if this QCborValue is of the string type. The string value
+ can be retrieved using toString().
+
+ \sa type(), toString()
+ */
+
+/*!
+ \fn bool QCborValue::isArray() const
+
+ Returns true if this QCborValue is of the array type. The array value can
+ be retrieved using toArray().
+
+ \sa type(), toArray()
+ */
+
+/*!
+ \fn bool QCborValue::isMap() const
+
+ Returns true if this QCborValue is of the map type. The map value can be
+ retrieved using toMap().
+
+ \sa type(), toMap()
+ */
+
+/*!
+ \fn bool QCborValue::isTag() const
+
+ Returns true if this QCborValue is of the tag type. The tag value can be
+ retrieved using tag() and the tagged value using taggedValue().
+
+ This function also returns true for extended types that the API
+ recognizes. For code that handles extended types directly before the Qt API
+ is updated to support them, it is possible to recreate the tag + tagged
+ value pair by using taggedValue().
+
+ \sa type(), tag(), taggedValue(), taggedValue()
+ */
+
+/*!
+ \fn bool QCborValue::isFalse() const
+
+ Returns true if this QCborValue is a boolean with false value. This
+ function exists because, internally, CBOR booleans are stored as two
+ separate types, one for true and one for false.
+
+ \sa type(), isBool(), isTrue(), toBool()
+ */
+
+/*!
+ \fn bool QCborValue::isTrue() const
+
+ Returns true if this QCborValue is a boolean with true value. This
+ function exists because, internally, CBOR booleans are stored as two
+ separate types, one for false and one for true.
+
+ \sa type(), isBool(), isFalse(), toBool()
+ */
+
+/*!
+ \fn bool QCborValue::isBool() const
+
+ Returns true if this QCborValue is a boolean. The value can be retrieved
+ using toBool().
+
+ \sa type(), toBool(), isTrue(), isFalse()
+ */
+
+/*!
+ \fn bool QCborValue::isUndefined() const
+
+ Returns true if this QCborValue is of the undefined type.
+
+ CBOR undefined values are used to indicate missing information, usually as
+ a result of a previous operation that did not complete as expected. They
+ are also used by the QCborArray and QCborMap API to indicate the searched
+ item was not found.
+
+ Undefined values are distinct from null values.
+
+ QCborValue objects with undefined values are also different from invalid
+ QCborValue objects. The API will not create invalid QCborValues, but they
+ may exist as a result of a parsing error.
+
+ \sa type(), isNull(), isInvalid()
+ */
+
+/*!
+ \fn bool QCborValue::isNull() const
+
+ Returns true if this QCborValue is of the null type.
+
+ CBOR null values are used to indicate optional values that were not
+ provided. They are distinct from undefined values, in that null values are
+ usually not the result of an earlier error or problem.
+
+ Null values are distinct from undefined values and from invalid QCborValue
+ objects. The API will not create invalid QCborValues, but they may exist as
+ a result of a parsing error.
+
+ \sa type(), isUndefined(), isInvalid()
+ */
+
+/*!
+ \fn bool QCborValue::isDouble() const
+
+ Returns true if this QCborValue is of the floating-point type. The value
+ can be retrieved using toDouble().
+
+ \sa type(), toDouble()
+ */
+
+/*!
+ \fn bool QCborValue::isDateTime() const
+
+ Returns true if this QCborValue is of the date/time type. The value can be
+ retrieved using toDateTime(). Date/times are extended types that use the
+ tag \l{QCborKnownTags}{DateTime}.
+
+ Additionally, when decoding from a CBOR stream, QCborValue will interpret
+ tags of value \l{QCborKnownTags}{UnixTime_t} and convert them to the
+ equivalent date/time.
+
+ \sa type(), toDateTime()
+ */
+
+/*!
+ \fn bool QCborValue::isUrl() const
+
+ Returns true if this QCborValue is of the URL type. The URL value
+ can be retrieved using toUrl().
+
+ \sa type(), toUrl()
+ */
+
+/*!
+ \fn bool QCborValue::isRegularExpression() const
+
+ Returns true if this QCborValue contains a regular expression's pattern.
+ The pattern can be retrieved using toRegularExpression().
+
+ \sa type(), toRegularExpression()
+ */
+
+/*!
+ \fn bool QCborValue::isUuid() const
+
+ Returns true if this QCborValue contains a UUID. The value can be retrieved
+ using toUuid().
+
+ \sa type(), toUuid()
+ */
+
+/*!
+ \fn bool QCborValue::isInvalid() const
+
+ Returns true if this QCborValue is not of any valid type. Invalid
+ QCborValues are distinct from those with undefined values and they usually
+ represent a decoding error.
+
+ \sa isUndefined(), isNull()
+ */
+
+/*!
+ \fn bool QCborValue::isContainer() const
+
+ This convenience function returns true if the QCborValue is either an array
+ or a map.
+
+ \sa isArray(), isMap()
+ */
+
+/*!
+ \fn bool QCborValue::isSimpleType() const
+
+ Returns true if this QCborValue is of one of the CBOR simple types. The
+ type itself can later be retrieved using type(), even for types that don't have an
+ enumeration in the API. They can also be checked with the
+ \l{isSimpleType(QCborSimpleType)} overload.
+
+ \sa QCborSimpleType, isSimpleType(QCborSimpleType), toSimpleType()
+ */
+
+/*!
+ \fn bool QCborValue::isSimpleType(QCborSimpleType st) const
+ \overload
+
+ Returns true if this QCborValue is of a simple type and toSimpleType()
+ would return \a st, false otherwise. This function can be used to check for
+ any CBOR simple type, even those for which there is no enumeration in the
+ API. For example, for the simple type of value 12, you could write:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 2
+
+ \sa QCborValue::QCborValue(QCborSimpleType), isSimpleType(), isFalse(),
+ isTrue(), isNull, isUndefined(), toSimpleType()
+ */
+
+/*!
+ \fn QCborSimpleType QCborValue::toSimpleType(QCborSimpleType defaultValue) const
+
+ Returns the simple type this QCborValue is of, if it is a simple type. If
+ it is not a simple type, it returns \a defaultValue.
+
+ The following types are simple types and this function will return the
+ listed values:
+
+ \table
+ \row \li QCborValue::False \li QCborSimpleType::False
+ \row \li QCborValue::True \li QCborSimpleType::True
+ \row \li QCborValue::Null \li QCborSimpleType::Null
+ \row \li QCborValue::Undefined \li QCborSimpleType::Undefined
+ \endtable
+
+ \sa type(), isSimpleType(), isBool(), isTrue(), isFalse(), isTrue(),
+ isNull(), isUndefined()
+ */
+
+/*!
+ \fn qint64 QCborValue::toInteger(qint64 defaultValue) const
+
+ Returns the integer value stored in this QCborValue, if it is of the
+ integer type. If it is of the Double type, this function returns the
+ floating point value converted to integer. In any other case, it returns \a
+ defaultValue.
+
+ \sa isInteger(), isDouble(), toDouble()
+ */
+
+/*!
+ \fn bool QCborValue::toBool(bool defaultValue) const
+
+ Returns the boolean value stored in this QCborValue, if it is of a boolean
+ type. Otherwise, it returns \a defaultValue.
+
+ \sa isBool(), isTrue(), isFalse()
+ */
+
+/*!
+ \fn double QCborValue::toDouble(double defaultValue) const
+
+ Returns the floating point value stored in this QCborValue, if it is of the
+ Double type. If it is of the Integer type, this function returns the
+ integer value converted to double. In any other case, it returns \a
+ defaultValue.
+
+ \sa isDouble(), isInteger(), toInteger()
+ */
+
+using namespace QtCbor;
+
+// in qcborstream.cpp
+extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
+
+static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
+{
+ if (qt_is_nan(d)) {
+ if (opt & QCborValue::UseFloat16) {
+ if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16)
+ return writer.append(qfloat16(qt_qnan()));
+ return writer.append(float(qt_qnan()));
+ }
+ return writer.append(qt_qnan());
+ }
+
+ if (qt_is_inf(d)) {
+ d = d > 0 ? qt_inf() : -qt_inf();
+ } else if (opt & QCborValue::UseIntegers) {
+ quint64 i;
+ if (convertDoubleTo(d, &i)) {
+ if (d < 0)
+ return writer.append(QCborNegativeInteger(i));
+ return writer.append(i);
+ }
+ }
+
+ if (opt & QCborValue::UseFloat16) {
+ float f = float(d);
+ if (f == d) {
+ // no data loss, we could use float
+ if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16) {
+ qfloat16 f16 = f;
+ if (f16 == f)
+ return writer.append(f16);
+ }
+
+ return writer.append(f);
+ }
+ }
+
+ writer.append(d);
+}
+
+static inline int typeOrder(Element e1, Element e2)
+{
+ auto comparable = [](Element e) {
+ if (e.type >= 0x10000) // see QCborValue::isTag_helper()
+ return QCborValue::Tag;
+ return e.type;
+ };
+ return comparable(e1) - comparable(e2);
+}
+
+QCborContainerPrivate::~QCborContainerPrivate()
+{
+ // delete our elements
+ for (Element &e : elements) {
+ if (e.flags & Element::IsContainer)
+ e.container->deref();
+ }
+}
+
+void QCborContainerPrivate::compact(qsizetype reserved)
+{
+ if (usedData > data.size() / 2)
+ return;
+
+ // 50% savings if we recreate the byte data
+ // ### TBD
+ Q_UNUSED(reserved);
+}
+
+QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qsizetype reserved)
+{
+ if (!d) {
+ d = new QCborContainerPrivate;
+ } else {
+ d = new QCborContainerPrivate(*d);
+ if (reserved >= 0) {
+ d->elements.reserve(reserved);
+ d->compact(reserved);
+ }
+ for (auto &e : qAsConst(d->elements)) {
+ if (e.flags & Element::IsContainer)
+ e.container->ref.ref();
+ }
+ }
+ return d;
+}
+
+QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, qsizetype reserved)
+{
+ if (!d || d->ref.load() != 1)
+ return clone(d, reserved);
+ return d;
+}
+
+/*!
+ Prepare for an insertion at position \a index
+
+ Detaches and ensures there are at least index entries in the array, padding
+ with Undefined as needed.
+*/
+QCborContainerPrivate *QCborContainerPrivate::grow(QCborContainerPrivate *d, qsizetype index)
+{
+ Q_ASSERT(index >= 0);
+ d = detach(d, index + 1);
+ Q_ASSERT(d);
+ int j = d->elements.size();
+ while (j < index)
+ d->append(Undefined());
+ return d;
+}
+
+// Copies or moves \a value into element at position \a e. If \a disp is
+// CopyContainer, then this function increases the reference count of the
+// container, but otherwise leaves it unmodified. If \a disp is MoveContainer,
+// then it transfers ownership (move semantics) and the caller must set
+// value.container back to nullptr.
+void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &value, ContainerDisposition disp)
+{
+ if (value.n < 0) {
+ // This QCborValue is an array, map, or tagged value (container points
+ // to itself).
+
+ // detect self-assignment
+ if (Q_UNLIKELY(this == value.container)) {
+ Q_ASSERT(ref.load() >= 2);
+ if (disp == MoveContainer)
+ ref.deref(); // not deref() because it can't drop to 0
+ QCborContainerPrivate *d = QCborContainerPrivate::clone(this);
+ d->elements.detach();
+ d->ref.store(1);
+ e.container = d;
+ } else {
+ e.container = value.container;
+ if (disp == CopyContainer)
+ e.container->ref.ref();
+ }
+
+ e.type = value.type();
+ e.flags = Element::IsContainer;
+ } else {
+ // String data, copy contents
+ e = value.container->elements.at(value.n);
+
+ // Copy string data, if any
+ if (const ByteData *b = value.container->byteData(value.n))
+ e.value = addByteData(b->byte(), b->len);
+
+ if (disp == MoveContainer)
+ value.container->deref();
+ }
+}
+
+// in qstring.cpp
+void qt_to_latin1_unchecked(uchar *dst, const ushort *uc, qsizetype len);
+
+Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(const QString &s)
+{
+ qsizetype len = s.size();
+ QtCbor::Element e;
+ e.value = addByteData(nullptr, len);
+ e.type = QCborValue::String;
+ e.flags = Element::HasByteData | Element::StringIsAscii;
+ elements.append(e);
+
+ char *ptr = data.data() + e.value + sizeof(ByteData);
+ uchar *l = reinterpret_cast<uchar *>(ptr);
+ const ushort *uc = (const ushort *)s.unicode();
+ qt_to_latin1_unchecked(l, uc, len);
+}
+
+QCborValue QCborContainerPrivate::extractAt_complex(Element e)
+{
+ // create a new container for the returned value, containing the byte data
+ // from this element, if it's worth it
+ Q_ASSERT(e.flags & Element::HasByteData);
+ auto b = byteData(e);
+ auto container = new QCborContainerPrivate;
+
+ if (b->len + qsizetype(sizeof(*b)) < data.size() / 4) {
+ // make a shallow copy of the byte data
+ container->appendByteData(b->byte(), b->len, e.type, e.flags);
+ usedData -= b->len + qsizetype(sizeof(*b));
+ compact(elements.size());
+ } else {
+ // just share with the original byte data
+ container->data = data;
+ container->elements.reserve(1);
+ container->elements.append(e);
+ }
+
+ return makeValue(e.type, 0, container);
+}
+
+QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2);
+static int compareElementNoData(const Element &e1, const Element &e2)
+{
+ Q_ASSERT(e1.type == e2.type);
+
+ if (e1.type == QCborValue::Integer) {
+ // CBOR sorting order is 0, 1, 2, ..., INT64_MAX, -1, -2, -3, ... INT64_MIN
+ // So we transform:
+ // 0 -> 0
+ // 1 -> 1
+ // INT64_MAX -> INT64_MAX
+ // -1 -> INT64_MAX + 1 = INT64_MAX - (-1)
+ // -2 -> INT64_MAX + 2 = INT64_MAX - (-2)
+ // INT64_MIN -> UINT64_MAX = INT64_MAX - INT64_MIN
+ // Note how the unsigned arithmethic is well defined in C++ (it's
+ // always performed modulo 2^64).
+ auto makeSortable = [](qint64 v) {
+ quint64 u = quint64(v);
+ if (v < 0)
+ return quint64(std::numeric_limits<qint64>::max()) + (-u);
+ return u;
+ };
+ quint64 u1 = makeSortable(e1.value);
+ quint64 u2 = makeSortable(e2.value);
+ if (u1 < u2)
+ return -1;
+ if (u1 > u2)
+ return 1;
+ }
+
+ if (e1.type == QCborValue::Tag || e1.type == QCborValue::Double) {
+ // Perform unsigned comparisons for the tag value and floating point
+ quint64 u1 = quint64(e1.value);
+ quint64 u2 = quint64(e2.value);
+ if (u1 != u2)
+ return u1 < u2 ? -1 : 1;
+ }
+
+ // Any other type is equal at this point:
+ // - simple types carry no value
+ // - empty strings, arrays and maps
+ return 0;
+}
+
+static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1,
+ const QCborContainerPrivate *c2, const Element &e2)
+{
+ int cmp = typeOrder(e1, e2);
+ if (cmp != 0)
+ return cmp;
+
+ if ((e1.flags & Element::IsContainer) || (e2.flags & Element::IsContainer))
+ return compareContainer(e1.flags & Element::IsContainer ? e1.container : nullptr,
+ e2.flags & Element::IsContainer ? e2.container : nullptr);
+
+ // string data?
+ const ByteData *b1 = c1 ? c1->byteData(e1) : nullptr;
+ const ByteData *b2 = c2 ? c2->byteData(e2) : nullptr;
+ if (b1 || b2) {
+ auto len1 = b1 ? b1->len : 0;
+ auto len2 = b2 ? b2->len : 0;
+
+ if (e1.flags & Element::StringIsUtf16)
+ len1 /= 2;
+ if (e2.flags & Element::StringIsUtf16)
+ len2 /= 2;
+ if (len1 == 0 || len2 == 0)
+ return len1 < len2 ? -1 : len1 == len2 ? 0 : 1;
+
+ // we definitely have data from this point forward
+ Q_ASSERT(b1);
+ Q_ASSERT(b2);
+
+ // Officially with CBOR, we sort first the string with the shortest
+ // UTF-8 length. The length of an ASCII string is the same as its UTF-8
+ // and UTF-16 ones, but the UTF-8 length of a string is bigger than the
+ // UTF-16 equivalent. Combinations are:
+ // 1) UTF-16 and UTF-16
+ // 2) UTF-16 and UTF-8 <=== this is the problem case
+ // 3) UTF-16 and US-ASCII
+ // 4) UTF-8 and UTF-8
+ // 5) UTF-8 and US-ASCII
+ // 6) US-ASCII and US-ASCII
+ if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16)) {
+ // Case 1: both UTF-16, so lengths are comparable.
+ // (we can't use memcmp in little-endian machines)
+ if (len1 == len2)
+ return QtPrivate::compareStrings(b1->asStringView(), b2->asStringView());
+ return len1 < len2 ? -1 : 1;
+ }
+
+ if (!(e1.flags & Element::StringIsUtf16) && !(e2.flags & Element::StringIsUtf16)) {
+ // Cases 4, 5 and 6: neither is UTF-16, so lengths are comparable too
+ // (this case includes byte arrays too)
+ if (len1 == len2)
+ return memcmp(b1->byte(), b2->byte(), size_t(len1));
+ return len1 < len2 ? -1 : 1;
+ }
+
+ if (!(e1.flags & Element::StringIsAscii) || !(e2.flags & Element::StringIsAscii)) {
+ // Case 2: one of them is UTF-8 and the other is UTF-16, so lengths
+ // are NOT comparable. We need to convert to UTF-16 first...
+ auto string = [](const Element &e, const ByteData *b) {
+ return e.flags & Element::StringIsUtf16 ? b->asQStringRaw() : b->toUtf8String();
+ };
+
+ QString s1 = string(e1, b1);
+ QString s2 = string(e2, b2);
+ if (s1.size() == s2.size())
+ return s1.compare(s2);
+ return s1.size() < s2.size() ? -1 : 1;
+ }
+
+ // Case 3 (UTF-16 and US-ASCII) remains, so lengths are comparable again
+ if (len1 != len2)
+ return len1 < len2 ? -1 : 1;
+ if (e1.flags & Element::StringIsUtf16)
+ return QtPrivate::compareStrings(b1->asStringView(), b2->asLatin1());
+ return QtPrivate::compareStrings(b1->asLatin1(), b2->asStringView());
+ }
+
+ return compareElementNoData(e1, e2);
+}
+
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2)
+{
+ auto len1 = c1 ? c1->elements.size() : 0;
+ auto len2 = c2 ? c2->elements.size() : 0;
+ if (len1 != len2) {
+ // sort the shorter container first
+ return len1 < len2 ? -1 : 1;
+ }
+
+ for (qsizetype i = 0; i < len1; ++i) {
+ const Element &e1 = c1->elements.at(i);
+ const Element &e2 = c2->elements.at(i);
+ int cmp = QCborContainerPrivate::compareElement_helper(c1, e1, c2, e2);
+ if (cmp)
+ return cmp;
+ }
+
+ return 0;
+}
+
+inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPrivate *c1, Element e1,
+ const QCborContainerPrivate *c2, Element e2)
+{
+ return compareElementRecursive(c1, e1, c2, e2);
+}
+
+/*!
+ \fn bool QCborValue::operator==(const QCborValue &other) const
+
+ Compares this value and \a other, and returns true if they hold the same
+ contents, false otherwise. If each QCborValue contains an array or map, the
+ comparison is recursive to elements contained in them.
+
+ For more information on CBOR equality in Qt, see, compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator!=(), operator<()
+ */
+
+/*!
+ \fn bool QCborValue::operator!=(const QCborValue &other) const
+
+ Compares this value and \a other, and returns true if contents differ,
+ false otherwise. If each QCborValue contains an array or map, the comparison
+ is recursive to elements contained in them.
+
+ For more information on CBOR equality in Qt, see, QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator<()
+ */
+
+/*!
+ \fn bool QCborValue::operator<(const QCborValue &other) const
+
+ Compares this value and \a other, and returns true if this value should be
+ sorted before \a other, false otherwise. If each QCborValue contains an
+ array or map, the comparison is recursive to elements contained in them.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+ */
+
+/*!
+ Compares this value and \a other, and returns an integer that indicates
+ whether this value should be sorted prior to (if the result is negative) or
+ after \a other (if the result is positive). If this function returns 0, the
+ two values are equal and hold the same contents.
+
+ If each QCborValue contains an array or map, the comparison is recursive to
+ elements contained in them.
+
+ \section3 Extended types
+
+ QCborValue compares equal a QCborValue containing an extended type, like
+ \l{Type}{Url} and \l{Type}{Url} and its equivalent tagged representation.
+ So, for example, the following expression is true:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 3
+
+ Do note that Qt types like \l QUrl and \l QDateTime will normalize and
+ otherwise modify their arguments. The expression above is true only because
+ the string on the right side is the normalized value that the QCborValue on
+ the left would take. If, for example, the "https" part were uppercase in
+ both sides, the comparison would fail. For information on normalizations
+ performed by QCborValue, please consult the documentation of the
+ constructor taking the Qt type in question.
+
+ \section3 Sorting order
+
+ Sorting order in CBOR is defined in RFC 7049
+ {https://tools.ietf.org/html/rfc7049#section-3.9}{section 3.9}, which
+ discusses the sorting of keys in a map when following the Canonical
+ encoding. According to the specification, "sorting is performed on the
+ bytes of the representation of the key data items" and lists as
+ consequences that:
+
+ \list
+ \li "If two keys have different lengths, the shorter one sorts earlier;"
+ \li "If two keys have the same length, the one with the lower value in
+ (byte-wise) lexical order sorts earlier."
+ \endlist
+
+ This results in surprising sorting of QCborValues, where the result of this
+ function is different from that which would later be retrieved by comparing the
+ contained elements. For example, the QCborValue containing string "zzz"
+ sorts before the QCborValue with string "foobar", even though when
+ comparing as \l{QString::compare()}{QStrings} or
+ \l{QByteArray}{QByteArrays} the "zzz" sorts after "foobar"
+ (dictionary order).
+
+ The specification does not clearly indicate what sorting order should be
+ done for values of different types (it says sorting should not pay
+ "attention to the 3/5 bit splitting for major types"). QCborValue makes the
+ assumption that types should be sorted too. The numeric values of the
+ QCborValue::Type enumeration are in that order, with the exception of the
+ extended types, which compare as their tagged equivalents.
+
+ \note Sorting order is preliminary and is subject to change. Applications
+ should not depend on the order returned by this function for the time
+ being.
+
+ \sa QCborArray::compare(), QCborMap::compare(), operator==()
+ */
+int QCborValue::compare(const QCborValue &other) const
+{
+ Element e1 = QCborContainerPrivate::elementFromValue(*this);
+ Element e2 = QCborContainerPrivate::elementFromValue(other);
+ return compareElementRecursive(container, e1, other.container, e2);
+}
+
+int QCborArray::compare(const QCborArray &other) const noexcept
+{
+ return compareContainer(d.data(), other.d.data());
+}
+
+int QCborMap::compare(const QCborMap &other) const noexcept
+{
+ return compareContainer(d.data(), other.d.data());
+}
+
+static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate *d, qsizetype idx,
+ QCborValue::EncodingOptions opt)
+{
+ if (idx == -QCborValue::Array || idx == -QCborValue::Map) {
+ bool isArray = (idx == -QCborValue::Array);
+ qsizetype len = d ? d->elements.size() : 0;
+ if (isArray)
+ writer.startArray(quint64(len));
+ else
+ writer.startMap(quint64(len) / 2);
+
+ for (idx = 0; idx < len; ++idx)
+ encodeToCbor(writer, d, idx, opt);
+
+ if (isArray)
+ writer.endArray();
+ else
+ writer.endMap();
+ } else if (idx < 0) {
+ if (d->elements.size() != 2) {
+ // invalid state!
+ qWarning("QCborValue: invalid tag state; are you encoding something that was improperly decoded?");
+ return;
+ }
+
+ // write the tag and the tagged element
+ writer.append(QCborTag(d->elements.at(0).value));
+ encodeToCbor(writer, d, 1, opt);
+ } else {
+ // just one element
+ auto e = d->elements.at(idx);
+ const ByteData *b = d->byteData(idx);
+ switch (e.type) {
+ case QCborValue::Integer:
+ return writer.append(qint64(e.value));
+
+ case QCborValue::ByteArray:
+ if (b)
+ return writer.appendByteString(b->byte(), b->len);
+ return writer.appendByteString("", 0);
+
+ case QCborValue::String:
+ if (b) {
+ if (e.flags & Element::StringIsUtf16)
+ return writer.append(b->asStringView());
+ return writer.appendTextString(b->byte(), b->len);
+ }
+ return writer.append(QLatin1String());
+
+ case QCborValue::Array:
+ case QCborValue::Map:
+ case QCborValue::Tag:
+ // recurse
+ return encodeToCbor(writer,
+ e.flags & Element::IsContainer ? e.container : nullptr,
+ -qsizetype(e.type), opt);
+
+ case QCborValue::SimpleType:
+ case QCborValue::False:
+ case QCborValue::True:
+ case QCborValue::Null:
+ case QCborValue::Undefined:
+ break;
+
+ case QCborValue::Double:
+ return writeDoubleToCbor(writer, e.fpvalue(), opt);
+
+ case QCborValue::Invalid:
+ return;
+
+ case QCborValue::DateTime:
+ case QCborValue::Url:
+ case QCborValue::RegularExpression:
+ case QCborValue::Uuid:
+ // recurse as tag
+ return encodeToCbor(writer, e.container, -QCborValue::Tag, opt);
+ }
+
+ // maybe it's a simple type
+ int simpleType = e.type - QCborValue::SimpleType;
+ if (unsigned(simpleType) < 0x100)
+ return writer.append(QCborSimpleType(simpleType));
+
+ // if we got here, we've got an unknown type
+ qWarning("QCborValue: found unknown type 0x%x", e.type);
+ }
+}
+
+static inline double integerOutOfRange(const QCborStreamReader &reader)
+{
+ Q_ASSERT(reader.isInteger());
+ if (reader.isUnsignedInteger()) {
+ quint64 v = reader.toUnsignedInteger();
+ if (qint64(v) < 0)
+ return double(v);
+ } else {
+ quint64 v = quint64(reader.toNegativeInteger());
+ if (qint64(v - 1) < 0)
+ return -double(v);
+ }
+
+ // result is in range
+ return 0;
+}
+
+static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
+{
+ Element e = {};
+
+ switch (reader.type()) {
+ case QCborStreamReader::UnsignedInteger:
+ case QCborStreamReader::NegativeInteger:
+ if (double d = integerOutOfRange(reader)) {
+ e.type = QCborValue::Double;
+ qToUnaligned(d, &e.value);
+ } else {
+ e.type = QCborValue::Integer;
+ e.value = reader.toInteger();
+ }
+ break;
+ case QCborStreamReader::SimpleType:
+ e.type = QCborValue::Type(quint8(reader.toSimpleType()) + 0x100);
+ break;
+ case QCborStreamReader::Float16:
+ e.type = QCborValue::Double;
+ qToUnaligned(double(reader.toFloat16()), &e.value);
+ break;
+ case QCborStreamReader::Float:
+ e.type = QCborValue::Double;
+ qToUnaligned(double(reader.toFloat()), &e.value);
+ break;
+ case QCborStreamReader::Double:
+ e.type = QCborValue::Double;
+ qToUnaligned(reader.toDouble(), &e.value);
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+
+ reader.next();
+ return e;
+}
+
+static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader)
+{
+ auto d = new QCborContainerPrivate;
+ d->ref.store(1);
+ d->decodeFromCbor(reader);
+ return d;
+}
+
+static QCborValue taggedValueFromCbor(QCborStreamReader &reader)
+{
+ auto d = new QCborContainerPrivate;
+ d->append(reader.toTag());
+ reader.next();
+
+ if (reader.lastError() == QCborError::NoError) {
+ // decode tagged value
+ d->decodeValueFromCbor(reader);
+ }
+
+ QCborValue::Type type = QCborValue::Tag;
+ if (reader.lastError() == QCborError::NoError) {
+ // post-process to create our extended types
+ qint64 tag = d->elements.at(0).value;
+ auto &e = d->elements[1];
+ const ByteData *b = d->byteData(e);
+
+ auto replaceByteData = [&](const char *buf, qsizetype len) {
+ d->data.clear();
+ d->usedData = 0;
+ e.flags = Element::HasByteData | Element::StringIsAscii;
+ e.value = d->addByteData(buf, len);
+ };
+
+ switch (tag) {
+ case qint64(QCborKnownTags::DateTimeString):
+ case qint64(QCborKnownTags::UnixTime_t): {
+ QDateTime dt;
+ if (tag == qint64(QCborKnownTags::DateTimeString) && b &&
+ e.type == QCborValue::String && (e.flags & Element::StringIsUtf16) == 0) {
+ // The data is supposed to be US-ASCII. If it isn't,
+ // QDateTime::fromString will fail anyway.
+ dt = QDateTime::fromString(b->asLatin1(), Qt::ISODateWithMs);
+ } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Integer) {
+ dt = QDateTime::fromSecsSinceEpoch(e.value, Qt::UTC);
+ } else if (tag == qint64(QCborKnownTags::UnixTime_t) && e.type == QCborValue::Double) {
+ dt = QDateTime::fromMSecsSinceEpoch(qint64(e.fpvalue() * 1000), Qt::UTC);
+ }
+ if (dt.isValid()) {
+ QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1();
+ replaceByteData(text, text.size());
+ e.type = QCborValue::String;
+ d->elements[0].value = qint64(QCborKnownTags::DateTimeString);
+ type = QCborValue::DateTime;
+ }
+ break;
+ }
+
+ case qint64(QCborKnownTags::Url):
+ if (e.type == QCborValue::String) {
+ if (b) {
+ // normalize to a short (decoded) form, so as to save space
+ QUrl url(e.flags & Element::StringIsUtf16 ?
+ b->asQStringRaw() :
+ b->toUtf8String());
+ QByteArray encoded = url.toString(QUrl::DecodeReserved).toUtf8();
+ replaceByteData(encoded, encoded.size());
+ }
+ type = QCborValue::Url;
+ }
+ break;
+
+ case quint64(QCborKnownTags::RegularExpression):
+ if (e.type == QCborValue::String) {
+ // no normalization is necessary
+ type = QCborValue::RegularExpression;
+ }
+ break;
+
+ case qint64(QCborKnownTags::Uuid):
+ if (e.type == QCborValue::ByteArray) {
+ // force the size to 16
+ char buf[sizeof(QUuid)] = {};
+ if (b)
+ memcpy(buf, b->byte(), qMin(sizeof(buf), size_t(b->len)));
+ replaceByteData(buf, sizeof(buf));
+
+ type = QCborValue::Uuid;
+ }
+ break;
+ }
+ } else {
+ // decoding error
+ type = QCborValue::Invalid;
+ }
+
+ // note: may return invalid state!
+ return QCborContainerPrivate::makeValue(type, -1, d);
+}
+
+void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
+{
+ auto addByteData_local = [this](QByteArray::size_type len) -> qint64 {
+ // this duplicates a lot of addByteData, but with overflow checking
+ QByteArray::size_type newSize;
+ QByteArray::size_type increment = sizeof(QtCbor::ByteData);
+ QByteArray::size_type alignment = alignof(QtCbor::ByteData);
+ QByteArray::size_type offset = data.size();
+
+ // calculate the increment we want
+ if (add_overflow(increment, len, &increment))
+ return -1;
+
+ // align offset
+ if (add_overflow(offset, alignment - 1, &offset))
+ return -1;
+ offset &= ~(alignment - 1);
+
+ // and calculate the final size
+ if (add_overflow(offset, increment, &newSize))
+ return -1;
+
+ // since usedData <= data.size(), this can't overflow
+ usedData += increment;
+ data.resize(newSize);
+ return offset;
+ };
+ auto dataPtr = [this]() {
+ // Null happens when we're reading zero bytes.
+ Q_ASSERT(data.isNull() || data.isDetached());
+ return const_cast<char *>(data.constData());
+ };
+
+ Element e = {};
+ e.type = (reader.isByteArray() ? QCborValue::ByteArray : QCborValue::String);
+ if (reader.lastError() != QCborError::NoError)
+ return;
+
+ qsizetype rawlen = reader.currentStringChunkSize();
+ QByteArray::size_type len = rawlen;
+ if (rawlen < 0)
+ return; // error
+ if (len != rawlen) {
+ // truncation
+ qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
+ return;
+ }
+
+ // allocate space, but only if there will be data
+ if (len != 0 || !reader.isLengthKnown()) {
+ e.flags = Element::HasByteData;
+ e.value = addByteData_local(len);
+ if (e.value < 0) {
+ // overflow
+ qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
+ return;
+ }
+ }
+
+ // read chunks
+ bool isAscii = (e.type == QCborValue::String);
+ auto r = reader.readStringChunk(dataPtr() + e.value + sizeof(ByteData), len);
+ while (r.status == QCborStreamReader::Ok) {
+ if (e.type == QCborValue::String && len) {
+ // verify UTF-8 string validity
+ auto utf8result = QUtf8::isValidUtf8(dataPtr() + data.size() - len, len);
+ if (!utf8result.isValidUtf8) {
+ r.status = QCborStreamReader::Error;
+ qt_cbor_stream_set_error(reader.d.data(), { QCborError::InvalidUtf8String });
+ break;
+ }
+ isAscii = isAscii && utf8result.isValidAscii;
+ }
+
+ // allocate space for the next chunk
+ rawlen = reader.currentStringChunkSize();
+ len = rawlen;
+ if (len == rawlen) {
+ auto oldSize = data.size();
+ auto newSize = oldSize;
+ if (!add_overflow(newSize, len, &newSize)) {
+ if (newSize != oldSize)
+ data.resize(newSize);
+
+ // read the chunk
+ r = reader.readStringChunk(dataPtr() + oldSize, len);
+ continue;
+ }
+ }
+
+ // error
+ r.status = QCborStreamReader::Error;
+ qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
+ }
+
+ if (r.status == QCborStreamReader::Error) {
+ // There can only be errors if there was data to be read.
+ Q_ASSERT(e.flags & Element::HasByteData);
+ data.truncate(e.value);
+ return;
+ }
+
+ // update size
+ if (e.flags & Element::HasByteData) {
+ auto b = new (dataPtr() + e.value) ByteData;
+ b->len = data.size() - e.value - int(sizeof(*b));
+ usedData += b->len;
+
+ if (isAscii) {
+ // set the flag if it is US-ASCII only (as it often is)
+ Q_ASSERT(e.type == QCborValue::String);
+ e.flags |= Element::StringIsAscii;
+ }
+ }
+
+ elements.append(e);
+}
+
+void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader)
+{
+ switch (reader.type()) {
+ case QCborStreamReader::UnsignedInteger:
+ case QCborStreamReader::NegativeInteger:
+ case QCborStreamReader::SimpleType:
+ case QCborStreamReader::Float16:
+ case QCborStreamReader::Float:
+ case QCborStreamReader::Double:
+ elements.append(decodeBasicValueFromCbor(reader));
+ break;
+
+ case QCborStreamReader::ByteArray:
+ case QCborStreamReader::String:
+ decodeStringFromCbor(reader);
+ break;
+
+ case QCborStreamReader::Array:
+ case QCborStreamReader::Map:
+ case QCborStreamReader::Tag:
+ return append(QCborValue::fromCbor(reader));
+
+ case QCborStreamReader::Invalid:
+ return; // probably a decode error
+ }
+}
+
+void QCborContainerPrivate::decodeFromCbor(QCborStreamReader &reader)
+{
+ int mapShift = reader.isMap() ? 1 : 0;
+ if (reader.isLengthKnown()) {
+ quint64 len = reader.length();
+
+ // Clamp allocation to 1M elements (avoids crashing due to corrupt
+ // stream or loss of precision when converting from quint64 to
+ // QVector::size_type).
+ len = qMin(len, quint64(1024 * 1024 - 1));
+ elements.reserve(qsizetype(len) << mapShift);
+ }
+
+ reader.enterContainer();
+ if (reader.lastError() != QCborError::NoError)
+ return;
+
+ while (reader.hasNext() && reader.lastError() == QCborError::NoError)
+ decodeValueFromCbor(reader);
+
+ if (reader.lastError() == QCborError::NoError)
+ reader.leaveContainer();
+}
+
+/*!
+ Creates a QCborValue with byte array value \a ba. The value can later be
+ retrieved using toByteArray().
+
+ \sa toByteArray(), isByteArray(), isString()
+ */
+QCborValue::QCborValue(const QByteArray &ba)
+ : n(0), container(new QCborContainerPrivate), t(ByteArray)
+{
+ container->appendByteData(ba.constData(), ba.size(), t);
+ container->ref.store(1);
+}
+
+/*!
+ Creates a QCborValue with string value \a s. The value can later be
+ retrieved using toString().
+
+ \sa toString(), isString(), isByteArray()
+ */
+QCborValue::QCborValue(const QString &s)
+ : n(0), container(new QCborContainerPrivate), t(String)
+{
+ container->append(s);
+ container->ref.store(1);
+}
+
+/*!
+ \overload
+
+ Creates a QCborValue with string value \a s. The value can later be
+ retrieved using toString().
+
+ \sa toString(), isString(), isByteArray()
+ */
+QCborValue::QCborValue(QLatin1String s)
+ : n(0), container(new QCborContainerPrivate), t(String)
+{
+ container->append(s);
+ container->ref.store(1);
+}
+
+/*!
+ \fn QCborValue::QCborValue(const QCborArray &a)
+ \fn QCborValue::QCborValue(QCborArray &&a)
+
+ Creates a QCborValue with the array \a a. The array can later be retrieved
+ using toArray().
+
+ \sa toArray(), isArray(), isMap()
+ */
+QCborValue::QCborValue(const QCborArray &a)
+ : n(-1), container(a.d.data()), t(Array)
+{
+ if (container)
+ container->ref.ref();
+}
+
+/*!
+ \fn QCborValue::QCborValue(const QCborMap &m)
+ \fn QCborValue::QCborValue(QCborMap &&m)
+
+ Creates a QCborValue with the map \a m. The map can later be retrieved
+ using toMap().
+
+ \sa toMap(), isMap(), isArray()
+ */
+QCborValue::QCborValue(const QCborMap &m)
+ : n(-1), container(m.d.data()), t(Map)
+{
+ if (container)
+ container->ref.ref();
+}
+
+/*!
+ \fn QCborValue::QCborValue(QCborTag t, const QCborValue &tv)
+ \fn QCborValue::QCborValue(QCborKnownTags t, const QCborValue &tv)
+
+ Creates a QCborValue for the extended type represented by the tag value \a
+ t, tagging value \a tv. The tag can later be retrieved using tag() and
+ the tagged value using taggedValue().
+
+ \sa isTag(), tag(), taggedValue(), QCborKnownTags
+ */
+QCborValue::QCborValue(QCborTag t, const QCborValue &tv)
+ : n(-1), container(new QCborContainerPrivate), t(Tag)
+{
+ container->ref.store(1);
+ container->append(t);
+ container->append(tv);
+}
+
+/*!
+ Copies the contents of \a other into this object.
+ */
+QCborValue::QCborValue(const QCborValue &other)
+ : n(other.n), container(other.container), t(other.t)
+{
+ if (container)
+ container->ref.ref();
+}
+
+/*!
+ Creates a QCborValue object of the date/time extended type and containing
+ the value represented by \a dt. The value can later be retrieved using
+ toDateTime().
+
+ The CBOR date/time types are extension types using tags: either a string
+ (in ISO date format) tagged as a \l{QCborKnownTags}{DateTime} or a number
+ (of seconds since the start of 1970, UTC) tagged as a
+ \l{QCborKnownTags}{UnixTime_t}. When parsing CBOR streams, QCborValue will
+ convert \l{QCborKnownTags}{UnixTime_t} to the string-based type.
+
+ \sa toDateTime(), isDateTime(), taggedValue()
+ */
+QCborValue::QCborValue(const QDateTime &dt)
+ : QCborValue(QCborKnownTags::DateTimeString, dt.toString(Qt::ISODateWithMs).toLatin1())
+{
+ // change types
+ t = DateTime;
+ container->elements[1].type = String;
+}
+
+/*!
+ Creates a QCborValue object of the URL extended type and containing the
+ value represented by \a url. The value can later be retrieved using toUrl().
+
+ The CBOR URL type is an extended type represented by a string tagged as an
+ \l{QCborKnownTags}{Url}.
+
+ \sa toUrl(), isUrl(), taggedValue()
+ */
+QCborValue::QCborValue(const QUrl &url)
+ : QCborValue(QCborKnownTags::Url, url.toString(QUrl::DecodeReserved).toUtf8())
+{
+ // change types
+ t = Url;
+ container->elements[1].type = String;
+}
+
+/*!
+ Creates a QCborValue object of the regular expression pattern extended type
+ and containing the value represented by \a rx. The value can later be retrieved
+ using toRegularExpression().
+
+ The CBOR regular expression type is an extended type represented by a
+ string tagged as an \l{QCborKnownTags}{RegularExpression}. Note that CBOR
+ regular expressions only store the patterns, so any flags that the
+ QRegularExpression object may carry will be lost.
+
+ \sa toRegularExpression(), isRegularExpression(), taggedValue()
+ */
+QCborValue::QCborValue(const QRegularExpression &rx)
+ : QCborValue(QCborKnownTags::RegularExpression, rx.pattern())
+{
+ // change type
+ t = RegularExpression;
+}
+
+/*!
+ Creates a QCborValue object of the UUID extended type and containing the
+ value represented by \a uuid. The value can later be retrieved using
+ toUuid().
+
+ The CBOR UUID type is an extended type represented by a byte array tagged
+ as an \l{QCborKnownTags}{Uuid}.
+
+ \sa toUuid(), isUuid(), taggedValue()
+ */
+QCborValue::QCborValue(const QUuid &uuid)
+ : QCborValue(QCborKnownTags::Uuid, uuid.toRfc4122())
+{
+ // change our type
+ t = Uuid;
+}
+
+// destructor
+void QCborValue::dispose()
+{
+ container->deref();
+}
+
+/*!
+ Replaces the contents of this QCborObject with a copy of \a other.
+ */
+QCborValue &QCborValue::operator=(const QCborValue &other)
+{
+ if (other.container)
+ other.container->ref.ref();
+ if (container)
+ container->deref();
+
+ n = other.n;
+ container = other.container;
+ t = other.t;
+ return *this;
+}
+
+/*!
+ Returns the tag of this extended QCborValue object, if it is of the tag
+ type, \a defaultValue otherwise.
+
+ CBOR represents extended types by associating a number (the tag) with a
+ stored representation. This function returns that number. To retrieve the
+ representation, use taggedValue().
+
+ \sa isTag(), taggedValue(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
+ */
+QCborTag QCborValue::tag(QCborTag defaultValue) const
+{
+ return isTag() && container && container->elements.size() == 2 ?
+ QCborTag(container->elements.at(0).value) : defaultValue;
+}
+
+/*!
+ Returns the tagged value of this extended QCborValue object, if it is of
+ the tag type, \a defaultValue otherwise.
+
+ CBOR represents extended types by associating a number (the tag) with a
+ stored representation. This function returns that representation. To
+ retrieve the tag, use tag().
+
+ \sa isTag(), tag(), isDateTime(), isUrl(), isRegularExpression(), isUuid()
+ */
+QCborValue QCborValue::taggedValue(const QCborValue &defaultValue) const
+{
+ return isTag() && container && container->elements.size() == 2 ?
+ container->valueAt(1) : defaultValue;
+}
+
+/*!
+ Returns the byte array value stored in this QCborValue, if it is of the byte
+ array type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QByteArray.
+
+ \sa isByteArray(), isString(), toString()
+ */
+QByteArray QCborValue::toByteArray(const QByteArray &defaultValue) const
+{
+ if (!container || !isByteArray())
+ return defaultValue;
+
+ Q_ASSERT(n >= 0);
+ return container->byteArrayAt(n);
+}
+
+/*!
+ Returns the string value stored in this QCborValue, if it is of the string
+ type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QString.
+
+ \sa isString(), isByteArray(), toByteArray()
+ */
+QString QCborValue::toString(const QString &defaultValue) const
+{
+ if (!container || !isString())
+ return defaultValue;
+
+ Q_ASSERT(n >= 0);
+ return container->stringAt(n);
+}
+
+/*!
+ Returns the date/time value stored in this QCborValue, if it is of the
+ date/time extended type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QDateTime.
+
+ \sa isDateTime(), isTag(), taggedValue()
+ */
+QDateTime QCborValue::toDateTime(const QDateTime &defaultValue) const
+{
+ if (!container || !isDateTime() || container->elements.size() != 2)
+ return defaultValue;
+
+ Q_ASSERT(n == -1);
+ const ByteData *byteData = container->byteData(1);
+ if (!byteData)
+ return defaultValue; // date/times are never empty, so this must be invalid
+
+ // Our data must be US-ASCII.
+ Q_ASSERT((container->elements.at(1).flags & Element::StringIsUtf16) == 0);
+ return QDateTime::fromString(byteData->asLatin1(), Qt::ISODateWithMs);
+}
+
+/*!
+ Returns the URL value stored in this QCborValue, if it is of the URL
+ extended type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to QUrl.
+
+ \sa isUrl(), isTag(), taggedValue()
+ */
+QUrl QCborValue::toUrl(const QUrl &defaultValue) const
+{
+ if (!container || !isUrl() || container->elements.size() != 2)
+ return defaultValue;
+
+ Q_ASSERT(n == -1);
+ const ByteData *byteData = container->byteData(1);
+ if (!byteData)
+ return QUrl(); // valid, empty URL
+
+ return QUrl::fromEncoded(byteData->asByteArrayView());
+}
+
+/*!
+ Returns the regular expression value stored in this QCborValue, if it is of
+ the regular expression pattern extended type. Otherwise, it returns \a
+ defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QRegularExpression.
+
+ \sa isRegularExpression(), isTag(), taggedValue()
+ */
+QRegularExpression QCborValue::toRegularExpression(const QRegularExpression &defaultValue) const
+{
+ if (!container || !isRegularExpression() || container->elements.size() != 2)
+ return defaultValue;
+
+ Q_ASSERT(n == -1);
+ return QRegularExpression(container->stringAt(1));
+}
+
+/*!
+ Returns the UUID value stored in this QCborValue, if it is of the UUID
+ extended type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to QUuid.
+
+ \sa isUuid(), isTag(), taggedValue()
+ */
+QUuid QCborValue::toUuid(const QUuid &defaultValue) const
+{
+ if (!container || !isUuid() || container->elements.size() != 2)
+ return defaultValue;
+
+ Q_ASSERT(n == -1);
+ const ByteData *byteData = container->byteData(1);
+ if (!byteData)
+ return defaultValue; // UUIDs must always be 16 bytes, so this must be invalid
+
+ return QUuid::fromRfc4122(byteData->asByteArrayView());
+}
+
+QCborArray QCborValue::toArray() const
+{
+ return toArray(QCborArray());
+}
+
+/*!
+ Returns the array value stored in this QCborValue, if it is of the array
+ type. Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QCborArray.
+
+ \sa isArray(), isByteArray(), isMap(), isContainer(), toMap()
+ */
+QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
+{
+ if (!isArray())
+ return defaultValue;
+ QCborContainerPrivate *dd = nullptr;
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
+ return dd ? QCborArray(*dd) : defaultValue;
+}
+
+QCborMap QCborValue::toMap() const
+{
+ return toMap(QCborMap());
+}
+
+/*!
+ Returns the map value stored in this QCborValue, if it is of the map type.
+ Otherwise, it returns \a defaultValue.
+
+ Note that this function performs no conversion from other types to
+ QCborMap.
+
+ \sa isMap(), isArray(), isContainer(), toArray()
+ */
+QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
+{
+ if (!isMap())
+ return defaultValue;
+ QCborContainerPrivate *dd = nullptr;
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
+ return dd ? QCborMap(*dd) : defaultValue;
+}
+
+/*!
+ If this QCborValue is a QCborMap, searches elements for the value whose key
+ matches \a key. If there's no key matching \a key in the map or if this
+ QCborValue object is not a map, returns the undefined value.
+
+ This function is equivalent to:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 4
+
+ \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
+ QCborMap::find()
+ */
+const QCborValue QCborValue::operator[](const QString &key) const
+{
+ if (isMap())
+ return toMap().value(key);
+ return QCborValue();
+}
+
+/*!
+ \overload
+
+ If this QCborValue is a QCborMap, searches elements for the value whose key
+ matches \a key. If there's no key matching \a key in the map or if this
+ QCborValue object is not a map, returns the undefined value.
+
+ This function is equivalent to:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 5
+
+ \sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
+ QCborMap::find()
+ */
+const QCborValue QCborValue::operator[](QLatin1String key) const
+{
+ if (isMap())
+ return toMap().value(key);
+ return QCborValue();
+}
+
+/*!
+ If this QCborValue is a QCborMap, searches elements for the value whose key
+ matches \a key. If this is an array, returns the element whose index is \a
+ key. If there's no matching value in the array or map, or if this
+ QCborValue object is not an array or map, returns the undefined value.
+
+ \sa operator[], QCborMap::operator[], QCborMap::value(),
+ QCborMap::find(), QCborArray::operator[], QCborArray::at()
+ */
+
+const QCborValue QCborValue::operator[](qint64 key) const
+{
+ if (isMap())
+ return toMap().value(key);
+ if (isArray())
+ return toArray().at(key);
+ return QCborValue();
+}
+
+/*!
+ Decodes one item from the CBOR stream found in \a reader and returns the
+ equivalent representation. This function is recursive: if the item is a map
+ or array, it will decode all items found in that map or array, until the
+ outermost object is finished.
+
+ This function need not be used on the root element of a \l
+ QCborStreamReader. For example, the following code illustrates how to skip
+ the CBOR signature tag from the beginning of a file:
+
+ \snippet code/src_corelib_serialization_qcborvalue.cpp 6
+
+ The returned value may be partially complete and indistinguishable from a
+ valid QCborValue even if the decoding failed. To determine if there was an
+ error, check if \l{QCborStreamReader::lastError()}{reader.lastError()} is
+ indicating an error condition. This function stops decoding immediately
+ after the first error.
+
+ \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
+ */
+QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
+{
+ QCborValue result;
+ auto t = reader.type();
+ if (reader.lastError() != QCborError::NoError)
+ t = QCborStreamReader::Invalid;
+
+ switch (t) {
+ // basic types, no container needed:
+ case QCborStreamReader::UnsignedInteger:
+ case QCborStreamReader::NegativeInteger:
+ case QCborStreamReader::SimpleType:
+ case QCborStreamReader::Float16:
+ case QCborStreamReader::Float:
+ case QCborStreamReader::Double: {
+ Element e = decodeBasicValueFromCbor(reader);
+ result.n = e.value;
+ result.t = e.type;
+ break;
+ }
+
+ case QCborStreamReader::Invalid:
+ result.t = QCborValue::Invalid;
+ break; // probably a decode error
+
+ // strings
+ case QCborStreamReader::ByteArray:
+ case QCborStreamReader::String:
+ result.n = 0;
+ result.t = reader.isString() ? String : ByteArray;
+ result.container = new QCborContainerPrivate;
+ result.container->ref.ref();
+ result.container->decodeStringFromCbor(reader);
+ break;
+
+ // containers
+ case QCborStreamReader::Array:
+ case QCborStreamReader::Map:
+ result.n = -1;
+ result.t = reader.isArray() ? Array : Map;
+ result.container = createContainerFromCbor(reader);
+ break;
+
+ // tag
+ case QCborStreamReader::Tag:
+ result = taggedValueFromCbor(reader);
+ break;
+ }
+
+ return result;
+}
+
+/*!
+ \overload
+
+ Decodes one item from the CBOR stream found in the byte array \a ba and
+ returns the equivalent representation. This function is recursive: if the
+ item is a map or array, it will decode all items found in that map or
+ array, until the outermost object is finished.
+
+ This function stores the error state, if any, in the object pointed to by
+ \a error, along with the offset of where the error occurred. If no error
+ happened, it stores \l{QCborError}{NoError} in the error state and the
+ number of bytes that it consumed (that is, it stores the offset for the
+ first unused byte). Using that information makes it possible to parse
+ further data that may exist in the same byte array.
+
+ The returned value may be partially complete and indistinguishable from a
+ valid QCborValue even if the decoding failed. To determine if there was an
+ error, check if there was an error stored in \a error. This function stops
+ decoding immediately after the first error.
+
+ \sa toCbor(), toDiagnosticNotation(), toVariant(), toJsonValue()
+ */
+QCborValue QCborValue::fromCbor(const QByteArray &ba, QCborParserError *error)
+{
+ QCborStreamReader reader(ba);
+ QCborValue result = fromCbor(reader);
+ if (error) {
+ error->error = reader.lastError();
+ error->offset = reader.currentOffset();
+ }
+ return result;
+}
+
+/*!
+ \fn QCborValue QCborValue::fromCbor(const char *data, qsizetype len, QCborParserError *error)
+ \fn QCborValue QCborValue::fromCbor(const quint8 *data, qsizetype len, QCborParserError *error)
+ \overload
+
+ Converts \a len bytes of \a data to a QByteArray and then calls the
+ overload of this function that accepts a QByteArray, also passing \a error,
+ if provided.
+*/
+
+/*!
+ Encodes this QCborValue object to its CBOR representation, using the
+ options specified in \a opt, and return the byte array containing that
+ representation.
+
+ This function will not fail, except if this QCborValue or any of the
+ contained items, if this is a map or array, are invalid. Invalid types are
+ not produced normally by the API, but can result from decoding errors.
+
+ By default, this function performs no transformation on the values in the
+ QCborValue, writing all floating point directly as double-precision (\c
+ double) types. If the \l{EncodingOption}{UseFloat} option is specified, it
+ will use single precision (\c float) for any floating point value for which
+ there's no loss of precision in using that representation. That includes
+ infinities and NaN values.
+
+ Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
+ will try to use half-precision (\c qfloat16) floating point if the
+ conversion to that results in no loss of precision. This is always true for
+ infinities and NaN.
+
+ If \l{EncodingOption}{UseIntegers} is specified, it will use integers for
+ any floating point value that contains an actual integer.
+
+ \sa fromCbor(), fromVariant(), fromJsonValue()
+ */
+QByteArray QCborValue::toCbor(EncodingOptions opt)
+{
+ QByteArray result;
+ QCborStreamWriter writer(&result);
+ toCbor(writer, opt);
+ return result;
+}
+
+/*!
+ \overload
+
+ Encodes this QCborValue object to its CBOR representation, using the
+ options specified in \a opt, to the writer specified by \a writer. The same
+ writer can be used by multiple QCborValues, for example, in order to encode
+ different elements in a larger array.
+
+ This function will not fail, except if this QCborValue or any of the
+ contained items, if this is a map or array, are invalid. Invalid types are
+ not produced normally by the API, but can result from decoding errors.
+
+ By default, this function performs no transformation on the values in the
+ QCborValue, writing all floating point directly as double-precision
+ (binary64) types. If the \l{EncodingOption}{UseFloat} option is
+ specified, it will use single precision (binary32) for any floating point
+ value for which there's no loss of precision in using that representation.
+ That includes infinities and NaN values.
+
+ Similarly, if \l{EncodingOption}{UseFloat16} is specified, this function
+ will try to use half-precision (binary16) floating point if the conversion
+ to that results in no loss of precision. This is always true for infinities
+ and NaN.
+
+ If \l{EncodingOption}{UseIntegers} is specified, it will use integers
+ for any floating point value that contains an actual integer.
+
+ \sa fromCbor(), fromVariant(), fromJsonValue()
+ */
+Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOptions opt)
+{
+ if (isContainer() || isTag())
+ return encodeToCbor(writer, container, -type(), opt);
+ if (container)
+ return encodeToCbor(writer, container, n, opt);
+
+ // very simple types
+ if (isSimpleType())
+ return writer.append(toSimpleType());
+
+ switch (type()) {
+ case Integer:
+ return writer.append(n);
+
+ case Double:
+ return writeDoubleToCbor(writer, fp_helper(), opt);
+
+ case Invalid:
+ return;
+
+ case SimpleType:
+ case False:
+ case True:
+ case Null:
+ case Undefined:
+ // handled by "if (isSimpleType())"
+ Q_UNREACHABLE();
+ break;
+
+ case ByteArray:
+ // Byte array with no container is empty
+ return writer.appendByteString("", 0);
+
+ case String:
+ // String with no container is empty
+ return writer.appendTextString("", 0);
+
+ case Array:
+ case Map:
+ case Tag:
+ // handled by "if (isContainer() || isTag())"
+ Q_UNREACHABLE();
+ break;
+
+ case DateTime:
+ case Url:
+ case RegularExpression:
+ case Uuid:
+ // not possible
+ Q_UNREACHABLE();
+ break;
+ }
+}
+
+void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
+{
+ concrete().toCbor(writer, opt);
+}
+
+void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
+{
+ that.d->replaceAt(that.i, other);
+}
+
+void QCborValueRef::assign(QCborValueRef that, QCborValue &&other)
+{
+ that.d->replaceAt(that.i, other, QCborContainerPrivate::MoveContainer);
+}
+
+void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
+{
+ // ### optimize?
+ assign(that, other.concrete());
+}
+
+QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
+{
+ return self.d->valueAt(self.i);
+}
+
+QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
+{
+ return self.d->elements.at(self.i).type;
+}
+
+inline QCborArray::QCborArray(QCborContainerPrivate &dd) noexcept
+ : d(&dd)
+{
+}
+
+inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept
+ : d(&dd)
+{
+}
+
+uint qHash(const QCborValue &value, uint seed)
+{
+ switch (value.type()) {
+ case QCborValue::Integer:
+ return qHash(value.toInteger(), seed);
+ case QCborValue::ByteArray:
+ return qHash(value.toByteArray(), seed);
+ case QCborValue::String:
+ return qHash(value.toString(), seed);
+ case QCborValue::Array:
+ return qHash(value.toArray(), seed);
+ case QCborValue::Map:
+ return qHash(value.toMap(), seed);
+ case QCborValue::Tag: {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, value.tag());
+ seed = hash(seed, value.taggedValue());
+ return seed;
+ }
+ case QCborValue::SimpleType:
+ break;
+ case QCborValue::False:
+ return qHash(false, seed);
+ case QCborValue::True:
+ return qHash(true, seed);
+ case QCborValue::Null:
+ return qHash(nullptr, seed);
+ case QCborValue::Undefined:
+ return seed;
+ case QCborValue::Double:
+ return qHash(value.toDouble(), seed);
+ case QCborValue::DateTime:
+ return qHash(value.toDateTime(), seed);
+ case QCborValue::Url:
+ return qHash(value.toUrl(), seed);
+ case QCborValue::RegularExpression:
+ return qHash(value.toRegularExpression(), seed);
+ case QCborValue::Uuid:
+ return qHash(value.toUuid(), seed);
+ case QCborValue::Invalid:
+ return seed;
+ }
+
+ Q_ASSERT(value.isSimpleType());
+ return qHash(value.toSimpleType(), seed);
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+static QDebug debugContents(QDebug &dbg, const QCborValue &v)
+{
+ switch (v.type()) {
+ case QCborValue::Integer:
+ return dbg << v.toInteger();
+ case QCborValue::ByteArray:
+ return dbg << "QByteArray(" << v.toByteArray() << ')';
+ case QCborValue::String:
+ return dbg << v.toString();
+ case QCborValue::Array:
+ return dbg << v.toArray();
+ case QCborValue::Map:
+ return dbg << v.toMap();
+ case QCborValue::Tag:
+ dbg << v.tag() << ", ";
+ return debugContents(dbg, v.taggedValue());
+ case QCborValue::SimpleType:
+ break;
+ case QCborValue::True:
+ return dbg << true;
+ case QCborValue::False:
+ return dbg << false;
+ case QCborValue::Null:
+ return dbg << "nullptr";
+ case QCborValue::Undefined:
+ return dbg;
+ case QCborValue::Double: {
+ qint64 i = qint64(v.toDouble());
+ if (i == v.toDouble())
+ return dbg << i << ".0";
+ else
+ return dbg << v.toDouble();
+ }
+ case QCborValue::DateTime:
+ return dbg << v.toDateTime();
+ case QCborValue::Url:
+ return dbg << v.toUrl();
+ case QCborValue::RegularExpression:
+ return dbg << v.toRegularExpression();
+ case QCborValue::Uuid:
+ return dbg << v.toUuid();
+ case QCborValue::Invalid:
+ return dbg << "<invalid>";
+ }
+ if (v.isSimpleType())
+ return dbg << v.toSimpleType();
+ return dbg << "<unknown type " << hex << int(v.type()) << dec << '>';
+}
+QDebug operator<<(QDebug dbg, const QCborValue &v)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QCborValue(";
+ return debugContents(dbg, v) << ')';
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "qcborarray.cpp"
+#include "qcbormap.cpp"
+
+#include "moc_qcborvalue.cpp"
diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
new file mode 100644
index 0000000000..6d9ed0810a
--- /dev/null
+++ b/src/corelib/serialization/qcborvalue.h
@@ -0,0 +1,467 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORVALUE_H
+#define QCBORVALUE_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcborcommon.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringview.h>
+#include <QtCore/qurl.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvector.h>
+
+// See qcborcommon.h for why we check
+#if defined(QT_X11_DEFINES_FOUND)
+# undef True
+# undef False
+#endif
+
+#if 0 && QT_HAS_INCLUDE(<compare>)
+# include <compare>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QCborArray;
+class QCborMap;
+class QCborStreamReader;
+class QCborStreamWriter;
+
+struct QCborParserError
+{
+ qint64 offset = 0;
+ QCborError error = {};
+
+ QString errorString() const { return error.toString(); }
+};
+
+class QCborContainerPrivate;
+class Q_CORE_EXPORT QCborValue
+{
+ Q_GADGET
+public:
+ enum EncodingOption {
+ SortKeysInMaps = 0x01,
+ UseFloat = 0x02,
+ UseFloat16 = UseFloat | 0x04,
+ UseIntegers = 0x08,
+
+ NoTransformation = 0
+ };
+ Q_DECLARE_FLAGS(EncodingOptions, EncodingOption)
+
+ enum DiagnosticNotationOption {
+ Compact = 0x00,
+ LineWrapped = 0x01,
+ ExtendedFormat = 0x02
+ };
+ Q_DECLARE_FLAGS(DiagnosticNotationOptions, DiagnosticNotationOption)
+
+ // different from QCborStreamReader::Type because we have more types
+ enum Type : int {
+ Integer = 0x00,
+ ByteArray = 0x40,
+ String = 0x60,
+ Array = 0x80,
+ Map = 0xa0,
+ Tag = 0xc0,
+
+ // range 0x100 - 0x1ff for Simple Types
+ SimpleType = 0x100,
+ False = SimpleType + int(QCborSimpleType::False),
+ True = SimpleType + int(QCborSimpleType::True),
+ Null = SimpleType + int(QCborSimpleType::Null),
+ Undefined = SimpleType + int(QCborSimpleType::Undefined),
+
+ Double = 0x202,
+
+ // extended (tagged) types
+ DateTime = 0x10000,
+ Url = 0x10020,
+ RegularExpression = 0x10023,
+ Uuid = 0x10025,
+
+ Invalid = -1
+ };
+ Q_ENUM(Type)
+
+ QCborValue() {}
+ QCborValue(Type t_) : t(t_) {}
+ QCborValue(std::nullptr_t) : t(Null) {}
+ QCborValue(bool b_) : t(b_ ? True : False) {}
+#ifndef Q_QDOC
+ QCborValue(int i) : QCborValue(qint64(i)) {}
+ QCborValue(unsigned u) : QCborValue(qint64(u)) {}
+#endif
+ QCborValue(qint64 i) : n(i), t(Integer) {}
+ QCborValue(double v) : t(Double) { memcpy(&n, &v, sizeof(n)); }
+ QCborValue(QCborSimpleType st) : t(type_helper(st)) {}
+
+ QCborValue(const QByteArray &ba);
+ QCborValue(const QString &s);
+ QCborValue(QLatin1String s);
+#ifndef QT_NO_CAST_FROM_ASCII
+ QT_ASCII_CAST_WARN QCborValue(const char *s) : QCborValue(QString::fromUtf8(s)) {}
+#endif
+ QCborValue(const QCborArray &a);
+ QCborValue(QCborArray &&a);
+ QCborValue(const QCborMap &m);
+ QCborValue(QCborMap &&m);
+ QCborValue(QCborTag tag, const QCborValue &taggedValue = QCborValue());
+ QCborValue(QCborKnownTags t_, const QCborValue &tv = QCborValue())
+ : QCborValue(QCborTag(t_), tv)
+ {}
+
+ explicit QCborValue(const QDateTime &dt);
+ explicit QCborValue(const QUrl &url);
+ explicit QCborValue(const QRegularExpression &rx);
+ explicit QCborValue(const QUuid &uuid);
+
+ ~QCborValue() { if (container) dispose(); }
+
+ // make sure const char* doesn't go call the bool constructor
+ QCborValue(const void *) = delete;
+
+ QCborValue(const QCborValue &other);
+ QCborValue(QCborValue &&other) noexcept
+ : n(other.n), container(other.container), t(other.t)
+ {
+ other.t = Undefined;
+ other.container = nullptr;
+ }
+ QCborValue &operator=(const QCborValue &other);
+ QCborValue &operator=(QCborValue &&other) noexcept
+ {
+ QCborValue tmp;
+ qSwap(*this, tmp);
+ qSwap(other, *this);
+ return *this;
+ }
+
+ void swap(QCborValue &other) noexcept
+ {
+ qSwap(n, other.n);
+ qSwap(container, other.container);
+ qSwap(t, other.t);
+ }
+
+ Type type() const { return t; }
+ bool isInteger() const { return type() == Integer; }
+ bool isByteArray() const { return type() == ByteArray; }
+ bool isString() const { return type() == String; }
+ bool isArray() const { return type() == Array; }
+ bool isMap() const { return type() == Map; }
+ bool isTag() const { return isTag_helper(type()); }
+ bool isFalse() const { return type() == False; }
+ bool isTrue() const { return type() == True; }
+ bool isBool() const { return isFalse() || isTrue(); }
+ bool isNull() const { return type() == Null; }
+ bool isUndefined() const { return type() == Undefined; }
+ bool isDouble() const { return type() == Double; }
+ bool isDateTime() const { return type() == DateTime; }
+ bool isUrl() const { return type() == Url; }
+ bool isRegularExpression() const { return type() == RegularExpression; }
+ bool isUuid() const { return type() == Uuid; }
+ bool isInvalid() const { return type() == Invalid; }
+ bool isContainer() const { return isMap() || isArray(); }
+
+ bool isSimpleType() const
+ {
+ return int(type()) >> 8 == int(SimpleType) >> 8;
+ }
+ bool isSimpleType(QCborSimpleType st) const
+ {
+ return type() == type_helper(st);
+ }
+ QCborSimpleType toSimpleType(QCborSimpleType defaultValue = QCborSimpleType::Undefined) const
+ {
+ return isSimpleType() ? QCborSimpleType(type() & 0xff) : defaultValue;
+ }
+
+ qint64 toInteger(qint64 defaultValue = 0) const
+ { return isInteger() ? value_helper() : isDouble() ? qint64(fp_helper()) : defaultValue; }
+ bool toBool(bool defaultValue = false) const
+ { return isBool() ? isTrue() : defaultValue; }
+ double toDouble(double defaultValue = 0) const
+ { return isDouble() ? fp_helper() : isInteger() ? double(value_helper()) : defaultValue; }
+
+ QCborTag tag(QCborTag defaultValue = QCborTag(-1)) const;
+ QCborValue taggedValue(const QCborValue &defaultValue = QCborValue()) const;
+
+ QByteArray toByteArray(const QByteArray &defaultValue = {}) const;
+ QString toString(const QString &defaultValue = {}) const;
+ QDateTime toDateTime(const QDateTime &defaultValue = {}) const;
+ QUrl toUrl(const QUrl &defaultValue = {}) const;
+ QRegularExpression toRegularExpression(const QRegularExpression &defaultValue = {}) const;
+ QUuid toUuid(const QUuid &defaultValue = {}) const;
+
+#ifdef Q_QDOC
+ QCborArray toArray(const QCborArray &a = {}) const;
+ QCborMap toMap(const QCborMap &m = {}) const;
+#else
+ // only forward-declared, need split functions
+ QCborArray toArray() const;
+ QCborArray toArray(const QCborArray &defaultValue) const;
+ QCborMap toMap() const;
+ QCborMap toMap(const QCborMap &defaultValue) const;
+#endif
+
+ const QCborValue operator[](const QString &key) const;
+ const QCborValue operator[](QLatin1String key) const;
+ const QCborValue operator[](qint64 key) const;
+
+ int compare(const QCborValue &other) const;
+#if 0 && QT_HAS_INCLUDE(<compare>)
+ std::strong_ordering operator<=>(const QCborValue &other) const
+ {
+ int c = compare(other);
+ if (c > 0) return std::partial_ordering::greater;
+ if (c == 0) return std::partial_ordering::equivalent;
+ return std::partial_ordering::less;
+ }
+#else
+ bool operator==(const QCborValue &other) const noexcept
+ { return compare(other) == 0; }
+ bool operator!=(const QCborValue &other) const noexcept
+ { return !(*this == other); }
+ bool operator<(const QCborValue &other) const
+ { return compare(other) < 0; }
+#endif
+
+ static QCborValue fromVariant(const QVariant &variant);
+ QVariant toVariant() const;
+ static QCborValue fromJsonValue(const QJsonValue &v);
+ QJsonValue toJsonValue() const;
+
+ static QCborValue fromCbor(QCborStreamReader &reader);
+ static QCborValue fromCbor(const QByteArray &ba, QCborParserError *error = nullptr);
+ static QCborValue fromCbor(const char *data, qsizetype len, QCborParserError *error = nullptr)
+ { return fromCbor(QByteArray(data, int(len)), error); }
+ static QCborValue fromCbor(const quint8 *data, qsizetype len, QCborParserError *error = nullptr)
+ { return fromCbor(QByteArray(reinterpret_cast<const char *>(data), int(len)), error); }
+ QByteArray toCbor(EncodingOptions opt = NoTransformation);
+ void toCbor(QCborStreamWriter &writer, EncodingOptions opt = NoTransformation);
+
+ QString toDiagnosticNotation(DiagnosticNotationOptions opts = Compact) const;
+
+private:
+ friend class QCborValueRef;
+ friend class QCborContainerPrivate;
+ qint64 n = 0;
+ QCborContainerPrivate *container = nullptr;
+ Type t = Undefined;
+
+ void dispose();
+ qint64 value_helper() const
+ {
+ return n;
+ }
+
+ double fp_helper() const
+ {
+ Q_STATIC_ASSERT(sizeof(double) == sizeof(n));
+ double d;
+ memcpy(&d, &n, sizeof(d));
+ return d;
+ }
+
+ Q_DECL_CONSTEXPR static Type type_helper(QCborSimpleType st)
+ {
+ return Type(quint8(st) | SimpleType);
+ }
+
+ Q_DECL_CONSTEXPR static bool isTag_helper(Type t)
+ {
+ return t == Tag || t >= 0x10000;
+ }
+};
+Q_DECLARE_SHARED(QCborValue)
+
+class Q_CORE_EXPORT QCborValueRef
+{
+public:
+ operator QCborValue() const { return concrete(); }
+
+ QCborValueRef(const QCborValueRef &) noexcept = default;
+ QCborValueRef(QCborValueRef &&) noexcept = default;
+ QCborValueRef &operator=(const QCborValue &other)
+ { assign(*this, other); return *this; }
+ QCborValueRef &operator=(QCborValue &&other)
+ { assign(*this, std::move(other)); other.container = nullptr; return *this; }
+ QCborValueRef &operator=(const QCborValueRef &other)
+ { assign(*this, other); return *this; }
+
+ QCborValue::Type type() const { return concreteType(); }
+ bool isInteger() const { return type() == QCborValue::Integer; }
+ bool isByteArray() const { return type() == QCborValue::ByteArray; }
+ bool isString() const { return type() == QCborValue::String; }
+ bool isArray() const { return type() == QCborValue::Array; }
+ bool isMap() const { return type() == QCborValue::Map; }
+ bool isTag() const { return QCborValue::isTag_helper(type()); }
+ bool isFalse() const { return type() == QCborValue::False; }
+ bool isTrue() const { return type() == QCborValue::True; }
+ bool isBool() const { return isFalse() || isTrue(); }
+ bool isNull() const { return type() == QCborValue::Null; }
+ bool isUndefined() const { return type() == QCborValue::Undefined; }
+ bool isDouble() const { return type() == QCborValue::Double; }
+ bool isDateTime() const { return type() == QCborValue::DateTime; }
+ bool isUrl() const { return type() == QCborValue::Url; }
+ bool isRegularExpression() const { return type() == QCborValue::RegularExpression; }
+ bool isUuid() const { return type() == QCborValue::Uuid; }
+ bool isInvalid() const { return type() == QCborValue::Invalid; }
+ bool isContainer() const { return isMap() || isArray(); }
+ bool isSimpleType() const
+ {
+ return type() >= QCborValue::SimpleType && type() < QCborValue::SimpleType + 0x100;
+ }
+ bool isSimpleType(QCborSimpleType st) const
+ {
+ return type() == QCborValue::type_helper(st);
+ }
+
+ QCborTag tag(QCborTag defaultValue = QCborTag(-1)) const
+ { return concrete().tag(defaultValue); }
+ QCborValue taggedValue(const QCborValue &defaultValue = QCborValue()) const
+ { return concrete().taggedValue(defaultValue); }
+
+ qint64 toInteger(qint64 defaultValue = 0) const
+ { return concrete().toInteger(defaultValue); }
+ bool toBool(bool defaultValue = false) const
+ { return concrete().toBool(defaultValue); }
+ double toDouble(double defaultValue = 0) const
+ { return concrete().toDouble(defaultValue); }
+
+ QByteArray toByteArray(const QByteArray &defaultValue = {}) const
+ { return concrete().toByteArray(defaultValue); }
+ QString toString(const QString &defaultValue = {}) const
+ { return concrete().toString(defaultValue); }
+ QDateTime toDateTime(const QDateTime &defaultValue = {}) const
+ { return concrete().toDateTime(defaultValue); }
+ QUrl toUrl(const QUrl &defaultValue = {}) const
+ { return concrete().toUrl(defaultValue); }
+ QRegularExpression toRegularExpression(const QRegularExpression &defaultValue = {}) const
+ { return concrete().toRegularExpression(defaultValue); }
+ QUuid toUuid(const QUuid &defaultValue = {}) const
+ { return concrete().toUuid(defaultValue); }
+
+#ifdef Q_QDOC
+ QCborArray toArray(const QCborArray &a = {}) const;
+ QCborMap toMap(const QCborMap &m = {}) const;
+#else
+ // only forward-declared, need split functions. Implemented in qcbor{array,map}.h
+ QCborArray toArray() const;
+ QCborArray toArray(const QCborArray &a) const;
+ QCborMap toMap() const;
+ QCborMap toMap(const QCborMap &m) const;
+#endif
+
+ int compare(const QCborValue &other) const
+ { return concrete().compare(other); }
+#if 0 && QT_HAS_INCLUDE(<compare>)
+ std::strong_ordering operator<=>(const QCborValue &other) const
+ {
+ int c = compare(other);
+ if (c > 0) return std::strong_ordering::greater;
+ if (c == 0) return std::strong_ordering::equivalent;
+ return std::strong_ordering::less;
+ }
+#else
+ bool operator==(const QCborValue &other) const
+ { return compare(other) == 0; }
+ bool operator!=(const QCborValue &other) const
+ { return !(*this == other); }
+ bool operator<(const QCborValue &other) const
+ { return compare(other) < 0; }
+#endif
+
+ QVariant toVariant() const { return concrete().toVariant(); }
+ QJsonValue toJsonValue() const;
+
+ QByteArray toCbor(QCborValue::EncodingOptions opt = QCborValue::NoTransformation)
+ { return concrete().toCbor(opt); }
+ void toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt = QCborValue::NoTransformation);
+
+ QString toDiagnosticNotation(QCborValue::DiagnosticNotationOptions opt = QCborValue::Compact)
+ { return concrete().toDiagnosticNotation(opt); }
+
+private:
+ friend class QCborArray;
+ friend class QCborMap;
+ friend class QCborContainerPrivate;
+ friend class QCborValueRefPtr;
+
+ // static so we can pass this by value
+ static void assign(QCborValueRef that, const QCborValue &other);
+ static void assign(QCborValueRef that, QCborValue &&other);
+ static void assign(QCborValueRef that, const QCborValueRef other);
+ static QCborValue concrete(QCborValueRef that) noexcept;
+ QCborValue concrete() const noexcept { return concrete(*this); }
+
+ static QCborValue::Type concreteType(QCborValueRef self) noexcept Q_DECL_PURE_FUNCTION;
+ QCborValue::Type concreteType() const noexcept { return concreteType(*this); }
+
+ // this will actually be invalid...
+ Q_DECL_CONSTEXPR QCborValueRef() : d(nullptr), i(0) {}
+
+ QCborValueRef(QCborContainerPrivate *dd, qsizetype ii)
+ : d(dd), i(ii)
+ {}
+ QCborContainerPrivate *d;
+ qsizetype i;
+};
+
+Q_CORE_EXPORT uint qHash(const QCborValue &value, uint seed = 0);
+
+#if !defined(QT_NO_DEBUG_STREAM)
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborValue &v);
+#endif
+
+QT_END_NAMESPACE
+
+#if defined(QT_X11_DEFINES_FOUND)
+# define True 1
+# define False 0
+#endif
+
+#endif // QCBORVALUE_H
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
new file mode 100644
index 0000000000..4050d18fa9
--- /dev/null
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -0,0 +1,399 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCBORVALUE_P_H
+#define QCBORVALUE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API.
+// This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qcborvalue.h"
+
+#include <private/qglobal_p.h>
+#include <private/qutfcodec_p.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtCbor {
+struct Undefined {};
+struct Element
+{
+ enum ValueFlag : quint32 {
+ IsContainer = 0x0001,
+ HasByteData = 0x0002,
+ StringIsUtf16 = 0x0004,
+ StringIsAscii = 0x0008
+ };
+ Q_DECLARE_FLAGS(ValueFlags, ValueFlag)
+
+ union {
+ qint64 value;
+ QCborContainerPrivate *container;
+ };
+ QCborValue::Type type;
+ ValueFlags flags = {};
+
+ Element(qint64 v = 0, QCborValue::Type t = QCborValue::Undefined, ValueFlags f = {})
+ : value(v), type(t), flags(f)
+ {}
+
+ Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f = {})
+ : container(d), type(t), flags(f | IsContainer)
+ {}
+
+ double fpvalue() const
+ {
+ double d;
+ memcpy(&d, &value, sizeof(d));
+ return d;
+ }
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
+Q_STATIC_ASSERT(sizeof(Element) == 16);
+
+struct ByteData
+{
+ QByteArray::size_type len;
+
+ const char *byte() const { return reinterpret_cast<const char *>(this + 1); }
+ char *byte() { return reinterpret_cast<char *>(this + 1); }
+ const QChar *utf16() const { return reinterpret_cast<const QChar *>(this + 1); }
+ QChar *utf16() { return reinterpret_cast<QChar *>(this + 1); }
+
+ QByteArray toByteArray() const { return QByteArray(byte(), len); }
+ QString toString() const { return QString(utf16(), len / 2); }
+ QString toUtf8String() const { return QString::fromUtf8(byte(), len); }
+
+ QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), len); }
+ QLatin1String asLatin1() const { return QLatin1String(byte(), len); }
+ QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
+ QString asQStringRaw() const { return QString::fromRawData(utf16(), len / 2); }
+};
+Q_STATIC_ASSERT(std::is_pod<ByteData>::value);
+} // namespace QtCbor
+
+Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);
+
+class QCborContainerPrivate : public QSharedData
+{
+ friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
+ ~QCborContainerPrivate();
+
+public:
+ enum ContainerDisposition { CopyContainer, MoveContainer };
+
+ QByteArray::size_type usedData = 0;
+ QByteArray data;
+ QVector<QtCbor::Element> elements;
+
+ void deref() { if (!ref.deref()) delete this; }
+ void compact(qsizetype reserved);
+ static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
+ static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
+ static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
+
+ qptrdiff addByteData(const char *block, qsizetype len)
+ {
+ // This function does not do overflow checking, since the len parameter
+ // is expected to be trusted. There's another version of this function
+ // in decodeStringFromCbor(), which checks.
+
+ qptrdiff offset = data.size();
+
+ // align offset
+ offset += Q_ALIGNOF(QtCbor::ByteData) - 1;
+ offset &= ~(Q_ALIGNOF(QtCbor::ByteData) - 1);
+
+ qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
+
+ usedData += increment;
+ data.resize(offset + increment);
+
+ char *ptr = data.begin() + offset;
+ auto b = new (ptr) QtCbor::ByteData;
+ b->len = len;
+ if (block)
+ memcpy(b->byte(), block, len);
+
+ return offset;
+ }
+
+ const QtCbor::ByteData *byteData(QtCbor::Element e) const
+ {
+ if ((e.flags & QtCbor::Element::HasByteData) == 0)
+ return nullptr;
+
+ size_t offset = size_t(e.value);
+ Q_ASSERT((offset % Q_ALIGNOF(QtCbor::ByteData)) == 0);
+ Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
+
+ auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
+ Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
+ return b;
+ }
+ const QtCbor::ByteData *byteData(qsizetype idx) const
+ {
+ return byteData(elements.at(idx));
+ }
+
+ QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
+ {
+ const QtCbor::Element &e = elements.at(idx);
+ if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
+ return nullptr;
+ return e.container;
+ }
+
+ void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
+ void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
+ {
+ if (value.container)
+ return replaceAt_complex(e, value, disp);
+
+ e.value = value.value_helper();
+ e.type = value.type();
+ if (value.isContainer())
+ e.container = nullptr;
+ }
+ void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
+ {
+ QtCbor::Element &e = elements[idx];
+ if (e.flags & QtCbor::Element::IsContainer) {
+ e.container->deref();
+ e.container = nullptr;
+ e.flags = {};
+ } else if (auto b = byteData(e)) {
+ usedData -= b->len + sizeof(QtCbor::ByteData);
+ }
+ replaceAt_internal(e, value, disp);
+ }
+ void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
+ {
+ replaceAt_internal(*elements.insert(elements.begin() + idx, {}), value, disp);
+ }
+
+ void append(QtCbor::Undefined)
+ {
+ elements.append(QtCbor::Element());
+ }
+ void append(qint64 value)
+ {
+ elements.append(QtCbor::Element(value , QCborValue::Integer));
+ }
+ void append(QCborTag tag)
+ {
+ elements.append(QtCbor::Element(qint64(tag), QCborValue::Tag));
+ }
+ void appendByteData(const char *data, qsizetype len, QCborValue::Type type,
+ QtCbor::Element::ValueFlags extraFlags = {})
+ {
+ elements.append(QtCbor::Element(addByteData(data, len), type,
+ QtCbor::Element::HasByteData | extraFlags));
+ }
+ void append(QLatin1String s)
+ {
+ if (!QtPrivate::isAscii(s))
+ return append(QString(s));
+
+ // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
+ appendByteData(s.latin1(), s.size(), QCborValue::String,
+ QtCbor::Element::StringIsAscii);
+ }
+ void appendAsciiString(const QString &s);
+ void append(const QString &s)
+ {
+ if (QtPrivate::isAscii(s))
+ appendAsciiString(s);
+ else
+ appendByteData(reinterpret_cast<const char *>(s.constData()), s.size() * 2,
+ QCborValue::String, QtCbor::Element::StringIsUtf16);
+ }
+ void append(const QCborValue &v)
+ {
+ insertAt(elements.size(), v);
+ }
+
+ QByteArray byteArrayAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+ const auto data = byteData(e);
+ if (!data)
+ return QByteArray();
+ return data->toByteArray();
+ }
+ QString stringAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+ const auto data = byteData(e);
+ if (!data)
+ return QString();
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return data->toString();
+ if (e.flags & QtCbor::Element::StringIsAscii)
+ return data->asLatin1();
+ return data->toUtf8String();
+ }
+
+ static void resetValue(QCborValue &v)
+ {
+ v.container = nullptr;
+ }
+
+ static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
+ ContainerDisposition disp = CopyContainer)
+ {
+ QCborValue result(type);
+ result.n = n;
+ result.container = d;
+ if (d && disp == CopyContainer)
+ d->ref.ref();
+ return result;
+ }
+
+ QCborValue valueAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+
+ if (e.flags & QtCbor::Element::IsContainer) {
+ if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
+ // invalid tags can be created due to incomplete parsing
+ return makeValue(QCborValue::Invalid, 0, nullptr);
+ }
+ return makeValue(e.type, -1, e.container);
+ } else if (e.flags & QtCbor::Element::HasByteData) {
+ return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
+ }
+ return makeValue(e.type, e.value);
+ }
+ QCborValue extractAt_complex(QtCbor::Element e);
+ QCborValue extractAt(qsizetype idx)
+ {
+ QtCbor::Element e;
+ qSwap(e, elements[idx]);
+
+ if (e.flags & QtCbor::Element::IsContainer) {
+ if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
+ // invalid tags can be created due to incomplete parsing
+ e.container->deref();
+ return makeValue(QCborValue::Invalid, 0, nullptr);
+ }
+ return makeValue(e.type, -1, e.container, MoveContainer);
+ } else if (e.flags & QtCbor::Element::HasByteData) {
+ return extractAt_complex(e);
+ }
+ return makeValue(e.type, e.value);
+ }
+
+ static QtCbor::Element elementFromValue(const QCborValue &value)
+ {
+ if (value.n >= 0 && value.container)
+ return value.container->elements.at(value.n);
+
+ QtCbor::Element e;
+ e.value = value.n;
+ e.type = value.t;
+ if (value.container) {
+ e.container = value.container;
+ e.flags = QtCbor::Element::IsContainer;
+ }
+ return e;
+ }
+
+ bool stringEqualsElement(qsizetype idx, QLatin1String s) const
+ {
+ const auto &e = elements.at(idx);
+ if (e.type != QCborValue::String)
+ return false;
+
+ const QtCbor::ByteData *b = byteData(idx);
+ if (!b)
+ return s.isEmpty();
+
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return QtPrivate::compareStrings(b->asStringView(), s) == 0;
+ return QUtf8::compareUtf8(b->byte(), b->len, s) == 0;
+ }
+ bool stringEqualsElement(qsizetype idx, const QString &s) const
+ {
+ const auto &e = elements.at(idx);
+ if (e.type != QCborValue::String)
+ return false;
+
+ const QtCbor::ByteData *b = byteData(idx);
+ if (!b)
+ return s.isEmpty();
+
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return QtPrivate::compareStrings(b->asStringView(), s) == 0;
+ return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()) == 0;
+ }
+
+ static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
+ const QCborContainerPrivate *c2, QtCbor::Element e2);
+ int compareElement(qsizetype idx, const QCborValue &value) const
+ {
+ auto &e1 = elements.at(idx);
+ auto e2 = elementFromValue(value);
+ return compareElement_helper(this, e1, value.container, e2);
+ }
+
+ void removeAt(qsizetype idx)
+ {
+ replaceAt(idx, {});
+ elements.remove(idx);
+ }
+
+ void decodeValueFromCbor(QCborStreamReader &reader);
+ void decodeFromCbor(QCborStreamReader &reader);
+ void decodeStringFromCbor(QCborStreamReader &reader);
+};
+
+QT_END_NAMESPACE
+
+#endif // QCBORVALUE_P_H
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index 09e98cb2b4..951f6c9736 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -170,18 +170,12 @@ QT_BEGIN_NAMESPACE
will have appropriate stream operators declared as non-member of
the class:
- \code
- QDataStream &operator<<(QDataStream &, const QXxx &);
- QDataStream &operator>>(QDataStream &, QXxx &);
- \endcode
+ \snippet code/src_corelib_serialization_qdatastream.cpp 0
For example, here are the stream operators declared as non-members
of the QImage class:
- \code
- QDataStream & operator<< (QDataStream& stream, const QImage& image);
- QDataStream & operator>> (QDataStream& stream, QImage& image);
- \endcode
+ \snippet code/src_corelib_serialization_qdatastream.cpp 1
To see if your favorite Qt class has similar stream operators
defined, check the \b {Related Non-Members} section of the
@@ -564,6 +558,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_9 Same as Qt_5_6
\value Qt_5_10 Same as Qt_5_6
\value Qt_5_11 Same as Qt_5_6
+ \value Qt_5_12 Version 18 (Qt 5.12)
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 1775022355..eae0146553 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -98,10 +98,11 @@ public:
Qt_5_9 = Qt_5_8,
Qt_5_10 = Qt_5_9,
Qt_5_11 = Qt_5_10,
-#if QT_VERSION >= 0x050c00
+ Qt_5_12 = 18,
+#if QT_VERSION >= 0x050d00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_11
+ Qt_DefaultCompiledVersion = Qt_5_12
};
enum ByteOrder {
diff --git a/src/corelib/serialization/qjson.cpp b/src/corelib/serialization/qjson.cpp
index b82923fe0c..d74ffb2a20 100644
--- a/src/corelib/serialization/qjson.cpp
+++ b/src/corelib/serialization/qjson.cpp
@@ -70,6 +70,7 @@ void Data::compact()
int size = sizeof(Base) + reserve + base->length*sizeof(offset);
int alloc = sizeof(Header) + size;
Header *h = (Header *) malloc(alloc);
+ Q_CHECK_PTR(h);
h->tag = QJsonDocument::BinaryFormatTag;
h->version = 1;
Base *b = h->root();
diff --git a/src/corelib/serialization/qjson_p.h b/src/corelib/serialization/qjson_p.h
index dc56a49084..feba1faac6 100644
--- a/src/corelib/serialization/qjson_p.h
+++ b/src/corelib/serialization/qjson_p.h
@@ -69,6 +69,9 @@
QT_BEGIN_NAMESPACE
+// in qstring.cpp
+void qt_to_latin1_unchecked(uchar *dst, const ushort *uc, qsizetype len);
+
/*
This defines a binary data structure for Json data. The data structure is optimised for fast reading
and minimum allocations. The whole data structure can be mmap'ed and used directly.
@@ -294,31 +297,10 @@ public:
int len = d->length = str.length();
uchar *l = (uchar *)d->latin1;
const ushort *uc = (const ushort *)str.unicode();
- int i = 0;
-#ifdef __SSE2__
- for ( ; i + 16 <= len; i += 16) {
- __m128i chunk1 = _mm_loadu_si128((__m128i*)&uc[i]); // load
- __m128i chunk2 = _mm_loadu_si128((__m128i*)&uc[i + 8]); // load
- // pack the two vector to 16 x 8bits elements
- const __m128i result = _mm_packus_epi16(chunk1, chunk2);
- _mm_storeu_si128((__m128i*)&l[i], result); // store
- }
-# ifdef Q_PROCESSOR_X86_64
- // we can do one more round, of 8 characters
- if (i + 8 <= len) {
- __m128i chunk = _mm_loadu_si128((__m128i*)&uc[i]); // load
- // pack with itself, we'll discard the high part anyway
- chunk = _mm_packus_epi16(chunk, chunk);
- // unaligned 64-bit store
- qToUnaligned(_mm_cvtsi128_si64(chunk), l + i);
- i += 8;
- }
-# endif
-#endif
- for ( ; i < len; ++i)
- l[i] = uc[i];
- for ( ; (quintptr)(l+i) & 0x3; ++i)
- l[i] = 0;
+ qt_to_latin1_unchecked(l, uc, len);
+
+ for ( ; (quintptr)(l+len) & 0x3; ++len)
+ l[len] = 0;
return *this;
}
diff --git a/src/corelib/serialization/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp
index 8ee9ce0de7..1187bb03a3 100644
--- a/src/corelib/serialization/qjsonarray.cpp
+++ b/src/corelib/serialization/qjsonarray.cpp
@@ -1237,6 +1237,10 @@ void QJsonArray::compact()
a = static_cast<QJsonPrivate::Array *>(d->header->root());
}
+uint qHash(const QJsonArray &array, uint seed)
+{
+ return qHashRange(array.begin(), array.end(), seed);
+}
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
QDebug operator<<(QDebug dbg, const QJsonArray &a)
diff --git a/src/corelib/serialization/qjsonarray.h b/src/corelib/serialization/qjsonarray.h
index 8d41138c97..5dff4a0aa9 100644
--- a/src/corelib/serialization/qjsonarray.h
+++ b/src/corelib/serialization/qjsonarray.h
@@ -265,6 +265,8 @@ private:
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonArray)
+Q_CORE_EXPORT uint qHash(const QJsonArray &array, uint seed = 0);
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
#endif
diff --git a/src/corelib/serialization/qjsoncbor.cpp b/src/corelib/serialization/qjsoncbor.cpp
new file mode 100644
index 0000000000..158f1950d0
--- /dev/null
+++ b/src/corelib/serialization/qjsoncbor.cpp
@@ -0,0 +1,954 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcborvalue.h"
+#include "qcborvalue_p.h"
+
+#include "qcborarray.h"
+#include "qcbormap.h"
+#include "qjson_p.h"
+
+#include <private/qnumeric_p.h>
+#include <quuid.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtCbor;
+
+static QJsonValue fpToJson(double v)
+{
+ return qt_is_finite(v) ? QJsonValue(v) : QJsonValue();
+}
+
+static QString simpleTypeString(QCborValue::Type t)
+{
+ int simpleType = t - QCborValue::SimpleType;
+ if (unsigned(simpleType) < 0x100)
+ return QString::fromLatin1("simple(%1)").arg(simpleType);
+
+ // if we got here, we got an unknown type
+ qWarning("QCborValue: found unknown type 0x%x", t);
+ return QString();
+
+}
+
+static QString encodeByteArray(const QCborContainerPrivate *d, qsizetype idx, QCborTag encoding)
+{
+ const ByteData *b = d->byteData(idx);
+ if (!b)
+ return QString();
+
+ QByteArray data = QByteArray::fromRawData(b->byte(), b->len);
+ if (encoding == QCborKnownTags::ExpectedBase16)
+ data = data.toHex();
+ else if (encoding == QCborKnownTags::ExpectedBase64)
+ data = data.toBase64();
+ else
+ data = data.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
+
+ return QString::fromLatin1(data, data.size());
+}
+
+static QString makeString(const QCborContainerPrivate *d, qsizetype idx);
+
+static QString maybeEncodeTag(const QCborContainerPrivate *d)
+{
+ qint64 tag = d->elements.at(0).value;
+ const Element &e = d->elements.at(1);
+ const ByteData *b = d->byteData(e);
+
+ switch (tag) {
+ case qint64(QCborKnownTags::DateTimeString):
+ case qint64(QCborKnownTags::Url):
+ if (e.type == QCborValue::String)
+ return makeString(d, 1);
+ break;
+
+ case qint64(QCborKnownTags::ExpectedBase64url):
+ case qint64(QCborKnownTags::ExpectedBase64):
+ case qint64(QCborKnownTags::ExpectedBase16):
+ if (e.type == QCborValue::ByteArray)
+ return encodeByteArray(d, 1, QCborTag(tag));
+ break;
+
+ case qint64(QCborKnownTags::Uuid):
+ if (e.type == QCborValue::ByteArray && b->len == sizeof(QUuid))
+ return QUuid::fromRfc4122(b->asByteArrayView()).toString(QUuid::WithoutBraces);
+ }
+
+ // don't know what to do, bail out
+ return QString();
+}
+
+static QString encodeTag(const QCborContainerPrivate *d)
+{
+ QString s;
+ if (!d || d->elements.size() != 2)
+ return s; // invalid (incomplete?) tag state
+
+ s = maybeEncodeTag(d);
+ if (s.isNull()) {
+ // conversion failed, ignore the tag and convert the tagged value
+ s = makeString(d, 1);
+ }
+ return s;
+}
+
+static Q_NEVER_INLINE QString makeString(const QCborContainerPrivate *d, qsizetype idx)
+{
+ const auto &e = d->elements.at(idx);
+
+ switch (e.type) {
+ case QCborValue::Integer:
+ return QString::number(qint64(e.value));
+
+ case QCborValue::Double:
+ return QString::number(e.fpvalue());
+
+ case QCborValue::ByteArray:
+ return encodeByteArray(d, idx, QCborTag(QCborKnownTags::ExpectedBase64url));
+
+ case QCborValue::String:
+ return d->stringAt(idx);
+
+ case QCborValue::Array:
+ case QCborValue::Map:
+ return d->valueAt(idx).toDiagnosticNotation(QCborValue::Compact);
+
+ case QCborValue::SimpleType:
+ break;
+
+ case QCborValue::False:
+ return QStringLiteral("false");
+
+ case QCborValue::True:
+ return QStringLiteral("true");
+
+ case QCborValue::Null:
+ return QStringLiteral("null");
+
+ case QCborValue::Undefined:
+ return QStringLiteral("undefined");
+
+ case QCborValue::Invalid:
+ return QString();
+
+ case QCborValue::Tag:
+ case QCborValue::DateTime:
+ case QCborValue::Url:
+ case QCborValue::RegularExpression:
+ case QCborValue::Uuid:
+ return encodeTag(e.flags & Element::IsContainer ? e.container : nullptr);
+ }
+
+ // maybe it's a simple type
+ return simpleTypeString(e.type);
+}
+
+static QJsonValue convertToJson(const QCborContainerPrivate *d, qsizetype idx);
+
+static QJsonArray convertToJsonArray(const QCborContainerPrivate *d)
+{
+ QJsonArray a;
+ if (d) {
+ for (qsizetype idx = 0; idx < d->elements.size(); ++idx)
+ a.append(convertToJson(d, idx));
+ }
+ return a;
+}
+
+static QJsonObject convertToJsonObject(const QCborContainerPrivate *d)
+{
+ QJsonObject o;
+ if (d) {
+ for (qsizetype idx = 0; idx < d->elements.size(); idx += 2)
+ o.insert(makeString(d, idx), convertToJson(d, idx + 1));
+ }
+ return o;
+}
+
+static QJsonValue convertExtendedTypeToJson(const QCborContainerPrivate *d)
+{
+ qint64 tag = d->elements.at(0).value;
+
+ switch (tag) {
+ case qint64(QCborKnownTags::Url):
+ // use the fullly-encoded URL form
+ if (d->elements.at(1).type == QCborValue::String)
+ return QUrl::fromEncoded(d->byteData(1)->asByteArrayView()).toString(QUrl::FullyEncoded);
+ Q_FALLTHROUGH();
+
+ case qint64(QCborKnownTags::DateTimeString):
+ case qint64(QCborKnownTags::ExpectedBase64url):
+ case qint64(QCborKnownTags::ExpectedBase64):
+ case qint64(QCborKnownTags::ExpectedBase16):
+ case qint64(QCborKnownTags::Uuid): {
+ // use the string conversion
+ QString s = maybeEncodeTag(d);
+ if (!s.isNull())
+ return s;
+ }
+ }
+
+ // for all other tags, ignore it and return the converted tagged item
+ return convertToJson(d, 1);
+}
+
+static QJsonValue convertToJson(const QCborContainerPrivate *d, qsizetype idx)
+{
+ // encoding the container itself
+ if (idx == -QCborValue::Array)
+ return convertToJsonArray(d);
+ if (idx == -QCborValue::Map)
+ return convertToJsonObject(d);
+ if (idx < 0) {
+ // tag-like type
+ if (!d || d->elements.size() != 2)
+ return QJsonValue::Undefined; // invalid state
+ return convertExtendedTypeToJson(d);
+ }
+
+ // an element in the container
+ const auto &e = d->elements.at(idx);
+ switch (e.type) {
+ case QCborValue::Integer:
+ return qint64(e.value);
+
+ case QCborValue::ByteArray:
+ case QCborValue::String:
+ case QCborValue::SimpleType:
+ // make string
+ break;
+
+ case QCborValue::Array:
+ case QCborValue::Map:
+ case QCborValue::Tag:
+ case QCborValue::DateTime:
+ case QCborValue::Url:
+ case QCborValue::RegularExpression:
+ case QCborValue::Uuid:
+ // recurse
+ return convertToJson(e.flags & Element::IsContainer ? e.container : nullptr, -e.type);
+
+ case QCborValue::Null:
+ return QJsonValue();
+
+ case QCborValue::Undefined:
+ case QCborValue::Invalid:
+ return QJsonValue(QJsonValue::Undefined);
+
+ case QCborValue::False:
+ return false;
+
+ case QCborValue::True:
+ return true;
+
+ case QCborValue::Double:
+ return fpToJson(e.fpvalue());
+ }
+
+ return makeString(d, idx);
+}
+
+/*!
+ Converts this QCborValue object to an equivalent representation in JSON and
+ returns it as a QJsonValue.
+
+ Please note that CBOR contains a richer and wider type set than JSON, so
+ some information may be lost in this conversion. The following table
+ compares CBOR types to JSON types and indicates whether information may be
+ lost or not.
+
+ \table
+ \header \li CBOR Type \li JSON Type \li Comments
+ \row \li Bool \li Bool \li No data loss possible
+ \row \li Double \li Number \li Infinities and NaN will be converted to Null;
+ no data loss for other values
+ \row \li Integer \li Number \li Data loss possible in the conversion if the
+ integer is larger than 2\sup{53} or smaller
+ than -2\sup{53}.
+ \row \li Null \li Null \li No data loss possible
+ \row \li Undefined \li Null \li Type information lost
+ \row \li String \li String \li No data loss possible
+ \row \li Byte Array \li String \li Converted to a lossless encoding like Base64url,
+ but the distinction between strings and byte
+ arrays is lost
+ \row \li Other simple types \li String \li Type information lost
+ \row \li Array \li Array \li Conversion applies to each contained value
+ \row \li Map \li Object \li Keys are converted to string; values converted
+ according to this table
+ \row \li Tags and extended types \li Special \li The tag number itself is lost and the tagged
+ value is converted to JSON
+ \endtable
+
+ For information on the conversion of CBOR map keys to string, see
+ QCborMap::toJsonObject().
+
+ If this QCborValue contains the undefined value, this function will return
+ an undefined QJsonValue too. Note that JSON does not support undefined
+ values and undefined QJsonValues are an extension to the specification.
+ They cannot be held in a QJsonArray or QJsonObject, but can be returned
+ from functions to indicate a failure. For all other intents and purposes,
+ they are the same as null.
+
+ \section3 Special handling of tags and extended types
+
+ Some tags are handled specially and change the transformation of the tagged
+ value from CBOR to JSON. The following table lists those special cases:
+
+ \table
+ \header \li Tag \li CBOR type \li Transformation
+ \row \li ExpectedBase64url \li Byte array \li Encodes the byte array as Base64url
+ \row \li ExpectedBase64 \li Byte array \li Encodes the byte array as Base64
+ \row \li ExpectedBase16 \li Byte array \li Encodes the byte array as hex
+ \row \li Url \li Url and String \li Uses QUrl::toEncoded() to normalize the
+ encoding to the URL's fully encoded format
+ \row \li Uuid \li Uuid and Byte array \li Uses QUuid::toString() to create
+ the string representation
+ \endtable
+
+ \sa fromJsonValue(), toVariant(), QCborArray::toJsonArray(), QCborMap::toJsonObject()
+ */
+QJsonValue QCborValue::toJsonValue() const
+{
+ if (container)
+ return convertToJson(container, n < 0 ? -type() : n);
+
+ // simple values
+ switch (type()) {
+ case Integer:
+ return n;
+
+ case Null:
+ return QJsonValue();
+
+ case False:
+ return false;
+
+ case True:
+ return true;
+
+ case Double:
+ return fpToJson(fp_helper());
+
+ case SimpleType:
+ break;
+
+ case Undefined:
+ case Invalid:
+ return QJsonValue(QJsonValue::Undefined);
+
+ case ByteArray:
+ case String:
+ // empty strings
+ return QString();
+
+ case Array:
+ // empty array
+ return QJsonArray();
+
+ case Map:
+ // empty map
+ return QJsonObject();
+
+ case Tag:
+ case DateTime:
+ case Url:
+ case RegularExpression:
+ case Uuid:
+ Q_UNREACHABLE();
+ return QJsonValue::Undefined;
+ }
+
+ return simpleTypeString(type());
+}
+
+QJsonValue QCborValueRef::toJsonValue() const
+{
+ return convertToJson(d, i);
+}
+
+/*!
+ Recursively converts every \l QCborValue element in this array to JSON
+ using QCborValue::toJsonValue() and returns the corresponding QJsonArray
+ composed of those elements.
+
+ Please note that CBOR contains a richer and wider type set than JSON, so
+ some information may be lost in this conversion. For more details on what
+ conversions are applied, see QCborValue::toJsonValue().
+
+ \sa fromJsonArray(), QCborValue::toJsonValue(), QCborMap::toJsonObject(), toVariantList()
+ */
+QJsonArray QCborArray::toJsonArray() const
+{
+ return convertToJsonArray(d.data());
+}
+
+/*!
+ Recursively converts every \l QCborValue value in this array to JSON using
+ QCborValue::toJsonValue() and creates a string key for all keys that aren't
+ strings, then returns the corresponding QJsonObject composed of those
+ associations.
+
+ Please note that CBOR contains a richer and wider type set than JSON, so
+ some information may be lost in this conversion. For more details on what
+ conversions are applied, see QCborValue::toJsonValue().
+
+ \section3 Map key conversion to string
+
+ JSON objects are defined as having string keys, unlike CBOR, so the
+ conversion of a QCborMap to QJsonObject will imply a step of
+ "stringification" of the key values. The conversion will use the special
+ handling of tags and extended types from above and will also convert the
+ rest of the types as follows:
+
+ \table
+ \header \li Type \li Transformation
+ \row \li Bool \li "true" and "false"
+ \row \li Null \li "null"
+ \row \li Undefined \li "undefined"
+ \row \li Integer \li The decimal string form of the number
+ \row \li Double \li The decimal string form of the number
+ \row \li Byte array \li Unless tagged differently (see above), encoded as
+ Base64url
+ \row \li Array \li Replaced by the compact form of its
+ \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
+ \row \li Map \li Replaced by the compact form of its
+ \l{QCborValue::toDiagnosticNotation()}{Diagnostic notation}
+ \row \li Tags and extended types \li Tag number is dropped and the tagged value is converted
+ to string
+ \endtable
+
+ \sa fromJsonObject(), QCborValue::toJsonValue(), QCborArray::toJsonArray(), toVariantMap()
+ */
+QJsonObject QCborMap::toJsonObject() const
+{
+ return convertToJsonObject(d.data());
+}
+
+/*!
+ Converts this value to a native Qt type and returns the corresponding QVariant.
+
+ The following table lists the mapping performed between \l{Type}{QCborValue
+ types} and \l{QMetaType::Type}{Qt meta types}.
+
+ \table
+ \header \li CBOR Type \li Qt or C++ type \li Notes
+ \row \li Integer \li \l qint64 \li
+ \row \li Double \li \c double \li
+ \row \li Bool \li \c bool \li
+ \row \li Null \li \c std::nullptr_t \li
+ \row \li Undefined \li no type (QVariant()) \li
+ \row \li Byte array \li \l QByteArray \li
+ \row \li String \li \l QString \li
+ \row \li Array \li \l QVariantList \li Recursively converts all values
+ \row \li Map \li \l QVariantMap \li Key types are "stringified"
+ \row \li Other simple types \li \l QCborSimpleType \li
+ \row \li DateTime \li \l QDateTime \li
+ \row \li Url \li \l QUrl \li
+ \row \li RegularExpression \li \l QRegularExpression \li
+ \row \li Uuid \li \l QUuid \li
+ \row \li Other tags \li Special \li The tag is ignored and the tagged
+ value is converted using this
+ function
+ \endtable
+
+ Note that values in both CBOR Maps and Arrays are converted recursively
+ using this function too and placed in QVariantMap and QVariantList instead.
+ You will not find QCborMap and QCborArray stored inside the QVariants.
+
+ QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
+ to QVariantMap will imply a step of "stringification" of the key values.
+ See QCborMap::toJsonObject() for details.
+
+ \sa fromVariant(), toJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap()
+ */
+QVariant QCborValue::toVariant() const
+{
+ switch (type()) {
+ case Integer:
+ return toInteger();
+
+ case Double:
+ return toDouble();
+
+ case SimpleType:
+ break;
+
+ case False:
+ case True:
+ return isTrue();
+
+ case Null:
+ return QVariant::fromValue(nullptr);
+
+ case Undefined:
+ return QVariant();
+
+ case ByteArray:
+ return toByteArray();
+
+ case String:
+ return toString();
+
+ case Array:
+ return toArray().toVariantList();
+
+ case Map:
+ return toMap().toVariantMap();
+
+ case Tag:
+ // ignore tags
+ return taggedValue().toVariant();
+
+ case DateTime:
+ return toDateTime();
+
+ case Url:
+ return toUrl();
+
+ case RegularExpression:
+ return toRegularExpression();
+
+ case Uuid:
+ return toUuid();
+
+ case Invalid:
+ return QVariant();
+ }
+
+ if (isSimpleType())
+ return QVariant::fromValue(toSimpleType());
+
+ Q_UNREACHABLE();
+ return QVariant();
+}
+
+/*!
+ Converts the JSON value contained in \a v into its corresponding CBOR value
+ and returns it. There is no data loss in converting from JSON to CBOR, as
+ the CBOR type set is richer than JSON's. Additionally, values converted to
+ CBOR using this function can be converted back to JSON using toJsonValue()
+ with no data loss.
+
+ The following table lists the mapping of JSON types to CBOR types:
+
+ \table
+ \header \li JSON Type \li CBOR Type
+ \row \li Bool \li Bool
+ \row \li Number \li Integer (if the number has no fraction and is in the \l qint64
+ range) or Double
+ \row \li String \li String
+ \row \li Array \li Array
+ \row \li Object \li Map
+ \row \li Null \li Null
+ \endtable
+
+ \l QJsonValue can also be undefined, indicating a previous operation that
+ failed to complete (for example, searching for a key not present in an
+ object). Undefined values are not JSON types and may not appear in JSON
+ arrays and objects, but this function does return the QCborValue undefined
+ value if the corresponding QJsonValue is undefined.
+
+ \sa toJsonValue(), fromVariant(), QCborArray::fromJsonArray(), QCborMap::fromJsonObject()
+ */
+QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
+{
+ switch (v.type()) {
+ case QJsonValue::Bool:
+ return v.b;
+ case QJsonValue::Double:
+ if (v.dbl == qint64(v.dbl))
+ return qint64(v.dbl);
+ return v.dbl;
+ case QJsonValue::String:
+ return v.toString();
+ case QJsonValue::Array:
+ return QCborArray::fromJsonArray(v.toArray());
+ case QJsonValue::Object:
+ return QCborMap::fromJsonObject(v.toObject());
+ case QJsonValue::Null:
+ return nullptr;
+ case QJsonValue::Undefined:
+ break;
+ }
+ return QCborValue();
+}
+
+static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
+{
+ // Handle strings and byte arrays directly, to avoid creating a temporary
+ // dummy container to hold their data.
+ int type = variant.userType();
+ if (type == QVariant::String) {
+ d->append(variant.toString());
+ } else if (type == QVariant::ByteArray) {
+ QByteArray ba = variant.toByteArray();
+ d->appendByteData(ba.constData(), ba.size(), QCborValue::ByteArray);
+ } else {
+ // For everything else, use the function below.
+ d->append(QCborValue::fromVariant(variant));
+ }
+}
+
+/*!
+ Converts the QVariant \a variant into QCborValue and returns it.
+
+ QVariants may contain a large list of different meta types, many of which
+ have no corresponding representation in CBOR. That includes all
+ user-defined meta types. When preparing transmission using CBOR, it is
+ suggested to encode carefully each value to prevent loss of representation.
+
+ The following table lists the conversion this function will apply:
+
+ \table
+ \header \li Qt (C++) type \li CBOR type
+ \row \li invalid (QVariant()) \li Undefined
+ \row \li \c bool \li Bool
+ \row \li \c std::nullptr_t \li Null
+ \row \li \c short, \c ushort, \c int, \c uint, \l qint64 \li Integer
+ \row \li \l quint64 \li Integer, but they are cast to \c qint64 first so
+ values higher than 2\sup{63}-1 (\c INT64_MAX) will
+ be wrapped to negative
+ \row \li \c float, \c double \li Double
+ \row \li \l QByteArray \li ByteArray
+ \row \li \l QDateTime \li DateTime
+ \row \li \l QCborSimpleType \li Simple type
+ \row \li \l QJsonArray \li Array, converted using QCborArray::formJsonArray()
+ \row \li \l QJsonDocument \li Array or Map
+ \row \li \l QJsonObject \li Map, converted using QCborMap::fromJsonObject()
+ \row \li \l QJsonValue \li converted using fromJsonValue()
+ \row \li \l QRegularExpression \li RegularExpression
+ \row \li \l QString \li String
+ \row \li \l QStringList \li Array
+ \row \li \l QVariantHash \li Map
+ \row \li \l QVariantList \li Array
+ \row \li \l QVariantMap \li Map
+ \row \li \l QUrl \li Url
+ \row \li \l QUuid \li Uuid
+ \endtable
+
+ For any other types, this function will return Null if the QVariant itself
+ is null, and otherwise will try to convert to string using
+ QVariant::toString(). If the conversion to string fails, this function
+ returns Undefined.
+
+ Please note that the conversions via QVariant::toString() are subject to
+ change at any time. QCborValue may be extended in the future to support
+ more types, which will result in a change in how this function performs
+ conversions.
+
+ \sa toVariant(), fromJsonValue(), QCborArray::toVariantList(), QCborMap::toVariantMap()
+ */
+QCborValue QCborValue::fromVariant(const QVariant &variant)
+{
+ switch (variant.userType()) {
+ case QVariant::Invalid:
+ return {};
+ case QMetaType::Nullptr:
+ return nullptr;
+ case QVariant::Bool:
+ return variant.toBool();
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QVariant::Int:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::UInt:
+ return variant.toLongLong();
+ case QMetaType::Float:
+ case QVariant::Double:
+ return variant.toDouble();
+ case QVariant::String:
+ return variant.toString();
+ case QVariant::StringList:
+ return QCborArray::fromStringList(variant.toStringList());
+ case QVariant::ByteArray:
+ return variant.toByteArray();
+ case QVariant::DateTime:
+ return QCborValue(variant.toDateTime());
+ case QVariant::Url:
+ return QCborValue(variant.toUrl());
+ case QVariant::Uuid:
+ return QCborValue(variant.toUuid());
+ case QVariant::List:
+ return QCborArray::fromVariantList(variant.toList());
+ case QVariant::Map:
+ return QCborMap::fromVariantMap(variant.toMap());
+ case QVariant::Hash:
+ return QCborMap::fromVariantHash(variant.toHash());
+#ifndef QT_BOOTSTRAPPED
+ case QVariant::RegularExpression:
+ return QCborValue(variant.toRegularExpression());
+ case QMetaType::QJsonValue:
+ return fromJsonValue(variant.toJsonValue());
+ case QMetaType::QJsonObject:
+ return QCborMap::fromJsonObject(variant.toJsonObject());
+ case QMetaType::QJsonArray:
+ return QCborArray::fromJsonArray(variant.toJsonArray());
+ case QMetaType::QJsonDocument: {
+ QJsonDocument doc = variant.toJsonDocument();
+ if (doc.isArray())
+ return QCborArray::fromJsonArray(doc.array());
+ return QCborMap::fromJsonObject(doc.object());
+ }
+ case QMetaType::QCborValue:
+ return variant.value<QCborValue>();
+ case QMetaType::QCborArray:
+ return variant.value<QCborArray>();
+ case QMetaType::QCborMap:
+ return variant.value<QCborMap>();
+ case QMetaType::QCborSimpleType:
+ return variant.value<QCborSimpleType>();
+#endif
+ default:
+ break;
+ }
+
+ if (variant.isNull())
+ return QCborValue(nullptr);
+
+ QString string = variant.toString();
+ if (string.isNull())
+ return QCborValue(); // undefined
+ return string;
+}
+
+/*!
+ Recursively converts each \l QCborValue in this array using
+ QCborValue::toVariant() and returns the QVariantList composed of the
+ converted items.
+
+ Conversion to \l QVariant is not completely lossless. Please see the
+ documentation in QCborValue::toVariant() for more information.
+
+ \sa fromVariantList(), fromStringList(), toJsonArray(),
+ QCborValue::toVariant(), QCborMap::toVariantMap()
+ */
+QVariantList QCborArray::toVariantList() const
+{
+ QVariantList retval;
+ retval.reserve(size());
+ for (qsizetype i = 0; i < size(); ++i)
+ retval.append(d->valueAt(i).toVariant());
+ return retval;
+}
+
+/*!
+ Returns a QCborArray containing all the strings found in the \a list list.
+
+ \sa fromVariantList(), fromJsonArray()
+ */
+QCborArray QCborArray::fromStringList(const QStringList &list)
+{
+ QCborArray a;
+ a.detach(list.size());
+ for (const QString &s : list)
+ a.d->append(s);
+ return a;
+}
+
+/*!
+ Converts all the items in the \a list to CBOR using
+ QCborValue::fromVariant() and returns the array composed of those elements.
+
+ Conversion from \l QVariant is not completely lossless. Please see the
+ documentation in QCborValue::fromVariant() for more information.
+
+ \sa toVariantList(), fromStringList(), fromJsonArray(), QCborMap::fromVariantMap()
+ */
+QCborArray QCborArray::fromVariantList(const QVariantList &list)
+{
+ QCborArray a;
+ a.detach(list.size());
+ for (const QVariant &v : list)
+ appendVariant(a.d.data(), v);
+ return a;
+}
+
+/*!
+ Converts all JSON items found in the \a array array to CBOR using
+ QCborValue::fromJson(), and returns the CBOR array composed of those
+ elements.
+
+ This conversion is lossless, as the CBOR type system is a superset of
+ JSON's. Moreover, the array returned by this function can be converted back
+ to the original \a array by using toJsonArray().
+
+ \sa toJsonArray(), toVariantList(), QCborValue::fromJsonValue(), QCborMap::fromJsonObject()
+ */
+QCborArray QCborArray::fromJsonArray(const QJsonArray &array)
+{
+ QCborArray a;
+ a.detach(array.size());
+ for (const QJsonValue v : array) {
+ if (v.isString())
+ a.d->append(v.toString());
+ else
+ a.d->append(QCborValue::fromJsonValue(v));
+ }
+ return a;
+}
+
+/*!
+ Converts the CBOR values to QVariant using QCborValue::toVariant() and
+ "stringifies" all the CBOR keys in this map, returning the QVariantMap that
+ results from that association list.
+
+ QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
+ to QVariantMap will imply a step of "stringification" of the key values.
+ See QCborMap::toJsonObject() for details.
+
+ In addition, the conversion to \l QVariant is not completely lossless.
+ Please see the documentation in QCborValue::toVariant() for more
+ information.
+
+ \sa fromVariantMap(), toVariantHash(), toJsonObject(), QCborValue::toVariant(),
+ QCborArray::toVariantList()
+ */
+QVariantMap QCborMap::toVariantMap() const
+{
+ QVariantMap retval;
+ for (qsizetype i = 0; i < 2 * size(); i += 2)
+ retval.insert(makeString(d.data(), i), d->valueAt(i + 1).toVariant());
+ return retval;
+}
+
+/*!
+ Converts the CBOR values to QVariant using QCborValue::toVariant() and
+ "stringifies" all the CBOR keys in this map, returning the QVariantHash that
+ results from that association list.
+
+ QVariantMaps have string keys, unlike CBOR, so the conversion of a QCborMap
+ to QVariantMap will imply a step of "stringification" of the key values.
+ See QCborMap::toJsonObject() for details.
+
+ In addition, the conversion to \l QVariant is not completely lossless.
+ Please see the documentation in QCborValue::toVariant() for more
+ information.
+
+ \sa fromVariantHash(), toVariantMap(), toJsonObject(), QCborValue::toVariant(),
+ QCborArray::toVariantList()
+ */
+QVariantHash QCborMap::toVariantHash() const
+{
+ QVariantHash retval;
+ retval.reserve(size());
+ for (qsizetype i = 0; i < 2 * size(); i += 2)
+ retval.insert(makeString(d.data(), i), d->valueAt(i + 1).toVariant());
+ return retval;
+}
+
+/*!
+ Converts all the items in \a map to CBOR using QCborValue::fromVariant()
+ and returns the map composed of those elements.
+
+ Conversion from \l QVariant is not completely lossless. Please see the
+ documentation in QCborValue::fromVariant() for more information.
+
+ \sa toVariantMap(), fromVariantHash(), fromJsonObject(), QCborValue::fromVariant()
+ */
+QCborMap QCborMap::fromVariantMap(const QVariantMap &map)
+{
+ QCborMap m;
+ m.detach(map.size());
+ QCborContainerPrivate *d = m.d.data();
+
+ auto it = map.begin();
+ auto end = map.end();
+ for ( ; it != end; ++it) {
+ d->append(it.key());
+ appendVariant(d, it.value());
+ }
+ return m;
+}
+
+/*!
+ Converts all the items in \a hash to CBOR using QCborValue::fromVariant()
+ and returns the map composed of those elements.
+
+ Conversion from \l QVariant is not completely lossless. Please see the
+ documentation in QCborValue::fromVariant() for more information.
+
+ \sa toVariantHash(), fromVariantMap(), fromJsonObject(), QCborValue::fromVariant()
+ */
+QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
+{
+ QCborMap m;
+ m.detach(hash.size());
+ QCborContainerPrivate *d = m.d.data();
+
+ auto it = hash.begin();
+ auto end = hash.end();
+ for ( ; it != end; ++it) {
+ d->append(it.key());
+ appendVariant(d, it.value());
+ }
+ return m;
+}
+
+/*!
+ Converts all JSON items found in the \a obj object to CBOR using
+ QCborValue::fromJson(), and returns the map composed of those elements.
+
+ This conversion is lossless, as the CBOR type system is a superset of
+ JSON's. Moreover, the map returned by this function can be converted back
+ to the original \a obj by using toJsonObject().
+
+ \sa toJsonObject(), toVariantMap(), QCborValue::fromJsonValue(), QCborArray::fromJsonArray()
+ */
+QCborMap QCborMap::fromJsonObject(const QJsonObject &obj)
+{
+ QCborMap m;
+ m.detach(obj.size());
+ QCborContainerPrivate *d = m.d.data();
+
+ auto it = obj.begin();
+ auto end = obj.end();
+ for ( ; it != end; ++it) {
+ d->append(it.key());
+ if (it.value().isString())
+ d->append(it.value().toString());
+ else
+ d->append(QCborValue::fromJsonValue(it.value()));
+ }
+ return m;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qjsondocument.cpp b/src/corelib/serialization/qjsondocument.cpp
index 5018f7c267..0cd86d3ded 100644
--- a/src/corelib/serialization/qjsondocument.cpp
+++ b/src/corelib/serialization/qjsondocument.cpp
@@ -350,22 +350,10 @@ QByteArray QJsonDocument::toJson() const
when converting to a QJsonDocument using toJson().
\value Indented Defines human readable output as follows:
- \code
- {
- "Array": [
- true,
- 999,
- "string"
- ],
- "Key": "Value",
- "null": null
- }
- \endcode
+ \snippet code/src_corelib_serialization_qjsondocument.cpp 0
\value Compact Defines a compact output as follows:
- \code
- {"Array":[true,999,"string"],"Key":"Value","null":null}
- \endcode
+ \snippet code/src_corelib_serialization_qjsondocument.cpp 1
*/
/*!
diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp
index 4a316c8a6f..950bec535b 100644
--- a/src/corelib/serialization/qjsonobject.cpp
+++ b/src/corelib/serialization/qjsonobject.cpp
@@ -1292,6 +1292,17 @@ void QJsonObject::setValueAt(int i, const QJsonValue &val)
insert(e->key(), val);
}
+uint qHash(const QJsonObject &object, uint seed)
+{
+ QtPrivate::QHashCombine hash;
+ for (auto it = object.begin(), end = object.end(); it != end; ++it) {
+ const QString key = it.key();
+ const QJsonValue value = it.value();
+ seed = hash(seed, std::pair<const QString&, const QJsonValue&>(key, value));
+ }
+ return seed;
+}
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
QDebug operator<<(QDebug dbg, const QJsonObject &o)
{
diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h
index 610bce694c..be42d3747a 100644
--- a/src/corelib/serialization/qjsonobject.h
+++ b/src/corelib/serialization/qjsonobject.h
@@ -262,6 +262,8 @@ private:
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonObject)
+Q_CORE_EXPORT uint qHash(const QJsonObject &object, uint seed = 0);
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
#endif
diff --git a/src/corelib/serialization/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp
index 39738b90a8..bfba95520e 100644
--- a/src/corelib/serialization/qjsonparser.cpp
+++ b/src/corelib/serialization/qjsonparser.cpp
@@ -304,6 +304,7 @@ QJsonDocument Parser::parse(QJsonParseError *error)
// allocate some space
dataLength = qMax(end - json, (ptrdiff_t) 256);
data = (char *)malloc(dataLength);
+ Q_CHECK_PTR(data);
// fill in Header data
QJsonPrivate::Header *h = (QJsonPrivate::Header *)data;
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index aa44305fce..2c04da4885 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -46,6 +46,11 @@
#include <qstringlist.h>
#include <qdebug.h>
+#ifndef QT_BOOTSTRAPPED
+# include <qcborarray.h>
+# include <qcbormap.h>
+#endif
+
#include "qjson_p.h"
QT_BEGIN_NAMESPACE
@@ -423,6 +428,25 @@ QJsonValue &QJsonValue::operator =(const QJsonValue &other)
\li QMetaType::QUuid
\endlist
\li QJsonValue::String. Since Qt 5.11, the resulting string will not include braces
+ \row
+ \li
+ \list
+ \li QMetaType::QCborValue
+ \endlist
+ \li Whichever type QCborValue::toJsonValue() returns.
+ \row
+ \li
+ \list
+ \li QMetaType::QCborArray
+ \endlist
+ \li QJsonValue::Array. See QCborValue::toJsonValue() for conversion restrictions.
+ \row
+ \li
+ \list
+ \li QMetaType::QCborMap
+ \endlist
+ \li QJsonValue::Map. See QCborValue::toJsonValue() for conversion restrictions and the
+ "stringification" of map keys.
\endtable
For all other QVariant types a conversion to a QString will be attempted. If the returned string
@@ -469,6 +493,12 @@ QJsonValue QJsonValue::fromVariant(const QVariant &variant)
QJsonDocument doc = variant.toJsonDocument();
return doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object());
}
+ case QMetaType::QCborValue:
+ return variant.value<QCborValue>().toJsonValue();
+ case QMetaType::QCborArray:
+ return variant.value<QCborArray>().toJsonArray();
+ case QMetaType::QCborMap:
+ return variant.value<QCborMap>().toJsonObject();
#endif
default:
break;
@@ -846,6 +876,28 @@ QJsonValue QJsonValueRef::toValue() const
return o->valueAt(index);
}
+uint qHash(const QJsonValue &value, uint seed)
+{
+ switch (value.type()) {
+ case QJsonValue::Null:
+ return qHash(nullptr, seed);
+ case QJsonValue::Bool:
+ return qHash(value.toBool(), seed);
+ case QJsonValue::Double:
+ return qHash(value.toDouble(), seed);
+ case QJsonValue::String:
+ return qHash(value.toString(), seed);
+ case QJsonValue::Array:
+ return qHash(value.toArray(), seed);
+ case QJsonValue::Object:
+ return qHash(value.toObject(), seed);
+ case QJsonValue::Undefined:
+ return seed;
+ }
+ Q_UNREACHABLE();
+ return 0;
+}
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
QDebug operator<<(QDebug dbg, const QJsonValue &o)
{
diff --git a/src/corelib/serialization/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h
index 96538ebbf9..d8e121524d 100644
--- a/src/corelib/serialization/qjsonvalue.h
+++ b/src/corelib/serialization/qjsonvalue.h
@@ -150,6 +150,7 @@ private:
friend class QJsonPrivate::Value;
friend class QJsonArray;
friend class QJsonObject;
+ friend class QCborValue;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
QJsonValue(QJsonPrivate::Data *d, QJsonPrivate::Base *b, const QJsonPrivate::Value& v);
@@ -246,6 +247,8 @@ public:
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonValue)
+Q_CORE_EXPORT uint qHash(const QJsonValue &value, uint seed = 0);
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
#endif
diff --git a/src/corelib/serialization/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp
index ee3cb4efcb..05a5a55926 100644
--- a/src/corelib/serialization/qtextstream.cpp
+++ b/src/corelib/serialization/qtextstream.cpp
@@ -2595,6 +2595,21 @@ QTextStream &QTextStream::operator<<(const QString &string)
Writes \a string to the stream, and returns a reference to the
QTextStream.
+ \since 5.12
+*/
+QTextStream &QTextStream::operator<<(QStringView string)
+{
+ Q_D(QTextStream);
+ CHECK_VALID_STREAM(*this);
+ d->putString(string.cbegin(), int(string.size()));
+ return *this;
+}
+
+/*!
+ \overload
+
+ Writes \a string to the stream, and returns a reference to the
+ QTextStream.
*/
QTextStream &QTextStream::operator<<(QLatin1String string)
{
diff --git a/src/corelib/serialization/qtextstream.h b/src/corelib/serialization/qtextstream.h
index ee0b09419d..ee90d01779 100644
--- a/src/corelib/serialization/qtextstream.h
+++ b/src/corelib/serialization/qtextstream.h
@@ -184,6 +184,7 @@ public:
QTextStream &operator<<(float f);
QTextStream &operator<<(double f);
QTextStream &operator<<(const QString &s);
+ QTextStream &operator<<(QStringView s);
QTextStream &operator<<(QLatin1String s);
QTextStream &operator<<(const QStringRef &s);
QTextStream &operator<<(const QByteArray &array);
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index f18c4cc8e7..5002848d83 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -3956,13 +3956,13 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
writeEndDocument();
break;
case QXmlStreamReader::StartElement: {
+ writeStartElement(reader.namespaceUri().toString(), reader.name().toString());
QXmlStreamNamespaceDeclarations namespaceDeclarations = reader.namespaceDeclarations();
for (int i = 0; i < namespaceDeclarations.size(); ++i) {
const QXmlStreamNamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(i);
writeNamespace(namespaceDeclaration.namespaceUri().toString(),
namespaceDeclaration.prefix().toString());
}
- writeStartElement(reader.namespaceUri().toString(), reader.name().toString());
writeAttributes(reader.attributes());
} break;
case QXmlStreamReader::EndElement:
diff --git a/src/corelib/serialization/serialization.pri b/src/corelib/serialization/serialization.pri
index 3d039dc30f..4f2dc64e4f 100644
--- a/src/corelib/serialization/serialization.pri
+++ b/src/corelib/serialization/serialization.pri
@@ -1,6 +1,12 @@
# Qt data formats core module
HEADERS += \
+ serialization/qcborarray.h \
+ serialization/qcborcommon.h \
+ serialization/qcbormap.h \
+ serialization/qcborvalue.h \
+ serialization/qcborvalue_p.h \
+ serialization/qcborstream.h \
serialization/qdatastream.h \
serialization/qdatastream_p.h \
serialization/qjson_p.h \
@@ -17,8 +23,12 @@ HEADERS += \
serialization/qxmlutils_p.h
SOURCES += \
+ serialization/qcborstream.cpp \
+ serialization/qcbordiagnostic.cpp \
+ serialization/qcborvalue.cpp \
serialization/qdatastream.cpp \
serialization/qjson.cpp \
+ serialization/qjsoncbor.cpp \
serialization/qjsondocument.cpp \
serialization/qjsonobject.cpp \
serialization/qjsonarray.cpp \
@@ -28,3 +38,9 @@ SOURCES += \
serialization/qtextstream.cpp \
serialization/qxmlstream.cpp \
serialization/qxmlutils.cpp
+
+false: SOURCES += \
+ serialization/qcborarray.cpp \
+ serialization/qcbormap.cpp
+
+INCLUDEPATH += ../3rdparty/tinycbor/src