| /**************************************************************************** |
| ** |
| ** 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. |
| |
| Enumerations can be serialized through QDataStream without the |
| need of manually defining streaming operators. Enum classes are |
| serialized using the declared size. |
| |
| 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: |
| |
| \snippet code/src_corelib_serialization_qdatastream.cpp 0 |
| |
| For example, here are the stream operators declared as non-members |
| of the QImage class: |
| |
| \snippet code/src_corelib_serialization_qdatastream.cpp 1 |
| |
| 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 = nullptr; |
| 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 \nullptr if no |
| device is currently set. |
| |
| \sa setDevice() |
| */ |
| |
| /*! |
| void QDataStream::setDevice(QIODevice *d) |
| |
| Sets the I/O device to \a d, which can be \nullptr |
| to unset to current I/O device. |
| |
| \sa device() |
| */ |
| |
| void QDataStream::setDevice(QIODevice *d) |
| { |
| if (owndev) { |
| delete dev; |
| owndev = false; |
| } |
| dev = d; |
| } |
| |
| #if QT_DEPRECATED_SINCE(5, 13) |
| /*! |
| \obsolete |
| Unsets the I/O device. |
| Use setDevice(nullptr) instead. |
| */ |
| |
| void QDataStream::unsetDevice() |
| { |
| setDevice(nullptr); |
| } |
| #endif |
| |
| /*! |
| \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 ? d->floatingPointPrecision : QDataStream::DoublePrecision; |
| } |
| |
| /*! |
| 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) |
| 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 |
| \value Qt_5_12 Version 18 (Qt 5.12) |
| \value Qt_5_13 Version 19 (Qt 5.13) |
| \value Qt_5_14 Same as Qt_5_13 |
| \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) |
| 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 \nullptr. |
| |
| 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 = nullptr; |
| 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 = nullptr; |
| char *curBuf = nullptr; |
| |
| 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 decoded. |
| |
| \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 |