From 3c93286f08a80b6e1821d7d63d361742b25c6578 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Mon, 13 Jun 2016 17:25:34 +0300 Subject: QDataStream: unify deserialization of containers Serialization of the Qt container classes is accomplished by breaking up the data into primitive units. On the receiver side, these units should be read atomically to guarantee integrity of the container. Deserialization procedures for QHash and QMap were already implemented in accordance with this strategy and have the following behavior: - a previously latched error status is saved for the caller. This overrides possible different errors in the current read. This is consistent with the treatment of primitive types. - if an error occurs during the deserialization, the container is cleared. To make the API consistent, this patch adjusts the behavior of QList, QLinkedList, QVector, and QSet deserialization. On the implementation side we accomplish this with a private StreamStateSaver RAII class that consolidates the handling of the stream status for all containers. [ChangeLog][Important Behavior Changes][QtCore][QDataStream] Incomplete reads of Qt containers are now handled same way as for primitive types, meaning that previous errors are latched. Task-number: QTBUG-54022 Change-Id: I5c77257fe2a4637e8a7e6cf3cd43091c8469340e Reviewed-by: Oswald Buddenhagen Reviewed-by: Edward Welbourne --- src/corelib/io/qdatastream.h | 75 ++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 20 deletions(-) (limited to 'src/corelib/io/qdatastream.h') diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index e0a9cccdad..260dd519e3 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -194,6 +194,29 @@ private: int readBlock(char *data, int len); }; +namespace QtPrivate { + +class StreamStateSaver +{ +public: + inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status()) + { + stream->resetStatus(); + } + inline ~StreamStateSaver() + { + if (oldStatus != QDataStream::Ok) { + stream->resetStatus(); + stream->setStatus(oldStatus); + } + } + +private: + QDataStream *stream; + QDataStream::Status oldStatus; +}; + +} // QtPrivate namespace /***************************************************************************** QDataStream inline functions @@ -238,6 +261,8 @@ inline QDataStream &QDataStream::operator<<(quint64 i) template QDataStream& operator>>(QDataStream& s, QList& l) { + QtPrivate::StreamStateSaver stateSaver(&s); + l.clear(); quint32 c; s >> c; @@ -246,10 +271,13 @@ QDataStream& operator>>(QDataStream& s, QList& l) { T t; s >> t; - l.append(t); - if (s.atEnd()) + if (s.status() != QDataStream::Ok) { + l.clear(); break; + } + l.append(t); } + return s; } @@ -265,6 +293,8 @@ QDataStream& operator<<(QDataStream& s, const QList& l) template QDataStream& operator>>(QDataStream& s, QLinkedList& l) { + QtPrivate::StreamStateSaver stateSaver(&s); + l.clear(); quint32 c; s >> c; @@ -272,10 +302,13 @@ QDataStream& operator>>(QDataStream& s, QLinkedList& l) { T t; s >> t; - l.append(t); - if (s.atEnd()) + if (s.status() != QDataStream::Ok) { + l.clear(); break; + } + l.append(t); } + return s; } @@ -292,6 +325,8 @@ QDataStream& operator<<(QDataStream& s, const QLinkedList& l) template QDataStream& operator>>(QDataStream& s, QVector& v) { + QtPrivate::StreamStateSaver stateSaver(&s); + v.clear(); quint32 c; s >> c; @@ -299,8 +334,13 @@ QDataStream& operator>>(QDataStream& s, QVector& v) for(quint32 i = 0; i < c; ++i) { T t; s >> t; + if (s.status() != QDataStream::Ok) { + v.clear(); + break; + } v[i] = t; } + return s; } @@ -316,16 +356,21 @@ QDataStream& operator<<(QDataStream& s, const QVector& v) template QDataStream &operator>>(QDataStream &in, QSet &set) { + QtPrivate::StreamStateSaver stateSaver(&in); + set.clear(); quint32 c; in >> c; for (quint32 i = 0; i < c; ++i) { T t; in >> t; - set << t; - if (in.atEnd()) + if (in.status() != QDataStream::Ok) { + set.clear(); break; + } + set << t; } + return in; } @@ -344,10 +389,9 @@ QDataStream& operator<<(QDataStream &out, const QSet &set) template Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash &hash) { - QDataStream::Status oldStatus = in.status(); - in.resetStatus(); - hash.clear(); + QtPrivate::StreamStateSaver stateSaver(&in); + hash.clear(); quint32 n; in >> n; @@ -363,10 +407,6 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash &has if (in.status() != QDataStream::Ok) hash.clear(); - if (oldStatus != QDataStream::Ok) { - in.resetStatus(); - in.setStatus(oldStatus); - } return in; } @@ -390,10 +430,9 @@ template Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap &map) #endif { - QDataStream::Status oldStatus = in.status(); - in.resetStatus(); - map.clear(); + QtPrivate::StreamStateSaver stateSaver(&in); + map.clear(); quint32 n; in >> n; @@ -409,10 +448,6 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap &ma } if (in.status() != QDataStream::Ok) map.clear(); - if (oldStatus != QDataStream::Ok) { - in.resetStatus(); - in.setStatus(oldStatus); - } return in; } -- cgit v1.2.3