summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qglobal.h13
-rw-r--r--src/corelib/tools/qbytearray.cpp311
-rw-r--r--src/corelib/tools/qbytearray.h132
-rw-r--r--src/corelib/tools/qdatetime_p.h5
-rw-r--r--src/corelib/tools/qstring.cpp60
-rw-r--r--src/corelib/tools/qstring.h8
-rw-r--r--src/gui/text/qfontengine_ft.cpp4
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp2
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h3
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp97
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h1
-rw-r--r--src/network/access/qhttpnetworkreply.cpp239
-rw-r--r--src/network/access/qhttpnetworkreply_p.h26
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp12
-rw-r--r--src/network/ssl/qsslcertificate.cpp16
-rw-r--r--src/network/ssl/qsslcertificate.h3
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp181
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h2
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp6
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h4
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp3
21 files changed, 633 insertions, 495 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 844fe0528e..4960d2a245 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -540,6 +540,7 @@ namespace QT_NAMESPACE {}
# define Q_COMPILER_DEFAULT_DELETE_MEMBERS
# define Q_COMPILER_CLASS_ENUM
# define Q_COMPILER_INITIALIZER_LISTS
+# define Q_COMPILER_ATOMICS
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
/* C++0x features supported in GCC 4.5: */
@@ -547,7 +548,10 @@ namespace QT_NAMESPACE {}
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
/* C++0x features supported in GCC 4.6: */
+# define Q_COMPILER_NULLPTR
# define Q_COMPILER_CONSTEXPR
+# define Q_COMPILER_UNRESTRICTED_UNIONS
+# define Q_COMPILER_RANGE_FOR
# endif
# endif
@@ -799,11 +803,10 @@ namespace QT_NAMESPACE {}
# define Q_NO_TEMPLATE_FRIENDS
# endif
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
-# if __INTEL_COMPILER >= 1100
+# if __INTEL_COMPILER >= 1200
# define Q_COMPILER_RVALUE_REFS
# define Q_COMPILER_EXTERN_TEMPLATES
# define Q_COMPILER_DECLTYPE
-# elif __INTEL_COMPILER >= 1200
# define Q_COMPILER_VARIADIC_TEMPLATES
# define Q_COMPILER_AUTO_TYPE
# define Q_COMPILER_DEFAULT_DELETE_MEMBERS
@@ -1114,6 +1117,12 @@ redefine to built-in booleans to make autotests work properly */
# define QT_FASTCALL
#endif
+#ifdef Q_COMPILER_NULLPTR
+# define Q_NULLPTR nullptr
+#else
+# define Q_NULLPTR 0
+#endif
+
#ifdef Q_COMPILER_CONSTEXPR
# define Q_DECL_CONSTEXPR constexpr
#else
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 767b71338f..0c5276f442 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -57,7 +57,7 @@
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) ((d)->data != (d)->array)
+#define IS_RAW_DATA(d) ((d)->offset != 0)
QT_BEGIN_NAMESPACE
@@ -546,7 +546,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
qWarning("qUncompress: Input data is corrupted");
return QByteArray();
}
- QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + alloc));
+ QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + alloc + 1));
if (!p) {
// we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
qWarning("qUncompress: could not allocate enough memory to uncompress data");
@@ -554,8 +554,9 @@ QByteArray qUncompress(const uchar* data, int nbytes)
}
d.take(); // realloc was successful
d.reset(p);
+ d->offset = 0;
- int res = ::uncompress((uchar*)d->array, &len,
+ int res = ::uncompress((uchar*)d->data(), &len,
(uchar*)data+4, nbytes-4);
switch (res) {
@@ -566,7 +567,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
qWarning("qUncompress: Input data is corrupted");
return QByteArray();
}
- QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + len));
+ QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + len + 1));
if (!p) {
// we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
qWarning("qUncompress: could not allocate enough memory to uncompress data");
@@ -576,9 +577,11 @@ QByteArray qUncompress(const uchar* data, int nbytes)
d.reset(p);
}
d->ref = 1;
- d->alloc = d->size = len;
- d->data = d->array;
- d->array[len] = 0;
+ d->size = len;
+ d->alloc = len;
+ d->capacityReserved = false;
+ d->offset = 0;
+ d->data()[len] = 0;
return QByteArray(d.take(), 0, 0);
@@ -611,10 +614,10 @@ static inline char qToLower(char c)
return c;
}
-QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1),
- 0, 0, shared_null.array, {0} };
-QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1),
- 0, 0, shared_empty.array, {0} };
+QConstByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZER(-1),
+ 0, 0, 0, { 0 } }, { 0 } };
+QConstByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1),
+ 0, 0, 0, { 0 } }, { 0 } };
/*!
\class QByteArray
@@ -896,15 +899,15 @@ QByteArray &QByteArray::operator=(const char *str)
{
Data *x;
if (!str) {
- x = &shared_null;
+ x = const_cast<Data *>(&shared_null.ba);
} else if (!*str) {
- x = &shared_empty;
+ x = const_cast<Data *>(&shared_empty.ba);
} else {
int len = qstrlen(str);
if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1))
realloc(len);
x = d;
- memcpy(x->data, str, len + 1); // include null terminator
+ memcpy(x->data(), str, len + 1); // include null terminator
x->size = len;
}
x->ref.ref();
@@ -1294,19 +1297,20 @@ void QByteArray::chop(int n)
QByteArray::QByteArray(const char *str)
{
if (!str) {
- d = &shared_null;
+ d = const_cast<Data *>(&shared_null.ba);
} else if (!*str) {
- d = &shared_empty;
+ d = const_cast<Data *>(&shared_empty.ba);
} else {
int len = qstrlen(str);
- d = static_cast<Data *>(qMalloc(sizeof(Data)+len));
+ d = static_cast<Data *>(qMalloc(sizeof(Data) + len + 1));
Q_CHECK_PTR(d);
- d->ref = 0;;
- d->alloc = d->size = len;
- d->data = d->array;
- memcpy(d->array, str, len+1); // include null terminator
+ d->ref = 1;
+ d->size = len;
+ d->alloc = len;
+ d->capacityReserved = false;
+ d->offset = 0;
+ memcpy(d->data(), str, len+1); // include null terminator
}
- d->ref.ref();
}
/*!
@@ -1323,19 +1327,20 @@ QByteArray::QByteArray(const char *str)
QByteArray::QByteArray(const char *data, int size)
{
if (!data) {
- d = &shared_null;
+ d = const_cast<Data *>(&shared_null.ba);
} else if (size <= 0) {
- d = &shared_empty;
+ d = const_cast<Data *>(&shared_empty.ba);
} else {
- d = static_cast<Data *>(qMalloc(sizeof(Data) + size));
+ d = static_cast<Data *>(qMalloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d);
- d->ref = 0;
- d->alloc = d->size = size;
- d->data = d->array;
- memcpy(d->array, data, size);
- d->array[size] = '\0';
+ d->ref = 1;
+ d->size = size;
+ d->alloc = size;
+ d->capacityReserved = false;
+ d->offset = 0;
+ memcpy(d->data(), data, size);
+ d->data()[size] = '\0';
}
- d->ref.ref();
}
/*!
@@ -1348,17 +1353,18 @@ QByteArray::QByteArray(const char *data, int size)
QByteArray::QByteArray(int size, char ch)
{
if (size <= 0) {
- d = &shared_null;
+ d = const_cast<Data *>(&shared_null.ba);
} else {
- d = static_cast<Data *>(qMalloc(sizeof(Data)+size));
+ d = static_cast<Data *>(qMalloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d);
- d->ref = 0;
- d->alloc = d->size = size;
- d->data = d->array;
- d->array[size] = '\0';
- memset(d->array, ch, size);
+ d->ref = 1;
+ d->size = size;
+ d->alloc = size;
+ d->capacityReserved = false;
+ d->offset = 0;
+ memset(d->data(), ch, size);
+ d->data()[size] = '\0';
}
- d->ref.ref();
}
/*!
@@ -1369,12 +1375,14 @@ QByteArray::QByteArray(int size, char ch)
QByteArray::QByteArray(int size, Qt::Initialization)
{
- d = static_cast<Data *>(qMalloc(sizeof(Data)+size));
+ d = static_cast<Data *>(qMalloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d);
d->ref = 1;
- d->alloc = d->size = size;
- d->data = d->array;
- d->array[size] = '\0';
+ d->size = size;
+ d->alloc = size;
+ d->capacityReserved = false;
+ d->offset = 0;
+ d->data()[size] = '\0';
}
/*!
@@ -1392,13 +1400,20 @@ QByteArray::QByteArray(int size, Qt::Initialization)
void QByteArray::resize(int size)
{
- if (size <= 0) {
- Data *x = &shared_empty;
- x->ref.ref();
+ if (size < 0)
+ size = 0;
+
+ if (d->offset && d->ref == 1 && size < d->size) {
+ d->size = size;
+ return;
+ }
+
+ if (size == 0 && !d->capacityReserved) {
+ Data *x = const_cast<Data *>(&shared_empty.ba);
if (!d->ref.deref())
qFree(d);
d = x;
- } else if (d == &shared_null) {
+ } else if (d == &shared_null.ba || d == &shared_empty.ba) {
//
// Optimize the idiom:
// QByteArray a;
@@ -1407,22 +1422,21 @@ void QByteArray::resize(int size)
// which is used in place of the Qt 3 idiom:
// QByteArray a(sz);
//
- Data *x = static_cast<Data *>(qMalloc(sizeof(Data)+size));
+ Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(x);
x->ref = 1;
- x->alloc = x->size = size;
- x->data = x->array;
- x->array[size] = '\0';
- (void) d->ref.deref(); // cannot be 0, x points to shared_null
+ x->size = size;
+ x->alloc = size;
+ x->capacityReserved = false;
+ x->offset = 0;
+ x->data()[size] = '\0';
d = x;
} else {
- if (d->ref != 1 || size > d->alloc || (size < d->size && size < d->alloc >> 1))
+ if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1))
realloc(qAllocMore(size, sizeof(Data)));
if (d->alloc >= size) {
d->size = size;
- if (d->data == d->array) {
- d->array[size] = '\0';
- }
+ d->data()[size] = '\0';
}
}
}
@@ -1442,29 +1456,30 @@ QByteArray &QByteArray::fill(char ch, int size)
{
resize(size < 0 ? d->size : size);
if (d->size)
- memset(d->data, ch, d->size);
+ memset(d->data(), ch, d->size);
return *this;
}
void QByteArray::realloc(int alloc)
{
- if (d->ref != 1 || d->data != d->array) {
- Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc));
+ if (d->ref != 1 || d->offset) {
+ Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x);
- x->size = qMin(alloc, d->size);
- ::memcpy(x->array, d->data, x->size);
- x->array[x->size] = '\0';
x->ref = 1;
+ x->size = qMin(alloc, d->size);
x->alloc = alloc;
- x->data = x->array;
+ x->capacityReserved = d->capacityReserved;
+ x->offset = 0;
+ ::memcpy(x->data(), d->data(), x->size);
+ x->data()[x->size] = '\0';
if (!d->ref.deref())
qFree(d);
d = x;
} else {
- Data *x = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc));
+ Data *x = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x);
x->alloc = alloc;
- x->data = x->array;
+ x->offset = 0;
d = x;
}
}
@@ -1486,7 +1501,7 @@ void QByteArray::expand(int i)
QByteArray QByteArray::nulTerminated() const
{
// is this fromRawData?
- if (d->data == d->array)
+ if (!d->offset)
return *this; // no, then we're sure we're zero terminated
QByteArray copy(*this);
@@ -1517,9 +1532,9 @@ QByteArray QByteArray::nulTerminated() const
QByteArray &QByteArray::prepend(const QByteArray &ba)
{
- if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) {
+ if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba;
- } else if (ba.d != &shared_null) {
+ } else if (ba.d != &shared_null.ba) {
QByteArray tmp = *this;
*this = ba;
append(tmp);
@@ -1550,10 +1565,10 @@ QByteArray &QByteArray::prepend(const char *str, int len)
if (str) {
if (d->ref != 1 || d->size + len > d->alloc)
realloc(qAllocMore(d->size + len, sizeof(Data)));
- memmove(d->data+len, d->data, d->size);
- memcpy(d->data, str, len);
+ memmove(d->data()+len, d->data(), d->size);
+ memcpy(d->data(), str, len);
d->size += len;
- d->data[d->size] = '\0';
+ d->data()[d->size] = '\0';
}
return *this;
}
@@ -1568,10 +1583,10 @@ QByteArray &QByteArray::prepend(char ch)
{
if (d->ref != 1 || d->size + 1 > d->alloc)
realloc(qAllocMore(d->size + 1, sizeof(Data)));
- memmove(d->data+1, d->data, d->size);
- d->data[0] = ch;
+ memmove(d->data()+1, d->data(), d->size);
+ d->data()[0] = ch;
++d->size;
- d->data[d->size] = '\0';
+ d->data()[d->size] = '\0';
return *this;
}
@@ -1601,14 +1616,14 @@ QByteArray &QByteArray::prepend(char ch)
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) {
+ if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba;
- } else if (ba.d != &shared_null) {
+ } else if (ba.d != &shared_null.ba) {
if (d->ref != 1 || d->size + ba.d->size > d->alloc)
realloc(qAllocMore(d->size + ba.d->size, sizeof(Data)));
- memcpy(d->data + d->size, ba.d->data, ba.d->size);
+ memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
- d->data[d->size] = '\0';
+ d->data()[d->size] = '\0';
}
return *this;
}
@@ -1640,7 +1655,7 @@ QByteArray& QByteArray::append(const char *str)
int len = qstrlen(str);
if (d->ref != 1 || d->size + len > d->alloc)
realloc(qAllocMore(d->size + len, sizeof(Data)));
- memcpy(d->data + d->size, str, len + 1); // include null terminator
+ memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
}
return *this;
@@ -1665,9 +1680,9 @@ QByteArray &QByteArray::append(const char *str, int len)
if (str && len) {
if (d->ref != 1 || d->size + len > d->alloc)
realloc(qAllocMore(d->size + len, sizeof(Data)));
- memcpy(d->data + d->size, str, len); // include null terminator
+ memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
- d->data[d->size] = '\0';
+ d->data()[d->size] = '\0';
}
return *this;
}
@@ -1682,8 +1697,8 @@ QByteArray& QByteArray::append(char ch)
{
if (d->ref != 1 || d->size + 1 > d->alloc)
realloc(qAllocMore(d->size + 1, sizeof(Data)));
- d->data[d->size++] = ch;
- d->data[d->size] = '\0';
+ d->data()[d->size++] = ch;
+ d->data()[d->size] = '\0';
return *this;
}
@@ -1724,7 +1739,7 @@ static inline QByteArray &qbytearray_insert(QByteArray *ba,
QByteArray &QByteArray::insert(int i, const QByteArray &ba)
{
QByteArray copy(ba);
- return qbytearray_insert(this, i, copy.d->data, copy.d->size);
+ return qbytearray_insert(this, i, copy.d->data(), copy.d->size);
}
/*!
@@ -1812,7 +1827,7 @@ QByteArray &QByteArray::remove(int pos, int len)
if (pos + len >= d->size) {
resize(pos);
} else {
- memmove(d->data + pos, d->data + pos + len, d->size - pos - len);
+ memmove(d->data() + pos, d->data() + pos + len, d->size - pos - len);
resize(d->size - len);
}
return *this;
@@ -1832,7 +1847,7 @@ QByteArray &QByteArray::replace(int pos, int len, const QByteArray &after)
{
if (len == after.d->size && (pos + len <= d->size)) {
detach();
- memmove(d->data + pos, after.d->data, len*sizeof(char));
+ memmove(d->data() + pos, after.d->data(), len*sizeof(char));
return *this;
} else {
QByteArray copy(after);
@@ -1869,7 +1884,7 @@ QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen)
{
if (len == alen && (pos + len <= d->size)) {
detach();
- memcpy(d->data + pos, after, len*sizeof(char));
+ memcpy(d->data() + pos, after, len*sizeof(char));
return *this;
} else {
remove(pos, len);
@@ -1936,13 +1951,13 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
// protect against before or after being part of this
const char *a = after;
const char *b = before;
- if (after >= d->data && after < d->data + d->size) {
+ if (after >= d->data() && after < d->data() + d->size) {
char *copy = (char *)malloc(asize);
Q_CHECK_PTR(copy);
memcpy(copy, after, asize);
a = copy;
}
- if (before >= d->data && before < d->data + d->size) {
+ if (before >= d->data() && before < d->data() + d->size) {
char *copy = (char *)malloc(bsize);
Q_CHECK_PTR(copy);
memcpy(copy, before, bsize);
@@ -2019,7 +2034,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after
resize(newlen);
len = newlen;
}
- d = this->d->data;
+ d = this->d->data();
while(pos) {
pos--;
@@ -2192,19 +2207,19 @@ QByteArray QByteArray::repeated(int times) const
if (result.d->alloc != resultSize)
return QByteArray(); // not enough memory
- memcpy(result.d->data, d->data, d->size);
+ memcpy(result.d->data(), d->data(), d->size);
int sizeSoFar = d->size;
- char *end = result.d->data + sizeSoFar;
+ char *end = result.d->data() + sizeSoFar;
const int halfResultSize = resultSize >> 1;
while (sizeSoFar <= halfResultSize) {
- memcpy(end, result.d->data, sizeSoFar);
+ memcpy(end, result.d->data(), sizeSoFar);
end += sizeSoFar;
sizeSoFar <<= 1;
}
- memcpy(end, result.d->data, resultSize - sizeSoFar);
- result.d->data[resultSize] = '\0';
+ memcpy(end, result.d->data(), resultSize - sizeSoFar);
+ result.d->data()[resultSize] = '\0';
result.d->size = resultSize;
return result;
}
@@ -2231,13 +2246,13 @@ int QByteArray::indexOf(const QByteArray &ba, int from) const
if (ol == 0)
return from;
if (ol == 1)
- return indexOf(*ba.d->data, from);
+ return indexOf(*ba.d->data(), from);
const int l = d->size;
if (from > d->size || ol + from > l)
return -1;
- return qFindByteArray(d->data, d->size, from, ba.d->data, ol);
+ return qFindByteArray(d->data(), d->size, from, ba.d->data(), ol);
}
/*! \fn int QByteArray::indexOf(const QString &str, int from) const
@@ -2279,7 +2294,7 @@ int QByteArray::indexOf(const char *c, int from) const
if (ol == 0)
return from;
- return qFindByteArray(d->data, d->size, from, c, ol);
+ return qFindByteArray(d->data(), d->size, from, c, ol);
}
/*!
@@ -2300,11 +2315,11 @@ int QByteArray::indexOf(char ch, int from) const
if (from < 0)
from = qMax(from + d->size, 0);
if (from < d->size) {
- const char *n = d->data + from - 1;
- const char *e = d->data + d->size;
+ const char *n = d->data() + from - 1;
+ const char *e = d->data() + d->size;
while (++n != e)
if (*n == ch)
- return n - d->data;
+ return n - d->data();
}
return -1;
}
@@ -2361,9 +2376,9 @@ int QByteArray::lastIndexOf(const QByteArray &ba, int from) const
{
const int ol = ba.d->size;
if (ol == 1)
- return lastIndexOf(*ba.d->data, from);
+ return lastIndexOf(*ba.d->data(), from);
- return lastIndexOfHelper(d->data, d->size, ba.d->data, ol, from);
+ return lastIndexOfHelper(d->data(), d->size, ba.d->data(), ol, from);
}
/*! \fn int QByteArray::lastIndexOf(const QString &str, int from) const
@@ -2400,7 +2415,7 @@ int QByteArray::lastIndexOf(const char *str, int from) const
if (ol == 1)
return lastIndexOf(*str, from);
- return lastIndexOfHelper(d->data, d->size, str, ol, from);
+ return lastIndexOfHelper(d->data(), d->size, str, ol, from);
}
/*!
@@ -2424,8 +2439,8 @@ int QByteArray::lastIndexOf(char ch, int from) const
else if (from > d->size)
from = d->size-1;
if (from >= 0) {
- const char *b = d->data;
- const char *n = d->data + from + 1;
+ const char *b = d->data();
+ const char *n = d->data() + from + 1;
while (n-- != b)
if (*n == ch)
return n - b;
@@ -2479,8 +2494,8 @@ int QByteArray::count(const char *str) const
int QByteArray::count(char ch) const
{
int num = 0;
- const char *i = d->data + d->size;
- const char *b = d->data;
+ const char *i = d->data() + d->size;
+ const char *b = d->data();
while (i != b)
if (*--i == ch)
++num;
@@ -2509,7 +2524,7 @@ bool QByteArray::startsWith(const QByteArray &ba) const
return true;
if (d->size < ba.d->size)
return false;
- return memcmp(d->data, ba.d->data, ba.d->size) == 0;
+ return memcmp(d->data(), ba.d->data(), ba.d->size) == 0;
}
/*! \overload
@@ -2524,7 +2539,7 @@ bool QByteArray::startsWith(const char *str) const
int len = qstrlen(str);
if (d->size < len)
return false;
- return qstrncmp(d->data, str, len) == 0;
+ return qstrncmp(d->data(), str, len) == 0;
}
/*! \overload
@@ -2536,7 +2551,7 @@ bool QByteArray::startsWith(char ch) const
{
if (d->size == 0)
return false;
- return d->data[0] == ch;
+ return d->data()[0] == ch;
}
/*!
@@ -2554,7 +2569,7 @@ bool QByteArray::endsWith(const QByteArray &ba) const
return true;
if (d->size < ba.d->size)
return false;
- return memcmp(d->data + d->size - ba.d->size, ba.d->data, ba.d->size) == 0;
+ return memcmp(d->data() + d->size - ba.d->size, ba.d->data(), ba.d->size) == 0;
}
/*! \overload
@@ -2569,7 +2584,7 @@ bool QByteArray::endsWith(const char *str) const
int len = qstrlen(str);
if (d->size < len)
return false;
- return qstrncmp(d->data + d->size - len, str, len) == 0;
+ return qstrncmp(d->data() + d->size - len, str, len) == 0;
}
/*! \overload
@@ -2581,7 +2596,7 @@ bool QByteArray::endsWith(char ch) const
{
if (d->size == 0)
return false;
- return d->data[d->size - 1] == ch;
+ return d->data()[d->size - 1] == ch;
}
/*!
@@ -2603,7 +2618,7 @@ QByteArray QByteArray::left(int len) const
return *this;
if (len < 0)
len = 0;
- return QByteArray(d->data, len);
+ return QByteArray(d->data(), len);
}
/*!
@@ -2625,7 +2640,7 @@ QByteArray QByteArray::right(int len) const
return *this;
if (len < 0)
len = 0;
- return QByteArray(d->data + d->size - len, len);
+ return QByteArray(d->data() + d->size - len, len);
}
/*!
@@ -2644,7 +2659,7 @@ QByteArray QByteArray::right(int len) const
QByteArray QByteArray::mid(int pos, int len) const
{
- if (d == &shared_null || d == &shared_empty || pos >= d->size)
+ if (d == &shared_null.ba || d == &shared_empty.ba || pos >= d->size)
return QByteArray();
if (len < 0)
len = d->size - pos;
@@ -2656,7 +2671,7 @@ QByteArray QByteArray::mid(int pos, int len) const
len = d->size - pos;
if (pos == 0 && len == d->size)
return *this;
- return QByteArray(d->data + pos, len);
+ return QByteArray(d->data() + pos, len);
}
/*!
@@ -2715,7 +2730,7 @@ void QByteArray::clear()
{
if (!d->ref.deref())
qFree(d);
- d = &shared_null;
+ d = const_cast<Data *>(&shared_null.ba);
d->ref.ref();
}
@@ -3106,10 +3121,10 @@ QByteArray QByteArray::simplified() const
if (d->size == 0)
return *this;
QByteArray result(d->size, Qt::Uninitialized);
- const char *from = d->data;
+ const char *from = d->data();
const char *fromend = from + d->size;
int outc=0;
- char *to = result.d->data;
+ char *to = result.d->data();
for (;;) {
while (from!=fromend && isspace(uchar(*from)))
from++;
@@ -3145,7 +3160,7 @@ QByteArray QByteArray::trimmed() const
{
if (d->size == 0)
return *this;
- const char *s = d->data;
+ const char *s = d->data();
if (!isspace(uchar(*s)) && !isspace(uchar(s[d->size-1])))
return *this;
int start = 0;
@@ -3158,8 +3173,7 @@ QByteArray QByteArray::trimmed() const
}
int l = end - start + 1;
if (l <= 0) {
- shared_empty.ref.ref();
- return QByteArray(&shared_empty, 0, 0);
+ return QByteArray(const_cast<Data *>(&shared_empty.ba), 0, 0);
}
return QByteArray(s+start, l);
}
@@ -3190,8 +3204,8 @@ QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const
if (padlen > 0) {
result.resize(len+padlen);
if (len)
- memcpy(result.d->data, d->data, len);
- memset(result.d->data+len, fill, padlen);
+ memcpy(result.d->data(), d->data(), len);
+ memset(result.d->data()+len, fill, padlen);
} else {
if (truncate)
result = left(width);
@@ -3227,8 +3241,8 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const
if (padlen > 0) {
result.resize(len+padlen);
if (len)
- memcpy(result.d->data+padlen, data(), len);
- memset(result.d->data, fill, padlen);
+ memcpy(result.d->data()+padlen, data(), len);
+ memset(result.d->data(), fill, padlen);
} else {
if (truncate)
result = left(width);
@@ -3238,7 +3252,7 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const
return result;
}
-bool QByteArray::isNull() const { return d == &shared_null; }
+bool QByteArray::isNull() const { return d == &shared_null.ba; }
/*!
@@ -3562,13 +3576,13 @@ QByteArray QByteArray::toBase64() const
char *out = tmp.data();
while (i < d->size) {
int chunk = 0;
- chunk |= int(uchar(d->data[i++])) << 16;
+ chunk |= int(uchar(d->data()[i++])) << 16;
if (i == d->size) {
padlen = 2;
} else {
- chunk |= int(uchar(d->data[i++])) << 8;
+ chunk |= int(uchar(d->data()[i++])) << 8;
if (i == d->size) padlen = 1;
- else chunk |= int(uchar(d->data[i++]));
+ else chunk |= int(uchar(d->data()[i++]));
}
int j = (chunk & 0x00fc0000) >> 18;
@@ -3864,17 +3878,20 @@ QByteArray QByteArray::number(double n, char f, int prec)
QByteArray QByteArray::fromRawData(const char *data, int size)
{
- Data *x = static_cast<Data *>(qMalloc(sizeof(Data)));
- Q_CHECK_PTR(x);
- if (data) {
- x->data = const_cast<char *>(data);
+ Data *x;
+ if (!data) {
+ x = const_cast<Data *>(&shared_null.ba);
+ } else if (!size) {
+ x = const_cast<Data *>(&shared_empty.ba);
} else {
- x->data = x->array;
- size = 0;
+ x = static_cast<Data *>(qMalloc(sizeof(Data) + 1));
+ Q_CHECK_PTR(x);
+ x->ref = 1;
+ x->size = size;
+ x->alloc = 0;
+ x->capacityReserved = false;
+ x->offset = data - (x->d + sizeof(qptrdiff));
}
- x->ref = 1;
- x->alloc = x->size = size;
- *x->array = '\0';
return QByteArray(x, 0, 0);
}
@@ -3898,13 +3915,13 @@ QByteArray &QByteArray::setRawData(const char *data, uint size)
*this = fromRawData(data, size);
} else {
if (data) {
- d->data = const_cast<char *>(data);
+ d->size = size;
+ d->offset = data - (d->d + sizeof(qptrdiff));
} else {
- d->data = d->array;
- size = 0;
+ d->offset = 0;
+ d->size = 0;
+ *d->data() = 0;
}
- d->alloc = d->size = size;
- *d->array = '\0';
}
return *this;
}
@@ -4013,7 +4030,7 @@ QByteArray QByteArray::toHex() const
{
QByteArray hex(d->size * 2, Qt::Uninitialized);
char *hexData = hex.data();
- const uchar *data = (const uchar *)d->data;
+ const uchar *data = (const uchar *)d->data();
for (int i = 0; i < d->size; ++i) {
int j = (data[i] >> 4) & 0xf;
if (j <= 9)
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 26cf2af59c..dbac302d05 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -42,7 +42,7 @@
#ifndef QBYTEARRAY_H
#define QBYTEARRAY_H
-#include <QtCore/qatomic.h>
+#include <QtCore/qrefcount.h>
#include <QtCore/qnamespace.h>
#include <string.h>
@@ -119,18 +119,65 @@ class QString;
class QDataStream;
template <typename T> class QList;
+struct QByteArrayData
+{
+ QtPrivate::RefCount ref;
+ int size;
+ uint alloc : 31;
+ uint capacityReserved : 1;
+ union {
+ qptrdiff offset; // will always work as we add/subtract from a ushort ptr
+ char d[sizeof(qptrdiff)];
+ };
+ inline char *data() { return d + sizeof(qptrdiff) + offset; }
+ inline const char *data() const { return d + sizeof(qptrdiff) + offset; }
+};
+
+template<int n> struct QConstByteArrayData
+{
+ const QByteArrayData ba;
+ const char data[n];
+};
+
+template<int N> struct QConstByteArrayDataPtr
+{
+ const QConstByteArrayData<N> *ptr;
+};
+
+
+#if defined(Q_COMPILER_LAMBDA)
+# define QByteArrayLiteral(str) ([]() { \
+ enum { Size = sizeof(str) }; \
+ static const QConstByteArrayData<Size> qbytearray_literal = \
+ { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \
+ QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
+ return holder; }())
+
+#elif defined(Q_CC_GNU)
+// We need to create a QByteArrayData in the .rodata section of memory
+// and the only way to do that is to create a "static const" variable.
+// To do that, we need the __extension__ {( )} trick which only GCC supports
+
+# define QByteArrayLiteral(str) \
+ __extension__ ({ \
+ enum { Size = sizeof(str) }; \
+ static const QConstByteArrayData<Size> qbytearray_literal = \
+ { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \
+ QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
+ holder; })
+#endif
+
+#ifndef QByteArrayLiteral
+// no lambdas, not GCC, use const char * instead
+
+# define QByteArrayLiteral(str) (str)
+#endif
+
+
class Q_CORE_EXPORT QByteArray
{
private:
- struct Data {
- QBasicAtomicInt ref;
- int alloc, size;
- // ### Qt 5.0: We need to add the missing capacity bit
- // (like other tool classes have), to maintain the
- // reserved memory on resize.
- char *data;
- char array[1];
- };
+ typedef QByteArrayData Data;
public:
inline QByteArray();
@@ -330,10 +377,17 @@ public:
int length() const { return d->size; }
bool isNull() const;
+ template <int n>
+ inline QByteArray(const QConstByteArrayData<n> &dd)
+ : d(const_cast<QByteArrayData *>(&dd.str)) {}
+ template <int N>
+ Q_DECL_CONSTEXPR inline QByteArray(QConstByteArrayDataPtr<N> dd)
+ : d(const_cast<QByteArrayData *>(&dd.ptr->ba)) {}
+
private:
operator QNoImplicitBoolCast() const;
- static Data shared_null;
- static Data shared_empty;
+ static QConstByteArrayData<1> shared_null;
+ static QConstByteArrayData<1> shared_empty;
Data *d;
QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {}
void realloc(int alloc);
@@ -348,34 +402,34 @@ public:
inline DataPtr &data_ptr() { return d; }
};
-inline QByteArray::QByteArray(): d(&shared_null) { d->ref.ref(); }
+inline QByteArray::QByteArray(): d(const_cast<Data *>(&shared_null.ba)) { d->ref.ref(); }
inline QByteArray::~QByteArray() { if (!d->ref.deref()) qFree(d); }
inline int QByteArray::size() const
{ return d->size; }
inline char QByteArray::at(int i) const
-{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; }
+{ Q_ASSERT(i >= 0 && i < size()); return d->data()[i]; }
inline char QByteArray::operator[](int i) const
-{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; }
+{ Q_ASSERT(i >= 0 && i < size()); return d->data()[i]; }
inline char QByteArray::operator[](uint i) const
-{ Q_ASSERT(i < uint(size())); return d->data[i]; }
+{ Q_ASSERT(i < uint(size())); return d->data()[i]; }
inline bool QByteArray::isEmpty() const
{ return d->size == 0; }
#ifndef QT_NO_CAST_FROM_BYTEARRAY
inline QByteArray::operator const char *() const
-{ return d->data; }
+{ return d->data(); }
inline QByteArray::operator const void *() const
-{ return d->data; }
+{ return d->data(); }
#endif
inline char *QByteArray::data()
-{ detach(); return d->data; }
+{ detach(); return d->data(); }
inline const char *QByteArray::data() const
-{ return d->data; }
+{ return d->data(); }
inline const char *QByteArray::constData() const
-{ return d->data; }
+{ return d->data(); }
inline void QByteArray::detach()
-{ if (d->ref != 1 || d->data != d->array) realloc(d->size); }
+{ if (d->ref != 1 || d->offset) realloc(d->size); }
inline bool QByteArray::isDetached() const
{ return d->ref == 1; }
inline QByteArray::QByteArray(const QByteArray &a) : d(a.d)
@@ -385,10 +439,10 @@ inline int QByteArray::capacity() const
{ return d->alloc; }
inline void QByteArray::reserve(int asize)
-{ if (d->ref != 1 || asize > d->alloc) realloc(asize); }
+{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; }
inline void QByteArray::squeeze()
-{ if (d->size < d->alloc) realloc(d->size); }
+{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; }
class Q_CORE_EXPORT QByteRef {
QByteArray &a;
@@ -398,25 +452,25 @@ class Q_CORE_EXPORT QByteRef {
friend class QByteArray;
public:
inline operator char() const
- { return i < a.d->size ? a.d->data[i] : char(0); }
+ { return i < a.d->size ? a.d->data()[i] : char(0); }
inline QByteRef &operator=(char c)
{ if (i >= a.d->size) a.expand(i); else a.detach();
- a.d->data[i] = c; return *this; }
+ a.d->data()[i] = c; return *this; }
inline QByteRef &operator=(const QByteRef &c)
{ if (i >= a.d->size) a.expand(i); else a.detach();
- a.d->data[i] = c.a.d->data[c.i]; return *this; }
+ a.d->data()[i] = c.a.d->data()[c.i]; return *this; }
inline bool operator==(char c) const
- { return a.d->data[i] == c; }
+ { return a.d->data()[i] == c; }
inline bool operator!=(char c) const
- { return a.d->data[i] != c; }
+ { return a.d->data()[i] != c; }
inline bool operator>(char c) const
- { return a.d->data[i] > c; }
+ { return a.d->data()[i] > c; }
inline bool operator>=(char c) const
- { return a.d->data[i] >= c; }
+ { return a.d->data()[i] >= c; }
inline bool operator<(char c) const
- { return a.d->data[i] < c; }
+ { return a.d->data()[i] < c; }
inline bool operator<=(char c) const
- { return a.d->data[i] <= c; }
+ { return a.d->data()[i] <= c; }
};
inline QByteRef QByteArray::operator[](int i)
@@ -424,17 +478,17 @@ inline QByteRef QByteArray::operator[](int i)
inline QByteRef QByteArray::operator[](uint i)
{ return QByteRef(*this, i); }
inline QByteArray::iterator QByteArray::begin()
-{ detach(); return d->data; }
+{ detach(); return d->data(); }
inline QByteArray::const_iterator QByteArray::begin() const
-{ return d->data; }
+{ return d->data(); }
inline QByteArray::const_iterator QByteArray::constBegin() const
-{ return d->data; }
+{ return d->data(); }
inline QByteArray::iterator QByteArray::end()
-{ detach(); return d->data + d->size; }
+{ detach(); return d->data() + d->size; }
inline QByteArray::const_iterator QByteArray::end() const
-{ return d->data + d->size; }
+{ return d->data() + d->size; }
inline QByteArray::const_iterator QByteArray::constEnd() const
-{ return d->data + d->size; }
+{ return d->data() + d->size; }
inline QByteArray &QByteArray::operator+=(char c)
{ return append(c); }
inline QByteArray &QByteArray::operator+=(const char *s)
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h
index 8d931dccc0..c20f2123f9 100644
--- a/src/corelib/tools/qdatetime_p.h
+++ b/src/corelib/tools/qdatetime_p.h
@@ -76,17 +76,16 @@
QT_BEGIN_NAMESPACE
-class QDateTimePrivate
+class QDateTimePrivate : public QSharedData
{
public:
enum Spec { LocalUnknown = -1, LocalStandard = 0, LocalDST = 1, UTC = 2, OffsetFromUTC = 3};
QDateTimePrivate() : spec(LocalUnknown), utcOffset(0) {}
QDateTimePrivate(const QDateTimePrivate &other)
- : date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset)
+ : QSharedData(other), date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset)
{}
- QAtomicInt ref;
QDate date;
QTime time;
Spec spec;
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index dab281cdf8..b5efc85391 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -1051,7 +1051,11 @@ QString::QString(const QChar *unicode, int size)
} else {
d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } };
+ d->ref = 1;
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = 0;
memcpy(d->data(), unicode, size * sizeof(QChar));
d->data()[size] = '\0';
}
@@ -1079,7 +1083,11 @@ QString::QString(const QChar *unicode)
} else {
d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } };
+ d->ref = 1;
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = 0;
memcpy(d->data(), unicode, size * sizeof(QChar));
d->data()[size] = '\0';
}
@@ -1100,7 +1108,11 @@ QString::QString(int size, QChar ch)
} else {
d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } };
+ d->ref = 1;
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = 0;
d->data()[size] = '\0';
ushort *i = d->data() + size;
ushort *b = d->data();
@@ -1120,7 +1132,11 @@ QString::QString(int size, Qt::Initialization)
{
d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } };
+ d->ref = 1;
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = 0;
d->data()[size] = '\0';
}
@@ -1138,7 +1154,11 @@ QString::QString(QChar ch)
{
d = (Data *) qMalloc(sizeof(Data) + 2*sizeof(QChar));
Q_CHECK_PTR(d);
- *d = (Data) { Q_REFCOUNT_INITIALIZER(1), 1, 1, false, { 0 } };
+ d->ref = 1;
+ d->size = 1;
+ d->alloc = 1;
+ d->capacityReserved = false;
+ d->offset = 0;
d->data()[0] = ch.unicode();
d->data()[1] = '\0';
}
@@ -1313,7 +1333,11 @@ void QString::realloc(int alloc)
if (d->ref != 1 || d->offset) {
Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + (alloc+1) * sizeof(QChar)));
Q_CHECK_PTR(x);
- *x = (Data){ Q_REFCOUNT_INITIALIZER(1), qMin(alloc, d->size), alloc, d->capacityReserved, { 0 } };
+ x->ref = 1;
+ x->size = qMin(alloc, d->size);
+ x->alloc = (uint) alloc;
+ x->capacityReserved = d->capacityReserved;
+ x->offset =0;
::memcpy(x->data(), d->data(), x->size * sizeof(QChar));
x->data()[x->size] = 0;
if (!d->ref.deref())
@@ -3747,7 +3771,11 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
size = qstrlen(str);
d = static_cast<Data *>(qMalloc(sizeof(Data) + (size+1) * sizeof(QChar)));
Q_CHECK_PTR(d);
- *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } };
+ d->ref = 1;
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = 0;
d->data()[size] = '\0';
ushort *dst = d->data();
/* SIMD:
@@ -7071,13 +7099,19 @@ bool QString::isRightToLeft() const
*/
QString QString::fromRawData(const QChar *unicode, int size)
{
- Data *x = static_cast<Data *>(qMalloc(sizeof(Data)));
- *x = (Data){ Q_REFCOUNT_INITIALIZER(1), size, 0, false, { 0 } };
- Q_CHECK_PTR(x);
- if (unicode) {
- x->offset = (const ushort *)unicode - (x->d + sizeof(qptrdiff)/sizeof(ushort));
+ Data *x;
+ if (!unicode) {
+ x = const_cast<Data *>(&shared_null.str);
+ } else if (!size) {
+ x = const_cast<Data *>(&shared_empty.str);
} else {
- size = 0;
+ x = static_cast<Data *>(qMalloc(sizeof(Data) + sizeof(ushort)));
+ Q_CHECK_PTR(x);
+ x->ref = 1;
+ x->size = size;
+ x->alloc = 0;
+ x->capacityReserved = false;
+ x->offset = (const ushort *)unicode - (x->d + sizeof(qptrdiff)/sizeof(ushort));
}
return QString(x, 0);
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 27948e04ea..45ff00211e 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -185,7 +185,7 @@ public:
int capacity() const;
inline void reserve(int size);
- inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacityReserved = false;}
+ inline void squeeze() { if (d->size < (int)d->alloc || d->ref != 1) realloc(); d->capacityReserved = false;}
inline const QChar *unicode() const;
inline QChar *data();
@@ -337,7 +337,7 @@ public:
inline QString &prepend(const QLatin1String &s) { return insert(0, s); }
inline QString &operator+=(QChar c) {
- if (d->ref != 1 || d->size + 1 > d->alloc)
+ if (d->ref != 1 || d->size + 1 > (int)d->alloc)
realloc(grow(d->size + 1));
d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0';
@@ -633,7 +633,7 @@ public:
class Q_CORE_EXPORT QLatin1String
{
public:
- inline explicit QLatin1String(const char *s) : m_size(s ? strlen(s) : 0), m_data(s) {}
+ inline explicit QLatin1String(const char *s) : m_size(s ? (int)strlen(s) : 0), m_data(s) {}
inline const char *latin1() const { return m_data; }
inline int size() const { return m_size; }
@@ -842,7 +842,7 @@ inline void QCharRef::setCell(uchar acell) { QChar(*this).setCell(acell); }
inline QString::QString() : d(const_cast<Data *>(&shared_null.str)) {}
inline QString::~QString() { if (!d->ref.deref()) free(d); }
-inline void QString::reserve(int asize) { if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true;}
+inline void QString::reserve(int asize) { if (d->ref != 1 || asize > (int)d->alloc) realloc(asize); d->capacityReserved = true;}
inline QString &QString::setUtf16(const ushort *autf16, int asize)
{ return setUnicode(reinterpret_cast<const QChar *>(autf16), asize); }
inline QCharRef QString::operator[](int i)
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index dd30a15030..25c7268a9c 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -1644,7 +1644,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
overall.y = qMin(overall.y, y);
xmax = qMax(xmax, x + g->width);
ymax = qMax(ymax, y + g->height);
- overall.xoff += qRound(g->advance);
+ overall.xoff += g->advance;
} else {
int left = FLOOR(face->glyph->metrics.horiBearingX);
int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
@@ -1657,7 +1657,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
overall.y = qMin(overall.y, y);
xmax = qMax(xmax, x + TRUNC(right - left));
ymax = qMax(ymax, y + TRUNC(top - bottom));
- overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
+ overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
}
}
overall.height = qMax(overall.height, ymax - overall.y);
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index a8a4fd9ae7..0f1132e2a8 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -271,7 +271,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
value = request.headerField("accept-encoding");
if (value.isEmpty()) {
#ifndef QT_NO_COMPRESS
- request.setHeaderField("Accept-Encoding", "gzip");
+ request.setHeaderField("Accept-Encoding", "gzip, deflate");
request.d->autoDecompress = true;
#else
// if zlib is not available set this to false always
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 0c86fd94b9..0652436b35 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -202,9 +202,6 @@ public:
QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket,
const QString &extraDetail = QString());
-#ifndef QT_NO_COMPRESS
- bool expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete);
-#endif
void removeReply(QHttpNetworkReply *reply);
QString hostName;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index b8ed8ee567..8be876dd48 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -403,7 +403,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
bytes += headerBytes;
// If headers were parsed successfully now it is the ReadingDataState
if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
- if (replyPrivate->isGzipped() && replyPrivate->autoDecompress) {
+ if (replyPrivate->isCompressed() && replyPrivate->autoDecompress) {
// remove the Content-Length from header
replyPrivate->removeAutoDecompressHeader();
} else {
@@ -448,12 +448,17 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
// the buffer in that size.
// note that this call will read only from the still buffered data
qint64 haveRead = replyPrivate->readBodyVeryFast(socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
- bytes += haveRead;
- replyPrivate->totalProgress += haveRead;
-
- // the user will get notified of it via progress signal
- if (haveRead > 0)
+ if (haveRead > 0) {
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
+ // the user will get notified of it via progress signal
emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
+ } else if (haveRead == 0) {
+ // Happens since this called in a loop. Currently no bytes available.
+ } else if (haveRead < 0) {
+ connection->d_func()->emitReplyError(socket, reply, QNetworkReply::RemoteHostClosedError);
+ break;
+ }
} else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
&& replyPrivate->bodyLength > 0) {
// bulk files like images should fulfill these properties and
@@ -470,30 +475,18 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
{
// use the traditional slower reading (for compressed encoding, chunked encoding,
// no content-length etc)
- QByteDataBuffer byteDatas;
- qint64 haveRead = replyPrivate->readBody(socket, &byteDatas);
- if (haveRead) {
+ qint64 haveRead = replyPrivate->readBody(socket, &replyPrivate->responseData);
+ if (haveRead > 0) {
bytes += haveRead;
- if (replyPrivate->autoDecompress)
- replyPrivate->appendCompressedReplyData(byteDatas);
- else
- replyPrivate->appendUncompressedReplyData(byteDatas);
-
- if (!replyPrivate->autoDecompress) {
- replyPrivate->totalProgress += bytes;
- if (replyPrivate->shouldEmitSignals()) {
- // important: At the point of this readyRead(), the byteDatas list must be empty,
- // else implicit sharing will trigger memcpy when the user is reading data!
- emit reply->readyRead();
- emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
- }
- }
-#ifndef QT_NO_COMPRESS
- else if (!expand(false)) { // expand a chunk if possible
- // If expand() failed we can just return, it had already called connection->emitReplyError()
- return;
+ replyPrivate->totalProgress += haveRead;
+ if (replyPrivate->shouldEmitSignals()) {
+ emit reply->readyRead();
+ emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
}
-#endif
+ } else if (haveRead == -1) {
+ // Some error occured
+ connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);
+ break;
}
}
// still in ReadingDataState? This function will be called again by the socket's readyRead
@@ -633,57 +626,9 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
return true;
}
-
-#ifndef QT_NO_COMPRESS
-bool QHttpNetworkConnectionChannel::expand(bool dataComplete)
-{
- Q_ASSERT(socket);
- Q_ASSERT(reply);
-
- qint64 total = reply->d_func()->compressedData.size();
- if (total >= CHUNK || dataComplete) {
- // uncompress the data
- QByteArray content, inflated;
- content = reply->d_func()->compressedData;
- reply->d_func()->compressedData.clear();
-
- int ret = Z_OK;
- if (content.size())
- ret = reply->d_func()->gunzipBodyPartially(content, inflated);
- int retCheck = (dataComplete) ? Z_STREAM_END : Z_OK;
- if (ret >= retCheck) {
- if (inflated.size()) {
- reply->d_func()->totalProgress += inflated.size();
- reply->d_func()->appendUncompressedReplyData(inflated);
- if (reply->d_func()->shouldEmitSignals()) {
- // important: At the point of this readyRead(), inflated must be cleared,
- // else implicit sharing will trigger memcpy when the user is reading data!
- emit reply->readyRead();
- emit reply->dataReadProgress(reply->d_func()->totalProgress, 0);
- }
- }
- } else {
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);
- return false;
- }
- }
- return true;
-}
-#endif
-
-
void QHttpNetworkConnectionChannel::allDone()
{
Q_ASSERT(reply);
-#ifndef QT_NO_COMPRESS
- // expand the whole data.
- if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) {
- bool expandResult = expand(true);
- // If expand() failed we can just return, it had already called connection->emitReplyError()
- if (!expandResult)
- return;
- }
-#endif
if (!reply) {
qWarning() << "QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt.nokia.com/";
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index c159f1a0c5..7a4dd07db1 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -149,7 +149,6 @@ public:
bool ensureConnection();
- bool expand(bool dataComplete);
void allDone(); // reply header + body have been read
void handleStatus(); // called from allDone()
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 00653b62e8..5b174dbc05 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -65,6 +65,11 @@ QHttpNetworkReply::~QHttpNetworkReply()
if (d->connection) {
d->connection->d_func()->removeReply(this);
}
+
+#ifndef QT_NO_COMPRESS
+ if (d->autoDecompress && d->isCompressed())
+ inflateEnd(&d->inflateStrm);
+#endif
}
QUrl QHttpNetworkReply::url() const
@@ -211,7 +216,7 @@ void QHttpNetworkReply::setDownstreamLimited(bool dsl)
bool QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
{
Q_D(QHttpNetworkReply);
- return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0);
+ return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0 && d->statusCode == 200);
}
void QHttpNetworkReply::setUserProvidedDownloadBuffer(char* b)
@@ -252,7 +257,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
chunkedTransferEncoding(false),
connectionCloseEnabled(true),
forceConnectionCloseEnabled(false),
- currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false),
+ currentChunkSize(0), currentChunkRead(0), connection(0),
autoDecompress(false), responseData(), requestIsPrepared(false)
,pipeliningUsed(false), downstreamLimited(false)
,userProvidedDownloadBuffer(0)
@@ -274,11 +279,9 @@ void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
currentChunkRead = 0;
connectionCloseEnabled = true;
#ifndef QT_NO_COMPRESS
- if (initInflate)
+ if (autoDecompress)
inflateEnd(&inflateStrm);
#endif
- initInflate = false;
- streamEnd = false;
fields.clear();
}
@@ -297,10 +300,10 @@ qint64 QHttpNetworkReplyPrivate::bytesAvailable() const
return (state != ReadingDataState ? 0 : fragment.size());
}
-bool QHttpNetworkReplyPrivate::isGzipped()
+bool QHttpNetworkReplyPrivate::isCompressed()
{
QByteArray encoding = headerField("content-encoding");
- return qstricmp(encoding.constData(), "gzip") == 0;
+ return qstricmp(encoding.constData(), "gzip") == 0 || qstricmp(encoding.constData(), "deflate") == 0;
}
void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
@@ -358,120 +361,6 @@ QAuthenticatorPrivate::Method QHttpNetworkReplyPrivate::authenticationMethod(boo
return method;
}
-#ifndef QT_NO_COMPRESS
-bool QHttpNetworkReplyPrivate::gzipCheckHeader(QByteArray &content, int &pos)
-{
- int method = 0; // method byte
- int flags = 0; // flags byte
- bool ret = false;
-
- // Assure two bytes in the buffer so we can peek ahead -- handle case
- // where first byte of header is at the end of the buffer after the last
- // gzip segment
- pos = -1;
- QByteArray &body = content;
- int maxPos = body.size()-1;
- if (maxPos < 1) {
- return ret;
- }
-
- // Peek ahead to check the gzip magic header
- if (body[0] != char(gz_magic[0]) ||
- body[1] != char(gz_magic[1])) {
- return ret;
- }
- pos += 2;
- // Check the rest of the gzip header
- if (++pos <= maxPos)
- method = body[pos];
- if (pos++ <= maxPos)
- flags = body[pos];
- if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
- return ret;
- }
-
- // Discard time, xflags and OS code:
- pos += 6;
- if (pos > maxPos)
- return ret;
- if ((flags & EXTRA_FIELD) && ((pos+2) <= maxPos)) { // skip the extra field
- unsigned len = (unsigned)body[++pos];
- len += ((unsigned)body[++pos])<<8;
- pos += len;
- if (pos > maxPos)
- return ret;
- }
- if ((flags & ORIG_NAME) != 0) { // skip the original file name
- while(++pos <= maxPos && body[pos]) {}
- }
- if ((flags & COMMENT) != 0) { // skip the .gz file comment
- while(++pos <= maxPos && body[pos]) {}
- }
- if ((flags & HEAD_CRC) != 0) { // skip the header crc
- pos += 2;
- if (pos > maxPos)
- return ret;
- }
- ret = (pos < maxPos); // return failed, if no more bytes left
- return ret;
-}
-
-int QHttpNetworkReplyPrivate::gunzipBodyPartially(QByteArray &compressed, QByteArray &inflated)
-{
- int ret = Z_DATA_ERROR;
- unsigned have;
- unsigned char out[CHUNK];
- int pos = -1;
-
- if (!initInflate) {
- // check the header
- if (!gzipCheckHeader(compressed, pos))
- return ret;
- // allocate inflate state
- inflateStrm.zalloc = Z_NULL;
- inflateStrm.zfree = Z_NULL;
- inflateStrm.opaque = Z_NULL;
- inflateStrm.avail_in = 0;
- inflateStrm.next_in = Z_NULL;
- ret = inflateInit2(&inflateStrm, -MAX_WBITS);
- if (ret != Z_OK)
- return ret;
- initInflate = true;
- streamEnd = false;
- }
-
- //remove the header.
- compressed.remove(0, pos+1);
- // expand until deflate stream ends
- inflateStrm.next_in = (unsigned char *)compressed.data();
- inflateStrm.avail_in = compressed.size();
- do {
- inflateStrm.avail_out = sizeof(out);
- inflateStrm.next_out = out;
- ret = inflate(&inflateStrm, Z_NO_FLUSH);
- switch (ret) {
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- // and fall through
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- inflateEnd(&inflateStrm);
- initInflate = false;
- return ret;
- }
- have = sizeof(out) - inflateStrm.avail_out;
- inflated.append(QByteArray((const char *)out, have));
- } while (inflateStrm.avail_out == 0);
- // clean up and return
- if (ret <= Z_ERRNO || ret == Z_STREAM_END) {
- inflateEnd(&inflateStrm);
- initInflate = false;
- }
- streamEnd = (ret == Z_STREAM_END);
- return ret;
-}
-#endif
-
qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
{
if (fragment.isEmpty()) {
@@ -616,6 +505,24 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
headerField("proxy-connection").toLower().contains("close")) ||
(majorVersion == 1 && minorVersion == 0 && connectionHeaderField.isEmpty());
+
+#ifndef QT_NO_COMPRESS
+ if (autoDecompress && isCompressed()) {
+ // allocate inflate state
+ inflateStrm.zalloc = Z_NULL;
+ inflateStrm.zfree = Z_NULL;
+ inflateStrm.opaque = Z_NULL;
+ inflateStrm.avail_in = 0;
+ inflateStrm.next_in = Z_NULL;
+ // "windowBits can also be greater than 15 for optional gzip decoding.
+ // Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection"
+ // http://www.zlib.net/manual.html
+ int ret = inflateInit2(&inflateStrm, MAX_WBITS+32);
+ if (ret != Z_OK)
+ return -1;
+ }
+#endif
+
}
return bytes;
}
@@ -672,7 +579,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char
qint64 haveRead = 0;
haveRead = socket->read(b, bodyLength - contentRead);
if (haveRead == -1) {
- return 0; // ### error checking here;
+ return -1;
}
contentRead += haveRead;
@@ -712,22 +619,74 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteData
qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
+
+#ifndef QT_NO_COMPRESS
+ // for gzip we'll allocate a temporary one that we then decompress
+ QByteDataBuffer *tempOutDataBuffer = (autoDecompress ? new QByteDataBuffer : out);
+#else
+ QByteDataBuffer *tempOutDataBuffer = out;
+#endif
+
+
if (isChunked()) {
// chunked transfer encoding (rfc 2616, sec 3.6)
- bytes += readReplyBodyChunked(socket, out);
+ bytes += readReplyBodyChunked(socket, tempOutDataBuffer);
} else if (bodyLength > 0) {
// we have a Content-Length
- bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
+ bytes += readReplyBodyRaw(socket, tempOutDataBuffer, bodyLength - contentRead);
if (contentRead + bytes == bodyLength)
state = AllDoneState;
} else {
// no content length. just read what's possible
- bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
+ bytes += readReplyBodyRaw(socket, tempOutDataBuffer, socket->bytesAvailable());
}
+
+#ifndef QT_NO_COMPRESS
+ // This is true if there is compressed encoding and we're supposed to use it.
+ if (autoDecompress) {
+ qint64 uncompressRet = uncompressBodyData(tempOutDataBuffer, out);
+ delete tempOutDataBuffer;
+ if (uncompressRet < 0)
+ return -1;
+ }
+#endif
+
contentRead += bytes;
return bytes;
}
+#ifndef QT_NO_COMPRESS
+qint64 QHttpNetworkReplyPrivate::uncompressBodyData(QByteDataBuffer *in, QByteDataBuffer *out)
+{
+ for (int i = 0; i < in->bufferCount(); i++) {
+ QByteArray &bIn = (*in)[i];
+
+ inflateStrm.avail_in = bIn.size();
+ inflateStrm.next_in = reinterpret_cast<Bytef*>(bIn.data());
+
+ do {
+ QByteArray bOut;
+ // make a wild guess about the uncompressed size.
+ bOut.reserve(inflateStrm.avail_in * 3 + 512);
+ inflateStrm.avail_out = bOut.capacity();
+ inflateStrm.next_out = reinterpret_cast<Bytef*>(bOut.data());
+
+ int ret = inflate(&inflateStrm, Z_NO_FLUSH);
+ switch (ret) {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ return -1;
+ }
+ bOut.resize(bOut.capacity() - inflateStrm.avail_out);
+ out->append(bOut);
+ } while (inflateStrm.avail_in > 0);
+ }
+
+ return out->byteAmount();
+}
+#endif
+
qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByteDataBuffer *out, qint64 size)
{
// FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
@@ -841,36 +800,6 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *c
return bytes;
}
-void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteArray &qba)
-{
- responseData.append(qba);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- qba.clear();
-}
-
-void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteDataBuffer &data)
-{
- responseData.append(data);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- data.clear();
-}
-
-void QHttpNetworkReplyPrivate::appendCompressedReplyData(QByteDataBuffer &data)
-{
- // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
- // instead of one QByteArray.
- for(int i = 0; i < data.bufferCount(); i++) {
- QByteArray &byteData = data[i];
- compressedData.append(byteData.constData(), byteData.size());
- }
- data.clear();
-}
-
-
bool QHttpNetworkReplyPrivate::shouldEmitSignals()
{
// for 401 & 407 don't emit the data signals. Content along with these
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 583a256ada..14219d484b 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -56,15 +56,7 @@
#ifndef QT_NO_HTTP
#ifndef QT_NO_COMPRESS
-# include <zlib.h>
-static const unsigned char gz_magic[2] = {0x1f, 0x8b}; // gzip magic header
-// gzip flag byte
-#define HEAD_CRC 0x02 // bit 1 set: header CRC present
-#define EXTRA_FIELD 0x04 // bit 2 set: extra field present
-#define ORIG_NAME 0x08 // bit 3 set: original file name present
-#define COMMENT 0x10 // bit 4 set: file comment present
-#define RESERVED 0xE0 // bits 5..7: reserved
-#define CHUNK 16384
+#include <zlib.h>
#endif
#include <QtNetwork/qtcpsocket.h>
@@ -192,10 +184,6 @@ public:
qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
- void appendUncompressedReplyData(QByteArray &qba);
- void appendUncompressedReplyData(QByteDataBuffer &data);
- void appendCompressedReplyData(QByteDataBuffer &data);
-
bool shouldEmitSignals();
bool expectContent();
void eraseData();
@@ -203,11 +191,8 @@ public:
qint64 bytesAvailable() const;
bool isChunked();
bool isConnectionCloseEnabled();
- bool isGzipped();
-#ifndef QT_NO_COMPRESS
- bool gzipCheckHeader(QByteArray &content, int &pos);
- int gunzipBodyPartially(QByteArray &compressed, QByteArray &inflated);
-#endif
+
+ bool isCompressed();
void removeAutoDecompressHeader();
enum ReplyState {
@@ -236,11 +221,12 @@ public:
qint64 currentChunkRead;
QPointer<QHttpNetworkConnection> connection;
QPointer<QHttpNetworkConnectionChannel> connectionChannel;
- bool initInflate;
- bool streamEnd;
+
#ifndef QT_NO_COMPRESS
z_stream inflateStrm;
+ qint64 uncompressBodyData(QByteDataBuffer *in, QByteDataBuffer *out);
#endif
+
bool autoDecompress;
QByteDataBuffer responseData; // uncompressed body
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index df0a32dd6c..52cbaae5e0 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -777,8 +777,16 @@ void QNetworkReplyHttpImplPrivate::postRequest()
if (!synchronous) {
// Tell our zerocopy policy to the delegate
- delegate->downloadBufferMaximumSize =
- request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute).toLongLong();
+ QVariant downloadBufferMaximumSizeAttribute = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
+ if (downloadBufferMaximumSizeAttribute.isValid()) {
+ delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
+ } else {
+ // If there is no MaximumDownloadBufferSizeAttribute set (which is for the majority
+ // of QNetworkRequest) then we can assume we'll do it anyway for small HTTP replies.
+ // This helps with performance and memory fragmentation.
+ delegate->downloadBufferMaximumSize = 128*1024;
+ }
+
// These atomic integers are used for signal compression
delegate->pendingDownloadData = pendingDownloadDataEmissions;
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 839a253b99..94273b0754 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -121,6 +121,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qmap.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvarlengtharray.h>
@@ -666,6 +667,21 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
: QSslCertificatePrivate::certificatesFromDer(data);
}
+/*!
+ Verifies a certificate chain. If \a hostName is specified then the certificate is
+ also checked to see if it is valid for the specified host name.
+ Note that the first certificate in the list should be the leaf certificate of
+ the chain to be verified.
+ The root (CA) certificate should not be included in the list to be verified,
+ this will be looked up automatically either using the CA list specified by
+ QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand
+ on Unix.
+ */
+QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
+{
+ return QSslSocketBackendPrivate::verify(certificateChain, hostName);
+}
+
void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
{
if (!data.isEmpty()) {
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index 4de84dd4ba..a057d7a17d 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -62,6 +62,7 @@ QT_MODULE(Network)
class QDateTime;
class QIODevice;
+class QSslError;
class QSslKey;
class QStringList;
template <typename T, typename U> class QMultiMap;
@@ -122,6 +123,8 @@ public:
static QList<QSslCertificate> fromData(
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
+ static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName = QString());
+
Qt::HANDLE handle() const;
private:
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index c7e938a705..84e5200043 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1283,33 +1283,14 @@ bool QSslSocketBackendPrivate::startHandshake()
// if we're the server, don't check CN
if (mode == QSslSocket::SslClientMode) {
QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
- QStringList commonNameList = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName);
- bool matched = false;
- foreach (const QString &commonName, commonNameList) {
- if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
- matched = true;
- break;
- }
- }
-
- if (!matched) {
- foreach (const QString &altName, configuration.peerCertificate
- .alternateSubjectNames().values(QSsl::DnsEntry)) {
- if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
- matched = true;
- break;
- }
- }
- }
-
- if (!matched) {
- // No matches in common names or alternate names.
- QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
+ if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
+ // No matches in common names or alternate names.
+ QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
}
}
} else {
@@ -1444,6 +1425,25 @@ QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
return errorString;
}
+bool QSslSocketBackendPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
+{
+ QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
+
+ foreach (const QString &commonName, commonNameList) {
+ if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
+ return true;
+ }
+ }
+
+ foreach (const QString &altName, cert.alternateSubjectNames().values(QSsl::DnsEntry)) {
+ if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
int wildcard = cn.indexOf(QLatin1Char('*'));
@@ -1484,4 +1484,133 @@ bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QStri
return true;
}
+QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
+{
+ QList<QSslError> errors;
+ if (certificateChain.count() <= 0) {
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ // Setup the store with the default CA certificates
+ X509_STORE *certStore = q_X509_STORE_new();
+ if (!certStore) {
+ qWarning() << "Unable to create certificate store";
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ QList<QSslCertificate> expiredCerts;
+
+ foreach (const QSslCertificate &caCertificate, QSslSocket::defaultCaCertificates()) {
+ // add expired certs later, so that the
+ // valid ones are used before the expired ones
+ if (!caCertificate.isValid()) {
+ expiredCerts.append(caCertificate);
+ } else {
+ q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle());
+ }
+ }
+
+ bool addExpiredCerts = true;
+#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
+ //On Leopard SSL does not work if we add the expired certificates.
+ if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5)
+ addExpiredCerts = false;
+#endif
+ // now add the expired certs
+ if (addExpiredCerts) {
+ foreach (const QSslCertificate &caCertificate, expiredCerts) {
+ q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle());
+ }
+ }
+
+ _q_sslErrorList()->mutex.lock();
+
+ // Register a custom callback to get all verification errors.
+ X509_STORE_set_verify_cb_func(certStore, q_X509Callback);
+
+ // Build the chain of intermediate certificates
+ STACK_OF(X509) *intermediates = 0;
+ if (certificateChain.length() > 1) {
+ intermediates = (STACK_OF(X509) *) q_sk_new_null();
+
+ if (!intermediates) {
+ q_X509_STORE_free(certStore);
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ bool first = true;
+ foreach (const QSslCertificate &cert, certificateChain) {
+ if (first) {
+ first = false;
+ continue;
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ q_sk_push( (_STACK *)intermediates, (X509 *)cert.handle());
+#else
+ q_sk_push( (STACK *)intermediates, (X509 *)cert.handle());
+#endif
+ }
+ }
+
+ X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
+ if (!storeContext) {
+ q_X509_STORE_free(certStore);
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ if (!q_X509_STORE_CTX_init(storeContext, certStore, (X509 *)certificateChain[0].handle(), intermediates)) {
+ q_X509_STORE_CTX_free(storeContext);
+ q_X509_STORE_free(certStore);
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ // Now we can actually perform the verification of the chain we have built.
+ // We ignore the result of this function since we process errors via the
+ // callback.
+ (void) q_X509_verify_cert(storeContext);
+
+ q_X509_STORE_CTX_free(storeContext);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ q_sk_free( (_STACK *) intermediates);
+#else
+ q_sk_free( (STACK *) intermediates);
+#endif
+
+ // Now process the errors
+ const QList<QPair<int, int> > errorList = _q_sslErrorList()->errors;
+ _q_sslErrorList()->errors.clear();
+
+ _q_sslErrorList()->mutex.unlock();
+
+ // Translate the errors
+ if (QSslCertificatePrivate::isBlacklisted(certificateChain[0])) {
+ QSslError error(QSslError::CertificateBlacklisted, certificateChain[0]);
+ errors << error;
+ }
+
+ // Check the certificate name against the hostname if one was specified
+ if ((!hostName.isEmpty()) && (!isMatchingHostname(certificateChain[0], hostName))) {
+ // No matches in common names or alternate names.
+ QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
+ errors << error;
+ }
+
+ // Translate errors from the error list into QSslErrors.
+ for (int i = 0; i < errorList.size(); ++i) {
+ const QPair<int, int> &errorAndDepth = errorList.at(i);
+ int err = errorAndDepth.first;
+ int depth = errorAndDepth.second;
+ errors << _q_OpenSSL_to_QSslError(err, certificateChain.value(depth));
+ }
+
+ q_X509_STORE_free(certStore);
+
+ return errors;
+}
+
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 7e489a4eff..080ad0064c 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -120,7 +120,9 @@ public:
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
+ static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static QString getErrorsFromOpenSsl();
};
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 31afab003f..be8da0eaf0 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -157,9 +157,13 @@ DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+DEFINEFUNC(_STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC2(void, sk_push, _STACK *a, a, void *b, b, return, DUMMYARG)
DEFINEFUNC(void, sk_free, _STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(void *, sk_value, STACK *a, a, int b, b, return 0, return)
#else
+DEFINEFUNC(STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC2(void, sk_push, STACK *a, a, void *b, b, return, DUMMYARG)
DEFINEFUNC(void, sk_free, STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return 0, return)
#endif
@@ -710,6 +714,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(RAND_seed)
RESOLVEFUNC(RAND_status)
RESOLVEFUNC(RSA_free)
+ RESOLVEFUNC(sk_new_null)
+ RESOLVEFUNC(sk_push)
RESOLVEFUNC(sk_free)
RESOLVEFUNC(sk_num)
RESOLVEFUNC(sk_pop_free)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index cd3aa07bc0..a1db6d9320 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -263,9 +263,13 @@ void q_RSA_free(RSA *a);
int q_sk_num(STACK *a);
void q_sk_pop_free(STACK *a, void (*b)(void *));
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+_STACK *q_sk_new_null();
+void q_sk_push(_STACK *st, void *data);
void q_sk_free(_STACK *a);
void * q_sk_value(STACK *a, int b);
#else
+STACK *q_sk_new_null();
+void q_sk_push(STACK *st, void *data);
void q_sk_free(STACK *a);
char * q_sk_value(STACK *a, int b);
#endif
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index dc55ce0cd1..165096637b 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -1638,7 +1638,8 @@ QGraphicsScene::~QGraphicsScene()
Q_D(QGraphicsScene);
// Remove this scene from qApp's global scene list.
- qApp->d_func()->scene_list.removeAll(this);
+ if (!QApplicationPrivate::is_app_closing)
+ qApp->d_func()->scene_list.removeAll(this);
clear();