Add support for containers > 4 Gi elements in QDataStream
The format is changed from 6.7 to support more than UINT32_MAX - 1 elements. The format used to have a quint32 size. Now if the size is larger or equal to 0xfffffffe (2^32 -2) the old size is an extend value 0xfffffffe followed by one quint64 with the actual value. The 32 bit size with all bits set is still used as null value. Fixes: QTBUG-105034 Change-Id: I62188be170fe779022ad58ab84a54b1eaf46e5d9 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
0d413506a1
commit
fd48ce0b73
@ -631,6 +631,56 @@ void QDateTime::setTimeZone(const QTimeZone &toZone)
|
||||
setTimeZone(toZone, TransitionResolution::LegacyBehavior);
|
||||
}
|
||||
|
||||
#include "qdatastream.h"
|
||||
|
||||
QDataStream &QDataStream::readBytes(char *&s, uint &l)
|
||||
{
|
||||
qsizetype length = 0;
|
||||
(void)readBytes(s, length);
|
||||
if (length != qsizetype(uint(length))) {
|
||||
setStatus(ReadCorruptData); // Cannot store length in l
|
||||
delete[] s;
|
||||
l = 0;
|
||||
return *this;
|
||||
}
|
||||
l = uint(length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QDataStream &QDataStream::writeBytes(const char *s, uint len)
|
||||
{
|
||||
qsizetype length = qsizetype(len);
|
||||
if (length < 0) {
|
||||
setStatus(WriteFailed);
|
||||
return *this;
|
||||
}
|
||||
return writeBytes(s, length);
|
||||
}
|
||||
|
||||
int QDataStream::skipRawData(int len)
|
||||
{
|
||||
return int(skipRawData(qint64(len)));
|
||||
}
|
||||
|
||||
#if QT_POINTER_SIZE != 4
|
||||
|
||||
int QDataStream::readBlock(char *data, int len)
|
||||
{
|
||||
return int(readBlock(data, qsizetype(len)));
|
||||
}
|
||||
|
||||
int QDataStream::readRawData(char *s, int len)
|
||||
{
|
||||
return int(readRawData(s, qsizetype(len)));
|
||||
}
|
||||
|
||||
int QDataStream::writeRawData(const char *s, int len)
|
||||
{
|
||||
return writeRawData(s, qsizetype(len));
|
||||
}
|
||||
|
||||
#endif // QT_POINTER_SIZE != 4
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
|
||||
#include "qjniobject.h"
|
||||
|
@ -525,8 +525,8 @@ void QDataStream::setByteOrder(ByteOrder bo)
|
||||
\value Qt_6_3 Same as Qt_6_0
|
||||
\value Qt_6_4 Same as Qt_6_0
|
||||
\value Qt_6_5 Same as Qt_6_0
|
||||
\value Qt_6_6 Same as Qt_6_0
|
||||
\value Qt_6_7 Same as Qt_6_6
|
||||
\value Qt_6_6 Version 21 (Qt 6.6)
|
||||
\value Qt_6_7 Version 22 (Qt 6.7)
|
||||
\omitvalue Qt_DefaultCompiledVersion
|
||||
|
||||
\sa setVersion(), version()
|
||||
@ -731,13 +731,13 @@ bool QDataStream::isDeviceTransactionStarted() const
|
||||
\internal
|
||||
*/
|
||||
|
||||
int QDataStream::readBlock(char *data, int len)
|
||||
qsizetype QDataStream::readBlock(char *data, qsizetype len)
|
||||
{
|
||||
// Disable reads on failure in transacted stream
|
||||
if (q_status != Ok && dev->isTransactionStarted())
|
||||
return -1;
|
||||
|
||||
const int readResult = dev->read(data, len);
|
||||
const qsizetype readResult = dev->read(data, len);
|
||||
if (readResult != len)
|
||||
setStatus(ReadPastEnd);
|
||||
return readResult;
|
||||
@ -976,7 +976,7 @@ QDataStream &QDataStream::operator>>(double &f)
|
||||
|
||||
QDataStream &QDataStream::operator>>(char *&s)
|
||||
{
|
||||
uint len = 0;
|
||||
qsizetype len = 0;
|
||||
return readBytes(s, len);
|
||||
}
|
||||
|
||||
@ -1020,30 +1020,40 @@ QDataStream &QDataStream::operator>>(char32_t &c)
|
||||
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.
|
||||
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.
|
||||
|
||||
\sa readRawData(), writeBytes()
|
||||
*/
|
||||
|
||||
QDataStream &QDataStream::readBytes(char *&s, uint &l)
|
||||
QDataStream &QDataStream::readBytes(char *&s, qsizetype &l)
|
||||
{
|
||||
s = nullptr;
|
||||
l = 0;
|
||||
CHECK_STREAM_PRECOND(*this)
|
||||
|
||||
quint32 len;
|
||||
*this >> len;
|
||||
if (len == 0)
|
||||
qint64 length = readQSizeType(*this);
|
||||
if (length == 0)
|
||||
return *this;
|
||||
|
||||
const quint32 Step = 1024 * 1024;
|
||||
quint32 allocated = 0;
|
||||
qsizetype len = qsizetype(length);
|
||||
if (length != len || length < 0) {
|
||||
setStatus(ReadCorruptData); // Cannot store len in l
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr qsizetype Step = 1024 * 1024;
|
||||
qsizetype allocated = 0;
|
||||
char *prevBuf = nullptr;
|
||||
char *curBuf = nullptr;
|
||||
|
||||
do {
|
||||
int blockSize = qMin(Step, len - allocated);
|
||||
qsizetype blockSize = qMin(Step, len - allocated);
|
||||
prevBuf = curBuf;
|
||||
curBuf = new char[allocated + blockSize + 1];
|
||||
if (prevBuf) {
|
||||
@ -1059,7 +1069,7 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
|
||||
|
||||
s = curBuf;
|
||||
s[len] = '\0';
|
||||
l = (uint)len;
|
||||
l = len;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1072,7 +1082,7 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
|
||||
\sa readBytes(), QIODevice::read(), writeRawData()
|
||||
*/
|
||||
|
||||
int QDataStream::readRawData(char *s, int len)
|
||||
qsizetype QDataStream::readRawData(char *s, qsizetype len)
|
||||
{
|
||||
CHECK_STREAM_PRECOND(-1)
|
||||
return readBlock(s, len);
|
||||
@ -1346,22 +1356,26 @@ QDataStream &QDataStream::operator<<(char32_t c)
|
||||
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.
|
||||
The \a len is serialized as a quint32 and an optional quint64,
|
||||
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)
|
||||
QDataStream &QDataStream::writeBytes(const char *s, qsizetype len)
|
||||
{
|
||||
if (len < 0) {
|
||||
q_status = WriteFailed;
|
||||
return *this;
|
||||
}
|
||||
CHECK_STREAM_WRITE_PRECOND(*this)
|
||||
*this << (quint32)len; // write length specifier
|
||||
if (len)
|
||||
writeQSizeType(*this, len); // write length specifier
|
||||
if (len > 0)
|
||||
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.
|
||||
@ -1370,10 +1384,10 @@ QDataStream &QDataStream::writeBytes(const char *s, uint len)
|
||||
\sa writeBytes(), QIODevice::write(), readRawData()
|
||||
*/
|
||||
|
||||
int QDataStream::writeRawData(const char *s, int len)
|
||||
qsizetype QDataStream::writeRawData(const char *s, qsizetype len)
|
||||
{
|
||||
CHECK_STREAM_WRITE_PRECOND(-1)
|
||||
int ret = dev->write(s, len);
|
||||
qsizetype ret = dev->write(s, len);
|
||||
if (ret != len)
|
||||
q_status = WriteFailed;
|
||||
return ret;
|
||||
@ -1390,13 +1404,13 @@ int QDataStream::writeRawData(const char *s, int len)
|
||||
|
||||
\sa QIODevice::seek()
|
||||
*/
|
||||
int QDataStream::skipRawData(int len)
|
||||
qint64 QDataStream::skipRawData(qint64 len)
|
||||
{
|
||||
CHECK_STREAM_PRECOND(-1)
|
||||
if (q_status != Ok && dev->isTransactionStarted())
|
||||
return -1;
|
||||
|
||||
const int skipResult = dev->skip(len);
|
||||
const qint64 skipResult = dev->skip(len);
|
||||
if (skipResult != len)
|
||||
setStatus(ReadPastEnd);
|
||||
return skipResult;
|
||||
|
@ -19,12 +19,26 @@ QT_BEGIN_NAMESPACE
|
||||
class qfloat16;
|
||||
#endif
|
||||
class QByteArray;
|
||||
class QDataStream;
|
||||
class QIODevice;
|
||||
class QString;
|
||||
|
||||
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
|
||||
class QDataStreamPrivate;
|
||||
namespace QtPrivate {
|
||||
class StreamStateSaver;
|
||||
template <typename Container>
|
||||
QDataStream &readArrayBasedContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
QDataStream &readListBasedContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
QDataStream &readAssociativeContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
QDataStream &writeSequentialContainer(QDataStream &s, const Container &c);
|
||||
template <typename Container>
|
||||
QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c);
|
||||
template <typename Container>
|
||||
QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c);
|
||||
}
|
||||
class Q_CORE_EXPORT QDataStream : public QIODeviceBase
|
||||
{
|
||||
@ -69,7 +83,7 @@ public:
|
||||
Qt_6_4 = Qt_6_0,
|
||||
Qt_6_5 = Qt_6_0,
|
||||
Qt_6_6 = 21,
|
||||
Qt_6_7 = Qt_6_6,
|
||||
Qt_6_7 = 22,
|
||||
Qt_DefaultCompiledVersion = Qt_6_7
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
|
||||
@ -159,14 +173,20 @@ public:
|
||||
QDataStream &operator<<(char32_t c);
|
||||
QDataStream &operator<<(const volatile void *) = delete;
|
||||
|
||||
|
||||
#if QT_CORE_REMOVED_SINCE(6, 7)
|
||||
QDataStream &readBytes(char *&, uint &len);
|
||||
int readRawData(char *, int len);
|
||||
|
||||
QDataStream &writeBytes(const char *, uint len);
|
||||
int writeRawData(const char *, int len);
|
||||
|
||||
int skipRawData(int len);
|
||||
#endif
|
||||
#if QT_CORE_REMOVED_SINCE(6, 7) && QT_POINTER_SIZE != 4
|
||||
int readRawData(char *, int len);
|
||||
int writeRawData(const char *, int len);
|
||||
#endif
|
||||
QDataStream &readBytes(char *&, qsizetype &len);
|
||||
qsizetype readRawData(char *, qsizetype len);
|
||||
QDataStream &writeBytes(const char *, qsizetype len);
|
||||
qsizetype writeRawData(const char *, qsizetype len);
|
||||
qint64 skipRawData(qint64 len);
|
||||
|
||||
void startTransaction();
|
||||
bool commitTransaction();
|
||||
@ -185,9 +205,32 @@ private:
|
||||
ByteOrder byteorder;
|
||||
int ver;
|
||||
Status q_status;
|
||||
|
||||
#if QT_CORE_REMOVED_SINCE(6, 7) && QT_POINTER_SIZE != 4
|
||||
int readBlock(char *data, int len);
|
||||
#endif
|
||||
qsizetype readBlock(char *data, qsizetype len);
|
||||
static inline qint64 readQSizeType(QDataStream &s);
|
||||
static inline void writeQSizeType(QDataStream &s, qint64 value);
|
||||
enum class QDataStreamSizes : quint32 { NullCode = 0xffffffffu, ExtendedSize = 0xfffffffeu };
|
||||
|
||||
friend class QtPrivate::StreamStateSaver;
|
||||
Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QString &str);
|
||||
Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QString &str);
|
||||
Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QByteArray &ba);
|
||||
Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QByteArray &ba);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::readArrayBasedContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::readListBasedContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::readAssociativeContainer(QDataStream &s, Container &c);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::writeSequentialContainer(QDataStream &s, const Container &c);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::writeAssociativeContainer(QDataStream &s, const Container &c);
|
||||
template <typename Container>
|
||||
friend QDataStream &QtPrivate::writeAssociativeMultiContainer(QDataStream &s,
|
||||
const Container &c);
|
||||
};
|
||||
|
||||
namespace QtPrivate {
|
||||
@ -219,10 +262,14 @@ QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
|
||||
StreamStateSaver stateSaver(&s);
|
||||
|
||||
c.clear();
|
||||
quint32 n;
|
||||
s >> n;
|
||||
qint64 size = QDataStream::readQSizeType(s);
|
||||
qsizetype n = size;
|
||||
if (size != n || size < 0) {
|
||||
s.setStatus(QDataStream::ReadCorruptData);
|
||||
return s;
|
||||
}
|
||||
c.reserve(n);
|
||||
for (quint32 i = 0; i < n; ++i) {
|
||||
for (qsizetype i = 0; i < n; ++i) {
|
||||
typename Container::value_type t;
|
||||
s >> t;
|
||||
if (s.status() != QDataStream::Ok) {
|
||||
@ -241,9 +288,13 @@ QDataStream &readListBasedContainer(QDataStream &s, Container &c)
|
||||
StreamStateSaver stateSaver(&s);
|
||||
|
||||
c.clear();
|
||||
quint32 n;
|
||||
s >> n;
|
||||
for (quint32 i = 0; i < n; ++i) {
|
||||
qint64 size = QDataStream::readQSizeType(s);
|
||||
qsizetype n = size;
|
||||
if (size != n || size < 0) {
|
||||
s.setStatus(QDataStream::ReadCorruptData);
|
||||
return s;
|
||||
}
|
||||
for (qsizetype i = 0; i < n; ++i) {
|
||||
typename Container::value_type t;
|
||||
s >> t;
|
||||
if (s.status() != QDataStream::Ok) {
|
||||
@ -262,9 +313,13 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
|
||||
StreamStateSaver stateSaver(&s);
|
||||
|
||||
c.clear();
|
||||
quint32 n;
|
||||
s >> n;
|
||||
for (quint32 i = 0; i < n; ++i) {
|
||||
qint64 size = QDataStream::readQSizeType(s);
|
||||
qsizetype n = size;
|
||||
if (size != n || size < 0) {
|
||||
s.setStatus(QDataStream::ReadCorruptData);
|
||||
return s;
|
||||
}
|
||||
for (qsizetype i = 0; i < n; ++i) {
|
||||
typename Container::key_type k;
|
||||
typename Container::mapped_type t;
|
||||
s >> k >> t;
|
||||
@ -281,7 +336,7 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
|
||||
template <typename Container>
|
||||
QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
|
||||
{
|
||||
s << quint32(c.size());
|
||||
QDataStream::writeQSizeType(s, c.size());
|
||||
for (const typename Container::value_type &t : c)
|
||||
s << t;
|
||||
|
||||
@ -291,7 +346,7 @@ QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
|
||||
template <typename Container>
|
||||
QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
|
||||
{
|
||||
s << quint32(c.size());
|
||||
QDataStream::writeQSizeType(s, c.size());
|
||||
auto it = c.constBegin();
|
||||
auto end = c.constEnd();
|
||||
while (it != end) {
|
||||
@ -305,7 +360,7 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
|
||||
template <typename Container>
|
||||
QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
|
||||
{
|
||||
s << quint32(c.size());
|
||||
QDataStream::writeQSizeType(s, c.size());
|
||||
auto it = c.constBegin();
|
||||
auto end = c.constEnd();
|
||||
while (it != end) {
|
||||
@ -354,6 +409,31 @@ inline int QDataStream::version() const
|
||||
inline void QDataStream::setVersion(int v)
|
||||
{ ver = v; }
|
||||
|
||||
qint64 QDataStream::readQSizeType(QDataStream &s)
|
||||
{
|
||||
quint32 first;
|
||||
s >> first;
|
||||
if (first == quint32(QDataStreamSizes::NullCode))
|
||||
return -1;
|
||||
if (first < quint32(QDataStreamSizes::ExtendedSize) || s.version() < QDataStream::Qt_6_7)
|
||||
return qint64(first);
|
||||
qint64 extendedLen;
|
||||
s >> extendedLen;
|
||||
return extendedLen;
|
||||
}
|
||||
|
||||
void QDataStream::writeQSizeType(QDataStream &s, qint64 value)
|
||||
{
|
||||
if (value < qint64(QDataStreamSizes::ExtendedSize))
|
||||
s << quint32(value);
|
||||
else if (s.version() >= QDataStream::Qt_6_7)
|
||||
s << quint32(QDataStreamSizes::ExtendedSize) << value;
|
||||
else if (value == qint64(QDataStreamSizes::ExtendedSize))
|
||||
s << quint32(QDataStreamSizes::ExtendedSize);
|
||||
else
|
||||
s.setStatus(QDataStream::WriteFailed); // value is too big for old format
|
||||
}
|
||||
|
||||
inline QDataStream &QDataStream::operator>>(char &i)
|
||||
{ return *this >> reinterpret_cast<qint8&>(i); }
|
||||
|
||||
|
@ -3266,7 +3266,7 @@ void QByteArray::clear()
|
||||
QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
|
||||
{
|
||||
if (ba.isNull() && out.version() >= 6) {
|
||||
out << (quint32)0xffffffff;
|
||||
QDataStream::writeQSizeType(out, -1);
|
||||
return out;
|
||||
}
|
||||
return out.writeBytes(ba.constData(), ba.size());
|
||||
@ -3283,15 +3283,21 @@ QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
|
||||
QDataStream &operator>>(QDataStream &in, QByteArray &ba)
|
||||
{
|
||||
ba.clear();
|
||||
quint32 len;
|
||||
in >> len;
|
||||
if (len == 0xffffffff) { // null byte-array
|
||||
|
||||
qint64 size = QDataStream::readQSizeType(in);
|
||||
qsizetype len = size;
|
||||
if (size != len || size < -1) {
|
||||
ba.clear();
|
||||
in.setStatus(QDataStream::ReadCorruptData);
|
||||
return in;
|
||||
}
|
||||
if (len == -1) { // null byte-array
|
||||
ba = QByteArray();
|
||||
return in;
|
||||
}
|
||||
|
||||
const quint32 Step = 1024 * 1024;
|
||||
quint32 allocated = 0;
|
||||
constexpr qsizetype Step = 1024 * 1024;
|
||||
qsizetype allocated = 0;
|
||||
|
||||
do {
|
||||
qsizetype blockSize = qMin(Step, len - allocated);
|
||||
|
@ -9327,16 +9327,15 @@ QDataStream &operator<<(QDataStream &out, const QString &str)
|
||||
if (!str.isNull() || out.version() < 3) {
|
||||
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
|
||||
out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
|
||||
static_cast<uint>(sizeof(QChar) * str.size()));
|
||||
static_cast<qsizetype>(sizeof(QChar) * str.size()));
|
||||
} else {
|
||||
QVarLengthArray<char16_t> buffer(str.size());
|
||||
qbswap<sizeof(char16_t)>(str.constData(), str.size(), buffer.data());
|
||||
out.writeBytes(reinterpret_cast<const char *>(buffer.data()),
|
||||
static_cast<uint>(sizeof(char16_t) * buffer.size()));
|
||||
static_cast<qsizetype>(sizeof(char16_t) * buffer.size()));
|
||||
}
|
||||
} else {
|
||||
// write null marker
|
||||
out << (quint32)0xffffffff;
|
||||
QDataStream::writeQSizeType(out, -1); // write null marker
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@ -9358,20 +9357,25 @@ QDataStream &operator>>(QDataStream &in, QString &str)
|
||||
in >> l;
|
||||
str = QString::fromLatin1(l);
|
||||
} else {
|
||||
quint32 bytes = 0;
|
||||
in >> bytes; // read size of string
|
||||
if (bytes == 0xffffffff) { // null string
|
||||
qint64 size = QDataStream::readQSizeType(in);
|
||||
qsizetype bytes = size;
|
||||
if (size != bytes || size < -1) {
|
||||
str.clear();
|
||||
in.setStatus(QDataStream::ReadCorruptData);
|
||||
return in;
|
||||
}
|
||||
if (bytes == -1) { // null string
|
||||
str = QString();
|
||||
} else if (bytes > 0) { // not empty
|
||||
} else if (bytes > 0) {
|
||||
if (bytes & 0x1) {
|
||||
str.clear();
|
||||
in.setStatus(QDataStream::ReadCorruptData);
|
||||
return in;
|
||||
}
|
||||
|
||||
const quint32 Step = 1024 * 1024;
|
||||
quint32 len = bytes / 2;
|
||||
quint32 allocated = 0;
|
||||
const qsizetype Step = 1024 * 1024;
|
||||
qsizetype len = bytes / 2;
|
||||
qsizetype allocated = 0;
|
||||
|
||||
while (allocated < len) {
|
||||
int blockSize = qMin(Step, len - allocated);
|
||||
|
@ -296,6 +296,7 @@ static int NColorRoles[] = {
|
||||
QPalette::PlaceholderText + 1, // Qt_5_13, Qt_5_14, Qt_5_15
|
||||
QPalette::PlaceholderText + 1, // Qt_6_0
|
||||
QPalette::Accent + 1, // Qt_6_6
|
||||
QPalette::Accent + 1, // Qt_6_7
|
||||
0 // add the correct value for Qt_5_14 here later
|
||||
};
|
||||
|
||||
@ -2795,7 +2796,6 @@ void tst_QDataStream::status_charptr_QByteArray_data()
|
||||
QTest::newRow("badsize 1MB+1") << QByteArray("\x00\x10\x00\x01", 4) + oneMbMinus1 + QByteArray("j") << (int) QDataStream::ReadPastEnd << QByteArray();
|
||||
QTest::newRow("badsize 3MB") << QByteArray("\x00\x30\x00\x00", 4) + threeMbMinus1 << (int) QDataStream::ReadPastEnd << QByteArray();
|
||||
QTest::newRow("badsize 3MB+1") << QByteArray("\x00\x30\x00\x01", 4) + threeMbMinus1 + QByteArray("j") << (int) QDataStream::ReadPastEnd << QByteArray();
|
||||
QTest::newRow("size -1") << QByteArray("\xff\xff\xff\xff", 4) << (int) QDataStream::ReadPastEnd << QByteArray();
|
||||
QTest::newRow("size -2") << QByteArray("\xff\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QByteArray();
|
||||
}
|
||||
|
||||
@ -2818,10 +2818,10 @@ void tst_QDataStream::status_charptr_QByteArray()
|
||||
{
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
char *buf;
|
||||
uint len;
|
||||
qsizetype len;
|
||||
stream.readBytes(buf, len);
|
||||
|
||||
QCOMPARE((int)len, expectedString.size());
|
||||
QCOMPARE(len, expectedString.size());
|
||||
QCOMPARE(QByteArray(buf, len), expectedString);
|
||||
QCOMPARE(int(stream.status()), expectedStatus);
|
||||
delete [] buf;
|
||||
@ -2897,12 +2897,20 @@ void tst_QDataStream::status_QString_data()
|
||||
QTest::newRow("badsize 1MB+1") << QByteArray("\x00\x20\x00\x02", 4) + oneMbMinus1Data + QByteArray("j") << (int) QDataStream::ReadPastEnd << QString();
|
||||
QTest::newRow("badsize 3MB") << QByteArray("\x00\x60\x00\x00", 4) + threeMbMinus1Data << (int) QDataStream::ReadPastEnd << QString();
|
||||
QTest::newRow("badsize 3MB+1") << QByteArray("\x00\x60\x00\x02", 4) + threeMbMinus1Data + QByteArray("j") << (int) QDataStream::ReadPastEnd << QString();
|
||||
QTest::newRow("size -2") << QByteArray("\xff\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QString();
|
||||
QTest::newRow("size MAX") << QByteArray("\x7f\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QString();
|
||||
QTest::newRow("32 bit size should be 64 bit") << QByteArray("\xff\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QString();
|
||||
|
||||
// corrupt data
|
||||
#if QT_POINTER_SIZE != 4
|
||||
// past end on 64 bit platforms
|
||||
QTest::newRow("32 bit size MAX string no content") << QByteArray("\xff\xff\xff\xfc", 4) << (int) QDataStream::ReadPastEnd << QString();
|
||||
#else
|
||||
// too big for 32 bit platforms
|
||||
QTest::newRow("32 bit size MAX string no content") << QByteArray("\xff\xff\xff\xfc", 4) << (int) QDataStream::ReadCorruptData << QString();
|
||||
#endif
|
||||
// too big on both 32 and 64 bit platforms because qsizetype is signed
|
||||
QTest::newRow("64 bit size MAX string no content") << QByteArray("\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xfe", 12) << (int) QDataStream::ReadCorruptData << QString();
|
||||
|
||||
// corrupt data because QChar is 16 bit => even size required
|
||||
QTest::newRow("corrupt1") << QByteArray("yyyy") << (int) QDataStream::ReadCorruptData << QString();
|
||||
QTest::newRow("size -3") << QByteArray("\xff\xff\xff\xfd", 4) << (int) QDataStream::ReadCorruptData << QString();
|
||||
}
|
||||
|
||||
void tst_QDataStream::status_QString()
|
||||
|
@ -1,5 +1,6 @@
|
||||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qdatastream)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(tools)
|
||||
|
15
tests/manual/corelib/qdatastream/CMakeLists.txt
Normal file
15
tests/manual/corelib/qdatastream/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_manual_qdatastream Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_manual_test(tst_manual_qdatastream
|
||||
SOURCES
|
||||
tst_manualqdatastream.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
ENABLE_AUTOGEN_TOOLS
|
||||
uic
|
||||
)
|
6
tests/manual/corelib/qdatastream/qdatastream.pro
Normal file
6
tests/manual/corelib/qdatastream/qdatastream.pro
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG += testcase
|
||||
|
||||
SOURCES += tst_manualqdatastream.cpp
|
||||
QT = core testlib
|
||||
|
||||
TARGET = tst_manual_qdatastream
|
171
tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp
Normal file
171
tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright (C) 2023 BlackBerry Limited. All rights reserved.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QTest>
|
||||
|
||||
// These tests are way too slow to be part of automatic unit tests
|
||||
class tst_QDataStream : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
template <class T>
|
||||
void fill(T &input);
|
||||
template <>
|
||||
void fill(QSet<qsizetype> &input);
|
||||
template <>
|
||||
void fill(QMap<qsizetype, qsizetype> &input);
|
||||
template <>
|
||||
void fill(QHash<qsizetype, qsizetype> &input);
|
||||
|
||||
template <class T>
|
||||
void stream_big();
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
|
||||
private slots:
|
||||
void stream_bigQString();
|
||||
void stream_bigQList();
|
||||
void stream_bigQSet();
|
||||
void stream_bigQMap();
|
||||
void stream_bigQHash();
|
||||
};
|
||||
|
||||
void tst_QDataStream::initTestCase()
|
||||
{
|
||||
qputenv("QTEST_FUNCTION_TIMEOUT", "9000000");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void tst_QDataStream::fill(T &input)
|
||||
{
|
||||
constexpr qsizetype GiB = 1024 * 1024 * 1024;
|
||||
constexpr qsizetype BaseSize = 4 * GiB + 1;
|
||||
qDebug("Filling container with %lld entries", qint64(BaseSize));
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
try {
|
||||
input.reserve(BaseSize);
|
||||
input.resize(BaseSize, 'a');
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Could not allocate 4 GiB of RAM.");
|
||||
}
|
||||
qDebug("Created dataset in %lld ms", timer.elapsed());
|
||||
}
|
||||
|
||||
template <>
|
||||
void tst_QDataStream::fill(QSet<qsizetype> &input)
|
||||
{
|
||||
constexpr qsizetype GiB = 1024 * 1024 * 1024;
|
||||
constexpr qsizetype BaseSize = 4 * GiB + 1;
|
||||
qDebug("Filling container with %lld entries", qint64(BaseSize));
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
try {
|
||||
input.reserve(BaseSize);
|
||||
for (qsizetype i = 0; i < BaseSize; ++i)
|
||||
input.insert(i);
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Could not allocate 4 Gi entries.");
|
||||
}
|
||||
qDebug("Created dataset in %lld ms", timer.elapsed());
|
||||
}
|
||||
|
||||
template <>
|
||||
void tst_QDataStream::fill(QMap<qsizetype, qsizetype> &input)
|
||||
{
|
||||
constexpr qsizetype GiB = 1024 * 1024 * 1024;
|
||||
constexpr qsizetype BaseSize = 4 * GiB + 1;
|
||||
qDebug("Filling container with %lld entries", qint64(BaseSize));
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
try {
|
||||
for (qsizetype i = 0; i < BaseSize; ++i)
|
||||
input.insert(i, i);
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Could not allocate 4 Gi entries.");
|
||||
}
|
||||
qDebug("Created dataset in %lld ms", timer.elapsed());
|
||||
}
|
||||
|
||||
template <>
|
||||
void tst_QDataStream::fill(QHash<qsizetype, qsizetype> &input)
|
||||
{
|
||||
constexpr qsizetype GiB = 1024 * 1024 * 1024;
|
||||
constexpr qsizetype BaseSize = 4 * GiB + 1;
|
||||
qDebug("Filling container with %lld entries", qint64(BaseSize));
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
try {
|
||||
input.reserve(BaseSize);
|
||||
for (qsizetype i = 0; i < BaseSize; ++i)
|
||||
input.emplace(i, i);
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Could not allocate 4 Gi entries.");
|
||||
}
|
||||
qDebug("Created dataset in %lld ms", timer.elapsed());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void tst_QDataStream::stream_big()
|
||||
{
|
||||
#if QT_POINTER_SIZE > 4
|
||||
QElapsedTimer timer;
|
||||
T input;
|
||||
fill(input);
|
||||
QByteArray ba;
|
||||
QDataStream inputstream(&ba, QIODevice::WriteOnly);
|
||||
timer.start();
|
||||
try {
|
||||
inputstream << input;
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Not enough memory to copy into QDataStream.");
|
||||
}
|
||||
qDebug("Streamed into QDataStream in %lld ms", timer.elapsed());
|
||||
T output;
|
||||
QDataStream outputstream(ba);
|
||||
timer.start();
|
||||
try {
|
||||
outputstream >> output;
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Not enough memory to copy out of QDataStream.");
|
||||
}
|
||||
qDebug("Streamed out of QDataStream in %lld ms", timer.elapsed());
|
||||
QCOMPARE(input.size(), output.size());
|
||||
QCOMPARE(input, output);
|
||||
#else
|
||||
QSKIP("This test is 64-bit only.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QDataStream::stream_bigQString()
|
||||
{
|
||||
stream_big<QString>();
|
||||
}
|
||||
void tst_QDataStream::stream_bigQList()
|
||||
{
|
||||
stream_big<QList<char>>();
|
||||
}
|
||||
|
||||
void tst_QDataStream::stream_bigQSet()
|
||||
{
|
||||
stream_big<QSet<qsizetype>>();
|
||||
}
|
||||
|
||||
void tst_QDataStream::stream_bigQMap()
|
||||
{
|
||||
stream_big<QMap<qsizetype, qsizetype>>();
|
||||
}
|
||||
void tst_QDataStream::stream_bigQHash()
|
||||
{
|
||||
stream_big<QHash<qsizetype, qsizetype>>();
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QDataStream)
|
||||
|
||||
#include "tst_manualqdatastream.moc"
|
Loading…
Reference in New Issue
Block a user