diff options
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/io.pri | 6 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.cpp | 3 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 32 | ||||
-rw-r--r-- | src/corelib/io/qdir.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qdiriterator.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 192 | ||||
-rw-r--r-- | src/corelib/io/qfilesystementry.cpp | 6 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemiterator_unix.cpp | 4 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemiterator_win.cpp | 14 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemmetadata_p.h | 6 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 73 | ||||
-rw-r--r-- | src/corelib/io/qlockfile_win.cpp | 14 | ||||
-rw-r--r-- | src/corelib/io/qsettings.cpp | 81 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths.cpp | 203 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths_blackberry.cpp | 9 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths_mac.cpp | 25 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths_win.cpp | 28 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths_winrt.cpp | 127 | ||||
-rw-r--r-- | src/corelib/io/qtemporaryfile.cpp | 15 | ||||
-rw-r--r-- | src/corelib/io/qurlrecode.cpp | 186 |
21 files changed, 795 insertions, 238 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index f06bf61b09..0ec3d949b9 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 += \ 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 43db2ec1fe..a60bcde30d 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -2144,7 +2144,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(), ©Params) != 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/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/qsettings.cpp b/src/corelib/io/qsettings.cpp index 35b3ed4e3d..db4612ae33 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -78,6 +78,17 @@ #ifdef Q_OS_WIN // for homedirpath reading from registry # include <private/qsystemlibrary_p.h> # include <qt_windows.h> +# include <shlobj.h> +#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 @@ -365,7 +376,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 +384,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 +1032,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 +1065,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 +1484,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 +1508,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/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index 2207b8c43e..c145ec4bad 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -72,34 +72,199 @@ 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 (including Android) + \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 + + 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. \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..b3a17eae7e 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -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/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, |