diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-09-30 10:41:58 (GMT) |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-09-30 10:46:00 (GMT) |
commit | 5170432e7cb2d0d1adf7ac2ec1ece627c75470f3 (patch) | |
tree | e9cca0ad6ba6c59ce1c0477542808e0f063dd7ac /src | |
parent | 45d5832a504516219167f0205901c56035118944 (diff) | |
download | Qt-5170432e7cb2d0d1adf7ac2ec1ece627c75470f3.zip Qt-5170432e7cb2d0d1adf7ac2ec1ece627c75470f3.tar.gz Qt-5170432e7cb2d0d1adf7ac2ec1ece627c75470f3.tar.bz2 |
Fix floating point precision when using qreal with QDataStream
A frequent bug when using QDataStream across platforms where the size
of qreal is different (such as any desktop platform and an ARM device)
is that you end up using different overloads for streaming the value
in and out (e.g. operator>>(double) on desktop and operator<<(float) on
ARM.)
This can leads to crashes and data corruption. To avoid the problem,
we define a single floating point precision for the entire data stream
and allow this to be set by the user. The default is to use 64-bit
precision for all floating point numbers.
Reviewed-by: Samuel
Reviewed-by: Thiago
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/io/io.pri | 1 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.cpp | 102 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 13 |
3 files changed, 107 insertions, 9 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index bca9baa..02a1586 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -5,6 +5,7 @@ HEADERS += \ io/qabstractfileengine_p.h \ io/qbuffer.h \ io/qdatastream.h \ + io/qdatastream_p.h \ io/qdebug.h \ io/qdir.h \ io/qdiriterator.h \ diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 9339b8e..cc62201 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdatastream.h" +#include "qdatastream_p.h" #ifndef QT_NO_DATASTREAM #include "qbuffer.h" @@ -193,6 +194,21 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QDataStream::FloatingPointPrecision + + The precision of floating point numbers used for reading/writing the data. This will only have + an effect if the version of the data stream is Qt_4_6 or higher. + + \warning The floating point precision must be set to the same value on the object that writes + and the object that reads the data stream. + + \value SinglePrecision All floating point numbers in the data stream have 32-bit precision. + \value DoublePrecision All floating point numbers in the data stream have 64-bit precision. + + \sa setFloatingPointPrecision(), floatingPointPrecision() +*/ + +/*! \enum QDataStream::Status This enum describes the current status of the data stream. @@ -222,7 +238,7 @@ QT_BEGIN_NAMESPACE #endif enum { - DefaultStreamVersion = QDataStream::Qt_4_5 + DefaultStreamVersion = QDataStream::Qt_4_6 }; // ### 5.0: when streaming invalid QVariants, just the type should @@ -414,6 +430,42 @@ bool QDataStream::atEnd() const } /*! + Returns the floating point precision of the data stream. + + \since 4.6 + + \sa FloatingPointPrecision setFloatingPointPrecision() +*/ +QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const +{ + return d == 0 ? QDataStream::DoublePrecision : d->floatingPointPrecision; +} + +/*! + Sets the floating point precision of the data stream. If the floating point precision is + DoublePrecision and the version of the data stream is Qt_4_6 or higher, all floating point + numbers will be written and read with 64-bit precision. If the floating point precision is + SinglePrecision and the version is Qt_4_6 or higher, all floating point numbers will be written + and read with 32-bit precision. + + For versions prior to Qt_4_6, the precision of floating point numbers in the data stream depends + on the stream operator called. + + The default is DoublePrecision. + + \warning This property must be set to the same value on the object that writes and the object + that reads the data stream. + + \since 4.6 +*/ +void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision) +{ + if (d == 0) + d.reset(new QDataStreamPrivate()); + d->floatingPointPrecision = precision; +} + +/*! Returns the status of the data stream. \sa Status setStatus() resetStatus() @@ -517,7 +569,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_3 Version 9 (Qt 4.3) \value Qt_4_4 Version 10 (Qt 4.4) \value Qt_4_5 Version 11 (Qt 4.5) - \omitvalue Qt_4_6 + \value Qt_4_6 Version 12 (Qt 4.6) \sa setVersion(), version() */ @@ -754,13 +806,23 @@ QDataStream &QDataStream::operator>>(bool &i) /*! \overload - Reads a 32-bit floating point number from the stream into \a f, + Reads a floating point number from the stream into \a f, using the standard IEEE 754 format. Returns a reference to the stream. + + \sa setFloatingPointPrecision() */ QDataStream &QDataStream::operator>>(float &f) -{ +{ + if (version() >= QDataStream::Qt_4_6 + && floatingPointPrecision() == QDataStream::DoublePrecision) { + double d; + *this >> d; + f = d; + return *this; + } + f = 0.0f; CHECK_STREAM_PRECOND(*this) if (noswap) { @@ -796,13 +858,23 @@ QDataStream &QDataStream::operator>>(float &f) /*! \overload - Reads a 64-bit floating point number from the stream into \a f, + Reads a floating point number from the stream into \a f, using the standard IEEE 754 format. Returns a reference to the stream. + + \sa setFloatingPointPrecision() */ QDataStream &QDataStream::operator>>(double &f) { + if (version() >= QDataStream::Qt_4_6 + && floatingPointPrecision() == QDataStream::SinglePrecision) { + float d; + *this >> d; + f = d; + return *this; + } + f = 0.0; CHECK_STREAM_PRECOND(*this) #ifndef Q_DOUBLE_FORMAT @@ -1115,12 +1187,20 @@ QDataStream &QDataStream::operator<<(bool i) /*! \overload - Writes a 32-bit floating point number, \a f, to the stream using + Writes a floating point number, \a f, to the stream using the standard IEEE 754 format. Returns a reference to the stream. + + \sa setFloatingPointPrecision() */ QDataStream &QDataStream::operator<<(float f) { + if (version() >= QDataStream::Qt_4_6 + && floatingPointPrecision() == QDataStream::DoublePrecision) { + *this << double(f); + return *this; + } + CHECK_STREAM_PRECOND(*this) float g = f; // fixes float-on-stack problem if (noswap) { // no conversion needed @@ -1146,12 +1226,20 @@ QDataStream &QDataStream::operator<<(float f) /*! \overload - Writes a 64-bit floating point number, \a f, to the stream using + Writes a floating point number, \a f, to the stream using the standard IEEE 754 format. Returns a reference to the stream. + + \sa setFloatingPointPrecision() */ QDataStream &QDataStream::operator<<(double f) { + if (version() >= QDataStream::Qt_4_6 + && floatingPointPrecision() == QDataStream::SinglePrecision) { + *this << float(f); + return *this; + } + CHECK_STREAM_PRECOND(*this) #ifndef Q_DOUBLE_FORMAT if (noswap) { diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index b376de6..6e83204 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -42,6 +42,7 @@ #ifndef QDATASTREAM_H #define QDATASTREAM_H +#include <QtCore/qscopedpointer.h> #include <QtCore/qiodevice.h> #include <QtCore/qglobal.h> @@ -83,7 +84,7 @@ public: Qt_4_3 = 9, Qt_4_4 = 10, Qt_4_5 = 11, - Qt_4_6 = Qt_4_5 + Qt_4_6 = 12, #if QT_VERSION >= 0x040700 #error Add the datastream version for this Qt version Qt_4_7 = Qt_4_6 @@ -101,6 +102,11 @@ public: ReadCorruptData }; + enum FloatingPointPrecision { + SinglePrecision, + DoublePrecision + }; + QDataStream(); explicit QDataStream(QIODevice *); #ifdef QT3_SUPPORT @@ -123,6 +129,9 @@ public: void setStatus(Status status); void resetStatus(); + FloatingPointPrecision floatingPointPrecision() const; + void setFloatingPointPrecision(FloatingPointPrecision precision); + ByteOrder byteOrder() const; void setByteOrder(ByteOrder); @@ -176,7 +185,7 @@ public: private: Q_DISABLE_COPY(QDataStream) - QDataStreamPrivate *d; + QScopedPointer<QDataStreamPrivate> d; QIODevice *dev; bool owndev; |