diff options
Diffstat (limited to 'src/corelib/serialization/qdatastream.cpp')
-rw-r--r-- | src/corelib/serialization/qdatastream.cpp | 1400 |
1 files changed, 1400 insertions, 0 deletions
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp new file mode 100644 index 0000000000..8f419a4a46 --- /dev/null +++ b/src/corelib/serialization/qdatastream.cpp @@ -0,0 +1,1400 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qdatastream.h" +#include "qdatastream_p.h" + +#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED) +#include "qbuffer.h" +#include "qfloat16.h" +#include "qstring.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include "qendian.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDataStream + \inmodule QtCore + \reentrant + \brief The QDataStream class provides serialization of binary data + to a QIODevice. + + \ingroup io + + + A data stream is a binary stream of encoded information which is + 100% independent of the host computer's operating system, CPU or + byte order. For example, a data stream that is written by a PC + under Windows can be read by a Sun SPARC running Solaris. + + You can also use a data stream to read/write \l{raw}{raw + unencoded binary data}. If you want a "parsing" input stream, see + QTextStream. + + The QDataStream class implements the serialization of C++'s basic + data types, like \c char, \c short, \c int, \c{char *}, etc. + Serialization of more complex data is accomplished by breaking up + the data into primitive units. + + A data stream cooperates closely with a QIODevice. A QIODevice + represents an input/output medium one can read data from and write + data to. The QFile class is an example of an I/O device. + + Example (write binary data to a stream): + + \snippet code/src_corelib_io_qdatastream.cpp 0 + + Example (read binary data from a stream): + + \snippet code/src_corelib_io_qdatastream.cpp 1 + + Each item written to the stream is written in a predefined binary + format that varies depending on the item's type. Supported Qt + types include QBrush, QColor, QDateTime, QFont, QPixmap, QString, + QVariant and many others. For the complete list of all Qt types + supporting data streaming see \l{Serializing Qt Data Types}. + + For integers it is best to always cast to a Qt integer type for + writing, and to read back into the same Qt integer type. This + ensures that you get integers of the size you want and insulates + you from compiler and platform differences. + + To take one example, a \c{char *} string is written as a 32-bit + integer equal to the length of the string including the '\\0' byte, + followed by all the characters of the string including the + '\\0' byte. When reading a \c{char *} string, 4 bytes are read to + create the 32-bit length value, then that many characters for the + \c {char *} string including the '\\0' terminator are read. + + The initial I/O device is usually set in the constructor, but can be + changed with setDevice(). If you've reached the end of the data + (or if there is no I/O device set) atEnd() will return true. + + \section1 Versioning + + QDataStream's binary format has evolved since Qt 1.0, and is + likely to continue evolving to reflect changes done in Qt. When + inputting or outputting complex types, it's very important to + make sure that the same version of the stream (version()) is used + for reading and writing. If you need both forward and backward + compatibility, you can hardcode the version number in the + application: + + \snippet code/src_corelib_io_qdatastream.cpp 2 + + If you are producing a new binary data format, such as a file + format for documents created by your application, you could use a + QDataStream to write the data in a portable format. Typically, you + would write a brief header containing a magic string and a version + number to give yourself room for future expansion. For example: + + \snippet code/src_corelib_io_qdatastream.cpp 3 + + Then read it in with: + + \snippet code/src_corelib_io_qdatastream.cpp 4 + + You can select which byte order to use when serializing data. The + default setting is big endian (MSB first). Changing it to little + endian breaks the portability (unless the reader also changes to + little endian). We recommend keeping this setting unless you have + special requirements. + + \target raw + \section1 Reading and Writing Raw Binary Data + + You may wish to read/write your own raw binary data to/from the + data stream directly. Data may be read from the stream into a + preallocated \c{char *} using readRawData(). Similarly data can be + written to the stream using writeRawData(). Note that any + encoding/decoding of the data must be done by you. + + A similar pair of functions is readBytes() and writeBytes(). These + differ from their \e raw counterparts as follows: readBytes() + reads a quint32 which is taken to be the length of the data to be + read, then that number of bytes is read into the preallocated + \c{char *}; writeBytes() writes a quint32 containing the length of the + data, followed by the data. Note that any encoding/decoding of + the data (apart from the length quint32) must be done by you. + + \section1 Reading and Writing Qt Collection Classes + + The Qt container classes can also be serialized to a QDataStream. + These include QList, QLinkedList, QVector, QSet, QHash, and QMap. + The stream operators are declared as non-members of the classes. + + \target Serializing Qt Classes + \section1 Reading and Writing Other Qt Classes + + In addition to the overloaded stream operators documented here, + any Qt classes that you might want to serialize to a QDataStream + will have appropriate stream operators declared as non-member of + the class: + + \code + QDataStream &operator<<(QDataStream &, const QXxx &); + QDataStream &operator>>(QDataStream &, QXxx &); + \endcode + + For example, here are the stream operators declared as non-members + of the QImage class: + + \code + QDataStream & operator<< (QDataStream& stream, const QImage& image); + QDataStream & operator>> (QDataStream& stream, QImage& image); + \endcode + + To see if your favorite Qt class has similar stream operators + defined, check the \b {Related Non-Members} section of the + class's documentation page. + + \section1 Using Read Transactions + + When a data stream operates on an asynchronous device, the chunks of data + can arrive at arbitrary points in time. The QDataStream class implements + a transaction mechanism that provides the ability to read the data + atomically with a series of stream operators. As an example, you can + handle incomplete reads from a socket by using a transaction in a slot + connected to the readyRead() signal: + + \snippet code/src_corelib_io_qdatastream.cpp 6 + + If no full packet is received, this code restores the stream to the + initial position, after which you need to wait for more data to arrive. + + \sa QTextStream, QVariant +*/ + +/*! + \enum QDataStream::ByteOrder + + The byte order used for reading/writing the data. + + \value BigEndian Most significant byte first (the default) + \value LittleEndian Least significant byte first +*/ + +/*! + \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. + + \value Ok The data stream is operating normally. + \value ReadPastEnd The data stream has read past the end of the + data in the underlying device. + \value ReadCorruptData The data stream has read corrupt data. + \value WriteFailed The data stream cannot write to the underlying device. +*/ + +/***************************************************************************** + QDataStream member functions + *****************************************************************************/ + +#define Q_VOID + +#undef CHECK_STREAM_PRECOND +#ifndef QT_NO_DEBUG +#define CHECK_STREAM_PRECOND(retVal) \ + if (!dev) { \ + qWarning("QDataStream: No device"); \ + return retVal; \ + } +#else +#define CHECK_STREAM_PRECOND(retVal) \ + if (!dev) { \ + return retVal; \ + } +#endif + +#define CHECK_STREAM_WRITE_PRECOND(retVal) \ + CHECK_STREAM_PRECOND(retVal) \ + if (q_status != Ok) \ + return retVal; + +#define CHECK_STREAM_TRANSACTION_PRECOND(retVal) \ + if (!d || d->transactionDepth == 0) { \ + qWarning("QDataStream: No transaction in progress"); \ + return retVal; \ + } + +/*! + Constructs a data stream that has no I/O device. + + \sa setDevice() +*/ + +QDataStream::QDataStream() +{ + dev = 0; + owndev = false; + byteorder = BigEndian; + ver = Qt_DefaultCompiledVersion; + noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian; + q_status = Ok; +} + +/*! + Constructs a data stream that uses the I/O device \a d. + + \sa setDevice(), device() +*/ + +QDataStream::QDataStream(QIODevice *d) +{ + dev = d; // set device + owndev = false; + byteorder = BigEndian; // default byte order + ver = Qt_DefaultCompiledVersion; + noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian; + q_status = Ok; +} + +/*! + \fn QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode mode) + + Constructs a data stream that operates on a byte array, \a a. The + \a mode describes how the device is to be used. + + Alternatively, you can use QDataStream(const QByteArray &) if you + just want to read from a byte array. + + Since QByteArray is not a QIODevice subclass, internally a QBuffer + is created to wrap the byte array. +*/ + +QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode flags) +{ + QBuffer *buf = new QBuffer(a); +#ifndef QT_NO_QOBJECT + buf->blockSignals(true); +#endif + buf->open(flags); + dev = buf; + owndev = true; + byteorder = BigEndian; + ver = Qt_DefaultCompiledVersion; + noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian; + q_status = Ok; +} + +/*! + Constructs a read-only data stream that operates on byte array \a a. + Use QDataStream(QByteArray*, int) if you want to write to a byte + array. + + Since QByteArray is not a QIODevice subclass, internally a QBuffer + is created to wrap the byte array. +*/ +QDataStream::QDataStream(const QByteArray &a) +{ + QBuffer *buf = new QBuffer; +#ifndef QT_NO_QOBJECT + buf->blockSignals(true); +#endif + buf->setData(a); + buf->open(QIODevice::ReadOnly); + dev = buf; + owndev = true; + byteorder = BigEndian; + ver = Qt_DefaultCompiledVersion; + noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian; + q_status = Ok; +} + +/*! + Destroys the data stream. + + The destructor will not affect the current I/O device, unless it is + an internal I/O device (e.g. a QBuffer) processing a QByteArray + passed in the \e constructor, in which case the internal I/O device + is destroyed. +*/ + +QDataStream::~QDataStream() +{ + if (owndev) + delete dev; +} + + +/*! + \fn QIODevice *QDataStream::device() const + + Returns the I/O device currently set, or 0 if no + device is currently set. + + \sa setDevice() +*/ + +/*! + void QDataStream::setDevice(QIODevice *d) + + Sets the I/O device to \a d, which can be 0 + to unset to current I/O device. + + \sa device() +*/ + +void QDataStream::setDevice(QIODevice *d) +{ + if (owndev) { + delete dev; + owndev = false; + } + dev = d; +} + +/*! + \obsolete + Unsets the I/O device. + Use setDevice(0) instead. +*/ + +void QDataStream::unsetDevice() +{ + setDevice(0); +} + + +/*! + \fn bool QDataStream::atEnd() const + + Returns \c true if the I/O device has reached the end position (end of + the stream or file) or if there is no I/O device set; otherwise + returns \c false. + + \sa QIODevice::atEnd() +*/ + +bool QDataStream::atEnd() const +{ + return dev ? dev->atEnd() : true; +} + +/*! + 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 to \a precision. 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. + + Note that this property does not affect the serialization or deserialization of \c qfloat16 + instances. + + \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() +*/ + +QDataStream::Status QDataStream::status() const +{ + return q_status; +} + +/*! + Resets the status of the data stream. + + \sa Status, status(), setStatus() +*/ +void QDataStream::resetStatus() +{ + q_status = Ok; +} + +/*! + Sets the status of the data stream to the \a status given. + + Subsequent calls to setStatus() are ignored until resetStatus() + is called. + + \sa Status, status(), resetStatus() +*/ +void QDataStream::setStatus(Status status) +{ + if (q_status == Ok) + q_status = status; +} + +/*! + \fn int QDataStream::byteOrder() const + + Returns the current byte order setting -- either BigEndian or + LittleEndian. + + \sa setByteOrder() +*/ + +/*! + Sets the serialization byte order to \a bo. + + The \a bo parameter can be QDataStream::BigEndian or + QDataStream::LittleEndian. + + The default setting is big endian. We recommend leaving this + setting unless you have special requirements. + + \sa byteOrder() +*/ + +void QDataStream::setByteOrder(ByteOrder bo) +{ + byteorder = bo; + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) + noswap = (byteorder == BigEndian); + else + noswap = (byteorder == LittleEndian); +} + + +/*! + \enum QDataStream::Version + + This enum provides symbolic synonyms for the data serialization + format version numbers. + + \value Qt_1_0 Version 1 (Qt 1.x) + \value Qt_2_0 Version 2 (Qt 2.0) + \value Qt_2_1 Version 3 (Qt 2.1, 2.2, 2.3) + \value Qt_3_0 Version 4 (Qt 3.0) + \value Qt_3_1 Version 5 (Qt 3.1, 3.2) + \value Qt_3_3 Version 6 (Qt 3.3) + \value Qt_4_0 Version 7 (Qt 4.0, Qt 4.1) + \value Qt_4_1 Version 7 (Qt 4.0, Qt 4.1) + \value Qt_4_2 Version 8 (Qt 4.2) + \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) + \value Qt_4_6 Version 12 (Qt 4.6, Qt 4.7, Qt 4.8) + \value Qt_4_7 Same as Qt_4_6. + \value Qt_4_8 Same as Qt_4_6. + \value Qt_4_9 Same as Qt_4_6. + \value Qt_5_0 Version 13 (Qt 5.0) + \value Qt_5_1 Version 14 (Qt 5.1) + \value Qt_5_2 Version 15 (Qt 5.2) + \value Qt_5_3 Same as Qt_5_2 + \value Qt_5_4 Version 16 (Qt 5.4) + \value Qt_5_5 Same as Qt_5_4 + \value Qt_5_6 Version 17 (Qt 5.6) + \value Qt_5_7 Same as Qt_5_6 + \value Qt_5_8 Same as Qt_5_6 + \value Qt_5_9 Same as Qt_5_6 + \value Qt_5_10 Same as Qt_5_6 + \value Qt_5_11 Same as Qt_5_6 + \omitvalue Qt_DefaultCompiledVersion + + \sa setVersion(), version() +*/ + +/*! + \fn int QDataStream::version() const + + Returns the version number of the data serialization format. + + \sa setVersion(), Version +*/ + +/*! + \fn void QDataStream::setVersion(int v) + + Sets the version number of the data serialization format to \a v, + a value of the \l Version enum. + + You don't \e have to set a version if you are using the current + version of Qt, but for your own custom binary formats we + recommend that you do; see \l{Versioning} in the Detailed + Description. + + To accommodate new functionality, the datastream serialization + format of some Qt classes has changed in some versions of Qt. If + you want to read data that was created by an earlier version of + Qt, or write data that can be read by a program that was compiled + with an earlier version of Qt, use this function to modify the + serialization format used by QDataStream. + + The \l Version enum provides symbolic constants for the different + versions of Qt. For example: + + \snippet code/src_corelib_io_qdatastream.cpp 5 + + \sa version(), Version +*/ + +/*! + \since 5.7 + + Starts a new read transaction on the stream. + + Defines a restorable point within the sequence of read operations. For + sequential devices, read data will be duplicated internally to allow + recovery in case of incomplete reads. For random-access devices, + this function saves the current position of the stream. Call + commitTransaction(), rollbackTransaction(), or abortTransaction() to + finish the current transaction. + + Once a transaction is started, subsequent calls to this function will make + the transaction recursive. Inner transactions act as agents of the + outermost transaction (i.e., report the status of read operations to the + outermost transaction, which can restore the position of the stream). + + \note Restoring to the point of the nested startTransaction() call is not + supported. + + When an error occurs during a transaction (including an inner transaction + failing), reading from the data stream is suspended (all subsequent read + operations return empty/zero values) and subsequent inner transactions are + forced to fail. Starting a new outermost transaction recovers from this + state. This behavior makes it unnecessary to error-check every read + operation separately. + + \sa commitTransaction(), rollbackTransaction(), abortTransaction() +*/ + +void QDataStream::startTransaction() +{ + CHECK_STREAM_PRECOND(Q_VOID) + + if (d == 0) + d.reset(new QDataStreamPrivate()); + + if (++d->transactionDepth == 1) { + dev->startTransaction(); + resetStatus(); + } +} + +/*! + \since 5.7 + + Completes a read transaction. Returns \c true if no read errors have + occurred during the transaction; otherwise returns \c false. + + If called on an inner transaction, committing will be postponed until + the outermost commitTransaction(), rollbackTransaction(), or + abortTransaction() call occurs. + + Otherwise, if the stream status indicates reading past the end of the + data, this function restores the stream data to the point of the + startTransaction() call. When this situation occurs, you need to wait for + more data to arrive, after which you start a new transaction. If the data + stream has read corrupt data or any of the inner transactions was aborted, + this function aborts the transaction. + + \sa startTransaction(), rollbackTransaction(), abortTransaction() +*/ + +bool QDataStream::commitTransaction() +{ + CHECK_STREAM_TRANSACTION_PRECOND(false) + if (--d->transactionDepth == 0) { + CHECK_STREAM_PRECOND(false) + + if (q_status == ReadPastEnd) { + dev->rollbackTransaction(); + return false; + } + dev->commitTransaction(); + } + return q_status == Ok; +} + +/*! + \since 5.7 + + Reverts a read transaction. + + This function is commonly used to rollback the transaction when an + incomplete read was detected prior to committing the transaction. + + If called on an inner transaction, reverting is delegated to the outermost + transaction, and subsequently started inner transactions are forced to + fail. + + For the outermost transaction, restores the stream data to the point of + the startTransaction() call. If the data stream has read corrupt data or + any of the inner transactions was aborted, this function aborts the + transaction. + + If the preceding stream operations were successful, sets the status of the + data stream to \value ReadPastEnd. + + \sa startTransaction(), commitTransaction(), abortTransaction() +*/ + +void QDataStream::rollbackTransaction() +{ + setStatus(ReadPastEnd); + + CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID) + if (--d->transactionDepth != 0) + return; + + CHECK_STREAM_PRECOND(Q_VOID) + if (q_status == ReadPastEnd) + dev->rollbackTransaction(); + else + dev->commitTransaction(); +} + +/*! + \since 5.7 + + Aborts a read transaction. + + This function is commonly used to discard the transaction after + higher-level protocol errors or loss of stream synchronization. + + If called on an inner transaction, aborting is delegated to the outermost + transaction, and subsequently started inner transactions are forced to + fail. + + For the outermost transaction, discards the restoration point and any + internally duplicated data of the stream. Will not affect the current + read position of the stream. + + Sets the status of the data stream to \value ReadCorruptData. + + \sa startTransaction(), commitTransaction(), rollbackTransaction() +*/ + +void QDataStream::abortTransaction() +{ + q_status = ReadCorruptData; + + CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID) + if (--d->transactionDepth != 0) + return; + + CHECK_STREAM_PRECOND(Q_VOID) + dev->commitTransaction(); +} + +/***************************************************************************** + QDataStream read functions + *****************************************************************************/ + +/*! + \internal +*/ + +int QDataStream::readBlock(char *data, int len) +{ + // Disable reads on failure in transacted stream + if (q_status != Ok && dev->isTransactionStarted()) + return -1; + + const int readResult = dev->read(data, len); + if (readResult != len) + setStatus(ReadPastEnd); + return readResult; +} + +/*! + \fn QDataStream &QDataStream::operator>>(std::nullptr_t &ptr) + \since 5.9 + \overload + + Simulates reading a \c{std::nullptr_t} from the stream into \a ptr and + returns a reference to the stream. This function does not actually read + anything from the stream, as \c{std::nullptr_t} values are stored as 0 + bytes. +*/ + +/*! + \fn QDataStream &QDataStream::operator>>(quint8 &i) + \overload + + Reads an unsigned byte from the stream into \a i, and returns a + reference to the stream. +*/ + +/*! + Reads a signed byte from the stream into \a i, and returns a + reference to the stream. +*/ + +QDataStream &QDataStream::operator>>(qint8 &i) +{ + i = 0; + CHECK_STREAM_PRECOND(*this) + char c; + if (readBlock(&c, 1) == 1) + i = qint8(c); + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>(quint16 &i) + \overload + + Reads an unsigned 16-bit integer from the stream into \a i, and + returns a reference to the stream. +*/ + +/*! + \overload + + Reads a signed 16-bit integer from the stream into \a i, and + returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>(qint16 &i) +{ + i = 0; + CHECK_STREAM_PRECOND(*this) + if (readBlock(reinterpret_cast<char *>(&i), 2) != 2) { + i = 0; + } else { + if (!noswap) { + i = qbswap(i); + } + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>(quint32 &i) + \overload + + Reads an unsigned 32-bit integer from the stream into \a i, and + returns a reference to the stream. +*/ + +/*! + \overload + + Reads a signed 32-bit integer from the stream into \a i, and + returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>(qint32 &i) +{ + i = 0; + CHECK_STREAM_PRECOND(*this) + if (readBlock(reinterpret_cast<char *>(&i), 4) != 4) { + i = 0; + } else { + if (!noswap) { + i = qbswap(i); + } + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator>>(quint64 &i) + \overload + + Reads an unsigned 64-bit integer from the stream, into \a i, and + returns a reference to the stream. +*/ + +/*! + \overload + + Reads a signed 64-bit integer from the stream into \a i, and + returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>(qint64 &i) +{ + i = qint64(0); + CHECK_STREAM_PRECOND(*this) + if (version() < 6) { + quint32 i1, i2; + *this >> i2 >> i1; + i = ((quint64)i1 << 32) + i2; + } else { + if (readBlock(reinterpret_cast<char *>(&i), 8) != 8) { + i = qint64(0); + } else { + if (!noswap) { + i = qbswap(i); + } + } + } + return *this; +} + +/*! + Reads a boolean value from the stream into \a i. Returns a + reference to the stream. +*/ +QDataStream &QDataStream::operator>>(bool &i) +{ + qint8 v; + *this >> v; + i = !!v; + return *this; +} + +/*! + \overload + + 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 (readBlock(reinterpret_cast<char *>(&f), 4) != 4) { + f = 0.0f; + } else { + if (!noswap) { + union { + float val1; + quint32 val2; + } x; + x.val2 = qbswap(*reinterpret_cast<quint32 *>(&f)); + f = x.val1; + } + } + return *this; +} + +/*! + \overload + + 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) + if (readBlock(reinterpret_cast<char *>(&f), 8) != 8) { + f = 0.0; + } else { + if (!noswap) { + union { + double val1; + quint64 val2; + } x; + x.val2 = qbswap(*reinterpret_cast<quint64 *>(&f)); + f = x.val1; + } + } + return *this; +} + + +/*! + \overload + \since 5.9 + + Reads a floating point number from the stream into \a f, + using the standard IEEE 754 format. Returns a reference to the + stream. +*/ +QDataStream &QDataStream::operator>>(qfloat16 &f) +{ + return *this >> reinterpret_cast<qint16&>(f); +} + + +/*! + \overload + + Reads the '\\0'-terminated string \a s from the stream and returns + a reference to the stream. + + The string is deserialized using \c{readBytes()}. + + Space for the string is allocated using \c{new []} -- the caller must + destroy it with \c{delete []}. + + \sa readBytes(), readRawData() +*/ + +QDataStream &QDataStream::operator>>(char *&s) +{ + uint len = 0; + return readBytes(s, len); +} + + +/*! + Reads the buffer \a s from the stream and returns a reference to + the stream. + + The buffer \a s is allocated using \c{new []}. Destroy it with the + \c{delete []} operator. + + The \a l parameter is set to the length of the buffer. If the + string read is empty, \a l is set to 0 and \a s is set to + a null pointer. + + The serialization format is a quint32 length specifier first, + then \a l bytes of data. + + \sa readRawData(), writeBytes() +*/ + +QDataStream &QDataStream::readBytes(char *&s, uint &l) +{ + s = 0; + l = 0; + CHECK_STREAM_PRECOND(*this) + + quint32 len; + *this >> len; + if (len == 0) + return *this; + + const quint32 Step = 1024 * 1024; + quint32 allocated = 0; + char *prevBuf = 0; + char *curBuf = 0; + + do { + int blockSize = qMin(Step, len - allocated); + prevBuf = curBuf; + curBuf = new char[allocated + blockSize + 1]; + if (prevBuf) { + memcpy(curBuf, prevBuf, allocated); + delete [] prevBuf; + } + if (readBlock(curBuf + allocated, blockSize) != blockSize) { + delete [] curBuf; + return *this; + } + allocated += blockSize; + } while (allocated < len); + + s = curBuf; + s[len] = '\0'; + l = (uint)len; + return *this; +} + +/*! + Reads at most \a len bytes from the stream into \a s and returns the number of + bytes read. If an error occurs, this function returns -1. + + The buffer \a s must be preallocated. The data is \e not encoded. + + \sa readBytes(), QIODevice::read(), writeRawData() +*/ + +int QDataStream::readRawData(char *s, int len) +{ + CHECK_STREAM_PRECOND(-1) + return readBlock(s, len); +} + + +/***************************************************************************** + QDataStream write functions + *****************************************************************************/ + +/*! + \fn QDataStream &QDataStream::operator<<(std::nullptr_t ptr) + \since 5.9 + \overload + + Simulates writing a \c{std::nullptr_t}, \a ptr, to the stream and returns a + reference to the stream. This function does not actually write anything to + the stream, as \c{std::nullptr_t} values are stored as 0 bytes. +*/ + +/*! + \fn QDataStream &QDataStream::operator<<(quint8 i) + \overload + + Writes an unsigned byte, \a i, to the stream and returns a + reference to the stream. +*/ + +/*! + Writes a signed byte, \a i, to the stream and returns a reference + to the stream. +*/ + +QDataStream &QDataStream::operator<<(qint8 i) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + if (!dev->putChar(i)) + q_status = WriteFailed; + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<(quint16 i) + \overload + + Writes an unsigned 16-bit integer, \a i, to the stream and returns + a reference to the stream. +*/ + +/*! + \overload + + Writes a signed 16-bit integer, \a i, to the stream and returns a + reference to the stream. +*/ + +QDataStream &QDataStream::operator<<(qint16 i) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + if (!noswap) { + i = qbswap(i); + } + if (dev->write((char *)&i, sizeof(qint16)) != sizeof(qint16)) + q_status = WriteFailed; + return *this; +} + +/*! + \overload + + Writes a signed 32-bit integer, \a i, to the stream and returns a + reference to the stream. +*/ + +QDataStream &QDataStream::operator<<(qint32 i) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + if (!noswap) { + i = qbswap(i); + } + if (dev->write((char *)&i, sizeof(qint32)) != sizeof(qint32)) + q_status = WriteFailed; + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<(quint64 i) + \overload + + Writes an unsigned 64-bit integer, \a i, to the stream and returns a + reference to the stream. +*/ + +/*! + \overload + + Writes a signed 64-bit integer, \a i, to the stream and returns a + reference to the stream. +*/ + +QDataStream &QDataStream::operator<<(qint64 i) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + if (version() < 6) { + quint32 i1 = i & 0xffffffff; + quint32 i2 = i >> 32; + *this << i2 << i1; + } else { + if (!noswap) { + i = qbswap(i); + } + if (dev->write((char *)&i, sizeof(qint64)) != sizeof(qint64)) + q_status = WriteFailed; + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<(quint32 i) + \overload + + Writes an unsigned integer, \a i, to the stream as a 32-bit + unsigned integer (quint32). Returns a reference to the stream. +*/ + +/*! + Writes a boolean value, \a i, to the stream. Returns a reference + to the stream. +*/ + +QDataStream &QDataStream::operator<<(bool i) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + if (!dev->putChar(qint8(i))) + q_status = WriteFailed; + return *this; +} + +/*! + \overload + + 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_WRITE_PRECOND(*this) + float g = f; // fixes float-on-stack problem + if (!noswap) { + union { + float val1; + quint32 val2; + } x; + x.val1 = g; + x.val2 = qbswap(x.val2); + + if (dev->write((char *)&x.val2, sizeof(float)) != sizeof(float)) + q_status = WriteFailed; + return *this; + } + + if (dev->write((char *)&g, sizeof(float)) != sizeof(float)) + q_status = WriteFailed; + return *this; +} + + +/*! + \overload + + 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_WRITE_PRECOND(*this) + if (noswap) { + if (dev->write((char *)&f, sizeof(double)) != sizeof(double)) + q_status = WriteFailed; + } else { + union { + double val1; + quint64 val2; + } x; + x.val1 = f; + x.val2 = qbswap(x.val2); + if (dev->write((char *)&x.val2, sizeof(double)) != sizeof(double)) + q_status = WriteFailed; + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<(qfloat16 f) + \overload + \since 5.9 + + Writes a floating point number, \a f, to the stream using + the standard IEEE 754 format. Returns a reference to the stream. +*/ +QDataStream &QDataStream::operator<<(qfloat16 f) +{ + return *this << reinterpret_cast<qint16&>(f); +} + +/*! + \overload + + Writes the '\\0'-terminated string \a s to the stream and returns a + reference to the stream. + + The string is serialized using \c{writeBytes()}. + + \sa writeBytes(), writeRawData() +*/ + +QDataStream &QDataStream::operator<<(const char *s) +{ + if (!s) { + *this << (quint32)0; + return *this; + } + uint len = qstrlen(s) + 1; // also write null terminator + *this << (quint32)len; // write length specifier + writeRawData(s, len); + return *this; +} + +/*! + Writes the length specifier \a len and the buffer \a s to the + stream and returns a reference to the stream. + + The \a len is serialized as a quint32, followed by \a len bytes + from \a s. Note that the data is \e not encoded. + + \sa writeRawData(), readBytes() +*/ + +QDataStream &QDataStream::writeBytes(const char *s, uint len) +{ + CHECK_STREAM_WRITE_PRECOND(*this) + *this << (quint32)len; // write length specifier + if (len) + writeRawData(s, len); + return *this; +} + + +/*! + Writes \a len bytes from \a s to the stream. Returns the + number of bytes actually written, or -1 on error. + The data is \e not encoded. + + \sa writeBytes(), QIODevice::write(), readRawData() +*/ + +int QDataStream::writeRawData(const char *s, int len) +{ + CHECK_STREAM_WRITE_PRECOND(-1) + int ret = dev->write(s, len); + if (ret != len) + q_status = WriteFailed; + return ret; +} + +/*! + \since 4.1 + + Skips \a len bytes from the device. Returns the number of bytes + actually skipped, or -1 on error. + + This is equivalent to calling readRawData() on a buffer of length + \a len and ignoring the buffer. + + \sa QIODevice::seek() +*/ +int QDataStream::skipRawData(int len) +{ + CHECK_STREAM_PRECOND(-1) + if (q_status != Ok && dev->isTransactionStarted()) + return -1; + + const int skipResult = dev->skip(len); + if (skipResult != len) + setStatus(ReadPastEnd); + return skipResult; +} + +QT_END_NAMESPACE + +#endif // QT_NO_DATASTREAM |