diff options
Diffstat (limited to 'src/corelib/serialization/qdatastream.cpp')
-rw-r--r-- | src/corelib/serialization/qdatastream.cpp | 50 |
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; |