// 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 #include #include #include #include #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) class QDataStreamPrivate; namespace QtPrivate { class StreamStateSaver; template QDataStream &readArrayBasedContainer(QDataStream &s, Container &c); template QDataStream &readListBasedContainer(QDataStream &s, Container &c); template QDataStream &readAssociativeContainer(QDataStream &s, Container &c); template QDataStream &writeSequentialContainer(QDataStream &s, const Container &c); template QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c); template QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c); } class Q_CORE_EXPORT QDataStream : public QIODeviceBase { public: enum Version { Qt_1_0 = 1, Qt_2_0 = 2, Qt_2_1 = 3, Qt_3_0 = 4, Qt_3_1 = 5, Qt_3_3 = 6, Qt_4_0 = 7, Qt_4_1 = Qt_4_0, Qt_4_2 = 8, Qt_4_3 = 9, Qt_4_4 = 10, Qt_4_5 = 11, Qt_4_6 = 12, Qt_4_7 = Qt_4_6, Qt_4_8 = Qt_4_7, Qt_4_9 = Qt_4_8, Qt_5_0 = 13, Qt_5_1 = 14, Qt_5_2 = 15, Qt_5_3 = Qt_5_2, Qt_5_4 = 16, Qt_5_5 = Qt_5_4, Qt_5_6 = 17, Qt_5_7 = Qt_5_6, Qt_5_8 = Qt_5_7, Qt_5_9 = Qt_5_8, Qt_5_10 = Qt_5_9, Qt_5_11 = Qt_5_10, Qt_5_12 = 18, Qt_5_13 = 19, Qt_5_14 = Qt_5_13, Qt_5_15 = Qt_5_14, Qt_6_0 = 20, Qt_6_1 = Qt_6_0, Qt_6_2 = Qt_6_0, 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_DefaultCompiledVersion = Qt_6_7 #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif }; enum ByteOrder { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian }; enum Status { Ok, ReadPastEnd, ReadCorruptData, WriteFailed }; enum FloatingPointPrecision { SinglePrecision, DoublePrecision }; QDataStream(); explicit QDataStream(QIODevice *); QDataStream(QByteArray *, OpenMode flags); QDataStream(const QByteArray &); ~QDataStream(); QIODevice *device() const; void setDevice(QIODevice *); bool atEnd() const; Status status() const; void setStatus(Status status); void resetStatus(); FloatingPointPrecision floatingPointPrecision() const; void setFloatingPointPrecision(FloatingPointPrecision precision); ByteOrder byteOrder() const; void setByteOrder(ByteOrder); int version() const; void setVersion(int); QDataStream &operator>>(char &i); QDataStream &operator>>(qint8 &i); QDataStream &operator>>(quint8 &i); QDataStream &operator>>(qint16 &i); QDataStream &operator>>(quint16 &i); QDataStream &operator>>(qint32 &i); inline QDataStream &operator>>(quint32 &i); QDataStream &operator>>(qint64 &i); QDataStream &operator>>(quint64 &i); 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); QDataStream &operator>>(char16_t &c); QDataStream &operator>>(char32_t &c); QDataStream &operator<<(char i); QDataStream &operator<<(qint8 i); QDataStream &operator<<(quint8 i); QDataStream &operator<<(qint16 i); QDataStream &operator<<(quint16 i); QDataStream &operator<<(qint32 i); inline QDataStream &operator<<(quint32 i); QDataStream &operator<<(qint64 i); QDataStream &operator<<(quint64 i); QDataStream &operator<<(std::nullptr_t) { 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<<(const char *str); QDataStream &operator<<(char16_t c); QDataStream &operator<<(char32_t c); QDataStream &operator<<(const volatile void *) = delete; #if QT_CORE_REMOVED_SINCE(6, 7) QDataStream &readBytes(char *&, uint &len); QDataStream &writeBytes(const char *, uint len); int skipRawData(int len); #endif #if QT_CORE_REMOVED_SINCE(6, 7) && QT_POINTER_SIZE != 4 int readRawData(char *, int len); int writeRawData(const char *, int len); #endif QDataStream &readBytes(char *&, qsizetype &len); qsizetype readRawData(char *, qsizetype len); QDataStream &writeBytes(const char *, qsizetype len); qsizetype writeRawData(const char *, qsizetype len); qint64 skipRawData(qint64 len); void startTransaction(); bool commitTransaction(); void rollbackTransaction(); void abortTransaction(); bool isDeviceTransactionStarted() const; private: Q_DISABLE_COPY(QDataStream) QScopedPointer d; QIODevice *dev; bool owndev; bool noswap; ByteOrder byteorder; int ver; Status q_status; #if QT_CORE_REMOVED_SINCE(6, 7) && QT_POINTER_SIZE != 4 int readBlock(char *data, int len); #endif qsizetype readBlock(char *data, qsizetype len); static inline qint64 readQSizeType(QDataStream &s); static inline void writeQSizeType(QDataStream &s, qint64 value); enum class QDataStreamSizes : quint32 { NullCode = 0xffffffffu, 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 friend QDataStream &QtPrivate::readArrayBasedContainer(QDataStream &s, Container &c); template friend QDataStream &QtPrivate::readListBasedContainer(QDataStream &s, Container &c); template friend QDataStream &QtPrivate::readAssociativeContainer(QDataStream &s, Container &c); template friend QDataStream &QtPrivate::writeSequentialContainer(QDataStream &s, const Container &c); template friend QDataStream &QtPrivate::writeAssociativeContainer(QDataStream &s, const Container &c); template friend QDataStream &QtPrivate::writeAssociativeMultiContainer(QDataStream &s, const Container &c); }; namespace QtPrivate { class StreamStateSaver { public: inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status()) { if (!stream->isDeviceTransactionStarted()) stream->resetStatus(); } inline ~StreamStateSaver() { if (oldStatus != QDataStream::Ok) { stream->resetStatus(); stream->setStatus(oldStatus); } } private: QDataStream *stream; QDataStream::Status oldStatus; }; template QDataStream &readArrayBasedContainer(QDataStream &s, Container &c) { StreamStateSaver stateSaver(&s); c.clear(); qint64 size = QDataStream::readQSizeType(s); qsizetype n = size; if (size != n || size < 0) { s.setStatus(QDataStream::ReadCorruptData); return s; } c.reserve(n); for (qsizetype i = 0; i < n; ++i) { typename Container::value_type t; s >> t; if (s.status() != QDataStream::Ok) { c.clear(); break; } c.append(t); } return s; } template QDataStream &readListBasedContainer(QDataStream &s, Container &c) { StreamStateSaver stateSaver(&s); c.clear(); qint64 size = QDataStream::readQSizeType(s); qsizetype n = size; if (size != n || size < 0) { s.setStatus(QDataStream::ReadCorruptData); return s; } for (qsizetype i = 0; i < n; ++i) { typename Container::value_type t; s >> t; if (s.status() != QDataStream::Ok) { c.clear(); break; } c << t; } return s; } template QDataStream &readAssociativeContainer(QDataStream &s, Container &c) { StreamStateSaver stateSaver(&s); c.clear(); qint64 size = QDataStream::readQSizeType(s); qsizetype n = size; if (size != n || size < 0) { s.setStatus(QDataStream::ReadCorruptData); return s; } for (qsizetype i = 0; i < n; ++i) { typename Container::key_type k; typename Container::mapped_type t; s >> k >> t; if (s.status() != QDataStream::Ok) { c.clear(); break; } c.insert(k, t); } return s; } template QDataStream &writeSequentialContainer(QDataStream &s, const Container &c) { QDataStream::writeQSizeType(s, c.size()); for (const typename Container::value_type &t : c) s << t; return s; } template QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c) { QDataStream::writeQSizeType(s, c.size()); auto it = c.constBegin(); auto end = c.constEnd(); while (it != end) { s << it.key() << it.value(); ++it; } return s; } template QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c) { QDataStream::writeQSizeType(s, c.size()); auto it = c.constBegin(); auto end = c.constEnd(); while (it != end) { const auto rangeStart = it++; while (it != end && rangeStart.key() == it.key()) ++it; const qint64 last = std::distance(rangeStart, it) - 1; for (qint64 i = last; i >= 0; --i) { auto next = std::next(rangeStart, i); s << next.key() << next.value(); } } return s; } } // QtPrivate namespace template using QDataStreamIfHasOStreamOperators = std::enable_if_t...>, QDataStream &>; template using QDataStreamIfHasOStreamOperatorsContainer = std::enable_if_t...>, QDataStream &>; template using QDataStreamIfHasIStreamOperators = std::enable_if_t...>, QDataStream &>; template using QDataStreamIfHasIStreamOperatorsContainer = std::enable_if_t...>, QDataStream &>; /***************************************************************************** QDataStream inline functions *****************************************************************************/ inline QIODevice *QDataStream::device() const { return dev; } inline QDataStream::ByteOrder QDataStream::byteOrder() const { return byteorder; } inline int QDataStream::version() const { return ver; } inline void QDataStream::setVersion(int v) { ver = v; } qint64 QDataStream::readQSizeType(QDataStream &s) { quint32 first; s >> first; if (first == quint32(QDataStreamSizes::NullCode)) return -1; if (first < quint32(QDataStreamSizes::ExtendedSize) || s.version() < QDataStream::Qt_6_7) return qint64(first); qint64 extendedLen; s >> extendedLen; return extendedLen; } void QDataStream::writeQSizeType(QDataStream &s, qint64 value) { if (value < qint64(QDataStreamSizes::ExtendedSize)) s << quint32(value); else if (s.version() >= QDataStream::Qt_6_7) s << quint32(QDataStreamSizes::ExtendedSize) << value; else if (value == qint64(QDataStreamSizes::ExtendedSize)) s << quint32(QDataStreamSizes::ExtendedSize); else s.setStatus(QDataStream::WriteFailed); // value is too big for old format } inline QDataStream &QDataStream::operator>>(char &i) { return *this >> reinterpret_cast(i); } inline QDataStream &QDataStream::operator>>(quint8 &i) { return *this >> reinterpret_cast(i); } inline QDataStream &QDataStream::operator>>(quint16 &i) { return *this >> reinterpret_cast(i); } inline QDataStream &QDataStream::operator>>(quint32 &i) { return *this >> reinterpret_cast(i); } inline QDataStream &QDataStream::operator>>(quint64 &i) { return *this >> reinterpret_cast(i); } inline QDataStream &QDataStream::operator<<(char i) { return *this << qint8(i); } inline QDataStream &QDataStream::operator<<(quint8 i) { return *this << qint8(i); } inline QDataStream &QDataStream::operator<<(quint16 i) { return *this << qint16(i); } inline QDataStream &QDataStream::operator<<(quint32 i) { return *this << qint32(i); } inline QDataStream &QDataStream::operator<<(quint64 i) { return *this << qint64(i); } template inline QDataStream &operator<<(QDataStream &s, QFlags e) { return s << typename QFlags::Int(e); } template inline QDataStream &operator>>(QDataStream &s, QFlags &e) { typename QFlags::Int i; s >> i; e = QFlag(i); return s; } template typename std::enable_if_t::value, QDataStream &> operator<<(QDataStream &s, const T &t) { return s << static_cast::type>(t); } template typename std::enable_if_t::value, QDataStream &> operator>>(QDataStream &s, T &t) { return s >> reinterpret_cast::type &>(t); } #ifndef Q_QDOC template inline QDataStreamIfHasIStreamOperatorsContainer, T> operator>>(QDataStream &s, QList &v) { return QtPrivate::readArrayBasedContainer(s, v); } template inline QDataStreamIfHasOStreamOperatorsContainer, T> operator<<(QDataStream &s, const QList &v) { return QtPrivate::writeSequentialContainer(s, v); } template inline QDataStreamIfHasIStreamOperatorsContainer, T> operator>>(QDataStream &s, QSet &set) { return QtPrivate::readListBasedContainer(s, set); } template inline QDataStreamIfHasOStreamOperatorsContainer, T> operator<<(QDataStream &s, const QSet &set) { return QtPrivate::writeSequentialContainer(s, set); } template inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QHash &hash) { return QtPrivate::readAssociativeContainer(s, hash); } template inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QHash &hash) { return QtPrivate::writeAssociativeContainer(s, hash); } template inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMultiHash &hash) { return QtPrivate::readAssociativeContainer(s, hash); } template inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMultiHash &hash) { return QtPrivate::writeAssociativeMultiContainer(s, hash); } template inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMap &map) { return QtPrivate::readAssociativeContainer(s, map); } template inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMap &map) { return QtPrivate::writeAssociativeContainer(s, map); } template inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMultiMap &map) { return QtPrivate::readAssociativeContainer(s, map); } template inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMultiMap &map) { return QtPrivate::writeAssociativeMultiContainer(s, map); } template inline QDataStreamIfHasIStreamOperators operator>>(QDataStream& s, std::pair &p) { s >> p.first >> p.second; return s; } template inline QDataStreamIfHasOStreamOperators operator<<(QDataStream& s, const std::pair &p) { s << p.first << p.second; return s; } #else template QDataStream &operator>>(QDataStream &s, QList &l); template QDataStream &operator<<(QDataStream &s, const QList &l); template QDataStream &operator>>(QDataStream &s, QSet &set); template QDataStream &operator<<(QDataStream &s, const QSet &set); template QDataStream &operator>>(QDataStream &s, QHash &hash); template QDataStream &operator<<(QDataStream &s, const QHash &hash); template QDataStream &operator>>(QDataStream &s, QMultiHash &hash); template QDataStream &operator<<(QDataStream &s, const QMultiHash &hash); template QDataStream &operator>>(QDataStream &s, QMap &map); template QDataStream &operator<<(QDataStream &s, const QMap &map); template QDataStream &operator>>(QDataStream &s, QMultiMap &map); template QDataStream &operator<<(QDataStream &s, const QMultiMap &map); template QDataStream &operator>>(QDataStream& s, std::pair &p); template QDataStream &operator<<(QDataStream& s, const std::pair &p); #endif // Q_QDOC inline QDataStream &operator>>(QDataStream &s, QKeyCombination &combination) { int combined; s >> combined; combination = QKeyCombination::fromCombined(combined); return s; } inline QDataStream &operator<<(QDataStream &s, QKeyCombination combination) { return s << combination.toCombined(); } #endif // QT_NO_DATASTREAM QT_END_NAMESPACE #endif // QDATASTREAM_H