summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qdatastream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization/qdatastream.cpp')
-rw-r--r--src/corelib/serialization/qdatastream.cpp50
1 files changed, 30 insertions, 20 deletions
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index 57713d3645..3d6d1d8e92 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -70,17 +70,30 @@ constexpr quint32 QDataStream::ExtendedSize;
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 Serializing containers and strings
+
+ The serialization format is a length specifier first, then \a l bytes of data.
+ The length specifier is one quint32 if the version is less than 6.7 or if the
+ number of elements is less than 0xfffffffe (2^32 -2). Otherwise there is
+ an extend value 0xfffffffe followed by one quint64 with the actual value.
+ In addition for containers that support isNull(), it is encoded as a single
+ quint32 with all bits set and no data.
+
+ To take one example, if the string size fits into 32 bits, 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. If the string size is greater, the value 0xffffffffe is written
+ as a marker of an extended size, followed by 64 bits of the actual size.
+ When reading a \c {char *} string, 4 bytes are read first. If the value is
+ not equal to 0xffffffffe (the marker of extended size), then these 4 bytes
+ are treated as the 32 bit size of the string. Otherwise, the next 8 bytes are
+ read and treated as a 64 bit size of the string. Then, all the characters for
+ the \c {char *} string, including the '\\0' terminator, are read.
+
\section1 Versioning
QDataStream's binary format has evolved since Qt 1.0, and is
@@ -534,6 +547,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_6 Version 21 (Qt 6.6)
\value Qt_6_7 Version 22 (Qt 6.7)
\value Qt_6_8 Same as Qt_6_7
+ \value Qt_6_9 Same as Qt_6_7
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -1075,26 +1089,22 @@ QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
qsizetype step = (dev->bytesAvailable() >= len) ? len : 1024 * 1024;
qsizetype allocated = 0;
- char *prevBuf = nullptr;
- char *curBuf = nullptr;
+ std::unique_ptr<char[]> curBuf = nullptr;
+ constexpr qsizetype StepIncreaseThreshold = std::numeric_limits<qsizetype>::max() / 2;
do {
qsizetype 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;
+ const qsizetype n = allocated + blockSize + 1;
+ if (const auto prevBuf = std::exchange(curBuf, std::make_unique<char[]>(n)))
+ memcpy(curBuf.get(), prevBuf.get(), allocated);
+ if (readBlock(curBuf.get() + allocated, blockSize) != blockSize)
return *this;
- }
allocated += blockSize;
- step *= 2;
+ if (step <= StepIncreaseThreshold)
+ step *= 2;
} while (allocated < len);
- s = curBuf;
+ s = curBuf.release();
s[len] = '\0';
l = len;
return *this;