diff options
Diffstat (limited to 'src/corelib/serialization/qdatastream.h')
-rw-r--r-- | src/corelib/serialization/qdatastream.h | 249 |
1 files changed, 175 insertions, 74 deletions
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) { |