summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp8
-rw-r--r--src/corelib/global/global.pri6
-rw-r--r--src/corelib/global/qglobal.cpp305
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp423
-rw-r--r--src/corelib/global/qoperatingsystemversion.h129
-rw-r--r--src/corelib/global/qoperatingsystemversion_darwin.mm101
-rw-r--r--src/corelib/global/qoperatingsystemversion_p.h87
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp171
-rw-r--r--src/corelib/global/qsysinfo.h53
-rw-r--r--src/corelib/io/qdatastream.h281
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp4
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp3
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp53
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h10
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp286
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h15
-rw-r--r--src/corelib/io/qsettings.cpp250
-rw-r--r--src/corelib/io/qsettings_mac.cpp13
-rw-r--r--src/corelib/io/qsettings_p.h18
-rw-r--r--src/corelib/io/qsettings_win.cpp31
-rw-r--r--src/corelib/io/qstorageinfo.cpp22
-rw-r--r--src/corelib/io/qstorageinfo.h3
-rw-r--r--src/corelib/io/qstorageinfo_p.h1
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp51
-rw-r--r--src/corelib/io/qtemporarydir.cpp27
-rw-r--r--src/corelib/io/qtemporarydir.h1
-rw-r--r--src/corelib/io/qtextstream.cpp15
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm54
-rw-r--r--src/corelib/kernel/qcore_mac_p.h6
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp10
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h2
-rw-r--r--src/corelib/kernel/qobject.cpp76
-rw-r--r--src/corelib/kernel/qobject.h8
-rw-r--r--src/corelib/tools/qarraydata.cpp51
-rw-r--r--src/corelib/tools/qarraydata.h11
-rw-r--r--src/corelib/tools/qbytearray.cpp86
-rw-r--r--src/corelib/tools/qdatetime.cpp9
-rw-r--r--src/corelib/tools/qlocale.cpp66
-rw-r--r--src/corelib/tools/qlocale.h4
-rw-r--r--src/corelib/tools/qlocale.qdoc11
-rw-r--r--src/corelib/tools/qlocale_p.h4
-rw-r--r--src/corelib/tools/qringbuffer.cpp1
-rw-r--r--src/corelib/tools/qstring.cpp145
-rw-r--r--src/corelib/tools/qstring.h10
44 files changed, 2146 insertions, 775 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
index 9fd52517c2..f852988e9a 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
@@ -48,14 +48,6 @@
**
****************************************************************************/
-//! [0]
-QLineEdit *lineEdit = static_cast<QLineEdit *>(
- qt_find_obj_child(myWidget, "QLineEdit", "my line edit"));
-if (lineEdit)
- lineEdit->setText("Default");
-//! [0]
-
-
//! [1]
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index f74662b464..bd2e125006 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -2,6 +2,8 @@
HEADERS += \
global/qglobal.h \
+ global/qoperatingsystemversion.h \
+ global/qoperatingsystemversion_p.h \
global/qsystemdetection.h \
global/qcompilerdetection.h \
global/qprocessordetection.h \
@@ -27,11 +29,15 @@ SOURCES += \
global/qlibraryinfo.cpp \
global/qmalloc.cpp \
global/qnumeric.cpp \
+ global/qoperatingsystemversion.cpp \
global/qlogging.cpp \
global/qhooks.cpp
VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
+darwin: SOURCES += global/qoperatingsystemversion_darwin.mm
+win32: SOURCES += global/qoperatingsystemversion_win.cpp
+
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index d06acb83b2..cbefe92eca 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -45,6 +45,8 @@
#include "qthreadstorage.h"
#include "qdir.h"
#include "qdatetime.h"
+#include "qoperatingsystemversion.h"
+#include "qoperatingsystemversion_p.h"
#include <private/qlocale_tools_p.h>
#include <qmutex.h>
@@ -1088,12 +1090,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::WindowsVersion
\brief the version of the Windows operating system on which the
application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::WindowsVersion QSysInfo::windowsVersion()
\since 4.4
@@ -1103,12 +1107,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::MacintoshVersion
\brief the version of the Macintosh operating system on which
the application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::MacVersion QSysInfo::macVersion()
Returns the version of Darwin (\macos or iOS) on which the
@@ -1126,6 +1132,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::WinVersion
This enum provides symbolic names for the various versions of the
@@ -1182,6 +1189,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::MacVersion
This enum provides symbolic names for the various versions of the
@@ -1943,28 +1951,31 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qnamespace.h"
QT_END_INCLUDE_NAMESPACE
+#if QT_DEPRECATED_SINCE(5, 9)
QSysInfo::MacVersion QSysInfo::macVersion()
{
- const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm
+ const auto version = QOperatingSystemVersion::current();
#if defined(Q_OS_OSX)
- return QSysInfo::MacVersion(Q_MV_OSX(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_OSX(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_IOS)
- return QSysInfo::MacVersion(Q_MV_IOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_IOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_TVOS)
- return QSysInfo::MacVersion(Q_MV_TVOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_TVOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_WATCHOS)
- return QSysInfo::MacVersion(Q_MV_WATCHOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_WATCHOS(version.majorVersion(), version.minorVersion()));
#else
return QSysInfo::MV_Unknown;
#endif
}
const QSysInfo::MacVersion QSysInfo::MacintoshVersion = QSysInfo::macVersion();
+#endif
-#ifdef Q_OS_OSX
-static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple_os_version())
+#ifdef Q_OS_DARWIN
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- if (version.major == 10) {
- switch (version.minor) {
+#ifdef Q_OS_MACOS
+ if (version.majorVersion() == 10) {
+ switch (version.minorVersion()) {
case 9:
return "Mavericks";
case 10:
@@ -1976,6 +1987,9 @@ static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple
}
}
// unknown, future version
+#else
+ Q_UNUSED(version);
+#endif
return 0;
}
#endif
@@ -2016,140 +2030,30 @@ QWindowsSockInit::~QWindowsSockInit()
Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
# endif // QT_BOOTSTRAPPED
-#ifdef Q_OS_WINRT
-static inline HMODULE moduleHandleForFunction(LPCVOID address)
-{
- // This is a widely used, decades-old technique for retrieving the handle
- // of a module and is effectively equivalent to GetModuleHandleEx
- // (which is unavailable on WinRT)
- MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
- if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
- return 0;
- return reinterpret_cast<HMODULE>(mbi.AllocationBase);
-}
-#endif
-
-static inline OSVERSIONINFOEX determineWinOsVersion()
-{
- OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
-
-#define GetProcAddressA GetProcAddress
-
- // GetModuleHandle is not supported in WinRT and linking to it at load time
- // will not pass the Windows App Certification Kit... but it exists and is functional,
- // so use some unusual but widely used techniques to get a pointer to it
-#ifdef Q_OS_WINRT
- // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
- HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
- if (Q_UNLIKELY(!kernelModule))
- return result;
-
- // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
- typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
- GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
- GetProcAddressA(kernelModule, "GetModuleHandleW"));
- if (Q_UNLIKELY(!pGetModuleHandle))
- return result;
-#else
-#define pGetModuleHandle GetModuleHandleW
-#endif
-
-#ifndef Q_OS_WINCE
- HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
- if (Q_UNLIKELY(!ntdll))
- return result;
-
- // NTSTATUS is not defined on WinRT
- typedef LONG NTSTATUS;
- typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
-
- // RtlGetVersion is documented public API but we must load it dynamically
- // because linking to it at load time will not pass the Windows App Certification Kit
- // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
- RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
- GetProcAddressA(ntdll, "RtlGetVersion"));
- if (Q_UNLIKELY(!pRtlGetVersion))
- return result;
-
- // GetVersionEx() has been deprecated in Windows 8.1 and will return
- // only Windows 8 from that version on, so use the kernel API function.
- pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
-#else // !Q_OS_WINCE
- GetVersionEx(&result);
-#endif
- return result;
-}
-
-static OSVERSIONINFOEX winOsVersion()
-{
- OSVERSIONINFOEX realResult = determineWinOsVersion();
-#ifdef QT_DEBUG
- {
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
- OSVERSIONINFOEX result = realResult;
- result.dwMajorVersion = 0;
- result.dwMinorVersion = 0;
-
- // Erase any build number and service pack information
- result.dwBuildNumber = 0;
- result.szCSDVersion[0] = L'\0';
- result.wServicePackMajor = 0;
- result.wServicePackMinor = 0;
-
- const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
- if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 1;
- } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 2;
- } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 3;
- } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
- result.dwMajorVersion = 10;
- } else {
- return realResult;
- }
-
- if (winVerOverride == "2008_R2"
- || winVerOverride == "2012"
- || winVerOverride == "2012_R2"
- || winVerOverride == "2016") {
- // If the current host OS is a domain controller and the override OS
- // is also a server type OS, preserve that information
- if (result.wProductType == VER_NT_WORKSTATION)
- result.wProductType = VER_NT_SERVER;
- } else {
- // Any other OS must be a workstation OS type
- result.wProductType = VER_NT_WORKSTATION;
- }
- }
- }
-#endif
- return realResult;
-}
-
+#if QT_DEPRECATED_SINCE(5, 9)
QSysInfo::WinVersion QSysInfo::windowsVersion()
{
- const OSVERSIONINFOEX osver = winOsVersion();
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
+ const auto version = QOperatingSystemVersion::current();
+ if (version.majorVersion() == 6 && version.minorVersion() == 1)
return QSysInfo::WV_WINDOWS7;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
+ if (version.majorVersion() == 6 && version.minorVersion() == 2)
return QSysInfo::WV_WINDOWS8;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3)
+ if (version.majorVersion() == 6 && version.minorVersion() == 3)
return QSysInfo::WV_WINDOWS8_1;
- if (osver.dwMajorVersion == 10 && osver.dwMinorVersion == 0)
+ if (version.majorVersion() == 10 && version.minorVersion() == 0)
return QSysInfo::WV_WINDOWS10;
return QSysInfo::WV_NT_based;
}
+const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
+#endif
static QString winSp_helper()
{
- const qint16 major = winOsVersion().wServicePackMajor;
+ const auto osv = qWindowsVersionInfo();
+ const qint16 major = osv.wServicePackMajor;
if (major) {
QString sp = QStringLiteral(" SP ") + QString::number(major);
- const qint16 minor = winOsVersion().wServicePackMinor;
+ const qint16 minor = osv.wServicePackMinor;
if (minor)
sp += QLatin1Char('.') + QString::number(minor);
@@ -2158,9 +2062,10 @@ static QString winSp_helper()
return QString();
}
-static const char *winVer_helper()
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- const OSVERSIONINFOEX osver = winOsVersion();
+ Q_UNUSED(version);
+ const OSVERSIONINFOEX osver = qWindowsVersionInfo();
const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
#define Q_WINVER(major, minor) (major << 8 | minor)
@@ -2179,8 +2084,6 @@ static const char *winVer_helper()
return 0;
}
-const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
-
#endif
#if defined(Q_OS_UNIX)
# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
@@ -2361,6 +2264,68 @@ static bool findUnixOsVersion(QUnixOSVersion &v)
# endif // USE_ETC_OS_RELEASE
#endif // Q_OS_UNIX
+#ifdef Q_OS_ANDROID
+static const char *osVer_helper(QOperatingSystemVersion)
+{
+/* Data:
+
+
+
+Cupcake
+Donut
+Eclair
+Eclair
+Eclair
+Froyo
+Gingerbread
+Gingerbread
+Honeycomb
+Honeycomb
+Honeycomb
+Ice Cream Sandwich
+Ice Cream Sandwich
+Jelly Bean
+Jelly Bean
+Jelly Bean
+KitKat
+KitKat
+Lollipop
+Lollipop
+Marshmallow
+Nougat
+Nougat
+ */
+ static const char versions_string[] =
+ "\0"
+ "Cupcake\0"
+ "Donut\0"
+ "Eclair\0"
+ "Froyo\0"
+ "Gingerbread\0"
+ "Honeycomb\0"
+ "Ice Cream Sandwich\0"
+ "Jelly Bean\0"
+ "KitKat\0"
+ "Lollipop\0"
+ "Marshmallow\0"
+ "Nougat\0"
+ "\0";
+
+ static const int versions_indices[] = {
+ 0, 0, 0, 1, 9, 15, 15, 15,
+ 22, 28, 28, 40, 40, 40, 50, 50,
+ 69, 69, 69, 80, 80, 87, 87, 96,
+ 108, 108, -1
+ };
+
+ static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]);
+
+ // https://source.android.com/source/build-numbers.html
+ // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
+ const int sdk_int = QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
+ return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
+}
+#endif
/*!
\since 5.4
@@ -2609,9 +2574,9 @@ QString QSysInfo::kernelType()
QString QSysInfo::kernelVersion()
{
#ifdef Q_OS_WIN
- const OSVERSIONINFOEX osver = winOsVersion();
- return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion))
- + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber));
+ const auto osver = QOperatingSystemVersion::current();
+ return QString::number(osver.majorVersion()) + QLatin1Char('.') + QString::number(osver.minorVersion())
+ + QLatin1Char('.') + QString::number(osver.microVersion());
#else
struct utsname u;
if (uname(&u) == 0)
@@ -2679,8 +2644,8 @@ QString QSysInfo::productType()
#elif defined(Q_OS_WATCHOS)
return QStringLiteral("watchos");
#elif defined(Q_OS_MACOS)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- if (version.major == 10 && version.minor < 12)
+ const auto version = QOperatingSystemVersion::current();
+ if (version.majorVersion() == 10 && version.minorVersion() < 12)
return QStringLiteral("osx");
return QStringLiteral("macos");
#elif defined(Q_OS_DARWIN)
@@ -2720,20 +2685,17 @@ QString QSysInfo::productType()
*/
QString QSysInfo::productVersion()
{
-#if defined(Q_OS_MAC)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- return QString::number(version.major) + QLatin1Char('.') + QString::number(version.minor);
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ const auto version = QOperatingSystemVersion::current();
+ return QString::number(version.majorVersion()) + QLatin1Char('.') + QString::number(version.minorVersion());
#elif defined(Q_OS_WIN)
- const char *version = winVer_helper();
+ const char *version = osVer_helper();
if (version) {
const QLatin1Char spaceChar(' ');
return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
}
// fall through
-// Android should not fall through to the Unix code
-#elif defined(Q_OS_ANDROID)
- return QJNIObjectPrivate::getStaticObjectField("android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString();
#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
QUnixOSVersion unixOsVersion;
findUnixOsVersion(unixOsVersion);
@@ -2761,44 +2723,23 @@ QString QSysInfo::productVersion()
*/
QString QSysInfo::prettyProductName()
{
-#if defined(Q_OS_IOS)
- return QLatin1String("iOS ") + productVersion();
-#elif defined(Q_OS_TVOS)
- return QLatin1String("tvOS ") + productVersion();
-#elif defined(Q_OS_WATCHOS)
- return QLatin1String("watchOS ") + productVersion();
-#elif defined(Q_OS_MACOS)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- const char *name = osxVer_helper(version);
- if (name) {
- return (version.major == 10 && version.minor < 12
- ? QLatin1String("OS X ")
- : QLatin1String("macOS "))
- + QLatin1String(name)
- + QLatin1String(" (") + QString::number(version.major)
- + QLatin1Char('.') + QString::number(version.minor)
- + QLatin1Char(')');
- } else {
- return QLatin1String("macOS ")
- + QString::number(version.major) + QLatin1Char('.')
- + QString::number(version.minor);
- }
-#elif defined(Q_OS_WINPHONE)
- return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper());
-#elif defined(Q_OS_WIN)
- const char *name = winVer_helper();
- const OSVERSIONINFOEX osver = winOsVersion();
+#if defined(Q_OS_WINPHONE)
+ return QLatin1String("Windows Phone ") + QLatin1String(osVer_helper());
+#elif defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
+ const auto version = QOperatingSystemVersion::current();
+ const char *name = osVer_helper(version);
if (name)
- return QLatin1String("Windows ") + QLatin1String(name) + winSp_helper()
- + QLatin1String(" (") + QString::number(osver.dwMajorVersion)
- + QLatin1Char('.') + QString::number(osver.dwMinorVersion)
+ return version.name() + QLatin1Char(' ') + QLatin1String(name)
+# if defined(Q_OS_WIN)
+ + winSp_helper()
+# endif
+ + QLatin1String(" (") + QString::number(version.majorVersion())
+ + QLatin1Char('.') + QString::number(version.minorVersion())
+ QLatin1Char(')');
- else
- return QLatin1String("Windows ")
- + QString::number(osver.dwMajorVersion) + QLatin1Char('.')
- + QString::number(osver.dwMinorVersion);
-#elif defined(Q_OS_ANDROID)
- return QLatin1String("Android ") + productVersion();
+ else
+ return version.name() + QLatin1Char(' ')
+ + QString::number(version.majorVersion()) + QLatin1Char('.')
+ + QString::number(version.minorVersion());
#elif defined(Q_OS_HAIKU)
return QLatin1String("Haiku ") + productVersion();
#elif defined(Q_OS_UNIX)
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
new file mode 100644
index 0000000000..75d3f99fee
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -0,0 +1,423 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion.h"
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+#include "qoperatingsystemversion_p.h"
+#endif
+
+#include <qversionnumber.h>
+
+#if defined(Q_OS_ANDROID)
+#include <private/qjni_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOperatingSystemVersion
+ \inmodule QtCore
+ \since 5.9
+ \brief The QOperatingSystemVersion class provides information about the operating system version.
+
+ Unlike other version functions in QSysInfo, QOperatingSystemVersion provides access to the full
+ version number that \a developers typically use to vary behavior or determine whether to enable
+ APIs or features based on the operating system version (as opposed to the kernel version number
+ or marketing version).
+
+ This class is also a complete replacement for QSysInfo::macVersion and QSysInfo::windowsVersion,
+ additionally providing access to the third (micro) version number component.
+
+ Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS), and Windows are supported.
+
+ The \a majorVersion(), \a minorVersion(), and \a microVersion() functions return the parts of
+ the operating system version number based on:
+
+ \table
+ \header \li Platforms \li Value
+ \row \li Android \li result of parsing
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{"android.os.Build.VERSION.RELEASE"}
+ using QVersionNumber, with a fallback to
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{"android.os.Build.VERSION.SDK_INT"}
+ to determine the major and minor version component if the former fails
+ \row \li Apple Platforms \li majorVersion, minorVersion, and patchVersion from
+ \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{"NSProcessInfo.operatingSystemVersion"}
+ \row \li Windows \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from
+ \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{"RtlGetVersion"} -
+ note that this function ALWAYS return the version number of the underlying operating system,
+ as opposed to the shim underneath GetVersionEx that hides the real version number
+ if the application is not manifested for that version of the OS
+ \endtable
+*/
+
+/*!
+ \fn QOperatingSystemVersion::QOperatingSystemVersion(int maj, int min, int mic)
+
+ Constructs a QOperatingSystemVersion consisting of the OS type \a os, and
+ major, minor, and micro version numbers \a maj, \a min and \a mic, respectively.
+*/
+
+/*!
+ \fn QOperatingSystemVersion QOperatingSystemVersion::current()
+
+ Returns a QOperatingSystemVersion indicating the current OS and its version number.
+*/
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion version;
+ version.m_os = currentType();
+#if defined(Q_OS_ANDROID)
+#ifndef QT_BOOTSTRAPPED
+ const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
+ "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
+ if (!v.isNull()) {
+ version.m_major = v.majorVersion();
+ version.m_minor = v.minorVersion();
+ version.m_micro = v.microVersion();
+ return version;
+ }
+#endif
+
+ version.m_major = -1;
+ version.m_minor = -1;
+
+ static const int versions[][2] = {
+ { 1, 0 }, // API level 1
+ { 1, 1 }, // API level 2
+ { 1, 5 }, // API level 3
+ { 1, 6 }, // API level 4
+ { 2, 0 }, // API level 5
+ { 2, 0 }, // API level 6
+ { 2, 1 }, // API level 7
+ { 2, 2 }, // API level 8
+ { 2, 3 }, // API level 9
+ { 2, 3 }, // API level 10
+ { 3, 0 }, // API level 11
+ { 3, 1 }, // API level 12
+ { 3, 2 }, // API level 13
+ { 4, 0 }, // API level 14
+ { 4, 0 }, // API level 15
+ { 4, 1 }, // API level 16
+ { 4, 2 }, // API level 17
+ { 4, 3 }, // API level 18
+ { 4, 4 }, // API level 19
+ { 4, 4 }, // API level 20
+ { 5, 0 }, // API level 21
+ { 5, 1 }, // API level 22
+ { 6, 0 }, // API level 23
+ { 7, 0 }, // API level 24
+ { 7, 1 }, // API level 25
+ };
+
+ // This will give us at least the first 2 version components
+ const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT")) - 1;
+ if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
+ version.m_major = versions[versionIdx][0];
+ version.m_minor = versions[versionIdx][1];
+ }
+
+ // API level 6 was exactly version 2.0.1
+ version.m_micro = versionIdx == 5 ? 1 : -1;
+#else
+ version.m_major = -1;
+ version.m_minor = -1;
+ version.m_micro = -1;
+#endif
+ return version;
+}
+#endif
+
+static inline int compareVersionComponents(int lhs, int rhs)
+{
+ return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
+}
+
+/*!
+ \fn int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
+ const QOperatingSystemVersion &v2)
+
+ Compares \a v1 with \a v2 and returns an integer less than, equal to, or
+ greater than zero, depending on whether \a v1 is less than, equal to, or
+ greater than \a v2, respectively.
+
+ Comparisons are performed by comparing the version number components of
+ \a v1 and \a v2.
+
+ \note This function cannot take the OS type into account; you should use
+ the overloaded comparison operators to compare QOperatingSystemVersions
+ in a safe manner.
+*/
+int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2)
+{
+ if (v1.m_major == v2.m_major) {
+ if (v1.m_minor == v2.m_minor) {
+ return compareVersionComponents(v1.m_micro, v2.m_micro);
+ }
+ return compareVersionComponents(v1.m_minor, v2.m_minor);
+ }
+ return compareVersionComponents(v1.m_major, v2.m_major);
+}
+
+#ifndef QT_BOOTSTRAPPED
+/*!
+ \fn QOperatingSystemVersion QOperatingSystemVersion::fromVersionNumber(const QVersionNumber &version,
+ QOperatingSystemVersion::OSType os)
+
+ Returns a QOperatingSystemVersion consisting of the OS type \a os and version number \a version.
+*/
+QOperatingSystemVersion QOperatingSystemVersion::fromVersionNumber(const QVersionNumber &version,
+ QOperatingSystemVersion::OSType os)
+{
+ return QOperatingSystemVersion(os, version.majorVersion(), version.minorVersion(), version.microVersion());
+}
+
+/*!
+ \fn QOperatingSystemVersion QOperatingSystemVersion::toVersionNumber() const
+
+ Returns the QOperatingSystemVersion's version number as a QVersionNumber.
+*/
+QVersionNumber QOperatingSystemVersion::toVersionNumber() const
+{
+ return QVersionNumber(m_major, m_minor, m_micro);
+}
+#endif
+
+/*!
+ \fn int QOperatingSystemVersion::majorVersion() const
+
+ Returns the major version number, that is, the first segment of the operating system's version number.
+
+ See the main class documentation for what the major version number is on a given operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa minorVersion(), microVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::minorVersion() const
+
+ Returns the minor version number, that is, the second segment of the operating system's version number.
+
+ See the main class documentation for what the minor version number is on a given operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), macro()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::microVersion() const
+
+ Returns the micro version number, that is, the third segment of the operating system's version number.
+
+ See the main class documentation for what the micro version number is on a given operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), minorVersion()
+*/
+
+/*!
+ \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const
+
+ Returns the OS type identified by the QOperatingSystemVersion.
+
+ \sa typeName()
+*/
+
+/*!
+ \fn QString QOperatingSystemVersion::name() const
+
+ Returns a string representation of the OS type identified by the QOperatingSystemVersion.
+
+ \sa type()
+*/
+QString QOperatingSystemVersion::name() const
+{
+ switch (type()) {
+ case QOperatingSystemVersion::Windows:
+ return QStringLiteral("Windows");
+ case QOperatingSystemVersion::MacOS: {
+ if (majorVersion() < 10)
+ return QStringLiteral("Mac OS");
+ if (majorVersion() == 10 && minorVersion() < 8)
+ return QStringLiteral("Mac OS X");
+ if (majorVersion() == 10 && minorVersion() < 12)
+ return QStringLiteral("OS X");
+ return QStringLiteral("macOS");
+ }
+ case QOperatingSystemVersion::IOS: {
+ if (majorVersion() < 4)
+ return QStringLiteral("iPhone OS");
+ return QStringLiteral("iOS");
+ }
+ case QOperatingSystemVersion::TvOS:
+ return QStringLiteral("tvOS");
+ case QOperatingSystemVersion::WatchOS:
+ return QStringLiteral("watchOS");
+ case QOperatingSystemVersion::Android:
+ return QStringLiteral("Android");
+ case QOperatingSystemVersion::Unknown:
+ default:
+ return QString();
+ }
+}
+
+/*!
+ \variable QOperatingSystemVersion::Windows7
+ \brief a version corresponding to Windows 7 (version 6.1).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows7 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8
+ \brief a version corresponding to Windows 8 (version 6.2).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8_1
+ \brief a version corresponding to Windows 8.1 (version 6.3).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3);
+
+/*!
+ \variable QOperatingSystemVersion::Windows10
+ \brief a version corresponding to Windows 10 (version 10.0).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows10 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXMavericks
+ \brief a version corresponding to OS X Mavericks (version 10.9).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9);
+
+/*!
+ \variable QOperatingSystemVersion::OSXYosemite
+ \brief a version corresponding to OS X Yosemite (version 10.10).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXElCapitan
+ \brief a version corresponding to OS X El Capitan (version 10.11).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11);
+
+/*!
+ \variable QOperatingSystemVersion::MacOSSierra
+ \brief a version corresponding to macOS Sierra (version 10.12).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean
+ \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR1
+ \brief a version corresponding to Android Jelly Bean, maintenance release 1 (version 4.2, API level 17).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR1 = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 2);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR2
+ \brief a version corresponding to Android Jelly Bean, maintenance release 2 (version 4.3, API level 18).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR2 = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 3);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidKitKat
+ \brief a version corresponding to Android KitKat (versions 4.4 & 4.4W, API levels 19 & 20).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop
+ \brief a version corresponding to Android Lollipop (version 5.0, API level 21).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop = QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop_MR1
+ \brief a version corresponding to Android Lollipop, maintenance release 1 (version 5.1, API level 22).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop_MR1 = QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidMarshmallow
+ \brief a version corresponding to Android Marshmallow (version 6.0, API level 23).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow = QOperatingSystemVersion(QOperatingSystemVersion::Android, 6, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat
+ \brief a version corresponding to Android Nougat (version 7.0, API level 24).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat = QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat_MR1
+ \brief a version corresponding to Android Nougat, maintenance release 1 (version 7.0, API level 25).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 = QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 1);
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
new file mode 100644
index 0000000000..ef999c6ae4
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QOPERATINGSYSTEMVERSION_H
+#define QOPERATINGSYSTEMVERSION_H
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QVersionNumber;
+
+class Q_CORE_EXPORT QOperatingSystemVersion
+{
+public:
+ enum OSType {
+ Unknown = 0,
+ Windows,
+ MacOS,
+ IOS,
+ TvOS,
+ WatchOS,
+ Android
+ };
+
+ static const QOperatingSystemVersion Windows7;
+ static const QOperatingSystemVersion Windows8;
+ static const QOperatingSystemVersion Windows8_1;
+ static const QOperatingSystemVersion Windows10;
+
+ static const QOperatingSystemVersion OSXMavericks;
+ static const QOperatingSystemVersion OSXYosemite;
+ static const QOperatingSystemVersion OSXElCapitan;
+ static const QOperatingSystemVersion MacOSSierra;
+
+ static const QOperatingSystemVersion AndroidJellyBean;
+ static const QOperatingSystemVersion AndroidJellyBean_MR1;
+ static const QOperatingSystemVersion AndroidJellyBean_MR2;
+ static const QOperatingSystemVersion AndroidKitKat;
+ static const QOperatingSystemVersion AndroidLollipop;
+ static const QOperatingSystemVersion AndroidLollipop_MR1;
+ static const QOperatingSystemVersion AndroidMarshmallow;
+ static const QOperatingSystemVersion AndroidNougat;
+ static const QOperatingSystemVersion AndroidNougat_MR1;
+
+ QOperatingSystemVersion(const QOperatingSystemVersion &other) = default;
+ Q_DECL_CONSTEXPR QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
+ : m_os(osType), m_major(vmajor), m_minor(vminor), m_micro(vmicro) { }
+
+ static QOperatingSystemVersion current();
+
+ static int compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2);
+
+ QOperatingSystemVersion fromVersionNumber(const QVersionNumber &version, OSType os);
+ QVersionNumber toVersionNumber() const;
+
+ Q_DECL_CONSTEXPR int majorVersion() const { return m_major; }
+ Q_DECL_CONSTEXPR int minorVersion() const { return m_minor; }
+ Q_DECL_CONSTEXPR int microVersion() const { return m_micro; }
+
+ Q_DECL_CONSTEXPR OSType type() const { return m_os; }
+ QString name() const;
+
+private:
+ QOperatingSystemVersion() = default;
+ OSType m_os;
+ int m_major;
+ int m_minor;
+ int m_micro;
+};
+
+inline bool operator>(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) > 0; }
+
+inline bool operator>=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) >= 0; }
+
+inline bool operator<(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) < 0; }
+
+inline bool operator<=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) <= 0; }
+
+inline bool operator==(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) == 0; }
+
+inline bool operator!=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+{ return !(lhs == rhs); }
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_H
diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm
new file mode 100644
index 0000000000..3dd007cbb3
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_darwin.mm
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#import <Foundation/Foundation.h>
+
+#ifdef Q_OS_IOS
+#import <UIKit/UIKit.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response);
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ v.m_major = -1;
+ v.m_minor = -1;
+ v.m_micro = -1;
+#if QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS)
+ if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) {
+ NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
+ v.m_major = osv.majorVersion;
+ v.m_minor = osv.minorVersion;
+ v.m_micro = osv.patchVersion;
+ return v;
+ }
+#endif
+ // Use temporary variables so we can return 0.0.0 (unknown version)
+ // in case of an error partway through determining the OS version
+ qint32 major = 0, minor = 0, patch = 0;
+#if QT_MACOS_IOS_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0)
+#if defined(Q_OS_IOS)
+ @autoreleasepool {
+ NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."];
+ major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0;
+ minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0;
+ patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0;
+ }
+#elif defined(Q_OS_MACOS)
+ static GestaltFunction pGestalt = 0;
+ if (!pGestalt) {
+ CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices"));
+ pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b,
+ CFSTR("Gestalt")));
+ }
+ if (!pGestalt)
+ return v;
+ if (pGestalt('sys1', &major) != 0)
+ return v;
+ if (pGestalt('sys2', &minor) != 0)
+ return v;
+ if (pGestalt('sys3', &patch) != 0)
+ return v;
+#endif
+#endif
+ v.m_major = major;
+ v.m_minor = minor;
+ v.m_micro = patch;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion_p.h b/src/corelib/global/qoperatingsystemversion_p.h
new file mode 100644
index 0000000000..78d0daf0c6
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPERATINGSYSTEMVERSION_P_H
+#define QOPERATINGSYSTEMVERSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qoperatingsystemversion.h"
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+OSVERSIONINFOEX qWindowsVersionInfo();
+#endif
+
+static inline QOperatingSystemVersion::OSType currentType()
+{
+#if defined(Q_OS_WIN)
+ return QOperatingSystemVersion::Windows;
+#elif defined(Q_OS_MACOS)
+ return QOperatingSystemVersion::MacOS;
+#elif defined(Q_OS_IOS)
+ return QOperatingSystemVersion::IOS;
+#elif defined(Q_OS_TVOS)
+ return QOperatingSystemVersion::TvOS;
+#elif defined(Q_OS_WATCHOS)
+ return QOperatingSystemVersion::WatchOS;
+#elif defined(Q_OS_ANDROID)
+ return QOperatingSystemVersion::Android;
+#else
+ return QOperatingSystemVersion::Unknown;
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_P_H
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
new file mode 100644
index 0000000000..060ca2f7da
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#include <qt_windows.h>
+#include <qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WINRT
+static inline HMODULE moduleHandleForFunction(LPCVOID address)
+{
+ // This is a widely used, decades-old technique for retrieving the handle
+ // of a module and is effectively equivalent to GetModuleHandleEx
+ // (which is unavailable on WinRT)
+ MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
+ if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
+ return 0;
+ return reinterpret_cast<HMODULE>(mbi.AllocationBase);
+}
+#endif
+
+static inline OSVERSIONINFOEX determineWinOsVersion()
+{
+ OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
+
+#define GetProcAddressA GetProcAddress
+
+ // GetModuleHandle is not supported in WinRT and linking to it at load time
+ // will not pass the Windows App Certification Kit... but it exists and is functional,
+ // so use some unusual but widely used techniques to get a pointer to it
+#ifdef Q_OS_WINRT
+ // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
+ HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
+ if (Q_UNLIKELY(!kernelModule))
+ return result;
+
+ // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
+ typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
+ GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
+ GetProcAddressA(kernelModule, "GetModuleHandleW"));
+ if (Q_UNLIKELY(!pGetModuleHandle))
+ return result;
+#else
+#define pGetModuleHandle GetModuleHandleW
+#endif
+
+#ifndef Q_OS_WINCE
+ HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
+ if (Q_UNLIKELY(!ntdll))
+ return result;
+
+ // NTSTATUS is not defined on WinRT
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
+
+ // RtlGetVersion is documented public API but we must load it dynamically
+ // because linking to it at load time will not pass the Windows App Certification Kit
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
+ RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
+ GetProcAddressA(ntdll, "RtlGetVersion"));
+ if (Q_UNLIKELY(!pRtlGetVersion))
+ return result;
+
+ // GetVersionEx() has been deprecated in Windows 8.1 and will return
+ // only Windows 8 from that version on, so use the kernel API function.
+ pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
+#else // !Q_OS_WINCE
+ GetVersionEx(&result);
+#endif
+ return result;
+}
+
+OSVERSIONINFOEX qWindowsVersionInfo()
+{
+ OSVERSIONINFOEX realResult = determineWinOsVersion();
+#ifdef QT_DEBUG
+ {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
+ OSVERSIONINFOEX result = realResult;
+ result.dwMajorVersion = 0;
+ result.dwMinorVersion = 0;
+
+ // Erase any build number and service pack information
+ result.dwBuildNumber = 0;
+ result.szCSDVersion[0] = L'\0';
+ result.wServicePackMajor = 0;
+ result.wServicePackMinor = 0;
+
+ const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
+ if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 1;
+ } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 2;
+ } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 3;
+ } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
+ result.dwMajorVersion = 10;
+ } else {
+ return realResult;
+ }
+
+ if (winVerOverride == "2008_R2"
+ || winVerOverride == "2012"
+ || winVerOverride == "2012_R2"
+ || winVerOverride == "2016") {
+ // If the current host OS is a domain controller and the override OS
+ // is also a server type OS, preserve that information
+ if (result.wProductType == VER_NT_WORKSTATION)
+ result.wProductType = VER_NT_SERVER;
+ } else {
+ // Any other OS must be a workstation OS type
+ result.wProductType = VER_NT_WORKSTATION;
+ }
+ }
+ }
+#endif
+ return realResult;
+}
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ const OSVERSIONINFOEX osv = qWindowsVersionInfo();
+ v.m_major = osv.dwMajorVersion;
+ v.m_minor = osv.dwMinorVersion;
+ v.m_micro = osv.dwBuildNumber;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index 23f412aa6a..3cbcfd3fc9 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -49,6 +49,23 @@ QT_BEGIN_NAMESPACE
System information
*/
+/*
+ * GCC (5-7) has a regression that causes it to emit wrong deprecated warnings:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77849
+ *
+ * Try to work around it by defining our own macro.
+ */
+
+#ifdef QT_SYSINFO_DEPRECATED_X
+#error "QT_SYSINFO_DEPRECATED_X already defined"
+#endif
+
+#ifdef Q_CC_GNU
+#define QT_SYSINFO_DEPRECATED_X(x)
+#else
+#define QT_SYSINFO_DEPRECATED_X(x) QT_DEPRECATED_X(x)
+#endif
+
class QString;
class Q_CORE_EXPORT QSysInfo {
public:
@@ -79,7 +96,8 @@ public:
# endif
};
#endif
- enum WinVersion {
+#if QT_DEPRECATED_SINCE(5, 9)
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") WinVersion {
WV_None = 0x0000,
WV_32s = 0x0001,
@@ -117,19 +135,25 @@ public:
WV_CE_6 = 0x0400,
WV_CE_based = 0x0f00
};
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_INTEL(1478)
+QT_WARNING_DISABLE_MSVC(4996)
#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
- static const WinVersion WindowsVersion;
- static WinVersion windowsVersion();
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion();
#else
- static const WinVersion WindowsVersion = WV_None;
- static WinVersion windowsVersion() { return WV_None; }
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion = WV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion() { return WV_None; }
#endif
+QT_WARNING_POP
#define Q_MV_OSX(major, minor) (major == 10 ? minor + 2 : (major == 9 ? 1 : 0))
#define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor)
#define Q_MV_TVOS(major, minor) (QSysInfo::MV_TVOS | major << 4 | minor)
#define Q_MV_WATCHOS(major, minor) (QSysInfo::MV_WATCHOS | major << 4 | minor)
- enum MacVersion {
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") MacVersion {
MV_None = 0xffff,
MV_Unknown = 0x0000,
@@ -198,13 +222,20 @@ public:
MV_WATCHOS_2_2 = Q_MV_WATCHOS(2, 2),
MV_WATCHOS_3_0 = Q_MV_WATCHOS(3, 0)
};
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_INTEL(1478)
+QT_WARNING_DISABLE_MSVC(4996)
#if defined(Q_OS_MAC)
- static const MacVersion MacintoshVersion;
- static MacVersion macVersion();
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion();
#else
- static const MacVersion MacintoshVersion = MV_None;
- static MacVersion macVersion() { return MV_None; }
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion = MV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion() { return MV_None; }
#endif
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(5, 9)
static QString buildCpuArchitecture();
static QString currentCpuArchitecture();
@@ -219,5 +250,7 @@ public:
static QString machineHostName();
};
+#undef QT_SYSINFO_DEPRECATED_X
+
QT_END_NAMESPACE
#endif // QSYSINFO_H
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index ac58677b77..994ed88791 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -95,10 +95,11 @@ public:
Qt_5_6 = 17,
Qt_5_7 = Qt_5_6,
Qt_5_8 = Qt_5_7,
-#if QT_VERSION >= 0x050900
+ Qt_5_9 = Qt_5_8,
+#if QT_VERSION >= 0x050a00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_8
+ Qt_DefaultCompiledVersion = Qt_5_9
};
enum ByteOrder {
@@ -222,6 +223,98 @@ private:
QDataStream::Status oldStatus;
};
+template <typename Container>
+QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ c.reserve(n);
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.append(t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readListBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c << t;
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::key_type k;
+ typename Container::mapped_type t;
+ s >> k >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.insertMulti(k, t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ for (const typename Container::value_type &t : c)
+ s << t;
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ // Deserialization should occur in the reverse order.
+ // Otherwise, value() will return the least recently inserted
+ // value instead of the most recently inserted one.
+ auto it = c.constEnd();
+ auto begin = c.constBegin();
+ while (it != begin) {
+ --it;
+ s << it.key() << it.value();
+ }
+
+ return s;
+}
+
} // QtPrivate namespace
/*****************************************************************************
@@ -265,209 +358,75 @@ inline QDataStream &QDataStream::operator<<(quint64 i)
{ return *this << qint64(i); }
template <typename T>
-QDataStream& operator>>(QDataStream& s, QList<T>& l)
+inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- l.clear();
- quint32 c;
- s >> c;
- l.reserve(c);
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
-
- return s;
+ return QtPrivate::readArrayBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
{
- s << quint32(l.size());
- for (int i = 0; i < l.size(); ++i)
- s << l.at(i);
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template <typename T>
-QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l)
+inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- l.clear();
- quint32 c;
- s >> c;
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
-
- return s;
+ return QtPrivate::readListBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
{
- s << quint32(l.size());
- typename QLinkedList<T>::ConstIterator it = l.constBegin();
- for(; it != l.constEnd(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template<typename T>
-QDataStream& operator>>(QDataStream& s, QVector<T>& v)
+inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- v.clear();
- quint32 c;
- s >> c;
- v.resize(c);
- for(quint32 i = 0; i < c; ++i) {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- v.clear();
- break;
- }
- v[i] = t;
- }
-
- return s;
+ return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-QDataStream& operator<<(QDataStream& s, const QVector<T>& v)
+inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
{
- s << quint32(v.size());
- for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- set.clear();
- quint32 c;
- in >> c;
- for (quint32 i = 0; i < c; ++i) {
- T t;
- in >> t;
- if (in.status() != QDataStream::Ok) {
- set.clear();
- break;
- }
- set << t;
- }
-
- return in;
+ return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-QDataStream& operator<<(QDataStream &out, const QSet<T> &set)
+inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
{
- out << quint32(set.size());
- typename QSet<T>::const_iterator i = set.constBegin();
- while (i != set.constEnd()) {
- out << *i;
- ++i;
- }
- return out;
+ return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash)
+inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- hash.clear();
- quint32 n;
- in >> n;
-
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- Key k;
- T t;
- in >> k >> t;
- hash.insertMulti(k, t);
- }
-
- if (in.status() != QDataStream::Ok)
- hash.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
+inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
- out << quint32(hash.size());
- typename QHash<Key, T>::ConstIterator it = hash.end();
- typename QHash<Key, T>::ConstIterator begin = hash.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, hash);
}
-#ifdef Q_QDOC
+
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map)
-#else
-template <class aKey, class aT>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map)
-#endif
+inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- map.clear();
- quint32 n;
- in >> n;
-
- map.detach();
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- aKey key;
- aT value;
- in >> key >> value;
- map.insertMulti(key, value);
- }
- if (in.status() != QDataStream::Ok)
- map.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
+inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
{
- out << quint32(map.size());
- typename QMap<Key, T>::ConstIterator it = map.end();
- typename QMap<Key, T>::ConstIterator begin = map.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, map);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index cdb64d08e1..663d9cd61d 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qfilesystemengine_p.h"
-
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qsysinfo.h"
#include "private/qabstractfileengine_p.h"
@@ -637,7 +637,7 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
if (handle) {
- result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
+ result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
CloseHandle(handle);
}
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 2ce7bd7a4b..9140118872 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -39,6 +39,7 @@
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qvector.h"
@@ -93,7 +94,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
haveData = true;
int infoLevel = 0 ; // FindExInfoStandard;
DWORD dwAdditionalFlags = 0;
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows7) {
dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
infoLevel = 1 ; // FindExInfoBasic;
}
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index a1d90c76f4..612b3fa57c 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -64,6 +64,9 @@
# include "qfilesystemwatcher_fsevents_p.h"
#endif
+#include <algorithm>
+#include <iterator>
+
QT_BEGIN_NAMESPACE
QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent)
@@ -102,6 +105,17 @@ void QFileSystemWatcherPrivate::init()
SIGNAL(directoryChanged(QString,bool)),
q,
SLOT(_q_directoryChanged(QString,bool)));
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemoval,
+ q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed,
+ q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveRemoved,
+ q, [this] (const QString &p) { _q_winDriveRemoved(p); });
+#endif // !Q_OS_WINRT
}
}
@@ -146,7 +160,46 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal());
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive for removal, release
+ // its paths under watch, temporarily storing them should the lock fail.
+ Q_Q(QFileSystemWatcher);
+ QStringList pathsToBeRemoved;
+ auto pred = [&path] (const QString &f) { return !f.startsWith(path, Qt::CaseInsensitive); };
+ std::remove_copy_if(files.cbegin(), files.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ std::remove_copy_if(directories.cbegin(), directories.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ if (!pathsToBeRemoved.isEmpty()) {
+ q->removePaths(pathsToBeRemoved);
+ temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved);
+ }
+}
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive failed (blocked by other
+ // application), restore the watched paths.
+ Q_Q(QFileSystemWatcher);
+ if (!path.isEmpty()) {
+ const auto it = temporarilyRemovedPaths.find(path.at(0));
+ if (it != temporarilyRemovedPaths.end()) {
+ q->addPaths(it.value());
+ temporarilyRemovedPaths.erase(it);
+ }
+ }
+}
+void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+{
+ // Windows: Drive finally removed, clear out paths stored in lock request.
+ if (!path.isEmpty())
+ temporarilyRemovedPaths.remove(path.at(0));
+}
+#endif // Q_OS_WIN && !Q_OS_WINRT
/*!
\class QFileSystemWatcher
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 6c64411f92..4220c1db28 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -58,6 +58,7 @@
#include <private/qobject_p.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,15 @@ public:
// private slots
void _q_fileChanged(const QString &path, bool removed);
void _q_directoryChanged(const QString &path, bool removed);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ void _q_winDriveLockForRemoval(const QString &);
+ void _q_winDriveLockForRemovalFailed(const QString &);
+ void _q_winDriveRemoved(const QString &);
+
+private:
+ QHash<QChar, QStringList> temporarilyRemovedPaths;
+#endif // Q_OS_WIN && !Q_OS_WINRT
};
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index be56d8dd1d..c385a82fc5 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -52,6 +52,16 @@
#include <qt_windows.h>
+#ifndef Q_OS_WINRT
+# include <qabstractnativeeventfilter.h>
+# include <qcoreapplication.h>
+# include <qdir.h>
+# include <private/qeventdispatcher_win_p.h>
+# include <dbt.h>
+# include <algorithm>
+# include <vector>
+#endif // !Q_OS_WINRT
+
QT_BEGIN_NAMESPACE
// #define WINQFSW_DEBUG
@@ -61,11 +71,275 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+#ifndef Q_OS_WINRT
+///////////
+// QWindowsRemovableDriveListener
+// Listen for the various WM_DEVICECHANGE message indicating drive addition/removal
+// requests and removals.
+///////////
+class QWindowsRemovableDriveListener : public QObject, public QAbstractNativeEventFilter
+{
+ Q_OBJECT
+public:
+ // Device UUids as declared in ioevent.h (GUID_IO_VOLUME_LOCK, ...)
+ enum VolumeUuid { UnknownUuid, UuidIoVolumeLock, UuidIoVolumeLockFailed,
+ UuidIoVolumeUnlock, UuidIoMediaRemoval };
+
+ struct RemovableDriveEntry {
+ HDEVNOTIFY devNotify;
+ wchar_t drive;
+ };
+
+ explicit QWindowsRemovableDriveListener(QObject *parent = nullptr);
+ ~QWindowsRemovableDriveListener();
+
+ // Call from QFileSystemWatcher::addPaths() to set up notifications on drives
+ void addPath(const QString &path);
+
+ bool nativeEventFilter(const QByteArray &, void *messageIn, long *) override;
+
+signals:
+ void driveAdded();
+ void driveRemoved(const QString &);
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+
+private:
+ static VolumeUuid volumeUuid(const UUID &needle);
+ void handleDbtCustomEvent(const MSG *msg);
+ void handleDbtDriveArrivalRemoval(const MSG *msg);
+
+ std::vector<RemovableDriveEntry> m_removableDrives;
+ quintptr m_lastMessageHash;
+};
+
+static inline QEventDispatcherWin32 *winEventDispatcher()
+{
+ return static_cast<QEventDispatcherWin32 *>(QCoreApplication::instance()->eventDispatcher());
+}
+
+QWindowsRemovableDriveListener::QWindowsRemovableDriveListener(QObject *parent)
+ : QObject(parent)
+ , m_lastMessageHash(0)
+{
+ winEventDispatcher()->installNativeEventFilter(this);
+}
+
+static void stopDeviceNotification(QWindowsRemovableDriveListener::RemovableDriveEntry &e)
+{
+ UnregisterDeviceNotification(e.devNotify);
+ e.devNotify = 0;
+}
+
+template <class Iterator> // Search sequence of RemovableDriveEntry for HDEVNOTIFY.
+static inline Iterator findByHDevNotify(Iterator i1, Iterator i2, HDEVNOTIFY hdevnotify)
+{
+ return std::find_if(i1, i2,
+ [hdevnotify] (const QWindowsRemovableDriveListener::RemovableDriveEntry &e) { return e.devNotify == hdevnotify; });
+}
+
+QWindowsRemovableDriveListener::~QWindowsRemovableDriveListener()
+{
+ std::for_each(m_removableDrives.begin(), m_removableDrives.end(), stopDeviceNotification);
+}
+
+static QString pathFromEntry(const QWindowsRemovableDriveListener::RemovableDriveEntry &re)
+{
+ QString path = QStringLiteral("A:/");
+ path[0] = QChar::fromLatin1(re.drive);
+ return path;
+}
+
+// Handle WM_DEVICECHANGE+DBT_CUSTOMEVENT, which is sent based on the registration
+// on the volume handle with QEventDispatcherWin32's message window in the class.
+// Capture the GUID_IO_VOLUME_LOCK indicating the drive is to be removed.
+QWindowsRemovableDriveListener::VolumeUuid QWindowsRemovableDriveListener::volumeUuid(const UUID &needle)
+{
+ static const struct VolumeUuidMapping // UUIDs from IoEvent.h (missing in MinGW)
+ {
+ VolumeUuid v;
+ UUID uuid;
+ } mapping[] = {
+ { UuidIoVolumeLock, // GUID_IO_VOLUME_LOCK
+ {0x50708874, 0xc9af, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeLockFailed, // GUID_IO_VOLUME_LOCK_FAILED
+ {0xae2eed10, 0x0ba8, 0x11d2, {0x8f, 0xfb, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeUnlock, // GUID_IO_VOLUME_UNLOCK
+ {0x9a8c3d68, 0xd0cb, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoMediaRemoval, // GUID_IO_MEDIA_REMOVAL
+ {0xd07433c1, 0xa98e, 0x11d2, {0x91, 0x7a, 0x0, 0xa0, 0xc9, 0x06, 0x8f, 0xf3}} }
+ };
+
+ static const VolumeUuidMapping *end = mapping + sizeof(mapping) / sizeof(mapping[0]);
+ const VolumeUuidMapping *m =
+ std::find_if(mapping, end, [&needle] (const VolumeUuidMapping &m) { return IsEqualGUID(m.uuid, needle); });
+ return m != end ? m->v : UnknownUuid;
+}
+
+inline void QWindowsRemovableDriveListener::handleDbtCustomEvent(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ if (broadcastHeader->dbch_devicetype != DBT_DEVTYP_HANDLE)
+ return;
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ broadcastHandle->dbch_hdevnotify);
+ if (it == m_removableDrives.cend())
+ return;
+ switch (volumeUuid(broadcastHandle->dbch_eventguid)) {
+ case UuidIoVolumeLock: // Received for removable USB media
+ emit driveLockForRemoval(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeLockFailed:
+ emit driveLockForRemovalFailed(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeUnlock:
+ break;
+ case UuidIoMediaRemoval: // Received for optical drives
+ break;
+ default:
+ break;
+ }
+}
+
+// Handle WM_DEVICECHANGE+DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE which are
+// sent to all top level windows and cannot be registered for (that is, their
+// triggering depends on top level windows being present)
+inline void QWindowsRemovableDriveListener::handleDbtDriveArrivalRemoval(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ switch (broadcastHeader->dbch_devicetype) {
+ case DBT_DEVTYP_HANDLE: // WM_DEVICECHANGE/DBT_DEVTYP_HANDLE is sent for our registered drives.
+ if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.begin(), m_removableDrives.end(),
+ broadcastHandle->dbch_hdevnotify);
+ // Emit for removable USB drives we were registered for.
+ if (it != m_removableDrives.end()) {
+ emit driveRemoved(pathFromEntry(*it));
+ stopDeviceNotification(*it);
+ m_removableDrives.erase(it);
+ }
+ }
+ break;
+ case DBT_DEVTYP_VOLUME: {
+ const DEV_BROADCAST_VOLUME *broadcastVolume = reinterpret_cast<const DEV_BROADCAST_VOLUME *>(broadcastHeader);
+ // WM_DEVICECHANGE/DBT_DEVTYP_VOLUME messages are sent to all toplevel windows. Compare a hash value to ensure
+ // it is handled only once.
+ const quintptr newHash = reinterpret_cast<quintptr>(broadcastVolume) + msg->wParam
+ + quintptr(broadcastVolume->dbcv_flags) + quintptr(broadcastVolume->dbcv_unitmask);
+ if (newHash == m_lastMessageHash)
+ return;
+ m_lastMessageHash = newHash;
+ // Check for DBTF_MEDIA (inserted/Removed Optical drives). Ignore for now.
+ if (broadcastVolume->dbcv_flags & DBTF_MEDIA)
+ return;
+ // Continue with plugged in USB media where dbcv_flags=0.
+ switch (msg->wParam) {
+ case DBT_DEVICEARRIVAL:
+ emit driveAdded();
+ break;
+ case DBT_DEVICEREMOVECOMPLETE: // handled by DBT_DEVTYP_HANDLE above
+ break;
+ }
+ }
+ break;
+ }
+}
+
+bool QWindowsRemovableDriveListener::nativeEventFilter(const QByteArray &, void *messageIn, long *)
+{
+ const MSG *msg = reinterpret_cast<const MSG *>(messageIn);
+ if (msg->message == WM_DEVICECHANGE) {
+ switch (msg->wParam) {
+ case DBT_CUSTOMEVENT:
+ handleDbtCustomEvent(msg);
+ break;
+ case DBT_DEVICEARRIVAL:
+ case DBT_DEVICEREMOVECOMPLETE:
+ handleDbtDriveArrivalRemoval(msg);
+ break;
+ }
+ }
+ return false;
+}
+
+// Set up listening for WM_DEVICECHANGE+DBT_CUSTOMEVENT for a removable drive path,
+void QWindowsRemovableDriveListener::addPath(const QString &p)
+{
+ const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':')
+ ? wchar_t(p.at(0).toUpper().unicode()) : L'\0';
+ if (!drive)
+ return;
+ // Already listening?
+ if (std::any_of(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ [drive](const RemovableDriveEntry &e) { return e.drive == drive; })) {
+ return;
+ }
+
+ wchar_t devicePath[8] = L"\\\\.\\A:\\";
+ devicePath[4] = drive;
+ RemovableDriveEntry re;
+ re.drive = drive;
+ if (GetDriveTypeW(devicePath + 4) != DRIVE_REMOVABLE)
+ return;
+ const HANDLE volumeHandle =
+ CreateFile(devicePath, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, // Volume requires BACKUP_SEMANTICS
+ 0);
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ qErrnoWarning("CreateFile %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ DEV_BROADCAST_HANDLE notify;
+ ZeroMemory(&notify, sizeof(notify));
+ notify.dbch_size = sizeof(notify);
+ notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ notify.dbch_handle = volumeHandle;
+ re.devNotify = RegisterDeviceNotification(winEventDispatcher()->internalHwnd(),
+ &notify, DEVICE_NOTIFY_WINDOW_HANDLE);
+ // Empirically found: The notifications also work when the handle is immediately
+ // closed. Do it here to avoid having to close/reopen in lock message handling.
+ CloseHandle(volumeHandle);
+ if (!re.devNotify) {
+ qErrnoWarning("RegisterDeviceNotification %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ m_removableDrives.push_back(re);
+}
+#endif // !Q_OS_WINRT
+
+///////////
+// QWindowsFileSystemWatcherEngine
+///////////
QWindowsFileSystemWatcherEngine::Handle::Handle()
: handle(INVALID_HANDLE_VALUE), flags(0u)
{
}
+QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent)
+ : QFileSystemWatcherEngine(parent)
+#ifndef Q_OS_WINRT
+ , m_driveListener(new QWindowsRemovableDriveListener(this))
+#endif
+{
+#ifndef Q_OS_WINRT
+ parent->setProperty("_q_driveListener",
+ QVariant::fromValue(static_cast<QObject *>(m_driveListener)));
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemoval,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemoval);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemovalFailed,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveRemoved,
+ this, &QWindowsFileSystemWatcherEngine::driveRemoved);
+#endif // !Q_OS_WINRT
+}
+
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
for (auto *thread : qAsConst(threads))
@@ -210,6 +484,13 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
}
}
+
+#ifndef Q_OS_WINRT
+ for (const QString &path : paths) {
+ if (!p.contains(path))
+ m_driveListener->addPath(path);
+ }
+#endif // !Q_OS_WINRT
return p;
}
@@ -439,4 +720,9 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
}
QT_END_NAMESPACE
+
+#ifndef Q_OS_WINRT
+# include "qfilesystemwatcher_win.moc"
+#endif
+
#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index e8f5c49dec..51c7082483 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -66,6 +66,7 @@
QT_BEGIN_NAMESPACE
class QWindowsFileSystemWatcherEngineThread;
+class QWindowsRemovableDriveListener;
// Even though QWindowsFileSystemWatcherEngine is derived of QThread
// via QFileSystemWatcher, it does not start a thread.
@@ -75,9 +76,7 @@ class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
public:
- inline QWindowsFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent)
- { }
+ explicit QWindowsFileSystemWatcherEngine(QObject *parent);
~QWindowsFileSystemWatcherEngine();
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
@@ -121,9 +120,17 @@ public:
|| lastModified != fileInfo.lastModified());
}
};
+
+signals:
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+ void driveRemoved(const QString &);
+
private:
QList<QWindowsFileSystemWatcherEngineThread *> threads;
-
+#ifndef Q_OS_WINRT
+ QWindowsRemovableDriveListener *m_driveListener;
+#endif
};
class QFileSystemWatcherPathKey : public QString
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 47108d057b..675b375b22 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -136,7 +136,18 @@ Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
typedef QHash<QString, QConfFile *> ConfFileHash;
typedef QCache<QString, QConfFile> ConfFileCache;
-typedef QHash<int, QString> PathHash;
+namespace {
+ struct Path
+ {
+ // Note: Defining constructors explicitly because of buggy C++11
+ // implementation in MSVC (uniform initialization).
+ Path() {}
+ Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
+ QString path;
+ bool userDefined; //!< true - user defined, overridden by setPath
+ };
+}
+typedef QHash<int, Path> PathHash;
typedef QVector<QConfFileCustomFormat> CustomFormatVector;
Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
@@ -228,7 +239,7 @@ void QConfFile::clearCache()
// QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
- : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true),
+ : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
pendingChanges(false), status(QSettings::NoError)
{
}
@@ -236,7 +247,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application),
- iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
+ iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{
}
@@ -948,7 +959,7 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
- if (confFiles[spec]) {
+ if (!confFiles.isEmpty()) {
if (format > QSettings::IniFormat) {
if (!readFunc)
setStatus(QSettings::AccessError);
@@ -1069,22 +1080,22 @@ static void initDefaultPaths(QMutexLocker *locker)
*/
#ifdef Q_OS_WIN
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
- windowsConfigPath(CSIDL_APPDATA) + QDir::separator());
+ Path(windowsConfigPath(CSIDL_APPDATA) + QDir::separator(), false));
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
- windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator());
+ Path(windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator(), false));
#else
const QString userPath = make_user_path();
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
#ifndef Q_OS_MAC
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
#endif
#endif // Q_OS_WIN
}
}
-static QString getPath(QSettings::Format format, QSettings::Scope scope)
+static Path getPath(QSettings::Format format, QSettings::Scope scope)
{
Q_ASSERT((int)QSettings::NativeFormat == 0);
Q_ASSERT((int)QSettings::IniFormat == 1);
@@ -1094,14 +1105,23 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- QString result = pathHash->value(pathHashKey(format, scope));
- if (!result.isEmpty())
+ Path result = pathHash->value(pathHashKey(format, scope));
+ if (!result.path.isEmpty())
return result;
// fall back on INI path
return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
}
+#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+// Note: Suitable only for autotests.
+void Q_AUTOTEST_EXPORT clearDefaultPaths()
+{
+ QMutexLocker locker(&settingsGlobalMutex);
+ pathHashFunc()->clear();
+}
+#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+
QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QSettings::Scope scope,
const QString &organization,
@@ -1109,7 +1129,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
: QSettingsPrivate(format, scope, organization, application),
nextPosition(0x40000000) // big positive number
{
- int i;
initFormat();
QString org = organization;
@@ -1122,22 +1141,43 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QString orgFile = org + extension;
if (scope == QSettings::UserScope) {
- QString userPath = getPath(format, QSettings::UserScope);
+ Path userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty())
- confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true));
- confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
}
- QString systemPath = getPath(format, QSettings::SystemScope);
- if (!application.isEmpty())
- confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false));
- confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false));
-
- for (i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i]) {
- spec = i;
- break;
+ Path systemPath = getPath(format, QSettings::SystemScope);
+#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+ // check if the systemPath wasn't overridden by QSettings::setPath()
+ if (!systemPath.userDefined) {
+ // Note: We can't use QStandardPaths::locateAll() as we need all the
+ // possible files (not just the existing ones) and there is no way
+ // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
+ QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
+ // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
+ if (!dirs.isEmpty())
+ dirs.takeFirst();
+ QStringList paths;
+ if (!application.isEmpty()) {
+ paths.reserve(dirs.size() * 2);
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + appFile);
+ } else {
+ paths.reserve(dirs.size());
}
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + orgFile);
+
+ // Note: No check for existence of files is done intentionaly.
+ for (const auto &path : qAsConst(paths))
+ confFiles.append(QConfFile::fromName(path, false));
+ } else
+#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+ {
+ if (!application.isEmpty())
+ confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
+ confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
initAccess();
@@ -1150,7 +1190,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{
initFormat();
- confFiles[0].reset(QConfFile::fromName(fileName, true));
+ confFiles.append(QConfFile::fromName(fileName, true));
initAccess();
}
@@ -1161,40 +1201,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i] && !confFiles[i]->ref.deref()) {
- if (confFiles[i]->size == 0) {
- delete confFiles[i].take();
+ for (auto conf_file : qAsConst(confFiles)) {
+ if (!conf_file->ref.deref()) {
+ if (conf_file->size == 0) {
+ delete conf_file;
} else {
if (usedHash)
- usedHash->remove(confFiles[i]->name);
+ usedHash->remove(conf_file->name);
if (unusedCache) {
QT_TRY {
// compute a better size?
- unusedCache->insert(confFiles[i]->name, confFiles[i].data(),
- 10 + (confFiles[i]->originalKeys.size() / 4));
- confFiles[i].take();
+ unusedCache->insert(conf_file->name, conf_file,
+ 10 + (conf_file->originalKeys.size() / 4));
} QT_CATCH(...) {
// out of memory. Do not cache the file.
- delete confFiles[i].take();
+ delete conf_file;
}
} else {
// unusedCache is gone - delete the entry to prevent a memory leak
- delete confFiles[i].take();
+ delete conf_file;
}
}
}
- // prevent the ScopedPointer to deref it again.
- confFiles[i].take();
}
}
void QConfFileSettingsPrivate::remove(const QString &key)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity);
QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
QMutexLocker locker(&confFile->mutex);
@@ -1218,10 +1257,12 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity, nextPosition++);
QMutexLocker locker(&confFile->mutex);
confFile->removedKeys.remove(theKey);
@@ -1234,29 +1275,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
ParsedSettingsMap::const_iterator j;
bool found = false;
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (!confFile->addedKeys.isEmpty()) {
- j = confFile->addedKeys.constFind(theKey);
- found = (j != confFile->addedKeys.constEnd());
- }
- if (!found) {
- ensureSectionParsed(confFile, theKey);
- j = confFile->originalKeys.constFind(theKey);
- found = (j != confFile->originalKeys.constEnd()
- && !confFile->removedKeys.contains(theKey));
- }
+ if (!confFile->addedKeys.isEmpty()) {
+ j = confFile->addedKeys.constFind(theKey);
+ found = (j != confFile->addedKeys.constEnd());
+ }
+ if (!found) {
+ ensureSectionParsed(confFile, theKey);
+ j = confFile->originalKeys.constFind(theKey);
+ found = (j != confFile->originalKeys.constEnd()
+ && !confFile->removedKeys.contains(theKey));
+ }
- if (found && value)
- *value = *j;
+ if (found && value)
+ *value = *j;
- if (found)
- return true;
- if (!fallbacks)
- break;
- }
+ if (found)
+ return true;
+ if (!fallbacks)
+ break;
}
return false;
}
@@ -1269,34 +1308,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
QSettingsKey thePrefix(prefix, caseSensitivity);
int startPos = prefix.size();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (thePrefix.isEmpty()) {
- ensureAllSectionsParsed(confFile);
- } else {
- ensureSectionParsed(confFile, thePrefix);
- }
-
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->originalKeys)->lowerBound( thePrefix);
- while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
- if (!confFile->removedKeys.contains(j.key()))
- processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ if (thePrefix.isEmpty())
+ ensureAllSectionsParsed(confFile);
+ else
+ ensureSectionParsed(confFile, thePrefix);
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->originalKeys)->lowerBound( thePrefix);
+ while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(j.key()))
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ ++j;
+ }
- if (!fallbacks)
- break;
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->addedKeys)->lowerBound(thePrefix);
+ while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
+ ++j;
}
+
+ if (!fallbacks)
+ break;
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()),
@@ -1306,10 +1342,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear()
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QMutexLocker locker(&confFile->mutex);
ensureAllSectionsParsed(confFile);
confFile->addedKeys.clear();
@@ -1321,12 +1359,9 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it
- for (int i = 0; i < NumConfFiles; ++i) {
- QConfFile *confFile = confFiles[i].data();
- if (confFile) {
- QMutexLocker locker(&confFile->mutex);
- syncConfFile(i);
- }
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
+ syncConfFile(confFile);
}
}
@@ -1337,10 +1372,11 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return QString();
- return confFile->name;
+
+ // Note: First config file is always the most specific.
+ return confFiles.at(0)->name;
}
bool QConfFileSettingsPrivate::isWritable() const
@@ -1348,16 +1384,14 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc)
return false;
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return false;
- return confFile->isWritable();
+ return confFiles.at(0)->isWritable();
}
-void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
+void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
- QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
/*
@@ -2187,9 +2221,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
\li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
- \li \c{/etc/xdg/MySoft/Star Runner.conf}
- \li \c{/etc/xdg/MySoft.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On \macos versions 10.2 and 10.3, these files are used by
default:
@@ -2224,9 +2259,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
\li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
- \li \c{/etc/xdg/MySoft/Star Runner.ini}
- \li \c{/etc/xdg/MySoft.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On Windows, the following files are used:
@@ -3378,7 +3414,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path)
PathHash *pathHash = pathHashFunc();
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- pathHash->insert(pathHashKey(format, scope), path + QDir::separator());
+ pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
}
/*!
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index b79abfb874..dcaefd1613 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -422,20 +422,15 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
javaPackageName.prepend(QLatin1String("com."));
suiteId = javaPackageName;
- if (scope == QSettings::SystemScope)
- spec |= F_System;
-
- if (application.isEmpty()) {
- spec |= F_Organization;
- } else {
+ if (!application.isEmpty()) {
javaPackageName += QLatin1Char('.');
javaPackageName += application;
applicationId = javaPackageName;
}
numDomains = 0;
- for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) {
- for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) {
+ for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) {
+ for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) {
SearchDomain &domain = domains[numDomains++];
domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
if (j == 0)
@@ -576,7 +571,7 @@ bool QMacSettingsPrivate::isWritable() const
QString QMacSettingsPrivate::fileName() const
{
QString result;
- if ((spec & F_System) == 0)
+ if (scope == QSettings::UserScope)
result = QDir::homePath();
result += QLatin1String("/Library/Preferences/");
result += QString::fromCFString(domains[0].applicationOrSuiteId);
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index e6d3413bab..639605d8c4 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -236,19 +236,6 @@ public:
QTextCodec *codec);
static QStringList splitArgs(const QString &s, int idx);
- /*
- The numeric values of these enums define their search order. For example,
- F_User | F_Organization is searched before F_System | F_Application,
- because their values are respectively 1 and 2.
- */
- enum {
- F_Application = 0x0,
- F_Organization = 0x1,
- F_User = 0x0,
- F_System = 0x2,
- NumConfFiles = 4
- };
-
QSettings::Format format;
QSettings::Scope scope;
QString organizationName;
@@ -258,7 +245,6 @@ public:
protected:
QStack<QSettingsGroup> groupStack;
QString groupPrefix;
- int spec;
bool fallbacks;
bool pendingChanges;
mutable QSettings::Status status;
@@ -293,7 +279,7 @@ public:
private:
void initFormat();
void initAccess();
- void syncConfFile(int confFileNo);
+ void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
@@ -302,7 +288,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
- QScopedSharedPointer<QConfFile> confFiles[NumConfFiles];
+ QVector<QConfFile *> confFiles;
QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc;
QString extension;
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 1c10548cbc..edcae16776 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -138,21 +138,6 @@ static void mergeKeySets(NameSet *dest, const QStringList &src)
** Wrappers for the insane windows registry API
*/
-static QString errorCodeToString(DWORD errorCode)
-{
- wchar_t *data = 0;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
- QString result = QString::fromWCharArray(data);
-
- if (data != 0)
- LocalFree(data);
-
- if (result.endsWith(QLatin1Char('\n')))
- result.truncate(result.length() - 1);
-
- return result;
-}
-
// Open a key with the specified "perms".
// "access" is to explicitly use the 32- or 64-bit branch.
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
@@ -184,7 +169,7 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub
return resultHandle;
//qWarning("QSettings: Failed to create subkey \"%s\": %s",
- // rSubKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ // qPrintable(rSubKey), qPrintable(qt_error_string(int(res))));
return 0;
}
@@ -224,7 +209,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
&numKeys, &maxKeySize, 0, 0, 0);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegQueryInfoKey() failed: %s", qPrintable(qt_error_string(int(res))));
return result;
}
@@ -258,7 +243,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegEnumValue failed: %s", qPrintable(qt_error_string(int(res))));
continue;
}
if (item.isEmpty())
@@ -313,7 +298,7 @@ static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0)
LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
return;
}
}
@@ -613,7 +598,7 @@ QWinSettingsPrivate::~QWinSettingsPrivate()
DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: Failed to delete key \"%s\": %s",
- regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(regList.at(0).key()), qPrintable(qt_error_string(int(res))));
}
}
@@ -652,7 +637,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
}
}
} else {
@@ -660,7 +645,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
}
}
RegCloseKey(handle);
@@ -758,7 +743,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
deleteWriteHandleOnExit = false;
} else {
qWarning("QSettings: failed to set subkey \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
setStatus(QSettings::AccessError);
}
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 3773b72606..9885da1af9 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -260,7 +260,7 @@ QByteArray QStorageInfo::fileSystemType() const
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
- \sa rootPath()
+ \sa rootPath(), subvolume()
*/
QByteArray QStorageInfo::device() const
{
@@ -268,6 +268,26 @@ QByteArray QStorageInfo::device() const
}
/*!
+ \since 5.8
+ Returns the subvolume name for this volume.
+
+ Some filesystem types allow multiple subvolumes inside one device, which
+ may be mounted in different paths. If the subvolume could be detected, it
+ is returned here. The format of the subvolume name is specific to each
+ filesystem type.
+
+ If this volume was not mounted from a subvolume of a larger filesystem or
+ if the subvolume could not be detected, this function returns an empty byte
+ array.
+
+ \sa device()
+*/
+QByteArray QStorageInfo::subvolume() const
+{
+ return d->subvolume;
+}
+
+/*!
Returns the human-readable name of a filesystem, usually called \c label.
Not all filesystems support this feature. In this case, the value returned by
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index 8941c11a16..e2d9747ceb 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -71,6 +71,7 @@ public:
QString rootPath() const;
QByteArray device() const;
+ QByteArray subvolume() const;
QByteArray fileSystemType() const;
QString name() const;
QString displayName() const;
@@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{
if (first.d == second.d)
return true;
- return first.device() == second.device();
+ return first.device() == second.device() && first.rootPath() == second.rootPath();
}
inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index a14fa8480a..ec5bb785e3 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -85,6 +85,7 @@ protected:
public:
QString rootPath;
QByteArray device;
+ QByteArray subvolume;
QByteArray fileSystemType;
QString name;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index ae5c42ffd1..fcc7b8ca50 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -120,6 +120,7 @@ public:
inline QString rootPath() const;
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
+ inline QByteArray options() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@@ -133,6 +134,7 @@ private:
QByteArray m_rootPath;
QByteArray m_fileSystemType;
QByteArray m_device;
+ QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
FILE *fp;
mntent mnt;
@@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(stat_buf[currentIndex].f_mntfromname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#elif defined(Q_OS_SOLARIS)
static const char pathMounted[] = "/etc/mnttab";
@@ -301,6 +308,7 @@ inline bool QStorageIterator::next()
m_device = data.at(0);
m_rootPath = data.at(1);
m_fileSystemType = data.at(2);
+ m_options = data.at(3);
return true;
}
@@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return m_options;
+}
+
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
static const char pathMounted[] = "/etc/mtab";
@@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_fsname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray(mnt.mnt_opts);
+}
+
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -455,8 +478,35 @@ inline QByteArray QStorageIterator::device() const
return QByteArray();
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#endif
+static QByteArray extractSubvolume(const QStorageIterator &it)
+{
+#ifdef Q_OS_LINUX
+ if (it.fileSystemType() == "btrfs") {
+ const QByteArrayList opts = it.options().split(',');
+ QByteArray id;
+ for (const QByteArray &opt : opts) {
+ static const char subvol[] = "subvol=";
+ static const char subvolid[] = "subvolid=";
+ if (opt.startsWith(subvol))
+ return std::move(opt).mid(strlen(subvol));
+ if (opt.startsWith(subvolid))
+ id = std::move(opt).mid(strlen(subvolid));
+ }
+
+ // if we didn't find the subvolume name, return the subvolume ID
+ return id;
+ }
+#endif
+ return QByteArray();
+}
+
void QStorageInfoPrivate::initRootPath()
{
rootPath = QFileInfo(rootPath).canonicalFilePath();
@@ -483,6 +533,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
+ subvolume = extractSubvolume(it);
}
}
}
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index 6e50a8513e..b2bf9fce97 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -305,6 +305,33 @@ QString QTemporaryDir::path() const
}
/*!
+ \since 5.9
+
+ Returns the path name of a file in the temporary directory.
+ Does \e not check if the file actually exists in the directory.
+ Redundant multiple separators or "." and ".." directories in
+ \a fileName are not removed (see QDir::cleanPath()). Absolute
+ paths are not allowed.
+*/
+QString QTemporaryDir::filePath(const QString &fileName) const
+{
+ if (QDir::isAbsolutePath(fileName)) {
+ qWarning("QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName));
+ return QString();
+ }
+
+ if (!d_ptr->success)
+ return QString();
+
+ QString ret = d_ptr->pathOrError;
+ if (!fileName.isEmpty()) {
+ ret += QLatin1Char('/');
+ ret += fileName;
+ }
+ return ret;
+}
+
+/*!
Returns \c true if the QTemporaryDir is in auto remove
mode. Auto-remove mode will automatically delete the directory from
disk upon destruction. This makes it very easy to create your
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 2e70d34ae4..3f6b70a2eb 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -65,6 +65,7 @@ public:
bool remove();
QString path() const;
+ QString filePath(const QString &fileName) const;
private:
QScopedPointer<QTemporaryDirPrivate> d_ptr;
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 4fdb1505ff..9b565bff9d 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2547,6 +2547,7 @@ QTextStream &QTextStream::operator<<(double f)
}
uint flags = 0;
+ const QLocale::NumberOptions numberOptions = locale().numberOptions();
if (numberFlags() & ShowBase)
flags |= QLocaleData::ShowBase;
if (numberFlags() & ForceSign)
@@ -2555,12 +2556,18 @@ QTextStream &QTextStream::operator<<(double f)
flags |= QLocaleData::UppercaseBase;
if (numberFlags() & UppercaseDigits)
flags |= QLocaleData::CapitalEorX;
- if (numberFlags() & ForcePoint)
- flags |= QLocaleData::Alternate;
- if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator))
+ if (numberFlags() & ForcePoint) {
+ flags |= QLocaleData::ForcePoint;
+
+ // Only for backwards compatibility
+ flags |= QLocaleData::AddTrailingZeroes | QLocaleData::ShowBase;
+ }
+ if (locale() != QLocale::c() && !(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale().numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
const QLocaleData *dd = d->locale.d->m_data;
QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags);
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index d7e8d4847a..231afb991c 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -47,14 +47,8 @@
#include <qdebug.h>
-#if defined(Q_OS_IOS)
-#import <UIKit/UIKit.h>
-#endif
-
QT_BEGIN_NAMESPACE
-typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response);
-
// -------------------------------------------------------------------------
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
@@ -87,54 +81,6 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
// -------------------------------------------------------------------------
-QAppleOperatingSystemVersion qt_apple_os_version()
-{
- QAppleOperatingSystemVersion v = {0, 0, 0};
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS)
- if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) {
- NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
- v.major = osv.majorVersion;
- v.minor = osv.minorVersion;
- v.patch = osv.patchVersion;
- return v;
- }
-#endif
- // Use temporary variables so we can return 0.0.0 (unknown version)
- // in case of an error partway through determining the OS version
- qint32 major = 0, minor = 0, patch = 0;
-#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0)
-#if defined(Q_OS_IOS)
- @autoreleasepool {
- NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."];
- major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0;
- minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0;
- patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0;
- }
-#elif defined(Q_OS_OSX)
- static GestaltFunction pGestalt = 0;
- if (!pGestalt) {
- CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices"));
- pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b,
- CFSTR("Gestalt")));
- }
- if (!pGestalt)
- return v;
- if (pGestalt('sys1', &major) != 0)
- return v;
- if (pGestalt('sys2', &minor) != 0)
- return v;
- if (pGestalt('sys3', &patch) != 0)
- return v;
-#endif
-#endif
- v.major = major;
- v.minor = minor;
- v.patch = patch;
- return v;
-}
-
-// -------------------------------------------------------------------------
-
QMacAutoReleasePool::QMacAutoReleasePool()
: pool([[NSAutoreleasePool alloc] init])
{
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index cb709f9d4b..d0edef33a2 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -131,12 +131,6 @@ private:
QString string;
};
-typedef struct {
- int major, minor, patch;
-} QAppleOperatingSystemVersion;
-
-QAppleOperatingSystemVersion qt_apple_os_version();
-
#ifdef Q_OS_OSX
Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 1a0efae2dc..75ac104155 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -42,6 +42,7 @@
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
+#include "qoperatingsystemversion.h"
#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.h"
@@ -236,7 +237,7 @@ static inline UINT inputTimerMask()
// QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
// QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
#if WINVER > 0x0601
- if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
result &= ~(QS_TOUCH | QS_POINTER);
#endif // WINVER > 0x0601
return result;
@@ -1058,4 +1059,11 @@ void QEventDispatcherWin32::sendPostedEvents()
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
}
+HWND QEventDispatcherWin32::internalHwnd()
+{
+ Q_D(QEventDispatcherWin32);
+ createInternalHwnd();
+ return d->internalHwnd;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index 773315c04f..227fcf89ff 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -106,6 +106,8 @@ public:
bool event(QEvent *e);
+ HWND internalHwnd();
+
protected:
QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0);
virtual void sendPostedEvents();
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 63b02d2c0c..4ae886150f 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -754,30 +754,6 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
\sa {Object Trees & Ownership}
*/
-/*!
- \relates QObject
-
- Returns a pointer to the object named \a name that inherits \a
- type and with a given \a parent.
-
- Returns 0 if there is no such child.
-
- \snippet code/src_corelib_kernel_qobject.cpp 0
-*/
-
-void *qt_find_obj_child(QObject *parent, const char *type, const QString &name)
-{
- QObjectList list = parent->children();
- if (list.size() == 0) return 0;
- for (int i = 0; i < list.size(); ++i) {
- QObject *obj = list.at(i);
- if (name == obj->objectName() && obj->inherits(type))
- return obj;
- }
- return 0;
-}
-
-
/*****************************************************************************
QObject member functions
*****************************************************************************/
@@ -3941,9 +3917,8 @@ QList<QByteArray> QObject::dynamicPropertyNames() const
QObject debugging output routines.
*****************************************************************************/
-static void dumpRecursive(int level, QObject *object)
+static void dumpRecursive(int level, const QObject *object)
{
-#if defined(QT_DEBUG)
if (object) {
QByteArray buf;
buf.fill(' ', level / 2 * 8);
@@ -3972,45 +3947,65 @@ static void dumpRecursive(int level, QObject *object)
dumpRecursive(level+1, children.at(i));
}
}
-#else
- Q_UNUSED(level)
- Q_UNUSED(object)
-#endif
}
/*!
- Dumps a tree of children to the debug output.
+ \overload
+ \obsolete
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
+ Dumps a tree of children to the debug output.
\sa dumpObjectInfo()
*/
void QObject::dumpObjectTree()
{
+ const_cast<const QObject *>(this)->dumpObjectTree();
+}
+
+/*!
+ Dumps a tree of children to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectInfo()
+*/
+
+void QObject::dumpObjectTree() const
+{
dumpRecursive(0, this);
}
/*!
+ \overload
+ \obsolete
+
Dumps information about signal connections, etc. for this object
to the debug output.
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
-
\sa dumpObjectTree()
*/
void QObject::dumpObjectInfo()
{
-#if defined(QT_DEBUG)
+ const_cast<const QObject *>(this)->dumpObjectInfo();
+}
+
+/*!
+ Dumps information about signal connections, etc. for this object
+ to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectTree()
+*/
+
+void QObject::dumpObjectInfo() const
+{
qDebug("OBJECT %s::%s", metaObject()->className(),
objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
- Q_D(QObject);
+ Q_D(const QObject);
QMutexLocker locker(signalSlotLock(this));
// first, look for connections where this object is the sender
@@ -4066,7 +4061,6 @@ void QObject::dumpObjectInfo()
} else {
qDebug(" <None>");
}
-#endif
}
#ifndef QT_NO_USERDATA
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 69b70ad6ec..25acdefeaf 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -375,8 +375,12 @@ public:
#endif //Q_QDOC
- void dumpObjectTree();
- void dumpObjectInfo();
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ void dumpObjectTree(); // ### Qt 6: remove
+ void dumpObjectInfo(); // ### Qt 6: remove
+#endif
+ void dumpObjectTree() const;
+ void dumpObjectInfo() const;
#ifndef QT_NO_PROPERTIES
bool setProperty(const char *name, const QVariant &value);
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 55af7256be..a04536b18b 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -63,6 +63,29 @@ QT_WARNING_POP
static const QArrayData &qt_array_empty = qt_array[0];
static const QArrayData &qt_array_unsharable_empty = qt_array[1];
+static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
+ uint options)
+{
+ // Calculate the byte size
+ // allocSize = objectSize * capacity + headerSize, but checked for overflow
+ // plus padded to grow in size
+ if (options & QArrayData::Grow) {
+ auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
+ capacity = r.elementCount;
+ return r.size;
+ } else {
+ return qCalculateBlockSize(capacity, objectSize, headerSize);
+ }
+}
+
+static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options)
+{
+ header = static_cast<QArrayData *>(::realloc(header, allocSize));
+ if (header)
+ header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ return header;
+}
+
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options) Q_DECL_NOTHROW
{
@@ -91,18 +114,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
if (headerSize > size_t(MaxAllocSize))
return 0;
- // Calculate the byte size
- // allocSize = objectSize * capacity + headerSize, but checked for overflow
- // plus padded to grow in size
- size_t allocSize;
- if (options & Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- allocSize = r.size;
- } else {
- allocSize = qCalculateBlockSize(capacity, objectSize, headerSize);
- }
-
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
@@ -122,6 +134,21 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
return header;
}
+QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
+ AllocationOptions options) Q_DECL_NOTHROW
+{
+ Q_ASSERT(data);
+ Q_ASSERT(data->isMutable());
+ Q_ASSERT(!data->ref.isShared());
+
+ size_t headerSize = sizeof(QArrayData);
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
+ QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
+ if (header)
+ header->alloc = capacity;
+ return header;
+}
+
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW
{
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 5a369baf08..bc20932cca 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -115,6 +115,9 @@ struct Q_CORE_EXPORT QArrayData
static QArrayData *allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options = Default)
Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+ static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
+ size_t newCapacity, AllocationOptions newOptions = Default)
+ Q_DECL_NOTHROW Q_REQUIRED_RESULT;
static void deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW;
@@ -222,6 +225,14 @@ struct QTypedArrayData
Q_ALIGNOF(AlignmentDummy), capacity, options));
}
+ static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
+ AllocationOptions options = Default)
+ {
+ Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
+ capacity, options));
+ }
+
static void deallocate(QArrayData *data)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 9298472305..7d9c5dc325 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -663,6 +663,20 @@ QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel)
*/
#ifndef QT_NO_COMPRESS
+namespace {
+struct QByteArrayDataDeleter
+{
+ static inline void cleanup(QTypedArrayData<char> *d)
+ { if (d) QTypedArrayData<char>::deallocate(d); }
+};
+}
+
+static QByteArray invalidCompressedData()
+{
+ qWarning("qUncompress: Input data is corrupted");
+ return QByteArray();
+}
+
QByteArray qUncompress(const uchar* data, int nbytes)
{
if (!data) {
@@ -677,53 +691,29 @@ QByteArray qUncompress(const uchar* data, int nbytes)
ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) |
(data[2] << 8) | (data[3] ));
ulong len = qMax(expectedSize, 1ul);
- QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d;
+ const ulong maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ }
+ QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1));
+ if (Q_UNLIKELY(d.data() == nullptr))
+ return invalidCompressedData();
+
+ d->size = expectedSize;
forever {
ulong alloc = len;
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(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");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- d->offset = sizeof(QByteArrayData);
- d->size = 0; // Shut up valgrind "uninitialized variable" warning
int res = ::uncompress((uchar*)d->data(), &len,
data+4, nbytes-4);
switch (res) {
case Z_OK:
- if (len != alloc) {
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(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");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- }
- d->ref.initializeOwned();
+ Q_ASSERT(len <= alloc);
+ Q_UNUSED(alloc);
d->size = len;
- d->alloc = uint(len) + 1u;
- d->capacityReserved = false;
- d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
-
{
QByteArrayDataPtr dataPtr = { d.take() };
return QByteArray(dataPtr);
@@ -735,6 +725,17 @@ QByteArray qUncompress(const uchar* data, int nbytes)
case Z_BUF_ERROR:
len *= 2;
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ } else {
+ // grow the block
+ QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1);
+ if (Q_UNLIKELY(p == nullptr))
+ return invalidCompressedData();
+ d.take(); // don't free
+ d.reset(p);
+ }
continue;
case Z_DATA_ERROR:
@@ -1707,19 +1708,8 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options)
Data::deallocate(d);
d = x;
} else {
- size_t blockSize;
- if (options & Data::Grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
-
- Data *x = static_cast<Data *>(::realloc(d, blockSize));
+ Data *x = Data::reallocateUnaligned(d, alloc, options);
Q_CHECK_PTR(x);
- x->alloc = alloc;
- x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0;
d = x;
}
}
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index f784aa13fc..896b4a3840 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -929,7 +929,7 @@ QString QDate::toString(Qt::DateFormat format) const
*/
QString QDate::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -1333,6 +1333,7 @@ QDate QDate::fromString(const QString &string, const QString &format)
QDate date;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, &date, 0);
#else
@@ -1676,7 +1677,7 @@ QString QTime::toString(Qt::DateFormat format) const
*/
QString QTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
/*!
@@ -2030,6 +2031,7 @@ QTime QTime::fromString(const QString &string, const QString &format)
QTime time;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, 0, &time);
#else
@@ -3896,7 +3898,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
*/
QString QDateTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -4950,6 +4952,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time);
#else
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 847fc2d55e..ca04c2bd44 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -2018,6 +2018,8 @@ QString QLocale::toString(double i, char f, int prec) const
flags |= QLocaleData::ThousandsGroup;
if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
return d->m_data->doubleToString(i, prec, form, -1, flags);
}
@@ -2779,7 +2781,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
reinterpret_cast<ushort *>(digits.data())[i] += z;
}
- bool always_show_decpt = (flags & Alternate || flags & ForcePoint);
+ bool always_show_decpt = (flags & ForcePoint);
switch (form) {
case DFExponent: {
num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
@@ -2794,7 +2796,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
break;
}
case DFSignificantDigits: {
- PrecisionMode mode = (flags & Alternate) ?
+ PrecisionMode mode = (flags & AddTrailingZeroes) ?
PMSignificantDigits : PMChopTrailingZeros;
int cutoff = precision < 0 ? 6 : precision;
@@ -2899,7 +2901,7 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -2920,10 +2922,10 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
--num_pad_chars;
// leave space for optional '0x' in hex form
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && (flags & ShowBase))
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
@@ -2933,9 +2935,9 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
if (flags & CapitalEorX)
num_str = num_str.toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- if (base == 2 && (flags & Alternate || flags & ShowBase))
+ if (base == 2 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -2984,7 +2986,7 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
if (zeroPadding > 0)
num_str.prepend(QString(zeroPadding, resultZero));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -2999,10 +3001,10 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
int num_pad_chars = width - num_str.length();
// leave space for optional '0x' in hex form
- if (base == 16 && flags & Alternate)
+ if (base == 16 && flags & ShowBase)
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && flags & Alternate)
+ else if (base == 2 && flags & ShowBase)
num_pad_chars -= 2;
if (num_pad_chars > 0)
@@ -3012,9 +3014,9 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
if (flags & CapitalEorX)
num_str = num_str.toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3075,25 +3077,37 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
out = in.toLatin1();
else
break;
+ } else if (out == '.') {
+ // Fail if more than one decimal point or point after e
+ if (decpt_idx != -1 || exponent_idx != -1)
+ return false;
+ decpt_idx = idx;
+ } else if (out == 'e' || out == 'E') {
+ exponent_idx = idx;
}
if (number_options & QLocale::RejectLeadingZeroInExponent) {
- if (out == 'e' || out == 'E') {
- exponent_idx = idx;
- } else if (exponent_idx != -1) {
- if (out >= '1' && out <= '9')
- exponent_idx = -1; // leading digit is not 0, forget exponent_idx
- else if (out == '0' && idx < l - 1)
+ if (exponent_idx != -1 && out == '0' && idx < l - 1) {
+ // After the exponent there can only be '+', '-' or digits.
+ // If we find a '0' directly after some non-digit, then that is a leading zero.
+ if (result->last() < '0' || result->last() > '9')
return false;
}
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // If we've seen a decimal point and the last character after the exponent is 0, then
+ // that is a trailing zero.
+ if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
+ return false;
+ }
+
if (!(number_options & QLocale::RejectGroupSeparator)) {
if (start_of_digits_idx == -1 && out >= '0' && out <= '9') {
start_of_digits_idx = idx;
} else if (out == ',') {
- // Don't allow group chars after the decimal point
- if (decpt_idx != -1)
+ // Don't allow group chars after the decimal point or exponent
+ if (decpt_idx != -1 || exponent_idx != -1)
return false;
// check distance from the last separator or from the beginning of the digits
@@ -3110,12 +3124,6 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
++idx;
continue;
} else if (out == '.' || out == 'e' || out == 'E') {
- // Fail if more than one decimal point
- if (out == '.' && decpt_idx != -1)
- return false;
- if (decpt_idx == -1)
- decpt_idx = idx;
-
// check distance from the last separator
// ### FIXME: Some locales allow other groupings! See https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
@@ -3141,6 +3149,12 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
return false;
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // In decimal form, the last character can be a trailing zero if we've seen a decpt.
+ if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
+ return false;
+ }
+
result->append('\0');
return idx == l;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 657fce9fa1..bd89e48234 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -897,7 +897,9 @@ public:
OmitGroupSeparator = 0x01,
RejectGroupSeparator = 0x02,
OmitLeadingZeroInExponent = 0x04,
- RejectLeadingZeroInExponent = 0x08
+ RejectLeadingZeroInExponent = 0x08,
+ IncludeTrailingZeroesAfterDot = 0x10,
+ RejectTrailingZeroesAfterDot = 0x20
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc
index 8c5711fb5e..d419172356 100644
--- a/src/corelib/tools/qlocale.qdoc
+++ b/src/corelib/tools/qlocale.qdoc
@@ -949,7 +949,8 @@
setNumberOptions().
\value DefaultNumberOptions This option represents the default behavior, with
- group separators and with one leading zero in single digit exponents.
+ group separators, with one leading zero in single digit exponents, and
+ without trailing zeroes after the decimal dot.
\value OmitGroupSeparator If this option is set, the number-to-string functions
will not insert group separators in their return values. The default
is to insert group separators.
@@ -964,6 +965,14 @@
functions will fail if they encounter an exponent padded with zeroes when
parsing a floating point number in scientific notation. The default is to
accept such padding.
+ \value IncludeTrailingZeroesAfterDot If this option is set, the number-to-string
+ functions will pad numbers with zeroes to the requested precision in "g"
+ or "most concise" mode, even if the number of significant digits is lower
+ than the requested precision. The default is to omit trailing zeroes.
+ \value RejectTrailingZeroesAfterDot If this option is set, the string-to-number
+ functions will fail if they encounter trailing zeroes after the decimal
+ dot when parsing a number in scientific or decimal representation. The
+ default is to accept trailing zeroes.
\sa setNumberOptions(), numberOptions()
*/
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index c83c9d3333..74d8e5f381 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -193,7 +193,7 @@ public:
enum Flags {
NoFlags = 0,
- Alternate = 0x01,
+ AddTrailingZeroes = 0x01,
ZeroPadded = 0x02,
LeftAdjusted = 0x04,
BlankBeforePositive = 0x08,
@@ -204,7 +204,7 @@ public:
ShowBase = 0x80,
UppercaseBase = 0x100,
ZeroPadExponent = 0x200,
- ForcePoint = Alternate
+ ForcePoint = 0x400
};
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index cb11e72435..8fa378e935 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -132,7 +132,6 @@ char *QRingBuffer::reserve(qint64 bytes)
char *writePtr = buffers.last().data() + tail;
bufferSize += bytes;
- Q_ASSERT(bytes < MaxByteArraySize);
tail += int(bytes);
return writePtr;
}
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 8520bb5740..94d2b5f65e 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -491,6 +491,30 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l)
return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ if (l >= 8) {
+ const QChar *end = a + l;
+ const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ while (a + 8 < end) {
+ uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
+ uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
+
+ uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
+ if (r) {
+ // found a different QChar
+ uint idx = qCountTrailingZeroBits(r);
+ return (int)a[idx].unicode() - (int)b[idx].unicode();
+ }
+ a += 8;
+ b += 8;
+ }
+ l &= 7;
+ }
+ const auto &lambda = [=](int i) -> int {
+ return a[i].unicode() - b[i].unicode();
+ };
+ return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
+#endif // __ARM_NEON__
if (!l)
return 0;
@@ -1767,17 +1791,11 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow)
{
- size_t blockSize;
- if (grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
+ auto allocOptions = d->detachFlags();
+ if (grow)
+ allocOptions |= QArrayData::Grow;
if (d->ref.isShared() || IS_RAW_DATA(d)) {
- Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0);
Data *x = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -1787,11 +1805,9 @@ void QString::reallocData(uint alloc, bool grow)
Data::deallocate(d);
d = x;
} else {
- Data *p = static_cast<Data *>(::realloc(d, blockSize));
+ Data *p = Data::reallocateUnaligned(d, alloc, allocOptions);
Q_CHECK_PTR(p);
d = p;
- d->alloc = alloc;
- d->offset = sizeof(QStringData);
}
}
@@ -4450,11 +4466,11 @@ bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
\sa startsWith()
*/
-bool QString::endsWith(const QString& s, Qt::CaseSensitivity cs) const
+bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
return qt_ends_with(isNull() ? 0 : unicode(), size(),
s.isNull() ? 0 : s.unicode(), s.size(), cs);
- }
+}
/*!
\since 4.8
@@ -5965,7 +5981,10 @@ static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW
uint flags = QLocaleData::ZeroPadExponent;
while (true) {
switch (*c) {
- case '#': flags |= QLocaleData::Alternate; break;
+ case '#':
+ flags |= QLocaleData::ShowBase | QLocaleData::AddTrailingZeroes
+ | QLocaleData::ForcePoint;
+ break;
case '0': flags |= QLocaleData::ZeroPadded; break;
case '-': flags |= QLocaleData::LeftAdjusted; break;
case ' ': flags |= QLocaleData::BlankBeforePositive; break;
@@ -6223,7 +6242,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case 'p': {
void *arg = va_arg(ap, void*);
const quint64 i = reinterpret_cast<quintptr>(arg);
- flags |= QLocaleData::Alternate;
+ flags |= QLocaleData::ShowBase;
subst = QLocaleData::c()->unsLongLongToString(i, precision, 16, width, flags);
++c;
break;
@@ -7798,10 +7817,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
if (d.locale_occurrences > 0) {
QLocale locale;
- if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
+ const QLocale::NumberOptions numberOptions = locale.numberOptions();
+ if (!(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags);
}
@@ -8009,33 +8031,12 @@ bool QString::isSimpleText() const
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
+
+ \sa QStringRef::isRightToLeft()
*/
bool QString::isRightToLeft() const
{
- const ushort *p = d->data();
- const ushort * const end = p + d->size;
- while (p < end) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
- ushort low = p[1];
- if (QChar::isLowSurrogate(low)) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++p;
- }
- }
- switch (QChar::direction(ucs4))
- {
- case QChar::DirL:
- return false;
- case QChar::DirR:
- case QChar::DirAL:
- return true;
- default:
- break;
- }
- ++p;
- }
- return false;
+ return QStringRef(this).isRightToLeft();
}
/*! \fn QChar *QString::data()
@@ -8991,7 +8992,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in
the string.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9000,7 +9001,16 @@ ownership of it, no memory is freed when instances are destroyed.
Same as begin().
- \sa begin(), cend(), rbegin(), rend()
+ \sa begin(), constBegin(), cend(), constEnd(), rbegin(), rend()
+*/
+
+/*!
+ \fn QStringRef::const_iterator QStringRef::constBegin() const
+ \since 5.9
+
+ Same as begin().
+
+ \sa begin(), cend(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9010,7 +9020,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*! \fn QStringRef::const_iterator QStringRef::cend() const
@@ -9018,7 +9028,15 @@ ownership of it, no memory is freed when instances are destroyed.
Same as end().
- \sa end(), cbegin(), rbegin(), rend()
+ \sa end(), constEnd(), cbegin(), constBegin(), rbegin(), rend()
+*/
+
+/*! \fn QStringRef::const_iterator QStringRef::constEnd() const
+ \since 5.9
+
+ Same as end().
+
+ \sa end(), cend(), cbegin(), constBegin(), rbegin(), rend()
*/
/*!
@@ -9942,6 +9960,41 @@ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const
}
/*!
+ \since 5.9
+
+ Returns \c true if the string is read right to left.
+
+ \sa QString::isRightToLeft()
+*/
+bool QStringRef::isRightToLeft() const
+{
+ const ushort *p = reinterpret_cast<const ushort*>(unicode());
+ const ushort * const end = p + size();
+ while (p < end) {
+ uint ucs4 = *p;
+ if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
+ ushort low = p[1];
+ if (QChar::isLowSurrogate(low)) {
+ ucs4 = QChar::surrogateToUcs4(ucs4, low);
+ ++p;
+ }
+ }
+ switch (QChar::direction(ucs4))
+ {
+ case QChar::DirL:
+ return false;
+ case QChar::DirR:
+ case QChar::DirAL:
+ return true;
+ default:
+ break;
+ }
+ ++p;
+ }
+ return false;
+}
+
+/*!
\since 4.8
Returns \c true if the string reference starts with \a str; otherwise
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index b50b2ee4e5..b370056d28 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -1400,7 +1400,8 @@ public:
QStringRef(QStringRef &&other) Q_DECL_NOTHROW : m_string(other.m_string), m_position(other.m_position), m_size(other.m_size) {}
QStringRef &operator=(QStringRef &&other) Q_DECL_NOTHROW { return *this = other; }
#endif
- QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW {
+ QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW
+ {
m_string = other.m_string; m_position = other.m_position;
m_size = other.m_size; return *this;
}
@@ -1449,6 +1450,8 @@ public:
m_size -= n;
}
+ bool isRightToLeft() const;
+
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -1461,7 +1464,8 @@ public:
inline QStringRef &operator=(const QString *string);
- inline const QChar *unicode() const {
+ inline const QChar *unicode() const
+ {
if (!m_string)
return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data());
return m_string->unicode() + m_position;
@@ -1471,8 +1475,10 @@ public:
inline const_iterator begin() const { return unicode(); }
inline const_iterator cbegin() const { return unicode(); }
+ inline const_iterator constBegin() const { return unicode(); }
inline const_iterator end() const { return unicode() + size(); }
inline const_iterator cend() const { return unicode() + size(); }
+ inline const_iterator constEnd() const { return unicode() + size(); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
inline const_reverse_iterator crbegin() const { return rbegin(); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }