summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qdatastream.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization/qdatastream.h')
-rw-r--r--src/corelib/serialization/qdatastream.h325
1 files changed, 241 insertions, 84 deletions
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 523dabfdc6..cf37df71d7 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.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) 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,
@@ -99,8 +81,14 @@ public:
Qt_6_0 = 20,
Qt_6_1 = Qt_6_0,
Qt_6_2 = Qt_6_0,
- Qt_DefaultCompiledVersion = Qt_6_2
-#if QT_VERSION >= 0x060300
+ Qt_6_3 = Qt_6_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
};
@@ -110,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
};
@@ -133,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);
@@ -158,7 +149,9 @@ public:
QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
QDataStream &operator>>(bool &i);
+#if QT_CORE_REMOVED_SINCE(6, 3)
QDataStream &operator>>(qfloat16 &f);
+#endif
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@@ -175,22 +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);
+#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();
@@ -203,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())
{
@@ -243,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) {
@@ -265,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) {
@@ -286,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;
@@ -305,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;
@@ -315,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) {
@@ -329,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) {
@@ -351,9 +411,16 @@ QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
template<typename ...T>
using QDataStreamIfHasOStreamOperators =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDataStream, T>...>, QDataStream &>;
+template<typename Container, typename ...T>
+using QDataStreamIfHasOStreamOperatorsContainer =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
+
template<typename ...T>
using QDataStreamIfHasIStreamOperators =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator<QDataStream, T>...>, QDataStream &>;
+template<typename Container, typename ...T>
+using QDataStreamIfHasIStreamOperatorsContainer =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
/*****************************************************************************
QDataStream inline functions
@@ -362,14 +429,58 @@ using QDataStreamIfHasIStreamOperators =
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); }
@@ -424,80 +535,81 @@ 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_QDOC
+
template<typename T>
-inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QList<T> &v)
+inline QDataStreamIfHasIStreamOperatorsContainer<QList<T>, T> operator>>(QDataStream &s, QList<T> &v)
{
return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QList<T> &v)
+inline QDataStreamIfHasOStreamOperatorsContainer<QList<T>, T> operator<<(QDataStream &s, const QList<T> &v)
{
return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QSet<T> &set)
+inline QDataStreamIfHasIStreamOperatorsContainer<QSet<T>, T> operator>>(QDataStream &s, QSet<T> &set)
{
return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QSet<T> &set)
+inline QDataStreamIfHasOStreamOperatorsContainer<QSet<T>, T> operator<<(QDataStream &s, const QSet<T> &set)
{
return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
+inline QDataStreamIfHasIStreamOperatorsContainer<QHash<Key, T>, Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
{
return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
+inline QDataStreamIfHasOStreamOperatorsContainer<QHash<Key, T>, Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
return QtPrivate::writeAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
{
return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
{
return QtPrivate::writeAssociativeMultiContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMap<Key, T>, Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
{
return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
{
return QtPrivate::writeAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
{
return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
{
return QtPrivate::writeAssociativeMultiContainer(s, map);
}
-#ifndef QT_NO_DATASTREAM
template <class T1, class T2>
inline QDataStreamIfHasIStreamOperators<T1, T2> operator>>(QDataStream& s, std::pair<T1, T2> &p)
{
@@ -511,7 +623,52 @@ inline QDataStreamIfHasOStreamOperators<T1, T2> operator<<(QDataStream& s, const
s << p.first << p.second;
return s;
}
-#endif
+
+#else
+
+template <class T>
+QDataStream &operator>>(QDataStream &s, QList<T> &l);
+
+template <class T>
+QDataStream &operator<<(QDataStream &s, const QList<T> &l);
+
+template <class T>
+QDataStream &operator>>(QDataStream &s, QSet<T> &set);
+
+template <class T>
+QDataStream &operator<<(QDataStream &s, const QSet<T> &set);
+
+template <class Key, class T>
+QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash);
+
+template <class Key, class T>
+QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash);
+
+template <class Key, class T>
+QDataStream &operator>>(QDataStream &s, QMultiHash<Key, T> &hash);
+
+template <class Key, class T>
+QDataStream &operator<<(QDataStream &s, const QMultiHash<Key, T> &hash);
+
+template <class Key, class T>
+QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map);
+
+template <class Key, class T>
+QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map);
+
+template <class Key, class T>
+QDataStream &operator>>(QDataStream &s, QMultiMap<Key, T> &map);
+
+template <class Key, class T>
+QDataStream &operator<<(QDataStream &s, const QMultiMap<Key, T> &map);
+
+template <class T1, class T2>
+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_QDOC
inline QDataStream &operator>>(QDataStream &s, QKeyCombination &combination)
{