From 02e448784543df2d81135ac583c39df6237dac69 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 10 Apr 2015 23:18:23 -0700 Subject: Correct calculation of filesystem data on unusual filesystems POSIX.1 says f_blocks, f_bfree, f_bavail are calculated in terms of f_frsize, not of the regular block size f_bsize. On most systems, it's the same, which is why we didn't catch it. I don't have any filesystem to test this on to confirm. Reference: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html Task-number: QTBUG-45137 Change-Id: I27eaacb532114dd188c4ffff13d3e13016bed4e6 Reviewed-by: Dmitry Shachnev Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Ivan Komissarov --- src/corelib/io/qstorageinfo_unix.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 2a83e87b0c..cd3c60650e 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -416,9 +416,9 @@ void QStorageInfoPrivate::retreiveVolumeInfo() valid = true; ready = true; - bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize; - bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; - bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize; + bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize; + bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize; + bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize; #if defined(Q_OS_ANDROID) #if defined(_STATFS_F_FLAGS) readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0; -- cgit v1.2.3 From 18a3b431678e3b456c33a9f7ae21d8653dd2ef85 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Mon, 27 Apr 2015 01:22:36 +0200 Subject: Update QProcess doc to use non-deprecated setProcessEnvironment Currently the documentation still mentions the use of the deprected setEnvironment function. This patch aims to correct that Task-number: QTBUG-45235 Change-Id: Iab35754b39f025c7493a6f061eb72e23bc4cf308 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qprocess.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index baba9a0f9e..4d2a75c0fa 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -373,8 +373,8 @@ QString QProcessEnvironment::value(const QString &name, const QString &defaultVa Use with the QProcess::setEnvironment function is not recommended due to potential encoding problems under Unix, and worse performance. - \sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(), - QProcess::setEnvironment() + \sa systemEnvironment(), QProcess::systemEnvironment(), + QProcess::setProcessEnvironment() */ QStringList QProcessEnvironment::toStringList() const { @@ -534,7 +534,7 @@ void QProcessPrivate::Channel::clear() Certain processes need special environment settings in order to operate. You can set environment variables for your process by - calling setEnvironment(). To set a working directory, call + calling setProcessEnvironment(). To set a working directory, call setWorkingDirectory(). By default, processes are run in the current working directory of the calling process. @@ -2471,7 +2471,7 @@ QT_END_INCLUDE_NAMESPACE \note For new code, it is recommended to use QProcessEnvironment::systemEnvironment() - \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment() + \sa QProcessEnvironment::systemEnvironment(), setProcessEnvironment() */ QStringList QProcess::systemEnvironment() { -- cgit v1.2.3 From 2cb17c1fb903434274e58692c9f0df619affdab0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 18 May 2015 11:29:31 +0200 Subject: Improve documentation for Qt::ItemNeverHasChildren. Change-Id: Ied817314d6e72f08a81138bd817c8570d586fa30 Reviewed-by: Oswald Buddenhagen Reviewed-by: David Faure Reviewed-by: Martin Smith Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/global/qnamespace.qdoc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 3f9526c788..87056b79f0 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2562,6 +2562,7 @@ \value ItemIsEnabled The user can interact with the item. \value ItemIsTristate The item is checkable with three separate states. \value ItemNeverHasChildren The item never has child items. + This is used for optimization purposes only. Note that checkable items need to be given both a suitable set of flags and an initial state, indicating whether the item is checked or not. -- cgit v1.2.3 From d1ce29557cea3a4f23c400a5cb03254f6cf31dc5 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Tue, 24 Feb 2015 12:36:54 +0100 Subject: Make QStyle::itemPixmapRect handle devicePixelRatio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layout sizes for images should be in the form QSize layoutSize = image.size() / image.devicePixelRatio() to be in device independent pixels Change-Id: Ic149144c45c8fa5c45ac5cbe2c82c35d721549cd Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qstyle.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 6072842fc9..5c0064c7a4 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -541,17 +541,21 @@ QRect QStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pi QRect result; int x, y, w, h; rect.getRect(&x, &y, &w, &h); + + const int pixmapWidth = pixmap.width()/pixmap.devicePixelRatio(); + const int pixmapHeight = pixmap.height()/pixmap.devicePixelRatio(); + if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter) - y += h/2 - pixmap.height()/2; + y += h/2 - pixmapHeight/2; else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom) - y += h - pixmap.height(); + y += h - pixmapHeight; if ((alignment & Qt::AlignRight) == Qt::AlignRight) - x += w - pixmap.width(); + x += w - pixmapWidth; else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter) - x += w/2 - pixmap.width()/2; + x += w/2 - pixmapWidth/2; else if ((alignment & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft()) - x += w - pixmap.width(); - result = QRect(x, y, pixmap.width(), pixmap.height()); + x += w - pixmapWidth; + result = QRect(x, y, pixmapWidth, pixmapHeight); return result; } -- cgit v1.2.3 From 34014406baaeac3e9d49d5654ef57ac6540a17a8 Mon Sep 17 00:00:00 2001 From: Evgeniy Fominov Date: Mon, 16 Feb 2015 14:36:54 +0100 Subject: quote QUuid values Task-number: QTBUG-44480 Change-Id: I125ab913c867758d958a2774ad125533d6a07a83 Reviewed-by: Evgeniy Fominov Reviewed-by: Mark Brand --- src/sql/drivers/psql/qsql_psql.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index 4268ea06f6..32f6e317d8 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -1320,6 +1320,9 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const } break; } + case QVariant::Uuid: + r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\''); + break; default: r = QSqlDriver::formatValue(field, trimStrings); break; -- cgit v1.2.3 From d82d5b1c43b270ef6f4f0d90ce5d7d96ea0b7a97 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Wed, 3 Jun 2015 10:09:42 +0300 Subject: Check for integer overflows in places where qAllocMore is used Task-number: QTBUG-41230 Change-Id: Ic2167364e326092482657f2d2b4ab6ad3e5af631 (partially cherry-picked from 880986be2357a1f80827d038d770dc2f80300201) Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydata.cpp | 16 ++++++++++++++-- src/corelib/tools/qbytearray.cpp | 7 +++++-- src/corelib/tools/qlist.cpp | 2 ++ src/corelib/tools/qstring.cpp | 5 ++++- src/corelib/tools/qtools_p.h | 6 ++++++ src/gui/text/qfragmentmap_p.h | 2 ++ 6 files changed, 33 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 98c484c1dd..d060ff84f2 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -85,8 +85,20 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, headerSize += (alignment - Q_ALIGNOF(QArrayData)); // Allocate additional space if array is growing - if (options & Grow) - capacity = qAllocMore(int(objectSize * capacity), int(headerSize)) / int(objectSize); + if (options & Grow) { + + // Guard against integer overflow when multiplying. + if (capacity > std::numeric_limits::max() / objectSize) + return 0; + + size_t alloc = objectSize * capacity; + + // Make sure qAllocMore won't overflow. + if (headerSize > size_t(MaxAllocSize) || alloc > size_t(MaxAllocSize) - headerSize) + return 0; + + capacity = qAllocMore(int(alloc), int(headerSize)) / int(objectSize); + } size_t allocSize = headerSize + objectSize * capacity; diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 5ec8c317e8..1e87f7b023 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -64,7 +64,7 @@ int qFindByteArray( int qAllocMore(int alloc, int extra) Q_DECL_NOTHROW { Q_ASSERT(alloc >= 0 && extra >= 0); - Q_ASSERT_X(uint(alloc) < QByteArray::MaxSize, "qAllocMore", "Requested size is too large!"); + Q_ASSERT_X(alloc <= MaxAllocSize - extra, "qAllocMore", "Requested size is too large!"); unsigned nalloc = qNextPowerOfTwo(alloc + extra); @@ -1495,8 +1495,11 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options) Data::deallocate(d); d = x; } else { - if (options & Data::Grow) + if (options & Data::Grow) { + if (alloc > uint(MaxAllocSize) - uint(sizeof(Data))) + qBadAlloc(); alloc = qAllocMore(alloc, sizeof(Data)); + } Data *x = static_cast(::realloc(d, sizeof(Data) + alloc)); Q_CHECK_PTR(x); x->alloc = alloc; diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index fe5e0f33b4..b91fd38a5f 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -55,6 +55,8 @@ const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0 static int grow(int size) { + if (size_t(size) > (MaxAllocSize - QListData::DataHeaderSize) / sizeof(void *)) + qBadAlloc(); // dear compiler: don't optimize me out. volatile int x = qAllocMore(size * sizeof(void *), QListData::DataHeaderSize) / sizeof(void *); return x; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 189caf8bd7..96f3c4147c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1656,8 +1656,11 @@ void QString::resize(int size) void QString::reallocData(uint alloc, bool grow) { - if (grow) + if (grow) { + if (alloc > (uint(MaxAllocSize) - sizeof(Data)) / sizeof(QChar)) + qBadAlloc(); alloc = qAllocMore(alloc * sizeof(QChar), sizeof(Data)) / sizeof(QChar); + } if (d->ref.isShared() || IS_RAW_DATA(d)) { Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0); diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h index 3876d3822c..1e72db1d87 100644 --- a/src/corelib/tools/qtools_p.h +++ b/src/corelib/tools/qtools_p.h @@ -46,9 +46,15 @@ // #include "QtCore/qglobal.h" +#include QT_BEGIN_NAMESPACE +// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size. +enum { + MaxAllocSize = (1 << (std::numeric_limits::digits - 1)) - 1 +}; + // implemented in qbytearray.cpp int Q_CORE_EXPORT qAllocMore(int alloc, int extra) Q_DECL_NOTHROW; diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 012d3c25ce..a19e3d9ea3 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -249,6 +249,8 @@ uint QFragmentMapData::createFragment() uint freePos = head->freelist; if (freePos == head->allocated) { // need to create some free space + if (freePos >= uint(MaxAllocSize) / fragmentSize) + qBadAlloc(); uint needed = qAllocMore((freePos+1)*fragmentSize, 0); Q_ASSERT(needed/fragmentSize > head->allocated); Fragment *newFragments = (Fragment *)realloc(fragments, needed); -- cgit v1.2.3 From eae0cb09f1310e755c2aff7c1112f7a6c09d7a53 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Fri, 19 Jun 2015 15:35:34 +0200 Subject: Network: Fix up previous corruption patch This is a fix-up for cff39fba10ffc10ee4dcfdc66ff6528eb26462d3. That patch lead to some internal state issues that lead to the QTBUG-47048 or to QNetworkReply objects erroring with "Connection Closed" when the server closed the Keep-Alive connection. This patch changes the QNAM socket slot connections to be DirectConnection. We don't close the socket anymore in slots where it is anyway in a closed state afterwards. This prevents event/stack recursions. We also flush QSslSocket/QTcpSocket receive buffers when receiving a disconnect so that the developer always gets the full decrypted data from the buffers. [ChangeLog][QtNetwork] Fix HTTP issues with "Unknown Error" and "Connection Closed" [ChangeLog][QtNetwork][Sockets] Read OS/encrypted read buffers when connection closed by server. Change-Id: Ib4d6a2d0d988317e3a5356f36e8dbcee4590beed Task-number: QTBUG-47048 Reviewed-by: Kai Koehne Reviewed-by: Richard J. Moore --- src/network/access/qhttpnetworkconnection.cpp | 1 - .../access/qhttpnetworkconnectionchannel.cpp | 108 +++++++++++++-------- .../access/qhttpnetworkconnectionchannel_p.h | 1 + src/network/access/qhttpnetworkreply.cpp | 2 +- src/network/access/qhttpprotocolhandler.cpp | 1 - src/network/socket/qabstractsocket.cpp | 7 +- src/network/ssl/qsslsocket.cpp | 8 ++ src/network/ssl/qsslsocket_openssl.cpp | 7 ++ 8 files changed, 89 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 365ce55f2b..543c70e8b7 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -917,7 +917,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() for (int i = 0; i < channelCount; ++i) { if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) { channels[i].resendCurrent = false; - channels[i].state = QHttpNetworkConnectionChannel::IdleState; // if this is not possible, error will be emitted and connection terminated if (!channels[i].resetUploadData()) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 49c6793b1f..e2f63071e1 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp +// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP +// connection times out) +// We use 3 because we can get a _q_error 3 times depending on the timing: +static const int reconnectAttemptsDefault = 3; + QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel() : socket(0) , ssl(false) @@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel() , resendCurrent(false) , lastStatus(0) , pendingEncrypt(false) - , reconnectAttempts(2) + , reconnectAttempts(reconnectAttemptsDefault) , authMethod(QAuthenticatorPrivate::None) , proxyAuthMethod(QAuthenticatorPrivate::None) , authenticationCredentialsSent(false) @@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init() socket->setProxy(QNetworkProxy::NoProxy); #endif - // We want all signals (except the interactive ones) be connected as QueuedConnection - // because else we're falling into cases where we recurse back into the socket code - // and mess up the state. Always going to the event loop (and expecting that when reading/writing) - // is safer. + // After some back and forth in all the last years, this is now a DirectConnection because otherwise + // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers + // which behave slightly differently on Windows vs Linux QObject::connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)), - Qt::QueuedConnection); + Qt::DirectConnection); QObject::connect(socket, SIGNAL(connected()), this, SLOT(_q_connected()), - Qt::QueuedConnection); + Qt::DirectConnection); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(_q_readyRead()), - Qt::QueuedConnection); + Qt::DirectConnection); // The disconnected() and error() signals may already come // while calling connectToHost(). @@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init() qRegisterMetaType(); QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(_q_disconnected()), - Qt::QueuedConnection); + Qt::DirectConnection); QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_error(QAbstractSocket::SocketError)), - Qt::QueuedConnection); + Qt::DirectConnection); #ifndef QT_NO_NETWORKPROXY @@ -147,13 +151,13 @@ void QHttpNetworkConnectionChannel::init() // won't be a sslSocket if encrypt is false QObject::connect(sslSocket, SIGNAL(encrypted()), this, SLOT(_q_encrypted()), - Qt::QueuedConnection); + Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(sslErrors(QList)), this, SLOT(_q_sslErrors(QList)), Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), - Qt::QueuedConnection); + Qt::DirectConnection); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -397,7 +401,7 @@ void QHttpNetworkConnectionChannel::allDone() // reset the reconnection attempts after we receive a complete reply. // in case of failures, each channel will attempt two reconnects before emitting error. - reconnectAttempts = 2; + reconnectAttempts = reconnectAttemptsDefault; // now the channel can be seen as free/idle again, all signal emissions for the reply have been done if (state != QHttpNetworkConnectionChannel::ClosingState) @@ -651,6 +655,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest() QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } +void QHttpNetworkConnectionChannel::resendCurrentRequest() +{ + requeueCurrentlyPipelinedRequests(); + if (reply) + resendCurrent = true; + if (qobject_cast(connection)) + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); +} + bool QHttpNetworkConnectionChannel::isSocketBusy() const { return (state & QHttpNetworkConnectionChannel::BusyState); @@ -694,8 +707,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected() return; } - // read the available data before closing - if (isSocketWaiting() || isSocketReading()) { + // read the available data before closing (also done in _q_error for other codepaths) + if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) { if (reply) { state = QHttpNetworkConnectionChannel::ReadingState; _q_receiveReply(); @@ -707,7 +720,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected() state = QHttpNetworkConnectionChannel::IdleState; requeueCurrentlyPipelinedRequests(); - close(); + + pendingEncrypt = false; } @@ -789,11 +803,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket errorCode = QNetworkReply::ConnectionRefusedError; break; case QAbstractSocket::RemoteHostClosedError: - // try to reconnect/resend before sending an error. - // while "Reading" the _q_disconnected() will handle this. - if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { + // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer. + // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket). + // The reconnectAttempts handling catches the cases where we can re-send the request. + if (!reply && state == QHttpNetworkConnectionChannel::IdleState) { + // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request + // is sent on them. No need to error the other replies below. Just bail out here. + // The _q_disconnected will handle the possibly pipelined replies + return; + } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { + // Try to reconnect/resend before sending an error. + // While "Reading" the _q_disconnected() will handle this. if (reconnectAttempts-- > 0) { - closeAndResendCurrentRequest(); + resendCurrentRequest(); return; } else { errorCode = QNetworkReply::RemoteHostClosedError; @@ -818,24 +840,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket // we can ignore the readbuffersize as the data is already // in memory and we will not receive more data on the socket. reply->setReadBufferSize(0); + reply->setDownstreamLimited(false); _q_receiveReply(); -#ifndef QT_NO_SSL - if (ssl) { - // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket. - // So we need to check this if the socket is a QSslSocket. When the socket is flushed - // it will force a decrypt of the encrypted data in the plainsocket. - QSslSocket *sslSocket = static_cast(socket); - qint64 beforeFlush = sslSocket->encryptedBytesAvailable(); - while (sslSocket->encryptedBytesAvailable()) { - sslSocket->flush(); - _q_receiveReply(); - qint64 afterFlush = sslSocket->encryptedBytesAvailable(); - if (afterFlush == beforeFlush) - break; - beforeFlush = afterFlush; - } + if (!reply) { + // No more reply assigned after the previous call? Then it had been finished successfully. + requeueCurrentlyPipelinedRequests(); + state = QHttpNetworkConnectionChannel::IdleState; + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); + return; } -#endif } errorCode = QNetworkReply::RemoteHostClosedError; @@ -846,7 +859,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket case QAbstractSocket::SocketTimeoutError: // try to reconnect/resend before sending an error. if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) { - closeAndResendCurrentRequest(); + resendCurrentRequest(); return; } errorCode = QNetworkReply::TimeoutError; @@ -860,7 +873,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket case QAbstractSocket::ProxyConnectionClosedError: // try to reconnect/resend before sending an error. if (reconnectAttempts-- > 0) { - closeAndResendCurrentRequest(); + resendCurrentRequest(); return; } errorCode = QNetworkReply::ProxyConnectionClosedError; @@ -868,7 +881,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket case QAbstractSocket::ProxyConnectionTimeoutError: // try to reconnect/resend before sending an error. if (reconnectAttempts-- > 0) { - closeAndResendCurrentRequest(); + resendCurrentRequest(); return; } errorCode = QNetworkReply::ProxyTimeoutError; @@ -916,8 +929,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket // send the next request QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection); - if (that) //signal emission triggered event loop - close(); + if (that) { + //signal emission triggered event loop + if (!socket) + state = QHttpNetworkConnectionChannel::IdleState; + else if (socket->state() == QAbstractSocket::UnconnectedState) + state = QHttpNetworkConnectionChannel::IdleState; + else + state = QHttpNetworkConnectionChannel::ClosingState; + + // pendingEncrypt must only be true in between connected and encrypted states + pendingEncrypt = false; + } } #ifndef QT_NO_NETWORKPROXY @@ -941,7 +964,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead() { - sendRequest(); + if (reply) + sendRequest(); } #ifndef QT_NO_SSL diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 231fe11135..a834b7d645 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -169,6 +169,7 @@ public: void handleUnexpectedEOF(); void closeAndResendCurrentRequest(); + void resendCurrentRequest(); bool isSocketBusy() const; bool isSocketWriting() const; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 55863a3c88..8b71bd8e70 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny() return QByteArray(); // we'll take the last buffer, so schedule another read from http - if (d->downstreamLimited && d->responseData.bufferCount() == 1) + if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished()) d->connection->d_func()->readMoreLater(this); return d->responseData.read(); } diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index 3357948519..380aaacf0c 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest() if (!m_reply) { // heh, how should that happen! qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply"; - m_channel->state = QHttpNetworkConnectionChannel::IdleState; return false; } diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 26667715be..0e82d4ab66 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -768,6 +768,7 @@ bool QAbstractSocketPrivate::canReadNotification() void QAbstractSocketPrivate::canCloseNotification() { Q_Q(QAbstractSocket); + // Note that this method is only called on Windows. Other platforms close in the canReadNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canCloseNotification()"); @@ -777,7 +778,11 @@ void QAbstractSocketPrivate::canCloseNotification() if (isBuffered) { // Try to read to the buffer, if the read fail we can close the socket. newBytes = buffer.size(); - if (!readFromSocket()) { + qint64 oldReadBufferMaxSize = readBufferMaxSize; + readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer + bool hadReadFromSocket = readFromSocket(); + readBufferMaxSize = oldReadBufferMaxSize; + if (!hadReadFromSocket) { q->disconnectFromHost(); return; } diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index c1fab94fce..2b9e9230e0 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2294,6 +2294,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error) qCDebug(lcSsl) << "\tstate =" << q->state(); qCDebug(lcSsl) << "\terrorString =" << q->errorString(); #endif + // this moves encrypted bytes from plain socket into our buffer + if (plainSocket->bytesAvailable()) { + qint64 tmpReadBufferMaxSize = readBufferMaxSize; + readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained + transmit(); + readBufferMaxSize = tmpReadBufferMaxSize; + } + q->setSocketError(plainSocket->error()); q->setErrorString(plainSocket->errorString()); emit q->error(error); diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index ac4336afcc..94655feb9b 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1419,6 +1419,13 @@ void QSslSocketBackendPrivate::disconnected() { if (plainSocket->bytesAvailable() <= 0) destroySslContext(); + else { + // Move all bytes into the plain buffer + qint64 tmpReadBufferMaxSize = readBufferMaxSize; + readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained + transmit(); + readBufferMaxSize = tmpReadBufferMaxSize; + } //if there is still buffered data in the plain socket, don't destroy the ssl context yet. //it will be destroyed when the socket is deleted. } -- cgit v1.2.3 From 4a1e5dbade4bab55f39bd368480dcca9a11e4b38 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 9 Jul 2015 09:30:42 +0200 Subject: Better handling of invalid font tables Specifically when reading files with broken cmap tables, we could get some undeterministic results. We handle this more gracefully by verifying that the offsets are sane and bailing out early if not. This replaces the current pattern throughout the font engine for consistency. Change-Id: I507bba49c0be634afca77d1eb3d199a427451bee Reviewed-by: Simon Hausmann Reviewed-by: Thiago Macieira --- src/gui/text/qfontengine.cpp | 212 ++++++++++++++++----- src/gui/text/qfontengine_p.h | 2 +- src/gui/text/qfontengine_qpf2.cpp | 10 +- .../platforms/windows/qwindowsfontengine.cpp | 16 +- src/plugins/platforms/windows/qwindowsfontengine.h | 1 + 5 files changed, 176 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index b360ed5c85..f973abc8e4 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -74,6 +74,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr } } +template +static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output) +{ + if (source + sizeof(T) > end) + return false; + + *output = qFromBigEndian(source); + return true; +} + // Harfbuzz helper functions #ifdef QT_ENABLE_HARFBUZZ_NG @@ -1044,26 +1054,38 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) return; const uchar *table = reinterpret_cast(tab.constData()); + const uchar *end = table + tab.size(); + + quint16 version; + if (!qSafeFromBigEndian(table, end, &version)) + return; - unsigned short version = qFromBigEndian(table); if (version != 0) { // qDebug("wrong version"); return; } - unsigned short numTables = qFromBigEndian(table + 2); + quint16 numTables; + if (!qSafeFromBigEndian(table + 2, end, &numTables)) + return; + { int offset = 4; for(int i = 0; i < numTables; ++i) { - if (offset + 6 > tab.size()) { -// qDebug("offset out of bounds"); - goto end; - } const uchar *header = table + offset; - ushort version = qFromBigEndian(header); - ushort length = qFromBigEndian(header+2); - ushort coverage = qFromBigEndian(header+4); + quint16 version; + if (!qSafeFromBigEndian(header, end, &version)) + goto end; + + quint16 length; + if (!qSafeFromBigEndian(header + 2, end, &length)) + goto end; + + quint16 coverage; + if (!qSafeFromBigEndian(header + 4, end, &coverage)) + goto end; + // qDebug("subtable: version=%d, coverage=%x",version, coverage); if(version == 0 && coverage == 0x0001) { if (offset + length > tab.size()) { @@ -1072,7 +1094,10 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) } const uchar *data = table + offset + 6; - ushort nPairs = qFromBigEndian(data); + quint16 nPairs; + if (!qSafeFromBigEndian(data, end, &nPairs)) + goto end; + if(nPairs * 6 + 8 > length - 6) { // qDebug("corrupt table!"); // corrupt table @@ -1082,8 +1107,21 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) int off = 8; for(int i = 0; i < nPairs; ++i) { QFontEngine::KernPair p; - p.left_right = (((uint)qFromBigEndian(data+off)) << 16) + qFromBigEndian(data+off+2); - p.adjust = QFixed(((int)(short)qFromBigEndian(data+off+4))) / scalingFactor; + + quint16 tmp; + if (!qSafeFromBigEndian(data + off, end, &tmp)) + goto end; + + p.left_right = uint(tmp) << 16; + if (!qSafeFromBigEndian(data + off + 2, end, &tmp)) + goto end; + + p.left_right |= tmp; + + if (!qSafeFromBigEndian(data + off + 4, end, &tmp)) + goto end; + + p.adjust = QFixed(int(short(tmp))) / scalingFactor; kerning_pairs.append(p); off += 6; } @@ -1103,26 +1141,31 @@ int QFontEngine::glyphCount() const QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p')); if (maxpTable.size() < 6) return 0; - return qFromBigEndian(reinterpret_cast(maxpTable.constData() + 4)); + + const uchar *source = reinterpret_cast(maxpTable.constData() + 4); + const uchar *end = source + maxpTable.size(); + + quint16 count = 0; + qSafeFromBigEndian(source, end, &count); + return count; } const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize) { const uchar *header = table; - if (tableSize < 4) - return 0; - const uchar *endPtr = table + tableSize; // version check - if (qFromBigEndian(header) != 0) + quint16 version; + if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0) return 0; - unsigned short numTables = qFromBigEndian(header + 2); - const uchar *maps = table + 4; - if (maps + 8 * numTables > endPtr) + quint16 numTables; + if (!qSafeFromBigEndian(header + 2, endPtr, &numTables)) return 0; + const uchar *maps = table + 4; + enum { Invalid, AppleRoman, @@ -1137,8 +1180,14 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy int tableToUse = -1; int score = Invalid; for (int n = 0; n < numTables; ++n) { - const quint16 platformId = qFromBigEndian(maps + 8 * n); - const quint16 platformSpecificId = qFromBigEndian(maps + 8 * n + 2); + quint16 platformId; + if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId)) + return 0; + + quint16 platformSpecificId; + if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId)) + return 0; + switch (platformId) { case 0: // Unicode if (score < Unicode && @@ -1192,20 +1241,30 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy resolveTable: *isSymbolFont = (symbolTable > -1); - unsigned int unicode_table = qFromBigEndian(maps + 8*tableToUse + 4); + quint32 unicode_table; + if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table)) + return 0; - if (!unicode_table || unicode_table + 8 > tableSize) + if (!unicode_table) return 0; // get the header of the unicode table header = table + unicode_table; - unsigned short format = qFromBigEndian(header); - unsigned int length; - if(format < 8) - length = qFromBigEndian(header + 2); - else - length = qFromBigEndian(header + 4); + quint16 format; + if (!qSafeFromBigEndian(header, endPtr, &format)) + return 0; + + quint32 length; + if (format < 8) { + quint16 tmp; + if (!qSafeFromBigEndian(header + 2, endPtr, &tmp)) + return 0; + length = tmp; + } else { + if (!qSafeFromBigEndian(header + 4, endPtr, &length)) + return 0; + } if (table + unicode_table + length > endPtr) return 0; @@ -1220,7 +1279,7 @@ resolveTable: // Check that none of the latin1 range are in the unicode table bool unicodeTableHasLatin1 = false; for (int uc=0x00; uc<0x100; ++uc) { - if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) { unicodeTableHasLatin1 = true; break; } @@ -1230,7 +1289,7 @@ resolveTable: bool unicodeTableHasSymbols = false; if (!unicodeTableHasLatin1) { for (int uc=0xf000; uc<0xf100; ++uc) { - if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) { unicodeTableHasSymbols = true; break; } @@ -1248,12 +1307,17 @@ resolveTable: return table + unicode_table; } -quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) +quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode) { - unsigned short format = qFromBigEndian(cmap); + const uchar *end = cmap + cmapSize; + quint16 format; + if (!qSafeFromBigEndian(cmap, end, &format)) + return 0; + if (format == 0) { - if (unicode < 256) - return (int) *(cmap+6+unicode); + const uchar *ptr = cmap + 6 + unicode; + if (unicode < 256 && ptr < end) + return quint32(*ptr); } else if (format == 4) { /* some fonts come with invalid cmap tables, where the last segment specified end = start = rangeoffset = 0xffff, delta = 0x0001 @@ -1262,25 +1326,49 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) */ if(unicode >= 0xffff) return 0; - quint16 segCountX2 = qFromBigEndian(cmap + 6); + + quint16 segCountX2; + if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2)) + return 0; + const unsigned char *ends = cmap + 14; + int i = 0; - for (; i < segCountX2/2 && qFromBigEndian(ends + 2*i) < unicode; i++) {} + for (; i < segCountX2/2; ++i) { + quint16 codePoint; + if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint)) + return 0; + if (codePoint >= unicode) + break; + } const unsigned char *idx = ends + segCountX2 + 2 + 2*i; - quint16 startIndex = qFromBigEndian(idx); + quint16 startIndex; + if (!qSafeFromBigEndian(idx, end, &startIndex)) + return 0; if (startIndex > unicode) return 0; idx += segCountX2; - qint16 idDelta = (qint16)qFromBigEndian(idx); + + quint16 tmp; + if (!qSafeFromBigEndian(idx, end, &tmp)) + return 0; + qint16 idDelta = qint16(tmp); + idx += segCountX2; - quint16 idRangeoffset_t = (quint16)qFromBigEndian(idx); + + quint16 idRangeoffset_t; + if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t)) + return 0; quint16 glyphIndex; if (idRangeoffset_t) { - quint16 id = qFromBigEndian(idRangeoffset_t + 2*(unicode - startIndex) + idx); + quint16 id; + if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id)) + return 0; + if (id) glyphIndex = (idDelta + id) % 0x10000; else @@ -1290,13 +1378,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) } return glyphIndex; } else if (format == 6) { - quint16 tableSize = qFromBigEndian(cmap + 2); + quint16 tableSize; + if (!qSafeFromBigEndian(cmap + 2, end, &tableSize)) + return 0; - quint16 firstCode6 = qFromBigEndian(cmap + 6); + quint16 firstCode6; + if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6)) + return 0; if (unicode < firstCode6) return 0; - quint16 entryCount6 = qFromBigEndian(cmap + 8); + quint16 entryCount6; + if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6)) + return 0; if (entryCount6 * 2 + 10 > tableSize) return 0; @@ -1305,9 +1399,14 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) return 0; quint16 entryIndex6 = unicode - firstCode6; - return qFromBigEndian(cmap + 10 + (entryIndex6 * 2)); + + quint16 index = 0; + qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index); + return index; } else if (format == 12) { - quint32 nGroups = qFromBigEndian(cmap + 12); + quint32 nGroups; + if (!qSafeFromBigEndian(cmap + 12, end, &nGroups)) + return 0; cmap += 16; // move to start of groups @@ -1315,13 +1414,24 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) while (left <= right) { int middle = left + ( ( right - left ) >> 1 ); - quint32 startCharCode = qFromBigEndian(cmap + 12*middle); + quint32 startCharCode; + if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode)) + return 0; + if(unicode < startCharCode) right = middle - 1; else { - quint32 endCharCode = qFromBigEndian(cmap + 12*middle + 4); - if(unicode <= endCharCode) - return qFromBigEndian(cmap + 12*middle + 8) + unicode - startCharCode; + quint32 endCharCode; + if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode)) + return 0; + + if (unicode <= endCharCode) { + quint32 index; + if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index)) + return 0; + + return index + unicode - startCharCode; + } left = middle + 1; } } diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 9364b82bed..423b9413ed 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -243,7 +243,7 @@ public: QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const; static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize); - static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode); + static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode); static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily); diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index 4785902c99..4bb27c4d51 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -322,9 +322,9 @@ bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) co glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const { - glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); if (glyph == 0 && symbol && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); if (!findGlyph(glyph)) glyph = 0; @@ -348,16 +348,16 @@ bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyp QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); ++glyph_pos; } } else { QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index e45ff5d744..afb134d014 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -181,9 +181,8 @@ void QWindowsFontEngine::getCMap() bool symb = false; if (ttf) { cmapTable = getSfntTable(qbswap(MAKE_TAG('c', 'm', 'a', 'p'))); - int size = 0; cmap = QFontEngine::getCMap(reinterpret_cast(cmapTable.constData()), - cmapTable.size(), &symb, &size); + cmapTable.size(), &symb, &cmapSize); } if (!cmap) { ttf = false; @@ -218,16 +217,16 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa QStringIterator it(str, str + numChars); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); ++glyph_pos; } } else if (ttf) { QStringIterator it(str, str + numChars); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); ++glyph_pos; } } else { @@ -276,6 +275,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name, hasOutline(0), lw(0), cmap(0), + cmapSize(0), lbearing(SHRT_MIN), rbearing(SHRT_MIN), x_height(-1), @@ -343,11 +343,11 @@ glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const #if !defined(Q_OS_WINCE) if (symbol) { - glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); if (glyph == 0 && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); } else if (ttf) { - glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); #else if (tm.tmFirstChar > 60000) { glyph = ucs4; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 02bc4008d1..c0dda6efca 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -147,6 +147,7 @@ private: TEXTMETRIC tm; int lw; const unsigned char *cmap; + int cmapSize; QByteArray cmapTable; mutable qreal lbearing; mutable qreal rbearing; -- cgit v1.2.3