summaryrefslogtreecommitdiff
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri10
-rw-r--r--src/corelib/io/qdatastream.cpp3
-rw-r--r--src/corelib/io/qdatastream.h5
-rw-r--r--src/corelib/io/qdebug.h32
-rw-r--r--src/corelib/io/qdir.cpp2
-rw-r--r--src/corelib/io/qdiriterator.cpp2
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp192
-rw-r--r--src/corelib/io/qfilesystementry.cpp6
-rw-r--r--src/corelib/io/qfilesystemiterator_unix.cpp4
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp14
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h6
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp8
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.mm507
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h142
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp6
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp15
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp73
-rw-r--r--src/corelib/io/qlockfile_win.cpp14
-rw-r--r--src/corelib/io/qloggingcategory.cpp151
-rw-r--r--src/corelib/io/qloggingcategory.h36
-rw-r--r--src/corelib/io/qloggingregistry.cpp137
-rw-r--r--src/corelib/io/qloggingregistry_p.h36
-rw-r--r--src/corelib/io/qprocess.cpp40
-rw-r--r--src/corelib/io/qprocess.h1
-rw-r--r--src/corelib/io/qprocess_unix.cpp100
-rw-r--r--src/corelib/io/qprocess_win.cpp2
-rw-r--r--src/corelib/io/qresource.cpp24
-rw-r--r--src/corelib/io/qsettings.cpp87
-rw-r--r--src/corelib/io/qsettings.h2
-rw-r--r--src/corelib/io/qstandardpaths.cpp244
-rw-r--r--src/corelib/io/qstandardpaths_blackberry.cpp9
-rw-r--r--src/corelib/io/qstandardpaths_mac.cpp25
-rw-r--r--src/corelib/io/qstandardpaths_win.cpp28
-rw-r--r--src/corelib/io/qstandardpaths_winrt.cpp127
-rw-r--r--src/corelib/io/qtemporaryfile.cpp17
-rw-r--r--src/corelib/io/qtextstream.cpp32
-rw-r--r--src/corelib/io/qurlidna.cpp2
-rw-r--r--src/corelib/io/qurlrecode.cpp186
-rw-r--r--src/corelib/io/qwindowspipereader.cpp3
-rw-r--r--src/corelib/io/qwindowspipereader_p.h2
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp4
-rw-r--r--src/corelib/io/qwinoverlappedionotifier.cpp139
-rw-r--r--src/corelib/io/qwinoverlappedionotifier_p.h47
43 files changed, 2026 insertions, 496 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 649493f8b7..989e4644c7 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -94,7 +94,6 @@ SOURCES += \
io/qloggingregistry.cpp
win32 {
- SOURCES += io/qsettings_win.cpp
SOURCES += io/qfsfileengine_win.cpp
SOURCES += io/qlockfile_win.cpp
@@ -102,11 +101,12 @@ win32 {
HEADERS += io/qfilesystemwatcher_win_p.h
SOURCES += io/qfilesystemengine_win.cpp
SOURCES += io/qfilesystemiterator_win.cpp
- SOURCES += io/qstandardpaths_win.cpp
!winrt {
+ SOURCES += io/qsettings_win.cpp
HEADERS += io/qwindowspipewriter_p.h
SOURCES += io/qwindowspipewriter.cpp
+ SOURCES += io/qstandardpaths_win.cpp
wince* {
SOURCES += io/qprocess_wince.cpp
@@ -119,6 +119,8 @@ win32 {
io/qwinoverlappedionotifier.cpp \
io/qwindowspipereader.cpp
}
+ } else {
+ SOURCES += io/qstandardpaths_winrt.cpp
}
} else:unix|integrity {
SOURCES += \
@@ -133,6 +135,10 @@ win32 {
OBJECTIVE_SOURCES += io/qurl_mac.mm
}
mac {
+ osx {
+ OBJECTIVE_SOURCES += io/qfilesystemwatcher_fsevents.mm
+ HEADERS += io/qfilesystemwatcher_fsevents_p.h
+ }
macx {
SOURCES += io/qstandardpaths_mac.cpp
} else:ios {
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index af5605f8c7..a6fbffee7e 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -251,7 +251,7 @@ QT_BEGIN_NAMESPACE
return retVal;
enum {
- DefaultStreamVersion = QDataStream::Qt_5_2
+ DefaultStreamVersion = QDataStream::Qt_5_3
};
/*!
@@ -541,6 +541,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_0 Version 13 (Qt 5.0)
\value Qt_5_1 Version 14 (Qt 5.1)
\value Qt_5_2 Version 15 (Qt 5.2)
+ \value Qt_5_3 Same as Qt_5_2
\sa setVersion(), version()
*/
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index f107e801b6..28f1d51a12 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -87,8 +87,9 @@ public:
Qt_4_9 = Qt_4_8,
Qt_5_0 = 13,
Qt_5_1 = 14,
- Qt_5_2 = 15
-#if QT_VERSION >= 0x050300
+ Qt_5_2 = 15,
+ Qt_5_3 = Qt_5_2
+#if QT_VERSION >= 0x050400
#error Add the datastream version for this Qt version
#endif
};
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 9ed5f6e951..00177b659e 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -80,7 +80,9 @@ public:
inline QDebug &operator=(const QDebug &other);
inline ~QDebug() {
if (!--stream->ref) {
- if(stream->message_output) {
+ if (stream->space && stream->buffer.endsWith(QLatin1Char(' ')))
+ stream->buffer.chop(1);
+ if (stream->message_output) {
QT_TRY {
qt_message_output(stream->type,
stream->context,
@@ -172,6 +174,7 @@ template <class T>
inline QDebug operator<<(QDebug debug, const QList<T> &list)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << '(';
for (typename QList<T>::size_type i = 0; i < list.count(); ++i) {
if (i)
@@ -179,7 +182,8 @@ inline QDebug operator<<(QDebug debug, const QList<T> &list)
debug << list.at(i);
}
debug << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
#if defined(FORCE_UREF)
@@ -190,7 +194,9 @@ template <typename T>
inline QDebug operator<<(QDebug debug, const QVector<T> &vec)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QVector";
+ debug.setAutoInsertSpaces(oldSetting);
return operator<<(debug, vec.toList());
}
@@ -202,13 +208,15 @@ template <class aKey, class aT>
inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QMap(";
for (typename QMap<aKey, aT>::const_iterator it = map.constBegin();
it != map.constEnd(); ++it) {
debug << '(' << it.key() << ", " << it.value() << ')';
}
debug << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
#if defined(FORCE_UREF)
@@ -219,12 +227,14 @@ template <class aKey, class aT>
inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QHash(";
for (typename QHash<aKey, aT>::const_iterator it = hash.constBegin();
it != hash.constEnd(); ++it)
debug << '(' << it.key() << ", " << it.value() << ')';
debug << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
#if defined(FORCE_UREF)
@@ -235,14 +245,18 @@ template <class T1, class T2>
inline QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QPair(" << pair.first << ',' << pair.second << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
template <typename T>
inline QDebug operator<<(QDebug debug, const QSet<T> &set)
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QSet";
+ debug.setAutoInsertSpaces(oldSetting);
return operator<<(debug, set.toList());
}
@@ -254,6 +268,7 @@ template <class T>
inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QContiguousCache(";
for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
debug << cache[i];
@@ -261,7 +276,8 @@ inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
debug << ", ";
}
debug << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
#if defined(FORCE_UREF)
@@ -272,6 +288,7 @@ template <class T>
inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
#endif
{
+ const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QFlags(";
bool needSeparator = false;
for (uint i = 0; i < sizeof(T) * 8; ++i) {
@@ -284,7 +301,8 @@ inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
}
}
debug << ')';
- return debug.space();
+ debug.setAutoInsertSpaces(oldSetting);
+ return debug.maybeSpace();
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index c5a0db310a..ec7d89fa87 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -2146,7 +2146,7 @@ QString QDir::cleanPath(const QString &path)
name.replace(dir_separator, QLatin1Char('/'));
bool allowUncPaths = false;
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //allow unc paths
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) //allow unc paths
allowUncPaths = true;
#endif
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 5b48c4c7db..79cdec9674 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -477,7 +477,7 @@ QDirIterator::~QDirIterator()
/*!
Advances the iterator to the next entry, and returns the file path of this
new entry. If hasNext() returns \c false, this function does nothing, and
- returns a null QString.
+ returns an empty QString.
You can call fileName() or filePath() to get the current entry file name
or path, or fileInfo() to get a QFileInfo for the current entry.
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 257f18a6bb..dbc6d28846 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -63,13 +63,28 @@
# include <types.h>
#endif
#include <objbase.h>
-#include <shlobj.h>
+#ifndef Q_OS_WINRT
+# include <shlobj.h>
+# include <accctrl.h>
+#endif
#include <initguid.h>
-#include <accctrl.h>
#include <ctype.h>
#include <limits.h>
-#define SECURITY_WIN32
-#include <security.h>
+#ifndef Q_OS_WINRT
+# define SECURITY_WIN32
+# include <security.h>
+#else // !Q_OS_WINRT
+# include <wrl.h>
+# include <windows.foundation.h>
+# include <windows.storage.h>
+# include <Windows.ApplicationModel.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::ApplicationModel;
+#endif // Q_OS_WINRT
#ifndef SPI_GETPLATFORMTYPE
#define SPI_GETPLATFORMTYPE 257
@@ -141,7 +156,7 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
-#if defined(Q_OS_WINCE)
+#if defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
static QString qfsPrivateCurrentDir = QLatin1String("");
// As none of the functions we try to resolve do exist on Windows CE
// we use QT_NO_LIBRARY to shorten everything up a little bit.
@@ -289,14 +304,14 @@ static bool resolveUNCLibs()
}
#endif
triedResolve = true;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
HINSTANCE hLib = QSystemLibrary::load(L"Netapi32");
if (hLib) {
ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum");
if (ptrNetShareEnum)
ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree");
}
-#endif
+#endif // !Q_OS_WINCE && !Q_OS_WINRT
}
return ptrNetShareEnum && ptrNetApiBufferFree;
}
@@ -304,7 +319,7 @@ static bool resolveUNCLibs()
static QString readSymLink(const QFileSystemEntry &link)
{
QString result;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
HANDLE handle = CreateFile((wchar_t*)link.nativeFilePath().utf16(),
FILE_READ_EA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -347,11 +362,11 @@ static QString readSymLink(const QFileSystemEntry &link)
result.replace(0,matchVolName.matchedLength(), QString::fromWCharArray(buffer));
}
}
-#endif
+#endif // !Q_OS_WINCE && !Q_OS_WINRT
}
#else
Q_UNUSED(link);
-#endif // Q_OS_WINCE
+#endif // Q_OS_WINCE || Q_OS_WINRT
return result;
}
@@ -432,7 +447,11 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
// can't handle drives
if (!path.endsWith(QLatin1Char(':'))) {
+#ifndef Q_OS_WINRT
HANDLE hFind = ::FindFirstFile((wchar_t*)path.utf16(), &findData);
+#else
+ HANDLE hFind = ::FindFirstFileEx((const wchar_t*)path.utf16(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0);
+#endif
if (hFind != INVALID_HANDLE_VALUE) {
::FindClose(hFind);
return true;
@@ -506,7 +525,7 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
{
// can be //server or //server/share
QString absPath;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
wchar_t *fileName = 0;
DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
@@ -516,12 +535,17 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
}
if (retLen != 0)
absPath = QString::fromWCharArray(buf.data(), retLen);
-#else
+#elif !defined(Q_OS_WINCE)
+ if (QDir::isRelativePath(path))
+ absPath = QDir::toNativeSeparators(QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + path));
+ else
+ absPath = QDir::toNativeSeparators(QDir::cleanPath(path));
+#else // Q_OS_WINRT
if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\')))
absPath = QDir::toNativeSeparators(path);
else
absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path));
-#endif
+#endif // Q_OS_WINCE
// This is really ugly, but GetFullPathName strips off whitespace at the end.
// If you for instance write ". " in the lineedit of QFileDialog,
// (which is an invalid filename) this function will strip the space off and viola,
@@ -548,9 +572,17 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
ret = entry.filePath();
#endif
} else {
+#ifndef Q_OS_WINRT
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
+#else
+ // Some WinRT APIs do not support absolute paths (due to sandboxing).
+ // Thus the port uses the executable's directory as its root directory
+ // and treats paths relative to that as absolute paths.
+ ret = QDir::cleanPath(QDir::current().relativeFilePath(entry.filePath()));
+#endif
}
+#ifndef Q_OS_WINRT
// The path should be absolute at this point.
// From the docs :
// Absolute paths begin with the directory separator "/"
@@ -563,6 +595,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
// Force uppercase drive letters.
ret[0] = ret.at(0).toUpper();
}
+#endif // !Q_OS_WINRT
return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath());
}
@@ -590,18 +623,24 @@ typedef struct _FILE_ID_INFO {
static inline QByteArray fileId(HANDLE handle)
{
QByteArray result;
+#ifndef Q_OS_WINRT
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle(handle, &info)) {
result = QByteArray::number(uint(info.nFileIndexLow), 16);
result += ':';
result += QByteArray::number(uint(info.nFileIndexHigh), 16);
}
+#else // !Q_OS_WINRT
+ Q_UNUSED(handle);
+ Q_UNIMPLEMENTED();
+#endif // Q_OS_WINRT
return result;
}
// File ID for Windows starting from version 8.
QByteArray fileIdWin8(HANDLE handle)
{
+#ifndef Q_OS_WINRT
typedef BOOL (WINAPI* GetFileInformationByHandleExType)(HANDLE, Q_FILE_INFO_BY_HANDLE_CLASS, void *, DWORD);
// Dynamically resolve GetFileInformationByHandleEx (Vista onwards).
@@ -621,6 +660,16 @@ QByteArray fileIdWin8(HANDLE handle)
result += QByteArray((char *)&infoEx.FileId, sizeof(infoEx.FileId)).toHex();
}
}
+#else // !Q_OS_WINRT
+ QByteArray result;
+ FILE_ID_INFO infoEx;
+ if (GetFileInformationByHandleEx(handle, FileIdInfo,
+ &infoEx, sizeof(FILE_ID_INFO))) {
+ result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
+ result += ':';
+ result += QByteArray((char *)infoEx.FileId.Identifier, sizeof(infoEx.FileId.Identifier)).toHex();
+ }
+#endif // Q_OS_WINRT
return result;
}
#endif // !Q_OS_WINCE
@@ -631,8 +680,13 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
#ifndef Q_OS_WINCE
QByteArray result;
const HANDLE handle =
+#ifndef Q_OS_WINRT
CreateFile((wchar_t*)entry.nativeFilePath().utf16(), GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+#else // !Q_OS_WINRT
+ CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), GENERIC_READ,
+ FILE_SHARE_READ, OPEN_EXISTING, NULL);
+#endif // Q_OS_WINRT
if (handle) {
result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
fileIdWin8(handle) : fileId(handle);
@@ -810,7 +864,7 @@ static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaDa
{
bool entryExists = false;
DWORD fileAttrib = 0;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
if (fname.isDriveRoot()) {
// a valid drive ??
DWORD drivesBitmask = ::GetLogicalDrives();
@@ -851,7 +905,7 @@ static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaDa
fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
entryExists = true;
}
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
}
#endif
if (entryExists)
@@ -894,12 +948,32 @@ bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
{
data.entryFlags &= ~what;
clearWinStatData(data);
+#ifndef Q_OS_WINRT
BY_HANDLE_FILE_INFORMATION fileInfo;
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
if (GetFileInformationByHandle(fHandle , &fileInfo)) {
data.fillFromFindInfo(fileInfo);
}
SetErrorMode(oldmode);
+#else // !Q_OS_WINRT
+ FILE_BASIC_INFO fileBasicInfo;
+ if (GetFileInformationByHandleEx(fHandle, FileBasicInfo, &fileBasicInfo, sizeof(fileBasicInfo))) {
+ data.fillFromFileAttribute(fileBasicInfo.FileAttributes);
+ data.creationTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart;
+ data.creationTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart;
+ data.lastAccessTime_.dwHighDateTime = fileBasicInfo.LastAccessTime.HighPart;
+ data.lastAccessTime_.dwLowDateTime = fileBasicInfo.LastAccessTime.LowPart;
+ data.lastWriteTime_.dwHighDateTime = fileBasicInfo.LastWriteTime.HighPart;
+ data.lastWriteTime_.dwLowDateTime = fileBasicInfo.LastWriteTime.LowPart;
+ if (!(data.fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY)) {
+ FILE_STANDARD_INFO fileStandardInfo;
+ if (GetFileInformationByHandleEx(fHandle, FileStandardInfo, &fileStandardInfo, sizeof(fileStandardInfo)))
+ data.size_ = fileStandardInfo.EndOfFile.QuadPart;
+ } else
+ data.size_ = 0;
+ data.knownFlagsMask |= QFileSystemMetaData::Times | QFileSystemMetaData::SizeAttribute;
+ }
+#endif // Q_OS_WINRT
return data.hasFlags(what);
}
@@ -931,7 +1005,9 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
}
if (what & QFileSystemMetaData::WinStatFlags) {
+#ifndef Q_OS_WINRT
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+#endif
clearWinStatData(data);
WIN32_FIND_DATA findData;
// The memory structure for WIN32_FIND_DATA is same as WIN32_FILE_ATTRIBUTE_DATA
@@ -943,11 +1019,15 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
} else {
if (!tryFindFallback(fname, data))
if (!tryDriveUNCFallback(fname, data)) {
+#ifndef Q_OS_WINRT
SetErrorMode(oldmode);
+#endif
return false;
}
}
+#ifndef Q_OS_WINRT
SetErrorMode(oldmode);
+#endif
}
if (what & QFileSystemMetaData::Permissions)
@@ -1006,7 +1086,14 @@ static bool isDirPath(const QString &dirPath, bool *existed)
if (path.length() == 2 && path.at(1) == QLatin1Char(':'))
path += QLatin1Char('\\');
+#ifndef Q_OS_WINRT
DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
+#else // Q_OS_WINRT
+ DWORD fileAttrib = INVALID_FILE_ATTRIBUTES;
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if (::GetFileAttributesEx((const wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), GetFileExInfoStandard, &data))
+ fileAttrib = data.dwFileAttributes;
+#endif // Q_OS_WINRT
if (fileAttrib == INVALID_FILE_ATTRIBUTES) {
int errorCode = GetLastError();
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
@@ -1100,6 +1187,30 @@ QString QFileSystemEngine::rootPath()
{
#if defined(Q_OS_WINCE)
QString ret = QLatin1String("/");
+#elif defined(Q_OS_WINRT)
+ // We specify the package root as root directory
+ QString ret = QLatin1String("/");
+ // Get package location
+ ComPtr<IPackageStatics> statics;
+ if (FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Package).Get(), &statics)))
+ return ret;
+ ComPtr<IPackage> package;
+ if (FAILED(statics->get_Current(&package)))
+ return ret;
+ ComPtr<IStorageFolder> installedLocation;
+ if (FAILED(package->get_InstalledLocation(&installedLocation)))
+ return ret;
+
+ ComPtr<IStorageItem> item;
+ if (FAILED(installedLocation.As(&item)))
+ return ret;
+
+ HSTRING finalWinPath;
+ if (FAILED(item->get_Path(&finalWinPath)))
+ return ret;
+
+ ret = QDir::fromNativeSeparators(QString::fromWCharArray(WindowsGetStringRawBuffer(finalWinPath, nullptr)));
+
#else
QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData());
if (ret.isEmpty())
@@ -1158,12 +1269,13 @@ QString QFileSystemEngine::homePath()
QString QFileSystemEngine::tempPath()
{
QString ret;
+#ifndef Q_OS_WINRT
wchar_t tempPath[MAX_PATH];
const DWORD len = GetTempPath(MAX_PATH, tempPath);
#ifdef Q_OS_WINCE
if (len)
ret = QString::fromWCharArray(tempPath, len);
-#else
+#else // Q_OS_WINCE
if (len) { // GetTempPath() can return short names, expand.
wchar_t longTempPath[MAX_PATH];
const DWORD longLen = GetLongPathName(tempPath, longTempPath, MAX_PATH);
@@ -1171,12 +1283,33 @@ QString QFileSystemEngine::tempPath()
QString::fromWCharArray(longTempPath, longLen) :
QString::fromWCharArray(tempPath, len);
}
-#endif
+#endif // !Q_OS_WINCE
if (!ret.isEmpty()) {
while (ret.endsWith(QLatin1Char('\\')))
ret.chop(1);
ret = QDir::fromNativeSeparators(ret);
}
+#else // !Q_OS_WINRT
+ // According to http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.temporaryfolder.aspx
+ // the API is not available on winphone which should cause one of the functions
+ // below to fail
+ ComPtr<IApplicationDataStatics> applicationDataStatics;
+ if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
+ return ret;
+ ComPtr<IApplicationData> applicationData;
+ if (FAILED(applicationDataStatics->get_Current(&applicationData)))
+ return ret;
+ ComPtr<IStorageFolder> tempFolder;
+ if (FAILED(applicationData->get_TemporaryFolder(&tempFolder)))
+ return ret;
+ ComPtr<IStorageItem> tempFolderItem;
+ if (FAILED(tempFolder.As(&tempFolderItem)))
+ return ret;
+ HSTRING path;
+ if (FAILED(tempFolderItem->get_Path(&path)))
+ return ret;
+ ret = QDir::fromNativeSeparators(QString::fromWCharArray(WindowsGetStringRawBuffer(path, nullptr)));
+#endif // Q_OS_WINRT
if (ret.isEmpty()) {
#if !defined(Q_OS_WINCE)
ret = QLatin1String("C:/tmp");
@@ -1195,7 +1328,7 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
if(!(meta.exists() && meta.isDirectory()))
return false;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
//TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo
//which causes many problems later on when it's returned through currentPath()
return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0;
@@ -1208,7 +1341,7 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
QFileSystemEntry QFileSystemEngine::currentPath()
{
QString ret;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
DWORD size = 0;
wchar_t currentName[PATH_MAX];
size = ::GetCurrentDirectory(PATH_MAX, currentName);
@@ -1224,13 +1357,17 @@ QFileSystemEntry QFileSystemEngine::currentPath()
}
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
-#else
+#else // !Q_OS_WINCE && !Q_OS_WINRT
//TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads
if (qfsPrivateCurrentDir.isEmpty())
+#ifndef Q_OS_WINRT
qfsPrivateCurrentDir = QCoreApplication::applicationDirPath();
+#else
+ qfsPrivateCurrentDir = QDir::rootPath();
+#endif
ret = qfsPrivateCurrentDir;
-#endif
+#endif // Q_OS_WINCE || Q_OS_WINRT
return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
}
@@ -1248,8 +1385,16 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
+#ifndef Q_OS_WINRT
bool ret = ::CopyFile((wchar_t*)source.nativeFilePath().utf16(),
(wchar_t*)target.nativeFilePath().utf16(), true) != 0;
+#else // !Q_OS_WINRT
+ COPYFILE2_EXTENDED_PARAMETERS copyParams = {
+ sizeof(copyParams), COPY_FILE_FAIL_IF_EXISTS, NULL, NULL, NULL
+ };
+ bool ret = ::CopyFile2((const wchar_t*)source.nativeFilePath().utf16(),
+ (const wchar_t*)target.nativeFilePath().utf16(), &copyParams) != 0;
+#endif // Q_OS_WINRT
if(!ret)
error = QSystemError(::GetLastError(), QSystemError::NativeError);
return ret;
@@ -1258,8 +1403,13 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst
//static
bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
+#ifndef Q_OS_WINRT
bool ret = ::MoveFile((wchar_t*)source.nativeFilePath().utf16(),
(wchar_t*)target.nativeFilePath().utf16()) != 0;
+#else // !Q_OS_WINRT
+ bool ret = ::MoveFileEx((const wchar_t*)source.nativeFilePath().utf16(),
+ (const wchar_t*)target.nativeFilePath().utf16(), 0) != 0;
+#endif // Q_OS_WINRT
if(!ret)
error = QSystemError(::GetLastError(), QSystemError::NativeError);
return ret;
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index 3934c6a673..42a724670e 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -170,6 +170,12 @@ void QFileSystemEntry::resolveNativeFilePath() const
#else
m_nativeFilePath = QFile::encodeName(QDir::toNativeSeparators(m_filePath));
#endif
+#ifdef Q_OS_WINRT
+ while (m_nativeFilePath.startsWith(QLatin1Char('\\')))
+ m_nativeFilePath.remove(0,1);
+ if (m_nativeFilePath.isEmpty())
+ m_nativeFilePath.append(QLatin1Char('.'));
+#endif
}
}
diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
index bfedd3f70c..0b59aa169a 100644
--- a/src/corelib/io/qfilesystemiterator_unix.cpp
+++ b/src/corelib/io/qfilesystemiterator_unix.cpp
@@ -105,8 +105,8 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
if (!dir)
return false;
-#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R)
- lastError = _readdir_r(dir, mt_file.data(), &dirEntry, direntSize);
+#if defined(Q_OS_QNX) && defined(QT_EXT_QNX_READDIR_R)
+ lastError = QT_EXT_QNX_READDIR_R(dir, mt_file.data(), &dirEntry, direntSize);
if (lastError)
return false;
#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 90232f7cfc..dda96bd45a 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -39,10 +39,12 @@
**
****************************************************************************/
-#if _WIN32_WINNT < 0x0500
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0500
-#endif
+#if !defined(WINAPI_FAMILY)
+# if _WIN32_WINNT < 0x0500
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0500
+# endif // _WIN32_WINNT < 0x500
+#endif // !WINAPI_FAMILY
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
@@ -73,6 +75,10 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
if (!nativePath.endsWith(QLatin1Char('\\')))
nativePath.append(QLatin1Char('\\'));
nativePath.append(QLatin1Char('*'));
+#ifdef Q_OS_WINRT
+ if (nativePath.startsWith(QLatin1Char('\\')))
+ nativePath.remove(0, 1);
+#endif
if (!dirPath.endsWith(QLatin1Char('/')))
dirPath.append(QLatin1Char('/'));
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 1abc9b7ec4..de79ec32d3 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -219,7 +219,9 @@ public:
#if defined(Q_OS_WIN)
inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false);
inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false);
+# ifndef Q_OS_WINRT
inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo);
+# endif
#endif
private:
friend class QFileSystemEngine;
@@ -340,6 +342,7 @@ inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, boo
}
}
+#ifndef Q_OS_WINRT
inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
{
fillFromFileAttribute(fileInfo.dwFileAttributes);
@@ -355,7 +358,8 @@ inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fi
}
knownFlagsMask |= Times | SizeAttribute;
}
-#endif
+#endif // !Q_OS_WINRT
+#endif // Q_OS_WIN
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index d1deae2d7b..8cc6ad0552 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -60,8 +60,10 @@
# include "qfilesystemwatcher_win_p.h"
#elif defined(USE_INOTIFY)
# include "qfilesystemwatcher_inotify_p.h"
-#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) || (defined(Q_OS_OSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
# include "qfilesystemwatcher_kqueue_p.h"
+#elif defined(Q_OS_OSX) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_6
+# include "qfilesystemwatcher_fsevents_p.h"
#endif
QT_BEGIN_NAMESPACE
@@ -74,8 +76,10 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject
// there is a chance that inotify may fail on Linux pre-2.6.13 (August
// 2005), so we can't just new inotify directly.
return QInotifyFileSystemWatcherEngine::create(parent);
-#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) || (defined(Q_OS_OSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
return QKqueueFileSystemWatcherEngine::create(parent);
+#elif defined(Q_OS_OSX) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_6
+ return QFseventsFileSystemWatcherEngine::create(parent);
#else
Q_UNUSED(parent);
return 0;
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm
new file mode 100644
index 0000000000..cb6ddd913e
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qplatformdefs.h>
+
+#include "qdiriterator.h"
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_fsevents_p.h"
+#include "private/qcore_unix_p.h"
+#include "kernel/qcore_mac_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include <qdebug.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qvarlengtharray.h>
+
+//#define FSEVENT_DEBUG
+#ifdef FSEVENT_DEBUG
+# define DEBUG if (true) qDebug
+#else
+# define DEBUG if (false) qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static void callBackFunction(ConstFSEventStreamRef streamRef,
+ void *clientCallBackInfo,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[])
+{
+ char **paths = static_cast<char **>(eventPaths);
+ QFseventsFileSystemWatcherEngine *engine = static_cast<QFseventsFileSystemWatcherEngine *>(clientCallBackInfo);
+ engine->processEvent(streamRef, numEvents, paths, eventFlags, eventIds);
+}
+
+void QFseventsFileSystemWatcherEngine::checkDir(DirsByName::iterator &it)
+{
+ QT_STATBUF st;
+ const QString &name = it.key();
+ Info &info = it->dirInfo;
+ const int res = QT_STAT(QFile::encodeName(name), &st);
+ if (res == -1) {
+ derefPath(info.watchedPath);
+ emit emitDirectoryChanged(info.origPath, true);
+ it = watchedDirectories.erase(it);
+ } else if (st.st_ctimespec != info.ctime || st.st_mode != info.mode) {
+ info.ctime = st.st_ctimespec;
+ info.mode = st.st_mode;
+ emit emitDirectoryChanged(info.origPath, false);
+ ++it;
+ } else {
+ bool dirChanged = false;
+ InfoByName &entries = it->entries;
+ // check known entries:
+ for (InfoByName::iterator i = entries.begin(); i != entries.end(); ) {
+ if (QT_STAT(QFile::encodeName(i.key()), &st) == -1) {
+ // entry disappeared
+ dirChanged = true;
+ i = entries.erase(i);
+ } else {
+ if (i->ctime != st.st_ctimespec || i->mode != st.st_mode) {
+ // entry changed
+ dirChanged = true;
+ i->ctime = st.st_ctimespec;
+ i->mode = st.st_mode;
+ }
+ ++i;
+ }
+ }
+ // check for new entries:
+ QDirIterator dirIt(name);
+ while (dirIt.hasNext()) {
+ dirIt.next();
+ QString entryName = dirIt.filePath();
+ if (!entries.contains(entryName)) {
+ dirChanged = true;
+ QT_STATBUF st;
+ if (QT_STAT(QFile::encodeName(entryName), &st) == -1)
+ continue;
+ entries.insert(entryName, Info(QString(), st.st_ctimespec, st.st_mode, QString()));
+
+ }
+ }
+ if (dirChanged)
+ emit emitDirectoryChanged(info.origPath, false);
+ }
+}
+
+void QFseventsFileSystemWatcherEngine::rescanDirs(const QString &path)
+{
+ for (DirsByName::iterator it = watchedDirectories.begin(); it != watchedDirectories.end(); ) {
+ if (it.key().startsWith(path))
+ checkDir(it);
+ else
+ ++it;
+ }
+}
+
+void QFseventsFileSystemWatcherEngine::rescanFiles(InfoByName &filesInPath)
+{
+ for (InfoByName::iterator it = filesInPath.begin(); it != filesInPath.end(); ) {
+ QT_STATBUF st;
+ QString name = it.key();
+ const int res = QT_STAT(QFile::encodeName(name), &st);
+ if (res == -1) {
+ derefPath(it->watchedPath);
+ emit emitFileChanged(it.value().origPath, true);
+ it = filesInPath.erase(it);
+ continue;
+ } else if (st.st_ctimespec != it->ctime || st.st_mode != it->mode) {
+ it->ctime = st.st_ctimespec;
+ it->mode = st.st_mode;
+ emit emitFileChanged(it.value().origPath, false);
+ }
+
+ ++it;
+ }
+}
+
+void QFseventsFileSystemWatcherEngine::rescanFiles(const QString &path)
+{
+ for (FilesByPath::iterator i = watchedFiles.begin(); i != watchedFiles.end(); ) {
+ if (i.key().startsWith(path)) {
+ rescanFiles(i.value());
+ if (i.value().isEmpty()) {
+ i = watchedFiles.erase(i);
+ continue;
+ }
+ }
+
+ ++i;
+ }
+}
+
+void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef streamRef,
+ size_t numEvents,
+ char **eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[])
+{
+#if defined(Q_OS_OSX) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_6
+ Q_UNUSED(streamRef);
+
+ QMutexLocker locker(&lock);
+
+ for (size_t i = 0; i < numEvents; ++i) {
+ FSEventStreamEventFlags eFlags = eventFlags[i];
+ DEBUG("Change %llu in %s, flags %x", eventIds[i], eventPaths[i], (unsigned int)eFlags);
+ QString path = QFile::decodeName(eventPaths[i]);
+ if (path.endsWith(QDir::separator()))
+ path = path.mid(0, path.size() - 1);
+
+ if (eFlags & kFSEventStreamEventFlagMustScanSubDirs) {
+ DEBUG("\tmust rescan directory because of coalesced events");
+ if (eFlags & kFSEventStreamEventFlagUserDropped)
+ DEBUG("\t\t... user dropped.");
+ if (eFlags & kFSEventStreamEventFlagKernelDropped)
+ DEBUG("\t\t... kernel dropped.");
+ rescanDirs(path);
+ rescanFiles(path);
+ continue;
+ }
+
+ if (eFlags & kFSEventStreamEventFlagEventIdsWrapped) {
+ DEBUG("\tthe event ids wrapped");
+ // TODO: verify if we need to do something
+ }
+
+ if (eFlags & kFSEventStreamEventFlagRootChanged) {
+ // re-check everything:
+ DirsByName::iterator dirIt = watchedDirectories.find(path);
+ if (dirIt != watchedDirectories.end())
+ checkDir(dirIt);
+ rescanFiles(path);
+ continue;
+ }
+
+ if ((eFlags & kFSEventStreamEventFlagItemIsDir) && (eFlags & kFSEventStreamEventFlagItemRemoved))
+ rescanDirs(path);
+
+ // check watched directories:
+ DirsByName::iterator dirIt = watchedDirectories.find(path);
+ if (dirIt != watchedDirectories.end())
+ checkDir(dirIt);
+
+ // check watched files:
+ FilesByPath::iterator pIt = watchedFiles.find(path);
+ if (pIt != watchedFiles.end())
+ rescanFiles(pIt.value());
+ }
+#else
+ // This is a work-around for moc: when we put the version check at the top of the header file,
+ // moc will still see the Q_OBJECT macro and generate a meta-object when compiling for 10.6,
+ // which obviously won't link.
+ //
+ // So the trick is to still compile this class on 10.6, but never instantiate it.
+
+ Q_UNUSED(streamRef);
+ Q_UNUSED(numEvents);
+ Q_UNUSED(eventPaths);
+ Q_UNUSED(eventFlags);
+ Q_UNUSED(eventIds);
+#endif
+}
+
+void QFseventsFileSystemWatcherEngine::doEmitFileChanged(const QString path, bool removed)
+{
+ emit fileChanged(path, removed);
+}
+
+void QFseventsFileSystemWatcherEngine::doEmitDirectoryChanged(const QString path, bool removed)
+{
+ emit directoryChanged(path, removed);
+}
+
+QFseventsFileSystemWatcherEngine *QFseventsFileSystemWatcherEngine::create(QObject *parent)
+{
+ return new QFseventsFileSystemWatcherEngine(parent);
+}
+
+QFseventsFileSystemWatcherEngine::QFseventsFileSystemWatcherEngine(QObject *parent)
+ : QFileSystemWatcherEngine(parent)
+ , stream(0)
+{
+
+ // We cannot use signal-to-signal queued connections, because the
+ // QSignalSpy cannot spot signals fired from other/alien threads.
+ connect(this, SIGNAL(emitDirectoryChanged(const QString, bool)),
+ this, SLOT(doEmitDirectoryChanged(const QString, bool)), Qt::QueuedConnection);
+ connect(this, SIGNAL(emitFileChanged(const QString, bool)),
+ this, SLOT(doEmitFileChanged(const QString, bool)), Qt::QueuedConnection);
+
+ queue = dispatch_queue_create("org.qt-project.QFseventsFileSystemWatcherEngine", NULL);
+}
+
+QFseventsFileSystemWatcherEngine::~QFseventsFileSystemWatcherEngine()
+{
+ if (stream)
+ FSEventStreamStop(stream);
+
+ // The assumption with the locking strategy is that this class cannot and will not be subclassed!
+ QMutexLocker locker(&lock);
+
+ stopStream();
+ dispatch_release(queue);
+}
+
+QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ if (stream)
+ FSEventStreamFlushSync(stream);
+
+ QMutexLocker locker(&lock);
+
+ bool newWatchPathsFound = false;
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString origPath = it.next();
+ QString realPath = origPath;
+ if (realPath.endsWith(QDir::separator()))
+ realPath = realPath.mid(0, realPath.size() - 1);
+ QString watchedPath, parentPath;
+
+ realPath = QFileInfo(realPath).canonicalFilePath();
+ QFileInfo fi(realPath);
+ if (realPath.isEmpty())
+ continue;
+
+ QT_STATBUF st;
+ if (QT_STAT(QFile::encodeName(realPath), &st) == -1)
+ continue;
+
+ const bool isDir = S_ISDIR(st.st_mode);
+ if (isDir) {
+ if (watchedDirectories.contains(realPath))
+ continue;
+ directories->append(origPath);
+ watchedPath = realPath;
+ it.remove();
+ } else {
+ if (files->contains(origPath))
+ continue;
+ files->append(origPath);
+ it.remove();
+
+ watchedPath = fi.path();
+ parentPath = watchedPath;
+ }
+
+ for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i) {
+ if (watchedPath.startsWith(i.key())) {
+ watchedPath = i.key();
+ break;
+ }
+ }
+
+ PathRefCounts::iterator it = watchedPaths.find(watchedPath);
+ if (it == watchedPaths.end()) {
+ newWatchPathsFound = true;
+ watchedPaths.insert(watchedPath, 1);
+ } else {
+ ++it.value();
+ }
+
+ Info info(origPath, st.st_ctimespec, st.st_mode, watchedPath);
+ if (isDir) {
+ DirInfo dirInfo;
+ dirInfo.dirInfo = info;
+ dirInfo.entries = scanForDirEntries(realPath);
+ watchedDirectories.insert(realPath, dirInfo);
+ } else {
+ watchedFiles[parentPath].insert(realPath, info);
+ }
+ }
+
+ if (newWatchPathsFound) {
+ stopStream();
+ if (!startStream())
+ p = paths;
+ }
+
+ return p;
+}
+
+QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ QMutexLocker locker(&lock);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString origPath = it.next();
+ QString realPath = origPath;
+ if (realPath.endsWith(QDir::separator()))
+ realPath = realPath.mid(0, realPath.size() - 1);
+
+ QFileInfo fi(realPath);
+ realPath = fi.canonicalFilePath();
+
+ if (fi.isDir()) {
+ DirsByName::iterator dirIt = watchedDirectories.find(realPath);
+ if (dirIt != watchedDirectories.end()) {
+ derefPath(dirIt->dirInfo.watchedPath);
+ watchedDirectories.erase(dirIt);
+ directories->removeAll(origPath);
+ it.remove();
+ }
+ } else {
+ QFileInfo fi(realPath);
+ QString parentPath = fi.path();
+ FilesByPath::iterator pIt = watchedFiles.find(parentPath);
+ if (pIt != watchedFiles.end()) {
+ InfoByName &filesInDir = pIt.value();
+ InfoByName::iterator fIt = filesInDir.find(realPath);
+ if (fIt != filesInDir.end()) {
+ derefPath(fIt->watchedPath);
+ filesInDir.erase(fIt);
+ if (filesInDir.isEmpty())
+ watchedFiles.erase(pIt);
+ files->removeAll(origPath);
+ it.remove();
+ }
+ }
+ }
+ }
+
+ return p;
+}
+
+bool QFseventsFileSystemWatcherEngine::startStream()
+{
+ if (watchedPaths.isEmpty())
+ return false;
+
+ DEBUG() << "Starting stream with paths" << watchedPaths.keys();
+
+ NSMutableArray *pathsToWatch = [NSMutableArray arrayWithCapacity:watchedPaths.size()];
+ for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i)
+ [pathsToWatch addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(i.key()))];
+
+ struct FSEventStreamContext callBackInfo = {
+ 0,
+ this,
+ NULL,
+ NULL,
+ NULL
+ };
+ const CFAbsoluteTime latency = .5; // in seconds
+ FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagWatchRoot;
+
+ stream = FSEventStreamCreate(NULL,
+ &callBackFunction,
+ &callBackInfo,
+ reinterpret_cast<CFArrayRef>(pathsToWatch),
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ flags);
+
+ if (!stream) {
+ DEBUG() << "Failed to create stream!";
+ return false;
+ }
+
+ FSEventStreamSetDispatchQueue(stream, queue);
+
+ if (FSEventStreamStart(stream)) {
+ DEBUG() << "Stream started successfully.";
+ return true;
+ } else {
+ DEBUG() << "Stream failed to start!";
+ return false;
+ }
+}
+
+void QFseventsFileSystemWatcherEngine::stopStream(bool isStopped)
+{
+ if (stream) {
+ if (!isStopped)
+ FSEventStreamStop(stream);
+ FSEventStreamInvalidate(stream);
+ FSEventStreamRelease(stream);
+ stream = 0;
+ DEBUG() << "Stream stopped.";
+ }
+}
+
+QFseventsFileSystemWatcherEngine::InfoByName QFseventsFileSystemWatcherEngine::scanForDirEntries(const QString &path)
+{
+ InfoByName entries;
+
+ QDirIterator it(path);
+ while (it.hasNext()) {
+ it.next();
+ QString entryName = it.filePath();
+ QT_STATBUF st;
+ if (QT_STAT(QFile::encodeName(entryName), &st) == -1)
+ continue;
+ entries.insert(entryName, Info(QString(), st.st_ctimespec, st.st_mode, QString()));
+ }
+
+ return entries;
+}
+
+void QFseventsFileSystemWatcherEngine::derefPath(const QString &watchedPath)
+{
+ PathRefCounts::iterator it = watchedPaths.find(watchedPath);
+ if (it == watchedPaths.end())
+ return;
+ if (--it.value() < 1) {
+ watchedPaths.erase(it);
+ stopStream();
+ startStream();
+ }
+}
+
+#endif //QT_NO_FILESYSTEMWATCHER
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
new file mode 100644
index 0000000000..c899c556c8
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMWATCHER_FSEVENTS_P_H
+#define QFILESYSTEMWATCHER_FSEVENTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfilesystemwatcher_p.h"
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qsocketnotifier.h>
+
+#include <dispatch/dispatch.h>
+#include <CoreServices/CoreServices.h>
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+QT_BEGIN_NAMESPACE
+
+class QFseventsFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+public:
+ ~QFseventsFileSystemWatcherEngine();
+
+ static QFseventsFileSystemWatcherEngine *create(QObject *parent);
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ void processEvent(ConstFSEventStreamRef streamRef, size_t numEvents, char **eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]);
+
+Q_SIGNALS:
+ void emitFileChanged(const QString path, bool removed);
+ void emitDirectoryChanged(const QString path, bool removed);
+
+private slots:
+ void doEmitFileChanged(const QString path, bool removed);
+ void doEmitDirectoryChanged(const QString path, bool removed);
+
+private:
+ struct Info {
+ QString origPath;
+ timespec ctime;
+ mode_t mode;
+ QString watchedPath;
+
+ Info(): mode(0)
+ {
+ ctime.tv_sec = 0;
+ ctime.tv_nsec = 0;
+ }
+
+ Info(const QString &origPath, const timespec &ctime, mode_t mode, const QString &watchedPath)
+ : origPath(origPath)
+ , ctime(ctime)
+ , mode(mode)
+ , watchedPath(watchedPath)
+ {}
+ };
+ typedef QHash<QString, Info> InfoByName;
+ typedef QHash<QString, InfoByName> FilesByPath;
+ struct DirInfo {
+ Info dirInfo;
+ InfoByName entries;
+ };
+ typedef QHash<QString, DirInfo> DirsByName;
+ typedef QHash<QString, qint64> PathRefCounts;
+
+ QFseventsFileSystemWatcherEngine(QObject *parent);
+ bool startStream();
+ void stopStream(bool isStopped = false);
+ InfoByName scanForDirEntries(const QString &path);
+ void derefPath(const QString &watchedPath);
+ void checkDir(DirsByName::iterator &it);
+ void rescanDirs(const QString &path);
+ void rescanFiles(InfoByName &filesInPath);
+ void rescanFiles(const QString &path);
+
+ QMutex lock;
+ dispatch_queue_t queue;
+ FSEventStreamRef stream;
+ FilesByPath watchedFiles;
+ DirsByName watchedDirectories;
+ PathRefCounts watchedPaths;
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_FILESYSTEMWATCHER
+#endif // QFILESYSTEMWATCHER_FSEVENTS_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index c731f3d417..5fd20c6d74 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -129,9 +129,9 @@
# define __NR_inotify_rm_watch 271
# define __NR_inotify_init1 314
#elif defined (__avr32__)
-# define __NR_inotify_init 240
-# define __NR_inotify_add_watch 241
-# define __NR_inotify_rm_watch 242
+# define __NR_inotify_init 240
+# define __NR_inotify_add_watch 241
+# define __NR_inotify_rm_watch 242
// no inotify_init1 for AVR32
#elif defined (__mc68000__)
# define __NR_inotify_init 284
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index a5f077bd0b..064a1a511f 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -45,6 +45,7 @@
#include "private/qcore_unix_p.h"
#include "qfilesystementry_p.h"
#include "qfilesystemengine_p.h"
+#include "qcoreapplication.h"
#ifndef QT_NO_FSFILEENGINE
@@ -142,6 +143,16 @@ static inline bool setCloseOnExec(int fd)
return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
}
+static inline QString msgOpenDirectory()
+{
+ const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
+#ifndef QT_BOOTSTRAPPED
+ return QIODevice::tr(message);
+#else
+ return QLatin1String(message);
+#endif
+}
+
/*!
\internal
*/
@@ -169,7 +180,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
// we had received EISDIR anyway.
if (QFileSystemEngine::fillMetaData(fd, metaData)
&& metaData.isDirectory()) {
- q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
+ q->setError(QFile::OpenError, msgOpenDirectory());
QT_CLOSE(fd);
return false;
}
@@ -210,7 +221,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
// we had received EISDIR anyway.
if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData)
&& metaData.isDirectory()) {
- q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
+ q->setError(QFile::OpenError, msgOpenDirectory());
fclose(fh);
return false;
}
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 2b38019674..c974daab06 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -60,14 +60,18 @@
# include <types.h>
#endif
#include <objbase.h>
-#include <shlobj.h>
+#ifndef Q_OS_WINRT
+# include <shlobj.h>
+# include <accctrl.h>
+#endif
#include <initguid.h>
-#include <accctrl.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
-#define SECURITY_WIN32
-#include <security.h>
+#ifndef Q_OS_WINRT
+# define SECURITY_WIN32
+# include <security.h>
+#endif
#ifndef PATH_MAX
#define PATH_MAX FILENAME_MAX
@@ -93,7 +97,7 @@ QString QFSFileEnginePrivate::longFileName(const QString &path)
return path;
QString absPath = QFileSystemEngine::nativeAbsoluteFilePath(path);
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
QString prefix = QLatin1String("\\\\?\\");
if (isUncPath(absPath)) {
prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\"
@@ -121,11 +125,12 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
if (openMode & QIODevice::WriteOnly)
accessRights |= GENERIC_WRITE;
- SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
// WriteOnly can create files, ReadOnly cannot.
DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING;
// Create the file handle.
+#ifndef Q_OS_WINRT
+ SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
fileHandle = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
accessRights,
shareMode,
@@ -133,6 +138,13 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
creationDisp,
FILE_ATTRIBUTE_NORMAL,
NULL);
+#else // !Q_OS_WINRT
+ fileHandle = CreateFile2((const wchar_t*)fileEntry.nativeFilePath().utf16(),
+ accessRights,
+ shareMode,
+ creationDisp,
+ NULL);
+#endif // Q_OS_WINRT
// Bail out on error.
if (fileHandle == INVALID_HANDLE_VALUE) {
@@ -473,7 +485,7 @@ int QFSFileEnginePrivate::nativeHandle() const
*/
bool QFSFileEnginePrivate::nativeIsSequential() const
{
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
HANDLE handle = fileHandle;
if (fh || fd != -1)
handle = (HANDLE)_get_osfhandle(fh ? QT_FILENO(fh) : fd);
@@ -577,7 +589,7 @@ bool QFSFileEngine::setCurrentPath(const QString &path)
QString QFSFileEngine::currentPath(const QString &fileName)
{
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
QString ret;
//if filename is a drive: then get the pwd of that drive
if (fileName.length() >= 2 &&
@@ -596,10 +608,10 @@ QString QFSFileEngine::currentPath(const QString &fileName)
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
return ret;
-#else
+#else // !Q_OS_WINCE && !Q_OS_WINRT
Q_UNUSED(fileName);
return QFileSystemEngine::currentPath().filePath();
-#endif
+#endif // Q_OS_WINCE || Q_OS_WINRT
}
QString QFSFileEngine::homePath()
@@ -620,7 +632,7 @@ QString QFSFileEngine::tempPath()
QFileInfoList QFSFileEngine::drives()
{
QFileInfoList ret;
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
#if defined(Q_OS_WIN32)
quint32 driveBits = (quint32) GetLogicalDrives() & 0x3ffffff;
#endif
@@ -633,10 +645,10 @@ QFileInfoList QFSFileEngine::drives()
driveBits = driveBits >> 1;
}
return ret;
-#else
+#else // !Q_OS_WINCE && !Q_OS_WINRT
ret.append(QFileInfo(QLatin1String("/")));
return ret;
-#endif
+#endif // Q_OS_WINCE || Q_OS_WINRT
}
bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
@@ -661,7 +673,7 @@ bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) cons
bool QFSFileEngine::link(const QString &newName)
{
-#if !defined(Q_OS_WINCE)
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
#if !defined(QT_NO_LIBRARY)
bool ret = false;
@@ -707,7 +719,7 @@ bool QFSFileEngine::link(const QString &newName)
Q_UNUSED(newName);
return false;
#endif // QT_NO_LIBRARY
-#else
+#elif defined(Q_OS_WINCE)
QString linkName = newName;
linkName.replace(QLatin1Char('/'), QLatin1Char('\\'));
if (!linkName.endsWith(QLatin1String(".lnk")))
@@ -720,7 +732,11 @@ bool QFSFileEngine::link(const QString &newName)
if (!ret)
setError(QFile::RenameError, qt_error_string());
return ret;
-#endif // Q_OS_WINCE
+#else // Q_OS_WINCE
+ Q_UNUSED(newName);
+ Q_UNIMPLEMENTED();
+ return false;
+#endif // Q_OS_WINRT
}
/*!
@@ -937,6 +953,7 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
QFile::MemoryMapFlags flags)
{
+#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QFile::NotOpen) {
@@ -980,7 +997,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
// first create the file mapping handle
DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY;
+#ifndef Q_OS_WINRT
mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0);
+#else
+ mapHandle = ::CreateFileMappingFromApp(handle, 0, protection, 0, 0);
+#endif
if (mapHandle == NULL) {
q->setError(QFile::PermissionsError, qt_error_string());
#ifdef Q_USE_DEPRECATED_MAP_API
@@ -998,15 +1019,23 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
DWORD offsetHi = offset >> 32;
DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
SYSTEM_INFO sysinfo;
+#ifndef Q_OS_WINRT
::GetSystemInfo(&sysinfo);
+#else
+ ::GetNativeSystemInfo(&sysinfo);
+#endif
DWORD mask = sysinfo.dwAllocationGranularity - 1;
DWORD extra = offset & mask;
if (extra)
offsetLo &= ~mask;
// attempt to create the map
+#ifndef Q_OS_WINRT
LPVOID mapAddress = ::MapViewOfFile(mapHandle, access,
offsetHi, offsetLo, size + extra);
+#else
+ LPVOID mapAddress = ::MapViewOfFileFromApp(mapHandle, access, offset, size);
+#endif
if (mapAddress) {
uchar *address = extra + static_cast<uchar*>(mapAddress);
maps[address] = extra;
@@ -1025,11 +1054,18 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
::CloseHandle(mapHandle);
mapHandle = NULL;
+#else // !Q_OS_WINPHONE
+ Q_UNUSED(offset);
+ Q_UNUSED(size);
+ Q_UNUSED(flags);
+ Q_UNIMPLEMENTED();
+#endif // Q_OS_WINPHONE
return 0;
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
+#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
@@ -1048,6 +1084,11 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
}
return true;
+#else // !Q_OS_WINPHONE
+ Q_UNUSED(ptr);
+ Q_UNIMPLEMENTED();
+ return false;
+#endif // Q_OS_WINPHONE
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index b5f6d9f3da..28f6b02a64 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
- SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
const QFileSystemEntry fileEntry(fileName);
// When writing, allow others to read.
// When reading, QFile will allow others to read and write, all good.
@@ -60,6 +59,8 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
// but Windows doesn't allow recreating it while this handle is open anyway,
// so this would only create confusion (can't lock, but no lock file to read from).
const DWORD dwShareMode = FILE_SHARE_READ;
+#ifndef Q_OS_WINRT
+ SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
HANDLE fh = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
GENERIC_WRITE,
dwShareMode,
@@ -67,6 +68,13 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
CREATE_NEW, // error if already exists
FILE_ATTRIBUTE_NORMAL,
NULL);
+#else // !Q_OS_WINRT
+ HANDLE fh = CreateFile2((const wchar_t*)fileEntry.nativeFilePath().utf16(),
+ GENERIC_WRITE,
+ dwShareMode,
+ CREATE_NEW, // error if already exists
+ NULL);
+#endif // Q_OS_WINRT
if (fh == INVALID_HANDLE_VALUE) {
const DWORD lastError = GetLastError();
switch (lastError) {
@@ -112,6 +120,9 @@ bool QLockFilePrivate::isApparentlyStale() const
if (!getLockInfo(&pid, &hostname, &appname))
return false;
+ // On WinRT there seems to be no way of obtaining information about other
+ // processes due to sandboxing
+#ifndef Q_OS_WINRT
HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!procHandle)
return true;
@@ -120,6 +131,7 @@ bool QLockFilePrivate::isApparentlyStale() const
::CloseHandle(procHandle);
if (dwR == WAIT_TIMEOUT)
return true;
+#endif // !Q_OS_WINRT
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime;
}
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
index 4924ac89c6..f37b9575aa 100644
--- a/src/corelib/io/qloggingcategory.cpp
+++ b/src/corelib/io/qloggingcategory.cpp
@@ -83,16 +83,65 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
\section1 Default category configuration
- In the default configuration \l isWarningEnabled() and \l isCriticalEnabled()
- will return \c true. \l isDebugEnabled() will return \c true only
- for the \c "default" category.
+ In the default configuration \l isWarningEnabled() , \l isDebugEnabled() and
+ \l isCriticalEnabled() will return \c true.
- \section1 Changing the configuration of a category
+ \section1 Configuring Categories
- Use either \l setFilterRules() or \l installFilter() to
- configure categories, for example
+ Categories can be centrally configured by either setting logging rules,
+ or by installing a custom filter.
- \snippet qloggingcategory/main.cpp 2
+ \section2 Logging Rules
+
+ Logging rules allow to enable or disable logging for categories in a flexible
+ way. Rules are specified in text, where every line must have the format
+
+ \code
+ <category>[.<type>] = true|false
+ \endcode
+
+ \c <category> is the name of the category, potentially with \c{*} as a
+ wildcard symbol as the first or last character (or at both positions).
+ The optional \c <type> must be either \c debug, \c warning, or \c critical.
+ Lines that do not fit to his scheme are ignored.
+
+ Rules are evaluated in text order, from first to last. That is, if two rules
+ apply to a category/type, the rule that comes later is applied.
+
+ Rules can be set via \l setFilterRules(). Since Qt 5.3 logging rules
+ are also automatically loaded from the \c [rules] section of a logging
+ configuration file. Such configuration files are looked up in the QtProject
+ configuration directory, or explicitly set in a \c QT_LOGGING_CONF
+ environment variable.
+
+ Rules set by \l setFilterRules() take precedence over rules specified
+ in the QtProject configuration directory, and can, in turn, be
+ overwritten by rules from the configuration file specified by
+ \c QT_LOGGING_CONF.
+
+ Order of evaluation:
+ \list
+ \li Rules from QtProject/qlogging.ini
+ \li Rules set by \l setFilterRules()
+ \li Rules from file in \c QT_LOGGING_CONF
+ \endlist
+
+ The \c QtProject/qlogging.ini file is looked up in all directories returned
+ by QStandardPaths::GenericConfigLocation, e.g.
+
+ \list
+ \li on Mac OS X: \c ~/Library/Preferences
+ \li on Unix: \c ~/.config, \c /etc/xdg
+ \li on Windows: \c %LOCALAPPDATA%, \c %ProgramData%,
+ \l QCoreApplication::applicationDirPath(),
+ QCoreApplication::applicationDirPath() + \c "/data"
+ \endlist
+
+ \section2 Installing a Custom Filter
+
+ As a lower-level alternative to the text rules you can also implement a
+ custom filter via \l installFilter(). All filter rules are ignored in this
+ case.
\section1 Printing the category
@@ -111,21 +160,20 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
QLoggingCategory::QLoggingCategory(const char *category)
: d(0),
name(0),
- enabledDebug(false),
+ enabledDebug(true),
enabledWarning(true),
enabledCritical(true)
{
Q_UNUSED(d);
Q_UNUSED(placeholder);
- bool isDefaultCategory
+ const bool isDefaultCategory
= (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0);
+ // normalize "default" category name, so that we can just do
+ // pointer comparison in QLoggingRegistry::updateCategory
if (isDefaultCategory) {
- // normalize default category names, so that we can just do
- // pointer comparison in QLoggingRegistry::updateCategory
name = qtDefaultCategoryName;
- enabledDebug = true;
} else {
name = category;
}
@@ -226,6 +274,14 @@ void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
*/
/*!
+ \fn const QLoggingCategory &QLoggingCategory::operator()() const
+
+ Returns the object itself. This allows both a QLoggingCategory variable, and
+ a factory method returning a QLoggingCategory, to be used in \l qCDebug(),
+ \l qCWarning(), \l qCCritical() macros.
+ */
+
+/*!
Returns a pointer to the global category \c "default" that
is used e.g. by qDebug(), qWarning(), qCritical(), qFatal().
@@ -280,27 +336,18 @@ QLoggingCategory::installFilter(QLoggingCategory::CategoryFilter filter)
Configures which categories and message types should be enabled through a
a set of \a rules.
- Each line in \a rules must have the format
-
- \code
- <category>[.<type>] = true|false
- \endcode
-
- where \c <category> is the name of the category, potentially with \c{*} as a
- wildcard symbol at the start and/or the end. The optional \c <type> must
- be either \c debug, \c warning, or \c critical.
-
Example:
\snippet qloggingcategory/main.cpp 2
\note The rules might be ignored if a custom category filter is installed
- with \l installFilter().
+ with \l installFilter(), or if the user defined a custom logging
+ configuration file in the \c QT_LOGGING_CONF environment variable.
*/
void QLoggingCategory::setFilterRules(const QString &rules)
{
- QLoggingRegistry::instance()->rulesParser.setRules(rules);
+ QLoggingRegistry::instance()->setApiRules(rules);
}
/*!
@@ -326,6 +373,25 @@ void QLoggingCategory::setFilterRules(const QString &rules)
*/
/*!
+ \macro qCDebug(category, const char *message, ...)
+ \relates QLoggingCategory
+ \since 5.3
+
+ Logs a debug message \a message in the logging category \a category.
+ \a message might contain place holders that are replaced by additional
+ arguments, similar to the C printf() function.
+
+ Example:
+
+ \snippet qloggingcategory/main.cpp 13
+
+ \note Arguments might not be processed if debug output for the category is
+ not enabled, so do not rely on any side effects.
+
+ \sa qDebug()
+*/
+
+/*!
\macro qCWarning(category)
\relates QLoggingCategory
\since 5.2
@@ -348,6 +414,25 @@ void QLoggingCategory::setFilterRules(const QString &rules)
*/
/*!
+ \macro qCWarning(category, const char *message, ...)
+ \relates QLoggingCategory
+ \since 5.3
+
+ Logs a warning message \a message in the logging category \a category.
+ \a message might contain place holders that are replaced by additional
+ arguments, similar to the C printf() function.
+
+ Example:
+
+ \snippet qloggingcategory/main.cpp 14
+
+ \note Arguments might not be processed if warning output for the category is
+ not enabled, so do not rely on any side effects.
+
+ \sa qWarning()
+*/
+
+/*!
\macro qCCritical(category)
\relates QLoggingCategory
\since 5.2
@@ -370,6 +455,24 @@ void QLoggingCategory::setFilterRules(const QString &rules)
*/
/*!
+ \macro qCCritical(category, const char *message, ...)
+ \relates QLoggingCategory
+ \since 5.3
+
+ Logs a critical message \a message in the logging category \a category.
+ \a message might contain place holders that are replaced by additional
+ arguments, similar to the C printf() function.
+
+ Example:
+
+ \snippet qloggingcategory/main.cpp 15
+
+ \note Arguments might not be processed if critical output for the category
+ is not enabled, so do not rely on any side effects.
+
+ \sa qCritical()
+*/
+/*!
\macro Q_DECLARE_LOGGING_CATEGORY(name)
\relates QLoggingCategory
\since 5.2
diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h
index 15c0519827..4aec8e63bf 100644
--- a/src/corelib/io/qloggingcategory.h
+++ b/src/corelib/io/qloggingcategory.h
@@ -65,6 +65,7 @@ public:
// allows usage of both factory method and variable in qCX macros
QLoggingCategory &operator()() { return *this; }
+ const QLoggingCategory &operator()() const { return *this; }
static QLoggingCategory *defaultCategory();
@@ -84,25 +85,36 @@ private:
};
#define Q_DECLARE_LOGGING_CATEGORY(name) \
- extern QLoggingCategory &name();
+ extern const QLoggingCategory &name();
// relies on QLoggingCategory(QString) being thread safe!
#define Q_LOGGING_CATEGORY(name, string) \
- QLoggingCategory &name() \
+ const QLoggingCategory &name() \
{ \
- static QLoggingCategory category(string); \
+ static const QLoggingCategory category(string); \
return category; \
}
-#define qCDebug(category) \
- for (bool enabled = category().isDebugEnabled(); Q_UNLIKELY(enabled); enabled = false) \
- QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug()
-#define qCWarning(category) \
- for (bool enabled = category().isWarningEnabled(); enabled; enabled = false) \
- QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).warning()
-#define qCCritical(category) \
- for (bool enabled = category().isCriticalEnabled(); enabled; enabled = false) \
- QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical()
+#ifdef Q_COMPILER_VARIADIC_MACROS
+
+#define qCDebug(category, ...) \
+ for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug(__VA_ARGS__)
+#define qCWarning(category, ...) \
+ for (bool qt_category_enabled = category().isWarningEnabled(); qt_category_enabled; qt_category_enabled = false) \
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).warning(__VA_ARGS__)
+#define qCCritical(category, ...) \
+ for (bool qt_category_enabled = category().isCriticalEnabled(); qt_category_enabled; qt_category_enabled = false) \
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical(__VA_ARGS__)
+
+#else
+
+// check for enabled category inside QMessageLogger.
+#define qCDebug qDebug
+#define qCWarning qWarning
+#define qCCritical qCritical
+
+#endif // Q_COMPILER_VARIADIC_MACROS
#if defined(QT_NO_DEBUG_OUTPUT)
# undef qCDebug
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index a82e6f65f4..b8fef16c0e 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -42,6 +42,10 @@
#include "qloggingregistry_p.h"
#include "qloggingcategory_p.h"
+#include <QtCore/qfile.h>
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qtextstream.h>
+
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry)
@@ -150,33 +154,38 @@ void QLoggingRule::parse()
}
/*!
+ \class QLoggingSettingsParser
+ \since 5.3
\internal
- Creates a new QLoggingRules object.
+
+ Parses a .ini file with the following format:
+
+ [rules]
+ rule1=[true|false]
+ rule2=[true|false]
+ ...
+
+ [rules] is the default section, and therefore optional.
*/
-QLoggingRulesParser::QLoggingRulesParser(QLoggingRegistry *registry) :
- registry(registry)
-{
-}
/*!
\internal
- Sets logging rules string.
+ Parses configuration from \a content.
*/
-void QLoggingRulesParser::setRules(const QString &content)
+void QLoggingSettingsParser::setContent(const QString &content)
{
QString content_ = content;
QTextStream stream(&content_, QIODevice::ReadOnly);
- parseRules(stream);
+ setContent(stream);
}
/*!
\internal
- Parses rules out of a QTextStream.
+ Parses configuration from \a stream.
*/
-void QLoggingRulesParser::parseRules(QTextStream &stream)
+void QLoggingSettingsParser::setContent(QTextStream &stream)
{
- QVector<QLoggingRule> rules;
-
+ _rules.clear();
while (!stream.atEnd()) {
QString line = stream.readLine();
@@ -184,31 +193,79 @@ void QLoggingRulesParser::parseRules(QTextStream &stream)
line = line.simplified();
line.remove(QLatin1Char(' '));
- const QStringList pair = line.split(QLatin1Char('='));
- if (pair.count() == 2) {
- const QString pattern = pair.at(0);
- bool enabled = (QString::compare(pair.at(1),
- QLatin1String("true"),
- Qt::CaseInsensitive) == 0);
- rules.append(QLoggingRule(pattern, enabled));
+ // comment
+ if (line.startsWith(QLatin1Char(';')))
+ continue;
+
+ if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
+ // new section
+ _section = line.mid(1, line.size() - 2);
+ continue;
}
- }
- registry->setRules(rules);
+ if (_section == QLatin1String("rules")) {
+ int equalPos = line.indexOf(QLatin1Char('='));
+ if ((equalPos != -1)
+ && (line.lastIndexOf(QLatin1Char('=')) == equalPos)) {
+ const QString pattern = line.left(equalPos);
+ const QStringRef value = line.midRef(equalPos + 1);
+ bool enabled = (value.compare(QLatin1String("true"),
+ Qt::CaseInsensitive) == 0);
+ _rules.append(QLoggingRule(pattern, enabled));
+ }
+ }
+ }
}
/*!
\internal
- QLoggingPrivate constructor
+ QLoggingRegistry constructor
*/
QLoggingRegistry::QLoggingRegistry()
- : rulesParser(this),
- categoryFilter(defaultCategoryFilter)
+ : categoryFilter(defaultCategoryFilter)
{
}
/*!
\internal
+ Initializes the rules database by loading
+ .config/QtProject/qtlogging.ini and $QT_LOGGING_CONF.
+ */
+void QLoggingRegistry::init()
+{
+ // get rules from environment
+ const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
+ if (!rulesFilePath.isEmpty()) {
+ QFile file(QFile::decodeName(rulesFilePath));
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream stream(&file);
+ QLoggingSettingsParser parser;
+ parser.setContent(stream);
+ envRules = parser.rules();
+ }
+ }
+
+ // get rules from qt configuration
+ QString envPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation,
+ QStringLiteral("QtProject/qtlogging.ini"));
+ if (!envPath.isEmpty()) {
+ QFile file(envPath);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream stream(&file);
+ QLoggingSettingsParser parser;
+ parser.setContent(stream);
+ configRules = parser.rules();
+ }
+ }
+
+ if (!envRules.isEmpty() || !configRules.isEmpty()) {
+ QMutexLocker locker(&registryMutex);
+ updateRules();
+ }
+}
+
+/*!
+ \internal
Registers a category object.
This method might be called concurrently for the same category object.
@@ -236,17 +293,33 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
/*!
\internal
- Activates a new set of logging rules for the default filter.
-*/
-void QLoggingRegistry::setRules(const QVector<QLoggingRule> &rules_)
+ Installs logging rules as specified in \a content.
+ */
+void QLoggingRegistry::setApiRules(const QString &content)
{
+ QLoggingSettingsParser parser;
+ parser.setSection(QStringLiteral("rules"));
+ parser.setContent(content);
+
QMutexLocker locker(&registryMutex);
+ apiRules = parser.rules();
- rules = rules_;
+ updateRules();
+}
+
+/*!
+ \internal
+ Activates a new set of logging rules for the default filter.
+ (The caller must lock registryMutex to make sure the API is thread safe.)
+*/
+void QLoggingRegistry::updateRules()
+{
if (categoryFilter != defaultCategoryFilter)
return;
+ rules = configRules + apiRules + envRules;
+
foreach (QLoggingCategory *cat, categories)
(*categoryFilter)(cat);
}
@@ -283,9 +356,13 @@ QLoggingRegistry *QLoggingRegistry::instance()
*/
void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
{
- // QLoggingCategory() normalizes all "default" strings
+ // QLoggingCategory() normalizes "default" strings
// to qtDefaultCategoryName
- bool debug = (cat->categoryName() == qtDefaultCategoryName);
+ bool debug = true;
+ char c;
+ if (!memcmp(cat->categoryName(), "qt", 2) && (!(c = cat->categoryName()[2]) || c == '.'))
+ debug = false;
+
bool warning = true;
bool critical = true;
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index cbf7aecc4f..d4b97d42b8 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -60,6 +60,8 @@
#include <QtCore/qtextstream.h>
#include <QtCore/qvector.h>
+class tst_QLoggingRegistry;
+
QT_BEGIN_NAMESPACE
class QLoggingRule
@@ -89,45 +91,53 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QLoggingRule::PatternFlags)
Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE);
-class QLoggingRulesParser
+class Q_AUTOTEST_EXPORT QLoggingSettingsParser
{
-private:
- explicit QLoggingRulesParser(class QLoggingRegistry *logging);
-
public:
- void setRules(const QString &content);
+ void setSection(const QString &section) { _section = section; }
-private:
- void parseRules(QTextStream &stream);
- QLoggingRegistry *registry;
+ void setContent(const QString &content);
+ void setContent(QTextStream &stream);
+
+ QVector<QLoggingRule> rules() const { return _rules; }
- friend class QLoggingRegistry;
+private:
+ QString _section;
+ QVector<QLoggingRule> _rules;
};
-class QLoggingRegistry
+class Q_AUTOTEST_EXPORT QLoggingRegistry
{
public:
QLoggingRegistry();
+ void init();
+
void registerCategory(QLoggingCategory *category);
void unregisterCategory(QLoggingCategory *category);
- void setRules(const QVector<QLoggingRule> &rules);
+ void setApiRules(const QString &content);
QLoggingCategory::CategoryFilter
installFilter(QLoggingCategory::CategoryFilter filter);
static QLoggingRegistry *instance();
- QLoggingRulesParser rulesParser;
-
private:
+ void updateRules();
+
static void defaultCategoryFilter(QLoggingCategory *category);
QMutex registryMutex;
+
+ QVector<QLoggingRule> configRules;
+ QVector<QLoggingRule> envRules;
+ QVector<QLoggingRule> apiRules;
QVector<QLoggingRule> rules;
QList<QLoggingCategory*> categories;
QLoggingCategory::CategoryFilter categoryFilter;
+
+ friend class ::tst_QLoggingRegistry;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index ab2a69d054..3b78351809 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -1545,16 +1545,40 @@ void QProcess::setWorkingDirectory(const QString &dir)
d->workingDirectory = dir;
}
+
/*!
+ \deprecated
+ Use processId() instead.
+
Returns the native process identifier for the running process, if
- available. If no process is currently running, 0 is returned.
+ available. If no process is currently running, \c 0 is returned.
+
+ \note Unlike \l processId(), pid() returns an integer on Unix and a pointer on Windows.
+
+ \sa Q_PID, processId()
*/
-Q_PID QProcess::pid() const
+Q_PID QProcess::pid() const // ### Qt 6 remove or rename this method to processInformation()
{
Q_D(const QProcess);
return d->pid;
}
+/*!
+ \since 5.3
+
+ Returns the native process identifier for the running process, if
+ available. If no process is currently running, \c 0 is returned.
+ */
+qint64 QProcess::processId() const
+{
+ Q_D(const QProcess);
+#ifdef Q_OS_WIN
+ return d->pid ? d->pid->dwProcessId : 0;
+#else
+ return d->pid;
+#endif
+}
+
/*! \reimp
This function operates on the current read channel.
@@ -2388,14 +2412,14 @@ int QProcess::execute(const QString &program)
identifier of the started process.
*/
bool QProcess::startDetached(const QString &program,
- const QStringList &arguments,
- const QString &workingDirectory,
+ const QStringList &arguments,
+ const QString &workingDirectory,
qint64 *pid)
{
return QProcessPrivate::startDetached(program,
- arguments,
- workingDirectory,
- pid);
+ arguments,
+ workingDirectory,
+ pid);
}
/*!
@@ -2414,7 +2438,7 @@ bool QProcess::startDetached(const QString &program,
The started process will run as a regular standalone process.
*/
bool QProcess::startDetached(const QString &program,
- const QStringList &arguments)
+ const QStringList &arguments)
{
return QProcessPrivate::startDetached(program, arguments);
}
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index c0b3ab945e..6be267f15f 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -187,6 +187,7 @@ public:
// #### Qt 5: Q_PID is a pointer on Windows and a value on Unix
Q_PID pid() const;
+ qint64 processId() const;
bool waitForStarted(int msecs = 30000);
bool waitForReadyRead(int msecs = 30000);
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 3c6d294916..4076ec5855 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -1107,7 +1107,7 @@ bool QProcessPrivate::waitForStarted(int msecs)
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::waitForStarted(%d) waiting for child to start (fd = %d)", msecs,
- childStartedPipe[0]);
+ childStartedPipe[0]);
#endif
fd_set fds;
@@ -1172,32 +1172,32 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
if (ret == 0) {
processError = QProcess::Timedout;
q->setErrorString(QProcess::tr("Process operation timed out"));
- return false;
- }
+ return false;
+ }
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+ if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
if (!_q_startupNotification())
return false;
- }
+ }
bool readyReadEmitted = false;
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
- bool canRead = _q_canReadStandardOutput();
+ if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
+ bool canRead = _q_canReadStandardOutput();
if (processChannel == QProcess::StandardOutput && canRead)
readyReadEmitted = true;
- }
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
- bool canRead = _q_canReadStandardError();
+ }
+ if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
+ bool canRead = _q_canReadStandardError();
if (processChannel == QProcess::StandardError && canRead)
readyReadEmitted = true;
- }
+ }
if (readyReadEmitted)
return true;
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
- _q_canWrite();
+ if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+ _q_canWrite();
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
if (_q_processDied())
return false;
}
@@ -1248,26 +1248,26 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
}
if (ret == 0) {
- processError = QProcess::Timedout;
- q->setErrorString(QProcess::tr("Process operation timed out"));
- return false;
- }
+ processError = QProcess::Timedout;
+ q->setErrorString(QProcess::tr("Process operation timed out"));
+ return false;
+ }
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
- if (!_q_startupNotification())
- return false;
- }
+ if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+ if (!_q_startupNotification())
+ return false;
+ }
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
- return _q_canWrite();
+ if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+ return _q_canWrite();
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
- _q_canReadStandardOutput();
+ if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
+ _q_canReadStandardOutput();
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
- _q_canReadStandardError();
+ if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
+ _q_canReadStandardError();
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
if (_q_processDied())
return false;
}
@@ -1317,29 +1317,29 @@ bool QProcessPrivate::waitForFinished(int msecs)
if (ret < 0) {
break;
}
- if (ret == 0) {
- processError = QProcess::Timedout;
- q->setErrorString(QProcess::tr("Process operation timed out"));
- return false;
- }
-
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
- if (!_q_startupNotification())
- return false;
- }
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
- _q_canWrite();
-
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
- _q_canReadStandardOutput();
-
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
- _q_canReadStandardError();
-
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (ret == 0) {
+ processError = QProcess::Timedout;
+ q->setErrorString(QProcess::tr("Process operation timed out"));
+ return false;
+ }
+
+ if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+ if (!_q_startupNotification())
+ return false;
+ }
+ if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+ _q_canWrite();
+
+ if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
+ _q_canReadStandardOutput();
+
+ if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
+ _q_canReadStandardError();
+
+ if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
if (_q_processDied())
return true;
- }
+ }
}
return false;
}
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index fc2adb783e..d7050034bd 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -623,7 +623,7 @@ static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId)
DWORD currentProcId = 0;
GetWindowThreadProcessId(hwnd, &currentProcId);
if (currentProcId == (DWORD)procId)
- PostMessage(hwnd, WM_CLOSE, 0, 0);
+ PostMessage(hwnd, WM_CLOSE, 0, 0);
return TRUE;
}
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index c16b8d79a2..bfd0eef64f 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -1092,8 +1092,8 @@ QResource::unregisterResource(const QString &rccFilename, const QString &resourc
for(int i = 0; i < list->size(); ++i) {
QResourceRoot *res = list->at(i);
if(res->type() == QResourceRoot::Resource_File) {
- QDynamicFileResourceRoot *root = reinterpret_cast<QDynamicFileResourceRoot*>(res);
- if(root->mappingFile() == rccFilename && root->mappingRoot() == r) {
+ QDynamicFileResourceRoot *root = reinterpret_cast<QDynamicFileResourceRoot*>(res);
+ if (root->mappingFile() == rccFilename && root->mappingRoot() == r) {
resourceList()->removeAt(i);
if(!root->ref.deref()) {
delete root;
@@ -1101,7 +1101,7 @@ QResource::unregisterResource(const QString &rccFilename, const QString &resourc
}
return false;
}
- }
+ }
}
return false;
}
@@ -1163,16 +1163,16 @@ QResource::unregisterResource(const uchar *rccData, const QString &resourceRoot)
for(int i = 0; i < list->size(); ++i) {
QResourceRoot *res = list->at(i);
if(res->type() == QResourceRoot::Resource_Buffer) {
- QDynamicBufferResourceRoot *root = reinterpret_cast<QDynamicBufferResourceRoot*>(res);
- if(root->mappingBuffer() == rccData && root->mappingRoot() == r) {
+ QDynamicBufferResourceRoot *root = reinterpret_cast<QDynamicBufferResourceRoot*>(res);
+ if (root->mappingBuffer() == rccData && root->mappingRoot() == r) {
resourceList()->removeAt(i);
if(!root->ref.deref()) {
delete root;
return true;
}
- return false;
+ return false;
}
- }
+ }
}
return false;
}
@@ -1381,13 +1381,13 @@ QString QResourceFileEngine::fileName(FileName file) const
{
Q_D(const QResourceFileEngine);
if(file == BaseName) {
- int slash = d->resource.fileName().lastIndexOf(QLatin1Char('/'));
- if (slash == -1)
- return d->resource.fileName();
- return d->resource.fileName().mid(slash + 1);
+ int slash = d->resource.fileName().lastIndexOf(QLatin1Char('/'));
+ if (slash == -1)
+ return d->resource.fileName();
+ return d->resource.fileName().mid(slash + 1);
} else if(file == PathName || file == AbsolutePathName) {
const QString path = (file == AbsolutePathName) ? d->resource.absoluteFilePath() : d->resource.fileName();
- const int slash = path.lastIndexOf(QLatin1Char('/'));
+ const int slash = path.lastIndexOf(QLatin1Char('/'));
if (slash == -1)
return QLatin1String(":");
else if (slash <= 1)
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 35b3ed4e3d..a3727a6a4b 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -78,14 +78,27 @@
#ifdef Q_OS_WIN // for homedirpath reading from registry
# include <private/qsystemlibrary_p.h>
# include <qt_windows.h>
+# ifndef Q_OS_WINRT
+# include <shlobj.h>
+# endif
+#endif
+
+#ifdef Q_OS_WINRT
+#include <wrl.h>
+#include <windows.foundation.h>
+#include <windows.storage.h>
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Storage;
#endif
#ifndef CSIDL_COMMON_APPDATA
-#define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data
+#define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data
#endif
#ifndef CSIDL_APPDATA
-#define CSIDL_APPDATA 0x001a // <username>\Application Data
+#define CSIDL_APPDATA 0x001a // <username>\Application Data
#endif
#ifdef Q_AUTOTEST_EXPORT
@@ -365,7 +378,7 @@ after_loop:
// see also qsettings_win.cpp and qsettings_mac.cpp
-#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
+#if defined(Q_OS_WINRT) || (!defined(Q_OS_WIN) && !defined(Q_OS_MAC))
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
{
@@ -373,7 +386,7 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::
}
#endif
-#if !defined(Q_OS_WIN)
+#if defined(Q_OS_WINRT) || !defined(Q_OS_WIN)
QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
{
return new QConfFileSettingsPrivate(fileName, format);
@@ -1021,23 +1034,14 @@ void QConfFileSettingsPrivate::initAccess()
sync(); // loads the files the first time
}
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
static QString windowsConfigPath(int type)
{
QString result;
-#ifndef Q_OS_WINCE
- QSystemLibrary library(QLatin1String("shell32"));
-#else
- QSystemLibrary library(QLatin1String("coredll"));
-#endif // Q_OS_WINCE
- typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL);
- GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW");
- if (SHGetSpecialFolderPath) {
- wchar_t path[MAX_PATH];
- SHGetSpecialFolderPath(0, path, type, false);
+ wchar_t path[MAX_PATH];
+ if (SHGetSpecialFolderPath(0, path, type, false))
result = QString::fromWCharArray(path);
- }
if (result.isEmpty()) {
switch (type) {
@@ -1063,7 +1067,40 @@ static QString windowsConfigPath(int type)
return result;
}
-#endif // Q_OS_WIN
+#elif defined(Q_OS_WINRT) // Q_OS_WIN && !Q_OS_WINRT
+static QString windowsConfigPath(int type)
+{
+ static QString result;
+ while (result.isEmpty()) {
+ ComPtr<IApplicationDataStatics> applicationDataStatics;
+ if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
+ return result;
+ ComPtr<IApplicationData> applicationData;
+ if (FAILED(applicationDataStatics->get_Current(&applicationData)))
+ return result;
+ ComPtr<IStorageFolder> localFolder;
+ if (FAILED(applicationData->get_LocalFolder(&localFolder)))
+ return result;
+ ComPtr<IStorageItem> localFolderItem;
+ if (FAILED(localFolder.As(&localFolderItem)))
+ return result;
+ HSTRING path;
+ if (FAILED(localFolderItem->get_Path(&path)))
+ return result;
+ result = QString::fromWCharArray(WindowsGetStringRawBuffer(path, nullptr));
+ }
+
+ switch (type) {
+ case CSIDL_COMMON_APPDATA:
+ return result + QLatin1String("\\qt-common");
+ case CSIDL_APPDATA:
+ return result + QLatin1String("\\qt-user");
+ default:
+ break;
+ }
+ return result;
+}
+#endif // Q_OS_WINRT
static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
{
@@ -1449,10 +1486,18 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
QString writeSemName = QLatin1String("QSettingsWriteSem ");
writeSemName.append(file.fileName());
+#ifndef Q_OS_WINRT
writeSemaphore = CreateSemaphore(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()));
+#else
+ writeSemaphore = CreateSemaphoreEx(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()), 0, SEMAPHORE_ALL_ACCESS);
+#endif
if (writeSemaphore) {
+#ifndef Q_OS_WINRT
WaitForSingleObject(writeSemaphore, INFINITE);
+#else
+ WaitForSingleObjectEx(writeSemaphore, INFINITE, FALSE);
+#endif
} else {
setStatus(QSettings::AccessError);
return;
@@ -1465,11 +1510,19 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
QString readSemName(QLatin1String("QSettingsReadSem "));
readSemName.append(file.fileName());
+#ifndef Q_OS_WINRT
readSemaphore = CreateSemaphore(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()));
+#else
+ readSemaphore = CreateSemaphoreEx(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()), 0, SEMAPHORE_ALL_ACCESS);
+#endif
if (readSemaphore) {
for (int i = 0; i < numReadLocks; ++i)
+#ifndef Q_OS_WINRT
WaitForSingleObject(readSemaphore, INFINITE);
+#else
+ WaitForSingleObjectEx(readSemaphore, INFINITE, FALSE);
+#endif
} else {
setStatus(QSettings::AccessError);
if (writeSemaphore != 0) {
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index a720b3d709..f44b99d009 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -117,7 +117,7 @@ public:
QSettings(Scope scope, const QString &organization,
const QString &application = QString(), QObject *parent = 0);
QSettings(Format format, Scope scope, const QString &organization,
- const QString &application = QString(), QObject *parent = 0);
+ const QString &application = QString(), QObject *parent = 0);
QSettings(const QString &fileName, Format format, QObject *parent = 0);
explicit QSettings(QObject *parent = 0);
#else
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index 2207b8c43e..bd9fa68d93 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -72,34 +72,240 @@ QT_BEGIN_NAMESPACE
methods such as QStandardPaths::writableLocation, QStandardPaths::standardLocations,
and QStandardPaths::displayName.
- \value DesktopLocation Returns the user's desktop directory.
- \value DocumentsLocation Returns the user's document.
- \value FontsLocation Returns the user's fonts.
- \value ApplicationsLocation Returns the user's applications.
- \value MusicLocation Returns the user's music.
- \value MoviesLocation Returns the user's movies.
- \value PicturesLocation Returns the user's pictures.
- \value TempLocation Returns the system's temporary directory.
- \value HomeLocation Returns the user's home directory.
+ Some of the values in this enum represent a user configuration. Such enum
+ values will return the same paths in different applications, so they could
+ be used to share data with other applications. Other values are specific to
+ this application. Each enum value in the table below describes whether it's
+ application-specific or generic.
+
+ Application-specific directories should be assumed to be unreachable by
+ other applications. Therefore, files placed there might not be readable by
+ other applications, even if run by the same user. On the other hand, generic
+ directories should be assumed to be accessible by all applications run by
+ this user, but should still be assumed to be unreachable by applications by
+ other users.
+
+ The only exception is QStandardPaths::TempLocation (which is the same as
+ QDir::tempPath()): the path returned may be application-specific, but files
+ stored there may be accessed by other applications run by the same user.
+
+ Data interchange with other users is out of the scope of QStandardPaths.
+
+ \value DesktopLocation Returns the user's desktop directory. This is a generic value.
+ On systems with no concept of a desktop, this is the same as
+ QStandardPaths::HomeLocation.
+ \value DocumentsLocation Returns the directory containing user document files.
+ This is a generic value. The returned path is never empty.
+ \value FontsLocation Returns the directory containing user's fonts. This is a generic value.
+ Note that installing fonts may require additional, platform-specific operations.
+ \value ApplicationsLocation Returns the directory containing the user applications
+ (either executables, application bundles, or shortcuts to them). This is a generic value.
+ Note that installing applications may require additional, platform-specific operations.
+ Files, folders or shortcuts in this directory are platform-specific.
+ \value MusicLocation Returns the directory containing the user's music or other audio files.
+ This is a generic value. If no directory specific for music files exists, a sensible
+ fallback for storing user documents is returned.
+ \value MoviesLocation Returns the directory containing the user's movies and videos.
+ This is a generic value. If no directory specific for movie files exists, a sensible
+ fallback for storing user documents is returned.
+ \value PicturesLocation Returns the directory containing the user's pictures or photos.
+ This is a generic value. If no directory specific for picture files exists, a sensible
+ fallback for storing user documents is returned.
+ \value TempLocation Returns a directory where temporary files can be stored. The returned value
+ might be application-specific, shared among other applications for this user, or even
+ system-wide. The returned path is never empty.
+ \value HomeLocation Returns the user's home directory (the same as QDir::homePath()). On Unix
+ systems, this is equal to the HOME environment variable. This value might be
+ generic or application-specific, but the returned path is never empty.
\value DataLocation Returns a directory location where persistent
- application data can be stored. QCoreApplication::organizationName
- and QCoreApplication::applicationName are appended to the directory location
- returned for GenericDataLocation.
+ application data can be stored. This is an application-specific directory. To obtain a
+ path to store data to be shared with other applications, use
+ QStandardPaths::GenericDataLocation. The returned path is never empty.
\value CacheLocation Returns a directory location where user-specific
- non-essential (cached) data should be written.
- \value GenericCacheLocation Returns a directory location where user-specific
- non-essential (cached) data, shared across applications, should be written.
+ non-essential (cached) data should be written. This is an application-specific directory.
+ The returned path is never empty.
+ \value GenericCacheLocation Returns a directory location where user-specific non-essential
+ (cached) data, shared across applications, should be written. This is a generic value.
+ Note that the returned path may be empty if the system has no concept of shared cache.
\value GenericDataLocation Returns a directory location where persistent
- data shared across applications can be stored.
+ data shared across applications can be stored. This is a generic value. The returned
+ path is never empty.
\value RuntimeLocation Returns a directory location where runtime communication
- files should be written. For instance unix local sockets.
+ files should be written, like Unix local sockets. This is a generic value.
+ The returned path may be empty on some systems.
\value ConfigLocation Returns a directory location where user-specific
- configuration files should be written.
+ configuration files should be written. This may be either a generic value
+ or application-specific, and the returned path is never empty.
+ \value DownloadLocation Returns a directory for user's downloaded files. This is a generic value.
+ If no directory specific for downloads exists, a sensible fallback for storing user
+ documents is returned.
\value GenericConfigLocation Returns a directory location where user-specific
configuration files shared between multiple applications should be written.
This is a generic value and the returned path is never empty.
- \value DownloadLocation Returns a directory for user's downloaded files.
+ The following table gives examples of paths on different operating systems.
+ The first path is the writable path (unless noted). Other, additional
+ paths, if any, represent non-writable locations.
+
+ \table
+ \header \li Path type \li OS X \li Windows
+ \row \li DesktopLocation
+ \li "~/Desktop"
+ \li "C:/Users/<USER>/Desktop"
+ \row \li DocumentsLocation
+ \li "~/Documents"
+ \li "C:/Users/<USER>/Documents"
+ \row \li FontsLocation
+ \li "/System/Library/Fonts" (not writable)
+ \li "C:/Windows/Fonts" (not writable)
+ \row \li ApplicationsLocation
+ \li "/Applications" (not writable)
+ \li "C:/Users/<USER>/AppData/Roaming/Microsoft/Windows/Start Menu/Programs"
+ \row \li MusicLocation
+ \li "~/Music"
+ \li "C:/Users/<USER>/Music"
+ \row \li MoviesLocation
+ \li "~/Movies"
+ \li "C:/Users/<USER>/Videos"
+ \row \li PicturesLocation
+ \li "~/Pictures"
+ \li "C:/Users/<USER>/Pictures"
+ \row \li TempLocation
+ \li randomly generated by the OS
+ \li "C:/Users/<USER>/AppData/Local/Temp"
+ \row \li HomeLocation
+ \li "~"
+ \li "C:/Users/<USER>"
+ \row \li DataLocation
+ \li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
+ \row \li CacheLocation
+ \li "~/Library/Caches/<APPNAME>", "/Library/Caches/<APPNAME>"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>/cache"
+ \row \li GenericDataLocation
+ \li "~/Library/Application Support", "/Library/Application Support"
+ \li "C:/Users/<USER>/AppData/Local", "C:/ProgramData"
+ \row \li RuntimeLocation
+ \li "~/Library/Application Support"
+ \li "C:/Users/<USER>"
+ \row \li ConfigLocation
+ \li "~/Library/Preferences"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>"
+ \row \li GenericConfigLocation
+ \li "~/Library/Preferences"
+ \li "C:/Users/<USER>/AppData/Local", "C:/ProgramData"
+ \row \li DownloadLocation
+ \li "~/Documents"
+ \li "C:/Users/<USER>/Documents"
+ \row \li GenericCacheLocation
+ \li "~/Library/Caches", "/Library/Caches"
+ \li "C:/Users/<USER>/AppData/Local/cache"
+ \endtable
+
+ \table
+ \header \li Path type \li Blackberry \li Linux
+ \row \li DesktopLocation
+ \li "<APPROOT>/data"
+ \li "~/Desktop"
+ \row \li DocumentsLocation
+ \li "<APPROOT>/shared/documents"
+ \li "~/Documents"
+ \row \li FontsLocation
+ \li "/base/usr/fonts" (not writable)
+ \li "~/.fonts"
+ \row \li ApplicationsLocation
+ \li not supported (directory not readable)
+ \li "~/.local/share/applications", "/usr/local/share/applications", "/usr/share/applications"
+ \row \li MusicLocation
+ \li "<APPROOT>/shared/music"
+ \li "~/Music"
+ \row \li MoviesLocation
+ \li "<APPROOT>/shared/videos"
+ \li "~/Videos"
+ \row \li PicturesLocation
+ \li "<APPROOT>/shared/photos"
+ \li "~/Pictures"
+ \row \li TempLocation
+ \li "/var/tmp"
+ \li "/tmp"
+ \row \li HomeLocation
+ \li "<APPROOT>/data"
+ \li "~"
+ \row \li DataLocation
+ \li "<APPROOT>/data", "<APPROOT>/app/native/assets"
+ \li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
+ \row \li CacheLocation
+ \li "<APPROOT>/data/Cache"
+ \li "~/.cache/<APPNAME>"
+ \row \li GenericDataLocation
+ \li "<APPROOT>/shared/misc"
+ \li "~/.local/share", "/usr/local/share", "/usr/share"
+ \row \li RuntimeLocation
+ \li "/var/tmp"
+ \li "/run/user/<USER>"
+ \row \li ConfigLocation
+ \li "<APPROOT>/data/Settings"
+ \li "~/.config", "/etc/xdg"
+ \row \li GenericConfigLocation
+ \li "<APPROOT>/data/Settings"
+ \li "~/.config", "/etc/xdg"
+ \row \li DownloadLocation
+ \li "<APPROOT>/shared/downloads"
+ \li "~/Downloads"
+ \row \li GenericCacheLocation
+ \li "<APPROOT>/data/Cache" (there is no shared cache)
+ \li "~/.cache"
+ \endtable
+
+ \table
+ \header \li Path type \li Android
+ \row \li DesktopLocation
+ \li "<APPROOT>/files"
+ \row \li DocumentsLocation
+ \li "<USER>/Documents", "<USER>/<APPNAME>/Documents"
+ \row \li FontsLocation
+ \li "/system/fonts" (not writable)
+ \row \li ApplicationsLocation
+ \li not supported (directory not readable)
+ \row \li MusicLocation
+ \li "<USER>/Music", "<USER>/<APPNAME>/Music"
+ \row \li MoviesLocation
+ \li "<USER>/Movies", "<USER>/<APPNAME>/Movies"
+ \row \li PicturesLocation
+ \li "<USER>/Pictures", "<USER>/<APPNAME>/Pictures"
+ \row \li TempLocation
+ \li "<APPROOT>/cache"
+ \row \li HomeLocation
+ \li "<APPROOT>/files"
+ \row \li DataLocation
+ \li "<APPROOT>/files", "<USER>/<APPNAME>/files"
+ \row \li CacheLocation
+ \li "<APPROOT>/cache", "<USER>/<APPNAME>/cache"
+ \row \li GenericDataLocation
+ \li "<USER>"
+ \row \li RuntimeLocation
+ \li "<APPROOT>/cache"
+ \row \li ConfigLocation
+ \li "<APPROOT>/files/settings"
+ \row \li GenericConfigLocation
+ \li "<APPROOT>/files/settings" (there is no shared settings)
+ \row \li DownloadLocation
+ \li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
+ \row \li GenericCacheLocation
+ \li "<APPROOT>/cache" (there is no shared cache)
+ \endtable
+
+ In the table above, \c <APPNAME> is usually the organization name, the
+ application name, or both, or a unique name generated at packaging.
+ Similarly, <APPROOT> is the location where this application is installed
+ (often a sandbox). <APPDIR> is the directory containing the application
+ executable.
+
+ The paths above should not be relied upon, as they may change according to
+ OS configuration, locale, or they may change in future Qt versions.
+
+ \note On Android, applications with open files on the external storage (<USER> locations),
+ will be killed if the external storage is unmounted.
\sa writableLocation(), standardLocations(), displayName(), locate(), locateAll()
*/
diff --git a/src/corelib/io/qstandardpaths_blackberry.cpp b/src/corelib/io/qstandardpaths_blackberry.cpp
index 815756ff9a..ec2e61bd15 100644
--- a/src/corelib/io/qstandardpaths_blackberry.cpp
+++ b/src/corelib/io/qstandardpaths_blackberry.cpp
@@ -103,10 +103,17 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QStringList QStandardPaths::standardLocations(StandardLocation type)
{
+ QStringList dirs;
+
if (type == FontsLocation)
return QStringList(QLatin1String("/base/usr/fonts"));
- return QStringList(writableLocation(type));
+ if (type == DataLocation)
+ dirs.append(QDir::homePath() + testModeInsert() + QLatin1String("native/assets"));
+
+ const QString localDir = writableLocation(type);
+ dirs.prepend(localDir);
+ return dirs;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstandardpaths_mac.cpp b/src/corelib/io/qstandardpaths_mac.cpp
index 0efdfae253..aff9112fb7 100644
--- a/src/corelib/io/qstandardpaths_mac.cpp
+++ b/src/corelib/io/qstandardpaths_mac.cpp
@@ -47,6 +47,7 @@
#include <qcoreapplication.h>
#endif
+#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
QT_BEGIN_NAMESPACE
@@ -184,6 +185,30 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
dirs.append(path);
}
+ if (type == DataLocation) {
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+ if (mainBundle) {
+ CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
+ CFStringRef cfBundlePath = CFURLCopyPath(bundleUrl);
+ QString bundlePath = QCFString::toQString(cfBundlePath);
+ CFRelease(cfBundlePath);
+ CFRelease(bundleUrl);
+
+ CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(mainBundle);
+ CFStringRef cfResourcesPath = CFURLCopyPath(bundleUrl);
+ QString resourcesPath = QCFString::toQString(cfResourcesPath);
+ CFRelease(cfResourcesPath);
+ CFRelease(resourcesUrl);
+
+ // Handle bundled vs unbundled executables. CFBundleGetMainBundle() returns
+ // a valid bundle in both cases. CFBundleCopyResourcesDirectoryURL() returns
+ // an absolute path for unbundled executables.
+ if (resourcesPath.startsWith(QLatin1Char('/')))
+ dirs.append(resourcesPath);
+ else
+ dirs.append(bundlePath + resourcesPath);
+ }
+ }
const QString localDir = writableLocation(type);
dirs.prepend(localDir);
return dirs;
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index 6a79c7c00b..a0344a0206 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -68,21 +68,6 @@
QT_BEGIN_NAMESPACE
-typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL);
-static GetSpecialFolderPath resolveGetSpecialFolderPath()
-{
- static GetSpecialFolderPath gsfp = 0;
- if (!gsfp) {
-#ifndef Q_OS_WINCE
- QSystemLibrary library(QLatin1String("shell32"));
-#else
- QSystemLibrary library(QLatin1String("coredll"));
-#endif // Q_OS_WINCE
- gsfp = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW");
- }
- return gsfp;
-}
-
static QString convertCharArray(const wchar_t *path)
{
return QDir::fromNativeSeparators(QString::fromWCharArray(path));
@@ -92,10 +77,6 @@ QString QStandardPaths::writableLocation(StandardLocation type)
{
QString result;
- static GetSpecialFolderPath SHGetSpecialFolderPath = resolveGetSpecialFolderPath();
- if (!SHGetSpecialFolderPath)
- return QString();
-
wchar_t path[MAX_PATH];
switch (type) {
@@ -185,8 +166,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
// type-specific handling goes here
#ifndef Q_OS_WINCE
- static GetSpecialFolderPath SHGetSpecialFolderPath = resolveGetSpecialFolderPath();
- if (SHGetSpecialFolderPath) {
+ {
wchar_t path[MAX_PATH];
switch (type) {
case ConfigLocation: // same as DataLocation, on Windows (oversight, but too late to fix it)
@@ -204,6 +184,12 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
#endif
}
dirs.append(result);
+#ifndef QT_BOOTSTRAPPED
+ if (type != GenericDataLocation) {
+ dirs.append(QCoreApplication::applicationDirPath());
+ dirs.append(QCoreApplication::applicationDirPath() + QLatin1String("/data"));
+ }
+#endif
}
break;
default:
diff --git a/src/corelib/io/qstandardpaths_winrt.cpp b/src/corelib/io/qstandardpaths_winrt.cpp
new file mode 100644
index 0000000000..9b6a088a30
--- /dev/null
+++ b/src/corelib/io/qstandardpaths_winrt.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstandardpaths.h"
+
+#include <qdir.h>
+#include <private/qsystemlibrary_p.h>
+#include <qcoreapplication.h>
+#include <qstringlist.h>
+
+#include <qt_windows.h>
+
+#include <wrl.h>
+#include <windows.foundation.h>
+#include <windows.storage.h>
+#include <Windows.ApplicationModel.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::ApplicationModel;
+
+#ifndef QT_NO_STANDARDPATHS
+
+QT_BEGIN_NAMESPACE
+
+static QString convertCharArray(const wchar_t *path)
+{
+ return QDir::fromNativeSeparators(QString::fromWCharArray(path));
+}
+
+QString QStandardPaths::writableLocation(StandardLocation type)
+{
+ QString result;
+
+ switch (type) {
+ case ConfigLocation: // same as DataLocation, on Windows
+ case DataLocation:
+ case GenericDataLocation: {
+ ComPtr<IApplicationDataStatics> applicationDataStatics;
+ if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
+ break;
+ ComPtr<IApplicationData> applicationData;
+ if (FAILED(applicationDataStatics->get_Current(&applicationData)))
+ break;
+ ComPtr<IStorageFolder> settingsFolder;
+ if (FAILED(applicationData->get_LocalFolder(&settingsFolder)))
+ break;
+ ComPtr<IStorageItem> settingsFolderItem;
+ if (FAILED(settingsFolder.As(&settingsFolderItem)))
+ break;
+ HSTRING path;
+ if (FAILED(settingsFolderItem->get_Path(&path)))
+ break;
+ result = convertCharArray(WindowsGetStringRawBuffer(path, nullptr));
+ if (isTestModeEnabled())
+ result += QLatin1String("/qttest");
+ break;
+ }
+ case CacheLocation:
+ return writableLocation(DataLocation) + QLatin1String("/cache");
+
+ case GenericCacheLocation:
+ return writableLocation(GenericDataLocation) + QLatin1String("/cache");
+
+ case RuntimeLocation:
+ case HomeLocation:
+ result = QDir::homePath();
+ break;
+
+ case TempLocation:
+ result = QDir::tempPath();
+ break;
+ default:
+ Q_UNIMPLEMENTED();
+ }
+ return result;
+
+}
+
+QStringList QStandardPaths::standardLocations(StandardLocation type)
+{
+ return QStringList(writableLocation(type));
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_STANDARDPATHS
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index b3cb4e43f8..3cade0ed25 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -77,7 +77,7 @@ typedef int NativeFileHandle;
/*
* Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -151,18 +151,27 @@ static bool createFileFromTemplate(NativeFileHandle &file,
for (;;) {
// Atomically create file and obtain handle
#if defined(Q_OS_WIN)
+# ifndef Q_OS_WINRT
file = CreateFile((const wchar_t *)path.constData(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
+# else // !Q_OS_WINRT
+ file = CreateFile2((const wchar_t *)path.constData(),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, CREATE_NEW,
+ NULL);
+# endif // Q_OS_WINRT
if (file != INVALID_HANDLE_VALUE)
return true;
DWORD err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributes((const wchar_t *)path.constData());
- if (attributes == INVALID_FILE_ATTRIBUTES) {
+ WIN32_FILE_ATTRIBUTE_DATA attributes;
+ if (!GetFileAttributesEx((const wchar_t *)path.constData(),
+ GetFileExInfoStandard, &attributes)
+ || attributes.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
// Potential write error (read-only parent directory, etc.).
error = QSystemError(err, QSystemError::NativeError);
return false;
@@ -336,7 +345,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
-#if !defined(Q_OS_WIN)
+#if !defined(Q_OS_WIN) || defined(Q_OS_WINRT)
d->closeFileHandle = true;
#endif
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 8188628f57..163b087436 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2191,20 +2191,20 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative)
unsigned flags = 0;
const QTextStream::NumberFlags numberFlags = params.numberFlags;
if (numberFlags & QTextStream::ShowBase)
- flags |= QLocalePrivate::ShowBase;
+ flags |= QLocaleData::ShowBase;
if (numberFlags & QTextStream::ForceSign)
- flags |= QLocalePrivate::AlwaysShowSign;
+ flags |= QLocaleData::AlwaysShowSign;
if (numberFlags & QTextStream::UppercaseBase)
- flags |= QLocalePrivate::UppercaseBase;
+ flags |= QLocaleData::UppercaseBase;
if (numberFlags & QTextStream::UppercaseDigits)
- flags |= QLocalePrivate::CapitalEorX;
+ flags |= QLocaleData::CapitalEorX;
// add thousands group separators. For backward compatibility we
// don't add a group separator for C locale.
if (locale != QLocale::c())
- flags |= QLocalePrivate::ThousandsGroup;
+ flags |= QLocaleData::ThousandsGroup;
- const QLocalePrivate *dd = locale.d;
+ const QLocaleData *dd = locale.d->m_data;
int base = params.integerBase ? params.integerBase : 10;
if (negative && base == 10) {
result = dd->longLongToString(-static_cast<qlonglong>(number), -1,
@@ -2388,32 +2388,32 @@ QTextStream &QTextStream::operator<<(double f)
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
- QLocalePrivate::DoubleForm form = QLocalePrivate::DFDecimal;
+ QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
switch (realNumberNotation()) {
case FixedNotation:
- form = QLocalePrivate::DFDecimal;
+ form = QLocaleData::DFDecimal;
break;
case ScientificNotation:
- form = QLocalePrivate::DFExponent;
+ form = QLocaleData::DFExponent;
break;
case SmartNotation:
- form = QLocalePrivate::DFSignificantDigits;
+ form = QLocaleData::DFSignificantDigits;
break;
}
uint flags = 0;
if (numberFlags() & ShowBase)
- flags |= QLocalePrivate::ShowBase;
+ flags |= QLocaleData::ShowBase;
if (numberFlags() & ForceSign)
- flags |= QLocalePrivate::AlwaysShowSign;
+ flags |= QLocaleData::AlwaysShowSign;
if (numberFlags() & UppercaseBase)
- flags |= QLocalePrivate::UppercaseBase;
+ flags |= QLocaleData::UppercaseBase;
if (numberFlags() & UppercaseDigits)
- flags |= QLocalePrivate::CapitalEorX;
+ flags |= QLocaleData::CapitalEorX;
if (numberFlags() & ForcePoint)
- flags |= QLocalePrivate::Alternate;
+ flags |= QLocaleData::Alternate;
- const QLocalePrivate *dd = d->locale.d;
+ const QLocaleData *dd = d->locale.d->m_data;
QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags);
d->putString(num, true);
return *this;
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index 890a2260a2..4e9b257c7b 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -73,7 +73,7 @@ inline bool operator<(const NameprepCaseFoldingEntry &one, uint other)
{ return one.uc < other; }
static const NameprepCaseFoldingEntry NameprepCaseFolding[] = {
-/* { 0x0041, { 0x0061, 0x0000, 0x0000, 0x0000 } },
+/* { 0x0041, { 0x0061, 0x0000, 0x0000, 0x0000 } },
{ 0x0042, { 0x0062, 0x0000, 0x0000, 0x0000 } },
{ 0x0043, { 0x0063, 0x0000, 0x0000, 0x0000 } },
{ 0x0044, { 0x0064, 0x0000, 0x0000, 0x0000 } },
diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp
index 80fc0319fe..74a981b654 100644
--- a/src/corelib/io/qurlrecode.cpp
+++ b/src/corelib/io/qurlrecode.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qurl.h"
+#include "private/qutfcodec_p.h"
QT_BEGIN_NAMESPACE
@@ -232,110 +233,73 @@ static void ensureDetached(QString &result, ushort *&output, const ushort *begin
}
}
-// returns true if we performed an UTF-8 decoding
-static bool encodedUtf8ToUtf16(QString &result, ushort *&output, const ushort *begin, const ushort *&input,
- const ushort *end, ushort decoded)
+namespace {
+struct QUrlUtf8Traits : public QUtf8BaseTraitsNoAscii
{
- int charsNeeded;
- uint min_uc;
- uint uc;
-
- if (decoded <= 0xC1) {
- // an UTF-8 first character must be at least 0xC0
- // however, all 0xC0 and 0xC1 first bytes can only produce overlong sequences
- return false;
- } else if (decoded < 0xe0) {
- charsNeeded = 2;
- min_uc = 0x80;
- uc = decoded & 0x1f;
- } else if (decoded < 0xf0) {
- charsNeeded = 3;
- min_uc = 0x800;
- uc = decoded & 0x0f;
- } else if (decoded < 0xf5) {
- charsNeeded = 4;
- min_uc = 0x10000;
- uc = decoded & 0x07;
- } else {
- // the last Unicode character is U+10FFFF
- // it's encoded in UTF-8 as "\xF4\x8F\xBF\xBF"
- // therefore, a byte higher than 0xF4 is not the UTF-8 first byte
- return false;
+ // override: our "bytes" are three percent-encoded UTF-16 characters
+ static void appendByte(ushort *&ptr, uchar b)
+ {
+ // b >= 0x80, by construction, so percent-encode
+ *ptr++ = '%';
+ *ptr++ = encodeNibble(b >> 4);
+ *ptr++ = encodeNibble(b & 0xf);
}
- // are there enough remaining?
- if (end - input < 3*charsNeeded)
- return false;
+ static uchar peekByte(const ushort *ptr, int n = 0)
+ {
+ // decodePercentEncoding returns ushort(-1) if it can't decode,
+ // which means we return 0xff, which is not a valid continuation byte.
+ // If ptr[i * 3] is not '%', we'll multiply by zero and return 0,
+ // also not a valid continuation byte (if it's '%', we multiply by 1).
+ return uchar(decodePercentEncoding(ptr + n * 3))
+ * uchar(ptr[n * 3] == '%');
+ }
- if (input[3] != '%')
- return false;
+ static qptrdiff availableBytes(const ushort *ptr, const ushort *end)
+ {
+ return (end - ptr) / 3;
+ }
- // first continuation character
- decoded = decodePercentEncoding(input + 3);
- if ((decoded & 0xc0) != 0x80)
- return false;
- uc <<= 6;
- uc |= decoded & 0x3f;
-
- if (charsNeeded > 2) {
- if (input[6] != '%')
- return false;
-
- // second continuation character
- decoded = decodePercentEncoding(input + 6);
- if ((decoded & 0xc0) != 0x80)
- return false;
- uc <<= 6;
- uc |= decoded & 0x3f;
-
- if (charsNeeded > 3) {
- if (input[9] != '%')
- return false;
-
- // third continuation character
- decoded = decodePercentEncoding(input + 9);
- if ((decoded & 0xc0) != 0x80)
- return false;
- uc <<= 6;
- uc |= decoded & 0x3f;
- }
+ static void advanceByte(const ushort *&ptr, int n = 1)
+ {
+ ptr += n * 3;
}
+};
+}
- // we've decoded something; safety-check it
- if (uc < min_uc)
- return false;
- if (QChar::isSurrogate(uc) || uc > QChar::LastValidCodePoint)
+// returns true if we performed an UTF-8 decoding
+static bool encodedUtf8ToUtf16(QString &result, ushort *&output, const ushort *begin, const ushort *&input,
+ const ushort *end, ushort decoded)
+{
+ uint ucs4, *dst = &ucs4;
+ const ushort *src = input + 3;// skip the %XX that yielded \a decoded
+ int charsNeeded = QUtf8Functions::fromUtf8<QUrlUtf8Traits>(decoded, dst, src, end);
+ if (charsNeeded < 0)
return false;
- if (!QChar::requiresSurrogates(uc)) {
+ if (!QChar::requiresSurrogates(ucs4)) {
// UTF-8 decoded and no surrogates are required
// detach if necessary
- ensureDetached(result, output, begin, input, end, -9 * charsNeeded + 1);
- *output++ = uc;
+ // possibilities are: 6 chars (%XX%XX) -> one char; 9 chars (%XX%XX%XX) -> one char
+ ensureDetached(result, output, begin, input, end, -3 * charsNeeded + 1);
+ *output++ = ucs4;
} else {
// UTF-8 decoded to something that requires a surrogate pair
- ensureDetached(result, output, begin, input, end, -9 * charsNeeded + 2);
- *output++ = QChar::highSurrogate(uc);
- *output++ = QChar::lowSurrogate(uc);
+ // compressing from %XX%XX%XX%XX (12 chars) to two
+ ensureDetached(result, output, begin, input, end, -10);
+ *output++ = QChar::highSurrogate(ucs4);
+ *output++ = QChar::lowSurrogate(ucs4);
}
- input += charsNeeded * 3 - 1;
+
+ input = src - 1;
return true;
}
static void unicodeToEncodedUtf8(QString &result, ushort *&output, const ushort *begin,
const ushort *&input, const ushort *end, ushort decoded)
{
- uint uc = decoded;
- if (QChar::isHighSurrogate(uc)) {
- if (input < end && QChar::isLowSurrogate(input[1]))
- uc = QChar::surrogateToUcs4(uc, input[1]);
- }
-
- // note: we will encode bad UTF-16 to UTF-8
- // but they don't get decoded back
-
- // calculate the utf8 length
- int utf8len = uc >= 0x10000 ? 4 : uc >= 0x800 ? 3 : 2;
+ // calculate the utf8 length and ensure enough space is available
+ int utf8len = QChar::isHighSurrogate(decoded) ? 4 : decoded >= 0x800 ? 3 : 2;
// detach
if (!output) {
@@ -357,50 +321,32 @@ static void unicodeToEncodedUtf8(QString &result, ushort *&output, const ushort
}
}
- // write the sequence
- if (uc < 0x800) {
- // first of two bytes
- uchar c = 0xc0 | uchar(uc >> 6);
+ ++input;
+ int res = QUtf8Functions::toUtf8<QUrlUtf8Traits>(decoded, output, input, end);
+ --input;
+ if (res < 0) {
+ // bad surrogate pair sequence
+ // we will encode bad UTF-16 to UTF-8
+ // but they don't get decoded back
+
+ // first of three bytes
+ uchar c = 0xe0 | uchar(decoded >> 12);
*output++ = '%';
- *output++ = encodeNibble(c >> 4);
+ *output++ = 'E';
*output++ = encodeNibble(c & 0xf);
- } else {
- uchar c;
- if (uc > 0xFFFF) {
- // first two of four bytes
- c = 0xf0 | uchar(uc >> 18);
- *output++ = '%';
- *output++ = 'F';
- *output++ = encodeNibble(c & 0xf);
- // continuation byte
- c = 0x80 | (uchar(uc >> 12) & 0x3f);
- *output++ = '%';
- *output++ = encodeNibble(c >> 4);
- *output++ = encodeNibble(c & 0xf);
-
- // this was a surrogate pair
- ++input;
- } else {
- // first of three bytes
- c = 0xe0 | uchar(uc >> 12);
- *output++ = '%';
- *output++ = 'E';
- *output++ = encodeNibble(c & 0xf);
- }
+ // second byte
+ c = 0x80 | (uchar(decoded >> 6) & 0x3f);
+ *output++ = '%';
+ *output++ = encodeNibble(c >> 4);
+ *output++ = encodeNibble(c & 0xf);
- // continuation byte
- c = 0x80 | (uchar(uc >> 6) & 0x3f);
+ // third byte
+ c = 0x80 | (decoded & 0x3f);
*output++ = '%';
*output++ = encodeNibble(c >> 4);
*output++ = encodeNibble(c & 0xf);
}
-
- // continuation byte
- uchar c = 0x80 | (uc & 0x3f);
- *output++ = '%';
- *output++ = encodeNibble(c >> 4);
- *output++ = encodeNibble(c & 0xf);
}
static int recode(QString &result, const ushort *begin, const ushort *end, QUrl::ComponentFormattingOptions encoding,
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index fc9d191a90..df65aebcff 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -173,7 +173,8 @@ bool QWindowsPipeReader::canReadLine() const
\internal
Will be called whenever the read operation completes.
*/
-void QWindowsPipeReader::notified(DWORD numberOfBytesRead, DWORD errorCode, OVERLAPPED *notifiedOverlapped)
+void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode,
+ OVERLAPPED *notifiedOverlapped)
{
if (&overlapped != notifiedOverlapped)
return;
diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h
index ea3d3c271f..78ac8eb76d 100644
--- a/src/corelib/io/qwindowspipereader_p.h
+++ b/src/corelib/io/qwindowspipereader_p.h
@@ -94,7 +94,7 @@ Q_SIGNALS:
void pipeClosed();
private Q_SLOTS:
- void notified(DWORD numberOfBytesRead, DWORD errorCode, OVERLAPPED *notifiedOverlapped);
+ void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped);
private:
bool completeAsyncRead(DWORD bytesRead, DWORD errorCode);
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index 1808081d01..daa8068734 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -114,7 +114,7 @@ void QWindowsPipeWriter::run()
if (quitNow) {
lock.unlock();
quitNow = false;
- break;
+ break;
}
QByteArray copy = data;
@@ -153,7 +153,7 @@ void QWindowsPipeWriter::run()
totalWritten += written;
#if defined QPIPEWRITER_DEBUG
qDebug("QWindowsPipeWriter::run() wrote %d %d/%d bytes",
- written, int(totalWritten), int(maxlen));
+ written, int(totalWritten), int(maxlen));
#endif
lock.lock();
data.remove(0, written);
diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp
index 914264e69e..33583afb78 100644
--- a/src/corelib/io/qwinoverlappedionotifier.cpp
+++ b/src/corelib/io/qwinoverlappedionotifier.cpp
@@ -43,8 +43,11 @@
#include <qdebug.h>
#include <qmutex.h>
#include <qpointer.h>
+#include <qqueue.h>
#include <qset.h>
#include <qthread.h>
+#include <qt_windows.h>
+#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
@@ -79,6 +82,46 @@ QT_BEGIN_NAMESPACE
\warning This class is only available on Windows.
*/
+struct IOResult
+{
+ IOResult(DWORD n = 0, DWORD e = 0, OVERLAPPED *p = 0)
+ : numberOfBytes(n), errorCode(e), overlapped(p)
+ {}
+
+ DWORD numberOfBytes;
+ DWORD errorCode;
+ OVERLAPPED *overlapped;
+};
+
+
+class QWinIoCompletionPort;
+
+class QWinOverlappedIoNotifierPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QWinOverlappedIoNotifier)
+public:
+ QWinOverlappedIoNotifierPrivate()
+ : hHandle(INVALID_HANDLE_VALUE)
+ {
+ }
+
+ void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
+ OVERLAPPED *_q_notified();
+
+ static QWinIoCompletionPort *iocp;
+ static HANDLE iocpInstanceLock;
+ static unsigned int iocpInstanceRefCount;
+ HANDLE hHandle;
+ HANDLE hSemaphore;
+ HANDLE hResultsMutex;
+ QQueue<IOResult> results;
+};
+
+QWinIoCompletionPort *QWinOverlappedIoNotifierPrivate::iocp = 0;
+HANDLE QWinOverlappedIoNotifierPrivate::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
+unsigned int QWinOverlappedIoNotifierPrivate::iocpInstanceRefCount = 0;
+
+
class QWinIoCompletionPort : protected QThread
{
public:
@@ -109,11 +152,13 @@ public:
CloseHandle(hQueueDrainedEvent);
}
- void registerNotifier(QWinOverlappedIoNotifier *notifier)
+ void registerNotifier(QWinOverlappedIoNotifierPrivate *notifier)
{
- HANDLE hIOCP = CreateIoCompletionPort(notifier->hHandle, hPort, reinterpret_cast<ULONG_PTR>(notifier), 0);
+ const HANDLE hHandle = notifier->hHandle;
+ HANDLE hIOCP = CreateIoCompletionPort(hHandle, hPort,
+ reinterpret_cast<ULONG_PTR>(notifier), 0);
if (!hIOCP) {
- qErrnoWarning("Can't associate file handle %x with I/O completion port.", notifier->hHandle);
+ qErrnoWarning("Can't associate file handle %x with I/O completion port.", hHandle);
return;
}
mutex.lock();
@@ -123,7 +168,7 @@ public:
QThread::start();
}
- void unregisterNotifier(QWinOverlappedIoNotifier *notifier)
+ void unregisterNotifier(QWinOverlappedIoNotifierPrivate *notifier)
{
mutex.lock();
notifiers.remove(notifier);
@@ -176,7 +221,8 @@ protected:
continue;
}
- QWinOverlappedIoNotifier *notifier = reinterpret_cast<QWinOverlappedIoNotifier *>(pulCompletionKey);
+ QWinOverlappedIoNotifierPrivate *notifier
+ = reinterpret_cast<QWinOverlappedIoNotifierPrivate *>(pulCompletionKey);
mutex.lock();
if (notifiers.contains(notifier))
notifier->notify(dwBytesRead, errorCode, overlapped);
@@ -188,57 +234,62 @@ private:
const ULONG_PTR finishThreadKey;
const ULONG_PTR drainQueueKey;
HANDLE hPort;
- QSet<QWinOverlappedIoNotifier *> notifiers;
+ QSet<QWinOverlappedIoNotifierPrivate *> notifiers;
QMutex mutex;
QMutex drainQueueMutex;
HANDLE hQueueDrainedEvent;
};
-QWinIoCompletionPort *QWinOverlappedIoNotifier::iocp = 0;
-HANDLE QWinOverlappedIoNotifier::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
-unsigned int QWinOverlappedIoNotifier::iocpInstanceRefCount = 0;
QWinOverlappedIoNotifier::QWinOverlappedIoNotifier(QObject *parent)
- : QObject(parent),
- hHandle(INVALID_HANDLE_VALUE)
+ : QObject(*new QWinOverlappedIoNotifierPrivate, parent)
{
- WaitForSingleObject(iocpInstanceLock, INFINITE);
- if (!iocp)
- iocp = new QWinIoCompletionPort;
- iocpInstanceRefCount++;
- ReleaseMutex(iocpInstanceLock);
-
- hSemaphore = CreateSemaphore(NULL, 0, 255, NULL);
- hResultsMutex = CreateMutex(NULL, FALSE, NULL);
- connect(this, &QWinOverlappedIoNotifier::_q_notify,
- this, &QWinOverlappedIoNotifier::_q_notified, Qt::QueuedConnection);
+ Q_D(QWinOverlappedIoNotifier);
+ WaitForSingleObject(d->iocpInstanceLock, INFINITE);
+ if (!d->iocp)
+ d->iocp = new QWinIoCompletionPort;
+ d->iocpInstanceRefCount++;
+ ReleaseMutex(d->iocpInstanceLock);
+
+ d->hSemaphore = CreateSemaphore(NULL, 0, 255, NULL);
+ d->hResultsMutex = CreateMutex(NULL, FALSE, NULL);
+ connect(this, SIGNAL(_q_notify()), this, SLOT(_q_notified()), Qt::QueuedConnection);
}
QWinOverlappedIoNotifier::~QWinOverlappedIoNotifier()
{
+ Q_D(QWinOverlappedIoNotifier);
setEnabled(false);
- CloseHandle(hResultsMutex);
- CloseHandle(hSemaphore);
+ CloseHandle(d->hResultsMutex);
+ CloseHandle(d->hSemaphore);
- WaitForSingleObject(iocpInstanceLock, INFINITE);
- if (!--iocpInstanceRefCount) {
- delete iocp;
- iocp = 0;
+ WaitForSingleObject(d->iocpInstanceLock, INFINITE);
+ if (!--d->iocpInstanceRefCount) {
+ delete d->iocp;
+ d->iocp = 0;
}
- ReleaseMutex(iocpInstanceLock);
+ ReleaseMutex(d->iocpInstanceLock);
}
-void QWinOverlappedIoNotifier::setHandle(HANDLE h)
+void QWinOverlappedIoNotifier::setHandle(Qt::HANDLE h)
{
- hHandle = h;
+ Q_D(QWinOverlappedIoNotifier);
+ d->hHandle = h;
+}
+
+Qt::HANDLE QWinOverlappedIoNotifier::handle() const
+{
+ Q_D(const QWinOverlappedIoNotifier);
+ return d->hHandle;
}
void QWinOverlappedIoNotifier::setEnabled(bool enabled)
{
+ Q_D(QWinOverlappedIoNotifier);
if (enabled)
- iocp->registerNotifier(this);
+ d->iocp->registerNotifier(d);
else
- iocp->unregisterNotifier(this);
+ d->iocp->unregisterNotifier(d);
}
/*!
@@ -249,18 +300,19 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled)
*/
bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
{
- if (!iocp->isRunning()) {
+ Q_D(QWinOverlappedIoNotifier);
+ if (!d->iocp->isRunning()) {
qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier.");
return false;
}
forever {
if (msecs == 0)
- iocp->drainQueue();
- DWORD result = WaitForSingleObject(hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
+ d->iocp->drainQueue();
+ DWORD result = WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
if (result == WAIT_OBJECT_0) {
- ReleaseSemaphore(hSemaphore, 1, NULL);
- if (_q_notified() == overlapped)
+ ReleaseSemaphore(d->hSemaphore, 1, NULL);
+ if (d->_q_notified() == overlapped)
return true;
continue;
} else if (result == WAIT_TIMEOUT) {
@@ -275,25 +327,30 @@ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped
/*!
* Note: This function runs in the I/O completion port thread.
*/
-void QWinOverlappedIoNotifier::notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped)
+void QWinOverlappedIoNotifierPrivate::notify(DWORD numberOfBytes, DWORD errorCode,
+ OVERLAPPED *overlapped)
{
+ Q_Q(QWinOverlappedIoNotifier);
WaitForSingleObject(hResultsMutex, INFINITE);
results.enqueue(IOResult(numberOfBytes, errorCode, overlapped));
ReleaseMutex(hResultsMutex);
ReleaseSemaphore(hSemaphore, 1, NULL);
- emit _q_notify();
+ emit q->_q_notify();
}
-OVERLAPPED *QWinOverlappedIoNotifier::_q_notified()
+OVERLAPPED *QWinOverlappedIoNotifierPrivate::_q_notified()
{
+ Q_Q(QWinOverlappedIoNotifier);
if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0) {
WaitForSingleObject(hResultsMutex, INFINITE);
IOResult ioresult = results.dequeue();
ReleaseMutex(hResultsMutex);
- emit notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped);
+ emit q->notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped);
return ioresult.overlapped;
}
return 0;
}
QT_END_NAMESPACE
+
+#include "moc_qwinoverlappedionotifier_p.cpp"
diff --git a/src/corelib/io/qwinoverlappedionotifier_p.h b/src/corelib/io/qwinoverlappedionotifier_p.h
index 451bedf7cf..f90fd2e615 100644
--- a/src/corelib/io/qwinoverlappedionotifier_p.h
+++ b/src/corelib/io/qwinoverlappedionotifier_p.h
@@ -54,58 +54,35 @@
//
#include <qobject.h>
-#include <qt_windows.h>
-#include <qqueue.h>
+
+typedef struct _OVERLAPPED OVERLAPPED;
QT_BEGIN_NAMESPACE
-class QWinIoCompletionPort;
+class QWinOverlappedIoNotifierPrivate;
class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject
{
Q_OBJECT
+ Q_DISABLE_COPY(QWinOverlappedIoNotifier)
+ Q_DECLARE_PRIVATE(QWinOverlappedIoNotifier)
+ Q_PRIVATE_SLOT(d_func(), OVERLAPPED *_q_notified())
+ friend class QWinIoCompletionPort;
public:
QWinOverlappedIoNotifier(QObject *parent = 0);
~QWinOverlappedIoNotifier();
- void setHandle(HANDLE h);
- HANDLE handle() const { return hHandle; }
+ void setHandle(Qt::HANDLE h);
+ Qt::HANDLE handle() const;
void setEnabled(bool enabled);
bool waitForNotified(int msecs, OVERLAPPED *overlapped);
Q_SIGNALS:
- void notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
+ void notified(quint32 numberOfBytes, quint32 errorCode, OVERLAPPED *overlapped);
+#if !defined(Q_QDOC)
void _q_notify();
-
-private Q_SLOTS:
- OVERLAPPED *_q_notified();
-
-private:
- void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
-
-private:
- static QWinIoCompletionPort *iocp;
- static HANDLE iocpInstanceLock;
- static unsigned int iocpInstanceRefCount;
- HANDLE hHandle;
- HANDLE hSemaphore;
- HANDLE hResultsMutex;
-
- struct IOResult
- {
- IOResult(DWORD n = 0, DWORD e = 0, OVERLAPPED *p = 0)
- : numberOfBytes(n), errorCode(e), overlapped(p)
- {}
-
- DWORD numberOfBytes;
- DWORD errorCode;
- OVERLAPPED *overlapped;
- };
-
- QQueue<IOResult> results;
-
- friend class QWinIoCompletionPort;
+#endif
};
QT_END_NAMESPACE