summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization')
-rwxr-xr-xsrc/corelib/serialization/make-xml-parser.sh40
-rw-r--r--src/corelib/serialization/qcborarray.cpp219
-rw-r--r--src/corelib/serialization/qcborarray.h209
-rw-r--r--src/corelib/serialization/qcborcommon.cpp53
-rw-r--r--src/corelib/serialization/qcborcommon.h42
-rw-r--r--src/corelib/serialization/qcborcommon_p.h43
-rw-r--r--src/corelib/serialization/qcbordiagnostic.cpp86
-rw-r--r--src/corelib/serialization/qcbormap.cpp441
-rw-r--r--src/corelib/serialization/qcbormap.h306
-rw-r--r--src/corelib/serialization/qcborstream.h42
-rw-r--r--src/corelib/serialization/qcborstreamreader.cpp330
-rw-r--r--src/corelib/serialization/qcborstreamreader.h75
-rw-r--r--src/corelib/serialization/qcborstreamwriter.cpp85
-rw-r--r--src/corelib/serialization/qcborstreamwriter.h42
-rw-r--r--src/corelib/serialization/qcborvalue.cpp1045
-rw-r--r--src/corelib/serialization/qcborvalue.h341
-rw-r--r--src/corelib/serialization/qcborvalue_p.h151
-rw-r--r--src/corelib/serialization/qdatastream.cpp298
-rw-r--r--src/corelib/serialization/qdatastream.h249
-rw-r--r--src/corelib/serialization/qdatastream_p.h45
-rw-r--r--src/corelib/serialization/qjson_p.h73
-rw-r--r--src/corelib/serialization/qjsonarray.cpp227
-rw-r--r--src/corelib/serialization/qjsonarray.h212
-rw-r--r--src/corelib/serialization/qjsoncbor.cpp77
-rw-r--r--src/corelib/serialization/qjsondocument.cpp77
-rw-r--r--src/corelib/serialization/qjsondocument.h56
-rw-r--r--src/corelib/serialization/qjsonobject.cpp321
-rw-r--r--src/corelib/serialization/qjsonobject.h272
-rw-r--r--src/corelib/serialization/qjsonparser.cpp236
-rw-r--r--src/corelib/serialization/qjsonparser_p.h40
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp357
-rw-r--r--src/corelib/serialization/qjsonvalue.h247
-rw-r--r--src/corelib/serialization/qjsonwriter.cpp63
-rw-r--r--src/corelib/serialization/qjsonwriter_p.h40
-rw-r--r--src/corelib/serialization/qtextstream.cpp144
-rw-r--r--src/corelib/serialization/qtextstream.h69
-rw-r--r--src/corelib/serialization/qtextstream_p.h55
-rw-r--r--src/corelib/serialization/qxmlstream.cpp1209
-rw-r--r--src/corelib/serialization/qxmlstream.g154
-rw-r--r--src/corelib/serialization/qxmlstream.h217
-rw-r--r--src/corelib/serialization/qxmlstream_p.h128
-rw-r--r--src/corelib/serialization/qxmlstreamgrammar.cpp40
-rw-r--r--src/corelib/serialization/qxmlstreamgrammar_p.h42
-rw-r--r--src/corelib/serialization/qxmlstreamparser_p.h106
-rw-r--r--src/corelib/serialization/qxmlutils.cpp77
-rw-r--r--src/corelib/serialization/qxmlutils_p.h42
46 files changed, 4679 insertions, 4044 deletions
diff --git a/src/corelib/serialization/make-xml-parser.sh b/src/corelib/serialization/make-xml-parser.sh
index 0296e4c22b..1889833700 100755
--- a/src/corelib/serialization/make-xml-parser.sh
+++ b/src/corelib/serialization/make-xml-parser.sh
@@ -1,42 +1,6 @@
#!/bin/sh
-#############################################################################
-##
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
+# Copyright (C) 2016 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
me=$(dirname $0)
mkdir -p $me/out
diff --git a/src/corelib/serialization/qcborarray.cpp b/src/corelib/serialization/qcborarray.cpp
index 11f469dc86..626fb49a70 100644
--- a/src/corelib/serialization/qcborarray.cpp
+++ b/src/corelib/serialization/qcborarray.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborarray.h"
#include "qcborvalue_p.h"
@@ -49,11 +13,16 @@ using namespace QtCbor;
\class QCborArray
\inmodule QtCore
\ingroup cbor
+ \ingroup qtserialization
\reentrant
\since 5.12
\brief The QCborArray class is used to hold an array of CBOR elements.
+ \compares strong
+ \compareswith strong QCborValueConstRef
+ \endcompareswith
+
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
@@ -66,7 +35,8 @@ using namespace QtCbor;
from those two, though there may be loss of information in some
conversions.
- \sa QCborValue, QCborMap, QJsonArray, QList
+ \sa QCborValue, QCborMap, QJsonArray, QList, {Parsing and displaying CBOR data},
+ {Serialization Converter}, {Saving and Loading a Game}
*/
/*!
@@ -454,7 +424,7 @@ void QCborArray::removeAt(qsizetype i)
bool QCborArray::contains(const QCborValue &value) const
{
for (qsizetype i = 0; i < size(); ++i) {
- int cmp = d->compareElement(i, value);
+ int cmp = d->compareElement(i, value, Comparison::ForEquality);
if (cmp == 0)
return true;
}
@@ -476,9 +446,9 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator==(const QCborArray &other) const
+ \fn bool QCborArray::operator==(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
+ Compares \a lhs and \a rhs arrays, 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().
@@ -488,9 +458,9 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator!=(const QCborArray &other) const
+ \fn bool QCborArray::operator!=(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
+ Compares \a lhs and \a rhs arrays, 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().
@@ -500,19 +470,58 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator<(const QCborArray &other) const
+ \fn bool QCborArray::operator<(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
- returns true if this array should be sorted before \a other, false
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted before \a rhs, false
otherwise.
For more information on CBOR sorting order, see QCborValue::compare().
\sa compare(), QCborValue::operator==(), QCborMap::operator==(),
- operator==(), operator!=()
+ operator==(), operator!=(), operator<=()
*/
/*!
+ \fn bool QCborArray::operator<=(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted before \a rhs, or if both
+ arrays contains the same elements, false otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator<()
+*/
+
+/*!
+ \fn bool QCborArray::operator>(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted after \a rhs, false
+ otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator>=()
+*/
+
+/*!
+ \fn bool QCborArray::operator>=(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted after \a rhs, or if both
+ arrays contains the same elements, false otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator>()
+*/
+
+/*!
\typedef QCborArray::iterator
A synonym to QCborArray::Iterator.
@@ -713,6 +722,10 @@ void QCborArray::detach(qsizetype reserved)
\brief The QCborArray::Iterator class provides an STL-style non-const iterator for QCborArray.
+ \compares strong
+ \compareswith strong QCborArray::ConstIterator
+ \endcompareswith
+
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
@@ -809,7 +822,7 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn QCborValueRef QCborArray::Iterator::operator[](qsizetype j)
+ \fn QCborValueRef QCborArray::Iterator::operator[](qsizetype j) const
Returns a modifiable reference to the item at a position \a j steps forward
from the item pointed to by this iterator.
@@ -827,63 +840,63 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborArray::Iterator::operator==(const Iterator &other) const
- \fn bool QCborArray::Iterator::operator==(const ConstIterator &other) const
+ \fn bool QCborArray::Iterator::operator==(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator==(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the array as this
+ Returns \c true if \a lhs points to the same entry in the array as \a rhs
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
+ \fn bool QCborArray::Iterator::operator!=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator!=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the array than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the array than
+ \a rhs 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
+ \fn bool QCborArray::Iterator::operator<(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator<(const Iterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator<=(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator<=(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator<=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator<=(const Iterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator>(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator>(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator>(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator>(const Iterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator>=(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator>=(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator>=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator>=(const Iterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
\fn QCborArray::Iterator &QCborArray::Iterator::operator++()
- The prefix ++ operator, \c{++it}, advances the iterator to the next item in
+ The prefix \c{++} 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.
@@ -895,14 +908,14 @@ void QCborArray::detach(qsizetype reserved)
\fn QCborArray::Iterator QCborArray::Iterator::operator++(int)
\overload
- The postfix ++ operator, \c{it++}, advances the iterator to the next item
+ The postfix \c{++} 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
+ The prefix \c{--} operator, \c{--it}, makes the preceding item current and
returns this iterator.
Calling this function on QCborArray::begin() leads to undefined results.
@@ -914,7 +927,7 @@ void QCborArray::detach(qsizetype reserved)
\fn QCborArray::Iterator QCborArray::Iterator::operator--(int)
\overload
- The postfix -- operator, \c{it--}, makes the preceding item current and
+ The postfix \c{--} operator, \c{it--}, makes the preceding item current and
returns an iterator to the previously current item.
*/
@@ -968,6 +981,10 @@ void QCborArray::detach(qsizetype reserved)
\brief The QCborArray::ConstIterator class provides an STL-style const iterator for QCborArray.
+ \compares strong
+ \compareswith strong QCborArray::Iterator
+ \endcompareswith
+
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
@@ -1055,7 +1072,7 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn const QCborValueRef QCborArray::ConstIterator::operator[](qsizetype j)
+ \fn QCborValueRef QCborArray::ConstIterator::operator[](qsizetype j) const
Returns the item at a position \a j steps forward from the item pointed to
by this iterator.
@@ -1067,63 +1084,57 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborArray::ConstIterator::operator==(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator==(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator==(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the array as this
+ Returns \c true if \a lhs points to the same entry in the array as \a rhs
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
+ \fn bool QCborArray::ConstIterator::operator!=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a o points to a different entry in the array than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the array than
+ \a rhs 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
+ \fn bool QCborArray::ConstIterator::operator<(const ConstIterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator<=(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator<=(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator<=(const ConstIterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator>(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator>(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>(const ConstIterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator>=(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator>=(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>=(const ConstIterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
\fn QCborArray::ConstIterator &QCborArray::ConstIterator::operator++()
- The prefix ++ operator, \c{++it}, advances the iterator to the next item in
+ The prefix \c{++} 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.
@@ -1135,14 +1146,14 @@ void QCborArray::detach(qsizetype reserved)
\fn QCborArray::ConstIterator QCborArray::ConstIterator::operator++(int)
\overload
- The postfix ++ operator, \c{it++}, advances the iterator to the next item
+ The postfix \c{++} 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
+ The prefix \c{--} operator, \c{--it}, makes the preceding item current and
returns this iterator.
Calling this function on QCborArray::begin() leads to undefined results.
@@ -1154,7 +1165,7 @@ void QCborArray::detach(qsizetype reserved)
\fn QCborArray::ConstIterator QCborArray::ConstIterator::operator--(int)
\overload
- The postfix -- operator, \c{it--}, makes the preceding item current and
+ The postfix \c{--} operator, \c{it--}, makes the preceding item current and
returns an iterator to the previously current item.
*/
diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h
index dd0628b3bb..481f316f33 100644
--- a/src/corelib/serialization/qcborarray.h
+++ b/src/corelib/serialization/qcborarray.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORARRAY_H
#define QCBORARRAY_H
@@ -57,7 +21,7 @@ class Q_CORE_EXPORT QCborArray
public:
class ConstIterator;
class Iterator {
- mutable QCborValueRef item;
+ QCborValueRef item {};
friend class ConstIterator;
friend class QCborArray;
Iterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
@@ -79,21 +43,23 @@ public:
}
QCborValueRef operator*() const { return item; }
- QCborValueRef *operator->() const { return &item; }
- QCborValueRef operator[](qsizetype j) { return { item.d, item.i + j }; }
-
+ QCborValueRef *operator->() { return &item; }
+ const QCborValueConstRef *operator->() const { return &item; }
+ QCborValueRef operator[](qsizetype j) const { return { item.d, item.i + j }; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
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 &o) const { return !operator==(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 &o) const { return !operator==(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; }
+#endif
Iterator &operator++() { ++item.i; return *this; }
Iterator operator++(int) { Iterator n = *this; ++item.i; return n; }
Iterator &operator--() { item.i--; return *this; }
@@ -103,10 +69,57 @@ public:
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; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static bool comparesEqual_helper(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator)
+ friend bool comparesEqual(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator, ConstIterator)
};
class ConstIterator {
- QCborValueRef item;
+ QCborValueConstRef item;
friend class Iterator;
friend class QCborArray;
ConstIterator(QCborContainerPrivate *dd, qsizetype ii) : item(dd, ii) {}
@@ -127,22 +140,23 @@ public:
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 }; }
-
+ QCborValueConstRef operator*() const { return item; }
+ const QCborValueConstRef *operator->() const { return &item; }
+ QCborValueConstRef operator[](qsizetype j) const { return QCborValueRef{ item.d, item.i + j }; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
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 &o) const { return !operator==(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 &o) const { return !operator==(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; }
+#endif
ConstIterator &operator++() { ++item.i; return *this; }
ConstIterator operator++(int) { ConstIterator n = *this; ++item.i; return n; }
ConstIterator &operator--() { item.i--; return *this; }
@@ -152,6 +166,31 @@ public:
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; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const ConstIterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(ConstIterator)
};
typedef qsizetype size_type;
@@ -176,7 +215,7 @@ public:
void swap(QCborArray &other) noexcept
{
- qSwap(d, other.d);
+ d.swap(other.d);
}
QCborValue toCborValue() const { return *this; }
@@ -216,19 +255,11 @@ public:
bool contains(const QCborValue &value) const;
int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION;
-#if 0 && __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
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborArray &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborArray &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborArray &other) const
{ return compare(other) < 0; }
#endif
@@ -272,6 +303,48 @@ public:
QJsonArray toJsonArray() const;
private:
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborArray &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborArray &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray, QCborValue)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborArray &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray, QCborValueConstRef)
+
void detach(qsizetype reserve = 0);
friend QCborValue;
@@ -288,6 +361,7 @@ inline QCborValue::QCborValue(QCborArray &&a)
{
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
inline QCborArray QCborValueRef::toArray() const
{
return concrete().toArray();
@@ -297,6 +371,17 @@ inline QCborArray QCborValueRef::toArray(const QCborArray &a) const
{
return concrete().toArray(a);
}
+#endif
+
+inline QCborArray QCborValueConstRef::toArray() const
+{
+ return concrete().toArray();
+}
+
+inline QCborArray QCborValueConstRef::toArray(const QCborArray &a) const
+{
+ return concrete().toArray(a);
+}
Q_CORE_EXPORT size_t qHash(const QCborArray &array, size_t seed = 0);
diff --git a/src/corelib/serialization/qcborcommon.cpp b/src/corelib/serialization/qcborcommon.cpp
index 0ebefe38d7..b3d4f70aa2 100644
--- a/src/corelib/serialization/qcborcommon.cpp
+++ b/src/corelib/serialization/qcborcommon.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2019 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#define CBOR_NO_ENCODER_API
#define CBOR_NO_PARSER_API
@@ -46,11 +10,14 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QCborTag)
+
#include <cborerrorstrings.c>
/*!
\headerfile <QtCborCommon>
-
+ \inmodule QtCore
+ \ingroup qtserialization
\brief The <QtCborCommon> header contains definitions common to both the
streaming classes (QCborStreamReader and QCborStreamWriter) and to
QCborValue.
@@ -212,7 +179,9 @@ QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st)
\brief The QCborError class holds the error condition found while parsing or
validating a CBOR stream.
- \sa QCborStreamReader, QCborValue, QCborParserError
+ \sa QCborStreamReader, QCborValue, QCborParserError,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
@@ -231,7 +200,7 @@ QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st)
\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/unparsable Type (data is corrupt
- and the and the error is not recoverable).
+ 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
diff --git a/src/corelib/serialization/qcborcommon.h b/src/corelib/serialization/qcborcommon.h
index 2ea0cec44c..bd7a93dfe7 100644
--- a/src/corelib/serialization/qcborcommon.h
+++ b/src/corelib/serialization/qcborcommon.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORCOMMON_H
#define QCBORCOMMON_H
@@ -151,7 +115,7 @@ enum class QCborNegativeInteger : quint64 {};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QCborTag)
+QT_DECL_METATYPE_EXTERN(QCborTag, Q_CORE_EXPORT)
// To avoid changing namespace we need to reinstate defines, even though our .cpp
// will then have to remove them again.
diff --git a/src/corelib/serialization/qcborcommon_p.h b/src/corelib/serialization/qcborcommon_p.h
index 9b7f4b7099..69e80cb9d6 100644
--- a/src/corelib/serialization/qcborcommon_p.h
+++ b/src/corelib/serialization/qcborcommon_p.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2019 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORCOMMON_P_H
#define QCBORCOMMON_P_H
#include "qcborcommon.h"
+#include "private/qglobal_p.h"
//
// W A R N I N G
diff --git a/src/corelib/serialization/qcbordiagnostic.cpp b/src/corelib/serialization/qcbordiagnostic.cpp
index b7d8f1ed6b..e89afc4827 100644
--- a/src/corelib/serialization/qcbordiagnostic.cpp
+++ b/src/corelib/serialization/qcbordiagnostic.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborvalue.h"
#include "qcborvalue_p.h"
@@ -49,6 +13,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace {
class DiagnosticNotation
{
@@ -75,7 +41,7 @@ private:
++dn->nestingLevel;
static const char indent[IndentationWidth + 1] = " ";
if (dn->opts & QCborValue::LineWrapped)
- dn->separator += QLatin1String(indent, IndentationWidth);
+ dn->separator += QLatin1StringView(indent, IndentationWidth);
}
~Nest()
{
@@ -86,7 +52,7 @@ private:
};
DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
- : separator(QLatin1String(opts_ & QCborValue::LineWrapped ? "\n" : "")), opts(opts_)
+ : separator(opts_ & QCborValue::LineWrapped ? "\n"_L1 : ""_L1), opts(opts_)
{
byteArrayFormatStack.push(int(QCborKnownTags::ExpectedBase16));
}
@@ -109,11 +75,11 @@ static QString makeFpString(double d)
} else if (convertDoubleTo(d, &v)) {
s = QString::fromLatin1("%1.0").arg(v);
if (d < 0)
- s.prepend(QLatin1Char('-'));
+ s.prepend(u'-');
} else {
s = QString::number(d, 'g', QLocale::FloatingPointShortest);
if (!s.contains(u'.') && !s.contains(u'e'))
- s += QLatin1Char('.');
+ s += u'.';
}
return s;
}
@@ -131,7 +97,7 @@ static bool isByteArrayEncodingTag(QCborTag tag)
void DiagnosticNotation::appendString(const QString &s)
{
- result += QLatin1Char('"');
+ result += u'"';
const QChar *begin = s.begin();
const QChar *end = s.end();
@@ -161,7 +127,7 @@ void DiagnosticNotation::appendString(const QString &s)
};
int buflen = 2;
QChar buf[10];
- buf[0] = QLatin1Char('\\');
+ buf[0] = u'\\';
buf[1] = QChar::Null;
char16_t uc = ptr->unicode();
@@ -203,18 +169,18 @@ void DiagnosticNotation::appendString(const QString &s)
begin = ptr + 1;
}
- result += QLatin1Char('"');
+ result += u'"';
}
void DiagnosticNotation::appendArray(const QCborArray &a)
{
- result += QLatin1Char('[');
+ result += u'[';
// length 2 (including the space) when not line wrapping
- QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ QLatin1StringView commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
{
Nest n(this);
- QLatin1String comma;
+ QLatin1StringView comma;
for (auto v : a) {
result += comma + separator;
comma = commaValue;
@@ -222,28 +188,28 @@ void DiagnosticNotation::appendArray(const QCborArray &a)
}
}
- result += separator + QLatin1Char(']');
+ result += separator + u']';
}
void DiagnosticNotation::appendMap(const QCborMap &m)
{
- result += QLatin1Char('{');
+ result += u'{';
// length 2 (including the space) when not line wrapping
- QLatin1String commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
+ QLatin1StringView commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
{
Nest n(this);
- QLatin1String comma;
+ QLatin1StringView comma;
for (auto v : m) {
result += comma + separator;
comma = commaValue;
appendValue(v.first);
- result += QLatin1String(": ");
+ result += ": "_L1;
appendValue(v.second);
}
}
- result += separator + QLatin1Char('}');
+ result += separator + u'}';
};
void DiagnosticNotation::appendValue(const QCborValue &v)
@@ -276,16 +242,16 @@ void DiagnosticNotation::appendValue(const QCborValue &v)
case QCborValue::Map:
return appendMap(v.toMap());
case QCborValue::False:
- result += QLatin1String("false");
+ result += "false"_L1;
return;
case QCborValue::True:
- result += QLatin1String("true");
+ result += "true"_L1;
return;
case QCborValue::Null:
- result += QLatin1String("null");
+ result += "null"_L1;
return;
case QCborValue::Undefined:
- result += QLatin1String("undefined");
+ result += "undefined"_L1;
return;
case QCborValue::Double:
result += makeFpString(v.toDouble());
@@ -305,9 +271,9 @@ void DiagnosticNotation::appendValue(const QCborValue &v)
bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
if (byteArrayFormat)
byteArrayFormatStack.push(int(v.tag()));
- result += QString::number(quint64(v.tag())) + QLatin1Char('(');
+ result += QString::number(quint64(v.tag())) + u'(';
appendValue(v.taggedValue());
- result += QLatin1Char(')');
+ result += u')';
if (byteArrayFormat)
byteArrayFormatStack.pop();
} else {
diff --git a/src/corelib/serialization/qcbormap.cpp b/src/corelib/serialization/qcbormap.cpp
index b178018b7c..038e0d61ce 100644
--- a/src/corelib/serialization/qcbormap.cpp
+++ b/src/corelib/serialization/qcbormap.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcbormap.h"
#include "qcborvalue_p.h"
@@ -48,11 +12,16 @@ using namespace QtCbor;
\class QCborMap
\inmodule QtCore
\ingroup cbor
+ \ingroup qtserialization
\reentrant
\since 5.12
\brief The QCborMap class is used to hold an associative container representable in CBOR.
+ \compares strong
+ \compareswith strong QCborValue QCborValueConstRef
+ \endcompareswith
+
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
@@ -82,7 +51,9 @@ using namespace QtCbor;
stringified using a one-way method that the conversion back to QCborMap
will not undo.
- \sa QCborArray, QCborValue, QJsonDocument, QVariantMap
+ \sa QCborArray, QCborValue, QJsonDocument, QVariantMap,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
@@ -328,7 +299,7 @@ QList<QCborValue> QCborMap::keys() const
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 &)
+ value(QLatin1StringView), value(const QString &), value(const QCborValue &)
*/
/*!
@@ -350,7 +321,8 @@ QList<QCborValue> QCborMap::keys() const
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[] &)
+ operator[](QLatin1StringView), operator[](const QString &),
+ operator[](const QCborOperator[] &)
*/
/*!
@@ -366,7 +338,7 @@ QList<QCborValue> QCborMap::keys() const
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()
+ take(QLatin1StringView), take(const QString &), take(const QCborValue &), insert()
*/
/*!
@@ -382,7 +354,7 @@ QList<QCborValue> QCborMap::keys() const
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 &)
+ remove(QLatin1StringView), remove(const QString &), remove(const QCborValue &)
*/
/*!
@@ -393,7 +365,7 @@ QList<QCborValue> QCborMap::keys() const
are simpler to encode and decode.
\sa value(qint64), operator[](qint64), find(qint64), remove(qint64),
- contains(QLatin1String), remove(const QString &), remove(const QCborValue &)
+ contains(QLatin1StringView), remove(const QString &), remove(const QCborValue &)
*/
/*!
@@ -418,22 +390,15 @@ QList<QCborValue> QCborMap::keys() const
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 &)
+ operator[](QLatin1StringView), 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 };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
/*!
- \fn QCborValue QCborMap::value(QLatin1String key) const
+ \fn QCborValue QCborMap::value(QLatin1StringView key) const
\overload
Returns the QCborValue element in this map that corresponds to key \a key,
@@ -450,13 +415,13 @@ QCborValueRef QCborMap::operator[](qint64 key)
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)
+ \sa operator[](QLatin1StringView), find(QLatin1StringView), constFind(QLatin1StringView),
+ remove(QLatin1StringView), contains(QLatin1StringView)
value(qint64), value(const QString &), value(const QCborValue &)
*/
/*!
- \fn QCborValue QCborMap::operator[](QLatin1String key) const
+ \fn QCborValue QCborMap::operator[](QLatin1StringView key) const
\overload
Returns the QCborValue element in this map that corresponds to key \a key,
@@ -473,13 +438,13 @@ QCborValueRef QCborMap::operator[](qint64 key)
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)
+ \sa value(QLatin1StringView), find(QLatin1StringView), constFind(QLatin1StringView),
+ remove(QLatin1StringView), contains(QLatin1StringView)
operator[](qint64), operator[](const QString &), operator[](const QCborOperator[] &)
*/
/*!
- \fn QCborValue QCborMap::take(QLatin1String key)
+ \fn QCborValue QCborMap::take(QLatin1StringView 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.
@@ -490,12 +455,13 @@ QCborValueRef QCborMap::operator[](qint64 key)
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()
+ \sa value(QLatin1StringView), operator[](QLatin1StringView), find(QLatin1StringView),
+ contains(QLatin1StringView), take(qint64), take(const QString &),
+ take(const QCborValue &), insert()
*/
/*!
- \fn void QCborMap::remove(QLatin1String key)
+ \fn void QCborMap::remove(QLatin1StringView key)
\overload
Removes the key \a key and the corresponding value from the map, if it is
@@ -507,19 +473,21 @@ QCborValueRef QCborMap::operator[](qint64 key)
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 &)
+ \sa value(QLatin1StringView), operator[](QLatin1StringView), find(QLatin1StringView),
+ contains(QLatin1StringView), remove(qint64), remove(const QString &),
+ remove(const QCborValue &)
*/
/*!
- \fn bool QCborMap::contains(QLatin1String key) const
+ \fn bool QCborMap::contains(QLatin1StringView 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 &)
+ \sa value(QLatin1StringView), operator[](QLatin1StringView), find(QLatin1StringView),
+ remove(QLatin1StringView), contains(qint64), remove(const QString &),
+ remove(const QCborValue &)
*/
/*!
@@ -544,19 +512,13 @@ QCborValueRef QCborMap::operator[](qint64 key)
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 &)
+ \sa value(QLatin1StringView), find(QLatin1StringView), contains(QLatin1StringView),
+ remove(QLatin1StringView), operator[](qint64), operator[](const QString &),
+ operator[](const QCborValue &)
*/
-QCborValueRef QCborMap::operator[](QLatin1String key)
+QCborValueRef QCborMap::operator[](QLatin1StringView 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 };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
/*!
@@ -579,7 +541,7 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
\sa operator[](const QString &), find(const QString &), constFind(const QString &),
remove(const QString &), contains(const QString &)
- value(qint64), value(QLatin1String), value(const QCborValue &)
+ value(qint64), value(QLatin1StringView), value(const QCborValue &)
*/
/*!
@@ -602,7 +564,7 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
\sa value(const QString &), find(const QString &), constFind(const QString &),
remove(const QString &), contains(const QString &)
- operator[](qint64), operator[](QLatin1String), operator[](const QCborOperator[] &)
+ operator[](qint64), operator[](QLatin1StringView), operator[](const QCborOperator[] &)
*/
/*!
@@ -617,8 +579,9 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
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()
+ \sa value(const QString &), operator[](const QString &), find(const QString &),
+ contains(const QString &), take(QLatin1StringView), take(qint64),
+ take(const QCborValue &), insert()
*/
/*!
@@ -636,7 +599,7 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
\sa value(const QString &), operator[](const QString &), find(const QString &),
contains(const QString &)
- remove(qint64), remove(QLatin1String), remove(const QCborValue &)
+ remove(qint64), remove(QLatin1StringView), remove(const QCborValue &)
*/
/*!
@@ -648,7 +611,7 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
\sa value(const QString &), operator[](const QString &), find(const QString &),
remove(const QString &),
- contains(qint64), remove(QLatin1String), remove(const QCborValue &)
+ contains(qint64), remove(QLatin1StringView), remove(const QCborValue &)
*/
/*!
@@ -673,19 +636,13 @@ QCborValueRef QCborMap::operator[](QLatin1String key)
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 &)
+ \sa value(const QString &), find(const QString &), contains(const QString &),
+ remove(const QString &), operator[](qint64), operator[](QLatin1StringView),
+ 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 };
+ return QCborContainerPrivate::findOrAddMapKey(*this, qToStringViewIgnoringNull(key));
}
/*!
@@ -707,7 +664,7 @@ QCborValueRef QCborMap::operator[](const QString & key)
\sa operator[](const QCborValue &), find(const QCborValue &), constFind(const QCborValue &),
remove(const QCborValue &), contains(const QCborValue &)
- value(qint64), value(QLatin1String), value(const QString &)
+ value(qint64), value(QLatin1StringView), value(const QString &)
*/
/*!
@@ -729,7 +686,7 @@ QCborValueRef QCborMap::operator[](const QString & key)
\sa value(const QCborValue &), find(const QCborValue &), constFind(const QCborValue &),
remove(const QCborValue &), contains(const QCborValue &)
- operator[](qint64), operator[](QLatin1String), operator[](const QCborOperator[] &)
+ operator[](qint64), operator[](QLatin1StringView), operator[](const QCborOperator[] &)
*/
/*!
@@ -744,8 +701,9 @@ QCborValueRef QCborMap::operator[](const QString & key)
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()
+ \sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
+ contains(const QCborValue &), take(QLatin1StringView), take(const QString &),
+ take(qint64), insert()
*/
/*!
@@ -762,7 +720,7 @@ QCborValueRef QCborMap::operator[](const QString & key)
\sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
contains(const QCborValue &)
- remove(qint64), remove(QLatin1String), remove(const QString &)
+ remove(qint64), remove(QLatin1StringView), remove(const QString &)
*/
/*!
@@ -773,7 +731,7 @@ QCborValueRef QCborMap::operator[](const QString & key)
\sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
remove(const QCborValue &),
- contains(qint64), remove(QLatin1String), remove(const QString &)
+ contains(qint64), remove(QLatin1StringView), remove(const QString &)
*/
/*!
@@ -798,19 +756,21 @@ QCborValueRef QCborMap::operator[](const QString & key)
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 &)
+ \sa value(const QCborValue &), find(const QCborValue &), contains(const QCborValue &),
+ remove(const QCborValue &), operator[](qint64), operator[](QLatin1StringView),
+ 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 };
+ return QCborContainerPrivate::findOrAddMapKey<const QCborValue &>(*this, key);
+}
+
+template <typename KeyType> inline QCborValueRef
+QCborContainerPrivate::findOrAddMapKey(QCborMap &map, KeyType key)
+{
+ QCborValueRef result = findOrAddMapKey<KeyType>(map.d.data(), key);
+ map.d = result.d;
+ return result;
}
/*!
@@ -829,8 +789,8 @@ QCborValueRef QCborMap::operator[](const QCborValue &key)
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 &)
+ \sa value(qint64), operator[](qint64), constFind(qint64), remove(qint64), contains(qint64),
+ value(QLatin1StringView), value(const QString &), value(const QCborValue &)
*/
QCborMap::iterator QCborMap::find(qint64 key)
{
@@ -840,8 +800,8 @@ QCborMap::iterator QCborMap::find(qint64 key)
}
/*!
- \fn QCborMap::iterator QCborMap::find(QLatin1String key)
- \fn QCborMap::const_iterator QCborMap::find(QLatin1String key) const
+ \fn QCborMap::iterator QCborMap::find(QLatin1StringView key)
+ \fn QCborMap::const_iterator QCborMap::find(QLatin1StringView key) const
\overload
Returns a map iterator to the key-value pair whose key is \a key, if the
@@ -853,11 +813,11 @@ QCborMap::iterator QCborMap::find(qint64 key)
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)
+ \sa value(QLatin1StringView), operator[](QLatin1StringView), constFind(QLatin1StringView),
+ remove(QLatin1StringView), contains(QLatin1StringView),
value(qint64), value(const QString &), value(const QCborValue &)
*/
-QCborMap::iterator QCborMap::find(QLatin1String key)
+QCborMap::iterator QCborMap::find(QLatin1StringView key)
{
detach();
auto it = constFind(key);
@@ -879,8 +839,8 @@ QCborMap::iterator QCborMap::find(QLatin1String key)
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 &)
+ remove(const QString &), contains(const QString &),
+ value(qint64), value(QLatin1StringView), value(const QCborValue &)
*/
QCborMap::iterator QCborMap::find(const QString & key)
{
@@ -904,8 +864,8 @@ QCborMap::iterator QCborMap::find(const QString & key)
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 &)
+ remove(const QCborValue &), contains(const QCborValue &),
+ value(qint64), value(QLatin1StringView), value(const QString &)
*/
QCborMap::iterator QCborMap::find(const QCborValue &key)
{
@@ -927,17 +887,12 @@ QCborMap::iterator QCborMap::find(const QCborValue &key)
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 &)
+ \sa value(qint64), operator[](qint64), find(qint64), remove(qint64), contains(qint64),
+ value(QLatin1StringView), 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();
+ return d ? d->findCborMapKey(key) : constEnd();
}
/*!
@@ -952,17 +907,13 @@ QCborMap::const_iterator QCborMap::constFind(qint64 key) const
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)
+ \sa value(QLatin1StringView), operator[](QLatin1StringView), find(QLatin1StringView),
+ remove(QLatin1StringView), contains(QLatin1StringView),
value(qint64), value(const QString &), value(const QCborValue &)
*/
-QCborMap::const_iterator QCborMap::constFind(QLatin1String key) const
+QCborMap::const_iterator QCborMap::constFind(QLatin1StringView key) const
{
- for (qsizetype i = 0; i < 2 * size(); i += 2) {
- if (d->stringEqualsElement(i, key))
- return { d.data(), i + 1 };
- }
- return constEnd();
+ return d ? d->findCborMapKey(key) : constEnd();
}
/*!
@@ -978,16 +929,12 @@ QCborMap::const_iterator QCborMap::constFind(QLatin1String key) const
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 &)
+ remove(const QString &), contains(const QString &),
+ value(qint64), value(QLatin1StringView), value(const QCborValue &)
*/
-QCborMap::const_iterator QCborMap::constFind(const QString & key) const
+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();
+ return d ? d->findCborMapKey(qToStringViewIgnoringNull(key)) : constEnd();
}
/*!
@@ -1004,16 +951,11 @@ QCborMap::const_iterator QCborMap::constFind(const QString & key) const
\sa value(const QCborValue &), operator[](const QCborValue &), find(const QCborValue &),
remove(const QCborValue &), contains(const QCborValue &),
- value(qint64), value(QLatin1String), value(const QString &)
+ value(qint64), value(QLatin1StringView), 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();
+ return d ? d->findCborMapKey<const QCborValue &>(key) : constEnd();
}
/*!
@@ -1031,7 +973,7 @@ QCborMap::const_iterator QCborMap::constFind(const QCborValue &key) const
*/
/*!
- \fn QCborMap::iterator QCborMap::insert(QLatin1String key, const QCborValue &value)
+ \fn QCborMap::iterator QCborMap::insert(QLatin1StringView key, const QCborValue &value)
\overload
Inserts the key \a key and value \a value into this map and returns a map
@@ -1040,8 +982,8 @@ QCborMap::const_iterator QCborMap::constFind(const QCborValue &key) const
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()
+ \sa erase(), remove(QLatin1StringView), value(QLatin1StringView), operator[](QLatin1StringView),
+ find(QLatin1StringView), contains(QLatin1StringView), take(QLatin1StringView), extract()
*/
/*!
@@ -1167,10 +1109,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator==(const QCborMap &other) const
+ \fn bool QCborMap::operator==(const QCborMap &lhs, const QCborMap &rhs)
- 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,
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if the two maps contain the same elements in the same order,
false otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1186,10 +1128,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator!=(const QCborMap &other) const
+ \fn bool QCborMap::operator!=(const QCborMap &lhs, const QCborMap &rhs)
- 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
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if the two maps contain any different elements or elements in
different orders, false otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1205,10 +1147,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator<(const QCborMap &other) const
+ \fn bool QCborMap::operator<(const QCborMap &lhs, const QCborMap &rhs)
- Compares this map and \a other, comparing each element in sequence, and
- returns true if this map should be sorted before \a other, false
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted before \a rhs, false
otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1223,6 +1165,65 @@ QCborValue QCborMap::extract(iterator it)
operator==(), operator!=()
*/
+/*!
+ \fn bool QCborMap::operator<=(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted before \a rhs or
+ if the two maps contain 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 sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::operator>=(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted after \a rhs or
+ if the two maps contain 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 sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::operator>(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted after \a rhs, 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);
@@ -1237,6 +1238,10 @@ void QCborMap::detach(qsizetype reserved)
\brief The QCborMap::Iterator class provides an STL-style non-const iterator for QCborMap.
+ \compares strong
+ \compareswith strong ConstIterator
+ \endcompareswith
+
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
@@ -1358,63 +1363,63 @@ void QCborMap::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborMap::Iterator::operator==(const Iterator &other) const
- \fn bool QCborMap::Iterator::operator==(const ConstIterator &other) const
+ \fn bool QCborMap::Iterator::operator==(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator==(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the map as this
+ Returns \c true if \a lhs points to the same entry in the map as \a rhs
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
+ \fn bool QCborMap::Iterator::operator!=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator!=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the map than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the map than
+ \a rhs 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
+ \fn bool QCborMap::Iterator::operator<(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator<(const Iterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator<=(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator<=(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator<=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator<=(const Iterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator>(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator>(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator>(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator>(const Iterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator>=(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator>=(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator>=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator>=(const Iterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
\fn QCborMap::Iterator &QCborMap::Iterator::operator++()
- The prefix ++ operator, \c{++i}, advances the iterator to the next item in
+ The prefix \c{++} 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.
@@ -1426,14 +1431,14 @@ void QCborMap::detach(qsizetype reserved)
\fn QCborMap::Iterator QCborMap::Iterator::operator++(int)
\overload
- The postfix ++ operator, \c{i++}, advances the iterator to the next item in
+ The postfix \c{++} 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
+ The prefix \c{--} operator, \c{--i}, makes the preceding item current and
returns this iterator.
Calling this function on QCborMap::begin() leads to undefined results.
@@ -1445,7 +1450,7 @@ void QCborMap::detach(qsizetype reserved)
\fn QCborMap::Iterator QCborMap::Iterator::operator--(int)
\overload
- The postfix -- operator, \c{i--}, makes the preceding item current and
+ The postfix \c{--} operator, \c{i--}, makes the preceding item current and
returns an iterator pointing to the previously current item.
*/
@@ -1503,6 +1508,10 @@ void QCborMap::detach(qsizetype reserved)
\brief The QCborMap::ConstIterator class provides an STL-style const iterator for QCborMap.
+ \compares strong
+ \compareswith strong Iterator
+ \endcompareswith
+
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
@@ -1603,63 +1612,57 @@ void QCborMap::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborMap::ConstIterator::operator==(const ConstIterator &other) const
- \fn bool QCborMap::ConstIterator::operator==(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator==(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the map as this
+ Returns \c true if \a lhs points to the same entry in the map as \a rhs
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
+ \fn bool QCborMap::ConstIterator::operator!=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the map than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the map than
+ \a rhs 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
+ \fn bool QCborMap::ConstIterator::operator<(const ConstIterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator<=(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator<=(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator<=(const ConstIterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator>(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator>(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>(const ConstIterator &lhs, const ConstIterator &rhs)
- 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.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator>=(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator>=(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>=(const ConstIterator &lhs, const ConstIterator &rhs)
- 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
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
\fn QCborMap::ConstIterator &QCborMap::ConstIterator::operator++()
- The prefix ++ operator, \c{++i}, advances the iterator to the next item in
+ The prefix \c{++} 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.
@@ -1671,14 +1674,14 @@ void QCborMap::detach(qsizetype reserved)
\fn QCborMap::ConstIterator QCborMap::ConstIterator::operator++(int)
\overload
- The postfix ++ operator, \c{i++}, advances the iterator to the next item in
+ The postfix \c{++} 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
+ The prefix \c{--} operator, \c{--i}, makes the preceding item current and
returns this iterator.
Calling this function on QCborMap::begin() leads to undefined results.
@@ -1690,7 +1693,7 @@ void QCborMap::detach(qsizetype reserved)
\fn QCborMap::ConstIterator QCborMap::ConstIterator::operator--(int)
\overload
- The postfix -- operator, \c{i--}, makes the preceding item current and
+ The postfix \c{--} operator, \c{i--}, makes the preceding item current and
returns an iterator pointing to the previously current item.
*/
diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h
index f84552d992..d2fd769240 100644
--- a/src/corelib/serialization/qcbormap.h
+++ b/src/corelib/serialization/qcbormap.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORMAP_H
#define QCBORMAP_H
@@ -56,26 +20,27 @@ class QCborContainerPrivate;
class Q_CORE_EXPORT QCborMap
{
public:
- typedef QPair<QCborValue, QCborValue> value_type;
+ typedef std::pair<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
+ 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;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> value_type;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> reference;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> pointer;
constexpr Iterator() = default;
constexpr Iterator(const Iterator &) = default;
+ ~Iterator() = default;
Iterator &operator=(const Iterator &other)
{
// rebind the reference
@@ -84,23 +49,32 @@ public:
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); }
+ value_type operator*() const { return { QCborValueRef{item.d, item.i - 1}, item }; }
+ value_type operator[](qsizetype j) const { return *(*this + j); }
+ QCborValueRef *operator->() { return &item; }
+ const QCborValueConstRef *operator->() const { return &item; }
+#if QT_VERSION >= QT_VERSION_CHECK(7,0,0)
+ QCborValueConstRef
+#else
+ QCborValue
+#endif
+ key() const { return QCborValueRef(item.d, item.i - 1); }
QCborValueRef value() const { return item; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
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 &o) const { return !operator==(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 &o) const { return !operator==(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; }
+#endif
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; }
@@ -110,24 +84,74 @@ public:
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; }
+
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static bool comparesEqual_helper(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator)
+ friend bool comparesEqual(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator, ConstIterator)
};
class ConstIterator {
- QCborValueRef item; // points to the value
+ QCborValueConstRef item; // points to the value
friend class Iterator;
friend class QCborMap;
friend class QCborValue;
friend class QCborValueRef;
+ constexpr ConstIterator(QCborValueConstRef it) : item{it} {}
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;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> value_type;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> reference;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> pointer;
constexpr ConstIterator() = default;
constexpr ConstIterator(const ConstIterator &) = default;
+ ~ConstIterator() = default;
ConstIterator &operator=(const ConstIterator &other)
{
// rebind the reference
@@ -136,32 +160,65 @@ public:
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; }
+ value_type operator*() const { return { QCborValueRef(item.d, item.i - 1), item }; }
+ value_type operator[](qsizetype j) const { return *(*this + j); }
+ const QCborValueConstRef *operator->() const { return &item; }
+#if QT_VERSION >= QT_VERSION_CHECK(7,0,0)
+ QCborValueConstRef
+#else
+ QCborValue
+#endif
+ key() const { return QCborValueRef(item.d, item.i - 1); }
+ QCborValueConstRef value() const { return item; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
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 &o) const { return !operator==(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 &o) const { return !operator==(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; }
+#endif
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 }); }
+ 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; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const ConstIterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(ConstIterator)
};
QCborMap() noexcept;
@@ -178,7 +235,7 @@ public:
void swap(QCborMap &other) noexcept
{
- qSwap(d, other.d);
+ d.swap(other.d);
}
QCborValue toCborValue() const { return *this; }
@@ -189,73 +246,65 @@ public:
QList<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(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
+ QCborValue value(QLatin1StringView key) const
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
QCborValue value(const QString & key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
QCborValue value(const QCborValue &key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(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_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
+ const QCborValue operator[](QLatin1StringView key) const
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
const QCborValue operator[](const QString & key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
const QCborValue operator[](const QCborValue &key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(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[](QLatin1StringView 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(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) return extract(it); return QCborValue(); }
+ QCborValue take(QLatin1StringView key)
+ { const_iterator it = constFind(key); if (!comparesEqual(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(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(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(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(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); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
+ void remove(QLatin1StringView key)
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
void remove(const QString & key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
void remove(const QCborValue &key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(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(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
+ bool contains(QLatin1StringView key) const
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
bool contains(const QString & key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
bool contains(const QCborValue &key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION;
-#if 0 && __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
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborMap &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborMap &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborMap &other) const
{ return compare(other) < 0; }
#endif
@@ -277,15 +326,15 @@ public:
bool empty() const { return isEmpty(); }
iterator find(qint64 key);
- iterator find(QLatin1String key);
+ iterator find(QLatin1StringView 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(QLatin1StringView 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(QLatin1StringView 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); }
@@ -295,7 +344,7 @@ public:
v = value_;
return { d.data(), v.i };
}
- iterator insert(QLatin1String key, const QCborValue &value_)
+ iterator insert(QLatin1StringView key, const QCborValue &value_)
{
QCborValueRef v = operator[](key); // detaches
v = value_;
@@ -324,11 +373,54 @@ public:
QJsonObject toJsonObject() const;
private:
+ friend class QCborContainerPrivate;
friend class QCborValue;
friend class QCborValueRef;
friend class QJsonPrivate::Variant;
void detach(qsizetype reserve = 0);
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborMap &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborMap &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap, QCborValue)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborMap &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap, QCborValueConstRef)
+
explicit QCborMap(QCborContainerPrivate &dd) noexcept;
QExplicitlySharedDataPointer<QCborContainerPrivate> d;
};
@@ -340,6 +432,7 @@ inline QCborValue::QCborValue(QCborMap &&m)
{
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
inline QCborMap QCborValueRef::toMap() const
{
return concrete().toMap();
@@ -349,6 +442,17 @@ inline QCborMap QCborValueRef::toMap(const QCborMap &m) const
{
return concrete().toMap(m);
}
+#endif
+
+inline QCborMap QCborValueConstRef::toMap() const
+{
+ return concrete().toMap();
+}
+
+inline QCborMap QCborValueConstRef::toMap(const QCborMap &m) const
+{
+ return concrete().toMap(m);
+}
Q_CORE_EXPORT size_t qHash(const QCborMap &map, size_t seed = 0);
diff --git a/src/corelib/serialization/qcborstream.h b/src/corelib/serialization/qcborstream.h
index f2b88820cd..7850d26663 100644
--- a/src/corelib/serialization/qcborstream.h
+++ b/src/corelib/serialization/qcborstream.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORSTREAM_H
#define QCBORSTREAM_H
diff --git a/src/corelib/serialization/qcborstreamreader.cpp b/src/corelib/serialization/qcborstreamreader.cpp
index cf90f3e397..863c24534a 100644
--- a/src/corelib/serialization/qcborstreamreader.cpp
+++ b/src/corelib/serialization/qcborstreamreader.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborstreamreader.h"
#define CBOR_NO_ENCODER_API
#include <private/qcborcommon_p.h>
-#include <private/qbytearray_p.h>
#include <private/qnumeric_p.h>
#include <private/qstringconverter_p.h>
#include <qiodevice.h>
@@ -65,6 +28,7 @@ static CborError qt_cbor_decoder_transfer_string(void *token, const void **userp
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
#include <cborparser.c>
@@ -72,13 +36,11 @@ QT_WARNING_POP
static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, CborValue *)
{
- Q_UNREACHABLE();
- return CborErrorInternalError;
+ Q_UNREACHABLE_RETURN(CborErrorInternalError);
}
[[maybe_unused]] static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
{
- Q_UNREACHABLE();
- return CborErrorInternalError;
+ Q_UNREACHABLE_RETURN(CborErrorInternalError);
}
// confirm our constants match TinyCBOR's
@@ -98,6 +60,7 @@ static_assert(int(QCborStreamReader::Invalid) == CborInvalidType);
\class QCborStreamReader
\inmodule QtCore
\ingroup cbor
+ \ingroup qtserialization
\reentrant
\since 5.12
@@ -187,7 +150,9 @@ static_assert(int(QCborStreamReader::Invalid) == CborInvalidType);
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
+ \sa QCborStreamWriter, QCborValue, QXmlStreamReader,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
@@ -565,7 +530,7 @@ public:
CborValue currentElement;
QCborError lastError = {};
- QByteArray::size_type bufferStart;
+ QByteArray::size_type bufferStart = 0;
bool corrupt = false;
QCborStreamReaderPrivate(const QByteArray &data)
@@ -653,21 +618,24 @@ public:
QByteArray *array;
QString *string;
};
- enum { ByteArray = -1, String = -3 };
+ enum Type { ByteArray = -1, String = -3, Utf8String = -5 };
qsizetype maxlen_or_type;
ReadStringChunk(char *ptr, qsizetype maxlen) : ptr(ptr), maxlen_or_type(maxlen) {}
- ReadStringChunk(QByteArray *array) : array(array), maxlen_or_type(ByteArray) {}
+ ReadStringChunk(QByteArray *array, Type type = ByteArray) : array(array), maxlen_or_type(type) {}
ReadStringChunk(QString *str) : string(str), maxlen_or_type(String) {}
bool isString() const { return maxlen_or_type == String; }
+ bool isUtf8String() const { return maxlen_or_type == Utf8String; }
bool isByteArray() const { return maxlen_or_type == ByteArray; }
bool isPlainPointer() const { return maxlen_or_type >= 0; }
};
static QCborStreamReader::StringResultCode appendStringChunk(QCborStreamReader &reader, QByteArray *data);
+ bool readFullString(ReadStringChunk params);
QCborStreamReader::StringResult<qsizetype> readStringChunk(ReadStringChunk params);
qsizetype readStringChunk_byte(ReadStringChunk params, qsizetype len);
qsizetype readStringChunk_unicode(ReadStringChunk params, qsizetype utf8len);
+ qsizetype readStringChunk_utf8(ReadStringChunk params, qsizetype utf8len);
bool ensureStringIteration();
};
@@ -717,7 +685,7 @@ static CborError qt_cbor_decoder_transfer_string(void *token, const void **userp
// (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))
+ || qAddOverflow<qsizetype>(offset, len, &total))
return CborErrorDataTooLarge;
// our string transfer is just saving the offset to the userptr
@@ -787,7 +755,7 @@ inline void QCborStreamReader::preparse()
\sa addData(), isValid()
*/
QCborStreamReader::QCborStreamReader()
- : QCborStreamReader(QByteArray())
+ : d(new QCborStreamReaderPrivate({})), type_(Invalid)
{
}
@@ -964,7 +932,7 @@ void QCborStreamReader::reset()
\sa isValid()
*/
-QCborError QCborStreamReader::lastError()
+QCborError QCborStreamReader::lastError() const
{
return d->lastError;
}
@@ -1005,7 +973,7 @@ QCborStreamReader::Type QCborStreamReader::parentContainerType() const
{
if (d->containerStack.isEmpty())
return Invalid;
- return Type(cbor_value_get_type(&qAsConst(d->containerStack).top()));
+ return Type(cbor_value_get_type(&std::as_const(d->containerStack).top()));
}
/*!
@@ -1325,16 +1293,20 @@ bool QCborStreamReader::leaveContainer()
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
+ always loop around calling this function, even if isLengthKnown()
is true. The typical use of this function is as follows:
\snippet code/src_corelib_serialization_qcborstream.cpp 27
+ The readAllString() function implements the above loop and some extra checks.
+
+//! [string-no-type-conversions]
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.
+//! [string-no-type-conversions]
- \sa readByteArray(), isString(), readStringChunk()
+ \sa readAllString(), readByteArray(), isString(), readStringChunk()
*/
QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
{
@@ -1344,7 +1316,41 @@ QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
if (r.status == Error) {
result.data.clear();
} else {
- Q_ASSERT(r.data == result.data.length());
+ Q_ASSERT(r.data == result.data.size());
+ if (r.status == EndOfString && lastError() == QCborError::NoError)
+ preparse();
+ }
+
+ return result;
+}
+
+/*!
+ \fn QCborStreamReader::StringResult<QByteArray> QCborStreamReader::readUtf8String()
+ \since 6.7
+
+ 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() is true.
+ The typical use of this function is as for readString() in the following:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 27
+
+ The readAllUtf8String() function implements the above loop and some extra checks.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \sa readAllString(), readByteArray(), isString(), readStringChunk()
+ */
+QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readUtf8String_helper()
+{
+ using P = QCborStreamReaderPrivate::ReadStringChunk;
+ QCborStreamReader::StringResult<QByteArray> result;
+ auto r = d->readStringChunk(P{ &result.data, P::Utf8String });
+ result.status = r.status;
+ if (r.status == Error) {
+ result.data.clear();
+ } else {
+ Q_ASSERT(r.data == result.data.size());
if (r.status == EndOfString && lastError() == QCborError::NoError)
preparse();
}
@@ -1357,16 +1363,20 @@ QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
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
+ always loop around calling this function, even if isLengthKnown()
is true. The typical use of this function is as follows:
\snippet code/src_corelib_serialization_qcborstream.cpp 28
+ The readAllByteArray() function implements the above loop and some extra checks.
+
+//! [bytearray-no-type-conversions]
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.
+//! [bytearray-no-type-conversions]
- \sa readString(), isByteArray(), readStringChunk()
+ \sa readAllByteArray(), readString(), isByteArray(), readStringChunk()
*/
QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_helper()
{
@@ -1376,7 +1386,7 @@ QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_he
if (r.status == Error) {
result.data.clear();
} else {
- Q_ASSERT(r.data == result.data.length());
+ Q_ASSERT(r.data == result.data.size());
if (r.status == EndOfString && lastError() == QCborError::NoError)
preparse();
}
@@ -1415,6 +1425,147 @@ qsizetype QCborStreamReader::_currentStringChunkSize() const
return -1;
}
+bool QCborStreamReaderPrivate::readFullString(ReadStringChunk params)
+{
+ auto r = readStringChunk(params);
+ while (r.status == QCborStreamReader::Ok) {
+ // keep appending
+ r = readStringChunk(params);
+ }
+
+ bool ok = r.status == QCborStreamReader::EndOfString;
+ Q_ASSERT(ok == !lastError);
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllString()
+ \since 6.7
+
+ Decodes the current text string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QString(), but
+ that may not be distinguishable from certain empty text strings. Instead,
+ check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+//! [note-not-restartable]
+ \note This function cannot be resumed. That is, this function should not
+ be used in contexts where the CBOR data may still be received, for example
+ from a socket or pipe. It should only be used when the full data has
+ already been received and is available in the input QByteArray or
+ QIODevice.
+//! [note-not-restartable]
+
+ \sa readString(), readStringChunk(), isString(), readAllByteArray()
+ */
+/*!
+ \fn QCborStreamReader::readAndAppendToString(QString &dst)
+ \since 6.7
+
+ Decodes the current text string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
+ */
+bool QCborStreamReader::_readAndAppendToString_helper(QString &dst)
+{
+ bool ok = d->readFullString(&dst);
+ if (ok)
+ preparse();
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllUtf8String()
+ \since 6.7
+
+ Decodes the current text string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QString(), but
+ that may not be distinguishable from certain empty text strings. Instead,
+ check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAllByteArray()
+ */
+/*!
+ \fn QCborStreamReader::readAndAppendToUtf8String(QByteArray &dst)
+ \since 6.7
+
+ Decodes the current text string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
+ */
+bool QCborStreamReader::_readAndAppendToUtf8String_helper(QByteArray &dst)
+{
+ using P = QCborStreamReaderPrivate::ReadStringChunk;
+ bool ok = d->readFullString({ &dst, P::Utf8String });
+ if (ok)
+ preparse();
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllByteArray()
+ \since 6.7
+
+ Decodes the current byte string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QByteArray(),
+ but that may not be distinguishable from certain empty byte strings.
+ Instead, check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp bytearray-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readByteArray(), readStringChunk(), isByteArray(), readAllString()
+ */
+
+/*!
+ \fn QCborStreamReader::readAndAppendToByteArray(QByteArray &dst)
+ \since 6.7
+
+ Decodes the current byte string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp bytearray-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readByteArray(), readStringChunk(), isByteArray(), readAndAppendToString()
+ */
+bool QCborStreamReader::_readAndAppendToByteArray_helper(QByteArray &dst)
+{
+ bool ok = d->readFullString(&dst);
+ if (ok)
+ preparse();
+ return ok;
+}
+
/*!
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
@@ -1487,6 +1638,12 @@ QCborStreamReaderPrivate::readStringChunk(ReadStringChunk params)
// qt_cbor_decoder_transfer_string() enforces that
// QIODevice::bytesAvailable() be bigger than the amount we're about to
// read.
+ //
+ // This is an important security gate: if the CBOR stream is corrupt or
+ // malicious, and has an impossibly large string size, we only go past it
+ // if the transfer to the destination buffer will succeed (modulo QIODevice
+ // I/O failures).
+
#if 1
// Using internal TinyCBOR API!
err = _cbor_value_get_string_chunk(&currentElement, &content, &len, &currentElement);
@@ -1529,6 +1686,8 @@ QCborStreamReaderPrivate::readStringChunk(ReadStringChunk params)
if (params.isString()) {
// readString()
result.data = readStringChunk_unicode(params, qsizetype(len));
+ } else if (params.isUtf8String()) {
+ result.data = readStringChunk_utf8(params, qsizetype(len));
} else {
// readByteArray() or readStringChunk()
result.data = readStringChunk_byte(params, qsizetype(len));
@@ -1575,11 +1734,11 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
else
toRead = params.maxlen_or_type; // buffer smaller than string
ptr = params.ptr;
- } else if (params.isByteArray()) {
+ } else if (!params.isString()) {
// See note above on having ensured there is enough incoming data.
auto oldSize = params.array->size();
auto newSize = oldSize;
- if (add_overflow<decltype(newSize)>(oldSize, toRead, &newSize)) {
+ if (qAddOverflow<decltype(newSize)>(oldSize, toRead, &newSize)) {
handleError(CborErrorDataTooLarge);
return -1;
}
@@ -1589,7 +1748,7 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
// the distinction between DataTooLarge and OOM is mostly for
// compatibility with Qt 5; in Qt 6, we could consider everything
// to be OOM.
- handleError(newSize > MaxByteArraySize ? CborErrorDataTooLarge: CborErrorOutOfMemory);
+ handleError(newSize > QByteArray::max_size() ? CborErrorDataTooLarge: CborErrorOutOfMemory);
return -1;
}
@@ -1622,24 +1781,25 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
inline qsizetype
QCborStreamReaderPrivate::readStringChunk_unicode(ReadStringChunk params, qsizetype utf8len)
{
+ Q_ASSERT(params.isString());
+
// See QUtf8::convertToUnicode() a detailed explanation of why this
// conversion uses the same number of words or less.
- QChar *begin = nullptr;
- if (params.isString()) {
- QT_TRY {
- params.string->resize(utf8len);
- } QT_CATCH (const std::bad_alloc &) {
- if (utf8len > MaxStringSize)
- handleError(CborErrorDataTooLarge);
- else
- handleError(CborErrorOutOfMemory);
- return -1;
- }
-
- begin = const_cast<QChar *>(params.string->constData());
+ qsizetype currentSize = params.string->size();
+ size_t newSize = size_t(utf8len) + size_t(currentSize); // can't overflow
+ if (utf8len > QString::max_size() || qsizetype(newSize) < 0) {
+ handleError(CborErrorDataTooLarge);
+ return -1;
+ }
+ QT_TRY {
+ params.string->resize(qsizetype(newSize));
+ } QT_CATCH (const std::bad_alloc &) {
+ handleError(CborErrorOutOfMemory);
+ return -1;
}
- QChar *ptr = begin;
+ QChar *begin = const_cast<QChar *>(params.string->constData());
+ QChar *ptr = begin + currentSize;
QStringConverter::State cs(QStringConverter::Flag::Stateless);
if (device == nullptr) {
// Easy case: we can decode straight from the buffer we already have
@@ -1671,9 +1831,25 @@ QCborStreamReaderPrivate::readStringChunk_unicode(ReadStringChunk params, qsizet
}
qsizetype size = ptr - begin;
- if (params.isString())
- params.string->truncate(size);
- return size;
+ params.string->truncate(ptr - begin);
+ return size - currentSize; // how many bytes we added
+}
+
+inline qsizetype
+QCborStreamReaderPrivate::readStringChunk_utf8(ReadStringChunk params, qsizetype utf8len)
+{
+ qsizetype result = readStringChunk_byte(params, utf8len);
+ if (result < 0)
+ return result;
+
+ // validate the UTF-8 content we've just read
+ QByteArrayView chunk = *params.array;
+ chunk = chunk.last(result);
+ if (QtPrivate::isValidUtf8(chunk))
+ return result;
+
+ handleError(CborErrorInvalidUtf8TextString);
+ return -1;
}
QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcborstreamreader.h b/src/corelib/serialization/qcborstreamreader.h
index 3665b09ea8..2666b7c7b2 100644
--- a/src/corelib/serialization/qcborstreamreader.h
+++ b/src/corelib/serialization/qcborstreamreader.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORSTREAMREADER_H
#define QCBORSTREAMREADER_H
@@ -113,7 +77,10 @@ public:
void clear();
void reset();
+#if QT_CORE_REMOVED_SINCE(6, 7)
QCborError lastError();
+#endif
+ QCborError lastError() const;
qint64 currentOffset() const;
@@ -153,7 +120,14 @@ public:
bool enterContainer() { Q_ASSERT(isContainer()); return _enterContainer_helper(); }
bool leaveContainer();
+ bool readAndAppendToString(QString &dst)
+ { Q_ASSERT(isString()); return _readAndAppendToString_helper(dst); }
+ bool readAndAppendToUtf8String(QByteArray &dst)
+ { Q_ASSERT(isString()); return _readAndAppendToUtf8String_helper(dst); }
+ bool readAndAppendToByteArray(QByteArray &dst)
+ { Q_ASSERT(isByteArray()); return _readAndAppendToByteArray_helper(dst); }
StringResult<QString> readString() { Q_ASSERT(isString()); return _readString_helper(); }
+ StringResult<QByteArray> readUtf8String() { Q_ASSERT(isString()); return _readUtf8String_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);
@@ -175,13 +149,38 @@ public:
return -v - 1;
return v;
}
+ QString readAllString()
+ {
+ QString dst;
+ if (!readAndAppendToString(dst))
+ dst = QString{};
+ return dst;
+ }
+ QByteArray readAllUtf8String()
+ {
+ QByteArray dst;
+ if (!readAndAppendToUtf8String(dst))
+ dst = QByteArray{};
+ return dst;
+ }
+ QByteArray readAllByteArray()
+ {
+ QByteArray dst;
+ if (!readAndAppendToByteArray(dst))
+ dst = QByteArray{};
+ return dst;
+ }
private:
void preparse();
bool _enterContainer_helper();
StringResult<QString> _readString_helper();
+ StringResult<QByteArray> _readUtf8String_helper();
StringResult<QByteArray> _readByteArray_helper();
qsizetype _currentStringChunkSize() const;
+ bool _readAndAppendToString_helper(QString &);
+ bool _readAndAppendToUtf8String_helper(QByteArray &);
+ bool _readAndAppendToByteArray_helper(QByteArray &);
template <typename FP> FP _toFloatingPoint() const noexcept
{
diff --git a/src/corelib/serialization/qcborstreamwriter.cpp b/src/corelib/serialization/qcborstreamwriter.cpp
index d3c0066cca..7b5099567e 100644
--- a/src/corelib/serialization/qcborstreamwriter.cpp
+++ b/src/corelib/serialization/qcborstreamwriter.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborstreamwriter.h"
@@ -43,9 +7,11 @@
#include <private/qcborcommon_p.h>
#include <private/qnumeric_p.h>
+#include <private/qstringconverter_p.h>
#include <qbuffer.h>
#include <qdebug.h>
#include <qstack.h>
+#include <qvarlengtharray.h>
QT_BEGIN_NAMESPACE
@@ -65,14 +31,12 @@ QT_WARNING_POP
// but never defined
[[maybe_unused]] static CborError cbor_encoder_close_container_checked(CborEncoder*, const CborEncoder*)
{
- Q_UNREACHABLE();
- return CborErrorInternalError;
+ Q_UNREACHABLE_RETURN(CborErrorInternalError);
}
[[maybe_unused]] static CborError cbor_encode_float_as_half_float(CborEncoder *, float)
{
- Q_UNREACHABLE();
- return CborErrorInternalError;
+ Q_UNREACHABLE_RETURN(CborErrorInternalError);
}
Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
@@ -81,6 +45,7 @@ Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
\class QCborStreamWriter
\inmodule QtCore
\ingroup cbor
+ \ingroup qtserialization
\reentrant
\since 5.12
@@ -211,6 +176,8 @@ Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
\endlist
\sa QCborStreamReader, QCborValue, QXmlStreamWriter
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
class QCborStreamWriterPrivate
@@ -449,11 +416,11 @@ void QCborStreamWriter::append(QCborNegativeInteger n)
/*!
\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.
+ Appends the Latin-1 string viewed by \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:
+ The following example appends a simple Latin-1 string literal to the stream:
\snippet code/src_corelib_serialization_qcborstream.cpp 8
@@ -466,7 +433,7 @@ void QCborStreamWriter::append(QCborNegativeInteger n)
\sa QCborStreamReader::isString(), QCborStreamReader::readString()
*/
-void QCborStreamWriter::append(QLatin1String str)
+void QCborStreamWriter::append(QLatin1StringView str)
{
// We've got Latin-1 but CBOR wants UTF-8, so check if the string is the
// common subset (US-ASCII).
@@ -474,8 +441,10 @@ void QCborStreamWriter::append(QLatin1String 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));
+ // non-ASCII, convert:
+ QVarLengthArray<char> utf8(str.size() * 2); // each L1 char gives at most two U8 units
+ const qsizetype written = QUtf8::convertFromLatin1(utf8.data(), str) - utf8.data();
+ appendTextString(utf8.data(), written);
}
}
@@ -639,11 +608,11 @@ void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
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
+ Unlike the QLatin1StringView 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),
+ \sa append(QLatin1StringView), append(QStringView),
QCborStreamReader::isString(), QCborStreamReader::readString()
*/
void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
@@ -663,11 +632,11 @@ void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
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
+ Unlike the QLatin1StringView 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),
+ \sa append(QLatin1StringView), append(QStringView),
QCborStreamReader::isString(), QCborStreamReader::readString()
*/
@@ -762,7 +731,8 @@ void QCborStreamWriter::startArray()
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.
+ QCborArray is currently limited to 2\sup{27} elements on 32-bit platforms and
+ 2\sup{59} elements on 64-bit ones.
\sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
QCborStreamReader::isLengthKnown()
@@ -835,7 +805,8 @@ void QCborStreamWriter::startMap()
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.
+ QCborMap is currently limited to 2\sup{26} elements on 32-bit platforms and
+ 2\sup{58} on 64-bit ones.
\sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
QCborStreamReader::isLengthKnown()
@@ -865,3 +836,7 @@ bool QCborStreamWriter::endMap()
}
QT_END_NAMESPACE
+
+#undef CBOR_ENCODER_WRITER_CONTROL
+#undef CBOR_ENCODER_WRITE_FUNCTION
+#undef CBOR_ENCODER_NO_CHECK_USER
diff --git a/src/corelib/serialization/qcborstreamwriter.h b/src/corelib/serialization/qcborstreamwriter.h
index 9c2f9e81ab..1018646c99 100644
--- a/src/corelib/serialization/qcborstreamwriter.h
+++ b/src/corelib/serialization/qcborstreamwriter.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORSTREAMWRITER_H
#define QCBORSTREAMWRITER_H
@@ -77,7 +41,7 @@ public:
void append(qint64 i);
void append(QCborNegativeInteger n);
void append(const QByteArray &ba) { appendByteString(ba.constData(), ba.size()); }
- void append(QLatin1String str);
+ void append(QLatin1StringView str);
void append(QStringView str);
void append(QCborTag tag);
void append(QCborKnownTags tag) { append(QCborTag(tag)); }
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index 562f363869..cd0b842111 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborvalue.h"
#include "qcborvalue_p.h"
@@ -53,7 +17,8 @@
#include <qendian.h>
#include <qlocale.h>
-#include <private/qbytearray_p.h>
+#include <qdatetime.h>
+#include <qtimezone.h>
#include <private/qnumeric_p.h>
#include <private/qsimd_p.h>
@@ -61,15 +26,33 @@
QT_BEGIN_NAMESPACE
+// Worst case memory allocation for a corrupt stream: 256 MB for 32-bit, 1 GB for 64-bit
+static constexpr quint64 MaxAcceptableMemoryUse = (sizeof(void*) == 4 ? 256 : 1024) * 1024 * 1024;
+
+// Internal limits to ensure we don't blow up the memory when parsing a corrupt
+// (possibly crafted to exploit) CBOR stream. The recursion impacts both the
+// maps/arrays we'll open when parsing and the thread's stack, as the parser is
+// itself recursive. If someone really needs more than 1024 layers of nesting,
+// they probably have a weird use-case for which custom parsing and
+// serialisation code would make sense. The limit on element count is the
+// preallocated limit: if the stream does actually have more elements, we will
+// grow the container.
+Q_DECL_UNUSED static constexpr int MaximumRecursionDepth = 1024;
+Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
+ MaxAcceptableMemoryUse / MaximumRecursionDepth / sizeof(QtCbor::Element) - 1;
+
/*!
\class QCborValue
\inmodule QtCore
\ingroup cbor
+ \ingroup qtserialization
\reentrant
\since 5.12
\brief The QCborValue class encapsulates a value in CBOR.
+ \compares strong
+
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
@@ -209,8 +192,9 @@ QT_BEGIN_NAMESPACE
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
+ \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter,
+ QJsonValue, QJsonDocument, {Serialization Converter}, {Saving and Loading a Game}
+ {Parsing and displaying CBOR data}
*/
/*!
@@ -421,7 +405,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QCborValue::QCborValue(QCborSimpleType st)
- Creates a QCborValue of simple type \a st. The type can later later be retrieved
+ Creates a QCborValue of simple type \a st. The type can later be retrieved
using toSimpleType() as well as isSimpleType(st).
CBOR simple types are types that do not have any associated value, like
@@ -766,6 +750,17 @@ QT_BEGIN_NAMESPACE
using namespace QtCbor;
+static QCborContainerPrivate *assignContainer(QCborContainerPrivate *&d, QCborContainerPrivate *x)
+{
+ if (d == x)
+ return d;
+ if (d)
+ d->deref();
+ if (x)
+ x->ref.ref();
+ return d = x;
+}
+
static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
{
qint64 tag = d->elements.at(0).value;
@@ -793,9 +788,9 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
bool ok = false;
if (e.type == QCborValue::Integer) {
#if QT_POINTER_SIZE == 8
- // we don't have a fast 64-bit mul_overflow implementation on
+ // we don't have a fast 64-bit qMulOverflow implementation on
// 32-bit architectures.
- ok = !mul_overflow(e.value, qint64(1000), &msecs);
+ ok = !qMulOverflow(e.value, qint64(1000), &msecs);
#else
static const qint64 Limit = std::numeric_limits<qint64>::max() / 1000;
ok = (e.value > -Limit && e.value < Limit);
@@ -806,7 +801,7 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
ok = convertDoubleTo(round(e.fpvalue() * 1000), &msecs);
}
if (ok)
- dt = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
+ dt = QDateTime::fromMSecsSinceEpoch(msecs, QTimeZone::UTC);
}
if (dt.isValid()) {
QByteArray text = dt.toString(Qt::ISODateWithMs).toLatin1();
@@ -895,7 +890,7 @@ static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::E
// no data loss, we could use float
#ifndef QT_BOOTSTRAPPED
if ((opt & QCborValue::UseFloat16) == QCborValue::UseFloat16) {
- qfloat16 f16 = f;
+ qfloat16 f16 = qfloat16(f);
if (f16 == f)
return writer.append(f16);
}
@@ -909,12 +904,12 @@ static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::E
}
#endif // QT_CONFIG(cborstreamwriter)
-static inline int typeOrder(Element e1, Element e2)
+static inline int typeOrder(QCborValue::Type e1, QCborValue::Type e2)
{
- auto comparable = [](Element e) {
- if (e.type >= 0x10000) // see QCborValue::isTag_helper()
+ auto comparable = [](QCborValue::Type type) {
+ if (type >= 0x10000) // see QCborValue::isTag_helper()
return QCborValue::Tag;
- return e.type;
+ return type;
};
return comparable(e1) - comparable(e2);
}
@@ -928,14 +923,24 @@ QCborContainerPrivate::~QCborContainerPrivate()
}
}
-void QCborContainerPrivate::compact(qsizetype reserved)
+void QCborContainerPrivate::compact()
{
if (usedData > data.size() / 2)
return;
// 50% savings if we recreate the byte data
- // ### TBD
- Q_UNUSED(reserved);
+ QByteArray newData;
+ QByteArray::size_type newUsedData = 0;
+ // Compact only elements that have byte data.
+ // Nested containers will be compacted when their data changes.
+ for (auto &e : elements) {
+ if (e.flags & Element::HasByteData) {
+ if (const ByteData *b = byteData(e))
+ e.value = addByteDataImpl(newData, newUsedData, b->byte(), b->len);
+ }
+ }
+ data = newData;
+ usedData = newUsedData;
}
QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qsizetype reserved)
@@ -943,12 +948,17 @@ QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qs
if (!d) {
d = new QCborContainerPrivate;
} else {
- d = new QCborContainerPrivate(*d);
+ // in case QList::reserve throws
+ QExplicitlySharedDataPointer u(new QCborContainerPrivate(*d));
if (reserved >= 0) {
- d->elements.reserve(reserved);
- d->compact(reserved);
+ u->elements.reserve(reserved);
+ u->compact();
}
- for (auto &e : qAsConst(d->elements)) {
+
+ d = u.take();
+ d->ref.storeRelaxed(0);
+
+ for (auto &e : std::as_const(d->elements)) {
if (e.flags & Element::IsContainer)
e.container->ref.ref();
}
@@ -974,7 +984,7 @@ QCborContainerPrivate *QCborContainerPrivate::grow(QCborContainerPrivate *d, qsi
Q_ASSERT(index >= 0);
d = detach(d, index + 1);
Q_ASSERT(d);
- int j = d->elements.size();
+ qsizetype j = d->elements.size();
while (j++ < index)
d->append(Undefined());
return d;
@@ -1014,10 +1024,23 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu
// Copy string data, if any
if (const ByteData *b = value.container->byteData(value.n)) {
- if (this == value.container)
- e.value = addByteData(b->toByteArray(), b->len);
- else
+ const auto flags = e.flags;
+ // The element e has an invalid e.value, because it is copied from
+ // value. It means that calling compact() will trigger an assertion
+ // or just silently corrupt the data.
+ // Temporarily unset the Element::HasByteData flag in order to skip
+ // the element e in the call to compact().
+ e.flags = e.flags & ~Element::HasByteData;
+ if (this == value.container) {
+ const QByteArray valueData = b->toByteArray();
+ compact();
+ e.value = addByteData(valueData, valueData.size());
+ } else {
+ compact();
e.value = addByteData(b->byte(), b->len);
+ }
+ // restore the flags
+ e.flags = flags;
}
if (disp == MoveContainer)
@@ -1042,6 +1065,12 @@ Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s)
qt_to_latin1_unchecked(l, s.utf16(), len);
}
+void QCborContainerPrivate::appendNonAsciiString(QStringView s)
+{
+ appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
+ QCborValue::String, QtCbor::Element::StringIsUtf16);
+}
+
QCborValue QCborContainerPrivate::extractAt_complex(Element e)
{
// create a new container for the returned value, containing the byte data
@@ -1054,7 +1083,7 @@ QCborValue QCborContainerPrivate::extractAt_complex(Element e)
// 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());
+ compact();
} else {
// just share with the original byte data
container->data = data;
@@ -1065,9 +1094,127 @@ QCborValue QCborContainerPrivate::extractAt_complex(Element e)
return makeValue(e.type, 0, container);
}
+// Similar to QStringIterator::next() but returns malformed surrogate pair
+// itself when one is detected, and returns the length in UTF-8.
+static auto nextUtf32Character(const char16_t *&ptr, const char16_t *end) noexcept
+{
+ Q_ASSERT(ptr != end);
+ struct R {
+ char32_t c;
+ qsizetype len = 1; // in UTF-8 code units (bytes)
+ } r = { *ptr++ };
+
+ if (r.c < 0x0800) {
+ if (r.c >= 0x0080)
+ ++r.len;
+ } else if (!QChar::isHighSurrogate(r.c) || ptr == end) {
+ r.len += 2;
+ } else {
+ r.len += 3;
+ r.c = QChar::surrogateToUcs4(r.c, *ptr++);
+ }
+
+ return r;
+}
+
+static qsizetype stringLengthInUtf8(const char16_t *ptr, const char16_t *end) noexcept
+{
+ qsizetype len = 0;
+ while (ptr < end)
+ len += nextUtf32Character(ptr, end).len;
+ return len;
+}
+
+static int compareStringsInUtf8(QStringView lhs, QStringView rhs, Comparison mode) noexcept
+{
+ if (mode == Comparison::ForEquality)
+ return lhs == rhs ? 0 : 1;
+
+ // The UTF-16 length is *usually* comparable, but not always. There are
+ // pathological cases where they can be wrong, so we need to compare as if
+ // we were doing it in UTF-8. That includes the case of UTF-16 surrogate
+ // pairs, because qstring.cpp sorts them before U+E000-U+FFFF.
+ int diff = 0;
+ qsizetype len1 = 0;
+ qsizetype len2 = 0;
+ const char16_t *src1 = lhs.utf16();
+ const char16_t *src2 = rhs.utf16();
+ const char16_t *end1 = src1 + lhs.size();
+ const char16_t *end2 = src2 + rhs.size();
+
+ // first, scan until we find a difference (if any)
+ do {
+ auto r1 = nextUtf32Character(src1, end1);
+ auto r2 = nextUtf32Character(src2, end2);
+ len1 += r1.len;
+ len2 += r2.len;
+ diff = int(r1.c) - int(r2.c); // no underflow due to limited range
+ } while (src1 < end1 && src2 < end2 && diff == 0);
+
+ // compute the full length past this first difference
+ len1 += stringLengthInUtf8(src1, end1);
+ len2 += stringLengthInUtf8(src2, end2);
+ if (len1 == len2)
+ return diff;
+ return len1 < len2 ? -1 : 1;
+}
+
+static int compareStringsInUtf8(QUtf8StringView lhs, QStringView rhs, Comparison mode) noexcept
+{
+ // CBOR requires that the shortest of the two strings be sorted first, so
+ // we have to calculate the UTF-8 length of the UTF-16 string while
+ // comparing. Unlike the UTF-32 comparison above, we convert the UTF-16
+ // string to UTF-8 so we only need to decode one string.
+
+ const qsizetype len1 = lhs.size();
+ const auto src1 = reinterpret_cast<const uchar *>(lhs.data());
+ const char16_t *src2 = rhs.utf16();
+ const char16_t *const end2 = src2 + rhs.size();
+
+ // Compare the two strings until we find a difference.
+ int diff = 0;
+ qptrdiff idx1 = 0;
+ qsizetype len2 = 0;
+ do {
+ uchar utf8[4]; // longest possible Unicode character in UTF-8
+ uchar *ptr = utf8;
+ char16_t uc = *src2++;
+ int r = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, ptr, src2, end2);
+ Q_UNUSED(r); // ignore failure to encode proper UTF-16 surrogates
+
+ qptrdiff n = ptr - utf8;
+ len2 += n;
+ if (len1 - idx1 < n)
+ return -1; // lhs is definitely shorter
+ diff = memcmp(src1 + idx1, utf8, n);
+ idx1 += n;
+ } while (diff == 0 && idx1 < len1 && src2 < end2);
+
+ if (mode == Comparison::ForEquality && diff)
+ return diff;
+ if ((idx1 == len1) != (src2 == end2)) {
+ // One of the strings ended earlier than the other
+ return idx1 == len1 ? -1 : 1;
+ }
+
+ // We found a difference and neither string ended, so continue calculating
+ // the UTF-8 length of rhs.
+ len2 += stringLengthInUtf8(src2, end2);
+
+ if (len1 != len2)
+ return len1 < len2 ? -1 : 1;
+ return diff;
+}
+
+static int compareStringsInUtf8(QStringView lhs, QUtf8StringView rhs, Comparison mode) noexcept
+{
+ return -compareStringsInUtf8(rhs, lhs, mode);
+}
+
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)
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
+ Comparison mode) noexcept;
+static int compareElementNoData(const Element &e1, const Element &e2) noexcept
{
Q_ASSERT(e1.type == e2.type);
@@ -1111,15 +1258,16 @@ static int compareElementNoData(const Element &e1, const Element &e2)
}
static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1,
- const QCborContainerPrivate *c2, const Element &e2)
+ const QCborContainerPrivate *c2, const Element &e2,
+ Comparison mode) noexcept
{
- int cmp = typeOrder(e1, e2);
+ int cmp = typeOrder(e1.type, e2.type);
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);
+ e2.flags & Element::IsContainer ? e2.container : nullptr, mode);
// string data?
const ByteData *b1 = c1 ? c1->byteData(e1) : nullptr;
@@ -1127,11 +1275,6 @@ static int compareElementRecursive(const QCborContainerPrivate *c1, const Elemen
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;
@@ -1140,58 +1283,37 @@ static int compareElementRecursive(const QCborContainerPrivate *c1, const Elemen
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;
- }
+ // UTF-8 length. Since US-ASCII is just a subset of UTF-8, its length
+ // is the UTF-8 length. But the UTF-16 length may not be directly
+ // comparable.
+ if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16))
+ return compareStringsInUtf8(b1->asStringView(), b2->asStringView(), mode);
if (!(e1.flags & Element::StringIsUtf16) && !(e2.flags & Element::StringIsUtf16)) {
- // Cases 4, 5 and 6: neither is UTF-16, so lengths are comparable too
+ // Neither is UTF-16, so lengths are comparable too
// (this case includes byte arrays too)
- if (len1 == len2)
+ if (len1 == len2) {
+ if (mode == Comparison::ForEquality) {
+ // GCC optimizes this to __memcmpeq(); Clang to bcmp()
+ return memcmp(b1->byte(), b2->byte(), size_t(len1)) == 0 ? 0 : 1;
+ }
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...
- // (we can't use QUtf8::compareUtf8 because we need to compare lengths)
- 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;
+ // Only one is UTF-16
if (e1.flags & Element::StringIsUtf16)
- return QtPrivate::compareStrings(b1->asStringView(), b2->asLatin1());
- return QtPrivate::compareStrings(b1->asLatin1(), b2->asStringView());
+ return compareStringsInUtf8(b1->asStringView(), b2->asUtf8StringView(), mode);
+ else
+ return compareStringsInUtf8(b1->asUtf8StringView(), b2->asStringView(), mode);
}
return compareElementNoData(e1, e2);
}
-static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2)
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
+ Comparison mode) noexcept
{
auto len1 = c1 ? c1->elements.size() : 0;
auto len2 = c2 ? c2->elements.size() : 0;
@@ -1203,7 +1325,7 @@ static int compareContainer(const QCborContainerPrivate *c1, const QCborContaine
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);
+ int cmp = compareElementRecursive(c1, e1, c2, e2, mode);
if (cmp)
return cmp;
}
@@ -1212,15 +1334,16 @@ static int compareContainer(const QCborContainerPrivate *c1, const QCborContaine
}
inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPrivate *c1, Element e1,
- const QCborContainerPrivate *c2, Element e2)
+ const QCborContainerPrivate *c2, Element e2,
+ Comparison mode) noexcept
{
- return compareElementRecursive(c1, e1, c2, e2);
+ return compareElementRecursive(c1, e1, c2, e2, mode);
}
/*!
- \fn bool QCborValue::operator==(const QCborValue &other) const
+ \fn bool QCborValue::operator==(const QCborValue &lhs, const QCborValue &rhs)
- Compares this value and \a other, and returns true if they hold the same
+ Compares \a lhs and \a rhs, 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.
@@ -1231,9 +1354,9 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
*/
/*!
- \fn bool QCborValue::operator!=(const QCborValue &other) const
+ \fn bool QCborValue::operator!=(const QCborValue &lhs, const QCborValue &rhs)
- Compares this value and \a other, and returns true if contents differ,
+ Compares \a lhs and \a rhs, 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.
@@ -1242,12 +1365,20 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
\sa compare(), QCborValue::operator==(), QCborMap::operator==(),
operator==(), operator<()
*/
+bool comparesEqual(const QCborValue &lhs,
+ const QCborValue &rhs) noexcept
+{
+ Element e1 = QCborContainerPrivate::elementFromValue(lhs);
+ Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ return compareElementRecursive(lhs.container, e1, rhs.container, e2,
+ Comparison::ForEquality) == 0;
+}
/*!
- \fn bool QCborValue::operator<(const QCborValue &other) const
+ \fn bool QCborValue::operator<(const QCborValue &lhs, const QCborValue &rhs)
- 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
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted before \a rhs, 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().
@@ -1257,6 +1388,47 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
*/
/*!
+ \fn bool QCborValue::operator<=(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted before \a rhs or is being equal to \a rhs, 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!=()
+*/
+
+/*!
+ \fn bool QCborValue::operator>(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted after \a rhs, 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!=()
+*/
+
+/*!
+ \fn bool QCborValue::operator>=(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted after \a rhs or is being equal to \a rhs, 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
@@ -1321,17 +1493,59 @@ int QCborValue::compare(const QCborValue &other) const
{
Element e1 = QCborContainerPrivate::elementFromValue(*this);
Element e2 = QCborContainerPrivate::elementFromValue(other);
- return compareElementRecursive(container, e1, other.container, e2);
+ return compareElementRecursive(container, e1, other.container, e2, Comparison::ForOrdering);
+}
+
+bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
+{
+ return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
}
int QCborArray::compare(const QCborArray &other) const noexcept
{
- return compareContainer(d.data(), other.d.data());
+ return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
+}
+
+bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
+{
+ if (typeOrder(QCborValue::Array, rhs.type()))
+ return false;
+ return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
+{
+ int c = typeOrder(QCborValue::Array, rhs.type());
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
+{
+ return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
}
int QCborMap::compare(const QCborMap &other) const noexcept
{
- return compareContainer(d.data(), other.d.data());
+ return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
+}
+
+bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
+{
+ if (typeOrder(QCborValue::Map, rhs.type()))
+ return false;
+ return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
+{
+ int c = typeOrder(QCborValue::Map, rhs.type());
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
}
#if QT_CONFIG(cborstreamwriter)
@@ -1384,7 +1598,7 @@ static void encodeToCbor(QCborStreamWriter &writer, const QCborContainerPrivate
return writer.append(b->asStringView());
return writer.appendTextString(b->byte(), b->len);
}
- return writer.append(QLatin1String());
+ return writer.append(QLatin1StringView());
case QCborValue::Array:
case QCborValue::Map:
@@ -1483,6 +1697,19 @@ static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
return e;
}
+// Clamp allocation to avoid crashing due to corrupt stream. This also
+// ensures we never overflow qsizetype. The returned length is doubled for Map
+// entries to account for key-value pairs.
+static qsizetype clampedContainerLength(const QCborStreamReader &reader)
+{
+ if (!reader.isLengthKnown())
+ return 0;
+ int mapShift = reader.isMap() ? 1 : 0;
+ quint64 shiftedMaxElements = MaximumPreallocatedElementCount >> mapShift;
+ qsizetype len = qsizetype(qMin(reader.length(), shiftedMaxElements));
+ return len << mapShift;
+}
+
static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{
if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
@@ -1491,33 +1718,27 @@ static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &
}
QCborContainerPrivate *d = nullptr;
- 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
- // QList::size_type).
- len = qMin(len, quint64(1024 * 1024 - 1));
- if (len) {
- d = new QCborContainerPrivate;
- d->ref.storeRelaxed(1);
- d->elements.reserve(qsizetype(len) << mapShift);
- }
- } else {
- d = new QCborContainerPrivate;
- d->ref.storeRelaxed(1);
+ {
+ // in case QList::reserve throws
+ QExplicitlySharedDataPointer u(new QCborContainerPrivate);
+ if (qsizetype len = clampedContainerLength(reader))
+ u->elements.reserve(len);
+ d = u.take();
}
reader.enterContainer();
- if (reader.lastError() != QCborError::NoError)
+ if (reader.lastError() != QCborError::NoError) {
+ d->elements.clear();
return d;
+ }
while (reader.hasNext() && reader.lastError() == QCborError::NoError)
d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
if (reader.lastError() == QCborError::NoError)
reader.leaveContainer();
+ else
+ d->elements.squeeze();
return d;
}
@@ -1587,7 +1808,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// add space for aligned ByteData (this can't overflow)
offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
offset &= ~(alignof(QtCbor::ByteData) - 1);
- if (offset > size_t(MaxByteArraySize)) {
+ if (offset > size_t(QByteArray::max_size())) {
// overflow
setErrorInReader(reader, { QCborError::DataTooLarge });
return;
@@ -1600,9 +1821,9 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// so capa how much we allocate
newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
}
- if (newCapacity > size_t(MaxByteArraySize)) {
+ if (newCapacity > size_t(QByteArray::max_size())) {
// this may cause an allocation failure
- newCapacity = MaxByteArraySize;
+ newCapacity = QByteArray::max_size();
}
if (newCapacity > size_t(data.capacity()))
data.reserve(newCapacity);
@@ -1653,7 +1874,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// check that this UTF-8 text string can be loaded onto a QString
if (e.type == QCborValue::String) {
- if (Q_UNLIKELY(b->len > MaxStringSize)) {
+ if (Q_UNLIKELY(b->len > QString::max_size())) {
setErrorInReader(reader, { QCborError::DataTooLarge });
status = QCborStreamReader::Error;
}
@@ -1713,7 +1934,6 @@ QCborValue::QCborValue(const QByteArray &ba)
container->ref.storeRelaxed(1);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Creates a QCborValue with string value \a s. The value can later be
retrieved using toString().
@@ -1721,7 +1941,6 @@ QCborValue::QCborValue(const QByteArray &ba)
\sa toString(), isString(), isByteArray()
*/
QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {}
-#endif
/*!
Creates a QCborValue with string value \a s. The value can later be
@@ -1739,12 +1958,12 @@ QCborValue::QCborValue(QStringView s)
/*!
\overload
- Creates a QCborValue with string value \a s. The value can later be
- retrieved using toString().
+ Creates a QCborValue with the Latin-1 string viewed by \a s.
+ The value can later be retrieved using toString().
\sa toString(), isString(), isByteArray()
*/
-QCborValue::QCborValue(QLatin1String s)
+QCborValue::QCborValue(QLatin1StringView s)
: n(0), container(new QCborContainerPrivate), t(String)
{
container->append(s);
@@ -1805,7 +2024,7 @@ QCborValue::QCborValue(QCborTag tag, const QCborValue &tv)
/*!
Copies the contents of \a other into this object.
*/
-QCborValue::QCborValue(const QCborValue &other)
+QCborValue::QCborValue(const QCborValue &other) noexcept
: n(other.n), container(other.container), t(other.t)
{
if (container)
@@ -1850,7 +2069,6 @@ QCborValue::QCborValue(const QUrl &url)
t = Url;
container->elements[1].type = String;
}
-#endif
#if QT_CONFIG(regularexpression)
/*!
@@ -1889,6 +2107,7 @@ QCborValue::QCborValue(const QUuid &uuid)
// change our type
t = Uuid;
}
+#endif
// destructor
void QCborValue::dispose()
@@ -1899,15 +2118,10 @@ void QCborValue::dispose()
/*!
Replaces the contents of this QCborObject with a copy of \a other.
*/
-QCborValue &QCborValue::operator=(const QCborValue &other)
+QCborValue &QCborValue::operator=(const QCborValue &other) noexcept
{
- if (other.container)
- other.container->ref.ref();
- if (container)
- container->deref();
-
n = other.n;
- container = other.container;
+ assignContainer(container, other.container);
t = other.t;
return *this;
}
@@ -2025,7 +2239,6 @@ QUrl QCborValue::toUrl(const QUrl &defaultValue) const
return QUrl::fromEncoded(byteData->asByteArrayView());
}
-#endif
#if QT_CONFIG(regularexpression)
/*!
@@ -2068,6 +2281,7 @@ QUuid QCborValue::toUuid(const QUuid &defaultValue) const
return QUuid::fromRfc4122(byteData->asByteArrayView());
}
+#endif
/*!
\fn QCborArray QCborValue::toArray() const
@@ -2108,7 +2322,8 @@ QCborArray QCborValue::toArray(const QCborArray &defaultValue) const
Q_ASSERT(n == -1 || container == nullptr);
if (n < 0)
dd = container;
- return dd ? QCborArray(*dd) : defaultValue;
+ // return QCborArray(*dd); but that's UB if dd is nullptr
+ return dd ? QCborArray(*dd) : QCborArray();
}
/*!
@@ -2150,7 +2365,8 @@ QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
Q_ASSERT(n == -1 || container == nullptr);
if (n < 0)
dd = container;
- return dd ? QCborMap(*dd) : defaultValue;
+ // return QCborMap(*dd); but that's UB if dd is nullptr
+ return dd ? QCborMap(*dd) : QCborMap();
}
/*!
@@ -2167,9 +2383,7 @@ QCborMap QCborValue::toMap(const QCborMap &defaultValue) const
*/
const QCborValue QCborValue::operator[](const QString &key) const
{
- if (isMap())
- return toMap().value(key);
- return QCborValue();
+ return QCborContainerPrivate::findCborMapKey(*this, qToStringViewIgnoringNull(key));
}
/*!
@@ -2186,11 +2400,9 @@ const QCborValue QCborValue::operator[](const QString &key) const
\sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
QCborMap::find()
*/
-const QCborValue QCborValue::operator[](QLatin1String key) const
+const QCborValue QCborValue::operator[](QLatin1StringView key) const
{
- if (isMap())
- return toMap().value(key);
- return QCborValue();
+ return QCborContainerPrivate::findCborMapKey(*this, key);
}
/*!
@@ -2206,44 +2418,53 @@ const QCborValue QCborValue::operator[](QLatin1String key) const
*/
const QCborValue QCborValue::operator[](qint64 key) const
{
- if (isMap())
- return toMap().value(key);
- if (isArray())
- return toArray().at(key);
- return QCborValue();
+ if (isArray() && container && quint64(key) < quint64(container->elements.size()))
+ return container->valueAt(key);
+ return QCborContainerPrivate::findCborMapKey(*this, key);
}
-/*!
- \internal
- */
-static Q_DECL_COLD_FUNCTION QCborMap arrayAsMap(const QCborArray &array)
-{
- if (array.size())
- qWarning("Using CBOR array as map forced conversion");
- QCborMap map;
- for (qsizetype i = array.size(); i-- > 0; ) {
- QCborValue entry = array.at(i);
- // Ignore padding entries that may have been added to grow the array
- // when inserting past its end:
- if (!entry.isInvalid())
- map[i] = entry;
- }
- return map;
+static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container)
+{
+ constexpr qint64 LargeKey = 0x10000;
+ if (t != QCborValue::Array)
+ return false;
+ if (key < 0)
+ return false; // negative keys can't be an array index
+ if (key < LargeKey)
+ return true;
+
+ // Only convert to map if key is greater than array size + 1
+ qsizetype currentSize = container ? container->elements.size() : 0;
+ return key <= currentSize;
}
/*!
\internal
*/
-static QCborContainerPrivate *maybeDetach(QCborContainerPrivate *container, qsizetype size)
+static void convertArrayToMap(QCborContainerPrivate *&array)
{
- auto replace = QCborContainerPrivate::detach(container, size);
- Q_ASSERT(replace);
- if (replace != container) {
- if (container)
- container->deref();
- replace->ref.ref();
+ if (Q_LIKELY(!array || array->elements.isEmpty()))
+ return;
+
+ // The Q_LIKELY and the qWarning mark the rest of this function as unlikely
+ qWarning("Using CBOR array as map forced conversion");
+
+ qsizetype size = array->elements.size();
+ QCborContainerPrivate *map = QCborContainerPrivate::detach(array, size * 2);
+ map->elements.resize(size * 2);
+
+ // this may be an in-place copy, so we have to do it from the end
+ auto dst = map->elements.begin();
+ auto src = array->elements.constBegin();
+ for (qsizetype i = size - 1; i >= 0; --i) {
+ Q_ASSERT(src->type != QCborValue::Invalid);
+ dst[i * 2 + 1] = src[i];
}
- return replace;
+ for (qsizetype i = 0; i < size; ++i)
+ dst[i * 2] = { i, QCborValue::Integer };
+
+ // update reference counts
+ assignContainer(array, map);
}
/*!
@@ -2253,16 +2474,48 @@ static QCborContainerPrivate *maybeGrow(QCborContainerPrivate *container, qsizet
{
auto replace = QCborContainerPrivate::grow(container, index);
Q_ASSERT(replace);
- if (replace != container) {
- if (container)
- container->deref();
- replace->ref.ref();
- }
if (replace->elements.size() == index)
replace->append(Undefined());
else
Q_ASSERT(replace->elements.size() > index);
- return replace;
+ return assignContainer(container, replace);
+}
+
+template <typename KeyType> inline QCborValueRef
+QCborContainerPrivate::findOrAddMapKey(QCborValue &self, KeyType key)
+{
+ // we need a map, so convert if necessary
+ if (self.isArray())
+ convertArrayToMap(self.container);
+ else if (!self.isMap())
+ self = QCborValue(QCborValue::Map);
+ self.t = QCborValue::Map;
+ self.n = -1;
+
+ QCborValueRef result = findOrAddMapKey<KeyType>(self.container, key);
+ assignContainer(self.container, result.d);
+ return result;
+}
+
+template<typename KeyType> QCborValueRef
+QCborContainerPrivate::findOrAddMapKey(QCborValueRef self, KeyType key)
+{
+ auto &e = self.d->elements[self.i];
+
+ // we need a map, so convert if necessary
+ if (e.type == QCborValue::Array) {
+ convertArrayToMap(e.container);
+ } else if (e.type != QCborValue::Map) {
+ if (e.flags & QtCbor::Element::IsContainer)
+ e.container->deref();
+ e.container = nullptr;
+ }
+ e.flags = QtCbor::Element::IsContainer;
+ e.type = QCborValue::Map;
+
+ QCborValueRef result = findOrAddMapKey<KeyType>(e.container, key);
+ assignContainer(e.container, result.d);
+ return result;
}
/*!
@@ -2280,30 +2533,7 @@ static QCborContainerPrivate *maybeGrow(QCborContainerPrivate *container, qsizet
*/
QCborValueRef QCborValue::operator[](const QString &key)
{
- if (!isMap())
- *this = QCborValue(isArray() ? arrayAsMap(toArray()) : QCborMap());
-
- const qsizetype size = container ? container->elements.size() : 0;
- qsizetype index = size + 1;
- bool found = false;
- if (container) {
- QCborMap proxy(*container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- container = maybeDetach(container, size + (found ? 0 : 2));
- Q_ASSERT(container);
- if (!found) {
- container->append(key);
- container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(container->elements.size() & 1));
- Q_ASSERT(index < container->elements.size());
- return { container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, qToStringViewIgnoringNull(key));
}
/*!
@@ -2321,32 +2551,9 @@ QCborValueRef QCborValue::operator[](const QString &key)
\sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
QCborMap::find()
*/
-QCborValueRef QCborValue::operator[](QLatin1String key)
+QCborValueRef QCborValue::operator[](QLatin1StringView key)
{
- if (!isMap())
- *this = QCborValue(isArray() ? arrayAsMap(toArray()) : QCborMap());
-
- const qsizetype size = container ? container->elements.size() : 0;
- qsizetype index = size + 1;
- bool found = false;
- if (container) {
- QCborMap proxy(*container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- container = maybeDetach(container, size + (found ? 0 : 2));
- Q_ASSERT(container);
- if (!found) {
- container->append(key);
- container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(container->elements.size() & 1));
- Q_ASSERT(index < container->elements.size());
- return { container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
/*!
@@ -2367,40 +2574,14 @@ QCborValueRef QCborValue::operator[](QLatin1String key)
*/
QCborValueRef QCborValue::operator[](qint64 key)
{
- if (isArray() && key >= 0 && key < 0x10000) {
+ if (shouldArrayRemainArray(key, t, container)) {
container = maybeGrow(container, key);
return { container, qsizetype(key) };
}
- if (!isMap())
- *this = QCborValue(isArray() ? arrayAsMap(toArray()) : QCborMap());
-
- const qsizetype size = container ? container->elements.size() : 0;
- Q_ASSERT(!(size & 1));
- qsizetype index = size + 1;
- bool found = false;
- if (container) {
- QCborMap proxy(*container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- container = maybeDetach(container, size + (found ? 0 : 2));
- Q_ASSERT(container);
- if (!found) {
- container->append(key);
- container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(container->elements.size() & 1));
- Q_ASSERT(index < container->elements.size());
- return { container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
#if QT_CONFIG(cborstreamreader)
-enum { MaximumRecursionDepth = 1024 };
-
/*!
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
@@ -2636,10 +2817,12 @@ Q_NEVER_INLINE void QCborValue::toCbor(QCborStreamWriter &writer, EncodingOption
}
}
+# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt)
{
concrete().toCbor(writer, opt);
}
+# endif
#endif // QT_CONFIG(cborstreamwriter)
void QCborValueRef::assign(QCborValueRef that, const QCborValue &other)
@@ -2658,6 +2841,151 @@ void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other)
that = other.concrete();
}
+bool QCborValueConstRef::concreteBoolean(QCborValueConstRef self, bool defaultValue) noexcept
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ if (e.type != QCborValue::False && e.type != QCborValue::True)
+ return defaultValue;
+ return e.type == QCborValue::True;
+}
+
+double QCborValueConstRef::concreteDouble(QCborValueConstRef self, double defaultValue) noexcept
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ if (e.type == QCborValue::Integer)
+ return e.value;
+ if (e.type != QCborValue::Double)
+ return defaultValue;
+ return e.fpvalue();
+}
+
+qint64 QCborValueConstRef::concreteIntegral(QCborValueConstRef self, qint64 defaultValue) noexcept
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ QCborValue::Type t = e.type;
+ if (t == QCborValue::Double)
+ return e.fpvalue();
+ if (t != QCborValue::Integer)
+ return defaultValue;
+ return e.value;
+}
+
+QByteArray QCborValueConstRef::concreteByteArray(QCborValueConstRef self,
+ const QByteArray &defaultValue)
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ if (e.type != QCborValue::ByteArray)
+ return defaultValue;
+ return self.d->byteArrayAt(self.i);
+}
+
+QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QString &defaultValue)
+{
+ QtCbor::Element e = self.d->elements.at(self.i);
+ if (e.type != QCborValue::String)
+ return defaultValue;
+ return self.d->stringAt(self.i);
+}
+
+bool
+QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ return compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool
+QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ return compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ int c = compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ if (typeOrder(QCborValue::Array, e2.type))
+ return false;
+ return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = typeOrder(QCborValue::Array, e2.type);
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ if (typeOrder(QCborValue::Array, e2.type))
+ return false;
+ return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = typeOrder(QCborValue::Map, e2.type);
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+QCborValue QCborValueConstRef::concrete(QCborValueConstRef self) noexcept
+{
+ return self.d->valueAt(self.i);
+}
+
+QCborValue::Type QCborValueConstRef::concreteType(QCborValueConstRef self) noexcept
+{
+ return self.d->elements.at(self.i).type;
+}
+
+const QCborValue QCborValueConstRef::operator[](const QString &key) const
+{
+ const QCborValue item = d->valueAt(i);
+ return item[key];
+}
+
+const QCborValue QCborValueConstRef::operator[](const QLatin1StringView key) const
+{
+ const QCborValue item = d->valueAt(i);
+ return item[key];
+}
+
+const QCborValue QCborValueConstRef::operator[](qint64 key) const
+{
+ const QCborValue item = d->valueAt(i);
+ return item[key];
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QCborValue QCborValueRef::concrete(QCborValueRef self) noexcept
{
return self.d->valueAt(self.i);
@@ -2684,8 +3012,7 @@ QCborValue::Type QCborValueRef::concreteType(QCborValueRef self) noexcept
*/
const QCborValue QCborValueRef::operator[](const QString &key) const
{
- const QCborValue item = d->valueAt(i);
- return item[key];
+ return QCborValueConstRef::operator[](key);
}
/*!
@@ -2704,10 +3031,9 @@ const QCborValue QCborValueRef::operator[](const QString &key) const
\sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
QCborMap::find()
*/
-const QCborValue QCborValueRef::operator[](QLatin1String key) const
+const QCborValue QCborValueRef::operator[](QLatin1StringView key) const
{
- const QCborValue item = d->valueAt(i);
- return item[key];
+ return QCborValueConstRef::operator[](key);
}
/*!
@@ -2724,8 +3050,7 @@ const QCborValue QCborValueRef::operator[](QLatin1String key) const
*/
const QCborValue QCborValueRef::operator[](qint64 key) const
{
- const QCborValue item = d->valueAt(i);
- return item[key];
+ return QCborValueConstRef::operator[](key);
}
/*!
@@ -2744,48 +3069,7 @@ const QCborValue QCborValueRef::operator[](qint64 key) const
*/
QCborValueRef QCborValueRef::operator[](const QString &key)
{
- auto &e = d->elements[i];
- qsizetype size = 0;
- if (e.flags & QtCbor::Element::IsContainer) {
- if (e.container) {
- if (e.type == QCborValue::Array) {
- QCborValue repack = QCborValue(arrayAsMap(QCborArray(*e.container)));
- qSwap(e.container, repack.container);
- } else if (e.type != QCborValue::Map) {
- e.container->deref();
- e.container = nullptr;
- }
- }
- e.type = QCborValue::Map;
- if (e.container)
- size = e.container->elements.size();
- } else {
- // Stomp any prior e.value, replace with a map (that we'll grow)
- e.container = nullptr;
- e.type = QCborValue::Map;
- e.flags = QtCbor::Element::IsContainer;
- }
-
- qsizetype index = size + 1;
- bool found = false;
- if (e.container) {
- QCborMap proxy(*e.container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- e.container = maybeDetach(e.container, size + (found ? 0 : 2));
- Q_ASSERT(e.container);
- if (!found) {
- e.container->append(key);
- e.container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(e.container->elements.size() & 1));
- Q_ASSERT(index < e.container->elements.size());
- return { e.container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, qToStringViewIgnoringNull(key));
}
/*!
@@ -2803,50 +3087,9 @@ QCborValueRef QCborValueRef::operator[](const QString &key)
\sa operator[](qint64), QCborMap::operator[], QCborMap::value(),
QCborMap::find()
*/
-QCborValueRef QCborValueRef::operator[](QLatin1String key)
+QCborValueRef QCborValueRef::operator[](QLatin1StringView key)
{
- auto &e = d->elements[i];
- qsizetype size = 0;
- if (e.flags & QtCbor::Element::IsContainer) {
- if (e.container) {
- if (e.type == QCborValue::Array) {
- QCborValue repack = QCborValue(arrayAsMap(QCborArray(*e.container)));
- qSwap(e.container, repack.container);
- } else if (e.type != QCborValue::Map) {
- e.container->deref();
- e.container = nullptr;
- }
- }
- e.type = QCborValue::Map;
- if (e.container)
- size = e.container->elements.size();
- } else {
- // Stomp any prior e.value, replace with a map (that we'll grow)
- e.container = nullptr;
- e.type = QCborValue::Map;
- e.flags = QtCbor::Element::IsContainer;
- }
-
- qsizetype index = size + 1;
- bool found = false;
- if (e.container) {
- QCborMap proxy(*e.container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- e.container = maybeDetach(e.container, size + (found ? 0 : 2));
- Q_ASSERT(e.container);
- if (!found) {
- e.container->append(key);
- e.container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(e.container->elements.size() & 1));
- Q_ASSERT(index < e.container->elements.size());
- return { e.container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
/*!
@@ -2868,54 +3111,14 @@ QCborValueRef QCborValueRef::operator[](QLatin1String key)
QCborValueRef QCborValueRef::operator[](qint64 key)
{
auto &e = d->elements[i];
- if (e.type == QCborValue::Array && key >= 0 && key < 0x10000) {
+ if (shouldArrayRemainArray(key, e.type, e.container)) {
e.container = maybeGrow(e.container, key);
+ e.flags |= QtCbor::Element::IsContainer;
return { e.container, qsizetype(key) };
}
- qsizetype size = 0;
- if (e.flags & QtCbor::Element::IsContainer) {
- if (e.container) {
- if (e.type == QCborValue::Array) {
- QCborValue repack = QCborValue(arrayAsMap(QCborArray(*e.container)));
- qSwap(e.container, repack.container);
- } else if (e.type != QCborValue::Map) {
- e.container->deref();
- e.container = nullptr;
- }
- }
- e.type = QCborValue::Map;
- if (e.container)
- size = e.container->elements.size();
- } else {
- // Stomp any prior e.value, replace with a map (that we'll grow)
- e.container = nullptr;
- e.type = QCborValue::Map;
- e.flags = QtCbor::Element::IsContainer;
- }
- Q_ASSERT(!(size & 1));
-
- qsizetype index = size + 1;
- bool found = false;
- if (e.container) {
- QCborMap proxy(*e.container);
- auto it = proxy.constFind(key);
- if (it < proxy.constEnd()) {
- found = true;
- index = it.item.i;
- }
- }
-
- e.container = maybeDetach(e.container, size + (found ? 0 : 2));
- Q_ASSERT(e.container);
- if (!found) {
- e.container->append(key);
- e.container->append(QCborValue());
- }
- Q_ASSERT(index & 1 && !(e.container->elements.size() & 1));
- Q_ASSERT(index < e.container->elements.size());
- return { e.container, index };
+ return QCborContainerPrivate::findOrAddMapKey(*this, key);
}
-
+#endif // < Qt 7
inline QCborArray::QCborArray(QCborContainerPrivate &dd) noexcept
: d(&dd)
@@ -2963,13 +3166,13 @@ size_t qHash(const QCborValue &value, size_t seed)
#ifndef QT_BOOTSTRAPPED
case QCborValue::Url:
return qHash(value.toUrl(), seed);
-#endif
-#if QT_CONFIG(regularexpression)
+# if QT_CONFIG(regularexpression)
case QCborValue::RegularExpression:
return qHash(value.toRegularExpression(), seed);
-#endif
+# endif
case QCborValue::Uuid:
return qHash(value.toUuid(), seed);
+#endif
case QCborValue::Invalid:
return seed;
default:
diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
index 9a26c9ab66..93adbec344 100644
--- a/src/corelib/serialization/qcborvalue.h
+++ b/src/corelib/serialization/qcborvalue.h
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORVALUE_H
#define QCBORVALUE_H
#include <QtCore/qbytearray.h>
-#include <QtCore/qdatetime.h>
#include <QtCore/qcborcommon.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qdatetime.h>
#if QT_CONFIG(regularexpression)
# include <QtCore/qregularexpression.h>
#endif
@@ -58,10 +23,6 @@
# undef False
#endif
-#if 0 && __has_include(<compare>)
-# include <compare>
-#endif
-
QT_BEGIN_NAMESPACE
class QCborArray;
@@ -146,11 +107,9 @@ public:
QCborValue(QCborSimpleType st) : t(type_helper(st)) {}
QCborValue(const QByteArray &ba);
-#if QT_STRINGVIEW_LEVEL < 2
QCborValue(const QString &s);
-#endif
QCborValue(QStringView s);
- QCborValue(QLatin1String s);
+ QCborValue(QLatin1StringView s);
#ifndef QT_NO_CAST_FROM_ASCII
QT_ASCII_CAST_WARN QCborValue(const char *s) : QCborValue(QString::fromUtf8(s)) {}
#endif
@@ -166,30 +125,30 @@ public:
explicit QCborValue(const QDateTime &dt);
#ifndef QT_BOOTSTRAPPED
explicit QCborValue(const QUrl &url);
-#endif
-#if QT_CONFIG(regularexpression)
+# if QT_CONFIG(regularexpression)
explicit QCborValue(const QRegularExpression &rx);
-#endif
+# endif
explicit QCborValue(const QUuid &uuid);
+#endif
~QCborValue() { if (container) dispose(); }
// make sure const char* doesn't go call the bool constructor
QCborValue(const void *) = delete;
- QCborValue(const QCborValue &other);
+ QCborValue(const QCborValue &other) noexcept;
QCborValue(QCborValue &&other) noexcept
- : n(other.n), container(qExchange(other.container, nullptr)), t(qExchange(other.t, Undefined))
+ : n(other.n), container(std::exchange(other.container, nullptr)), t(std::exchange(other.t, Undefined))
{
}
- QCborValue &operator=(const QCborValue &other);
+ QCborValue &operator=(const QCborValue &other) noexcept;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QCborValue)
void swap(QCborValue &other) noexcept
{
- qSwap(n, other.n);
- qSwap(container, other.container);
- qSwap(t, other.t);
+ std::swap(n, other.n);
+ qt_ptr_swap(container, other.container);
+ std::swap(t, other.t);
}
Type type() const { return t; }
@@ -238,11 +197,13 @@ public:
QByteArray toByteArray(const QByteArray &defaultValue = {}) const;
QString toString(const QString &defaultValue = {}) const;
QDateTime toDateTime(const QDateTime &defaultValue = {}) const;
+#ifndef QT_BOOTSTRAPPED
QUrl toUrl(const QUrl &defaultValue = {}) const;
-#if QT_CONFIG(regularexpression)
+# if QT_CONFIG(regularexpression)
QRegularExpression toRegularExpression(const QRegularExpression &defaultValue = {}) const;
-#endif
+# endif
QUuid toUuid(const QUuid &defaultValue = {}) const;
+#endif
// only forward-declared, need split functions
QCborArray toArray() const;
@@ -251,26 +212,18 @@ public:
QCborMap toMap(const QCborMap &defaultValue) const;
const QCborValue operator[](const QString &key) const;
- const QCborValue operator[](QLatin1String key) const;
+ const QCborValue operator[](QLatin1StringView key) const;
const QCborValue operator[](qint64 key) const;
QCborValueRef operator[](qint64 key);
- QCborValueRef operator[](QLatin1String key);
+ QCborValueRef operator[](QLatin1StringView key);
QCborValueRef operator[](const QString & key);
int compare(const QCborValue &other) const;
-#if 0 && __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
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborValue &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborValue &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborValue &other) const
{ return compare(other) < 0; }
#endif
@@ -296,6 +249,19 @@ public:
QString toDiagnosticNotation(DiagnosticNotationOptions opts = Compact) const;
private:
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+ bool comparesEqual(const QCborValue &lhs, const QCborValue &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborValue &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+
+ Q_DECLARE_STRONGLY_ORDERED(QCborValue)
+ friend class QCborArray;
+ friend class QCborMap;
+ friend class QCborValueConstRef;
friend class QCborValueRef;
friend class QCborContainerPrivate;
friend class QJsonPrivate::Value;
@@ -330,11 +296,160 @@ private:
};
Q_DECLARE_SHARED(QCborValue)
-class Q_CORE_EXPORT QCborValueRef
+class QCborValueConstRef
{
public:
+ QCborValueConstRef(const QCborValueConstRef &) = default;
+ QCborValueConstRef &operator=(const QCborValueConstRef &) = delete;
operator QCborValue() const { return concrete(); }
+ QCborValue::Type type() const { return concreteType(*this); }
+ 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 concrete().isTag(); }
+ 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 concrete().isSimpleType(); }
+ bool isSimpleType(QCborSimpleType st) const { return concrete().isSimpleType(st); }
+
+ QCborSimpleType toSimpleType(QCborSimpleType defaultValue = QCborSimpleType::Undefined) const
+ {
+ return concrete().toSimpleType(defaultValue);
+ }
+
+ 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); }
+#ifndef QT_BOOTSTRAPPED
+ QUrl toUrl(const QUrl &defaultValue = {}) const
+ { return concrete().toUrl(defaultValue); }
+# if QT_CONFIG(regularexpression)
+ QRegularExpression toRegularExpression(const QRegularExpression &defaultValue = {}) const
+ { return concrete().toRegularExpression(defaultValue); }
+# endif
+ QUuid toUuid(const QUuid &defaultValue = {}) const
+ { return concrete().toUuid(defaultValue); }
+#endif
+
+ // only forward-declared, need split functions. Implemented in qcbor{array,map}.h
+ inline QCborArray toArray() const;
+ inline QCborArray toArray(const QCborArray &a) const;
+ inline QCborMap toMap() const;
+ inline QCborMap toMap(const QCborMap &m) const;
+
+ Q_CORE_EXPORT const QCborValue operator[](const QString &key) const;
+ Q_CORE_EXPORT const QCborValue operator[](QLatin1StringView key) const;
+ Q_CORE_EXPORT const QCborValue operator[](qint64 key) const;
+
+ int compare(const QCborValue &other) const
+ { return concrete().compare(other); }
+
+ QVariant toVariant() const { return concrete().toVariant(); }
+ inline QJsonValue toJsonValue() const; // in qjsonvalue.h
+
+#if QT_CONFIG(cborstreamwriter)
+ QByteArray toCbor(QCborValue::EncodingOptions opt = QCborValue::NoTransformation) const
+ { return concrete().toCbor(opt); }
+ void toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt = QCborValue::NoTransformation) const
+ { return concrete().toCbor(writer, opt); }
+#endif
+
+ QString toDiagnosticNotation(QCborValue::DiagnosticNotationOptions opt = QCborValue::Compact) const
+ { return concrete().toDiagnosticNotation(opt); }
+
+protected:
+ friend class QCborValue;
+ friend class QCborArray;
+ friend class QCborMap;
+ friend class QCborContainerPrivate;
+
+ QCborValue concrete() const noexcept { return concrete(*this); }
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept;
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborValueConstRef &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborValueConstRef &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborValueConstRef)
+
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept;
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborValueConstRef &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborValueConstRef &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborValueConstRef, QCborValue)
+
+ static Q_CORE_EXPORT QCborValue concrete(QCborValueConstRef that) noexcept;
+ static Q_CORE_EXPORT QCborValue::Type concreteType(QCborValueConstRef that) noexcept Q_DECL_PURE_FUNCTION;
+ static Q_CORE_EXPORT bool
+ concreteBoolean(QCborValueConstRef that, bool defaultValue) noexcept Q_DECL_PURE_FUNCTION;
+ static Q_CORE_EXPORT double
+ concreteDouble(QCborValueConstRef that, double defaultValue) noexcept Q_DECL_PURE_FUNCTION;
+ static Q_CORE_EXPORT qint64
+ concreteIntegral(QCborValueConstRef that, qint64 defaultValue) noexcept Q_DECL_PURE_FUNCTION;
+ static Q_CORE_EXPORT QByteArray
+ concreteByteArray(QCborValueConstRef that, const QByteArray &defaultValue);
+ static Q_CORE_EXPORT QString
+ concreteString(QCborValueConstRef that, const QString &defaultValue);
+
+ constexpr QCborValueConstRef() : d(nullptr), i(0) {} // this will actually be invalid
+ constexpr QCborValueConstRef(QCborContainerPrivate *dd, qsizetype ii)
+ : d(dd), i(ii)
+ {}
+ QCborContainerPrivate *d;
+ qsizetype i;
+};
+
+QT_WARNING_PUSH
+QT6_ONLY(QT_WARNING_DISABLE_MSVC(4275)) // non dll-interface class 'QJsonValueConstRef' used as base for dll-interface class 'QJsonValueRef'
+class QT6_ONLY(Q_CORE_EXPORT) QCborValueRef : public QCborValueConstRef
+{
+public:
QCborValueRef(const QCborValueRef &) noexcept = default;
QCborValueRef(QCborValueRef &&) noexcept = default;
QCborValueRef &operator=(const QCborValue &other)
@@ -344,6 +459,15 @@ public:
QCborValueRef &operator=(const QCborValueRef &other)
{ assign(*this, other); return *this; }
+ QT7_ONLY(Q_CORE_EXPORT) QCborValueRef operator[](qint64 key);
+ QT7_ONLY(Q_CORE_EXPORT) QCborValueRef operator[](QLatin1StringView key);
+ QT7_ONLY(Q_CORE_EXPORT) QCborValueRef operator[](const QString & key);
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ // retained for binary compatibility (due to the Q_CORE_EXPORT) because at
+ // least one compiler emits and exports all inlines in an exported class
+
+ operator QCborValue() const { return concrete(); }
QCborValue::Type type() const { return concreteType(); }
bool isInteger() const { return type() == QCborValue::Integer; }
bool isByteArray() const { return type() == QCborValue::ByteArray; }
@@ -371,6 +495,10 @@ public:
{
return type() == QCborValue::type_helper(st);
}
+ QCborSimpleType toSimpleType(QCborSimpleType defaultValue = QCborSimpleType::Undefined) const
+ {
+ return isSimpleType() ? QCborSimpleType(type() & 0xff) : defaultValue;
+ }
QCborTag tag(QCborTag defaultValue = QCborTag(-1)) const
{ return concrete().tag(defaultValue); }
@@ -378,28 +506,28 @@ public:
{ return concrete().taggedValue(defaultValue); }
qint64 toInteger(qint64 defaultValue = 0) const
- { return concrete().toInteger(defaultValue); }
+ { return concreteIntegral(*this, defaultValue); }
bool toBool(bool defaultValue = false) const
- { return concrete().toBool(defaultValue); }
+ { return concreteBoolean(*this, defaultValue); }
double toDouble(double defaultValue = 0) const
- { return concrete().toDouble(defaultValue); }
+ { return concreteDouble(*this, defaultValue); }
QByteArray toByteArray(const QByteArray &defaultValue = {}) const
- { return concrete().toByteArray(defaultValue); }
+ { return concreteByteArray(*this, defaultValue); }
QString toString(const QString &defaultValue = {}) const
- { return concrete().toString(defaultValue); }
+ { return concreteString(*this, defaultValue); }
QDateTime toDateTime(const QDateTime &defaultValue = {}) const
{ return concrete().toDateTime(defaultValue); }
#ifndef QT_BOOTSTRAPPED
QUrl toUrl(const QUrl &defaultValue = {}) const
{ return concrete().toUrl(defaultValue); }
-#endif
-#if QT_CONFIG(regularexpression)
+# if QT_CONFIG(regularexpression)
QRegularExpression toRegularExpression(const QRegularExpression &defaultValue = {}) const
{ return concrete().toRegularExpression(defaultValue); }
-#endif
+# endif
QUuid toUuid(const QUuid &defaultValue = {}) const
{ return concrete().toUuid(defaultValue); }
+#endif
// only forward-declared, need split functions. Implemented in qcbor{array,map}.h
QCborArray toArray() const;
@@ -408,27 +536,16 @@ public:
QCborMap toMap(const QCborMap &m) const;
const QCborValue operator[](const QString &key) const;
- const QCborValue operator[](QLatin1String key) const;
+ const QCborValue operator[](QLatin1StringView key) const;
const QCborValue operator[](qint64 key) const;
- QCborValueRef operator[](qint64 key);
- QCborValueRef operator[](QLatin1String key);
- QCborValueRef operator[](const QString & key);
int compare(const QCborValue &other) const
{ return concrete().compare(other); }
-#if 0 && __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
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborValue &other) const
{ return compare(other) == 0; }
bool operator!=(const QCborValue &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborValue &other) const
{ return compare(other) < 0; }
#endif
@@ -437,25 +554,17 @@ public:
QJsonValue toJsonValue() const;
#if QT_CONFIG(cborstreamwriter)
+ using QCborValueConstRef::toCbor;
QByteArray toCbor(QCborValue::EncodingOptions opt = QCborValue::NoTransformation)
- { return concrete().toCbor(opt); }
+ { return std::as_const(*this).toCbor(opt); }
void toCbor(QCborStreamWriter &writer, QCborValue::EncodingOptions opt = QCborValue::NoTransformation);
#endif
+ using QCborValueConstRef::toDiagnosticNotation;
QString toDiagnosticNotation(QCborValue::DiagnosticNotationOptions opt = QCborValue::Compact)
- { return concrete().toDiagnosticNotation(opt); }
+ { return std::as_const(*this).toDiagnosticNotation(opt); }
private:
- friend class QCborValue;
- 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); }
@@ -463,14 +572,30 @@ private:
QCborValue::Type concreteType() const noexcept { return concreteType(*this); }
// this will actually be invalid...
- constexpr QCborValueRef() : d(nullptr), i(0) {}
+ constexpr QCborValueRef() : QCborValueConstRef(nullptr, 0) {}
QCborValueRef(QCborContainerPrivate *dd, qsizetype ii)
- : d(dd), i(ii)
+ : QCborValueConstRef(dd, ii)
{}
- QCborContainerPrivate *d;
- qsizetype i;
+#else
+private:
+ using QCborValueConstRef::QCborValueConstRef;
+#endif // < Qt 7
+
+ friend class QCborValue;
+ friend class QCborArray;
+ friend class QCborMap;
+ friend class QCborContainerPrivate;
+ friend class QCborValueConstRef;
+
+ // static so we can pass this by value
+ QT7_ONLY(Q_CORE_EXPORT) static void assign(QCborValueRef that, const QCborValue &other);
+ QT7_ONLY(Q_CORE_EXPORT) static void assign(QCborValueRef that, QCborValue &&other);
+ QT7_ONLY(Q_CORE_EXPORT) static void assign(QCborValueRef that, const QCborValueRef other);
};
+QT_WARNING_POP
+Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::EncodingOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::DiagnosticNotationOptions)
Q_CORE_EXPORT size_t qHash(const QCborValue &value, size_t seed = 0);
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index e23b9fccf9..33eb912a6d 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCBORVALUE_P_H
#define QCBORVALUE_P_H
@@ -65,6 +29,11 @@
QT_BEGIN_NAMESPACE
namespace QtCbor {
+enum class Comparison {
+ ForEquality,
+ ForOrdering,
+};
+
struct Undefined {};
struct Element
{
@@ -115,7 +84,7 @@ struct ByteData
QString toUtf8String() const { return QString::fromUtf8(byte(), len); }
QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), len); }
- QLatin1String asLatin1() const { return QLatin1String(byte(), len); }
+ QLatin1StringView asLatin1() const { return {byte(), len}; }
QUtf8StringView asUtf8StringView() const { return QUtf8StringView(byte(), len); }
QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
QString asQStringRaw() const { return QString::fromRawData(utf16(), len / 2); }
@@ -139,18 +108,19 @@ public:
QList<QtCbor::Element> elements;
void deref() { if (!ref.deref()) delete this; }
- void compact(qsizetype reserved);
+ void compact();
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)
+ static qptrdiff addByteDataImpl(QByteArray &target, QByteArray::size_type &targetUsed,
+ 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();
+ qptrdiff offset = target.size();
// align offset
offset += alignof(QtCbor::ByteData) - 1;
@@ -158,10 +128,10 @@ public:
qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
- usedData += increment;
- data.resize(offset + increment);
+ targetUsed += increment;
+ target.resize(offset + increment);
- char *ptr = data.begin() + offset;
+ char *ptr = target.begin() + offset;
auto b = new (ptr) QtCbor::ByteData;
b->len = len;
if (block)
@@ -170,6 +140,11 @@ public:
return offset;
}
+ qptrdiff addByteData(const char *block, qsizetype len)
+ {
+ return addByteDataImpl(data, usedData, block, len);
+ }
+
const QtCbor::ByteData *byteData(QtCbor::Element e) const
{
if ((e.flags & QtCbor::Element::HasByteData) == 0)
@@ -220,7 +195,7 @@ public:
}
void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
{
- replaceAt_internal(*elements.insert(elements.begin() + int(idx), {}), value, disp);
+ replaceAt_internal(*elements.insert(idx, {}), value, disp);
}
void append(QtCbor::Undefined)
@@ -250,31 +225,29 @@ public:
{
appendByteData(str, len, QCborValue::String);
}
- void append(QLatin1String s)
+ void append(QLatin1StringView s)
{
if (!QtPrivate::isAscii(s))
- return append(QString(s));
+ return appendNonAsciiString(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(QStringView s);
+ void appendNonAsciiString(QStringView s);
-#if QT_STRINGVIEW_LEVEL < 2
void append(const QString &s)
{
append(qToStringViewIgnoringNull(s));
}
-#endif
void append(QStringView s)
{
if (QtPrivate::isAscii(s))
appendAsciiString(s);
else
- appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
- QCborValue::String, QtCbor::Element::StringIsUtf16);
+ appendNonAsciiString(s);
}
void append(const QCborValue &v)
{
@@ -367,7 +340,7 @@ public:
return e;
}
- static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s)
+ static int compareUtf8(const QtCbor::ByteData *b, QLatin1StringView s)
{
return QUtf8::compareUtf8(QByteArrayView(b->byte(), b->len), s);
}
@@ -378,7 +351,7 @@ public:
}
template<typename String>
- int stringCompareElement(const QtCbor::Element &e, String s) const
+ int stringCompareElement(const QtCbor::Element &e, String s, QtCbor::Comparison mode) const
{
if (e.type != QCborValue::String)
return int(e.type) - int(QCborValue::String);
@@ -387,15 +360,18 @@ public:
if (!b)
return s.isEmpty() ? 0 : -1;
- if (e.flags & QtCbor::Element::StringIsUtf16)
+ if (e.flags & QtCbor::Element::StringIsUtf16) {
+ if (mode == QtCbor::Comparison::ForEquality)
+ return QtPrivate::equalStrings(b->asStringView(), s) ? 0 : 1;
return QtPrivate::compareStrings(b->asStringView(), s);
+ }
return compareUtf8(b, s);
}
template<typename String>
bool stringEqualsElement(const QtCbor::Element &e, String s) const
{
- return stringCompareElement(e, s) == 0;
+ return stringCompareElement(e, s, QtCbor::Comparison::ForEquality) == 0;
}
template<typename String>
@@ -405,12 +381,13 @@ public:
}
static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
- const QCborContainerPrivate *c2, QtCbor::Element e2);
- int compareElement(qsizetype idx, const QCborValue &value) const
+ const QCborContainerPrivate *c2, QtCbor::Element e2,
+ QtCbor::Comparison mode) noexcept;
+ int compareElement(qsizetype idx, const QCborValue &value, QtCbor::Comparison mode) const
{
auto &e1 = elements.at(idx);
auto e2 = elementFromValue(value);
- return compareElement_helper(this, e1, value.container, e2);
+ return compareElement_helper(this, e1, value.container, e2, mode);
}
void removeAt(qsizetype idx)
@@ -419,6 +396,62 @@ public:
elements.remove(idx);
}
+ // doesn't apply to JSON
+ template <typename KeyType> QCborValueConstRef findCborMapKey(KeyType key)
+ {
+ qsizetype i = 0;
+ for ( ; i < elements.size(); i += 2) {
+ const auto &e = elements.at(i);
+ bool equals;
+ if constexpr (std::is_same_v<std::decay_t<KeyType>, QCborValue>) {
+ equals = (compareElement(i, key, QtCbor::Comparison::ForEquality) == 0);
+ } else if constexpr (std::is_integral_v<KeyType>) {
+ equals = (e.type == QCborValue::Integer && e.value == key);
+ } else {
+ // assume it's a string
+ equals = stringEqualsElement(i, key);
+ }
+ if (equals)
+ break;
+ }
+ return { this, i + 1 };
+ }
+ template <typename KeyType> static QCborValue findCborMapKey(const QCborValue &self, KeyType key)
+ {
+ if (self.isMap() && self.container) {
+ qsizetype idx = self.container->findCborMapKey(key).i;
+ if (idx < self.container->elements.size())
+ return self.container->valueAt(idx);
+ }
+ return QCborValue();
+ }
+ template <typename KeyType> static QCborValueRef
+ findOrAddMapKey(QCborContainerPrivate *container, KeyType key)
+ {
+ qsizetype size = 0;
+ qsizetype index = size + 1;
+ if (container) {
+ size = container->elements.size();
+ index = container->findCborMapKey<KeyType>(key).i; // returns size + 1 if not found
+ }
+ Q_ASSERT(index & 1);
+ Q_ASSERT((size & 1) == 0);
+
+ container = detach(container, qMax(index + 1, size));
+ Q_ASSERT(container);
+ Q_ASSERT((container->elements.size() & 1) == 0);
+
+ if (index >= size) {
+ container->append(key);
+ container->append(QCborValue());
+ }
+ Q_ASSERT(index < container->elements.size());
+ return { container, index };
+ }
+ template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborMap &map, KeyType key);
+ template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborValue &self, KeyType key);
+ template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborValueRef self, KeyType key);
+
#if QT_CONFIG(cborstreamreader)
void decodeValueFromCbor(QCborStreamReader &reader, int remainingStackDepth);
void decodeStringFromCbor(QCborStreamReader &reader);
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index ec3bd06a34..d35e871de0 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdatastream.h"
#include "qdatastream_p.h"
@@ -51,9 +15,13 @@
QT_BEGIN_NAMESPACE
+constexpr quint32 QDataStream::NullCode;
+constexpr quint32 QDataStream::ExtendedSize;
+
/*!
\class QDataStream
\inmodule QtCore
+ \ingroup qtserialization
\reentrant
\brief The QDataStream class provides serialization of binary data
to a QIODevice.
@@ -102,17 +70,30 @@ QT_BEGIN_NAMESPACE
need of manually defining streaming operators. Enum classes are
serialized using the declared size.
- To take one example, a \c{char *} string is written as a 32-bit
- integer equal to the length of the string including the '\\0' byte,
- followed by all the characters of the string including the
- '\\0' byte. When reading a \c{char *} string, 4 bytes are read to
- create the 32-bit length value, then that many characters for the
- \c {char *} string including the '\\0' terminator are read.
-
The initial I/O device is usually set in the constructor, but can be
changed with setDevice(). If you've reached the end of the data
(or if there is no I/O device set) atEnd() will return true.
+ \section1 Serializing containers and strings
+
+ The serialization format is a length specifier first, then \a l bytes of data.
+ The length specifier is one quint32 if the version is less than 6.7 or if the
+ number of elements is less than 0xfffffffe (2^32 -2). Otherwise there is
+ an extend value 0xfffffffe followed by one quint64 with the actual value.
+ In addition for containers that support isNull(), it is encoded as a single
+ quint32 with all bits set and no data.
+
+ To take one example, if the string size fits into 32 bits, a \c{char *} string
+ is written as a 32-bit integer equal to the length of the string, including
+ the '\\0' byte, followed by all the characters of the string, including the
+ '\\0' byte. If the string size is greater, the value 0xffffffffe is written
+ as a marker of an extended size, followed by 64 bits of the actual size.
+ When reading a \c {char *} string, 4 bytes are read first. If the value is
+ not equal to 0xffffffffe (the marker of extended size), then these 4 bytes
+ are treated as the 32 bit size of the string. Otherwise, the next 8 bytes are
+ read and treated as a 64 bit size of the string. Then, all the characters for
+ the \c {char *} string, including the '\\0' terminator, are read.
+
\section1 Versioning
QDataStream's binary format has evolved since Qt 1.0, and is
@@ -199,6 +180,27 @@ QT_BEGIN_NAMESPACE
If no full packet is received, this code restores the stream to the
initial position, after which you need to wait for more data to arrive.
+ \section1 Corruption and Security
+
+ QDataStream is not resilient against corrupted data inputs and should
+ therefore not be used for security-sensitive situations, even when using
+ transactions. Transactions will help determine if a valid input can
+ currently be decoded with the data currently available on an asynchronous
+ device, but will assume that the data that is available is correctly
+ formed.
+
+ Additionally, many QDataStream demarshalling operators will allocate memory
+ based on information found in the stream. Those operators perform no
+ verification on whether the requested amount of memory is reasonable or if
+ it is compatible with the amount of data available in the stream (example:
+ demarshalling a QByteArray or QString may see the request for allocation of
+ several gigabytes of data).
+
+ QDataStream should not be used on content whose provenance cannot be
+ trusted. Applications should be designed to attempt to decode only streams
+ whose provenance is at least as trustworthy as that of the application
+ itself or its plugins.
+
\sa QTextStream, QVariant
*/
@@ -236,6 +238,11 @@ QT_BEGIN_NAMESPACE
data in the underlying device.
\value ReadCorruptData The data stream has read corrupt data.
\value WriteFailed The data stream cannot write to the underlying device.
+ \value [since 6.7] SizeLimitExceeded The data stream cannot read or write
+ the data because its size is larger than supported
+ by the current platform. This can happen, for
+ example, when trying to read more that 2 GiB of
+ data on a 32-bit platform.
*/
/*****************************************************************************
@@ -264,7 +271,7 @@ QT_BEGIN_NAMESPACE
return retVal;
#define CHECK_STREAM_TRANSACTION_PRECOND(retVal) \
- if (!d || d->transactionDepth == 0) { \
+ if (transactionDepth == 0) { \
qWarning("QDataStream: No transaction in progress"); \
return retVal; \
}
@@ -277,12 +284,6 @@ QT_BEGIN_NAMESPACE
QDataStream::QDataStream()
{
- dev = nullptr;
- owndev = false;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -294,11 +295,6 @@ QDataStream::QDataStream()
QDataStream::QDataStream(QIODevice *d)
{
dev = d; // set device
- owndev = false;
- byteorder = BigEndian; // default byte order
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -323,10 +319,6 @@ QDataStream::QDataStream(QByteArray *a, OpenMode flags)
buf->open(flags);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -347,10 +339,6 @@ QDataStream::QDataStream(const QByteArray &a)
buf->open(QIODevice::ReadOnly);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -412,16 +400,14 @@ bool QDataStream::atEnd() const
}
/*!
+ \fn QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+
Returns the floating point precision of the data stream.
\since 4.6
\sa FloatingPointPrecision, setFloatingPointPrecision()
*/
-QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
-{
- return d ? d->floatingPointPrecision : QDataStream::DoublePrecision;
-}
/*!
Sets the floating point precision of the data stream to \a precision. If the floating point precision is
@@ -445,22 +431,17 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
*/
void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision)
{
- if (!d)
- d.reset(new QDataStreamPrivate());
- d->floatingPointPrecision = precision;
+ fpPrecision = precision;
}
/*!
+ \fn QDataStream::status() const
+
Returns the status of the data stream.
\sa Status, setStatus(), resetStatus()
*/
-QDataStream::Status QDataStream::status() const
-{
- return q_status;
-}
-
/*!
Resets the status of the data stream.
@@ -508,11 +489,14 @@ void QDataStream::setStatus(Status status)
void QDataStream::setByteOrder(ByteOrder bo)
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ // accessed by inline byteOrder() prior to Qt 6.8
byteorder = bo;
+#endif
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- noswap = (byteorder == BigEndian);
+ noswap = (bo == BigEndian);
else
- noswap = (byteorder == LittleEndian);
+ noswap = (bo == LittleEndian);
}
@@ -558,6 +542,11 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_1 Same as Qt_6_0
\value Qt_6_2 Same as Qt_6_0
\value Qt_6_3 Same as Qt_6_0
+ \value Qt_6_4 Same as Qt_6_0
+ \value Qt_6_5 Same as Qt_6_0
+ \value Qt_6_6 Version 21 (Qt 6.6)
+ \value Qt_6_7 Version 22 (Qt 6.7)
+ \value Qt_6_8 Same as Qt_6_7
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -631,10 +620,7 @@ void QDataStream::startTransaction()
{
CHECK_STREAM_PRECOND(Q_VOID)
- if (!d)
- d.reset(new QDataStreamPrivate());
-
- if (++d->transactionDepth == 1) {
+ if (++transactionDepth == 1) {
dev->startTransaction();
resetStatus();
}
@@ -663,7 +649,7 @@ void QDataStream::startTransaction()
bool QDataStream::commitTransaction()
{
CHECK_STREAM_TRANSACTION_PRECOND(false)
- if (--d->transactionDepth == 0) {
+ if (--transactionDepth == 0) {
CHECK_STREAM_PRECOND(false)
if (q_status == ReadPastEnd) {
@@ -703,7 +689,7 @@ void QDataStream::rollbackTransaction()
setStatus(ReadPastEnd);
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -739,7 +725,7 @@ void QDataStream::abortTransaction()
q_status = ReadCorruptData;
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -762,13 +748,13 @@ bool QDataStream::isDeviceTransactionStarted() const
\internal
*/
-int QDataStream::readBlock(char *data, int len)
+qint64 QDataStream::readBlock(char *data, qint64 len)
{
// Disable reads on failure in transacted stream
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int readResult = dev->read(data, len);
+ const qint64 readResult = dev->read(data, len);
if (readResult != len)
setStatus(ReadPastEnd);
return readResult;
@@ -992,25 +978,12 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\overload
- \since 5.9
-
- Reads a floating point number from the stream into \a f,
- using the standard IEEE 754 format. Returns a reference to the
- stream.
-*/
-QDataStream &QDataStream::operator>>(qfloat16 &f)
-{
- return *this >> reinterpret_cast<qint16&>(f);
-}
-
-
-/*!
- \overload
- Reads the '\\0'-terminated string \a s from the stream and returns
- a reference to the stream.
+ Reads string \a s from the stream and returns a reference to the stream.
- The string is deserialized using \c{readBytes()}.
+ The string is deserialized using \c{readBytes()} where the serialization
+ format is a \c quint32 length specifier first, followed by that many bytes
+ of data. The resulting string is always '\\0'-terminated.
Space for the string is allocated using \c{new []} -- the caller must
destroy it with \c{delete []}.
@@ -1020,7 +993,7 @@ QDataStream &QDataStream::operator>>(qfloat16 &f)
QDataStream &QDataStream::operator>>(char *&s)
{
- uint len = 0;
+ qint64 len = 0;
return readBytes(s, len);
}
@@ -1054,7 +1027,29 @@ QDataStream &QDataStream::operator>>(char32_t &c)
return *this;
}
+#if QT_DEPRECATED_SINCE(6, 11)
+
+/*
+ \deprecated [6.11] Use an overload that takes qint64 length instead.
+*/
+QDataStream &QDataStream::readBytes(char *&s, uint &l)
+{
+ qint64 length = 0;
+ (void)readBytes(s, length);
+ if (length != qint64(uint(length))) {
+ setStatus(SizeLimitExceeded); // Cannot store length in l
+ delete[] s;
+ l = 0;
+ return *this;
+ }
+ l = uint(length);
+ return *this;
+}
+
+#endif // QT_DEPRECATED_SINCE(6, 11)
+
/*!
+ \since 6.7
Reads the buffer \a s from the stream and returns a reference to
the stream.
@@ -1064,30 +1059,40 @@ QDataStream &QDataStream::operator>>(char32_t &c)
The \a l parameter is set to the length of the buffer. If the
string read is empty, \a l is set to 0 and \a s is set to \nullptr.
- The serialization format is a quint32 length specifier first,
- then \a l bytes of data.
+ The serialization format is a length specifier first, then \a l
+ bytes of data. The length specifier is one quint32 if the version
+ is less than 6.7 or if the number of elements is less than 0xfffffffe
+ (2^32 -2), otherwise there is an extend value 0xfffffffe followed by
+ one quint64 with the actual value. In addition for containers that
+ support isNull(), it is encoded as a single quint32 with all bits
+ set and no data.
\sa readRawData(), writeBytes()
*/
-QDataStream &QDataStream::readBytes(char *&s, uint &l)
+QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
{
s = nullptr;
l = 0;
CHECK_STREAM_PRECOND(*this)
- quint32 len;
- *this >> len;
- if (len == 0)
+ qint64 length = readQSizeType(*this);
+ if (length == 0)
+ return *this;
+
+ qsizetype len = qsizetype(length);
+ if (length != len || length < 0) {
+ setStatus(SizeLimitExceeded); // Cannot store len
return *this;
+ }
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
+ qsizetype step = (dev->bytesAvailable() >= len) ? len : 1024 * 1024;
+ qsizetype allocated = 0;
char *prevBuf = nullptr;
char *curBuf = nullptr;
do {
- int blockSize = qMin(Step, len - allocated);
+ qsizetype blockSize = qMin(step, len - allocated);
prevBuf = curBuf;
curBuf = new char[allocated + blockSize + 1];
if (prevBuf) {
@@ -1099,11 +1104,12 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
return *this;
}
allocated += blockSize;
+ step *= 2;
} while (allocated < len);
s = curBuf;
s[len] = '\0';
- l = (uint)len;
+ l = len;
return *this;
}
@@ -1116,7 +1122,7 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
\sa readBytes(), QIODevice::read(), writeRawData()
*/
-int QDataStream::readRawData(char *s, int len)
+qint64 QDataStream::readRawData(char *s, qint64 len)
{
CHECK_STREAM_PRECOND(-1)
return readBlock(s, len);
@@ -1254,18 +1260,13 @@ QDataStream &QDataStream::operator<<(qint64 i)
*/
/*!
+ \fn QDataStream &QDataStream::operator<<(bool i)
+ \overload
+
Writes a boolean value, \a i, to the stream. Returns a reference
to the stream.
*/
-QDataStream &QDataStream::operator<<(bool i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!dev->putChar(qint8(i)))
- q_status = WriteFailed;
- return *this;
-}
-
/*!
\overload
@@ -1340,19 +1341,6 @@ QDataStream &QDataStream::operator<<(double f)
/*!
- \fn QDataStream &QDataStream::operator<<(qfloat16 f)
- \overload
- \since 5.9
-
- Writes a floating point number, \a f, to the stream using
- the standard IEEE 754 format. Returns a reference to the stream.
-*/
-QDataStream &QDataStream::operator<<(qfloat16 f)
-{
- return *this << reinterpret_cast<qint16&>(f);
-}
-
-/*!
\overload
Writes the '\\0'-terminated string \a s to the stream and returns a
@@ -1365,13 +1353,9 @@ QDataStream &QDataStream::operator<<(qfloat16 f)
QDataStream &QDataStream::operator<<(const char *s)
{
- if (!s) {
- *this << (quint32)0;
- return *this;
- }
- int len = int(qstrlen(s)) + 1; // also write null terminator
- *this << (quint32)len; // write length specifier
- writeRawData(s, len);
+ // Include null terminator, unless s itself is null
+ const qint64 len = s ? qint64(qstrlen(s)) + 1 : 0;
+ writeBytes(s, len);
return *this;
}
@@ -1403,22 +1387,26 @@ QDataStream &QDataStream::operator<<(char32_t c)
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
- The \a len is serialized as a quint32, followed by \a len bytes
- from \a s. Note that the data is \e not encoded.
+ The \a len is serialized as a quint32 and an optional quint64,
+ followed by \a len bytes from \a s. Note that the data is
+ \e not encoded.
\sa writeRawData(), readBytes()
*/
-QDataStream &QDataStream::writeBytes(const char *s, uint len)
+QDataStream &QDataStream::writeBytes(const char *s, qint64 len)
{
+ if (len < 0) {
+ q_status = WriteFailed;
+ return *this;
+ }
CHECK_STREAM_WRITE_PRECOND(*this)
- *this << (quint32)len; // write length specifier
- if (len)
+ // Write length then, if any, content
+ if (writeQSizeType(*this, len) && len > 0)
writeRawData(s, len);
return *this;
}
-
/*!
Writes \a len bytes from \a s to the stream. Returns the
number of bytes actually written, or -1 on error.
@@ -1427,10 +1415,10 @@ QDataStream &QDataStream::writeBytes(const char *s, uint len)
\sa writeBytes(), QIODevice::write(), readRawData()
*/
-int QDataStream::writeRawData(const char *s, int len)
+qint64 QDataStream::writeRawData(const char *s, qint64 len)
{
CHECK_STREAM_WRITE_PRECOND(-1)
- int ret = dev->write(s, len);
+ qint64 ret = dev->write(s, len);
if (ret != len)
q_status = WriteFailed;
return ret;
@@ -1447,13 +1435,13 @@ int QDataStream::writeRawData(const char *s, int len)
\sa QIODevice::seek()
*/
-int QDataStream::skipRawData(int len)
+qint64 QDataStream::skipRawData(qint64 len)
{
CHECK_STREAM_PRECOND(-1)
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int skipResult = dev->skip(len);
+ const qint64 skipResult = dev->skip(len);
if (skipResult != len)
setStatus(ReadPastEnd);
return skipResult;
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index a673bfab82..cf37df71d7 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDATASTREAM_H
#define QDATASTREAM_H
@@ -45,25 +9,43 @@
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qnamespace.h>
+#include <iterator> // std::distance(), std::next()
+
#ifdef Status
#error qdatastream.h must be included before any header file that defines Status
#endif
QT_BEGIN_NAMESPACE
+#if QT_CORE_REMOVED_SINCE(6, 3)
class qfloat16;
+#endif
class QByteArray;
+class QDataStream;
class QIODevice;
+class QString;
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
class QDataStreamPrivate;
namespace QtPrivate {
class StreamStateSaver;
+template <typename Container>
+QDataStream &readArrayBasedContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &readListBasedContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &readAssociativeContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &writeSequentialContainer(QDataStream &s, const Container &c);
+template <typename Container>
+QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c);
+template <typename Container>
+QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c);
}
class Q_CORE_EXPORT QDataStream : public QIODeviceBase
{
public:
- enum Version {
+ enum Version QT7_ONLY(: quint8) {
Qt_1_0 = 1,
Qt_2_0 = 2,
Qt_2_1 = 3,
@@ -100,8 +82,13 @@ public:
Qt_6_1 = Qt_6_0,
Qt_6_2 = Qt_6_0,
Qt_6_3 = Qt_6_0,
- Qt_DefaultCompiledVersion = Qt_6_3
-#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ Qt_6_4 = Qt_6_0,
+ Qt_6_5 = Qt_6_0,
+ Qt_6_6 = 21,
+ Qt_6_7 = 22,
+ Qt_6_8 = Qt_6_7,
+ Qt_DefaultCompiledVersion = Qt_6_8
+#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
};
@@ -111,14 +98,15 @@ public:
LittleEndian = QSysInfo::LittleEndian
};
- enum Status {
+ enum Status QT7_ONLY(: quint8) {
Ok,
ReadPastEnd,
ReadCorruptData,
- WriteFailed
+ WriteFailed,
+ SizeLimitExceeded,
};
- enum FloatingPointPrecision {
+ enum FloatingPointPrecision QT7_ONLY(: quint8) {
SinglePrecision,
DoublePrecision
};
@@ -134,10 +122,12 @@ public:
bool atEnd() const;
+ QT_CORE_INLINE_SINCE(6, 8)
Status status() const;
void setStatus(Status status);
void resetStatus();
+ QT_CORE_INLINE_SINCE(6, 8)
FloatingPointPrecision floatingPointPrecision() const;
void setFloatingPointPrecision(FloatingPointPrecision precision);
@@ -159,8 +149,9 @@ public:
QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
QDataStream &operator>>(bool &i);
- // ### Qt 7: remove the operator or make qfloat16 fully defined, see QTBUG-93499
+#if QT_CORE_REMOVED_SINCE(6, 3)
QDataStream &operator>>(qfloat16 &f);
+#endif
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@@ -177,23 +168,42 @@ public:
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
QDataStream &operator<<(std::nullptr_t) { return *this; }
+#if QT_CORE_REMOVED_SINCE(6, 8) || defined(Q_QDOC)
QDataStream &operator<<(bool i);
- // ### Qt 7: remove the operator or make qfloat16 fully defined, see QTBUG-93499
+#endif
+#if !defined(Q_QDOC)
+ // Disable implicit conversions to bool (e.g. for pointers)
+ template <typename T,
+ std::enable_if_t<std::is_same_v<T, bool>, bool> = true>
+ QDataStream &operator<<(T i)
+ {
+ return (*this << qint8(i));
+ }
+#endif
+#if QT_CORE_REMOVED_SINCE(6, 3)
QDataStream &operator<<(qfloat16 f);
+#endif
QDataStream &operator<<(float f);
QDataStream &operator<<(double f);
QDataStream &operator<<(const char *str);
QDataStream &operator<<(char16_t c);
QDataStream &operator<<(char32_t c);
-
+#if QT_DEPRECATED_SINCE(6, 11)
+ QT_DEPRECATED_VERSION_X_6_11("Use an overload that takes qint64 length.")
QDataStream &readBytes(char *&, uint &len);
- int readRawData(char *, int len);
-
+#endif
+#if QT_CORE_REMOVED_SINCE(6, 7)
QDataStream &writeBytes(const char *, uint len);
- int writeRawData(const char *, int len);
-
int skipRawData(int len);
+ int readRawData(char *, int len);
+ int writeRawData(const char *, int len);
+#endif
+ QDataStream &readBytes(char *&, qint64 &len);
+ qint64 readRawData(char *, qint64 len);
+ QDataStream &writeBytes(const char *, qint64 len);
+ qint64 writeRawData(const char *, qint64 len);
+ qint64 skipRawData(qint64 len);
void startTransaction();
bool commitTransaction();
@@ -206,21 +216,53 @@ private:
QScopedPointer<QDataStreamPrivate> d;
- QIODevice *dev;
- bool owndev;
- bool noswap;
- ByteOrder byteorder;
- int ver;
- Status q_status;
+ QIODevice *dev = nullptr;
+ bool owndev = false;
+ bool noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ quint8 fpPrecision = QDataStream::DoublePrecision;
+ quint8 q_status = Ok;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ ByteOrder byteorder = BigEndian;
+ int ver = Qt_DefaultCompiledVersion;
+#else
+ Version ver = Qt_DefaultCompiledVersion;
+#endif
+ quint16 transactionDepth = 0;
+#if QT_CORE_REMOVED_SINCE(6, 7)
int readBlock(char *data, int len);
+#endif
+ qint64 readBlock(char *data, qint64 len);
+ static inline qint64 readQSizeType(QDataStream &s);
+ static inline bool writeQSizeType(QDataStream &s, qint64 value);
+ static constexpr quint32 NullCode = 0xffffffffu;
+ static constexpr quint32 ExtendedSize = 0xfffffffeu;
+
friend class QtPrivate::StreamStateSaver;
+ Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QString &str);
+ Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QString &str);
+ Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QByteArray &ba);
+ Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QByteArray &ba);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readArrayBasedContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readListBasedContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readAssociativeContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeSequentialContainer(QDataStream &s, const Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeAssociativeContainer(QDataStream &s, const Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeAssociativeMultiContainer(QDataStream &s,
+ const Container &c);
};
namespace QtPrivate {
class StreamStateSaver
{
+ Q_DISABLE_COPY_MOVE(StreamStateSaver)
public:
inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status())
{
@@ -246,10 +288,14 @@ QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
c.reserve(n);
- for (quint32 i = 0; i < n; ++i) {
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::value_type t;
s >> t;
if (s.status() != QDataStream::Ok) {
@@ -268,9 +314,13 @@ QDataStream &readListBasedContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::value_type t;
s >> t;
if (s.status() != QDataStream::Ok) {
@@ -289,9 +339,13 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::key_type k;
typename Container::mapped_type t;
s >> k >> t;
@@ -308,7 +362,8 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
template <typename Container>
QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
for (const typename Container::value_type &t : c)
s << t;
@@ -318,7 +373,8 @@ QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
template <typename Container>
QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
auto it = c.constBegin();
auto end = c.constEnd();
while (it != end) {
@@ -332,7 +388,8 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
template <typename Container>
QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
auto it = c.constBegin();
auto end = c.constEnd();
while (it != end) {
@@ -372,14 +429,58 @@ using QDataStreamIfHasIStreamOperatorsContainer =
inline QIODevice *QDataStream::device() const
{ return dev; }
+#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
+QDataStream::Status QDataStream::status() const
+{
+ return Status(q_status);
+}
+
+QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+{
+ return FloatingPointPrecision(fpPrecision);
+}
+#endif // INLINE_SINCE 6.8
+
inline QDataStream::ByteOrder QDataStream::byteOrder() const
-{ return byteorder; }
+{
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return noswap ? BigEndian : LittleEndian;
+ return noswap ? LittleEndian : BigEndian;
+}
inline int QDataStream::version() const
{ return ver; }
inline void QDataStream::setVersion(int v)
-{ ver = v; }
+{ ver = Version(v); }
+
+qint64 QDataStream::readQSizeType(QDataStream &s)
+{
+ quint32 first;
+ s >> first;
+ if (first == NullCode)
+ return -1;
+ if (first < ExtendedSize || s.version() < QDataStream::Qt_6_7)
+ return qint64(first);
+ qint64 extendedLen;
+ s >> extendedLen;
+ return extendedLen;
+}
+
+bool QDataStream::writeQSizeType(QDataStream &s, qint64 value)
+{
+ if (value < qint64(ExtendedSize)) {
+ s << quint32(value);
+ } else if (s.version() >= QDataStream::Qt_6_7) {
+ s << ExtendedSize << value;
+ } else if (value == qint64(ExtendedSize)) {
+ s << ExtendedSize;
+ } else {
+ s.setStatus(QDataStream::SizeLimitExceeded); // value is too big for old format
+ return false;
+ }
+ return true;
+}
inline QDataStream &QDataStream::operator>>(char &i)
{ return *this >> reinterpret_cast<qint8&>(i); }
@@ -434,7 +535,7 @@ typename std::enable_if_t<std::is_enum<T>::value, QDataStream &>
operator>>(QDataStream &s, T &t)
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template<typename T>
inline QDataStreamIfHasIStreamOperatorsContainer<QList<T>, T> operator>>(QDataStream &s, QList<T> &v)
@@ -567,7 +668,7 @@ QDataStream &operator>>(QDataStream& s, std::pair<T1, T2> &p);
template <class T1, class T2>
QDataStream &operator<<(QDataStream& s, const std::pair<T1, T2> &p);
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
inline QDataStream &operator>>(QDataStream &s, QKeyCombination &combination)
{
diff --git a/src/corelib/serialization/qdatastream_p.h b/src/corelib/serialization/qdatastream_p.h
index 3ca0ae840e..c4fe7c784c 100644
--- a/src/corelib/serialization/qdatastream_p.h
+++ b/src/corelib/serialization/qdatastream_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDATASTREAM_P_H
#define QDATASTREAM_P_H
@@ -60,11 +24,6 @@ QT_BEGIN_NAMESPACE
class QDataStreamPrivate
{
public:
- QDataStreamPrivate() : floatingPointPrecision(QDataStream::DoublePrecision),
- transactionDepth(0) { }
-
- QDataStream::FloatingPointPrecision floatingPointPrecision;
- int transactionDepth;
};
#endif
diff --git a/src/corelib/serialization/qjson_p.h b/src/corelib/serialization/qjson_p.h
index edab2c6b13..5a5b6926be 100644
--- a/src/corelib/serialization/qjson_p.h
+++ b/src/corelib/serialization/qjson_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSON_P_H
#define QJSON_P_H
@@ -56,6 +20,11 @@
#include <qcborvalue.h>
#include <private/qcborvalue_p.h>
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+# include <qjsonarray.h>
+# include <qjsonobject.h>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QJsonPrivate {
@@ -136,7 +105,6 @@ struct ObjectIterator
bool operator<=(ObjectIterator other) const { return it <= other.it; }
bool operator>=(ObjectIterator other) const { return it >= other.it; }
-private:
ElementsIterator it;
};
@@ -203,8 +171,31 @@ inline void swap(KeyIterator::reference a, KeyIterator::reference b)
class Value
{
public:
- static QCborContainerPrivate *container(const QCborValue &v) { return v.container; }
static qint64 valueHelper(const QCborValue &v) { return v.n; }
+ static QCborContainerPrivate *container(const QCborValue &v) { return v.container; }
+ static const QCborContainerPrivate *container(QJsonValueConstRef r) noexcept
+ {
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ return (r.is_object ? r.o->o : r.a->a).data();
+#else
+ return r.d;
+#endif
+ }
+ static QCborContainerPrivate *container(QJsonValueRef r) noexcept
+ {
+ return const_cast<QCborContainerPrivate *>(container(QJsonValueConstRef(r)));
+ }
+ static qsizetype indexHelper(QJsonValueConstRef r) noexcept
+ {
+ qsizetype index = r.index;
+ if (r.is_object)
+ index = index * 2 + 1;
+ return index;
+ }
+ static const QtCbor::Element &elementHelper(QJsonValueConstRef r) noexcept
+ {
+ return container(r)->elements.at(indexHelper(r));
+ }
static QJsonValue fromTrustedCbor(const QCborValue &v)
{
diff --git a/src/corelib/serialization/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp
index bf678a0bd8..0c1b0ac7c8 100644
--- a/src/corelib/serialization/qjsonarray.cpp
+++ b/src/corelib/serialization/qjsonarray.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qjsonobject.h>
#include <qjsonvalue.h>
@@ -58,11 +22,16 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonArray class encapsulates a JSON array.
+ \compares equality
+ \compareswith equality QJsonValue
+ \endcompareswith
+
A JSON array is a list of values. The list can be manipulated by inserting and
removing QJsonValue's from the array.
@@ -75,7 +44,7 @@ QT_BEGIN_NAMESPACE
You can convert the array to and from text based JSON through QJsonDocument.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -155,7 +124,6 @@ QJsonArray::QJsonArray() = default;
QJsonArray::QJsonArray(QCborContainerPrivate *array)
: a(array)
{
- Q_ASSERT(array);
}
/*!
@@ -175,11 +143,13 @@ QJsonArray::QJsonArray(std::initializer_list<QJsonValue> args)
Since QJsonArray is implicitly shared, the copy is shallow
as long as the object doesn't get modified.
*/
-QJsonArray::QJsonArray(const QJsonArray &other)
-{
- a = other.a;
-}
+QJsonArray::QJsonArray(const QJsonArray &other) noexcept = default;
+
+/*!
+ \since 5.10
+ Move-constructs a QJsonArray from \a other.
+*/
QJsonArray::QJsonArray(QJsonArray &&other) noexcept
: a(other.a)
{
@@ -189,18 +159,7 @@ QJsonArray::QJsonArray(QJsonArray &&other) noexcept
/*!
Assigns \a other to this array.
*/
-QJsonArray &QJsonArray::operator =(const QJsonArray &other)
-{
- a = other.a;
- return *this;
-}
-
-/*!
- \fn QJsonArray::QJsonArray(QJsonArray &&other)
- \since 5.10
-
- Move-constructs a QJsonArray from \a other.
-*/
+QJsonArray &QJsonArray::operator =(const QJsonArray &other) noexcept = default;
/*!
\fn QJsonArray &QJsonArray::operator =(QJsonArray &&other)
@@ -256,6 +215,7 @@ QJsonArray QJsonArray::fromStringList(const QStringList &list)
return array;
}
+#ifndef QT_NO_VARIANT
/*!
Converts the variant list \a list to a QJsonArray.
@@ -280,6 +240,7 @@ QVariantList QJsonArray::toVariantList() const
{
return QCborArray::fromJsonArray(*this).toVariantList();
}
+#endif // !QT_NO_VARIANT
/*!
@@ -376,7 +337,7 @@ void QJsonArray::append(const QJsonValue &value)
*/
void QJsonArray::removeAt(qsizetype i)
{
- if (!a || i < 0 || i >= a->elements.length())
+ if (!a || i < 0 || i >= a->elements.size())
return;
detach();
a->removeAt(i);
@@ -412,7 +373,7 @@ void QJsonArray::removeAt(qsizetype i)
*/
QJsonValue QJsonArray::takeAt(qsizetype i)
{
- if (!a || i < 0 || i >= a->elements.length())
+ if (!a || i < 0 || i >= a->elements.size())
return QJsonValue(QJsonValue::Undefined);
detach();
@@ -431,11 +392,11 @@ QJsonValue QJsonArray::takeAt(qsizetype i)
void QJsonArray::insert(qsizetype i, const QJsonValue &value)
{
if (a)
- detach(a->elements.length() + 1);
+ detach(a->elements.size() + 1);
else
a = new QCborContainerPrivate;
- Q_ASSERT (i >= 0 && i <= a->elements.length());
+ Q_ASSERT (i >= 0 && i <= a->elements.size());
a->insertAt(i, value.type() == QJsonValue::Undefined ? QCborValue(nullptr)
: QCborValue::fromJsonValue(value));
}
@@ -466,7 +427,7 @@ void QJsonArray::insert(qsizetype i, const QJsonValue &value)
*/
void QJsonArray::replace(qsizetype i, const QJsonValue &value)
{
- Q_ASSERT (a && i >= 0 && i < a->elements.length());
+ Q_ASSERT (a && i >= 0 && i < a->elements.size());
detach();
a->replaceAt(i, QCborValue::fromJsonValue(value));
}
@@ -500,7 +461,7 @@ bool QJsonArray::contains(const QJsonValue &value) const
*/
QJsonValueRef QJsonArray::operator [](qsizetype i)
{
- Q_ASSERT(a && i >= 0 && i < a->elements.length());
+ Q_ASSERT(a && i >= 0 && i < a->elements.size());
return QJsonValueRef(this, i);
}
@@ -514,36 +475,40 @@ QJsonValue QJsonArray::operator[](qsizetype i) const
return at(i);
}
-/*!
- Returns \c true if this array is equal to \a other.
- */
-bool QJsonArray::operator==(const QJsonArray &other) const
+bool comparesEqual(const QJsonArray &lhs, const QJsonArray &rhs) noexcept
{
- if (a == other.a)
+ if (lhs.a == rhs.a)
return true;
- if (!a)
- return !other.a->elements.length();
- if (!other.a)
- return !a->elements.length();
- if (a->elements.length() != other.a->elements.length())
+ if (!lhs.a)
+ return !rhs.a->elements.size();
+ if (!rhs.a)
+ return !lhs.a->elements.size();
+ if (lhs.a->elements.size() != rhs.a->elements.size())
return false;
- for (qsizetype i = 0; i < a->elements.length(); ++i) {
- if (a->valueAt(i) != other.a->valueAt(i))
+ for (qsizetype i = 0; i < lhs.a->elements.size(); ++i) {
+ if (lhs.a->valueAt(i) != rhs.a->valueAt(i))
return false;
}
return true;
}
-/*!
- Returns \c true if this array is not equal to \a other.
- */
-bool QJsonArray::operator!=(const QJsonArray &other) const
+bool comparesEqual(const QJsonArray &lhs, const QJsonValue &rhs) noexcept
{
- return !(*this == other);
+ return lhs == rhs.toArray();
}
+/*! \fn bool QJsonArray::operator==(const QJsonArray &lhs, const QJsonArray &rhs)
+
+ Returns \c true if \a lhs array is equal to \a rhs, \c false otherwise.
+*/
+
+/*! \fn bool QJsonArray::operator!=(const QJsonArray &lhs, const QJsonArray &rhs)
+
+ Returns \c true if \a lhs array is not equal to \a rhs, \c false otherwise.
+*/
+
/*! \fn QJsonArray::iterator QJsonArray::begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
@@ -638,6 +603,10 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\inmodule QtCore
\brief The QJsonArray::iterator class provides an STL-style non-const iterator for QJsonArray.
+ \compares strong
+ \compareswith strong QJsonArray::const_iterator
+ \endcompareswith
+
QJsonArray::iterator allows you to iterate over a QJsonArray
and to modify the array item associated with the
iterator. If you want to iterate over a const QJsonArray, use
@@ -742,60 +711,60 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
*/
/*!
- \fn bool QJsonArray::iterator::operator==(const iterator &other) const
- \fn bool QJsonArray::iterator::operator==(const const_iterator &other) const
+ \fn bool QJsonArray::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator==(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QJsonArray::iterator::operator!=(const iterator &other) const
- \fn bool QJsonArray::iterator::operator!=(const const_iterator &other) const
+ \fn bool QJsonArray::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator!=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonArray::iterator::operator<(const iterator& other) const
- \fn bool QJsonArray::iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator<(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator<(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator<=(const iterator& other) const
- \fn bool QJsonArray::iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator<=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator<=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator>(const iterator& other) const
- \fn bool QJsonArray::iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator>(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator>(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator>=(const iterator& other) const
- \fn bool QJsonArray::iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator>=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator>=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator++()
- The prefix ++ operator, \c{++it}, advances the iterator to the
+ The prefix \c{++} operator, \c{++it}, advances the iterator to the
next item in the array and returns an iterator to the new current
item.
@@ -808,14 +777,14 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\overload
- The postfix ++ operator, \c{it++}, advances the iterator to the
+ The postfix \c{++} operator, \c{it++}, advances the iterator to the
next item in the array and returns an iterator to the previously
current item.
*/
/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator--()
- The prefix -- operator, \c{--it}, makes the preceding item
+ The prefix \c{--} operator, \c{--it}, makes the preceding item
current and returns an iterator to the new current item.
Calling this function on QJsonArray::begin() leads to undefined results.
@@ -827,7 +796,7 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\overload
- The postfix -- operator, \c{it--}, makes the preceding item
+ The postfix \c{--} operator, \c{it--}, makes the preceding item
current and returns an iterator to the previously current item.
*/
@@ -873,6 +842,10 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\inmodule QtCore
\brief The QJsonArray::const_iterator class provides an STL-style const iterator for QJsonArray.
+ \compares strong
+ \compareswith strong QJsonArray::iterator
+ \endcompareswith
+
QJsonArray::const_iterator allows you to iterate over a
QJsonArray. If you want to modify the QJsonArray as
you iterate over it, use QJsonArray::iterator instead. It is generally a
@@ -965,53 +938,53 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\sa operator+()
*/
-/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &other) const
+/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
-/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &other) const
+/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonArray::const_iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator<(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator<=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator>(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator>=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator++()
- The prefix ++ operator, \c{++it}, advances the iterator to the
+ The prefix \c{++} operator, \c{++it}, advances the iterator to the
next item in the array and returns an iterator to the new current
item.
@@ -1024,14 +997,14 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\overload
- The postfix ++ operator, \c{it++}, advances the iterator to the
+ The postfix \c{++} operator, \c{it++}, advances the iterator to the
next item in the array and returns an iterator to the previously
current item.
*/
/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator--()
- The prefix -- operator, \c{--it}, makes the preceding item
+ The prefix \c{--} operator, \c{--it}, makes the preceding item
current and returns an iterator to the new current item.
Calling this function on QJsonArray::begin() leads to undefined results.
@@ -1043,7 +1016,7 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\overload
- The postfix -- operator, \c{it--}, makes the preceding item
+ The postfix \c{--} operator, \c{it--}, makes the preceding item
current and returns an iterator to the previously current item.
*/
@@ -1121,9 +1094,7 @@ QDebug operator<<(QDebug dbg, const QJsonArray &a)
#ifndef QT_NO_DATASTREAM
QDataStream &operator<<(QDataStream &stream, const QJsonArray &array)
{
- QJsonDocument doc{array};
- stream << doc.toJson(QJsonDocument::Compact);
- return stream;
+ return stream << QJsonDocument{array};
}
QDataStream &operator>>(QDataStream &stream, QJsonArray &array)
diff --git a/src/corelib/serialization/qjsonarray.h b/src/corelib/serialization/qjsonarray.h
index 406fbc2f47..26a04e9196 100644
--- a/src/corelib/serialization/qjsonarray.h
+++ b/src/corelib/serialization/qjsonarray.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONARRAY_H
#define QJSONARRAY_H
@@ -59,8 +23,8 @@ public:
~QJsonArray();
- QJsonArray(const QJsonArray &other);
- QJsonArray &operator =(const QJsonArray &other);
+ QJsonArray(const QJsonArray &other) noexcept;
+ QJsonArray &operator =(const QJsonArray &other) noexcept;
QJsonArray(QJsonArray &&other) noexcept;
@@ -96,12 +60,13 @@ public:
QJsonValueRef operator[](qsizetype i);
QJsonValue operator[](qsizetype i) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonArray &other) const;
bool operator!=(const QJsonArray &other) const;
-
+#endif
void swap(QJsonArray &other) noexcept
{
- qSwap(a, other.a);
+ a.swap(other.a);
}
class const_iterator;
@@ -120,48 +85,94 @@ public:
constexpr iterator(const iterator &other) = default;
iterator &operator=(const iterator &other)
{
- item.a = other.item.a;
- item.index = other.item.index;
+ item.rebind(other.item);
return *this;
}
inline QJsonValueRef operator*() const { return item; }
- inline QJsonValueRef *operator->() const { return &item; }
- inline QJsonValueRef operator[](qsizetype j) const
- { return { item.a, qsizetype(item.index) + j }; }
+ inline const QJsonValueConstRef *operator->() const { return &item; }
+ inline QJsonValueRef *operator->() { return &item; }
+ inline QJsonValueRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &o) const
- { return item.a == o.item.a && item.index == o.item.index; }
- inline bool operator!=(const iterator &o) const { return !(*this == o); }
+ { return item.d == o.item.d && item.index == o.item.index; }
+ inline bool operator!=(const iterator &o) const { return !operator==(o); }
inline bool operator<(const iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index <= other.item.index; }
- inline bool operator>(const iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const iterator &other) const { return !(*this < other); }
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ inline bool operator>(const iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const iterator &other) const { return !operator<(other); }
inline bool operator==(const const_iterator &o) const
- { return item.a == o.item.a && item.index == o.item.index; }
- inline bool operator!=(const const_iterator &o) const { return !(*this == o); }
+ { return item.d == o.item.d && item.index == o.item.index; }
+ inline bool operator!=(const const_iterator &o) const { return !operator==(o); }
inline bool operator<(const const_iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const const_iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index <= other.item.index; }
- inline bool operator>(const const_iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const const_iterator &other) const { return !(*this < other); }
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ inline bool operator>(const const_iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const const_iterator &other) const { return !operator<(other); }
+#endif
inline iterator &operator++() { ++item.index; return *this; }
inline iterator operator++(int) { iterator n = *this; ++item.index; return n; }
inline iterator &operator--() { item.index--; return *this; }
inline iterator operator--(int) { iterator n = *this; item.index--; return n; }
inline iterator &operator+=(qsizetype j) { item.index += quint64(j); return *this; }
inline iterator &operator-=(qsizetype j) { item.index -= quint64(j); return *this; }
- inline iterator operator+(qsizetype j) const
- { return iterator(item.a, qsizetype(item.index) + j); }
- inline iterator operator-(qsizetype j) const
- { return iterator(item.a, qsizetype(item.index) - j); }
+ inline iterator operator+(qsizetype j) const { iterator r = *this; return r += j; }
+ inline iterator operator-(qsizetype j) const { return operator+(-j); }
inline qsizetype operator-(iterator j) const { return item.index - j.item.index; }
private:
- mutable QJsonValueRef item;
+ // Helper functions
+ static bool comparesEqual_helper(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static bool comparesEqual_helper(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator)
+ friend bool comparesEqual(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator, const_iterator)
+
+ QJsonValueRef item;
friend class QJsonArray;
};
friend class iterator;
@@ -182,39 +193,61 @@ public:
constexpr const_iterator(const const_iterator &other) = default;
const_iterator &operator=(const const_iterator &other)
{
- item.a = other.item.a;
- item.index = other.item.index;
+ item.rebind(other.item);
return *this;
}
- inline const QJsonValueRef operator*() const { return item; }
- inline const QJsonValueRef *operator->() const { return &item; }
+ inline const QJsonValueConstRef operator*() const { return item; }
+ inline const QJsonValueConstRef *operator->() const { return &item; }
- inline QJsonValueRef operator[](qsizetype j) const
- { return { item.a, qsizetype(item.index) + j }; }
+ inline QJsonValueConstRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &o) const
- { return item.a == o.item.a && item.index == o.item.index; }
- inline bool operator!=(const const_iterator &o) const { return !(*this == o); }
+ { return item.d == o.item.d && item.index == o.item.index; }
+ inline bool operator!=(const const_iterator &o) const { return !operator==(o); }
inline bool operator<(const const_iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const const_iterator &other) const
- { Q_ASSERT(item.a == other.item.a); return item.index <= other.item.index; }
- inline bool operator>(const const_iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const const_iterator &other) const { return !(*this < other); }
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ inline bool operator>(const const_iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const const_iterator &other) const { return !operator<(other); }
+#endif
inline const_iterator &operator++() { ++item.index; return *this; }
inline const_iterator operator++(int) { const_iterator n = *this; ++item.index; return n; }
inline const_iterator &operator--() { item.index--; return *this; }
inline const_iterator operator--(int) { const_iterator n = *this; item.index--; return n; }
inline const_iterator &operator+=(qsizetype j) { item.index += quint64(j); return *this; }
inline const_iterator &operator-=(qsizetype j) { item.index -= quint64(j); return *this; }
- inline const_iterator operator+(qsizetype j) const
- { return const_iterator(item.a, qsizetype(item.index) + j); }
- inline const_iterator operator-(qsizetype j) const
- { return const_iterator(item.a, qsizetype(item.index) - j); }
+ inline const_iterator operator+(qsizetype j) const { const_iterator r = *this; return r += j; }
+ inline const_iterator operator-(qsizetype j) const { return operator+(-j); }
inline qsizetype operator-(const_iterator j) const { return item.index - j.item.index; }
private:
- QJsonValueRef item;
+ // Helper functions
+ static bool comparesEqual_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const const_iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(const_iterator)
+ QJsonValueConstRef item;
friend class QJsonArray;
};
friend class const_iterator;
@@ -261,10 +294,21 @@ public:
private:
friend class QJsonValue;
+ friend class QJsonValueConstRef;
+ friend class QJsonValueRef;
+ friend class QJsonPrivate::Value;
friend class QJsonDocument;
friend class QCborArray;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonArray &lhs,
+ const QJsonArray &rhs) noexcept;
+
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonArray &lhs,
+ const QJsonValue &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonArray)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonArray, QJsonValue)
+
QJsonArray(QCborContainerPrivate *array);
bool detach(qsizetype reserve = 0);
@@ -273,6 +317,12 @@ private:
Q_DECLARE_SHARED(QJsonArray)
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
+inline QJsonValueConstRef::QJsonValueConstRef(QJsonArray *a, qsizetype idx)
+ : d(a ? a->a.data() : nullptr), is_object(false), index(idx)
+{}
+#endif
+
Q_CORE_EXPORT size_t qHash(const QJsonArray &array, size_t seed = 0);
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
diff --git a/src/corelib/serialization/qjsoncbor.cpp b/src/corelib/serialization/qjsoncbor.cpp
index 3d79388b1d..da07eca8a7 100644
--- a/src/corelib/serialization/qjsoncbor.cpp
+++ b/src/corelib/serialization/qjsoncbor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcborvalue.h"
#include "qcborvalue_p.h"
@@ -48,6 +12,9 @@
#include "qjsondocument.h"
#include "qjson_p.h"
+#include <qmap.h>
+#include <qhash.h>
+
#include <private/qnumeric_p.h>
#include <quuid.h>
@@ -98,7 +65,6 @@ 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):
@@ -115,8 +81,12 @@ static QString maybeEncodeTag(const QCborContainerPrivate *d)
break;
case qint64(QCborKnownTags::Uuid):
- if (e.type == QCborValue::ByteArray && b->len == sizeof(QUuid))
+#ifndef QT_BOOTSTRAPPED
+ if (const ByteData *b = d->byteData(e); e.type == QCborValue::ByteArray && b
+ && b->len == sizeof(QUuid))
return QUuid::fromRfc4122(b->asByteArrayView()).toString(QUuid::WithoutBraces);
+#endif
+ break;
}
// don't know what to do, bail out
@@ -205,10 +175,14 @@ static QJsonValue convertExtendedTypeToJson(QCborContainerPrivate *d)
switch (tag) {
case qint64(QCborKnownTags::Url):
- // use the fullly-encoded URL form
+#ifdef QT_BOOTSTRAPPED
+ break;
+#else
+ // use the fully-encoded URL form
if (d->elements.at(1).type == QCborValue::String)
return QUrl::fromEncoded(d->byteData(1)->asByteArrayView()).toString(QUrl::FullyEncoded);
Q_FALLTHROUGH();
+#endif
case qint64(QCborKnownTags::DateTimeString):
case qint64(QCborKnownTags::ExpectedBase64url):
@@ -424,10 +398,12 @@ QJsonValue QCborValue::toJsonValue() const
return QJsonPrivate::Value::fromTrustedCbor(simpleTypeString(type()));
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QJsonValue QCborValueRef::toJsonValue() const
{
return qt_convertToJson(d, i);
}
+#endif
/*!
Recursively converts every \l QCborValue element in this array to JSON
@@ -445,11 +421,13 @@ QJsonArray QCborArray::toJsonArray() const
return convertToJsonArray(d.data());
}
+#ifndef QT_NO_VARIANT
QJsonArray QJsonPrivate::Variant::toJsonArray(const QVariantList &list)
{
const auto cborArray = QCborArray::fromVariantList(list);
return convertToJsonArray(cborArray.d.data(), ConversionMode::FromVariantToJson);
}
+#endif // !QT_NO_VARIANT
/*!
Recursively converts every \l QCborValue value in this map to JSON using
@@ -493,6 +471,7 @@ QJsonObject QCborMap::toJsonObject() const
return convertToJsonObject(d.data());
}
+#ifndef QT_NO_VARIANT
QJsonObject QJsonPrivate::Variant::toJsonObject(const QVariantMap &map)
{
const auto cborMap = QCborMap::fromVariantMap(map);
@@ -580,15 +559,15 @@ QVariant QCborValue::toVariant() const
#ifndef QT_BOOTSTRAPPED
case Url:
return toUrl();
-#endif
-#if QT_CONFIG(regularexpression)
+# if QT_CONFIG(regularexpression)
case RegularExpression:
return toRegularExpression();
-#endif
+# endif
case Uuid:
return toUuid();
+#endif
case Invalid:
return QVariant();
@@ -600,9 +579,9 @@ QVariant QCborValue::toVariant() const
if (isSimpleType())
return QVariant::fromValue(toSimpleType());
- Q_UNREACHABLE();
- return QVariant();
+ Q_UNREACHABLE_RETURN(QVariant());
}
+#endif // !QT_NO_VARIANT
/*!
Converts the JSON value contained in \a v into its corresponding CBOR value
@@ -656,6 +635,7 @@ QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
return QCborValue();
}
+#ifndef QT_NO_VARIANT
static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
{
// Handle strings and byte arrays directly, to avoid creating a temporary
@@ -757,9 +737,9 @@ QCborValue QCborValue::fromVariant(const QVariant &variant)
#ifndef QT_BOOTSTRAPPED
case QMetaType::QUrl:
return QCborValue(variant.toUrl());
-#endif
case QMetaType::QUuid:
return QCborValue(variant.toUuid());
+#endif
case QMetaType::QVariantList:
return QCborArray::fromVariantList(variant.toList());
case QMetaType::QVariantMap:
@@ -856,6 +836,7 @@ QCborArray QCborArray::fromVariantList(const QVariantList &list)
appendVariant(a.d.data(), v);
return a;
}
+#endif // !QT_NO_VARIANT
/*!
Converts all JSON items found in the \a array array to CBOR using
@@ -887,6 +868,7 @@ QCborArray QCborArray::fromJsonArray(QJsonArray &&array) noexcept
}
+#ifndef QT_NO_VARIANT
/*!
Converts the CBOR values to QVariant using QCborValue::toVariant() and
"stringifies" all the CBOR keys in this map, returning the QVariantMap that
@@ -983,6 +965,7 @@ QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
}
return m;
}
+#endif // !QT_NO_VARIANT
/*!
Converts all JSON items found in the \a obj object to CBOR using
diff --git a/src/corelib/serialization/qjsondocument.cpp b/src/corelib/serialization/qjsondocument.cpp
index 6b015d759d..e2528f18dc 100644
--- a/src/corelib/serialization/qjsondocument.cpp
+++ b/src/corelib/serialization/qjsondocument.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qjsondocument.h>
#include <qjsonobject.h>
@@ -43,6 +7,8 @@
#include <qjsonarray.h>
#include <qstringlist.h>
#include <qvariant.h>
+#include <qmap.h>
+#include <qhash.h>
#include <qdebug.h>
#include <qcbormap.h>
#include <qcborarray.h>
@@ -58,11 +24,14 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonDocument class provides a way to read and write JSON documents.
+ \compares equality
+
QJsonDocument is a class that wraps a complete JSON document and can read
this document from, and write it to, a UTF-8 encoded text-based
representation.
@@ -77,7 +46,7 @@ QT_BEGIN_NAMESPACE
and isObject(). The array or object contained in the document can be retrieved using
array() or object() and then read or manipulated.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
@@ -214,6 +183,7 @@ QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
Swaps the document \a other with this. This operation is very fast and never fails.
*/
+#ifndef QT_NO_VARIANT
/*!
Creates a QJsonDocument from the QVariant \a variant.
@@ -264,6 +234,7 @@ QVariant QJsonDocument::toVariant() const
return QJsonArray(container).toVariantList();
return QJsonObject(container).toVariantMap();
}
+#endif // !QT_NO_VARIANT
/*!
\enum QJsonDocument::JsonFormat
@@ -285,7 +256,7 @@ QVariant QJsonDocument::toVariant() const
\sa fromJson(), JsonFormat
*/
-#if !defined(QT_JSON_READONLY) || defined(Q_CLANG_QDOC)
+#if !defined(QT_JSON_READONLY) || defined(Q_QDOC)
QByteArray QJsonDocument::toJson(JsonFormat format) const
{
QByteArray json;
@@ -314,7 +285,7 @@ QByteArray QJsonDocument::toJson(JsonFormat format) const
*/
QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error)
{
- QJsonPrivate::Parser parser(json.constData(), json.length());
+ QJsonPrivate::Parser parser(json.constData(), json.size());
QJsonDocument result;
const QCborValue val = parser.parse(error);
if (val.isArray() || val.isMap()) {
@@ -425,7 +396,6 @@ void QJsonDocument::setArray(const QJsonArray &array)
d->value = QCborValue::fromJsonValue(array);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a QJsonValue representing the value for the key \a key.
@@ -442,7 +412,6 @@ const QJsonValue QJsonDocument::operator[](const QString &key) const
{
return (*this)[QStringView(key)];
}
-#endif
/*!
\overload
@@ -460,7 +429,7 @@ const QJsonValue QJsonDocument::operator[](QStringView key) const
\overload
\since 5.10
*/
-const QJsonValue QJsonDocument::operator[](QLatin1String key) const
+const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const
{
if (!isObject())
return QJsonValue(QJsonValue::Undefined);
@@ -489,20 +458,22 @@ const QJsonValue QJsonDocument::operator[](qsizetype i) const
}
/*!
- Returns \c true if the \a other document is equal to this document.
- */
-bool QJsonDocument::operator==(const QJsonDocument &other) const
+ \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs)
+
+ Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise.
+*/
+bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept
{
- if (d && other.d)
- return d->value == other.d->value;
- return !d == !other.d;
+ if (lhs.d && rhs.d)
+ return lhs.d->value == rhs.d->value;
+ return !lhs.d == !rhs.d;
}
/*!
- \fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
+ \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs)
- returns \c true if \a other is not equal to this document
- */
+ Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise.
+*/
/*!
returns \c true if this document is null.
diff --git a/src/corelib/serialization/qjsondocument.h b/src/corelib/serialization/qjsondocument.h
index d262a5e6b6..3659f7b5cb 100644
--- a/src/corelib/serialization/qjsondocument.h
+++ b/src/corelib/serialization/qjsondocument.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONDOCUMENT_H
#define QJSONDOCUMENT_H
+#include <QtCore/qcompare.h>
#include <QtCore/qjsonvalue.h>
#include <QtCore/qscopedpointer.h>
@@ -116,7 +81,7 @@ public:
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = nullptr);
-#if !defined(QT_JSON_READONLY) || defined(Q_CLANG_QDOC)
+#if !defined(QT_JSON_READONLY) || defined(Q_QDOC)
QByteArray toJson(JsonFormat format = Indented) const;
#endif
@@ -130,22 +95,23 @@ public:
void setObject(const QJsonObject &object);
void setArray(const QJsonArray &array);
-#if QT_STRINGVIEW_LEVEL < 2
const QJsonValue operator[](const QString &key) const;
-#endif
const QJsonValue operator[](QStringView key) const;
- const QJsonValue operator[](QLatin1String key) const;
+ const QJsonValue operator[](QLatin1StringView key) const;
const QJsonValue operator[](qsizetype i) const;
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonDocument &other) const;
- bool operator!=(const QJsonDocument &other) const { return !(*this == other); }
-
+ bool operator!=(const QJsonDocument &other) const { return !operator==(other); }
+#endif
bool isNull() const;
private:
friend class QJsonValue;
friend class QJsonPrivate::Parser;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonDocument &lhs,
+ const QJsonDocument &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonDocument)
QJsonDocument(const QCborValue &data);
diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp
index a06af5d02d..2f61de0824 100644
--- a/src/corelib/serialization/qjsonobject.cpp
+++ b/src/corelib/serialization/qjsonobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qjsonobject.h>
#include <qjsonvalue.h>
@@ -45,6 +9,8 @@
#include <qdebug.h>
#include <qvariant.h>
#include <qcbormap.h>
+#include <qmap.h>
+#include <qhash.h>
#include <private/qcborvalue_p.h>
#include "qjsonwriter_p.h"
@@ -59,11 +25,16 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonObject class encapsulates a JSON object.
+ \compares equality
+ \compareswith equality QJsonValue QJsonValueConstRef
+ \endcompareswith
+
A JSON object is a list of key value pairs, where the keys are unique strings
and the values are represented by a QJsonValue.
@@ -76,7 +47,7 @@ QT_BEGIN_NAMESPACE
You can convert the object to and from text based JSON through QJsonDocument.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -118,7 +89,7 @@ QT_BEGIN_NAMESPACE
QJsonObject::QJsonObject() = default;
/*!
- \fn QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
+ \fn QJsonObject::QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args)
\since 5.4
Constructs a QJsonObject instance initialized from \a args initialization list.
For example:
@@ -137,7 +108,6 @@ QJsonObject::QJsonObject() = default;
QJsonObject::QJsonObject(QCborContainerPrivate *object)
: o(object)
{
- Q_ASSERT(o);
}
/*!
@@ -145,7 +115,7 @@ QJsonObject::QJsonObject(QCborContainerPrivate *object)
*/
QJsonObject::~QJsonObject() = default;
-QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
+QJsonObject::QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args)
{
for (const auto &arg : args)
insert(arg.first, arg.second);
@@ -157,11 +127,13 @@ QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args
Since QJsonObject is implicitly shared, the copy is shallow
as long as the object does not get modified.
*/
-QJsonObject::QJsonObject(const QJsonObject &other)
-{
- o = other.o;
-}
+QJsonObject::QJsonObject(const QJsonObject &other) noexcept = default;
+
+/*!
+ \since 5.10
+ Move-constructs a QJsonObject from \a other.
+*/
QJsonObject::QJsonObject(QJsonObject &&other) noexcept
: o(other.o)
{
@@ -171,18 +143,8 @@ QJsonObject::QJsonObject(QJsonObject &&other) noexcept
/*!
Assigns \a other to this object.
*/
-QJsonObject &QJsonObject::operator =(const QJsonObject &other)
-{
- o = other.o;
- return *this;
-}
+QJsonObject &QJsonObject::operator =(const QJsonObject &other) noexcept = default;
-/*!
- \fn QJsonObject::QJsonObject(QJsonObject &&other)
- \since 5.10
-
- Move-constructs a QJsonObject from \a other.
-*/
/*!
\fn QJsonObject &QJsonObject::operator =(QJsonObject &&other)
@@ -198,7 +160,7 @@ QJsonObject &QJsonObject::operator =(const QJsonObject &other)
Swaps the object \a other with this. This operation is very fast and never fails.
*/
-
+#ifndef QT_NO_VARIANT
/*!
Converts the variant map \a map to a QJsonObject.
@@ -261,18 +223,19 @@ QVariantHash QJsonObject::toVariantHash() const
{
return QCborMap::fromJsonObject(*this).toVariantHash();
}
+#endif // !QT_NO_VARIANT
/*!
Returns a list of all keys in this object.
- The list is sorted lexographically.
+ The list is sorted alphabetically.
*/
QStringList QJsonObject::keys() const
{
QStringList keys;
if (o) {
- keys.reserve(o->elements.length() / 2);
- for (qsizetype i = 0, end = o->elements.length(); i < end; i += 2)
+ keys.reserve(o->elements.size() / 2);
+ for (qsizetype i = 0, end = o->elements.size(); i < end; i += 2)
keys.append(o->stringAt(i));
}
return keys;
@@ -283,7 +246,7 @@ QStringList QJsonObject::keys() const
*/
qsizetype QJsonObject::size() const
{
- return o ? o->elements.length() / 2 : 0;
+ return o ? o->elements.size() / 2 : 0;
}
/*!
@@ -306,14 +269,13 @@ static qsizetype indexOf(const QExplicitlySharedDataPointer<QCborContainerPrivat
const auto it = std::lower_bound(
begin, end, key,
[&](const QJsonPrivate::ConstKeyIterator::value_type &e, const String &key) {
- return o->stringCompareElement(e.key(), key) < 0;
+ return o->stringCompareElement(e.key(), key, QtCbor::Comparison::ForOrdering) < 0;
});
*keyExists = (it != end) && o->stringEqualsElement((*it).key(), key);
- return (it - begin) * 2;
+ return it.it - begin.it;
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a QJsonValue representing the value for the key \a key.
@@ -325,7 +287,6 @@ QJsonValue QJsonObject::value(const QString &key) const
{
return value(QStringView(key));
}
-#endif
/*!
\overload
@@ -340,7 +301,7 @@ QJsonValue QJsonObject::value(QStringView key) const
\overload
\since 5.7
*/
-QJsonValue QJsonObject::value(QLatin1String key) const
+QJsonValue QJsonObject::value(QLatin1StringView key) const
{
return valueImpl(key);
}
@@ -361,7 +322,6 @@ QJsonValue QJsonObject::valueImpl(T key) const
return QJsonPrivate::Value::fromTrustedCbor(o->valueAt(i + 1));
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a QJsonValue representing the value for the key \a key.
@@ -375,7 +335,6 @@ QJsonValue QJsonObject::operator [](const QString &key) const
{
return (*this)[QStringView(key)];
}
-#endif
/*!
\fn QJsonValue QJsonObject::operator [](QStringView key) const
@@ -385,13 +344,12 @@ QJsonValue QJsonObject::operator [](const QString &key) const
*/
/*!
- \fn QJsonValue QJsonObject::operator [](QLatin1String key) const
+ \fn QJsonValue QJsonObject::operator [](QLatin1StringView key) const
\overload
\since 5.7
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a reference to the value for \a key. If there is no value with key
\a key in the object, one is created with a QJsonValue::Null value and then
@@ -409,7 +367,6 @@ QJsonValueRef QJsonObject::operator [](const QString &key)
{
return (*this)[QStringView(key)];
}
-#endif
/*!
\overload
@@ -424,7 +381,7 @@ QJsonValueRef QJsonObject::operator [](QStringView key)
\overload
\since 5.7
*/
-QJsonValueRef QJsonObject::operator [](QLatin1String key)
+QJsonValueRef QJsonObject::operator [](QLatin1StringView key)
{
return atImpl(key);
}
@@ -441,7 +398,7 @@ QJsonValueRef QJsonObject::atImpl(T key)
bool keyExists = false;
auto index = indexOf(o, key, &keyExists);
if (!keyExists) {
- detach(o->elements.length() / 2 + 1);
+ detach(o->elements.size() / 2 + 1);
o->insertAt(index, key);
o->insertAt(index + 1, QCborValue::fromJsonValue(QJsonValue()));
}
@@ -449,7 +406,6 @@ QJsonValueRef QJsonObject::atImpl(T key)
return QJsonValueRef(this, index / 2);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Inserts a new item with the key \a key and a value of \a value.
@@ -467,7 +423,6 @@ QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &
{
return insert(QStringView(key), value);
}
-#endif
/*!
\overload
@@ -482,7 +437,7 @@ QJsonObject::iterator QJsonObject::insert(QStringView key, const QJsonValue &val
\overload
\since 5.14
*/
-QJsonObject::iterator QJsonObject::insert(QLatin1String key, const QJsonValue &value)
+QJsonObject::iterator QJsonObject::insert(QLatin1StringView key, const QJsonValue &value)
{
return insertImpl(key, value);
}
@@ -509,7 +464,7 @@ template <typename T>
QJsonObject::iterator QJsonObject::insertAt(qsizetype pos, T key, const QJsonValue &value, bool keyExists)
{
if (o)
- detach(o->elements.length() / 2 + (keyExists ? 0 : 1));
+ detach(o->elements.size() / 2 + (keyExists ? 0 : 1));
else
o = new QCborContainerPrivate;
@@ -522,7 +477,6 @@ QJsonObject::iterator QJsonObject::insertAt(qsizetype pos, T key, const QJsonVal
return {this, pos / 2};
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Removes \a key from the object.
@@ -532,7 +486,6 @@ void QJsonObject::remove(const QString &key)
{
remove(QStringView(key));
}
-#endif
/*!
\overload
@@ -547,7 +500,7 @@ void QJsonObject::remove(QStringView key)
\overload
\since 5.14
*/
-void QJsonObject::remove(QLatin1String key)
+void QJsonObject::remove(QLatin1StringView key)
{
removeImpl(key);
}
@@ -566,10 +519,9 @@ void QJsonObject::removeImpl(T key)
if (!keyExists)
return;
- removeAt(index / 2);
+ removeAt(index);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Removes \a key from the object.
@@ -583,7 +535,6 @@ QJsonValue QJsonObject::take(const QString &key)
{
return take(QStringView(key));
}
-#endif
/*!
\overload
@@ -598,7 +549,7 @@ QJsonValue QJsonObject::take(QStringView key)
\overload
\since 5.14
*/
-QJsonValue QJsonObject::take(QLatin1String key)
+QJsonValue QJsonObject::take(QLatin1StringView key)
{
return takeImpl(key);
}
@@ -619,11 +570,10 @@ QJsonValue QJsonObject::takeImpl(T key)
detach();
const QJsonValue v = QJsonPrivate::Value::fromTrustedCbor(o->extractAt(index + 1));
- removeAt(index / 2);
+ removeAt(index);
return v;
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns \c true if the object contains key \a key.
@@ -633,7 +583,6 @@ bool QJsonObject::contains(const QString &key) const
{
return contains(QStringView(key));
}
-#endif
/*!
\overload
@@ -648,7 +597,7 @@ bool QJsonObject::contains(QStringView key) const
\overload
\since 5.7
*/
-bool QJsonObject::contains(QLatin1String key) const
+bool QJsonObject::contains(QLatin1StringView key) const
{
return containsImpl(key);
}
@@ -668,22 +617,24 @@ bool QJsonObject::containsImpl(T key) const
}
/*!
- Returns \c true if \a other is equal to this object.
- */
-bool QJsonObject::operator==(const QJsonObject &other) const
+ \fn bool QJsonObject::operator==(const QJsonObject &lhs, const QJsonObject &rhs)
+
+ Returns \c true if \a lhs object is equal to \a rhs, \c false otherwise.
+*/
+bool comparesEqual(const QJsonObject &lhs, const QJsonObject &rhs) noexcept
{
- if (o == other.o)
+ if (lhs.o == rhs.o)
return true;
- if (!o)
- return !other.o->elements.length();
- if (!other.o)
- return !o->elements.length();
- if (o->elements.length() != other.o->elements.length())
+ if (!lhs.o)
+ return !rhs.o->elements.size();
+ if (!rhs.o)
+ return !lhs.o->elements.size();
+ if (lhs.o->elements.size() != rhs.o->elements.size())
return false;
- for (qsizetype i = 0, end = o->elements.length(); i < end; ++i) {
- if (o->valueAt(i) != other.o->valueAt(i))
+ for (qsizetype i = 0, end = lhs.o->elements.size(); i < end; ++i) {
+ if (lhs.o->valueAt(i) != rhs.o->valueAt(i))
return false;
}
@@ -691,12 +642,10 @@ bool QJsonObject::operator==(const QJsonObject &other) const
}
/*!
- Returns \c true if \a other is not equal to this object.
- */
-bool QJsonObject::operator!=(const QJsonObject &other) const
-{
- return !(*this == other);
-}
+ \fn bool QJsonObject::operator!=(const QJsonObject &lhs, const QJsonObject &rhs)
+
+ Returns \c true if \a lhs object is not equal to \a rhs, \c false otherwise.
+*/
/*!
Removes the (key, value) pair pointed to by the iterator \a it
@@ -707,16 +656,14 @@ bool QJsonObject::operator!=(const QJsonObject &other) const
*/
QJsonObject::iterator QJsonObject::erase(QJsonObject::iterator it)
{
- if (it.item.o != this || qsizetype(it.item.index) >= o->elements.length())
- return {this, o->elements.length()};
-
- removeAt(it.item.index);
+ removeAt(it.item.index * 2);
- // iterator hasn't changed
- return it;
+ // index hasn't changed; the container pointer shouldn't have changed
+ // because we shouldn't have detached (detaching happens on obtaining a
+ // non-const iterator). But just in case we did, reload the pointer.
+ return { this, qsizetype(it.item.index) };
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns an iterator pointing to the item with key \a key in the
map.
@@ -728,7 +675,6 @@ QJsonObject::iterator QJsonObject::find(const QString &key)
{
return find(QStringView(key));
}
-#endif
/*!
\overload
@@ -743,7 +689,7 @@ QJsonObject::iterator QJsonObject::find(QStringView key)
\overload
\since 5.7
*/
-QJsonObject::iterator QJsonObject::find(QLatin1String key)
+QJsonObject::iterator QJsonObject::find(QLatin1StringView key)
{
return findImpl(key);
}
@@ -762,12 +708,10 @@ QJsonObject::iterator QJsonObject::findImpl(T key)
return {this, index / 2};
}
-#if QT_STRINGVIEW_LEVEL < 2
/*! \fn QJsonObject::const_iterator QJsonObject::find(const QString &key) const
\overload
*/
-#endif
/*! \fn QJsonObject::const_iterator QJsonObject::find(QStringView key) const
@@ -775,13 +719,12 @@ QJsonObject::iterator QJsonObject::findImpl(T key)
\since 5.14
*/
-/*! \fn QJsonObject::const_iterator QJsonObject::find(QLatin1String key) const
+/*! \fn QJsonObject::const_iterator QJsonObject::find(QLatin1StringView key) const
\overload
\since 5.7
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a const iterator pointing to the item with key \a key in the
map.
@@ -793,7 +736,6 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
{
return constFind(QStringView(key));
}
-#endif
/*!
\overload
@@ -808,7 +750,7 @@ QJsonObject::const_iterator QJsonObject::constFind(QStringView key) const
\overload
\since 5.7
*/
-QJsonObject::const_iterator QJsonObject::constFind(QLatin1String key) const
+QJsonObject::const_iterator QJsonObject::constFind(QLatin1StringView key) const
{
return constFindImpl(key);
}
@@ -898,6 +840,10 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\brief The QJsonObject::iterator class provides an STL-style non-const iterator for QJsonObject.
+ \compares strong
+ \compareswith strong QJsonObject::const_iterator
+ \endcompareswith
+
QJsonObject::iterator allows you to iterate over a QJsonObject
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QJsonObject, you
@@ -914,7 +860,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
Multiple iterators can be used on the same object. Existing iterators will however
become dangling once the object gets modified.
- \sa QJsonObject::const_iterator, {JSON Support in Qt}, {JSON Save Game Example}
+ \sa QJsonObject::const_iterator, {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*! \typedef QJsonObject::iterator::difference_type
@@ -1003,12 +949,17 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\sa key()
*/
-/*! \fn QJsonValueRef *QJsonObject::iterator::operator->() const
+/*! \fn QJsonValueRef *QJsonObject::iterator::operator->()
Returns a pointer to a modifiable reference to the current item.
*/
-/*! \fn const QJsonValueRef QJsonObject::iterator::operator[](qsizetype j)
+/*! \fn const QJsonValueConstRef *QJsonObject::iterator::operator->() const
+
+ Returns a pointer to a constant reference to the current item.
+*/
+
+/*! \fn const QJsonValueRef QJsonObject::iterator::operator[](qsizetype j) const
Returns a modifiable reference to the item at offset \a j from the
item pointed to by this iterator (the item at position \c{*this + j}).
@@ -1026,60 +977,60 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
*/
/*!
- \fn bool QJsonObject::iterator::operator==(const iterator &other) const
- \fn bool QJsonObject::iterator::operator==(const const_iterator &other) const
+ \fn bool QJsonObject::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator==(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QJsonObject::iterator::operator!=(const iterator &other) const
- \fn bool QJsonObject::iterator::operator!=(const const_iterator &other) const
+ \fn bool QJsonObject::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator!=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonObject::iterator::operator<(const iterator& other) const
- \fn bool QJsonObject::iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator<(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator<(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator<=(const iterator& other) const
- \fn bool QJsonObject::iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator<=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator<=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator>(const iterator& other) const
- \fn bool QJsonObject::iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator>(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator>(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator>=(const iterator& other) const
- \fn bool QJsonObject::iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator>=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator>=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++()
- The prefix ++ operator, \c{++i}, advances the iterator to the
+ The prefix \c{++} operator, \c{++i}, advances the iterator to the
next item in the object and returns an iterator to the new current
item.
@@ -1092,14 +1043,14 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\overload
- The postfix ++ operator, \c{i++}, advances the iterator to the
+ The postfix \c{++} operator, \c{i++}, advances the iterator to the
next item in the object and returns an iterator to the previously
current item.
*/
/*! \fn QJsonObject::iterator QJsonObject::iterator::operator--()
- The prefix -- operator, \c{--i}, makes the preceding item
+ The prefix \c{--} operator, \c{--i}, makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QJsonObject::begin() leads to undefined
@@ -1112,7 +1063,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\overload
- The postfix -- operator, \c{i--}, makes the preceding item
+ The postfix \c{--} operator, \c{i--}, makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1163,6 +1114,10 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\since 5.0
\brief The QJsonObject::const_iterator class provides an STL-style const iterator for QJsonObject.
+ \compares strong
+ \compareswith strong QJsonObject::iterator
+ \endcompareswith
+
QJsonObject::const_iterator allows you to iterate over a QJsonObject.
If you want to modify the QJsonObject as you iterate
over it, you must use QJsonObject::iterator instead. It is generally
@@ -1179,7 +1134,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
Multiple iterators can be used on the same object. Existing iterators
will however become dangling if the object gets modified.
- \sa QJsonObject::iterator, {JSON Support in Qt}, {JSON Save Game Example}
+ \sa QJsonObject::iterator, {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*! \typedef QJsonObject::const_iterator::difference_type
@@ -1238,14 +1193,14 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\sa value()
*/
-/*! \fn QJsonValueRef QJsonObject::const_iterator::value() const
+/*! \fn QJsonValueConstRef QJsonObject::const_iterator::value() const
Returns the current item's value.
\sa key(), operator*()
*/
-/*! \fn const QJsonValueRef QJsonObject::const_iterator::operator*() const
+/*! \fn const QJsonValueConstRef QJsonObject::const_iterator::operator*() const
Returns the current item's value.
@@ -1254,12 +1209,12 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\sa key()
*/
-/*! \fn const QJsonValueRef *QJsonObject::const_iterator::operator->() const
+/*! \fn const QJsonValueConstRef *QJsonObject::const_iterator::operator->() const
Returns a pointer to the current item.
*/
-/*! \fn const QJsonValue QJsonObject::const_iterator::operator[](qsizetype j)
+/*! \fn const QJsonValueConstRef QJsonObject::const_iterator::operator[](qsizetype j) const
Returns the item at offset \a j from the item pointed to by this iterator (the item at
position \c{*this + j}).
@@ -1271,55 +1226,53 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
*/
-/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
- \fn bool QJsonObject::const_iterator::operator==(const iterator &other) const
+/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
-/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &other) const
- \fn bool QJsonObject::const_iterator::operator!=(const iterator &other) const
+/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonObject::const_iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator<(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator<=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator>(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator>=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++()
- The prefix ++ operator, \c{++i}, advances the iterator to the
+ The prefix \c{++} operator, \c{++i}, advances the iterator to the
next item in the object and returns an iterator to the new current
item.
@@ -1332,14 +1285,14 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\overload
- The postfix ++ operator, \c{i++}, advances the iterator to the
+ The postfix \c{++} operator, \c{i++}, advances the iterator to the
next item in the object and returns an iterator to the previously
current item.
*/
/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator--()
- The prefix -- operator, \c{--i}, makes the preceding item
+ The prefix \c{--} operator, \c{--i}, makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QJsonObject::begin() leads to undefined
@@ -1352,7 +1305,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\overload
- The postfix -- operator, \c{i--}, makes the preceding item
+ The postfix \c{--} operator, \c{i--}, makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1411,16 +1364,17 @@ bool QJsonObject::detach(qsizetype reserve)
{
if (!o)
return true;
- o = QCborContainerPrivate::detach(o.data(), reserve ? reserve * 2 : o->elements.length());
+ o = QCborContainerPrivate::detach(o.data(), reserve ? reserve * 2 : o->elements.size());
return o;
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
/*!
\internal
*/
QString QJsonObject::keyAt(qsizetype i) const
{
- Q_ASSERT(o && i >= 0 && i * 2 < o->elements.length());
+ Q_ASSERT(o && i >= 0 && i * 2 < o->elements.size());
return o->stringAt(i * 2);
}
@@ -1429,7 +1383,7 @@ QString QJsonObject::keyAt(qsizetype i) const
*/
QJsonValue QJsonObject::valueAt(qsizetype i) const
{
- if (!o || i < 0 || 2 * i + 1 >= o->elements.length())
+ if (!o || i < 0 || 2 * i + 1 >= o->elements.size())
return QJsonValue(QJsonValue::Undefined);
return QJsonPrivate::Value::fromTrustedCbor(o->valueAt(2 * i + 1));
}
@@ -1439,7 +1393,7 @@ QJsonValue QJsonObject::valueAt(qsizetype i) const
*/
void QJsonObject::setValueAt(qsizetype i, const QJsonValue &val)
{
- Q_ASSERT(o && i >= 0 && 2 * i + 1 < o->elements.length());
+ Q_ASSERT(o && i >= 0 && 2 * i + 1 < o->elements.size());
detach();
if (val.isUndefined()) {
o->removeAt(2 * i + 1);
@@ -1448,6 +1402,7 @@ void QJsonObject::setValueAt(qsizetype i, const QJsonValue &val)
o->replaceAt(2 * i + 1, QCborValue::fromJsonValue(val));
}
}
+#endif // Qt 7
/*!
\internal
@@ -1455,8 +1410,8 @@ void QJsonObject::setValueAt(qsizetype i, const QJsonValue &val)
void QJsonObject::removeAt(qsizetype index)
{
detach();
- o->removeAt(2 * index + 1);
- o->removeAt(2 * index);
+ o->removeAt(index + 1);
+ o->removeAt(index);
}
size_t qHash(const QJsonObject &object, size_t seed)
diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h
index e477345643..4cdbf4511d 100644
--- a/src/corelib/serialization/qjsonobject.h
+++ b/src/corelib/serialization/qjsonobject.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONOBJECT_H
#define QJSONOBJECT_H
@@ -57,12 +21,12 @@ class Q_CORE_EXPORT QJsonObject
public:
QJsonObject();
- QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args);
+ QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args);
~QJsonObject();
- QJsonObject(const QJsonObject &other);
- QJsonObject &operator =(const QJsonObject &other);
+ QJsonObject(const QJsonObject &other) noexcept;
+ QJsonObject &operator =(const QJsonObject &other) noexcept;
QJsonObject(QJsonObject &&other) noexcept;
@@ -74,7 +38,7 @@ public:
void swap(QJsonObject &other) noexcept
{
- qSwap(o, other.o);
+ o.swap(other.o);
}
static QJsonObject fromVariantMap(const QVariantMap &map);
@@ -88,40 +52,37 @@ public:
inline qsizetype length() const { return size(); }
bool isEmpty() const;
-#if QT_STRINGVIEW_LEVEL < 2
QJsonValue value(const QString &key) const;
QJsonValue operator[] (const QString &key) const;
QJsonValueRef operator[] (const QString &key);
-#endif
QJsonValue value(QStringView key) const;
- QJsonValue value(QLatin1String key) const;
+ QJsonValue value(QLatin1StringView key) const;
QJsonValue operator[] (QStringView key) const { return value(key); }
- QJsonValue operator[] (QLatin1String key) const { return value(key); }
+ QJsonValue operator[] (QLatin1StringView key) const { return value(key); }
QJsonValueRef operator[] (QStringView key);
- QJsonValueRef operator[] (QLatin1String key);
+ QJsonValueRef operator[] (QLatin1StringView key);
-#if QT_STRINGVIEW_LEVEL < 2
void remove(const QString &key);
QJsonValue take(const QString &key);
bool contains(const QString &key) const;
-#endif
void remove(QStringView key);
- void remove(QLatin1String key);
+ void remove(QLatin1StringView key);
QJsonValue take(QStringView key);
- QJsonValue take(QLatin1String key);
+ QJsonValue take(QLatin1StringView key);
bool contains(QStringView key) const;
- bool contains(QLatin1String key) const;
+ bool contains(QLatin1StringView key) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonObject &other) const;
bool operator!=(const QJsonObject &other) const;
-
+#endif
class const_iterator;
class iterator
{
friend class const_iterator;
friend class QJsonObject;
- mutable QJsonValueRef item;
+ QJsonValueRef item;
public:
typedef std::random_access_iterator_tag iterator_category;
@@ -136,62 +97,109 @@ public:
constexpr iterator(const iterator &other) = default;
iterator &operator=(const iterator &other)
{
- item.o = other.item.o;
- item.index = other.item.index;
+ item.rebind(other.item);
return *this;
}
- inline QString key() const { return item.o->keyAt(item.index); }
+ inline QString key() const { return item.objectKey(); }
inline QJsonValueRef value() const { return item; }
inline QJsonValueRef operator*() const { return item; }
- inline QJsonValueRef *operator->() const { return &item; }
- const QJsonValueRef operator[](qsizetype j) { return { item.o, qsizetype(item.index) + j }; }
-
+ inline const QJsonValueConstRef *operator->() const { return &item; }
+ inline QJsonValueRef *operator->() { return &item; }
+ inline QJsonValueRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &other) const
- { return item.o == other.item.o && item.index == other.item.index; }
- inline bool operator!=(const iterator &other) const { return !(*this == other); }
+ { return item.d == other.item.d && item.index == other.item.index; }
+ inline bool operator!=(const iterator &other) const { return !operator==(other); }
bool operator<(const iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index <= other.item.index; }
- bool operator>(const iterator& other) const { return !(*this <= other); }
- bool operator>=(const iterator& other) const { return !(*this < other); }
-
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ bool operator>(const iterator& other) const { return !operator<=(other); }
+ bool operator>=(const iterator& other) const { return !operator<(other); }
+#endif
inline iterator &operator++() { ++item.index; return *this; }
inline iterator operator++(int) { iterator r = *this; ++item.index; return r; }
inline iterator &operator--() { --item.index; return *this; }
inline iterator operator--(int) { iterator r = *this; --item.index; return r; }
- inline iterator operator+(qsizetype j) const
- { iterator r = *this; r.item.index += quint64(j); return r; }
+ inline iterator operator+(qsizetype j) const { iterator r = *this; return r += j; }
inline iterator operator-(qsizetype j) const { return operator+(-j); }
inline iterator &operator+=(qsizetype j) { item.index += quint64(j); return *this; }
inline iterator &operator-=(qsizetype j) { item.index -= quint64(j); return *this; }
qsizetype operator-(iterator j) const { return item.index - j.item.index; }
public:
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &other) const
- { return item.o == other.item.o && item.index == other.item.index; }
- inline bool operator!=(const const_iterator &other) const { return !(*this == other); }
+ { return item.d == other.item.d && item.index == other.item.index; }
+ inline bool operator!=(const const_iterator &other) const { return !operator==(other); }
bool operator<(const const_iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const const_iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index <= other.item.index; }
- bool operator>(const const_iterator& other) const { return !(*this <= other); }
- bool operator>=(const const_iterator& other) const { return !(*this < other); }
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ bool operator>(const const_iterator& other) const { return operator<=(other); }
+ bool operator>=(const const_iterator& other) const { return operator<(other); }
+#endif
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static bool comparesEqual_helper(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator)
+
+ friend bool comparesEqual(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator, const_iterator)
};
friend class iterator;
class const_iterator
{
friend class iterator;
- QJsonValueRef item;
+ QJsonValueConstRef item;
public:
typedef std::random_access_iterator_tag iterator_category;
typedef qsizetype difference_type;
typedef QJsonValue value_type;
- typedef const QJsonValueRef reference;
- typedef const QJsonValueRef *pointer;
+ typedef const QJsonValueConstRef reference;
+ typedef const QJsonValueConstRef *pointer;
inline const_iterator() : item(static_cast<QJsonObject*>(nullptr), 0) { }
inline const_iterator(const QJsonObject *obj, qsizetype index)
@@ -202,47 +210,72 @@ public:
constexpr const_iterator(const const_iterator &other) = default;
const_iterator &operator=(const const_iterator &other)
{
- item.o = other.item.o;
- item.index = other.item.index;
+ item.rebind(other.item);
return *this;
}
- inline QString key() const { return item.o->keyAt(item.index); }
- inline QJsonValueRef value() const { return item; }
- inline const QJsonValueRef operator*() const { return item; }
- inline const QJsonValueRef *operator->() const { return &item; }
- const QJsonValueRef operator[](qsizetype j) { return { item.o, qsizetype(item.index) + j }; }
-
+ inline QString key() const { return item.objectKey(); }
+ inline QJsonValueConstRef value() const { return item; }
+ inline const QJsonValueConstRef operator*() const { return item; }
+ inline const QJsonValueConstRef *operator->() const { return &item; }
+ inline QJsonValueConstRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &other) const
- { return item.o == other.item.o && item.index == other.item.index; }
- inline bool operator!=(const const_iterator &other) const { return !(*this == other); }
+ { return item.d == other.item.d && item.index == other.item.index; }
+ inline bool operator!=(const const_iterator &other) const { return !operator==(other); }
bool operator<(const const_iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const const_iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index <= other.item.index; }
- bool operator>(const const_iterator& other) const { return !(*this <= other); }
- bool operator>=(const const_iterator& other) const { return !(*this < other); }
-
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ bool operator>(const const_iterator& other) const { return !operator<=(other); }
+ bool operator>=(const const_iterator& other) const { return !operator<(other); }
+#endif
inline const_iterator &operator++() { ++item.index; return *this; }
inline const_iterator operator++(int) { const_iterator r = *this; ++item.index; return r; }
inline const_iterator &operator--() { --item.index; return *this; }
inline const_iterator operator--(int) { const_iterator r = *this; --item.index; return r; }
- inline const_iterator operator+(qsizetype j) const
- { const_iterator r = *this; r.item.index += quint64(j); return r; }
+ inline const_iterator operator+(qsizetype j) const { const_iterator r = *this; return r += j; }
inline const_iterator operator-(qsizetype j) const { return operator+(-j); }
inline const_iterator &operator+=(qsizetype j) { item.index += quint64(j); return *this; }
inline const_iterator &operator-=(qsizetype j) { item.index -= quint64(j); return *this; }
qsizetype operator-(const_iterator j) const { return item.index - j.item.index; }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &other) const
- { return item.o == other.item.o && item.index == other.item.index; }
- inline bool operator!=(const iterator &other) const { return !(*this == other); }
+ { return item.d == other.item.d && item.index == other.item.index; }
+ inline bool operator!=(const iterator &other) const { return !operator==(other); }
bool operator<(const iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
+ { Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const iterator& other) const
- { Q_ASSERT(item.o == other.item.o); return item.index <= other.item.index; }
- bool operator>(const iterator& other) const { return !(*this <= other); }
- bool operator>=(const iterator& other) const { return !(*this < other); }
+ { Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
+ bool operator>(const iterator& other) const { return !operator<=(other); }
+ bool operator>=(const iterator& other) const { return !operator<(other); }
+#endif
+
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const const_iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(const_iterator)
};
friend class const_iterator;
@@ -258,20 +291,18 @@ public:
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
-#if QT_STRINGVIEW_LEVEL < 2
iterator find(const QString &key);
const_iterator find(const QString &key) const { return constFind(key); }
const_iterator constFind(const QString &key) const;
iterator insert(const QString &key, const QJsonValue &value);
-#endif
iterator find(QStringView key);
- iterator find(QLatin1String key);
+ iterator find(QLatin1StringView key);
const_iterator find(QStringView key) const { return constFind(key); }
- const_iterator find(QLatin1String key) const { return constFind(key); }
+ const_iterator find(QLatin1StringView key) const { return constFind(key); }
const_iterator constFind(QStringView key) const;
- const_iterator constFind(QLatin1String key) const;
+ const_iterator constFind(QLatin1StringView key) const;
iterator insert(QStringView key, const QJsonValue &value);
- iterator insert(QLatin1String key, const QJsonValue &value);
+ iterator insert(QLatin1StringView key, const QJsonValue &value);
// STL compatibility
typedef QJsonValue mapped_type;
@@ -281,8 +312,25 @@ public:
inline bool empty() const { return isEmpty(); }
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonObject &lhs,
+ const QJsonObject &rhs) noexcept;
+ friend bool comparesEqual(const QJsonObject &lhs,
+ const QJsonValue &rhs) noexcept
+ {
+ return comparesEqual(lhs, rhs.toObject());
+ }
+ friend bool comparesEqual(const QJsonObject &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(lhs, rhs.toObject());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject, QJsonValue)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject, QJsonValueConstRef)
friend class QJsonValue;
friend class QJsonDocument;
+ friend class QJsonPrivate::Value;
+ friend class QJsonValueConstRef;
friend class QJsonValueRef;
friend class QCborMap;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
@@ -299,9 +347,11 @@ private:
template <typename T> const_iterator constFindImpl(T key) const;
template <typename T> iterator insertImpl(T key, const QJsonValue &value);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QString keyAt(qsizetype i) const;
QJsonValue valueAt(qsizetype i) const;
void setValueAt(qsizetype i, const QJsonValue &val);
+#endif
void removeAt(qsizetype i);
template <typename T> iterator insertAt(qsizetype i, T key, const QJsonValue &val, bool exists);
@@ -310,6 +360,12 @@ private:
Q_DECLARE_SHARED(QJsonObject)
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
+inline QJsonValueConstRef::QJsonValueConstRef(QJsonObject *o, qsizetype idx)
+ : d(o ? o->o.data() : nullptr), is_object(true), index(idx)
+{}
+#endif
+
Q_CORE_EXPORT size_t qHash(const QJsonObject &object, size_t seed = 0);
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
diff --git a/src/corelib/serialization/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp
index 2514319e0e..ba4887225d 100644
--- a/src/corelib/serialization/qjsonparser.cpp
+++ b/src/corelib/serialization/qjsonparser.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2021 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QT_BOOTSTRAPPED
#include <qcoreapplication.h>
@@ -47,23 +11,30 @@
#include "private/qstringconverter_p.h"
#include "private/qcborvalue_p.h"
#include "private/qnumeric_p.h"
+#include <private/qtools_p.h>
//#define PARSER_DEBUG
#ifdef PARSER_DEBUG
-static int indent = 0;
-#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current
-#define END --indent
-#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
+# error currently broken after `current` was moved to StashedContainer
+Q_CONSTINIT static int indent = 0;
+# define QT_PARSER_TRACING_BEGIN \
+ qDebug() << QByteArray(4 * indent++, ' ').constData() << "pos=" << current
+# define QT_PARSER_TRACING_END --indent
+# define QT_PARSER_TRACING_DEBUG qDebug() << QByteArray(4 * indent, ' ').constData()
#else
-#define BEGIN if (1) ; else qDebug()
-#define END do {} while (0)
-#define DEBUG if (1) ; else qDebug()
+# define QT_PARSER_TRACING_BEGIN QT_NO_QDEBUG_MACRO()
+# define QT_PARSER_TRACING_END \
+ do { \
+ } while (0)
+# define QT_PARSER_TRACING_DEBUG QT_NO_QDEBUG_MACRO()
#endif
static const int nestingLimit = 1024;
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
// error strings for the JSON parser
#define JSONERR_OK QT_TRANSLATE_NOOP("QJsonParseError", "no error occurred")
#define JSONERR_UNTERM_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "unterminated object")
@@ -86,12 +57,13 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonParseError class is used to report errors during JSON parsing.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -193,7 +165,7 @@ QString QJsonParseError::errorString() const
#ifndef QT_BOOTSTRAPPED
return QCoreApplication::translate("QJsonParseError", sz);
#else
- return QLatin1String(sz);
+ return QLatin1StringView(sz);
#endif
}
@@ -333,7 +305,7 @@ QCborValue Parser::parse(QJsonParseError *error)
QCborValue data;
- DEBUG << Qt::hex << (uint)token;
+ QT_PARSER_TRACING_DEBUG << Qt::hex << (uint)token;
if (token == BeginArray) {
container = new QCborContainerPrivate;
if (!parseArray())
@@ -357,7 +329,7 @@ QCborValue Parser::parse(QJsonParseError *error)
goto error;
}
- END;
+ QT_PARSER_TRACING_END;
{
if (error) {
error->offset = 0;
@@ -379,10 +351,42 @@ error:
return QCborValue();
}
+// We need to retain the _last_ value for any duplicate keys and we need to deref containers.
+// Therefore the manual implementation of std::unique().
+template<typename Iterator, typename Compare, typename Assign>
+static Iterator customAssigningUniqueLast(Iterator first, Iterator last,
+ Compare compare, Assign assign)
+{
+ first = std::adjacent_find(first, last, compare);
+ if (first == last)
+ return last;
+
+ // After adjacent_find, we know that *first and *(first+1) compare equal,
+ // and that first+1 != last.
+ Iterator result = first++;
+ Q_ASSERT(compare(*result, *first));
+ assign(*result, *first);
+ Q_ASSERT(first != last);
+
+ while (++first != last) {
+ if (!compare(*result, *first))
+ ++result;
+
+ // Due to adjacent_find above, we know that we've at least eliminated one element.
+ // Therefore we have to move each further element across the gap.
+ Q_ASSERT(result != first);
+
+ // We have to overwrite each element we want to eliminate, to deref() the container.
+ // Therefore we don't try to optimize the number of assignments here.
+ assign(*result, *first);
+ }
+
+ return ++result;
+}
+
static void sortContainer(QCborContainerPrivate *container)
{
using Forward = QJsonPrivate::KeyIterator;
- using Reverse = std::reverse_iterator<Forward>;
using Value = Forward::value_type;
auto compare = [container](const Value &a, const Value &b)
@@ -417,17 +421,31 @@ static void sortContainer(QCborContainerPrivate *container)
}
};
- std::sort(Forward(container->elements.begin()), Forward(container->elements.end()),
- [&compare](const Value &a, const Value &b) { return compare(a, b) < 0; });
+ // The elements' containers are owned by the outer container, not by the elements themselves.
+ auto move = [](Forward::reference target, Forward::reference source)
+ {
+ QtCbor::Element &targetValue = target.value();
+
+ // If the target has a container, deref it before overwriting, so that we don't leak.
+ if (targetValue.flags & QtCbor::Element::IsContainer)
+ targetValue.container->deref();
- // We need to retain the _last_ value for any duplicate keys. Therefore the reverse dance here.
- auto it = std::unique(Reverse(container->elements.end()), Reverse(container->elements.begin()),
- [&compare](const Value &a, const Value &b) {
- return compare(a, b) == 0;
- }).base().elementsIterator();
+ // Do not move, so that we can clear the value afterwards.
+ target = source;
- // The erase from beginning is expensive but hopefully rare.
- container->elements.erase(container->elements.begin(), it);
+ // Clear the source value, so that we don't store the same container twice.
+ source.value() = QtCbor::Element();
+ };
+
+ std::stable_sort(
+ Forward(container->elements.begin()), Forward(container->elements.end()),
+ [&compare](const Value &a, const Value &b) { return compare(a, b) < 0; });
+
+ Forward result = customAssigningUniqueLast(
+ Forward(container->elements.begin()), Forward(container->elements.end()),
+ [&compare](const Value &a, const Value &b) { return compare(a, b) == 0; }, move);
+
+ container->elements.erase(result.elementsIterator(), container->elements.end());
}
@@ -443,7 +461,7 @@ bool Parser::parseObject()
return false;
}
- BEGIN << "parseObject" << json;
+ QT_PARSER_TRACING_BEGIN << "parseObject" << json;
char token = nextToken();
while (token == Quote) {
@@ -461,13 +479,13 @@ bool Parser::parseObject()
}
}
- DEBUG << "end token=" << token;
+ QT_PARSER_TRACING_DEBUG << "end token=" << token;
if (token != EndObject) {
lastError = QJsonParseError::UnterminatedObject;
return false;
}
- END;
+ QT_PARSER_TRACING_END;
--nestingLevel;
@@ -481,7 +499,7 @@ bool Parser::parseObject()
*/
bool Parser::parseMember()
{
- BEGIN << "parseMember";
+ QT_PARSER_TRACING_BEGIN << "parseMember";
if (!parseString())
return false;
@@ -497,7 +515,7 @@ bool Parser::parseMember()
if (!parseValue())
return false;
- END;
+ QT_PARSER_TRACING_END;
return true;
}
@@ -506,7 +524,7 @@ bool Parser::parseMember()
*/
bool Parser::parseArray()
{
- BEGIN << "parseArray";
+ QT_PARSER_TRACING_BEGIN << "parseArray";
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
@@ -542,8 +560,8 @@ bool Parser::parseArray()
}
}
- DEBUG << "size =" << (container ? container->elements.length() : 0);
- END;
+ QT_PARSER_TRACING_DEBUG << "size =" << (container ? container->elements.size() : 0);
+ QT_PARSER_TRACING_END;
--nestingLevel;
@@ -557,7 +575,7 @@ value = false / null / true / object / array / number / string
bool Parser::parseValue()
{
- BEGIN << "parse Value" << json;
+ QT_PARSER_TRACING_BEGIN << "parse Value" << json;
switch (*json++) {
case 'n':
@@ -569,8 +587,8 @@ bool Parser::parseValue()
*json++ == 'l' &&
*json++ == 'l') {
container->append(QCborValue(QCborValue::Null));
- DEBUG << "value: null";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: null";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -584,8 +602,8 @@ bool Parser::parseValue()
*json++ == 'u' &&
*json++ == 'e') {
container->append(QCborValue(true));
- DEBUG << "value: true";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: true";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -600,8 +618,8 @@ bool Parser::parseValue()
*json++ == 's' &&
*json++ == 'e') {
container->append(QCborValue(false));
- DEBUG << "value: false";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: false";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -609,24 +627,24 @@ bool Parser::parseValue()
case Quote: {
if (!parseString())
return false;
- DEBUG << "value: string";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: string";
+ QT_PARSER_TRACING_END;
return true;
}
case BeginArray: {
StashedContainer stashedContainer(&container, QCborValue::Array);
if (!parseArray())
return false;
- DEBUG << "value: array";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: array";
+ QT_PARSER_TRACING_END;
return true;
}
case BeginObject: {
StashedContainer stashedContainer(&container, QCborValue::Map);
if (!parseObject())
return false;
- DEBUG << "value: object";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: object";
+ QT_PARSER_TRACING_END;
return true;
}
case ValueSeparator:
@@ -642,8 +660,8 @@ bool Parser::parseValue()
--json;
if (!parseNumber())
return false;
- DEBUG << "value: number";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: number";
+ QT_PARSER_TRACING_END;
}
return true;
@@ -669,7 +687,7 @@ bool Parser::parseValue()
bool Parser::parseNumber()
{
- BEGIN << "parseNumber" << json;
+ QT_PARSER_TRACING_BEGIN << "parseNumber" << json;
const char *start = json;
bool isInt = true;
@@ -682,14 +700,14 @@ bool Parser::parseNumber()
if (json < end && *json == '0') {
++json;
} else {
- while (json < end && *json >= '0' && *json <= '9')
+ while (json < end && isAsciiDigit(*json))
++json;
}
// frac = decimal-point 1*DIGIT
if (json < end && *json == '.') {
++json;
- while (json < end && *json >= '0' && *json <= '9') {
+ while (json < end && isAsciiDigit(*json)) {
isInt = isInt && *json == '0';
++json;
}
@@ -701,7 +719,7 @@ bool Parser::parseNumber()
++json;
if (json < end && (*json == '-' || *json == '+'))
++json;
- while (json < end && *json >= '0' && *json <= '9')
+ while (json < end && isAsciiDigit(*json))
++json;
}
@@ -711,14 +729,14 @@ bool Parser::parseNumber()
}
const QByteArray number = QByteArray::fromRawData(start, json - start);
- DEBUG << "numberstring" << number;
+ QT_PARSER_TRACING_DEBUG << "numberstring" << number;
if (isInt) {
bool ok;
qlonglong n = number.toLongLong(&ok);
if (ok) {
container->append(QCborValue(n));
- END;
+ QT_PARSER_TRACING_END;
return true;
}
}
@@ -737,7 +755,7 @@ bool Parser::parseNumber()
else
container->append(QCborValue(d));
- END;
+ QT_PARSER_TRACING_END;
return true;
}
@@ -766,15 +784,13 @@ bool Parser::parseNumber()
static inline bool addHexDigit(char digit, char32_t *result)
{
*result <<= 4;
- if (digit >= '0' && digit <= '9')
- *result |= (digit - '0');
- else if (digit >= 'a' && digit <= 'f')
- *result |= (digit - 'a') + 10;
- else if (digit >= 'A' && digit <= 'F')
- *result |= (digit - 'A') + 10;
- else
- return false;
- return true;
+ const int h = fromHex(digit);
+ if (h != -1) {
+ *result |= h;
+ return true;
+ }
+
+ return false;
}
static inline bool scanEscapeSequence(const char *&json, const char *end, char32_t *ch)
@@ -783,7 +799,7 @@ static inline bool scanEscapeSequence(const char *&json, const char *end, char32
if (json >= end)
return false;
- DEBUG << "scan escape" << (char)*json;
+ QT_PARSER_TRACING_DEBUG << "scan escape" << (char)*json;
uchar escaped = *json++;
switch (escaped) {
case '"':
@@ -827,7 +843,7 @@ static inline bool scanUtf8Char(const char *&json, const char *end, char32_t *re
const auto *usrc = reinterpret_cast<const uchar *>(json);
const auto *uend = reinterpret_cast<const uchar *>(end);
const uchar b = *usrc++;
- int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, usrc, uend);
+ qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, usrc, uend);
if (res < 0)
return false;
@@ -841,7 +857,7 @@ bool Parser::parseString()
// try to parse a utf-8 string without escape sequences, and note whether it's 7bit ASCII.
- BEGIN << "parse string" << json;
+ QT_PARSER_TRACING_BEGIN << "parse string" << json;
bool isUtf8 = true;
bool isAscii = true;
while (json < end) {
@@ -862,10 +878,10 @@ bool Parser::parseString()
}
if (ch > 0x7f)
isAscii = false;
- DEBUG << " " << ch << char(ch);
+ QT_PARSER_TRACING_DEBUG << " " << ch << char(ch);
}
++json;
- DEBUG << "end of string";
+ QT_PARSER_TRACING_DEBUG << "end of string";
if (json >= end) {
lastError = QJsonParseError::UnterminatedString;
return false;
@@ -877,11 +893,11 @@ bool Parser::parseString()
container->appendAsciiString(start, json - start - 1);
else
container->appendUtf8String(start, json - start - 1);
- END;
+ QT_PARSER_TRACING_END;
return true;
}
- DEBUG << "has escape sequences";
+ QT_PARSER_TRACING_DEBUG << "has escape sequences";
json = start;
@@ -910,10 +926,14 @@ bool Parser::parseString()
return false;
}
- container->appendByteData(reinterpret_cast<const char *>(ucs4.utf16()), ucs4.size() * 2,
+ container->appendByteData(reinterpret_cast<const char *>(ucs4.constData()), ucs4.size() * 2,
QCborValue::String, QtCbor::Element::StringIsUtf16);
- END;
+ QT_PARSER_TRACING_END;
return true;
}
QT_END_NAMESPACE
+
+#undef QT_PARSER_TRACING_BEGIN
+#undef QT_PARSER_TRACING_END
+#undef QT_PARSER_TRACING_DEBUG
diff --git a/src/corelib/serialization/qjsonparser_p.h b/src/corelib/serialization/qjsonparser_p.h
index 14d9705447..47830a108e 100644
--- a/src/corelib/serialization/qjsonparser_p.h
+++ b/src/corelib/serialization/qjsonparser_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONPARSER_P_H
#define QJSONPARSER_P_H
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index 933a8e1552..6c2656d89f 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qjsonobject.h>
#include <qjsonvalue.h>
@@ -45,6 +10,8 @@
#include <quuid.h>
#include <qvariant.h>
#include <qstringlist.h>
+#include <qmap.h>
+#include <qhash.h>
#include <qdebug.h>
#include "qdatastream.h"
@@ -58,16 +25,44 @@
QT_BEGIN_NAMESPACE
+static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept
+{
+ switch (type) {
+ case QCborValue::Null:
+ return QJsonValue::Null;
+ case QCborValue::True:
+ case QCborValue::False:
+ return QJsonValue::Bool;
+ case QCborValue::Double:
+ case QCborValue::Integer:
+ return QJsonValue::Double;
+ case QCborValue::String:
+ return QJsonValue::String;
+ case QCborValue::Array:
+ return QJsonValue::Array;
+ case QCborValue::Map:
+ return QJsonValue::Object;
+ case QCborValue::Undefined:
+ default:
+ return QJsonValue::Undefined;
+ }
+}
+
/*!
\class QJsonValue
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonValue class encapsulates a value in JSON.
+ \compares equality
+ \compareswith equality QJsonValueConstRef QJsonValueRef
+ \endcompareswith
+
A value in JSON can be one of 6 basic types:
JSON is a format to store structured data. It has 6 basic data types:
@@ -105,7 +100,7 @@ QT_BEGIN_NAMESPACE
\li \l {QJsonObject}::operator[](const QString & key) const
\endlist
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -207,9 +202,9 @@ QJsonValue::QJsonValue(const QString &s)
*/
/*!
- Creates a value of type String, with value \a s.
+ Creates a value of type String, with the Latin-1 string viewed by \a s.
*/
-QJsonValue::QJsonValue(QLatin1String s)
+QJsonValue::QJsonValue(QLatin1StringView s)
: value(s)
{
}
@@ -257,15 +252,12 @@ QJsonValue::~QJsonValue() = default;
/*!
Creates a copy of \a other.
*/
-QJsonValue::QJsonValue(const QJsonValue &other)
- : value(other.value)
-{
-}
+QJsonValue::QJsonValue(const QJsonValue &other) noexcept = default;
/*!
Assigns the value stored in \a other to this object.
*/
-QJsonValue &QJsonValue::operator =(const QJsonValue &other)
+QJsonValue &QJsonValue::operator =(const QJsonValue &other) noexcept
{
QJsonValue copy(other);
swap(copy);
@@ -357,6 +349,7 @@ void QJsonValue::swap(QJsonValue &other) noexcept
error cases as e.g. accessing a non existing key in a QJsonObject.
*/
+#ifndef QT_NO_VARIANT
/*!
Converts \a variant to a QJsonValue and returns it.
@@ -599,6 +592,7 @@ QVariant QJsonValue::toVariant() const
error condition, when trying to read an out of bounds value
in an array or a non existent key in an object.
*/
+#endif // !QT_NO_VARIANT
/*!
Returns the type of the value.
@@ -607,25 +601,7 @@ QVariant QJsonValue::toVariant() const
*/
QJsonValue::Type QJsonValue::type() const
{
- switch (value.type()) {
- case QCborValue::Null:
- return QJsonValue::Null;
- case QCborValue::True:
- case QCborValue::False:
- return QJsonValue::Bool;
- case QCborValue::Double:
- case QCborValue::Integer:
- return QJsonValue::Double;
- case QCborValue::String:
- return QJsonValue::String;
- case QCborValue::Array:
- return QJsonValue::Array;
- case QCborValue::Map:
- return QJsonValue::Object;
- case QCborValue::Undefined:
- default:
- return QJsonValue::Undefined;
- }
+ return convertFromCborType(value.type());
}
/*!
@@ -736,11 +712,14 @@ QString QJsonValue::toString() const
*/
QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const
{
- const auto dd = QJsonPrivate::Value::container(value);
- const auto n = QJsonPrivate::Value::valueHelper(value);
- if (value.type() != QCborValue::Array || n >= 0 || !dd)
+ if (!isArray())
return defaultValue;
-
+ QCborContainerPrivate *dd = nullptr;
+ const auto n = QJsonPrivate::Value::valueHelper(value);
+ const auto container = QJsonPrivate::Value::container(value);
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
return QJsonArray(dd);
}
@@ -763,11 +742,14 @@ QJsonArray QJsonValue::toArray() const
*/
QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const
{
- const auto dd = QJsonPrivate::Value::container(value);
- const auto n = QJsonPrivate::Value::valueHelper(value);
- if (value.type() != QCborValue::Map || n >= 0 || !dd)
+ if (!isObject())
return defaultValue;
-
+ QCborContainerPrivate *dd = nullptr;
+ const auto container = QJsonPrivate::Value::container(value);
+ const auto n = QJsonPrivate::Value::valueHelper(value);
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
return QJsonObject(dd);
}
@@ -783,7 +765,6 @@ QJsonObject QJsonValue::toObject() const
return toObject(QJsonObject());
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a QJsonValue representing the value for the key \a key.
@@ -800,7 +781,6 @@ const QJsonValue QJsonValue::operator[](const QString &key) const
{
return (*this)[QStringView(key)];
}
-#endif
/*!
\overload
@@ -818,7 +798,7 @@ const QJsonValue QJsonValue::operator[](QStringView key) const
\overload
\since 5.10
*/
-const QJsonValue QJsonValue::operator[](QLatin1String key) const
+const QJsonValue QJsonValue::operator[](QLatin1StringView key) const
{
if (!isObject())
return QJsonValue(QJsonValue::Undefined);
@@ -847,35 +827,37 @@ const QJsonValue QJsonValue::operator[](qsizetype i) const
}
/*!
- Returns \c true if the value is equal to \a other.
- */
-bool QJsonValue::operator==(const QJsonValue &other) const
+ \fn bool QJsonValue::operator==(const QJsonValue &lhs, const QJsonValue &rhs)
+
+ Returns \c true if the \a lhs value is equal to \a rhs value, \c false otherwise.
+*/
+bool comparesEqual(const QJsonValue &lhs, const QJsonValue &rhs) noexcept
{
- if (value.type() != other.value.type()) {
- if (isDouble() && other.isDouble()) {
+ if (lhs.value.type() != rhs.value.type()) {
+ if (lhs.isDouble() && rhs.isDouble()) {
// One value Cbor integer, one Cbor double, should interact as doubles.
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
}
return false;
}
- switch (value.type()) {
+ switch (lhs.value.type()) {
case QCborValue::Undefined:
case QCborValue::Null:
case QCborValue::True:
case QCborValue::False:
break;
case QCborValue::Double:
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
case QCborValue::Integer:
- return QJsonPrivate::Value::valueHelper(value)
- == QJsonPrivate::Value::valueHelper(other.value);
+ return QJsonPrivate::Value::valueHelper(lhs.value)
+ == QJsonPrivate::Value::valueHelper(rhs.value);
case QCborValue::String:
- return toString() == other.toString();
+ return lhs.toString() == rhs.toString();
case QCborValue::Array:
- return toArray() == other.toArray();
+ return lhs.toArray() == rhs.toArray();
case QCborValue::Map:
- return toObject() == other.toObject();
+ return lhs.toObject() == rhs.toObject();
default:
return false;
}
@@ -883,12 +865,10 @@ bool QJsonValue::operator==(const QJsonValue &other) const
}
/*!
- Returns \c true if the value is not equal to \a other.
- */
-bool QJsonValue::operator!=(const QJsonValue &other) const
-{
- return !(*this == other);
-}
+ \fn bool QJsonValue::operator!=(const QJsonValue &lhs, const QJsonValue &rhs)
+
+ Returns \c true if the \a lhs value is not equal to \a rhs value, \c false otherwise.
+*/
/*!
\class QJsonValueRef
@@ -913,48 +893,200 @@ bool QJsonValue::operator!=(const QJsonValue &other) const
However, they are not explicitly documented here.
*/
-
-QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
+void QJsonValueRef::detach()
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ QCborContainerPrivate *d = QJsonPrivate::Value::container(*this);
+ d = QCborContainerPrivate::detach(d, d->elements.size());
+
if (is_object)
- o->setValueAt(index, val);
+ o->o.reset(d);
else
- a->replace(index, val);
+ a->a.reset(d);
+#else
+ d = QCborContainerPrivate::detach(d, d->elements.size());
+#endif
+}
- return *this;
+static QJsonValueRef &assignToRef(QJsonValueRef &ref, const QCborValue &value, bool is_object)
+{
+ QCborContainerPrivate *d = QJsonPrivate::Value::container(ref);
+ qsizetype index = QJsonPrivate::Value::indexHelper(ref);
+ if (is_object && value.isUndefined()) {
+ d->removeAt(index);
+ d->removeAt(index - 1);
+ } else {
+ d->replaceAt(index, value);
+ }
+
+ return ref;
+}
+
+QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
+{
+ detach();
+ return assignToRef(*this, QCborValue::fromJsonValue(val), is_object);
}
QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref)
{
- if (is_object)
- o->setValueAt(index, ref);
- else
- a->replace(index, ref);
+ // ### optimize more?
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(ref);
+ qsizetype index = QJsonPrivate::Value::indexHelper(ref);
- return *this;
+ if (d == QJsonPrivate::Value::container(*this) &&
+ index == QJsonPrivate::Value::indexHelper(*this))
+ return *this; // self assignment
+
+ detach();
+ return assignToRef(*this, d->valueAt(index), is_object);
+}
+
+#ifndef QT_NO_VARIANT
+QVariant QJsonValueConstRef::toVariant() const
+{
+ return concrete(*this).toVariant();
+}
+#endif // !QT_NO_VARIANT
+
+QJsonArray QJsonValueConstRef::toArray() const
+{
+ return concrete(*this).toArray();
+}
+
+QJsonObject QJsonValueConstRef::toObject() const
+{
+ return concrete(*this).toObject();
+}
+
+QJsonValue::Type QJsonValueConstRef::concreteType(QJsonValueConstRef self) noexcept
+{
+ return convertFromCborType(QJsonPrivate::Value::elementHelper(self).type);
+}
+
+bool QJsonValueConstRef::concreteBool(QJsonValueConstRef self, bool defaultValue) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ if (e.type == QCborValue::False)
+ return false;
+ if (e.type == QCborValue::True)
+ return true;
+ return defaultValue;
+}
+
+qint64 QJsonValueConstRef::concreteInt(QJsonValueConstRef self, qint64 defaultValue, bool clamp) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ qint64 v = defaultValue;
+ if (e.type == QCborValue::Double) {
+ // convertDoubleTo modifies the output even on returning false
+ if (!convertDoubleTo<qint64>(e.fpvalue(), &v))
+ v = defaultValue;
+ } else if (e.type == QCborValue::Integer) {
+ v = e.value;
+ }
+ if (clamp && qint64(int(v)) != v)
+ return defaultValue;
+ return v;
+}
+
+double QJsonValueConstRef::concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ if (e.type == QCborValue::Double)
+ return e.fpvalue();
+ if (e.type == QCborValue::Integer)
+ return e.value;
+ return defaultValue;
}
+QString QJsonValueConstRef::concreteString(QJsonValueConstRef self, const QString &defaultValue)
+{
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+ if (d->elements.at(index).type != QCborValue::String)
+ return defaultValue;
+ return d->stringAt(index);
+}
+
+QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept
+{
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+ return QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index));
+}
+
+QString QJsonValueConstRef::objectKey(QJsonValueConstRef self)
+{
+ Q_ASSERT(self.is_object);
+ Q_ASSERT(self.is_object);
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+
+ Q_ASSERT(d);
+ Q_ASSERT(index < d->elements.size());
+ return d->stringAt(index - 1);
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QVariant QJsonValueRef::toVariant() const
{
- return toValue().toVariant();
+ return QJsonValueConstRef::toVariant();
}
QJsonArray QJsonValueRef::toArray() const
{
- return toValue().toArray();
+ return QJsonValueConstRef::toArray();
}
QJsonObject QJsonValueRef::toObject() const
{
- return toValue().toObject();
+ return QJsonValueConstRef::toObject();
}
QJsonValue QJsonValueRef::toValue() const
{
- if (!is_object)
- return a->at(index);
- return o->valueAt(index);
+ return concrete(*this);
}
+#else
+QJsonValueRef QJsonValueRef::operator[](qsizetype key)
+{
+ if (d->elements.at(index).type != QCborValue::Array)
+ d->replaceAt(index, QCborValue::Array);
+
+ auto &e = d->elements[index];
+ e.container = QCborContainerPrivate::grow(e.container, key); // detaches
+ e.flags |= QtCbor::Element::IsContainer;
+
+ return QJsonValueRef(e.container, key, false);
+}
+
+QJsonValueRef QJsonValueRef::operator[](QAnyStringView key)
+{
+ // must go through QJsonObject because some of the machinery is non-static
+ // member or file-static in qjsonobject.cpp
+ QJsonObject o = QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index)).toObject();
+ QJsonValueRef ret = key.visit([&](auto v) {
+ if constexpr (std::is_same_v<decltype(v), QUtf8StringView>)
+ return o[QString::fromUtf8(v)];
+ else
+ return o[v];
+ });
+
+ // ### did the QJsonObject::operator[] above detach?
+ QCborContainerPrivate *x = o.o.take();
+ Q_ASSERT(x->ref.loadRelaxed() == 1);
+
+ auto &e = d->elements[index];
+ if (e.flags & QtCbor::Element::IsContainer && e.container != x)
+ o.o.reset(e.container); // might not an object!
+
+ e.flags |= QtCbor::Element::IsContainer;
+ e.container = x;
+
+ return ret;
+}
+#endif
size_t qHash(const QJsonValue &value, size_t seed)
{
@@ -974,8 +1106,7 @@ size_t qHash(const QJsonValue &value, size_t seed)
case QJsonValue::Undefined:
return seed;
}
- Q_UNREACHABLE();
- return 0;
+ Q_UNREACHABLE_RETURN(0);
}
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
diff --git a/src/corelib/serialization/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h
index fe7d0baf2f..d71dadf837 100644
--- a/src/corelib/serialization/qjsonvalue.h
+++ b/src/corelib/serialization/qjsonvalue.h
@@ -1,49 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONVALUE_H
#define QJSONVALUE_H
+#include <QtCore/qcborvalue.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qshareddata.h>
-#include <QtCore/qcborvalue.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +40,7 @@ public:
QJsonValue(int n);
QJsonValue(qint64 v);
QJsonValue(const QString &s);
- QJsonValue(QLatin1String s);
+ QJsonValue(QLatin1StringView s);
#ifndef QT_NO_CAST_FROM_ASCII
QT_ASCII_CAST_WARN inline QJsonValue(const char *s)
: QJsonValue(QString::fromUtf8(s)) {}
@@ -87,8 +52,8 @@ public:
~QJsonValue();
- QJsonValue(const QJsonValue &other);
- QJsonValue &operator =(const QJsonValue &other);
+ QJsonValue(const QJsonValue &other) noexcept;
+ QJsonValue &operator =(const QJsonValue &other) noexcept;
QJsonValue(QJsonValue &&other) noexcept;
@@ -123,17 +88,21 @@ public:
QJsonObject toObject() const;
QJsonObject toObject(const QJsonObject &defaultValue) const;
-#if QT_STRINGVIEW_LEVEL < 2
const QJsonValue operator[](const QString &key) const;
-#endif
const QJsonValue operator[](QStringView key) const;
- const QJsonValue operator[](QLatin1String key) const;
+ const QJsonValue operator[](QLatin1StringView key) const;
const QJsonValue operator[](qsizetype i) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonValue &other) const;
bool operator!=(const QJsonValue &other) const;
+#endif
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonValue &lhs,
+ const QJsonValue &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValue)
+
// avoid implicit conversions from char * to bool
QJsonValue(const void *) = delete;
friend class QJsonPrivate::Value;
@@ -150,22 +119,141 @@ private:
static_assert(sizeof(QCborValue::Type) == sizeof(QJsonValue::Type));
};
-class Q_CORE_EXPORT QJsonValueRef
+Q_DECLARE_SHARED(QJsonValue)
+
+class QJsonValueConstRef
{
public:
- QJsonValueRef(QJsonArray *array, qsizetype idx)
+ QJsonValueConstRef(const QJsonValueConstRef &) = default;
+ QJsonValueConstRef &operator=(const QJsonValueConstRef &) = delete;
+ inline operator QJsonValue() const { return concrete(*this); }
+
+ Q_CORE_EXPORT QVariant toVariant() const;
+ QJsonValue::Type type() const { return concreteType(*this); }
+ bool isNull() const { return type() == QJsonValue::Null; }
+ bool isBool() const { return type() == QJsonValue::Bool; }
+ bool isDouble() const { return type() == QJsonValue::Double; }
+ bool isString() const { return type() == QJsonValue::String; }
+ bool isArray() const { return type() == QJsonValue::Array; }
+ bool isObject() const { return type() == QJsonValue::Object; }
+ bool isUndefined() const { return type() == QJsonValue::Undefined; }
+
+ bool toBool(bool defaultValue = false) const
+ { return concreteBool(*this, defaultValue); }
+ int toInt(int defaultValue = 0) const
+ { return int(concreteInt(*this, defaultValue, true)); }
+ qint64 toInteger(qint64 defaultValue = 0) const
+ { return concreteInt(*this, defaultValue, false); }
+ double toDouble(double defaultValue = 0) const
+ { return concreteDouble(*this, defaultValue); }
+ QString toString(const QString &defaultValue = {}) const
+ { return concreteString(*this, defaultValue); }
+ Q_CORE_EXPORT QJsonArray toArray() const;
+ Q_CORE_EXPORT QJsonObject toObject() const;
+
+ const QJsonValue operator[](QStringView key) const { return concrete(*this)[key]; }
+ const QJsonValue operator[](QLatin1StringView key) const { return concrete(*this)[key]; }
+ const QJsonValue operator[](qsizetype i) const { return concrete(*this)[i]; }
+
+protected:
+ friend bool comparesEqual(const QJsonValueConstRef &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(concrete(lhs), concrete(rhs));
+ }
+ friend bool comparesEqual(const QJsonValueConstRef &lhs,
+ const QJsonValue &rhs) noexcept
+ {
+ return comparesEqual(concrete(lhs), rhs);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueConstRef)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueConstRef, QJsonValue)
+
+ Q_CORE_EXPORT static QJsonValue::Type
+ concreteType(QJsonValueConstRef self) noexcept Q_DECL_PURE_FUNCTION;
+ Q_CORE_EXPORT static bool
+ concreteBool(QJsonValueConstRef self, bool defaultValue) noexcept Q_DECL_PURE_FUNCTION;
+ Q_CORE_EXPORT static qint64
+ concreteInt(QJsonValueConstRef self, qint64 defaultValue, bool clamp) noexcept Q_DECL_PURE_FUNCTION;
+ Q_CORE_EXPORT static double
+ concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept Q_DECL_PURE_FUNCTION;
+ Q_CORE_EXPORT static QString concreteString(QJsonValueConstRef self, const QString &defaultValue);
+ Q_CORE_EXPORT static QJsonValue concrete(QJsonValueConstRef self) noexcept;
+
+ // for iterators
+ Q_CORE_EXPORT static QString objectKey(QJsonValueConstRef self);
+ QString objectKey() const { return objectKey(*this); }
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ QJsonValueConstRef(QJsonArray *array, qsizetype idx)
: a(array), is_object(false), index(static_cast<quint64>(idx)) {}
- QJsonValueRef(QJsonObject *object, qsizetype idx)
+ QJsonValueConstRef(QJsonObject *object, qsizetype idx)
: o(object), is_object(true), index(static_cast<quint64>(idx)) {}
+ void rebind(QJsonValueConstRef other)
+ {
+ Q_ASSERT(is_object == other.is_object);
+ if (is_object)
+ o = other.o;
+ else
+ a = other.a;
+ index = other.index;
+ }
+
+ union {
+ QJsonArray *a;
+ QJsonObject *o;
+ void *d;
+ };
+ quint64 is_object : 1;
+ quint64 index : 63;
+#else
+ constexpr QJsonValueConstRef(QCborContainerPrivate *d, size_t index, bool is_object)
+ : d(d), is_object(is_object), index(index)
+ {}
+
+ // implemented in qjsonarray.h & qjsonobject.h, to get their d
+ QJsonValueConstRef(QJsonArray *array, qsizetype idx);
+ QJsonValueConstRef(QJsonObject *object, qsizetype idx);
+
+ void rebind(QJsonValueConstRef other)
+ {
+ d = other.d;
+ index = other.index;
+ }
+
+ QCborContainerPrivate *d = nullptr;
+ size_t is_object : 1;
+ size_t index : std::numeric_limits<size_t>::digits - 1;
+#endif
+
+ friend class QJsonArray;
+ friend class QJsonObject;
+ friend class QJsonPrivate::Value;
+};
+
+QT_WARNING_PUSH
+QT6_ONLY(QT_WARNING_DISABLE_MSVC(4275)) // non dll-interface class 'QJsonValueConstRef' used as base for dll-interface class 'QJsonValueRef'
+class QT6_ONLY(Q_CORE_EXPORT) QJsonValueRef : public QJsonValueConstRef
+{
+public:
QJsonValueRef(const QJsonValueRef &) = default;
+ QT7_ONLY(Q_CORE_EXPORT) QJsonValueRef &operator = (const QJsonValue &val);
+ QT7_ONLY(Q_CORE_EXPORT) QJsonValueRef &operator = (const QJsonValueRef &val);
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ // retained for binary compatibility (due to the Q_CORE_EXPORT) because at
+ // least one compiler emits and exports all inlines in an exported class
- inline operator QJsonValue() const { return toValue(); }
- QJsonValueRef &operator = (const QJsonValue &val);
- QJsonValueRef &operator = (const QJsonValueRef &val);
+ QJsonValueRef(QJsonArray *array, qsizetype idx)
+ : QJsonValueConstRef(array, idx) {}
+ QJsonValueRef(QJsonObject *object, qsizetype idx)
+ : QJsonValueConstRef(object, idx) {}
+
+ operator QJsonValue() const { return toValue(); }
QVariant toVariant() const;
- inline QJsonValue::Type type() const { return toValue().type(); }
+ inline QJsonValue::Type type() const { return QJsonValueConstRef::type(); }
inline bool isNull() const { return type() == QJsonValue::Null; }
inline bool isBool() const { return type() == QJsonValue::Bool; }
inline bool isDouble() const { return type() == QJsonValue::Double; }
@@ -174,36 +262,57 @@ public:
inline bool isObject() const { return type() == QJsonValue::Object; }
inline bool isUndefined() const { return type() == QJsonValue::Undefined; }
- inline bool toBool(bool defaultValue = false) const { return toValue().toBool(defaultValue); }
- inline int toInt(int defaultValue = 0) const { return toValue().toInt(defaultValue); }
- inline qint64 toInteger(qint64 defaultValue = 0) const { return toValue().toInteger(defaultValue); }
- inline double toDouble(double defaultValue = 0) const { return toValue().toDouble(defaultValue); }
- inline QString toString(const QString &defaultValue = {}) const { return toValue().toString(defaultValue); }
+ inline bool toBool(bool defaultValue = false) const { return QJsonValueConstRef::toBool(defaultValue); }
+ inline int toInt(int defaultValue = 0) const { return QJsonValueConstRef::toInt(defaultValue); }
+ inline qint64 toInteger(qint64 defaultValue = 0) const { return QJsonValueConstRef::toInteger(defaultValue); }
+ inline double toDouble(double defaultValue = 0) const { return QJsonValueConstRef::toDouble(defaultValue); }
+ inline QString toString(const QString &defaultValue = {}) const { return QJsonValueConstRef::toString(defaultValue); }
QJsonArray toArray() const;
QJsonObject toObject() const;
- const QJsonValue operator[](QStringView key) const { return toValue()[key]; }
- const QJsonValue operator[](QLatin1String key) const { return toValue()[key]; }
- const QJsonValue operator[](qsizetype i) const { return toValue()[i]; }
+ const QJsonValue operator[](QStringView key) const { return QJsonValueConstRef::operator[](key); }
+ const QJsonValue operator[](QLatin1StringView key) const { return QJsonValueConstRef::operator[](key); }
+ const QJsonValue operator[](qsizetype i) const { return QJsonValueConstRef::operator[](i); }
- inline bool operator==(const QJsonValue &other) const { return toValue() == other; }
- inline bool operator!=(const QJsonValue &other) const { return toValue() != other; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QJsonValue &other) const { return comparesEqual(*this, other); }
+ inline bool operator!=(const QJsonValue &other) const { return !comparesEqual(*this, other); }
+#endif
private:
+ friend bool comparesEqual(const QJsonValueRef &lhs,
+ const QJsonValueRef &rhs) noexcept
+ {
+ return comparesEqual(QJsonValue(lhs), QJsonValue(rhs));
+ }
+ friend bool comparesEqual(const QJsonValueRef &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(QJsonValue(lhs), QJsonValue(rhs));
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueRef)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueRef, QJsonValueConstRef)
+
QJsonValue toValue() const;
+#else
+ using QJsonValueConstRef::operator[];
+ Q_CORE_EXPORT QJsonValueRef operator[](QAnyStringView key);
+ Q_CORE_EXPORT QJsonValueRef operator[](qsizetype i);
- union {
- QJsonArray *a;
- QJsonObject *o;
- };
- quint64 is_object : 1;
- quint64 index : 63;
+private:
+ using QJsonValueConstRef::QJsonValueConstRef;
+#endif // < Qt 7
+ QT7_ONLY(Q_CORE_EXPORT) void detach();
friend class QJsonArray;
friend class QJsonObject;
};
+QT_WARNING_POP
-Q_DECLARE_SHARED(QJsonValue)
+inline QJsonValue QCborValueConstRef::toJsonValue() const
+{
+ return concrete().toJsonValue();
+}
Q_CORE_EXPORT size_t qHash(const QJsonValue &value, size_t seed = 0);
diff --git a/src/corelib/serialization/qjsonwriter.cpp b/src/corelib/serialization/qjsonwriter.cpp
index 54aad864a5..ab34e9228d 100644
--- a/src/corelib/serialization/qjsonwriter.cpp
+++ b/src/corelib/serialization/qjsonwriter.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <cmath>
#include <qlocale.h>
@@ -58,23 +22,24 @@ static inline uchar hexdig(uint u)
return (u < 0xa ? '0' + u : 'a' + u - 0xa);
}
-static QByteArray escapedString(const QString &s)
+static QByteArray escapedString(QStringView s)
{
// give it a minimum size to ensure the resize() below always adds enough space
- QByteArray ba(qMax(s.length(), 16), Qt::Uninitialized);
+ QByteArray ba(qMax(s.size(), 16), Qt::Uninitialized);
+ auto ba_const_start = [&]() { return reinterpret_cast<const uchar *>(ba.constData()); };
uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
- const uchar *ba_end = cursor + ba.length();
- const char16_t *src = reinterpret_cast<const char16_t *>(s.constBegin());
- const char16_t *const end = reinterpret_cast<const char16_t *>(s.constEnd());
+ const uchar *ba_end = cursor + ba.size();
+ const char16_t *src = s.utf16();
+ const char16_t *const end = s.utf16() + s.size();
while (src != end) {
if (cursor >= ba_end - 6) {
// ensure we have enough space
- int pos = cursor - (const uchar *)ba.constData();
+ qptrdiff pos = cursor - ba_const_start();
ba.resize(ba.size()*2);
- cursor = (uchar *)ba.data() + pos;
- ba_end = (const uchar *)ba.constData() + ba.length();
+ cursor = reinterpret_cast<uchar *>(ba.data()) + pos;
+ ba_end = ba_const_start() + ba.size();
}
char16_t u = *src++;
@@ -124,7 +89,7 @@ static QByteArray escapedString(const QString &s)
}
}
- ba.resize(cursor - (const uchar *)ba.constData());
+ ba.resize(cursor - ba_const_start());
return ba;
}
@@ -143,7 +108,7 @@ static void valueToJson(const QCborValue &v, QByteArray &json, int indent, bool
break;
case QCborValue::Double: {
const double d = v.toDouble();
- if (qIsFinite(d))
+ if (qt_is_finite(d))
json += QByteArray::number(d, 'g', QLocale::FloatingPointShortest);
else
json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4)
diff --git a/src/corelib/serialization/qjsonwriter_p.h b/src/corelib/serialization/qjsonwriter_p.h
index 8c263bb7c3..f61840247f 100644
--- a/src/corelib/serialization/qjsonwriter_p.h
+++ b/src/corelib/serialization/qjsonwriter_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSONWRITER_P_H
#define QJSONWRITER_P_H
diff --git a/src/corelib/serialization/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp
index 5e09d2ef28..e9d650b3e2 100644
--- a/src/corelib/serialization/qtextstream.cpp
+++ b/src/corelib/serialization/qtextstream.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QTEXTSTREAM_DEBUG
static const int QTEXTSTREAM_BUFFERSIZE = 16384;
@@ -50,6 +14,7 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
\ingroup io
\ingroup string-processing
+ \ingroup qtserialization
\reentrant
QTextStream can operate on a QIODevice, a QByteArray or a
@@ -231,6 +196,8 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
#include "qnumeric.h"
#include "qvarlengtharray.h"
#include <private/qdebug_p.h>
+#include <private/qnumeric_p.h>
+#include <private/qtools_p.h>
#include <locale.h>
#include "private/qlocale_p.h"
@@ -279,6 +246,9 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+
//-------------------------------------------------------------------
/*!
@@ -310,7 +280,7 @@ void QTextStreamPrivate::Params::reset()
realNumberPrecision = 6;
integerBase = 0;
fieldWidth = 0;
- padChar = QLatin1Char(' ');
+ padChar = u' ';
fieldAlignment = QTextStream::AlignRight;
realNumberNotation = QTextStream::SmartNotation;
numberFlags = { };
@@ -390,6 +360,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
if (bytesRead <= 0)
return false;
+#ifndef QT_BOOTSTRAPPED
if (autoDetectUnicode) {
autoDetectUnicode = false;
@@ -404,6 +375,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
#if defined (QTEXTSTREAM_DEBUG)
qDebug("QTextStreamPrivate::fillReadBuffer(), using %s encoding", QStringConverter::nameForEncoding(encoding));
#endif
+#endif
#if defined (QTEXTSTREAM_DEBUG)
qDebug("QTextStreamPrivate::fillReadBuffer(), device->read(\"%s\", %d) == %d",
@@ -415,7 +387,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
// remove all '\r\n' in the string.
if (readBuffer.size() > oldReadBufferSize && textModeEnabled) {
- QChar CR = QLatin1Char('\r');
+ QChar CR = u'\r';
QChar *writePtr = readBuffer.data() + oldReadBufferSize;
QChar *readPtr = readBuffer.data() + oldReadBufferSize;
QChar *endPtr = readBuffer.data() + readBuffer.size();
@@ -483,7 +455,7 @@ void QTextStreamPrivate::flushWriteBuffer()
bool textModeEnabled = device->isTextModeEnabled();
if (textModeEnabled) {
device->setTextModeEnabled(false);
- writeBuffer.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
+ writeBuffer.replace(u'\n', "\r\n"_L1);
}
#endif
@@ -590,9 +562,9 @@ bool QTextStreamPrivate::scan(const QChar **ptr, int *length, int maxlen, TokenD
}
break;
case EndOfLine:
- if (ch == QLatin1Char('\n')) {
+ if (ch == u'\n') {
foundToken = true;
- delimSize = (lastChar == QLatin1Char('\r')) ? 2 : 1;
+ delimSize = (lastChar == u'\r') ? 2 : 1;
consumeDelimiter = true;
}
lastChar = ch;
@@ -614,7 +586,7 @@ bool QTextStreamPrivate::scan(const QChar **ptr, int *length, int maxlen, TokenD
// don't make it part of the line.
if (delimiter == EndOfLine && totalSize > 0 && !foundToken) {
if (((string && stringOffset + totalSize == string->size()) || (device && device->atEnd()))
- && lastChar == QLatin1Char('\r')) {
+ && lastChar == u'\r') {
consumeDelimiter = true;
++delimSize;
}
@@ -742,7 +714,7 @@ inline void QTextStreamPrivate::write(QChar ch)
/*!
\internal
*/
-void QTextStreamPrivate::write(QLatin1String data)
+void QTextStreamPrivate::write(QLatin1StringView data)
{
if (string) {
// ### What about seek()??
@@ -878,7 +850,7 @@ void QTextStreamPrivate::putString(const QChar *data, qsizetype len, bool number
/*!
\internal
*/
-void QTextStreamPrivate::putString(QLatin1String data, bool number)
+void QTextStreamPrivate::putString(QLatin1StringView data, bool number)
{
if (Q_UNLIKELY(params.fieldWidth > data.size())) {
@@ -891,7 +863,7 @@ void QTextStreamPrivate::putString(QLatin1String data, bool number)
if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
// write the sign before the padding, then skip it later
write(&sign, 1);
- data = QLatin1String(data.data() + 1, data.size() - 1);
+ data = QLatin1StringView(data.data() + 1, data.size() - 1);
}
}
@@ -1030,7 +1002,10 @@ QTextStream::QTextStream(FILE *fileHandle, OpenMode openMode)
fileHandle, int(openMode));
#endif
QFile *file = new QFile;
- file->open(fileHandle, openMode);
+ // Discarding the return value of open; even if it failed
+ // (and the file is not open), QTextStream still reports `Ok`
+ // for closed QIODevices, so there's nothing really to do here.
+ (void)file->open(fileHandle, openMode);
Q_D(QTextStream);
d->device = file;
@@ -1433,7 +1408,8 @@ QTextStream::RealNumberNotation QTextStream::realNumberNotation() const
/*!
Sets the precision of real numbers to \a precision. This value
describes the number of fraction digits QTextStream should
- write when generating real numbers.
+ write when generating real numbers (FixedNotation, ScientificNotation), or
+ the maximum number of significant digits (SmartNotation).
The precision cannot be a negative value. The default value is 6.
@@ -1452,7 +1428,9 @@ void QTextStream::setRealNumberPrecision(int precision)
/*!
Returns the current real number precision, or the number of fraction
- digits QTextStream will write when generating real numbers.
+ digits QTextStream will write when generating real numbers
+ (FixedNotation, ScientificNotation), or the maximum number of significant
+ digits (SmartNotation).
\sa setRealNumberNotation(), realNumberNotation(), numberFlags(), integerBase()
*/
@@ -1646,7 +1624,7 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong
QChar ch;
if (!getChar(&ch))
return npsInvalidPrefix;
- if (ch == QLatin1Char('0')) {
+ if (ch == u'0') {
QChar ch2;
if (!getChar(&ch2)) {
// Result is the number 0
@@ -1655,9 +1633,9 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong
}
ch2 = ch2.toLower();
- if (ch2 == QLatin1Char('x')) {
+ if (ch2 == u'x') {
base = 16;
- } else if (ch2 == QLatin1Char('b')) {
+ } else if (ch2 == u'b') {
base = 2;
} else if (ch2.isDigit() && ch2.digitValue() >= 0 && ch2.digitValue() <= 7) {
base = 8;
@@ -1682,9 +1660,9 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong
case 2: {
QChar pf1, pf2, dig;
// Parse prefix '0b'
- if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
+ if (!getChar(&pf1) || pf1 != u'0')
return npsInvalidPrefix;
- if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('b'))
+ if (!getChar(&pf2) || pf2.toLower() != u'b')
return npsInvalidPrefix;
// Parse digits
int ndigits = 0;
@@ -1710,13 +1688,13 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong
case 8: {
QChar pf, dig;
// Parse prefix '0'
- if (!getChar(&pf) || pf != QLatin1Char('0'))
+ if (!getChar(&pf) || pf != u'0')
return npsInvalidPrefix;
// Parse digits
int ndigits = 0;
while (getChar(&dig)) {
int n = dig.toLower().unicode();
- if (n >= '0' && n <= '7') {
+ if (isOctalDigit(n)) {
val *= 8;
val += n - '0';
} else {
@@ -1773,20 +1751,17 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong
case 16: {
QChar pf1, pf2, dig;
// Parse prefix ' 0x'
- if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
+ if (!getChar(&pf1) || pf1 != u'0')
return npsInvalidPrefix;
- if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('x'))
+ if (!getChar(&pf2) || pf2.toLower() != u'x')
return npsInvalidPrefix;
// Parse digits
int ndigits = 0;
while (getChar(&dig)) {
- int n = dig.toLower().unicode();
- if (n >= '0' && n <= '9') {
- val <<= 4;
- val += n - '0';
- } else if (n >= 'a' && n <= 'f') {
+ const int h = fromHex(dig.unicode());
+ if (h != -1) {
val <<= 4;
- val += 10 + (n - 'a');
+ val += h;
} else {
ungetChar(dig);
break;
@@ -1942,13 +1917,13 @@ bool QTextStreamPrivate::getReal(double *f)
// nan/+inf/-inf, so here we also check for uppercase and mixed
// case versions.
if (!qstricmp(buf, "nan") || !qstricmp(buf, "+nan") || !qstricmp(buf, "-nan")) {
- *f = qQNaN();
+ *f = qt_qnan();
return true;
} else if (!qstricmp(buf, "+inf") || !qstricmp(buf, "inf")) {
- *f = qInf();
+ *f = qt_inf();
return true;
} else if (!qstricmp(buf, "-inf")) {
- *f = -qInf();
+ *f = -qt_inf();
return true;
}
bool ok;
@@ -1980,7 +1955,7 @@ QTextStream &QTextStream::operator>>(QChar &c)
\overload
Reads a character from the stream and stores it in \a c. The
- character from the stream is converted to ISO-5589-1 before it is
+ character from the stream is converted to ISO-8859-1 before it is
stored.
\sa QChar::toLatin1()
@@ -1994,6 +1969,14 @@ QTextStream &QTextStream::operator>>(char &c)
}
/*!
+ \fn QTextStream &QTextStream::operator>>(char16_t &c)
+ \overload
+ \since 6.4
+
+ Reads a character from the stream and stores it in \a c.
+*/
+
+/*!
Reads an integer from the stream and stores it in \a i, then
returns a reference to the QTextStream. The number is cast to
the correct type before it is stored. If no number was detected on
@@ -2251,8 +2234,8 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative)
// workaround for backward compatibility - in octal form with
// ShowBase flag set zero should be written as '00'
if (number == 0 && base == 8 && params.numberFlags & QTextStream::ShowBase
- && result == QLatin1String("0")) {
- result.prepend(QLatin1Char('0'));
+ && result == "0"_L1) {
+ result.prepend(u'0');
}
}
putString(result, true);
@@ -2286,6 +2269,15 @@ QTextStream &QTextStream::operator<<(char c)
}
/*!
+ \fn QTextStream &QTextStream::operator<<(char16_t c)
+ \overload
+ \since 6.3.1
+
+ Writes the Unicode character \a c to the stream, then returns a
+ reference to the QTextStream.
+*/
+
+/*!
Writes the integer number \a i to the stream, then returns a
reference to the QTextStream. By default, the number is stored in
decimal form, but you can also set the base by calling
@@ -2496,7 +2488,7 @@ QTextStream &QTextStream::operator<<(QStringView string)
Writes \a string to the stream, and returns a reference to the
QTextStream.
*/
-QTextStream &QTextStream::operator<<(QLatin1String string)
+QTextStream &QTextStream::operator<<(QLatin1StringView string)
{
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
@@ -2514,7 +2506,7 @@ QTextStream &QTextStream::operator<<(const QByteArray &array)
{
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
- d->putString(QString::fromUtf8(array.constData(), array.length()));
+ d->putString(QString::fromUtf8(array.constData(), array.size()));
return *this;
}
@@ -2844,7 +2836,7 @@ QTextStream &center(QTextStream &stream)
*/
QTextStream &endl(QTextStream &stream)
{
- return stream << QLatin1Char('\n') << Qt::flush;
+ return stream << '\n'_L1 << Qt::flush;
}
/*!
@@ -2958,7 +2950,7 @@ void QTextStream::setEncoding(QStringConverter::Encoding encoding)
d->encoding = encoding;
d->toUtf16 = QStringDecoder(d->encoding);
- bool generateBOM = d->hasWrittenData && d->generateBOM;
+ bool generateBOM = !d->hasWrittenData && d->generateBOM;
d->fromUtf16 = QStringEncoder(d->encoding,
generateBOM ? QStringEncoder::Flag::WriteBom : QStringEncoder::Flag::Default);
diff --git a/src/corelib/serialization/qtextstream.h b/src/corelib/serialization/qtextstream.h
index e69c6a67dc..7a0fc42a68 100644
--- a/src/corelib/serialization/qtextstream.h
+++ b/src/corelib/serialization/qtextstream.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEXTSTREAM_H
#define QTEXTSTREAM_H
#include <QtCore/qiodevicebase.h>
-#include <QtCore/qstring.h>
#include <QtCore/qchar.h>
#include <QtCore/qscopedpointer.h>
-#include <QtCore/qstringconverter.h>
+#include <QtCore/qstringconverter_base.h>
#include <stdio.h>
+#if 0
+// the macros around the class name throw off syncqt:
+#pragma qt_class(QTextStream)
+#endif
+
#ifdef Status
#error qtextstream.h must be included before any header file that defines Status
#endif
@@ -56,9 +24,20 @@ QT_BEGIN_NAMESPACE
class QIODevice;
class QLocale;
+class QString;
+
+#if !QT_DEPRECATED_SINCE(6, 9)
+# define QT_NO_INHERITABLE_TEXT_STREAM
+#endif
+
+#ifdef QT_NO_INHERITABLE_TEXT_STREAM
+# define QT_TEXT_STREAM_FINAL final
+#else
+# define QT_TEXT_STREAM_FINAL
+#endif
class QTextStreamPrivate;
-class Q_CORE_EXPORT QTextStream : public QIODeviceBase
+class Q_CORE_EXPORT QTextStream QT_TEXT_STREAM_FINAL : public QIODeviceBase
{
Q_DECLARE_PRIVATE(QTextStream)
@@ -95,7 +74,8 @@ public:
explicit QTextStream(QString *string, OpenMode openMode = ReadWrite);
explicit QTextStream(QByteArray *array, OpenMode openMode = ReadWrite);
explicit QTextStream(const QByteArray &array, OpenMode openMode = ReadOnly);
- virtual ~QTextStream();
+ QT6_ONLY(virtual)
+ ~QTextStream();
void setEncoding(QStringConverter::Encoding encoding);
QStringConverter::Encoding encoding() const;
@@ -153,6 +133,8 @@ public:
QTextStream &operator>>(QChar &ch);
QTextStream &operator>>(char &ch);
+ QTextStream &operator>>(char16_t &ch)
+ { QChar c; *this >> c; ch = c.unicode(); return *this; }
QTextStream &operator>>(signed short &i);
QTextStream &operator>>(unsigned short &i);
QTextStream &operator>>(signed int &i);
@@ -169,6 +151,7 @@ public:
QTextStream &operator<<(QChar ch);
QTextStream &operator<<(char ch);
+ QTextStream &operator<<(char16_t ch) { return *this << QChar(ch); }
QTextStream &operator<<(signed short i);
QTextStream &operator<<(unsigned short i);
QTextStream &operator<<(signed int i);
@@ -181,7 +164,7 @@ public:
QTextStream &operator<<(double f);
QTextStream &operator<<(const QString &s);
QTextStream &operator<<(QStringView s);
- QTextStream &operator<<(QLatin1String s);
+ QTextStream &operator<<(QLatin1StringView s);
QTextStream &operator<<(const QByteArray &array);
QTextStream &operator<<(const char *c);
QTextStream &operator<<(const void *ptr);
diff --git a/src/corelib/serialization/qtextstream_p.h b/src/corelib/serialization/qtextstream_p.h
index 4a9f54ce1d..909b75d0de 100644
--- a/src/corelib/serialization/qtextstream_p.h
+++ b/src/corelib/serialization/qtextstream_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEXTSTREAM_P_H
#define QTEXTSTREAM_P_H
@@ -53,8 +17,9 @@
//
#include <QtCore/private/qglobal_p.h>
-#include "qiodevice.h"
-#include "qlocale.h"
+#include <QtCore/qstringconverter.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qlocale.h>
#include "qtextstream.h"
QT_BEGIN_NAMESPACE
@@ -174,17 +139,17 @@ public:
NumberParsingStatus getNumber(qulonglong *l);
bool getReal(double *f);
- inline void write(QStringView data) { write(data.begin(), data.length()); }
+ inline void write(QStringView data) { write(data.begin(), data.size()); }
inline void write(QChar ch);
void write(const QChar *data, qsizetype len);
- void write(QLatin1String data);
+ void write(QLatin1StringView data);
void writePadding(qsizetype len);
inline void putString(QStringView string, bool number = false)
{
- putString(string.constData(), string.length(), number);
+ putString(string.constData(), string.size(), number);
}
void putString(const QChar *data, qsizetype len, bool number = false);
- void putString(QLatin1String data, bool number = false);
+ void putString(QLatin1StringView data, bool number = false);
void putString(QUtf8StringView data, bool number = false);
inline void putChar(QChar ch);
void putNumber(qulonglong number, bool negative);
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index 68c06eb0bd..0fe8c87779 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "QtCore/qxmlstream.h"
-#ifndef QT_NO_XMLSTREAM
+#if QT_CONFIG(xmlstream)
#include "qxmlutils_p.h"
#include <qdebug.h>
@@ -49,28 +13,22 @@
#include <qstack.h>
#include <qbuffer.h>
#include <qscopeguard.h>
-#ifndef QT_BOOTSTRAPPED
#include <qcoreapplication.h>
-#else
-// This specialization of Q_DECLARE_TR_FUNCTIONS is not in qcoreapplication.h,
-// because that header depends on QObject being available, which is not the
-// case for most bootstrapped applications.
-#define Q_DECLARE_TR_FUNCTIONS(context) \
-public: \
- static inline QString tr(const char *sourceText, const char *comment = nullptr) \
- { Q_UNUSED(comment); return QString::fromUtf8(sourceText); } \
- static inline QString tr(const char *sourceText, const char*, int) \
- { return QString::fromUtf8(sourceText); } \
-private:
-#endif
+
+#include <private/qoffsetstringarray_p.h>
+#include <private/qtools_p.h>
#include <iterator>
#include "qxmlstream_p.h"
#include "qxmlstreamparser_p.h"
+#include <private/qstringconverter_p.h>
+#include <private/qstringiterator_p.h>
QT_BEGIN_NAMESPACE
using namespace QtPrivate;
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
enum { StreamEOF = ~0U };
@@ -89,8 +47,62 @@ auto reversed(Range &r)
template <typename Range>
void reversed(const Range &&) = delete;
+
+// implementation of missing QUtf8StringView methods for ASCII-only needles:
+auto transform(QLatin1StringView haystack, char needle)
+{
+ struct R { QLatin1StringView haystack; char16_t needle; };
+ return R{haystack, uchar(needle)};
+}
+
+auto transform(QStringView haystack, char needle)
+{
+ struct R { QStringView haystack; char16_t needle; };
+ return R{haystack, uchar(needle)};
+}
+
+auto transform(QUtf8StringView haystack, char needle)
+{
+ struct R { QByteArrayView haystack; char needle; };
+ return R{haystack, needle};
+}
+
+auto transform(QLatin1StringView haystack, QLatin1StringView needle)
+{
+ struct R { QLatin1StringView haystack; QLatin1StringView needle; };
+ return R{haystack, needle};
+}
+
+auto transform(QStringView haystack, QLatin1StringView needle)
+{
+ struct R { QStringView haystack; QLatin1StringView needle; };
+ return R{haystack, needle};
}
+auto transform(QUtf8StringView haystack, QLatin1StringView needle)
+{
+ struct R { QLatin1StringView haystack; QLatin1StringView needle; };
+ return R{QLatin1StringView{QByteArrayView{haystack}}, needle};
+}
+
+#define WRAP(method, Needle) \
+ auto method (QAnyStringView s, Needle needle) noexcept \
+ { \
+ return s.visit([needle](auto s) { \
+ auto r = transform(s, needle); \
+ return r.haystack. method (r.needle); \
+ }); \
+ } \
+ /*end*/
+
+WRAP(count, char)
+WRAP(contains, char)
+WRAP(contains, QLatin1StringView)
+WRAP(endsWith, char)
+WRAP(indexOf, QLatin1StringView)
+
+} // unnamed namespace
+
/*!
\enum QXmlStreamReader::TokenType
@@ -129,7 +141,7 @@ void reversed(const Range &&) = delete;
\value DTD The reader reports a DTD in text(), notation
declarations in notationDeclarations(), and entity declarations in
entityDeclarations(). Details of the DTD declaration are reported
- in in dtdName(), dtdPublicId(), and dtdSystemId().
+ in dtdName(), dtdPublicId(), and dtdSystemId().
\value EntityReference The reader reports an entity reference that
could not be resolved. The name of the reference is reported in
@@ -174,7 +186,7 @@ void reversed(const Range &&) = delete;
addData() or by waiting for it to arrive on the device().
\value UnexpectedElementError The parser encountered an element
- that was different to those it expected.
+ or token that was different to those it expected.
*/
@@ -221,7 +233,7 @@ QString QXmlStreamEntityResolver::resolveUndeclaredEntity(const QString &/*name*
return QString();
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(const QString &name)
{
@@ -277,6 +289,8 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
\ingroup xml-tools
+ \ingroup qtserialization
+
QXmlStreamReader provides a simple streaming API to parse well-formed
XML. It is an alternative to first loading the complete XML into a
DOM tree (see \l QDomDocument). QXmlStreamReader reads data either
@@ -309,13 +323,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
include external parsed entities. As long as no error occurs, the
- application code can thus be assured that the data provided by the
- stream reader satisfies the W3C's criteria for well-formed XML. For
- example, you can be certain that all tags are indeed nested and
- closed properly, that references to internal entities have been
- replaced with the correct replacement text, and that attributes have
- been normalized or added according to the internal subset of the
- DTD.
+ application code can thus be assured, that
+ \list
+ \li the data provided by the stream reader satisfies the W3C's
+ criteria for well-formed XML,
+ \li tokens are provided in a valid order.
+ \endlist
+
+ Unless QXmlStreamReader raises an error, it guarantees the following:
+ \list
+ \li All tags are nested and closed properly.
+ \li References to internal entities have been replaced with the
+ correct replacement text.
+ \li Attributes have been normalized or added according to the
+ internal subset of the \l DTD.
+ \li Tokens of type \l StartDocument happen before all others,
+ aside from comments and processing instructions.
+ \li At most one DOCTYPE element (a token of type \l DTD) is present.
+ \li If present, the DOCTYPE appears before all other elements,
+ aside from StartDocument, comments and processing instructions.
+ \endlist
+
+ In particular, once any token of type \l StartElement, \l EndElement,
+ \l Characters, \l EntityReference or \l EndDocument is seen, no
+ tokens of type StartDocument or DTD will be seen. If one is present in
+ the input stream, out of order, an error is raised.
+
+ \note The token types \l Comment and \l ProcessingInstruction may appear
+ anywhere in the stream.
If an error occurs while parsing, atEnd() and hasError() return
true, and error() returns the error that occurred. The functions
@@ -408,41 +443,55 @@ QXmlStreamReader::QXmlStreamReader(QIODevice *device)
}
/*!
- Creates a new stream reader that reads from \a data.
+ \overload
- \sa addData(), clear(), setDevice()
- */
-QXmlStreamReader::QXmlStreamReader(const QByteArray &data)
- : d_ptr(new QXmlStreamReaderPrivate(this))
-{
- Q_D(QXmlStreamReader);
- d->dataBuffer = data;
-}
+ \fn QXmlStreamReader::QXmlStreamReader(const QByteArray &data)
+
+ Creates a new stream reader that reads from \a data.
+
+ \sa addData(), clear(), setDevice()
+*/
/*!
- Creates a new stream reader that reads from \a data.
+ Creates a new stream reader that reads from \a data.
- \sa addData(), clear(), setDevice()
- */
-QXmlStreamReader::QXmlStreamReader(const QString &data)
+ \note In Qt versions prior to 6.5, this constructor was overloaded
+ for QString and \c {const char*}.
+
+ \sa addData(), clear(), setDevice()
+*/
+QXmlStreamReader::QXmlStreamReader(QAnyStringView data)
: d_ptr(new QXmlStreamReaderPrivate(this))
{
Q_D(QXmlStreamReader);
- d->dataBuffer = data.toUtf8();
- d->decoder = QStringDecoder(QStringDecoder::Utf8);
- d->lockEncoding = true;
+ data.visit([d](auto data) {
+ if constexpr (std::is_same_v<decltype(data), QStringView>) {
+ d->dataBuffer = data.toUtf8();
+ d->decoder = QStringDecoder(QStringDecoder::Utf8);
+ d->lockEncoding = true;
+ } else if constexpr (std::is_same_v<decltype(data), QLatin1StringView>) {
+ // Conversion to a QString is required, to avoid breaking
+ // pre-existing (before porting to QAnyStringView) behavior.
+ d->dataBuffer = QString::fromLatin1(data).toUtf8();
+ d->decoder = QStringDecoder(QStringDecoder::Utf8);
+ d->lockEncoding = true;
+ } else {
+ d->dataBuffer = QByteArray(data.data(), data.size());
+ }
+ });
}
/*!
- Creates a new stream reader that reads from \a data.
+ \internal
- \sa addData(), clear(), setDevice()
- */
-QXmlStreamReader::QXmlStreamReader(const char *data)
+ Creates a new stream reader that reads from \a data.
+ Used by the weak constructor taking a QByteArray.
+*/
+QXmlStreamReader::QXmlStreamReader(const QByteArray &data, PrivateConstructorTag)
: d_ptr(new QXmlStreamReaderPrivate(this))
{
Q_D(QXmlStreamReader);
- d->dataBuffer = QByteArray(data);
+ d->dataBuffer = data;
}
/*!
@@ -491,47 +540,61 @@ QIODevice *QXmlStreamReader::device() const
return d->device;
}
-
/*!
- Adds more \a data for the reader to read. This function does
- nothing if the reader has a device().
+ \overload
- \sa readNext(), clear()
- */
-void QXmlStreamReader::addData(const QByteArray &data)
-{
- Q_D(QXmlStreamReader);
- if (d->device) {
- qWarning("QXmlStreamReader: addData() with device()");
- return;
- }
- d->dataBuffer += data;
-}
+ \fn void QXmlStreamReader::addData(const QByteArray &data)
+
+ Adds more \a data for the reader to read. This function does
+ nothing if the reader has a device().
+
+ \sa readNext(), clear()
+*/
/*!
- Adds more \a data for the reader to read. This function does
- nothing if the reader has a device().
+ Adds more \a data for the reader to read. This function does
+ nothing if the reader has a device().
- \sa readNext(), clear()
- */
-void QXmlStreamReader::addData(const QString &data)
+ \note In Qt versions prior to 6.5, this function was overloaded
+ for QString and \c {const char*}.
+
+ \sa readNext(), clear()
+*/
+void QXmlStreamReader::addData(QAnyStringView data)
{
Q_D(QXmlStreamReader);
- d->lockEncoding = true;
- if (!d->decoder.isValid())
- d->decoder = QStringDecoder(QStringDecoder::Utf8);
- addData(data.toUtf8());
+ data.visit([this, d](auto data) {
+ if constexpr (std::is_same_v<decltype(data), QStringView>) {
+ d->lockEncoding = true;
+ if (!d->decoder.isValid())
+ d->decoder = QStringDecoder(QStringDecoder::Utf8);
+ addDataImpl(data.toUtf8());
+ } else if constexpr (std::is_same_v<decltype(data), QLatin1StringView>) {
+ // Conversion to a QString is required, to avoid breaking
+ // pre-existing (before porting to QAnyStringView) behavior.
+ if (!d->decoder.isValid())
+ d->decoder = QStringDecoder(QStringDecoder::Utf8);
+ addDataImpl(QString::fromLatin1(data).toUtf8());
+ } else {
+ addDataImpl(QByteArray(data.data(), data.size()));
+ }
+ });
}
/*!
- Adds more \a data for the reader to read. This function does
- nothing if the reader has a device().
+ \internal
- \sa readNext(), clear()
- */
-void QXmlStreamReader::addData(const char *data)
+ Adds more \a data for the reader to read. This function does
+ nothing if the reader has a device().
+*/
+void QXmlStreamReader::addDataImpl(const QByteArray &data)
{
- addData(QByteArray(data));
+ Q_D(QXmlStreamReader);
+ if (d->device) {
+ qWarning("QXmlStreamReader: addData() with device()");
+ return;
+ }
+ d->dataBuffer += data;
}
/*!
@@ -618,6 +681,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext()
d->token = -1;
return readNext();
}
+ d->checkToken();
return d->type;
}
@@ -658,7 +722,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const
bool QXmlStreamReader::readNextStartElement()
{
while (readNext() != Invalid) {
- if (isEndElement())
+ if (isEndElement() || isEndDocument())
return false;
else if (isStartElement())
return true;
@@ -688,55 +752,24 @@ void QXmlStreamReader::skipCurrentElement()
}
}
-/*
- * Use the following Perl script to generate the error string index list:
-===== PERL SCRIPT ====
-print "static const char QXmlStreamReader_tokenTypeString_string[] =\n";
-$counter = 0;
-$i = 0;
-while (<STDIN>) {
- chomp;
- print " \"$_\\0\"\n";
- $sizes[$i++] = $counter;
- $counter += length 1 + $_;
-}
-print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n ";
-for ($j = 0; $j < $i; ++$j) {
- printf "$sizes[$j], ";
-}
-print "0\n};\n";
-===== PERL SCRIPT ====
-
- * The input data is as follows (copied from qxmlstream.h):
-NoToken
-Invalid
-StartDocument
-EndDocument
-StartElement
-EndElement
-Characters
-Comment
-DTD
-EntityReference
-ProcessingInstruction
-*/
-static const char QXmlStreamReader_tokenTypeString_string[] =
- "NoToken\0"
- "Invalid\0"
- "StartDocument\0"
- "EndDocument\0"
- "StartElement\0"
- "EndElement\0"
- "Characters\0"
- "Comment\0"
- "DTD\0"
- "EntityReference\0"
- "ProcessingInstruction\0";
-
-static const short QXmlStreamReader_tokenTypeString_indices[] = {
- 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0
-};
+static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
+ "NoToken",
+ "Invalid",
+ "StartDocument",
+ "EndDocument",
+ "StartElement",
+ "EndElement",
+ "Characters",
+ "Comment",
+ "DTD",
+ "EntityReference",
+ "ProcessingInstruction"
+);
+static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
+ "Prolog",
+ "Body"
+);
/*!
\property QXmlStreamReader::namespaceProcessing
@@ -769,11 +802,19 @@ bool QXmlStreamReader::namespaceProcessing() const
QString QXmlStreamReader::tokenString() const
{
Q_D(const QXmlStreamReader);
- return QLatin1String(QXmlStreamReader_tokenTypeString_string +
- QXmlStreamReader_tokenTypeString_indices[d->type]);
+ return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
}
-#endif // QT_NO_XMLSTREAMREADER
+/*!
+ \internal
+ \return \param ctxt (Prolog/Body) as a string.
+ */
+static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
+{
+ return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast<int>(ctxt)));
+}
+
+#endif // feature xmlstreamreader
QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
{
@@ -787,7 +828,7 @@ QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
tagsDone = false;
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
:q_ptr(q)
@@ -802,7 +843,7 @@ QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
init();
#define ADD_PREDEFINED(n, v) \
do { \
- Entity e = Entity::createLiteral(QLatin1String(n), QLatin1String(v)); \
+ Entity e = Entity::createLiteral(n##_L1, v##_L1); \
entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e)); \
} while (false)
ADD_PREDEFINED("lt", "<");
@@ -823,6 +864,7 @@ void QXmlStreamReaderPrivate::init()
isWhitespace = true;
isCDATA = false;
standalone = false;
+ hasStandalone = false;
tos = 0;
resumeReduction = 0;
state_stack[tos++] = 0;
@@ -859,6 +901,8 @@ void QXmlStreamReaderPrivate::init()
type = QXmlStreamReader::NoToken;
error = QXmlStreamReader::NoError;
+ currentContext = XmlContext::Prolog;
+ foundDTD = false;
}
/*
@@ -969,8 +1013,8 @@ inline uint QXmlStreamReaderPrivate::peekChar()
*/
bool QXmlStreamReaderPrivate::scanUntil(const char *str, short tokenToInject)
{
- int pos = textBuffer.size();
- int oldLineNumber = lineNumber;
+ const qsizetype pos = textBuffer.size();
+ const auto oldLineNumber = lineNumber;
uint c;
while ((c = getChar()) != StreamEOF) {
@@ -1017,7 +1061,7 @@ bool QXmlStreamReaderPrivate::scanUntil(const char *str, short tokenToInject)
bool QXmlStreamReaderPrivate::scanString(const char *str, short tokenToInject, bool requireSpace)
{
- int n = 0;
+ qsizetype n = 0;
while (str[n]) {
uint c = getChar();
if (c != ushort(str[n])) {
@@ -1030,12 +1074,11 @@ bool QXmlStreamReaderPrivate::scanString(const char *str, short tokenToInject, b
}
++n;
}
- for (int i = 0; i < n; ++i)
- textBuffer += QChar(ushort(str[i]));
+ textBuffer += QLatin1StringView(str, n);
if (requireSpace) {
- int s = fastScanSpace();
+ const qsizetype s = fastScanSpace();
if (!s || atEnd) {
- int pos = textBuffer.size() - n - s;
+ qsizetype pos = textBuffer.size() - n - s;
putString(textBuffer, pos);
textBuffer.resize(pos);
return false;
@@ -1145,9 +1188,9 @@ bool QXmlStreamReaderPrivate::scanAttType()
encountered.
*/
-inline int QXmlStreamReaderPrivate::fastScanLiteralContent()
+inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
{
- int n = 0;
+ qsizetype n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
switch (ushort(c)) {
@@ -1169,7 +1212,7 @@ inline int QXmlStreamReaderPrivate::fastScanLiteralContent()
case ' ':
case '\t':
if (normalizeLiterals)
- textBuffer += QLatin1Char(' ');
+ textBuffer += u' ';
else
textBuffer += QChar(c);
++n;
@@ -1195,9 +1238,9 @@ inline int QXmlStreamReaderPrivate::fastScanLiteralContent()
return n;
}
-inline int QXmlStreamReaderPrivate::fastScanSpace()
+inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
{
- int n = 0;
+ qsizetype n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
switch (c) {
@@ -1228,9 +1271,9 @@ inline int QXmlStreamReaderPrivate::fastScanSpace()
Used for text nodes essentially. That is, characters appearing
inside elements.
*/
-inline int QXmlStreamReaderPrivate::fastScanContentCharList()
+inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
{
- int n = 0;
+ qsizetype n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
switch (ushort(c)) {
@@ -1241,7 +1284,7 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList()
return n;
case ']': {
isWhitespace = false;
- int pos = textBuffer.size();
+ const qsizetype pos = textBuffer.size();
textBuffer += QChar(ushort(c));
++n;
while ((c = getChar()) == ']') {
@@ -1251,7 +1294,7 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList()
if (c == 0) {
putString(textBuffer, pos);
textBuffer.resize(pos);
- } else if (c == '>' && textBuffer.at(textBuffer.size()-2) == QLatin1Char(']')) {
+ } else if (c == '>' && textBuffer.at(textBuffer.size() - 2) == u']') {
raiseWellFormedError(QXmlStream::tr("Sequence ']]>' not allowed in content."));
} else {
putChar(c);
@@ -1292,15 +1335,17 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList()
return n;
}
-inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
+// Fast scan an XML attribute name (e.g. "xml:lang").
+inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
{
- int n = 0;
+ qsizetype n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
if (n >= 4096) {
// This is too long to be a sensible name, and
- // can exhaust memory
- return 0;
+ // can exhaust memory, or the range of decltype(*prefix)
+ raiseNamePrefixTooLongError();
+ return std::nullopt;
}
switch (c) {
case '\n':
@@ -1329,16 +1374,16 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
case '+':
case '*':
putChar(c);
- if (prefix && *prefix == n+1) {
- *prefix = 0;
+ if (val && val->prefix == n + 1) {
+ val->prefix = 0;
putChar(':');
--n;
}
return n;
case ':':
- if (prefix) {
- if (*prefix == 0) {
- *prefix = n+2;
+ if (val) {
+ if (val->prefix == 0) {
+ val->prefix = qint16(n + 2);
} else { // only one colon allowed according to the namespace spec.
putChar(c);
return n;
@@ -1354,9 +1399,9 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
}
}
- if (prefix)
- *prefix = 0;
- int pos = textBuffer.size() - n;
+ if (val)
+ val->prefix = 0;
+ qsizetype pos = textBuffer.size() - n;
putString(textBuffer, pos);
textBuffer.resize(pos);
return 0;
@@ -1413,9 +1458,9 @@ static inline NameChar fastDetermineNameChar(QChar ch)
return NotName;
}
-inline int QXmlStreamReaderPrivate::fastScanNMTOKEN()
+inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
{
- int n = 0;
+ qsizetype n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
if (fastDetermineNameChar(QChar(c)) == NotName) {
@@ -1427,7 +1472,7 @@ inline int QXmlStreamReaderPrivate::fastScanNMTOKEN()
}
}
- int pos = textBuffer.size() - n;
+ qsizetype pos = textBuffer.size() - n;
putString(textBuffer, pos);
textBuffer.resize(pos);
@@ -1479,7 +1524,7 @@ void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
uint QXmlStreamReaderPrivate::getChar_helper()
{
- const int BUFFER_SIZE = 8192;
+ constexpr qsizetype BUFFER_SIZE = 8192;
characterOffset += readBufferPos;
readBufferPos = 0;
if (readBuffer.size())
@@ -1571,25 +1616,25 @@ void QXmlStreamReaderPrivate::resolveTag()
++i;
if (i != n)
continue;
- if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName == QLatin1String("xmlns")) {
+ if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName == "xmlns"_L1) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
namespaceDeclaration.prefix.clear();
const XmlStringRef ns(dtdAttribute.defaultValue);
- if (ns == QLatin1String("http://www.w3.org/2000/xmlns/") ||
- ns == QLatin1String("http://www.w3.org/XML/1998/namespace"))
+ if (ns == "http://www.w3.org/2000/xmlns/"_L1 ||
+ ns == "http://www.w3.org/XML/1998/namespace"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
else
namespaceDeclaration.namespaceUri = ns;
- } else if (dtdAttribute.attributePrefix == QLatin1String("xmlns")) {
+ } else if (dtdAttribute.attributePrefix == "xmlns"_L1) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
XmlStringRef namespacePrefix = dtdAttribute.attributeName;
XmlStringRef namespaceUri = dtdAttribute.defaultValue;
- if (((namespacePrefix == QLatin1String("xml"))
- ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
- || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
+ if (((namespacePrefix == "xml"_L1)
+ ^ (namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1))
+ || namespaceUri == "http://www.w3.org/2000/xmlns/"_L1
|| namespaceUri.isEmpty()
- || namespacePrefix == QLatin1String("xmlns"))
+ || namespacePrefix == "xmlns"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
namespaceDeclaration.prefix = namespacePrefix;
@@ -1718,9 +1763,9 @@ void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
{
//#x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
- const ushort *data = reinterpret_cast<const ushort *>(publicId.constData());
+ const char16_t *data = publicId.utf16();
uchar c = 0;
- int i;
+ qsizetype i;
for (i = publicId.size() - 1; i >= 0; --i) {
if (data[i] < 256)
switch ((c = data[i])) {
@@ -1730,9 +1775,7 @@ void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
case '$': case '_': case '%': case '\'': case '\"':
continue;
default:
- if ((c >= 'a' && c <= 'z')
- || (c >= 'A' && c <= 'Z')
- || (c >= '0' && c <= '9'))
+ if (isAsciiLetterOrNumber(c))
continue;
}
break;
@@ -1764,8 +1807,8 @@ bool QXmlStreamReaderPrivate::checkStartDocument()
void QXmlStreamReaderPrivate::startDocument()
{
QString err;
- if (documentVersion != QLatin1String("1.0")) {
- if (documentVersion.view().contains(QLatin1Char(' ')))
+ if (documentVersion != "1.0"_L1) {
+ if (documentVersion.view().contains(u' '))
err = QXmlStream::tr("Invalid XML version string.");
else
err = QXmlStream::tr("Unsupported XML version.");
@@ -1776,7 +1819,6 @@ void QXmlStreamReaderPrivate::startDocument()
* proper order:
*
* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
- bool hasStandalone = false;
for (qsizetype i = 0; err.isNull() && i < n; ++i) {
Attribute &attrib = attributeStack[i];
@@ -1784,7 +1826,7 @@ void QXmlStreamReaderPrivate::startDocument()
XmlStringRef key(symString(attrib.key));
XmlStringRef value(symString(attrib.value));
- if (prefix.isEmpty() && key == QLatin1String("encoding")) {
+ if (prefix.isEmpty() && key == "encoding"_L1) {
documentEncoding = value;
if (hasStandalone)
@@ -1802,16 +1844,16 @@ void QXmlStreamReaderPrivate::startDocument()
}
}
}
- } else if (prefix.isEmpty() && key == QLatin1String("standalone")) {
+ } else if (prefix.isEmpty() && key == "standalone"_L1) {
hasStandalone = true;
- if (value == QLatin1String("yes"))
+ if (value == "yes"_L1)
standalone = true;
- else if (value == QLatin1String("no"))
+ else if (value == "no"_L1)
standalone = false;
else
err = QXmlStream::tr("Standalone accepts only yes or no.");
} else {
- err = QXmlStream::tr("Invalid attribute in XML declaration.");
+ err = QXmlStream::tr("Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
}
}
@@ -1840,6 +1882,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
raiseError(QXmlStreamReader::NotWellFormedError, message);
}
+void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
+{
+ // TODO: add a ImplementationLimitsExceededError and use it instead
+ raiseError(QXmlStreamReader::NotWellFormedError,
+ QXmlStream::tr("Length of XML attribute name exceeds implementation limits (4KiB "
+ "characters)."));
+}
+
void QXmlStreamReaderPrivate::parseError()
{
@@ -1852,7 +1902,7 @@ void QXmlStreamReaderPrivate::parseError()
int ers = state_stack[tos];
int nexpected = 0;
int expected[nmax];
- if (token != ERROR)
+ if (token != XML_ERROR)
for (int tk = 0; tk < TERMINAL_COUNT; ++tk) {
int k = t_action(ers, tk);
if (k <= 0)
@@ -1865,22 +1915,27 @@ void QXmlStreamReaderPrivate::parseError()
if (nexpected && nexpected < nmax) {
//: '<first option>'
- QString exp_str = QXmlStream::tr("'%1'", "expected").arg(QLatin1String(spell[expected[0]]));
+ QString exp_str = QXmlStream::tr("'%1'", "expected")
+ .arg(QLatin1StringView(spell[expected[0]]));
if (nexpected == 2) {
//: <first option>, '<second option>'
- exp_str = QXmlStream::tr("%1 or '%2'", "expected").arg(exp_str, QLatin1String(spell[expected[1]]));
+ exp_str = QXmlStream::tr("%1 or '%2'", "expected")
+ .arg(exp_str, QLatin1StringView(spell[expected[1]]));
} else if (nexpected > 2) {
int s = 1;
for (; s < nexpected - 1; ++s) {
//: <options so far>, '<next option>'
- exp_str = QXmlStream::tr("%1, '%2'", "expected").arg(exp_str, QLatin1String(spell[expected[s]]));
+ exp_str = QXmlStream::tr("%1, '%2'", "expected")
+ .arg(exp_str, QLatin1StringView(spell[expected[s]]));
}
//: <options so far>, or '<final option>'
- exp_str = QXmlStream::tr("%1, or '%2'", "expected").arg(exp_str, QLatin1String(spell[expected[s]]));
+ exp_str = QXmlStream::tr("%1, or '%2'", "expected")
+ .arg(exp_str, QLatin1StringView(spell[expected[s]]));
}
- error_message = QXmlStream::tr("Expected %1, but got '%2'.").arg(exp_str, QLatin1String(spell[token]));
+ error_message = QXmlStream::tr("Expected %1, but got '%2'.")
+ .arg(exp_str, QLatin1StringView(spell[token]));
} else {
- error_message = QXmlStream::tr("Unexpected '%1'.").arg(QLatin1String(spell[token]));
+ error_message = QXmlStream::tr("Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
}
raiseWellFormedError(error_message);
@@ -2266,7 +2321,7 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const
return d->attributes;
}
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
/*!
\class QXmlStreamAttribute
@@ -2277,6 +2332,8 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const
\ingroup xml-tools
+ \compares equality
+
An attribute consists of an optionally empty namespaceUri(), a
name(), a value(), and an isDefault() attribute.
@@ -2307,7 +2364,7 @@ QXmlStreamAttribute::QXmlStreamAttribute(const QString &namespaceUri, const QStr
*/
QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QString &value)
{
- int colon = qualifiedName.indexOf(QLatin1Char(':'));
+ qsizetype colon = qualifiedName.indexOf(u':');
m_name = qualifiedName.mid(colon + 1);
m_qualifiedName = qualifiedName;
m_value = value;
@@ -2351,14 +2408,14 @@ QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QSt
value following an ATTLIST declaration in the DTD; otherwise
returns \c false.
*/
-/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &other) const
+/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &lhs, const QXmlStreamAttribute &rhs)
- Compares this attribute with \a other and returns \c true if they are
+ Compares \a lhs attribute with \a rhs and returns \c true if they are
equal; otherwise returns \c false.
*/
-/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &other) const
+/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &lhs, const QXmlStreamAttribute &rhs)
- Compares this attribute with \a other and returns \c true if they are
+ Compares \a lhs attribute with \a rhs and returns \c true if they are
not equal; otherwise returns \c false.
*/
@@ -2407,6 +2464,8 @@ QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QSt
\ingroup xml-tools
+ \compares equality
+
An notation declaration consists of a name(), a systemId(), and a publicId().
*/
@@ -2430,14 +2489,14 @@ Returns the system identifier.
Returns the public identifier.
*/
-/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &other) const
+/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &lhs, const QXmlStreamNotationDeclaration &rhs)
- Compares this notation declaration with \a other and returns \c true
+ Compares \a lhs notation declaration with \a rhs and returns \c true
if they are equal; otherwise returns \c false.
*/
-/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &other) const
+/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &lhs, const QXmlStreamNotationDeclaration &rhs)
- Compares this notation declaration with \a other and returns \c true
+ Compares \a lhs notation declaration with \a rhs and returns \c true
if they are not equal; otherwise returns \c false.
*/
@@ -2457,16 +2516,18 @@ Returns the public identifier.
\ingroup xml-tools
+ \compares equality
+
An namespace declaration consists of a prefix() and a namespaceUri().
*/
-/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &other) const
+/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &lhs, const QXmlStreamNamespaceDeclaration &rhs)
- Compares this namespace declaration with \a other and returns \c true
+ Compares \a lhs namespace declaration with \a rhs and returns \c true
if they are equal; otherwise returns \c false.
*/
-/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &other) const
+/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &lhs, const QXmlStreamNamespaceDeclaration &rhs)
- Compares this namespace declaration with \a other and returns \c true
+ Compares \a lhs namespace declaration with \a rhs and returns \c true
if they are not equal; otherwise returns \c false.
*/
@@ -2523,6 +2584,7 @@ Returns the namespaceUri.
\ingroup xml-tools
+ \compares equality
An entity declaration consists of a name(), a notationName(), a
systemId(), a publicId(), and a value().
*/
@@ -2555,50 +2617,25 @@ Returns the public identifier.
Returns the entity's value.
*/
-/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &other) const
+/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &lhs, const QXmlStreamEntityDeclaration &rhs)
- Compares this entity declaration with \a other and returns \c true if
+ Compares \a lhs entity declaration with \a rhs and returns \c true if
they are equal; otherwise returns \c false.
*/
-/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &other) const
+/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &lhs, const QXmlStreamEntityDeclaration &rhs)
- Compares this entity declaration with \a other and returns \c true if
+ Compares \a lhs entity declaration with \a rhs and returns \c true if
they are not equal; otherwise returns \c false.
*/
/*! Returns the value of the attribute \a name in the namespace
described with \a namespaceUri, or an empty string reference if the
attribute is not defined. The \a namespaceUri can be empty.
- */
-QStringView QXmlStreamAttributes::value(const QString &namespaceUri, const QString &name) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
- return attribute.value();
- }
- return QStringView();
-}
-
-/*!\overload
- Returns the value of the attribute \a name in the namespace
- described with \a namespaceUri, or an empty string reference if the
- attribute is not defined. The \a namespaceUri can be empty.
- */
-QStringView QXmlStreamAttributes::value(const QString &namespaceUri, QLatin1String name) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
- return attribute.value();
- }
- return QStringView();
-}
-/*!\overload
- Returns the value of the attribute \a name in the namespace
- described with \a namespaceUri, or an empty string reference if the
- attribute is not defined. The \a namespaceUri can be empty.
+ \note In Qt versions prior to 6.6, this function was implemented as an
+ overload set accepting combinations of QString and QLatin1StringView only.
*/
-QStringView QXmlStreamAttributes::value(QLatin1String namespaceUri, QLatin1String name) const
+QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name) const noexcept
{
for (const QXmlStreamAttribute &attribute : *this) {
if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
@@ -2618,29 +2655,12 @@ QStringView QXmlStreamAttributes::value(QLatin1String namespaceUri, QLatin1Strin
different prefixes can point to the same namespace), you shouldn't
use qualified names, but a resolved namespaceUri and the attribute's
local name.
- */
-QStringView QXmlStreamAttributes::value(const QString &qualifiedName) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.qualifiedName() == qualifiedName)
- return attribute.value();
- }
- return QStringView();
-}
-/*!\overload
+ \note In Qt versions prior to 6.6, this function was implemented as an
+ overload set accepting QString and QLatin1StringView only.
- Returns the value of the attribute with qualified name \a
- qualifiedName , or an empty string reference if the attribute is not
- defined. A qualified name is the raw name of an attribute in the XML
- data. It consists of the namespace prefix, followed by colon,
- followed by the attribute's local name. Since the namespace prefix
- is not unique (the same prefix can point to different namespaces and
- different prefixes can point to the same namespace), you shouldn't
- use qualified names, but a resolved namespaceUri and the attribute's
- local name.
*/
-QStringView QXmlStreamAttributes::value(QLatin1String qualifiedName) const
+QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName) const noexcept
{
for (const QXmlStreamAttribute &attribute : *this) {
if (attribute.qualifiedName() == qualifiedName)
@@ -2667,7 +2687,7 @@ void QXmlStreamAttributes::append(const QString &qualifiedName, const QString &v
append(QXmlStreamAttribute(qualifiedName, value));
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
/*! \fn bool QXmlStreamReader::isStartDocument() const
Returns \c true if tokenType() equals \l StartDocument; otherwise returns \c false.
@@ -2728,6 +2748,8 @@ bool QXmlStreamReader::isCDATA() const
XML declaration; otherwise returns \c false.
If no XML declaration has been parsed, this function returns \c false.
+
+ \sa hasStandaloneDeclaration()
*/
bool QXmlStreamReader::isStandaloneDocument() const
{
@@ -2735,6 +2757,21 @@ bool QXmlStreamReader::isStandaloneDocument() const
return d->standalone;
}
+/*!
+ \since 6.6
+
+ Returns \c true if this document has an explicit standalone
+ declaration (can be 'yes' or 'no'); otherwise returns \c false;
+
+ If no XML declaration has been parsed, this function returns \c false.
+
+ \sa isStandaloneDocument()
+ */
+bool QXmlStreamReader::hasStandaloneDeclaration() const
+{
+ Q_D(const QXmlStreamReader);
+ return d->hasStandalone;
+}
/*!
\since 4.4
@@ -2766,7 +2803,7 @@ QStringView QXmlStreamReader::documentEncoding() const
return QStringView();
}
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
/*!
\class QXmlStreamWriter
@@ -2778,6 +2815,7 @@ QStringView QXmlStreamReader::documentEncoding() const
simple streaming API.
\ingroup xml-tools
+ \ingroup qtserialization
QXmlStreamWriter is the counterpart to QXmlStreamReader for writing
XML. Like its related class, it operates on a QIODevice specified
@@ -2842,25 +2880,29 @@ QStringView QXmlStreamReader::documentEncoding() const
*/
-#ifndef QT_NO_XMLSTREAMWRITER
+#if QT_CONFIG(xmlstreamwriter)
-class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack {
+class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack
+{
QXmlStreamWriter *q_ptr;
Q_DECLARE_PUBLIC(QXmlStreamWriter)
public:
+ enum class StartElementOption {
+ KeepEverything = 0, // write out every attribute, namespace, &c.
+ OmitNamespaceDeclarations = 1,
+ };
+
QXmlStreamWriterPrivate(QXmlStreamWriter *q);
~QXmlStreamWriterPrivate() {
if (deleteDevice)
delete device;
}
- void write(const XmlStringRef &);
- void write(const QString &);
- void writeEscaped(const QString &, bool escapeWhitespace = false);
- void write(const char *s, int len);
- template <int N> void write(const char (&s)[N]) { write(s, N - 1); }
+ void write(QAnyStringView s);
+ void writeEscaped(QAnyStringView, bool escapeWhitespace = false);
bool finishStartElement(bool contents = true);
- void writeStartElement(const QString &namespaceUri, const QString &name);
+ void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
+ StartElementOption option = StartElementOption::KeepEverything);
QIODevice *device;
QString *stringDevice;
uint deleteDevice :1;
@@ -2871,23 +2913,26 @@ public:
uint hasIoError :1;
uint hasEncodingError :1;
uint autoFormatting :1;
- QByteArray autoFormattingIndent;
+ std::string autoFormattingIndent;
NamespaceDeclaration emptyNamespace;
qsizetype lastNamespaceDeclaration;
- QStringEncoder toUtf8;
- NamespaceDeclaration &findNamespace(const QString &namespaceUri, bool writeDeclaration = false, bool noDefault = false);
+ NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
+ NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri, bool writeDeclaration = false, bool noDefault = false);
void writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration);
int namespacePrefixCount;
void indent(int level);
+private:
+ void doWriteToDevice(QStringView s);
+ void doWriteToDevice(QUtf8StringView s);
+ void doWriteToDevice(QLatin1StringView s);
};
QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
- : autoFormattingIndent(4, ' '),
- toUtf8(QStringEncoder::Utf8, QStringEncoder::Flag::Stateless)
+ : autoFormattingIndent(4, ' ')
{
q_ptr = q;
device = nullptr;
@@ -2903,108 +2948,109 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
namespacePrefixCount = 0;
}
-void QXmlStreamWriterPrivate::write(const XmlStringRef &s)
+void QXmlStreamWriterPrivate::write(QAnyStringView s)
{
if (device) {
if (hasIoError)
return;
- QByteArray bytes = toUtf8(s);
- if (toUtf8.hasError()) {
- hasEncodingError = true;
- return;
- }
- if (device->write(bytes) != bytes.size())
- hasIoError = true;
- }
- else if (stringDevice)
- stringDevice->append(s);
- else
+
+ s.visit([&] (auto s) { doWriteToDevice(s); });
+ } else if (stringDevice) {
+ s.visit([&] (auto s) { stringDevice->append(s); });
+ } else {
qWarning("QXmlStreamWriter: No device");
+ }
}
-void QXmlStreamWriterPrivate::write(const QString &s)
+void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s, bool escapeWhitespace)
{
- if (device) {
- if (hasIoError)
- return;
- QByteArray bytes = toUtf8(s);
- if (toUtf8.hasError()) {
- hasEncodingError = true;
- return;
+ struct NextLatin1 {
+ char32_t operator()(const char *&it, const char *) const
+ { return uchar(*it++); }
+ };
+ struct NextUtf8 {
+ char32_t operator()(const char *&it, const char *end) const
+ {
+ uchar uc = *it++;
+ char32_t utf32 = 0;
+ char32_t *output = &utf32;
+ qsizetype n = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(uc, output, it, end);
+ return n < 0 ? 0 : utf32;
}
- if (device->write(bytes) != bytes.size())
- hasIoError = true;
- }
- else if (stringDevice)
- stringDevice->append(s);
- else
- qWarning("QXmlStreamWriter: No device");
-}
+ };
+ struct NextUtf16 {
+ char32_t operator()(const QChar *&it, const QChar *end) const
+ {
+ QStringIterator decoder(it, end);
+ char32_t result = decoder.next(u'\0');
+ it = decoder.position();
+ return result;
+ }
+ };
-void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespace)
-{
QString escaped;
escaped.reserve(s.size());
- for ( int i = 0; i < s.size(); ++i ) {
- QChar c = s.at(i);
- switch (c.unicode()) {
- case '<':
- escaped.append(QLatin1String("&lt;"));
- break;
- case '>':
- escaped.append(QLatin1String("&gt;"));
- break;
- case '&':
- escaped.append(QLatin1String("&amp;"));
- break;
- case '\"':
- escaped.append(QLatin1String("&quot;"));
- break;
- case '\t':
- if (escapeWhitespace)
- escaped.append(QLatin1String("&#9;"));
- else
- escaped += c;
- break;
- case '\n':
- if (escapeWhitespace)
- escaped.append(QLatin1String("&#10;"));
- else
- escaped += c;
- break;
- case '\v':
- case '\f':
- hasEncodingError = true;
- break;
- case '\r':
- if (escapeWhitespace)
- escaped.append(QLatin1String("&#13;"));
- else
- escaped += c;
- break;
- default:
- if (c.unicode() > 0x1f && c.unicode() < 0xfffe)
- escaped += c;
- else
- hasEncodingError = true;
- break;
- }
- }
- write(escaped);
-}
+ s.visit([&] (auto s) {
+ using View = decltype(s);
+ using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
+ std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
+
+ auto it = s.begin();
+ const auto end = s.end();
+ Decoder decoder;
+
+ while (it != end) {
+ QLatin1StringView replacement;
+ auto mark = it;
+
+ while (it != end) {
+ auto next_it = it;
+ char32_t uc = decoder(next_it, end);
+ if (uc == u'<') {
+ replacement = "&lt;"_L1;
+ break;
+ } else if (uc == u'>') {
+ replacement = "&gt;"_L1;
+ break;
+ } else if (uc == u'&') {
+ replacement = "&amp;"_L1;
+ break;
+ } else if (uc == u'\"') {
+ replacement = "&quot;"_L1;
+ break;
+ } else if (uc == u'\t') {
+ if (escapeWhitespace) {
+ replacement = "&#9;"_L1;
+ break;
+ }
+ } else if (uc == u'\n') {
+ if (escapeWhitespace) {
+ replacement = "&#10;"_L1;
+ break;
+ }
+ } else if (uc == u'\v' || uc == u'\f') {
+ hasEncodingError = true;
+ break;
+ } else if (uc == u'\r') {
+ if (escapeWhitespace) {
+ replacement = "&#13;"_L1;
+ break;
+ }
+ } else if (uc <= u'\x1F' || uc == u'\uFFFE' || uc == u'\uFFFF') {
+ hasEncodingError = true;
+ break;
+ }
+ it = next_it;
+ }
-// Writes utf8
-void QXmlStreamWriterPrivate::write(const char *s, int len)
-{
- if (device) {
- if (hasIoError)
- return;
- if (device->write(s, len) != len)
- hasIoError = true;
- return;
- }
+ escaped.append(View{mark, it});
+ escaped.append(replacement);
+ if (it != end)
+ ++it;
+ }
+ } );
- write(QString::fromUtf8(s, len));
+ write(escaped);
}
void QXmlStreamWriterPrivate::writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration) {
@@ -3041,7 +3087,33 @@ bool QXmlStreamWriterPrivate::finishStartElement(bool contents)
return hadSomethingWritten;
}
-QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(const QString &namespaceUri, bool writeDeclaration, bool noDefault)
+QXmlStreamPrivateTagStack::NamespaceDeclaration &
+QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
+{
+ const bool prefixIsXml = prefix == "xml"_L1;
+ const bool namespaceUriIsXml = namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1;
+ if (prefixIsXml && !namespaceUriIsXml) {
+ qWarning("Reserved prefix 'xml' must not be bound to a different namespace name "
+ "than 'http://www.w3.org/XML/1998/namespace'");
+ } else if (!prefixIsXml && namespaceUriIsXml) {
+ const QString prefixString = prefix.toString();
+ qWarning("The prefix '%ls' must not be bound to namespace name "
+ "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
+ qUtf16Printable(prefixString));
+ }
+ if (namespaceUri == "http://www.w3.org/2000/xmlns/"_L1) {
+ const QString prefixString = prefix.toString();
+ qWarning("The prefix '%ls' must not be bound to namespace name "
+ "'http://www.w3.org/2000/xmlns/'",
+ qUtf16Printable(prefixString));
+ }
+ auto &namespaceDeclaration = namespaceDeclarations.push();
+ namespaceDeclaration.prefix = addToStringStorage(prefix);
+ namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
+ return namespaceDeclaration;
+}
+
+QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri, bool writeDeclaration, bool noDefault)
{
for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
if (namespaceDeclaration.namespaceUri == namespaceUri) {
@@ -3058,7 +3130,7 @@ QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNa
QString s;
int n = ++namespacePrefixCount;
forever {
- s = QLatin1Char('n') + QString::number(n++);
+ s = u'n' + QString::number(n++);
qsizetype j = namespaceDeclarations.size() - 2;
while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
--j;
@@ -3078,10 +3150,43 @@ QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNa
void QXmlStreamWriterPrivate::indent(int level)
{
write("\n");
- for (int i = level; i > 0; --i)
- write(autoFormattingIndent.constData(), autoFormattingIndent.length());
+ for (int i = 0; i < level; ++i)
+ write(autoFormattingIndent);
+}
+
+void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
+{
+ constexpr qsizetype MaxChunkSize = 512;
+ char buffer [3 * MaxChunkSize];
+ QStringEncoder::State state;
+ while (!s.isEmpty()) {
+ const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
+ char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
+ doWriteToDevice(QUtf8StringView{buffer, end});
+ s = s.sliced(chunkSize);
+ }
+ if (state.remainingChars > 0)
+ hasEncodingError = true;
}
+void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
+{
+ QByteArrayView bytes = s;
+ if (device->write(bytes.data(), bytes.size()) != bytes.size())
+ hasIoError = true;
+}
+
+void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
+{
+ constexpr qsizetype MaxChunkSize = 512;
+ char buffer [2 * MaxChunkSize];
+ while (!s.isEmpty()) {
+ const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
+ char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
+ doWriteToDevice(QUtf8StringView{buffer, end});
+ s = s.sliced(chunkSize);
+ }
+}
/*!
Constructs a stream writer.
@@ -3224,13 +3329,14 @@ bool QXmlStreamWriter::autoFormatting() const
void QXmlStreamWriter::setAutoFormattingIndent(int spacesOrTabs)
{
Q_D(QXmlStreamWriter);
- d->autoFormattingIndent = QByteArray(qAbs(spacesOrTabs), spacesOrTabs >= 0 ? ' ' : '\t');
+ d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ? ' ' : '\t');
}
int QXmlStreamWriter::autoFormattingIndent() const
{
Q_D(const QXmlStreamWriter);
- return d->autoFormattingIndent.count(' ') - d->autoFormattingIndent.count('\t');
+ const QLatin1StringView indent(d->autoFormattingIndent);
+ return indent.count(u' ') - indent.count(u'\t');
}
/*!
@@ -3255,12 +3361,15 @@ bool QXmlStreamWriter::hasError() const
This function can only be called after writeStartElement() before
any content is written, or after writeEmptyElement().
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value)
+void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
{
Q_D(QXmlStreamWriter);
Q_ASSERT(d->inStartElement);
- Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
d->write(" ");
d->write(qualifiedName);
d->write("=\"");
@@ -3275,12 +3384,15 @@ void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QStrin
This function can only be called after writeStartElement() before
any content is written, or after writeEmptyElement().
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value)
+void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
{
Q_D(QXmlStreamWriter);
Q_ASSERT(d->inStartElement);
- Q_ASSERT(!name.contains(QLatin1Char(':')));
+ Q_ASSERT(!contains(name, ':'));
QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri, true, true);
d->write(" ");
if (!namespaceDeclaration.prefix.isEmpty()) {
@@ -3304,12 +3416,9 @@ void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString
void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute& attribute)
{
if (attribute.namespaceUri().isEmpty())
- writeAttribute(attribute.qualifiedName().toString(),
- attribute.value().toString());
+ writeAttribute(attribute.qualifiedName(), attribute.value());
else
- writeAttribute(attribute.namespaceUri().toString(),
- attribute.name().toString(),
- attribute.value().toString());
+ writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
}
@@ -3339,15 +3448,26 @@ void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes& attributes)
This function mainly exists for completeness. Normally you should
not need use it, because writeCharacters() automatically escapes all
non-content characters.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeCDATA(const QString &text)
+void QXmlStreamWriter::writeCDATA(QAnyStringView text)
{
Q_D(QXmlStreamWriter);
d->finishStartElement();
- QString copy(text);
- copy.replace(QLatin1String("]]>"), QLatin1String("]]]]><![CDATA[>"));
d->write("<![CDATA[");
- d->write(copy);
+ while (!text.isEmpty()) {
+ const auto idx = indexOf(text, "]]>"_L1);
+ if (idx < 0)
+ break; // no forbidden sequence found
+ d->write(text.first(idx));
+ d->write("]]" // text[idx, idx + 2)
+ "]]><![CDATA[" // escape sequence to separate ]] and >
+ ">"); // text[idx + 2, idx + 3)
+ text = text.sliced(idx + 3); // skip over "]]>"
+ }
+ d->write(text); // write remainder
d->write("]]>");
}
@@ -3357,8 +3477,11 @@ void QXmlStreamWriter::writeCDATA(const QString &text)
"]]>", ">" is also escaped as "&gt;".
\sa writeEntityReference()
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeCharacters(const QString &text)
+void QXmlStreamWriter::writeCharacters(QAnyStringView text)
{
Q_D(QXmlStreamWriter);
d->finishStartElement();
@@ -3367,13 +3490,16 @@ void QXmlStreamWriter::writeCharacters(const QString &text)
/*! Writes \a text as XML comment, where \a text must not contain the
- forbidden sequence "--" or end with "-". Note that XML does not
- provide any way to escape "-" in a comment.
+ forbidden sequence \c{--} or end with \c{-}. Note that XML does not
+ provide any way to escape \c{-} in a comment.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeComment(const QString &text)
+void QXmlStreamWriter::writeComment(QAnyStringView text)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!text.contains(QLatin1String("--")) && !text.endsWith(QLatin1Char('-')));
+ Q_ASSERT(!contains(text, "--"_L1) && !endsWith(text, '-'));
if (!d->finishStartElement(false) && d->autoFormatting)
d->indent(d->tagStack.size());
d->write("<!--");
@@ -3385,8 +3511,11 @@ void QXmlStreamWriter::writeComment(const QString &text)
/*! Writes a DTD section. The \a dtd represents the entire
doctypedecl production from the XML 1.0 specification.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeDTD(const QString &dtd)
+void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
{
Q_D(QXmlStreamWriter);
d->finishStartElement();
@@ -3402,12 +3531,15 @@ void QXmlStreamWriter::writeDTD(const QString &dtd)
/*! \overload
Writes an empty element with qualified name \a qualifiedName.
Subsequent calls to writeAttribute() will add attributes to this element.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName)
+void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
- d->writeStartElement(QString(), qualifiedName);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
+ d->writeStartElement({}, qualifiedName);
d->inEmptyElement = true;
}
@@ -3418,11 +3550,14 @@ void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName)
Subsequent calls to writeAttribute() will add attributes to this element.
\sa writeNamespace()
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeEmptyElement(const QString &namespaceUri, const QString &name)
+void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!name.contains(QLatin1Char(':')));
+ Q_ASSERT(!contains(name, ':'));
d->writeStartElement(namespaceUri, name);
d->inEmptyElement = true;
}
@@ -3435,8 +3570,10 @@ void QXmlStreamWriter::writeEmptyElement(const QString &namespaceUri, const QStr
This is a convenience function equivalent to:
\snippet code/src_corelib_xml_qxmlstream.cpp 1
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text)
+void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
{
writeStartElement(qualifiedName);
writeCharacters(text);
@@ -3452,8 +3589,10 @@ void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QStr
This is a convenience function equivalent to:
\snippet code/src_corelib_xml_qxmlstream.cpp 2
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text)
+void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
{
writeStartElement(namespaceUri, name);
writeCharacters(text);
@@ -3514,8 +3653,11 @@ void QXmlStreamWriter::writeEndElement()
/*!
Writes the entity reference \a name to the stream, as "&\a{name};".
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeEntityReference(const QString &name)
+void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
{
Q_D(QXmlStreamWriter);
d->finishStartElement();
@@ -3539,19 +3681,17 @@ void QXmlStreamWriter::writeEntityReference(const QString &name)
\e http://www.w3.org/2000/xmlns/ are used for the namespace mechanism
itself and thus completely forbidden in declarations.
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeNamespace(const QString &namespaceUri, const QString &prefix)
+void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(prefix != QLatin1String("xmlns"));
+ Q_ASSERT(prefix != "xmlns"_L1);
if (prefix.isEmpty()) {
d->findNamespace(namespaceUri, d->inStartElement);
} else {
- Q_ASSERT(!((prefix == QLatin1String("xml")) ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))));
- Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/"));
- QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
- namespaceDeclaration.prefix = d->addToStringStorage(prefix);
- namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
+ auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
if (d->inStartElement)
d->writeNamespaceDeclaration(namespaceDeclaration);
}
@@ -3567,12 +3707,15 @@ void QXmlStreamWriter::writeNamespace(const QString &namespaceUri, const QString
Note that the namespaces \e http://www.w3.org/XML/1998/namespace
(bound to \e xmlns) and \e http://www.w3.org/2000/xmlns/ (bound to
\e xml) by definition cannot be declared as default.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeDefaultNamespace(const QString &namespaceUri)
+void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/XML/1998/namespace"));
- Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/"));
+ Q_ASSERT(namespaceUri != "http://www.w3.org/XML/1998/namespace"_L1);
+ Q_ASSERT(namespaceUri != "http://www.w3.org/2000/xmlns/"_L1);
QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
namespaceDeclaration.prefix.clear();
namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
@@ -3584,11 +3727,14 @@ void QXmlStreamWriter::writeDefaultNamespace(const QString &namespaceUri)
/*!
Writes an XML processing instruction with \a target and \a data,
where \a data must not contain the sequence "?>".
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const QString &data)
+void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!data.contains(QLatin1String("?>")));
+ Q_ASSERT(!contains(data, "?>"_L1));
if (!d->finishStartElement(false) && d->autoFormatting)
d->indent(d->tagStack.size());
d->write("<?");
@@ -3611,7 +3757,7 @@ void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const Q
*/
void QXmlStreamWriter::writeStartDocument()
{
- writeStartDocument(QLatin1String("1.0"));
+ writeStartDocument("1.0"_L1);
}
@@ -3619,8 +3765,11 @@ void QXmlStreamWriter::writeStartDocument()
Writes a document start with the XML version number \a version.
\sa writeEndDocument()
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeStartDocument(const QString &version)
+void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
{
Q_D(QXmlStreamWriter);
d->finishStartElement(false);
@@ -3636,8 +3785,11 @@ void QXmlStreamWriter::writeStartDocument(const QString &version)
\sa writeEndDocument()
\since 4.5
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)
+void QXmlStreamWriter::writeStartDocument(QAnyStringView version, bool standalone)
{
Q_D(QXmlStreamWriter);
d->finishStartElement(false);
@@ -3658,12 +3810,15 @@ void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalon
writeAttribute() will add attributes to this element.
\sa writeEndElement(), writeEmptyElement()
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
+void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
- d->writeStartElement(QString(), qualifiedName);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
+ d->writeStartElement({}, qualifiedName);
}
@@ -3674,15 +3829,19 @@ void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
element.
\sa writeNamespace(), writeEndElement(), writeEmptyElement()
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name)
+void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!name.contains(QLatin1Char(':')));
+ Q_ASSERT(!contains(name, ':'));
d->writeStartElement(namespaceUri, name);
}
-void QXmlStreamWriterPrivate::writeStartElement(const QString &namespaceUri, const QString &name)
+void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
+ StartElementOption option)
{
if (!finishStartElement(false) && autoFormatting)
indent(tagStack.size());
@@ -3698,12 +3857,14 @@ void QXmlStreamWriterPrivate::writeStartElement(const QString &namespaceUri, con
write(tag.name);
inStartElement = lastWasStartElement = true;
- for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
- writeNamespaceDeclaration(namespaceDeclarations[i]);
+ if (option != StartElementOption::OmitNamespaceDeclarations) {
+ for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
+ writeNamespaceDeclaration(namespaceDeclarations[i]);
+ }
tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
/*! Writes the current state of the \a reader. All possible valid
states are supported.
@@ -3713,6 +3874,7 @@ void QXmlStreamWriterPrivate::writeStartElement(const QString &namespaceUri, con
*/
void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
{
+ Q_D(QXmlStreamWriter);
switch (reader.tokenType()) {
case QXmlStreamReader::NoToken:
break;
@@ -3723,13 +3885,19 @@ 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());
+ // Namespaces must be added before writeStartElement is called so new prefixes are found
+ QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
+ for (const auto &namespaceDeclaration : reader.namespaceDeclarations()) {
+ auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
+ namespaceDeclaration.prefix());
+ extraNamespaces.append(extraNamespace);
}
+ d->writeStartElement(
+ reader.namespaceUri(), reader.name(),
+ QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
+ // Namespace declarations are written afterwards
+ for (const auto &extraNamespace : std::as_const(extraNamespaces))
+ d->writeNamespaceDeclaration(extraNamespace);
writeAttributes(reader.attributes());
} break;
case QXmlStreamReader::EndElement:
@@ -3737,22 +3905,22 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
break;
case QXmlStreamReader::Characters:
if (reader.isCDATA())
- writeCDATA(reader.text().toString());
+ writeCDATA(reader.text());
else
- writeCharacters(reader.text().toString());
+ writeCharacters(reader.text());
break;
case QXmlStreamReader::Comment:
- writeComment(reader.text().toString());
+ writeComment(reader.text());
break;
case QXmlStreamReader::DTD:
- writeDTD(reader.text().toString());
+ writeDTD(reader.text());
break;
case QXmlStreamReader::EntityReference:
- writeEntityReference(reader.name().toString());
+ writeEntityReference(reader.name());
break;
case QXmlStreamReader::ProcessingInstruction:
- writeProcessingInstruction(reader.processingInstructionTarget().toString(),
- reader.processingInstructionData().toString());
+ writeProcessingInstruction(reader.processingInstructionTarget(),
+ reader.processingInstructionData());
break;
default:
Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
@@ -3761,9 +3929,99 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
}
}
+static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
+ QXmlStreamReaderPrivate::XmlContext ctxt)
+{
+ switch (type) {
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::DTD:
+ return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
+
+ case QXmlStreamReader::StartElement:
+ case QXmlStreamReader::EndElement:
+ case QXmlStreamReader::Characters:
+ case QXmlStreamReader::EntityReference:
+ case QXmlStreamReader::EndDocument:
+ return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
+
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::ProcessingInstruction:
+ return true;
+
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ return false;
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+#else
+ return false;
+#endif
+}
+
+/*!
+ \internal
+ \brief QXmlStreamReader::isValidToken
+ \return \c true if \param type is a valid token type.
+ \return \c false if \param type is an unexpected token,
+ which indicates a non-well-formed or invalid XML stream.
+ */
+bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
+{
+ // Don't change currentContext, if Invalid or NoToken occur in the prolog
+ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
+ return false;
+
+ // If a token type gets rejected in the body, there is no recovery
+ const bool result = isTokenAllowedInContext(type, currentContext);
+ if (result || currentContext == XmlContext::Body)
+ return result;
+
+ // First non-Prolog token observed => switch context to body and check again.
+ currentContext = XmlContext::Body;
+ return isTokenAllowedInContext(type, currentContext);
+}
+
/*!
- \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
- \since 4.5
+ \internal
+ Checks token type and raises an error, if it is invalid
+ in the current context (prolog/body).
+ */
+void QXmlStreamReaderPrivate::checkToken()
+{
+ Q_Q(QXmlStreamReader);
+
+ // The token type must be consumed, to keep track if the body has been reached.
+ const XmlContext context = currentContext;
+ const bool ok = isValidToken(type);
+
+ // Do nothing if an error has been raised already (going along with an unexpected token)
+ if (error != QXmlStreamReader::Error::NoError)
+ return;
+
+ if (!ok) {
+ raiseError(QXmlStreamReader::UnexpectedElementError,
+ QXmlStream::tr("Unexpected token type %1 in %2.")
+ .arg(q->tokenString(), contextString(context)));
+ return;
+ }
+
+ if (type != QXmlStreamReader::DTD)
+ return;
+
+ // Raise error on multiple DTD tokens
+ if (foundDTD) {
+ raiseError(QXmlStreamReader::UnexpectedElementError,
+ QXmlStream::tr("Found second DTD token in %1.").arg(contextString(context)));
+ } else {
+ foundDTD = true;
+ }
+}
+
+/*!
+ \fn bool QXmlStreamAttributes::hasAttribute(QAnyStringView qualifiedName) const
Returns \c true if this QXmlStreamAttributes has an attribute whose
qualified name is \a qualifiedName; otherwise returns \c false.
@@ -3777,25 +4035,18 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
*/
/*!
- \fn bool QXmlStreamAttributes::hasAttribute(QLatin1String qualifiedName) const
- \overload
- \since 4.5
-*/
-
-/*!
- \fn bool QXmlStreamAttributes::hasAttribute(const QString &namespaceUri,
- const QString &name) const
+ \fn bool QXmlStreamAttributes::hasAttribute(QAnyStringView namespaceUri,
+ QAnyStringView name) const
\overload
- \since 4.5
Returns \c true if this QXmlStreamAttributes has an attribute whose
namespace URI and name correspond to \a namespaceUri and \a name;
otherwise returns \c false.
*/
-#endif // QT_NO_XMLSTREAMREADER
-#endif // QT_NO_XMLSTREAMWRITER
+#endif // feature xmlstreamreader
+#endif // feature xmlstreamwriter
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAM
+#endif // feature xmlstream
diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g
index 0051c6255b..860b7fd727 100644
--- a/src/corelib/serialization/qxmlstream.g
+++ b/src/corelib/serialization/qxmlstream.g
@@ -1,41 +1,5 @@
-----------------------------------------------------------------------------
---
-- Copyright (C) 2020 The Qt Company Ltd.
--- 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$
---
-----------------------------------------------------------------------------
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
%parser QXmlStreamGrammar
%impl qxmlstreamparser_p.h
@@ -88,13 +52,13 @@
%token IMPLIED "IMPLIED"
%token FIXED "FIXED"
--- conent spec
+-- content spec
%token EMPTY "EMPTY"
%token ANY "ANY"
%token PCDATA "PCDATA"
-- error
-%token ERROR
+%token XML_ERROR
-- entities
%token PARSE_ENTITY
@@ -145,44 +109,8 @@
%start document
-/./****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml 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$
-**
-****************************************************************************/
+/.// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
@@ -219,12 +147,16 @@
#ifndef QXMLSTREAMPARSER_P_H
#define QXMLSTREAMPARSER_P_H
-#ifndef QT_NO_XMLSTREAMREADER
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(xmlstreamreader)
bool QXmlStreamReaderPrivate::parse()
{
// cleanup currently reported token
+ using namespace Qt::StringLiterals;
+
switch (type) {
case QXmlStreamReader::StartElement:
name.clear();
@@ -319,7 +251,7 @@ bool QXmlStreamReaderPrivate::parse()
} else switch (token_char) {
case 0xfffe:
case 0xffff:
- token = ERROR;
+ token = XML_ERROR;
break;
case '\r':
token = SPACE;
@@ -732,9 +664,9 @@ attdef ::= attdef_start att_type default_decl;
dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1));
dtdAttribute.attributeName = addToStringStorage(symString(1));
dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1));
- dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns")
+ dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == "xmlns"_L1
|| (dtdAttribute.attributePrefix.isEmpty()
- && dtdAttribute.attributeName == QLatin1String("xmlns")));
+ && dtdAttribute.attributeName == "xmlns"_L1));
if (lastAttributeValue.isNull()) {
dtdAttribute.defaultValue.clear();
} else {
@@ -756,14 +688,14 @@ attlist_decl ::= langle_bang ATTLIST qname attdef_list space_opt RANGLE;
case $rule_number: {
if (referenceToUnparsedEntityDetected && !standalone)
break;
- int n = dtdAttributes.size();
+ qsizetype n = dtdAttributes.size();
XmlStringRef tagName = addToStringStorage(symName(3));
while (n--) {
DtdAttribute &dtdAttribute = dtdAttributes[n];
if (!dtdAttribute.tagName.isNull())
break;
dtdAttribute.tagName = tagName;
- for (int i = 0; i < n; ++i) {
+ for (qsizetype i = 0; i < n; ++i) {
if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName)
&& dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) {
dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it
@@ -869,11 +801,11 @@ processing_instruction ::= LANGLE QUESTIONMARK name space;
/.
case $rule_number: {
setType(QXmlStreamReader::ProcessingInstruction);
- int pos = sym(4).pos + sym(4).len;
+ const qsizetype pos = sym(4).pos + sym(4).len;
processingInstructionTarget = symString(3);
if (scanUntil("?>")) {
processingInstructionData = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 2);
- if (!processingInstructionTarget.view().compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
+ if (!processingInstructionTarget.view().compare("xml"_L1, Qt::CaseInsensitive)) {
raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document."));
}
else if (!QXmlUtils::isNCName(processingInstructionTarget))
@@ -891,7 +823,7 @@ processing_instruction ::= LANGLE QUESTIONMARK name QUESTIONMARK RANGLE;
case $rule_number:
setType(QXmlStreamReader::ProcessingInstruction);
processingInstructionTarget = symString(3);
- if (!processingInstructionTarget.view().compare(QLatin1String("xml"), Qt::CaseInsensitive))
+ if (!processingInstructionTarget.view().compare("xml"_L1, Qt::CaseInsensitive))
raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name."));
break;
./
@@ -921,7 +853,7 @@ comment ::= comment_start RANGLE;
/.
case $rule_number: {
setType(QXmlStreamReader::Comment);
- int pos = sym(1).pos + 4;
+ const qsizetype pos = sym(1).pos + 4;
text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
} break;
./
@@ -933,7 +865,7 @@ cdata ::= langle_bang CDATA_START;
setType(QXmlStreamReader::Characters);
isCDATA = true;
isWhitespace = false;
- int pos = sym(2).pos;
+ const qsizetype pos = sym(2).pos;
if (scanUntil("]]>", -1)) {
text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
} else {
@@ -1069,7 +1001,7 @@ literal_content_start ::= SPACE;
/.
case $rule_number:
if (normalizeLiterals)
- textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' ');
+ textBuffer.data()[textBuffer.size()-1] = u' ';
break;
./
@@ -1184,13 +1116,13 @@ attribute ::= qname space_opt EQ space_opt attribute_value;
/.
case $rule_number: {
XmlStringRef prefix = symPrefix(1);
- if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) {
+ if (prefix.isEmpty() && symString(1) == "xmlns"_L1 && namespaceProcessing) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
namespaceDeclaration.prefix.clear();
const XmlStringRef ns(symString(5));
- if (ns.view() == QLatin1String("http://www.w3.org/2000/xmlns/") ||
- ns.view() == QLatin1String("http://www.w3.org/XML/1998/namespace"))
+ if (ns.view() == "http://www.w3.org/2000/xmlns/"_L1 ||
+ ns.view() == "http://www.w3.org/XML/1998/namespace"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
else
namespaceDeclaration.namespaceUri = addToStringStorage(ns);
@@ -1201,8 +1133,7 @@ attribute ::= qname space_opt EQ space_opt attribute_value;
XmlStringRef attributeQualifiedName = symName(1);
bool normalize = false;
- for (int a = 0; a < dtdAttributes.size(); ++a) {
- DtdAttribute &dtdAttribute = dtdAttributes[a];
+ for (const DtdAttribute &dtdAttribute : std::as_const(dtdAttributes)) {
if (!dtdAttribute.isCDATA
&& dtdAttribute.tagName == qualifiedName
&& dtdAttribute.attributeQualifiedName == attributeQualifiedName
@@ -1213,10 +1144,10 @@ attribute ::= qname space_opt EQ space_opt attribute_value;
}
if (normalize) {
// normalize attribute value (simplify and trim)
- int pos = textBuffer.size();
- int n = 0;
+ const qsizetype pos = textBuffer.size();
+ qsizetype n = 0;
bool wasSpace = true;
- for (int i = 0; i < attribute.value.len; ++i) {
+ for (qsizetype i = 0; i < attribute.value.len; ++i) {
QChar c = textBuffer.at(attribute.value.pos + i);
if (c.unicode() == ' ') {
if (wasSpace)
@@ -1234,16 +1165,16 @@ attribute ::= qname space_opt EQ space_opt attribute_value;
attribute.value.pos = pos;
attribute.value.len = n;
}
- if (prefix == QLatin1String("xmlns") && namespaceProcessing) {
+ if (prefix == "xmlns"_L1 && namespaceProcessing) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
XmlStringRef namespacePrefix = symString(attribute.key);
XmlStringRef namespaceUri = symString(attribute.value);
attributeStack.pop();
- if (((namespacePrefix == QLatin1String("xml"))
- ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
- || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
+ if (((namespacePrefix == "xml"_L1)
+ ^ (namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1))
+ || namespaceUri == "http://www.w3.org/2000/xmlns/"_L1
|| namespaceUri.isEmpty()
- || namespacePrefix == QLatin1String("xmlns"))
+ || namespacePrefix == "xmlns"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
namespaceDeclaration.prefix = addToStringStorage(namespacePrefix);
@@ -1299,9 +1230,9 @@ etag ::= LANGLE SLASH qname space_opt RANGLE;
Tag tag = tagStack_pop();
namespaceUri = tag.namespaceDeclaration.namespaceUri;
+ prefix = tag.namespaceDeclaration.prefix;
name = tag.name;
qualifiedName = tag.qualifiedName;
- prefix = tag.namespaceDeclaration.prefix;
if (qualifiedName != symName(3))
raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch."));
} break;
@@ -1488,7 +1419,12 @@ space_opt ::= space;
qname ::= LETTER;
/.
case $rule_number: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
@@ -1499,7 +1435,11 @@ qname ::= LETTER;
name ::= LETTER;
/.
case $rule_number:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
@@ -1547,7 +1487,9 @@ nmtoken ::= COLON;
return false;
}
-#endif
+#endif // feature xmlstreamreader
+
+QT_END_NAMESPACE
#endif
diff --git a/src/corelib/serialization/qxmlstream.h b/src/corelib/serialization/qxmlstream.h
index afd8563cc1..8a12c6d611 100644
--- a/src/corelib/serialization/qxmlstream.h
+++ b/src/corelib/serialization/qxmlstream.h
@@ -1,49 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXMLSTREAM_H
#define QXMLSTREAM_H
#include <QtCore/qiodevice.h>
-#ifndef QT_NO_XMLSTREAM
+#if QT_CONFIG(xmlstream)
+#include <QtCore/qcompare.h>
#include <QtCore/qlist.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qstring.h>
@@ -58,12 +23,12 @@ public:
QXmlString(QStringPrivate &&d) : m_string(std::move(d)) {}
QXmlString(const QString &s) : m_string(s.data_ptr()) {}
QXmlString & operator=(const QString &s) { m_string = s.data_ptr(); return *this; }
- QXmlString & operator=(QString &&s) { qSwap(m_string, s.data_ptr()); return *this; }
+ QXmlString & operator=(QString &&s) { m_string.swap(s.data_ptr()); return *this; }
inline constexpr QXmlString() {}
void swap(QXmlString &other) noexcept
{
- qSwap(m_string, other.m_string);
+ m_string.swap(other.m_string);
}
inline operator QStringView() const { return QStringView(m_string.data(), m_string.size); }
@@ -94,13 +59,23 @@ public:
}
inline QStringView value() const { return m_value; }
inline bool isDefault() const { return m_isDefault; }
- inline bool operator==(const QXmlStreamAttribute &other) const {
- return (value() == other.value()
- && (namespaceUri().isNull() ? (qualifiedName() == other.qualifiedName())
- : (namespaceUri() == other.namespaceUri() && name() == other.name())));
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamAttribute &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamAttribute &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+
+private:
+ friend bool comparesEqual(const QXmlStreamAttribute &lhs,
+ const QXmlStreamAttribute &rhs) noexcept
+ {
+ return (lhs.value() == rhs.value()
+ && (lhs.namespaceUri().isNull() ? (lhs.qualifiedName() == rhs.qualifiedName())
+ : (lhs.namespaceUri() == rhs.namespaceUri()
+ && lhs.name() == rhs.name())));
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamAttribute)
};
Q_DECLARE_TYPEINFO(QXmlStreamAttribute, Q_RELOCATABLE_TYPE);
@@ -111,25 +86,25 @@ class QXmlStreamAttributes : public QList<QXmlStreamAttribute>
{
public:
inline QXmlStreamAttributes() {}
+#if QT_CORE_REMOVED_SINCE(6, 6)
Q_CORE_EXPORT QStringView value(const QString &namespaceUri, const QString &name) const;
- Q_CORE_EXPORT QStringView value(const QString &namespaceUri, QLatin1String name) const;
- Q_CORE_EXPORT QStringView value(QLatin1String namespaceUri, QLatin1String name) const;
+ Q_CORE_EXPORT QStringView value(const QString &namespaceUri, QLatin1StringView name) const;
+ Q_CORE_EXPORT QStringView value(QLatin1StringView namespaceUri, QLatin1StringView name) const;
Q_CORE_EXPORT QStringView value(const QString &qualifiedName) const;
- Q_CORE_EXPORT QStringView value(QLatin1String qualifiedName) const;
+ Q_CORE_EXPORT QStringView value(QLatin1StringView qualifiedName) const;
+#endif
+ Q_CORE_EXPORT QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const noexcept;
+ Q_CORE_EXPORT QStringView value(QAnyStringView qualifiedName) const noexcept;
+
Q_CORE_EXPORT void append(const QString &namespaceUri, const QString &name, const QString &value);
Q_CORE_EXPORT void append(const QString &qualifiedName, const QString &value);
- inline bool hasAttribute(const QString &qualifiedName) const
- {
- return !value(qualifiedName).isNull();
- }
-
- inline bool hasAttribute(QLatin1String qualifiedName) const
+ bool hasAttribute(QAnyStringView qualifiedName) const
{
return !value(qualifiedName).isNull();
}
- inline bool hasAttribute(const QString &namespaceUri, const QString &name) const
+ bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const
{
return !value(namespaceUri, name).isNull();
}
@@ -147,11 +122,19 @@ public:
inline QStringView prefix() const { return m_prefix; }
inline QStringView namespaceUri() const { return m_namespaceUri; }
- inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const {
- return (prefix() == other.prefix() && namespaceUri() == other.namespaceUri());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamNamespaceDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+private:
+ friend bool comparesEqual(const QXmlStreamNamespaceDeclaration &lhs,
+ const QXmlStreamNamespaceDeclaration &rhs) noexcept
+ {
+ return (lhs.prefix() == rhs.prefix() && lhs.namespaceUri() == rhs.namespaceUri());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamNamespaceDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamNamespaceDeclaration, Q_RELOCATABLE_TYPE);
@@ -167,12 +150,20 @@ public:
inline QStringView name() const { return m_name; }
inline QStringView systemId() const { return m_systemId; }
inline QStringView publicId() const { return m_publicId; }
- inline bool operator==(const QXmlStreamNotationDeclaration &other) const {
- return (name() == other.name() && systemId() == other.systemId()
- && publicId() == other.publicId());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamNotationDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamNotationDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+private:
+ friend bool comparesEqual(const QXmlStreamNotationDeclaration &lhs,
+ const QXmlStreamNotationDeclaration &rhs) noexcept
+ {
+ return (lhs.name() == rhs.name() && lhs.systemId() == rhs.systemId()
+ && lhs.publicId() == rhs.publicId());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamNotationDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamNotationDeclaration, Q_RELOCATABLE_TYPE);
@@ -190,15 +181,24 @@ public:
inline QStringView systemId() const { return m_systemId; }
inline QStringView publicId() const { return m_publicId; }
inline QStringView value() const { return m_value; }
- inline bool operator==(const QXmlStreamEntityDeclaration &other) const {
- return (name() == other.name()
- && notationName() == other.notationName()
- && systemId() == other.systemId()
- && publicId() == other.publicId()
- && value() == other.value());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamEntityDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamEntityDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+
+private:
+ friend bool comparesEqual(const QXmlStreamEntityDeclaration &lhs,
+ const QXmlStreamEntityDeclaration &rhs) noexcept
+ {
+ return (lhs.name() == rhs.name()
+ && lhs.notationName() == rhs.notationName()
+ && lhs.systemId() == rhs.systemId()
+ && lhs.publicId() == rhs.publicId()
+ && lhs.value() == rhs.value());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamEntityDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamEntityDeclaration, Q_RELOCATABLE_TYPE);
@@ -206,14 +206,17 @@ typedef QList<QXmlStreamEntityDeclaration> QXmlStreamEntityDeclarations;
class Q_CORE_EXPORT QXmlStreamEntityResolver
{
+ Q_DISABLE_COPY_MOVE(QXmlStreamEntityResolver)
public:
+ QXmlStreamEntityResolver() = default;
virtual ~QXmlStreamEntityResolver();
virtual QString resolveEntity(const QString& publicId, const QString& systemId);
virtual QString resolveUndeclaredEntity(const QString &name);
};
-#ifndef QT_NO_XMLSTREAMREADER
-class Q_CORE_EXPORT QXmlStreamReader {
+#if QT_CONFIG(xmlstreamreader)
+class Q_CORE_EXPORT QXmlStreamReader
+{
QDOC_PROPERTY(bool namespaceProcessing READ namespaceProcessing WRITE setNamespaceProcessing)
public:
enum TokenType {
@@ -233,16 +236,27 @@ public:
QXmlStreamReader();
explicit QXmlStreamReader(QIODevice *device);
+#if QT_CORE_REMOVED_SINCE(6, 5)
explicit QXmlStreamReader(const QByteArray &data);
explicit QXmlStreamReader(const QString &data);
explicit QXmlStreamReader(const char * data);
+#endif // QT_CORE_REMOVED_SINCE(6, 5)
+ Q_WEAK_OVERLOAD
+ explicit QXmlStreamReader(const QByteArray &data)
+ : QXmlStreamReader(data, PrivateConstructorTag{}) { }
+ explicit QXmlStreamReader(QAnyStringView data);
~QXmlStreamReader();
void setDevice(QIODevice *device);
QIODevice *device() const;
+#if QT_CORE_REMOVED_SINCE(6, 5)
void addData(const QByteArray &data);
void addData(const QString &data);
void addData(const char *data);
+#endif // QT_CORE_REMOVED_SINCE(6, 5)
+ Q_WEAK_OVERLOAD
+ void addData(const QByteArray &data) { addDataImpl(data); }
+ void addData(QAnyStringView data);
void clear();
@@ -271,6 +285,7 @@ public:
inline bool isProcessingInstruction() const { return tokenType() == ProcessingInstruction; }
bool isStandaloneDocument() const;
+ bool hasStandaloneDeclaration() const;
QStringView documentVersion() const;
QStringView documentEncoding() const;
@@ -329,14 +344,18 @@ public:
QXmlStreamEntityResolver *entityResolver() const;
private:
+ struct PrivateConstructorTag { };
+ QXmlStreamReader(const QByteArray &data, PrivateConstructorTag);
+ void addDataImpl(const QByteArray &data);
+
Q_DISABLE_COPY(QXmlStreamReader)
Q_DECLARE_PRIVATE(QXmlStreamReader)
QScopedPointer<QXmlStreamReaderPrivate> d_ptr;
};
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
-#ifndef QT_NO_XMLSTREAMWRITER
+#if QT_CONFIG(xmlstreamwriter)
class QXmlStreamWriterPrivate;
@@ -360,11 +379,17 @@ public:
void setAutoFormattingIndent(int spacesOrTabs);
int autoFormattingIndent() const;
+#if QT_CORE_REMOVED_SINCE(6,5)
void writeAttribute(const QString &qualifiedName, const QString &value);
void writeAttribute(const QString &namespaceUri, const QString &name, const QString &value);
+#endif
+ void writeAttribute(QAnyStringView qualifiedName, QAnyStringView value);
+ void writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value);
+
void writeAttribute(const QXmlStreamAttribute& attribute);
void writeAttributes(const QXmlStreamAttributes& attributes);
+#if QT_CORE_REMOVED_SINCE(6,5)
void writeCDATA(const QString &text);
void writeCharacters(const QString &text);
void writeComment(const QString &text);
@@ -376,22 +401,47 @@ public:
void writeTextElement(const QString &qualifiedName, const QString &text);
void writeTextElement(const QString &namespaceUri, const QString &name, const QString &text);
+#endif
+ void writeCDATA(QAnyStringView text);
+ void writeCharacters(QAnyStringView text);
+ void writeComment(QAnyStringView text);
+
+ void writeDTD(QAnyStringView dtd);
+
+ void writeEmptyElement(QAnyStringView qualifiedName);
+ void writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name);
+
+ void writeTextElement(QAnyStringView qualifiedName, QAnyStringView text);
+ void writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text);
+
void writeEndDocument();
void writeEndElement();
+#if QT_CORE_REMOVED_SINCE(6,5)
void writeEntityReference(const QString &name);
- void writeNamespace(const QString &namespaceUri, const QString &prefix = QString());
+ void writeNamespace(const QString &namespaceUri, const QString &prefix);
void writeDefaultNamespace(const QString &namespaceUri);
- void writeProcessingInstruction(const QString &target, const QString &data = QString());
+ void writeProcessingInstruction(const QString &target, const QString &data);
+#endif
+ void writeEntityReference(QAnyStringView name);
+ void writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix = {});
+ void writeDefaultNamespace(QAnyStringView namespaceUri);
+ void writeProcessingInstruction(QAnyStringView target, QAnyStringView data = {});
void writeStartDocument();
+#if QT_CORE_REMOVED_SINCE(6,5)
void writeStartDocument(const QString &version);
void writeStartDocument(const QString &version, bool standalone);
void writeStartElement(const QString &qualifiedName);
void writeStartElement(const QString &namespaceUri, const QString &name);
+#endif
+ void writeStartDocument(QAnyStringView version);
+ void writeStartDocument(QAnyStringView version, bool standalone);
+ void writeStartElement(QAnyStringView qualifiedName);
+ void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name);
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
void writeCurrentToken(const QXmlStreamReader &reader);
#endif
@@ -402,9 +452,10 @@ private:
Q_DECLARE_PRIVATE(QXmlStreamWriter)
QScopedPointer<QXmlStreamWriterPrivate> d_ptr;
};
-#endif // QT_NO_XMLSTREAMWRITER
+#endif // feature xmlstreamwriter
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAM
+#endif // feature xmlstream
+
#endif // QXMLSTREAM_H
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
index 41b04d4c38..a29ee656e9 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -52,8 +16,12 @@
#include <qstringconverter.h>
#include <qxmlstream.h>
#include "qxmlstreamgrammar_p.h"
+#include <QtCore/qhash.h>
+#include <QCoreApplication> // Q_DECLARE_TR_FUNCTIONS
+
#include <memory>
+#include <optional>
#ifndef QXMLSTREAM_P_H
#define QXMLSTREAM_P_H
@@ -70,12 +38,12 @@ public:
qsizetype m_size = 0;
constexpr XmlStringRef() = default;
- constexpr inline XmlStringRef(const QString *string, int pos, int length)
- : m_string(string), m_pos(pos), m_size(length)
+ constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length)
+ : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length))
{
}
XmlStringRef(const QString *string)
- : XmlStringRef(string, 0, string->length())
+ : XmlStringRef(string, 0, string->size())
{
}
@@ -87,7 +55,6 @@ public:
d.size = m_size;
return QXmlString(std::move(d));
}
- operator QStringView() const { return view(); }
void clear() { m_string = nullptr; m_pos = 0; m_size= 0; }
QStringView view() const { return m_string ? QStringView(m_string->data() + m_pos, m_size) : QStringView(); }
@@ -95,6 +62,33 @@ public:
bool isNull() const { return !m_string; }
QString toString() const { return view().toString(); }
+ using value_type = QStringView::value_type;
+ using size_type = QStringView::size_type;
+ using difference_type = QStringView::difference_type;
+ using pointer = QStringView::pointer;
+ using const_pointer = QStringView::const_pointer;
+ using reference = QStringView::reference;
+ using const_reference = QStringView::const_reference;
+ using iterator = QStringView::iterator;
+ using const_iterator = QStringView::const_iterator;
+ using reverse_iterator = QStringView::reverse_iterator;
+ using const_reverse_iterator = QStringView::const_reverse_iterator;
+
+#define MAKE_MEMBER(name) \
+ auto name () const noexcept { return view(). name (); }
+ MAKE_MEMBER(data)
+ MAKE_MEMBER(size)
+ MAKE_MEMBER(empty)
+ MAKE_MEMBER(begin)
+ MAKE_MEMBER(end)
+ MAKE_MEMBER(cbegin)
+ MAKE_MEMBER(cend)
+ MAKE_MEMBER(rbegin)
+ MAKE_MEMBER(rend)
+ MAKE_MEMBER(crbegin)
+ MAKE_MEMBER(crend)
+#undef MAKE_MEMBER
+
#define MAKE_OP(op) \
friend auto operator op(const XmlStringRef &lhs, const XmlStringRef &rhs) noexcept { return lhs.view() op rhs.view(); } \
/*end*/
@@ -124,6 +118,8 @@ using namespace QtPrivate;
template <typename T> class QXmlStreamSimpleStack
{
+ Q_DISABLE_COPY_MOVE(QXmlStreamSimpleStack)
+
T *data;
qsizetype tos, cap;
public:
@@ -170,7 +166,6 @@ public:
const T *cend() const { return end(); }
};
-
class QXmlStream
{
Q_DECLARE_TR_FUNCTIONS(QXmlStream)
@@ -189,7 +184,7 @@ public:
XmlStringRef name;
XmlStringRef qualifiedName;
NamespaceDeclaration namespaceDeclaration;
- int tagStackStringStorageSize;
+ qsizetype tagStackStringStorageSize;
qsizetype namespaceDeclarationsSize;
};
@@ -197,17 +192,17 @@ public:
QXmlStreamPrivateTagStack();
QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations;
QString tagStackStringStorage;
- int tagStackStringStorageSize;
- int initialTagStackStringStorageSize;
+ qsizetype tagStackStringStorageSize;
+ qsizetype initialTagStackStringStorageSize;
bool tagsDone;
- XmlStringRef addToStringStorage(QStringView s)
+ XmlStringRef addToStringStorage(QAnyStringView s)
{
- int pos = tagStackStringStorageSize;
- int sz = s.size();
+ qsizetype pos = tagStackStringStorageSize;
if (pos != tagStackStringStorage.size())
tagStackStringStorage.resize(pos);
- tagStackStringStorage.append(s.data(), sz);
+ s.visit([&](auto s) { tagStackStringStorage.append(s); });
+ qsizetype sz = (tagStackStringStorage.size() - pos);
tagStackStringStorageSize += sz;
return XmlStringRef(&tagStackStringStorage, pos, sz);
}
@@ -246,14 +241,14 @@ public:
uchar firstByte;
qint64 nbytesread;
QString readBuffer;
- int readBufferPos;
+ qsizetype readBufferPos;
QXmlStreamSimpleStack<uint> putStack;
struct Entity {
Entity() = default;
Entity(const QString &name, const QString &value)
: name(name), value(value), external(false), unparsed(false), literal(false),
hasBeenParsed(false), isCurrentlyReferenced(false){}
- static inline Entity createLiteral(QLatin1String name, QLatin1String value)
+ static inline Entity createLiteral(QLatin1StringView name, QLatin1StringView value)
{ Entity result(name, value); result.literal = result.hasBeenParsed = true; return result; }
QString name, value;
uint external : 1;
@@ -302,6 +297,17 @@ public:
QStringDecoder decoder;
bool atEnd;
+ enum class XmlContext
+ {
+ Prolog,
+ Body,
+ };
+
+ XmlContext currentContext = XmlContext::Prolog;
+ bool foundDTD = false;
+ bool isValidToken(QXmlStreamReader::TokenType type);
+ void checkToken();
+
/*!
\sa setType()
*/
@@ -389,6 +395,7 @@ public:
uint hasExternalDtdSubset : 1;
uint lockEncoding : 1;
uint namespaceProcessing : 1;
+ uint hasStandalone : 1; // TODO: expose in public API
int resumeReduction;
void resume(int rule);
@@ -405,9 +412,9 @@ public:
int tos;
int stack_size;
struct Value {
- int pos;
- int len;
- int prefix;
+ qsizetype pos; // offset into textBuffer
+ qsizetype len; // length incl. prefix (if any)
+ qint16 prefix; // prefix of a name (as in "prefix:name") limited to 4k in fastScanName()
ushort c;
};
@@ -500,11 +507,11 @@ public:
// scan optimization functions. Not strictly necessary but LALR is
// not very well suited for scanning fast
- int fastScanLiteralContent();
- int fastScanSpace();
- int fastScanContentCharList();
- int fastScanName(int *prefix = nullptr);
- inline int fastScanNMTOKEN();
+ qsizetype fastScanLiteralContent();
+ qsizetype fastScanSpace();
+ qsizetype fastScanContentCharList();
+ std::optional<qsizetype> fastScanName(Value *val = nullptr);
+ inline qsizetype fastScanNMTOKEN();
bool parse();
@@ -512,6 +519,7 @@ public:
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
void raiseWellFormedError(const QString &message);
+ void raiseNamePrefixTooLongError();
QXmlStreamEntityResolver *entityResolver;
diff --git a/src/corelib/serialization/qxmlstreamgrammar.cpp b/src/corelib/serialization/qxmlstreamgrammar.cpp
index d709515249..074b9023ce 100644
--- a/src/corelib/serialization/qxmlstreamgrammar.cpp
+++ b/src/corelib/serialization/qxmlstreamgrammar.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file was generated by qlalr - DO NOT EDIT!
#include "qxmlstreamgrammar_p.h"
diff --git a/src/corelib/serialization/qxmlstreamgrammar_p.h b/src/corelib/serialization/qxmlstreamgrammar_p.h
index 32dd1d05fd..80ee8e929f 100644
--- a/src/corelib/serialization/qxmlstreamgrammar_p.h
+++ b/src/corelib/serialization/qxmlstreamgrammar_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -80,7 +44,6 @@ public:
ENTITY = 32,
ENTITY_DONE = 45,
EQ = 14,
- ERROR = 43,
FIXED = 39,
HASH = 6,
ID = 48,
@@ -117,6 +80,7 @@ public:
UNRESOLVED_ENTITY = 46,
VERSION = 55,
XML = 54,
+ XML_ERROR = 43,
ACCEPT_STATE = 416,
RULE_COUNT = 270,
diff --git a/src/corelib/serialization/qxmlstreamparser_p.h b/src/corelib/serialization/qxmlstreamparser_p.h
index d568f9d024..1363bf4d41 100644
--- a/src/corelib/serialization/qxmlstreamparser_p.h
+++ b/src/corelib/serialization/qxmlstreamparser_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
@@ -74,12 +38,14 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
bool QXmlStreamReaderPrivate::parse()
{
// cleanup currently reported token
+ using namespace Qt::StringLiterals;
+
switch (type) {
case QXmlStreamReader::StartElement:
name.clear();
@@ -174,7 +140,7 @@ bool QXmlStreamReaderPrivate::parse()
} else switch (token_char) {
case 0xfffe:
case 0xffff:
- token = ERROR;
+ token = XML_ERROR;
break;
case '\r':
token = SPACE;
@@ -467,9 +433,9 @@ bool QXmlStreamReaderPrivate::parse()
dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1));
dtdAttribute.attributeName = addToStringStorage(symString(1));
dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1));
- dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns")
+ dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == "xmlns"_L1
|| (dtdAttribute.attributePrefix.isEmpty()
- && dtdAttribute.attributeName == QLatin1String("xmlns")));
+ && dtdAttribute.attributeName == "xmlns"_L1));
if (lastAttributeValue.isNull()) {
dtdAttribute.defaultValue.clear();
} else {
@@ -484,14 +450,14 @@ bool QXmlStreamReaderPrivate::parse()
case 88: {
if (referenceToUnparsedEntityDetected && !standalone)
break;
- int n = dtdAttributes.size();
+ qsizetype n = dtdAttributes.size();
XmlStringRef tagName = addToStringStorage(symName(3));
while (n--) {
DtdAttribute &dtdAttribute = dtdAttributes[n];
if (!dtdAttribute.tagName.isNull())
break;
dtdAttribute.tagName = tagName;
- for (int i = 0; i < n; ++i) {
+ for (qsizetype i = 0; i < n; ++i) {
if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName)
&& dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) {
dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it
@@ -572,11 +538,11 @@ bool QXmlStreamReaderPrivate::parse()
case 96: {
setType(QXmlStreamReader::ProcessingInstruction);
- int pos = sym(4).pos + sym(4).len;
+ const qsizetype pos = sym(4).pos + sym(4).len;
processingInstructionTarget = symString(3);
if (scanUntil("?>")) {
processingInstructionData = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 2);
- if (!processingInstructionTarget.view().compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
+ if (!processingInstructionTarget.view().compare("xml"_L1, Qt::CaseInsensitive)) {
raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document."));
}
else if (!QXmlUtils::isNCName(processingInstructionTarget))
@@ -591,7 +557,7 @@ bool QXmlStreamReaderPrivate::parse()
case 97:
setType(QXmlStreamReader::ProcessingInstruction);
processingInstructionTarget = symString(3);
- if (!processingInstructionTarget.view().compare(QLatin1String("xml"), Qt::CaseInsensitive))
+ if (!processingInstructionTarget.view().compare("xml"_L1, Qt::CaseInsensitive))
raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name."));
break;
@@ -611,7 +577,7 @@ bool QXmlStreamReaderPrivate::parse()
case 100: {
setType(QXmlStreamReader::Comment);
- int pos = sym(1).pos + 4;
+ const qsizetype pos = sym(1).pos + 4;
text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
} break;
@@ -619,7 +585,7 @@ bool QXmlStreamReaderPrivate::parse()
setType(QXmlStreamReader::Characters);
isCDATA = true;
isWhitespace = false;
- int pos = sym(2).pos;
+ const qsizetype pos = sym(2).pos;
if (scanUntil("]]>", -1)) {
text = XmlStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
} else {
@@ -693,7 +659,7 @@ bool QXmlStreamReaderPrivate::parse()
case 173:
if (normalizeLiterals)
- textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' ');
+ textBuffer.data()[textBuffer.size()-1] = u' ';
break;
case 174:
@@ -749,13 +715,13 @@ bool QXmlStreamReaderPrivate::parse()
case 229: {
XmlStringRef prefix = symPrefix(1);
- if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) {
+ if (prefix.isEmpty() && symString(1) == "xmlns"_L1 && namespaceProcessing) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
namespaceDeclaration.prefix.clear();
const XmlStringRef ns(symString(5));
- if (ns.view() == QLatin1String("http://www.w3.org/2000/xmlns/") ||
- ns.view() == QLatin1String("http://www.w3.org/XML/1998/namespace"))
+ if (ns.view() == "http://www.w3.org/2000/xmlns/"_L1 ||
+ ns.view() == "http://www.w3.org/XML/1998/namespace"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
else
namespaceDeclaration.namespaceUri = addToStringStorage(ns);
@@ -766,8 +732,7 @@ bool QXmlStreamReaderPrivate::parse()
XmlStringRef attributeQualifiedName = symName(1);
bool normalize = false;
- for (int a = 0; a < dtdAttributes.size(); ++a) {
- DtdAttribute &dtdAttribute = dtdAttributes[a];
+ for (const DtdAttribute &dtdAttribute : std::as_const(dtdAttributes)) {
if (!dtdAttribute.isCDATA
&& dtdAttribute.tagName == qualifiedName
&& dtdAttribute.attributeQualifiedName == attributeQualifiedName
@@ -778,10 +743,10 @@ bool QXmlStreamReaderPrivate::parse()
}
if (normalize) {
// normalize attribute value (simplify and trim)
- int pos = textBuffer.size();
- int n = 0;
+ const qsizetype pos = textBuffer.size();
+ qsizetype n = 0;
bool wasSpace = true;
- for (int i = 0; i < attribute.value.len; ++i) {
+ for (qsizetype i = 0; i < attribute.value.len; ++i) {
QChar c = textBuffer.at(attribute.value.pos + i);
if (c.unicode() == ' ') {
if (wasSpace)
@@ -799,16 +764,16 @@ bool QXmlStreamReaderPrivate::parse()
attribute.value.pos = pos;
attribute.value.len = n;
}
- if (prefix == QLatin1String("xmlns") && namespaceProcessing) {
+ if (prefix == "xmlns"_L1 && namespaceProcessing) {
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
XmlStringRef namespacePrefix = symString(attribute.key);
XmlStringRef namespaceUri = symString(attribute.value);
attributeStack.pop();
- if (((namespacePrefix == QLatin1String("xml"))
- ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
- || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
+ if (((namespacePrefix == "xml"_L1)
+ ^ (namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1))
+ || namespaceUri == "http://www.w3.org/2000/xmlns/"_L1
|| namespaceUri.isEmpty()
- || namespacePrefix == QLatin1String("xmlns"))
+ || namespacePrefix == "xmlns"_L1)
raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
namespaceDeclaration.prefix = addToStringStorage(namespacePrefix);
@@ -982,7 +947,12 @@ bool QXmlStreamReaderPrivate::parse()
break;
case 262: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(262);
return false;
@@ -990,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse()
} break;
case 263:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(263);
return false;
@@ -1024,7 +998,7 @@ bool QXmlStreamReaderPrivate::parse()
return false;
}
-#endif
+#endif // feature xmlstreamreader
QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qxmlutils.cpp b/src/corelib/serialization/qxmlutils.cpp
index dccdf85182..e6fae7c173 100644
--- a/src/corelib/serialization/qxmlutils.cpp
+++ b/src/corelib/serialization/qxmlutils.cpp
@@ -1,48 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qstring.h>
#include "qxmlutils_p.h"
+#include <private/qtools_p.h>
+
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
/* TODO:
* - isNameChar() doesn't have to be public, it's only needed in
* qdom.cpp -- refactor fixedXmlName() to use isNCName()
@@ -80,7 +48,7 @@ bool QXmlUtils::rangeContains(RangeIter begin, RangeIter end, const QChar c)
return cp >= begin->min;
while (begin != end) {
- int delta = (end - begin) / 2;
+ qptrdiff delta = (end - begin) / 2;
RangeIter mid = begin + delta;
if (mid->min > cp)
@@ -233,16 +201,12 @@ bool QXmlUtils::isEncName(QStringView encName)
if (encName.isEmpty())
return false;
const auto first = encName.front().unicode();
- if (!((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')))
+ if (!(isAsciiLower(first) || isAsciiUpper(first)))
return false;
for (QChar ch : encName.mid(1)) {
const auto cp = ch.unicode();
- if ((cp >= 'a' && cp <= 'z')
- || (cp >= 'A' && cp <= 'Z')
- || (cp >= '0' && cp <= '9')
- || cp == '.' || cp == '_' || cp == '-') {
+ if (isAsciiLetterOrNumber(cp) || cp == '.' || cp == '_' || cp == '-')
continue;
- }
return false;
}
return true;
@@ -271,13 +235,16 @@ bool QXmlUtils::isLetter(const QChar c)
\sa {http://www.w3.org/TR/REC-xml/#NT-Char},
{Extensible Markup Language (XML) 1.0 (Fourth Edition), [2] Char}
*/
-bool QXmlUtils::isChar(const QChar c)
+bool QXmlUtils::isChar(const char32_t c)
{
- return (c.unicode() >= 0x0020 && c.unicode() <= 0xD7FF)
- || c.unicode() == 0x0009
- || c.unicode() == 0x000A
- || c.unicode() == 0x000D
- || (c.unicode() >= 0xE000 && c.unicode() <= 0xFFFD);
+ // The valid range is defined by https://www.w3.org/TR/REC-xml/#NT-Char as following:
+ // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ return (c >= 0x0020 && c <= 0xD7FF)
+ || c == 0x0009
+ || c == 0x000A
+ || c == 0x000D
+ || (c >= 0xE000 && c <= 0xFFFD)
+ || (c >= 0x10000 && c <= 0x10FFFF);
}
/*!
@@ -318,12 +285,8 @@ bool QXmlUtils::isPublicID(QStringView candidate)
for (QChar ch : candidate) {
const ushort cp = ch.unicode();
- if ((cp >= 'a' && cp <= 'z')
- || (cp >= 'A' && cp <= 'Z')
- || (cp >= '0' && cp <= '9'))
- {
+ if (isAsciiLetterOrNumber(cp))
continue;
- }
switch (cp)
{
@@ -380,7 +343,7 @@ bool QXmlUtils::isNCName(QStringView ncName)
return false;
for (QChar at : ncName) {
- if (!QXmlUtils::isNameChar(at) || at == QLatin1Char(':'))
+ if (!QXmlUtils::isNameChar(at) || at == u':')
return false;
}
diff --git a/src/corelib/serialization/qxmlutils_p.h b/src/corelib/serialization/qxmlutils_p.h
index db6bddd5be..0ad1758979 100644
--- a/src/corelib/serialization/qxmlutils_p.h
+++ b/src/corelib/serialization/qxmlutils_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXMLUTILS_P_H
#define QXMLUTILS_P_H
@@ -69,7 +33,7 @@ class Q_CORE_EXPORT QXmlUtils
{
public:
static bool isEncName(QStringView encName);
- static bool isChar(const QChar c);
+ static bool isChar(const char32_t c);
static bool isNameChar(const QChar c);
static bool isLetter(const QChar c);
static bool isNCName(QStringView ncName);