diff options
Diffstat (limited to 'src/corelib/io')
32 files changed, 588 insertions, 221 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index fe81689932..c4c6f41387 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -136,6 +136,7 @@ qtConfig(settings) { } else: darwin:!nacl { SOURCES += io/qsettings_mac.cpp } + wasm : SOURCES += io/qsettings_wasm.cpp } win32 { diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 8a1679c5af..070139b608 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -658,7 +658,7 @@ QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringL QAbstractFileEngine::FileFlags QAbstractFileEngine::fileFlags(FileFlags type) const { Q_UNUSED(type); - return nullptr; + return {}; } /*! diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index fae935fc24..526702d151 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -2372,8 +2372,9 @@ static QString qt_cleanPath(const QString &path, bool *ok) } /*! - Returns \a path with directory separators normalized (converted to "/") and - redundant ones removed, and "."s and ".."s resolved (as far as possible). + Returns \a path with directory separators normalized (that is, platform-native + separators converted to "/") and redundant ones removed, and "."s and ".."s + resolved (as far as possible). Symbolic links are kept. This function does not return the canonical path, but rather the simplest version of the input. diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index ce436b06e3..1cf6b1be08 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -181,7 +181,7 @@ QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QS #elif QT_CONFIG(regularexpression) nameRegExps.reserve(nameFilters.size()); for (const auto &filter : nameFilters) { - QString re = QRegularExpression::anchoredPattern(QRegularExpression::wildcardToRegularExpression(filter)); + QString re = QRegularExpression::wildcardToRegularExpression(filter); nameRegExps.append( QRegularExpression(re, (filters & QDir::CaseSensitive) ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption)); } diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 95f03ef816..5320ae2986 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -251,7 +251,7 @@ QFile::QFile(QFilePrivate &dd) Constructs a QFile object. */ QFile::QFile() - : QFileDevice(*new QFilePrivate, 0) + : QFileDevice(*new QFilePrivate, nullptr) { } /*! @@ -265,7 +265,7 @@ QFile::QFile(QObject *parent) Constructs a new file object to represent the file with the given \a name. */ QFile::QFile(const QString &name) - : QFileDevice(*new QFilePrivate, 0) + : QFileDevice(*new QFilePrivate, nullptr) { Q_D(QFile); d->fileName = name; diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index cf1465ec70..2099b2852f 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -84,6 +84,10 @@ public: // note: duplicated in qglobal.cpp (qEnvironmentVariable) return QString::fromUtf8(localFileName).normalized(QString::NormalizationForm_C); } + static inline QString decodeName(const char *localFileName) + { + return QString::fromUtf8(localFileName).normalized(QString::NormalizationForm_C); + } #else static inline QByteArray encodeName(const QString &fileName) { @@ -93,9 +97,11 @@ public: { return QString::fromLocal8Bit(localFileName); } + static inline QString decodeName(const char *localFileName) + { + return QString::fromLocal8Bit(localFileName); + } #endif - inline static QString decodeName(const char *localFileName) - { return decodeName(QByteArray(localFileName)); } #if QT_DEPRECATED_SINCE(5,0) typedef QByteArray (*EncoderFn)(const QString &fileName); diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index ee619d99cc..b0aba3193c 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -202,7 +202,7 @@ QFileDevice::QFileDevice(QFileDevicePrivate &dd) \internal */ QFileDevice::QFileDevice() - : QIODevice(*new QFileDevicePrivate, 0) + : QIODevice(*new QFileDevicePrivate, nullptr) { } /*! diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 89834de29f..3fe1aec41f 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -134,7 +134,7 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons // extra syscall. Bundle detecton on Mac can be slow, expecially on network // paths, so we separate out that as well. - QAbstractFileEngine::FileFlags req = nullptr; + QAbstractFileEngine::FileFlags req; uint cachedFlags = 0; if (request & (QAbstractFileEngine::FlagsMask | QAbstractFileEngine::TypesMask)) { @@ -1145,6 +1145,25 @@ bool QFileInfo::isShortcut() const [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); }); } + +/*! + Returns \c true if the object points to a junction; + otherwise returns \c false. + + Junctions only exist on Windows' NTFS file system, and are typically + created by the \c{mklink} command. They can be thought of as symlinks for + directories, and can only be created for absolute paths on the local + volume. +*/ +bool QFileInfo::isJunction() const +{ + Q_D(const QFileInfo); + return d->checkAttribute<bool>( + QFileSystemMetaData::LegacyLinkType, + [d]() { return d->metaData.isJunction(); }, + [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); }); +} + /*! Returns \c true if the object points to a directory or to a symbolic link to a directory, and that directory is the root directory; otherwise diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index 3ac028085a..7c7ff56ae4 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -113,6 +113,7 @@ public: bool isSymLink() const; bool isSymbolicLink() const; bool isShortcut() const; + bool isJunction() const; bool isRoot() const; bool isBundle() const; diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index c3abec8989..3bbebc7fe9 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -55,7 +55,7 @@ #include <stdio.h> #include <errno.h> -#if QT_HAS_INCLUDE(<paths.h>) +#if __has_include(<paths.h>) # include <paths.h> #endif #ifndef _PATH_TMP // from <paths.h> @@ -1076,14 +1076,14 @@ bool QFileSystemEngine::cloneFile(int srcfd, int dstfd, const QFileSystemMetaDat // sendfile(2) is limited in the kernel to 2G - 4k const size_t SendfileSize = 0x7ffff000; - ssize_t n = ::sendfile(dstfd, srcfd, NULL, SendfileSize); + ssize_t n = ::sendfile(dstfd, srcfd, nullptr, SendfileSize); if (n == -1) { // if we got an error here, give up and try at an upper layer return false; } while (n) { - n = ::sendfile(dstfd, srcfd, NULL, SendfileSize); + n = ::sendfile(dstfd, srcfd, nullptr, SendfileSize); if (n == -1) { // uh oh, this is probably a real error (like ENOSPC), but we have // no way to notify QFile of partial success, so just erase any work diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h index 81f4b3ba13..3154658e5c 100644 --- a/src/corelib/io/qfilesystemmetadata_p.h +++ b/src/corelib/io/qfilesystemmetadata_p.h @@ -76,8 +76,7 @@ class Q_AUTOTEST_EXPORT QFileSystemMetaData { public: QFileSystemMetaData() - : knownFlagsMask(nullptr), - size_(-1) + : size_(-1) { } @@ -111,8 +110,10 @@ public: AliasType = 0x0, #endif #if defined(Q_OS_WIN) + JunctionType = 0x04000000, WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac #else + JunctionType = 0x0, WinLnkType = 0x0, #endif SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag @@ -184,7 +185,7 @@ public: void clear() { - knownFlagsMask = nullptr; + knownFlagsMask = {}; } void clearFlags(MetaDataFlags flags = AllMetaDataFlags) @@ -205,8 +206,10 @@ public: bool wasDeleted() const { return (entryFlags & WasDeletedAttribute); } #if defined(Q_OS_WIN) bool isLnkFile() const { return (entryFlags & WinLnkType); } + bool isJunction() const { return (entryFlags & JunctionType); } #else bool isLnkFile() const { return false; } + bool isJunction() const { return false; } #endif qint64 size() const { return size_; } @@ -356,9 +359,15 @@ inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, boo if (setLinkType) { knownFlagsMask |= LinkType; entryFlags &= ~LinkType; - if ((fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) - && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { - entryFlags |= LinkType; + if (fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) { + if (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { + entryFlags |= LinkType; +#if defined(IO_REPARSE_TAG_MOUNT_POINT) + } else if ((fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) + && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { + entryFlags |= JunctionType; +#endif + } } } } diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 54460aff77..86c8963cb6 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -88,7 +88,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject } QFileSystemWatcherPrivate::QFileSystemWatcherPrivate() - : native(0), poller(0) + : native(nullptr), poller(nullptr) { } diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index ca1f6cc359..888af998a5 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -242,7 +242,7 @@ QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create(QObject if (fd == -1) { fd = inotify_init(); if (fd == -1) - return 0; + return nullptr; } return new QInotifyFileSystemWatcherEngine(fd, parent); } diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index 1d42dbfc70..f955e3b53a 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -403,6 +403,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); const uint flags = isDir ? (FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_FILE_NAME) : (FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 5b868cc447..dd4882a2bc 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -591,14 +591,14 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil if (type & Refresh) d->metaData.clear(); - QAbstractFileEngine::FileFlags ret = 0; + QAbstractFileEngine::FileFlags ret; if (type & FlagsMask) ret |= LocalDiskFlag; bool exists; { - QFileSystemMetaData::MetaDataFlags queryFlags = 0; + QFileSystemMetaData::MetaDataFlags queryFlags; queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type)) & QFileSystemMetaData::Permissions; diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index e26508e631..b89cab5e3c 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -461,7 +461,7 @@ QIODevice::QIODevice(QIODevicePrivate &dd) */ QIODevice::QIODevice() - : QObject(*new QIODevicePrivate, 0) + : QObject(*new QIODevicePrivate, nullptr) { #if defined QIODEVICE_DEBUG QFile *file = qobject_cast<QFile *>(this); diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 4d4784cdf7..5de8be116c 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -179,7 +179,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift) The \c QtProject/qtlogging.ini file is looked up in all directories returned by QStandardPaths::GenericConfigLocation. - Set the \c QT_LOGGING_DEBUG environment variable to find out where you logging + Set the \c QT_LOGGING_DEBUG environment variable to find out where your logging rules are loaded from. \section2 Installing a Custom Filter diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index d1806aa12b..df0197e8eb 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -127,7 +127,7 @@ QT_BEGIN_NAMESPACE \internal */ -QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0) +QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)nullptr) { } @@ -188,7 +188,7 @@ const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLen { if (atEnd()) { len = -1; - return 0; + return nullptr; } if (maximumLength != -1) @@ -241,7 +241,7 @@ const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLe { if (atEnd()) { len = -1; - return 0; + return nullptr; } const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len); @@ -282,7 +282,7 @@ qint64 QNonContiguousByteDeviceRingBufferImpl::size() const QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d) : QNonContiguousByteDevice(), - currentReadBuffer(0), currentReadBufferSize(16*1024), + currentReadBuffer(nullptr), currentReadBufferSize(16*1024), currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0), eof(false) { @@ -301,10 +301,10 @@ const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng { if (eof == true) { len = -1; - return 0; + return nullptr; } - if (currentReadBuffer == 0) + if (currentReadBuffer == nullptr) currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc if (maximumLength == -1) @@ -323,7 +323,7 @@ const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng // size was unknown before, emit a readProgress with the final size if (size() == -1) emit readProgress(totalAdvancements, totalAdvancements); - return 0; + return nullptr; } currentReadBufferAmount = haveRead; @@ -349,7 +349,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) if (currentReadBufferPosition > currentReadBufferAmount) { qint64 i = currentReadBufferPosition - currentReadBufferAmount; while (i > 0) { - if (device->getChar(0) == false) { + if (device->getChar(nullptr) == false) { emit readProgress(totalAdvancements - i, size()); return false; // ### FIXME handle eof } @@ -377,7 +377,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::reset() totalAdvancements = 0; //reset the progress counter if (currentReadBuffer) { delete currentReadBuffer; - currentReadBuffer = 0; + currentReadBuffer = nullptr; } currentReadBufferAmount = 0; currentReadBufferPosition = 0; @@ -405,7 +405,7 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() const return device->pos(); } -QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) +QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)nullptr) { byteDevice = bd; connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead())); diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 35ca2542f7..aedcae2cdc 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -100,7 +100,7 @@ QT_END_NAMESPACE #include <private/qcore_unix_p.h> #endif -#if QT_HAS_INCLUDE(<paths.h>) +#if __has_include(<paths.h>) #include <paths.h> #endif @@ -216,7 +216,7 @@ void QProcessEnvironmentPrivate::insert(const QProcessEnvironmentPrivate &other) environment variables to be removed. */ QProcessEnvironment::QProcessEnvironment() - : d(0) + : d(nullptr) { } @@ -436,18 +436,18 @@ void QProcessPrivate::Channel::clear() case PipeSource: Q_ASSERT(process); process->stdinChannel.type = Normal; - process->stdinChannel.process = 0; + process->stdinChannel.process = nullptr; break; case PipeSink: Q_ASSERT(process); process->stdoutChannel.type = Normal; - process->stdoutChannel.process = 0; + process->stdoutChannel.process = nullptr; break; } type = Normal; file.clear(); - process = 0; + process = nullptr; } /*! @@ -869,8 +869,8 @@ QProcessPrivate::QProcessPrivate() sequenceNumber = 0; exitCode = 0; exitStatus = QProcess::NormalExit; - startupSocketNotifier = 0; - deathNotifier = 0; + startupSocketNotifier = nullptr; + deathNotifier = nullptr; childStartedPipe[0] = INVALID_Q_PIPE; childStartedPipe[1] = INVALID_Q_PIPE; forkfd = -1; @@ -924,23 +924,23 @@ void QProcessPrivate::cleanup() if (stdoutChannel.notifier) { delete stdoutChannel.notifier; - stdoutChannel.notifier = 0; + stdoutChannel.notifier = nullptr; } if (stderrChannel.notifier) { delete stderrChannel.notifier; - stderrChannel.notifier = 0; + stderrChannel.notifier = nullptr; } if (stdinChannel.notifier) { delete stdinChannel.notifier; - stdinChannel.notifier = 0; + stdinChannel.notifier = nullptr; } if (startupSocketNotifier) { delete startupSocketNotifier; - startupSocketNotifier = 0; + startupSocketNotifier = nullptr; } if (deathNotifier) { delete deathNotifier; - deathNotifier = 0; + deathNotifier = nullptr; } closeChannel(&stdoutChannel); closeChannel(&stderrChannel); @@ -1004,7 +1004,7 @@ QT_WARNING_POP /*! \internal - Returns true if we emitted readyRead(). + Returns \c true if we emitted readyRead(). */ bool QProcessPrivate::tryReadFromChannel(Channel *channel) { @@ -1229,7 +1229,7 @@ void QProcessPrivate::closeWriteChannel() #endif if (stdinChannel.notifier) { delete stdinChannel.notifier; - stdinChannel.notifier = 0; + stdinChannel.notifier = nullptr; } #ifdef Q_OS_WIN // ### Find a better fix, feeding the process little by little @@ -2187,6 +2187,8 @@ bool QProcess::startDetached(qint64 *pid) This method is an alias for start(), and exists only to fully implement the interface defined by QIODevice. + Returns \c true if the program has been started. + \sa start(), setProgram(), setArguments() */ bool QProcess::open(OpenMode mode) @@ -2615,7 +2617,7 @@ QT_END_INCLUDE_NAMESPACE QStringList QProcess::systemEnvironment() { QStringList tmp; - char *entry = 0; + char *entry = nullptr; int count = 0; while ((entry = environ[count++])) tmp << QString::fromLocal8Bit(entry); diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 9fda5fba11..585508adf1 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -278,7 +278,8 @@ Q_SIGNALS: void finished(int exitCode); // ### Qt 6: merge the two signals with a default value #endif void finished(int exitCode, QProcess::ExitStatus exitStatus); -#if QT_DEPRECATED_SINCE(5,6) +#if QT_DEPRECATED_SINCE(5, 6) + QT_DEPRECATED_X("Use QProcess::errorOccurred(QProcess::ProcessError) instead") void error(QProcess::ProcessError error); #endif void errorOccurred(QProcess::ProcessError error); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 0c80daa024..2186f23ab6 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -246,7 +246,7 @@ bool QProcessPrivate::openChannel(Channel &channel) return false; // create the socket notifiers - if (threadData->hasEventDispatcher()) { + if (threadData.loadRelaxed()->hasEventDispatcher()) { if (&channel == &stdinChannel) { channel.notifier = new QSocketNotifier(channel.pipe[1], QSocketNotifier::Write, q); @@ -338,11 +338,11 @@ static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Map &environme { *envc = 0; if (environment.isEmpty()) - return 0; + return nullptr; char **envp = new char *[environment.count() + 2]; - envp[environment.count()] = 0; - envp[environment.count() + 1] = 0; + envp[environment.count()] = nullptr; + envp[environment.count() + 1] = nullptr; auto it = environment.constBegin(); const auto end = environment.constEnd(); @@ -377,7 +377,7 @@ void QProcessPrivate::startProcess() return; } - if (threadData->hasEventDispatcher()) { + if (threadData.loadRelaxed()->hasEventDispatcher()) { startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], QSocketNotifier::Read, q); QObject::connect(startupSocketNotifier, SIGNAL(activated(int)), @@ -390,7 +390,7 @@ void QProcessPrivate::startProcess() // Create argument list with right number of elements, and set the final // one to 0. char **argv = new char *[arguments.count() + 2]; - argv[arguments.count() + 1] = 0; + argv[arguments.count() + 1] = nullptr; // Encode the program name. QByteArray encodedProgramName = QFile::encodeName(program); @@ -437,13 +437,13 @@ void QProcessPrivate::startProcess() // Duplicate the environment. int envc = 0; - char **envp = 0; + char **envp = nullptr; if (environment.d.constData()) { envp = _q_dupEnvironment(environment.d.constData()->vars, &envc); } // Encode the working directory if it's non-empty, otherwise just pass 0. - const char *workingDirPtr = 0; + const char *workingDirPtr = nullptr; QByteArray encodedWorkingDirectory; if (!workingDirectory.isEmpty()) { encodedWorkingDirectory = QFile::encodeName(workingDirectory); @@ -451,8 +451,13 @@ void QProcessPrivate::startProcess() } // Start the process manager, and fork off the child process. + // ### Qt6: revisit whether the change in behavior due to not using fork() + // is acceptable for derived classes. + int ffdflags = FFD_CLOEXEC; + if (typeid(*q) != typeid(QProcess)) + ffdflags |= FFD_USE_FORK; pid_t childPid; - forkfd = ::forkfd(FFD_CLOEXEC, &childPid); + forkfd = ::forkfd(ffdflags , &childPid); int lastForkErrno = errno; if (forkfd != FFD_CHILD_PROCESS) { // Parent process. @@ -517,7 +522,7 @@ void QProcessPrivate::startProcess() if (stderrChannel.pipe[0] != -1) ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK); - if (threadData->eventDispatcher.loadAcquire()) { + if (threadData.loadRelaxed()->eventDispatcher.loadAcquire()) { deathNotifier = new QSocketNotifier(forkfd, QSocketNotifier::Read, q); QObject::connect(deathNotifier, SIGNAL(activated(int)), q, SLOT(_q_processDied())); @@ -596,7 +601,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage) if (startupSocketNotifier) { startupSocketNotifier->setEnabled(false); startupSocketNotifier->deleteLater(); - startupSocketNotifier = 0; + startupSocketNotifier = nullptr; } qt_safe_close(childStartedPipe[0]); childStartedPipe[0] = -1; @@ -889,7 +894,7 @@ bool QProcessPrivate::waitForDeadChild() crashed = info.code != CLD_EXITED; delete deathNotifier; - deathNotifier = 0; + deathNotifier = nullptr; EINTR_LOOP(ret, forkfd_close(forkfd)); forkfd = -1; // Child is dead, don't try to kill it anymore @@ -935,7 +940,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - ::sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, nullptr); ::setsid(); @@ -964,7 +969,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) char **argv = new char *[arguments.size() + 2]; for (int i = 0; i < arguments.size(); ++i) argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData()); - argv[arguments.size() + 1] = 0; + argv[arguments.size() + 1] = nullptr; // Duplicate the environment. int envc = 0; @@ -991,7 +996,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - ::sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, nullptr); // '\1' means execv failed char c = '\1'; @@ -1002,7 +1007,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; - ::sigaction(SIGPIPE, &noaction, 0); + ::sigaction(SIGPIPE, &noaction, nullptr); // '\2' means internal error char c = '\2'; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 3ba86063e3..1527cf93ed 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -49,7 +49,6 @@ #include <qelapsedtimer.h> #include <qfileinfo.h> #include <qrandom.h> -#include <qregexp.h> #include <qwineventnotifier.h> #include <private/qsystemlibrary_p.h> #include <private/qthread_p.h> @@ -398,7 +397,17 @@ static QString qt_create_commandline(const QString &program, const QStringList & for (int i=0; i<arguments.size(); ++i) { QString tmp = arguments.at(i); // Quotes are escaped and their preceding backslashes are doubled. - tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + int index = tmp.indexOf(QLatin1Char('"')); + while (index >= 0) { + // Escape quote + tmp.insert(index++, QLatin1Char('\\')); + // Double preceding backslashes (ignoring the one we just inserted) + for (int i = index - 2 ; i >= 0 && tmp.at(i) == QLatin1Char('\\') ; --i) { + tmp.insert(i, QLatin1Char('\\')); + index++; + } + index = tmp.indexOf(QLatin1Char('"'), index + 1); + } if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { // The argument must not end with a \ since this would be interpreted // as escaping the quote -- rather put the \ behind the quote: e.g. @@ -590,7 +599,7 @@ void QProcessPrivate::startProcess() if (!pid) return; - if (threadData->hasEventDispatcher()) { + if (threadData.loadRelaxed()->hasEventDispatcher()) { processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q); QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied())); processFinishedNotifier->setEnabled(true); diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 86d361b06a..e636712e57 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. -** Copyright (C) 2019 Intel Corporation. +** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -60,14 +60,14 @@ #include "private/qtools_p.h" #include "private/qsystemerror_p.h" +#ifndef QT_NO_COMPRESS +# include <zconf.h> +# include <zlib.h> +#endif #if QT_CONFIG(zstd) # include <zstd.h> #endif -#ifdef Q_OS_UNIX -# include "private/qcore_unix_p.h" -#endif - #if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY) # define QT_USE_MMAP # include <sys/mman.h> @@ -280,9 +280,9 @@ static inline QStringList *resourceSearchPaths() RCC tool used to compress the payload. \value NoCompression Contents are not compressed - \value ZlibCompression Contents are compressed using \l{zlib}{https://zlib.net} and can + \value ZlibCompression Contents are compressed using \l{https://zlib.net}{zlib} and can be decompressed using the qUncompress() function. - \value ZstdCompression Contents are compressed using \l{zstd}{https://zstd.net}. To + \value ZstdCompression Contents are compressed using \l{https://zstd.net}{zstd}. To decompress, use the \c{ZSTD_decompress} function from the zstd library. @@ -296,6 +296,8 @@ public: void ensureInitialized() const; void ensureChildren() const; + qint64 uncompressedSize() const Q_DECL_PURE_FUNCTION; + qsizetype decompress(char *buffer, qsizetype bufferSize) const; bool load(const QString &file); void clear(); @@ -440,6 +442,78 @@ QResourcePrivate::ensureChildren() const } } +qint64 QResourcePrivate::uncompressedSize() const +{ + switch (compressionAlgo) { + case QResource::NoCompression: + return size; + + case QResource::ZlibCompression: +#ifndef QT_NO_COMPRESS + if (size_t(size) >= sizeof(quint32)) + return qFromBigEndian<quint32>(data); +#else + Q_ASSERT(!"QResource: Qt built without support for Zlib compression"); + Q_UNREACHABLE(); +#endif + break; + + case QResource::ZstdCompression: { +#if QT_CONFIG(zstd) + size_t n = ZSTD_getFrameContentSize(data, size); + return ZSTD_isError(n) ? -1 : qint64(n); +#else + // This should not happen because we've refused to load such resource + Q_ASSERT(!"QResource: Qt built without support for Zstd compression"); + Q_UNREACHABLE(); +#endif + } + + } + return -1; +} + +qsizetype QResourcePrivate::decompress(char *buffer, qsizetype bufferSize) const +{ + Q_ASSERT(data); + + switch (compressionAlgo) { + case QResource::NoCompression: + Q_UNREACHABLE(); + break; + + case QResource::ZlibCompression: { +#ifndef QT_NO_COMPRESS + uLong len = uLong(bufferSize); + int res = ::uncompress(reinterpret_cast<Bytef *>(buffer), &len, + data + sizeof(quint32), uLong(size - sizeof(quint32))); + if (res != Z_OK) { + qWarning("QResource: error decompressing zlib content (%d)", res); + return -1; + } + return len; +#else + Q_UNREACHABLE(); +#endif + } + + case QResource::ZstdCompression: { +#if QT_CONFIG(zstd) + size_t usize = ZSTD_decompress(buffer, bufferSize, data, size); + if (ZSTD_isError(usize)) { + qWarning("QResource: error decompressing zstd content: %s", ZSTD_getErrorName(usize)); + return -1; + } + return usize; +#else + Q_UNREACHABLE(); +#endif + } + } + + return -1; +} + /*! Constructs a QResource pointing to \a file. \a locale is used to load a specific localization of a resource data. @@ -600,9 +674,12 @@ QResource::Compression QResource::compressionAlgorithm() const } /*! - Returns the size of the data backing the resource. + Returns the size of the stored data backing the resource. - \sa data(), isFile() + If the resource is compressed, this function returns the size of the + compressed data. See uncompressedSize() for the uncompressed size. + + \sa data(), uncompressedSize(), isFile() */ qint64 QResource::size() const @@ -613,12 +690,29 @@ qint64 QResource::size() const } /*! - Returns direct access to a read only segment of data that this resource - represents. If the resource is compressed the data returned is compressed - and the appropriate library functions must be used to access the data. If - the resource is a directory \nullptr is returned. + \since 5.15 + + Returns the size of the data in this resource. If the data was not + compressed, this function returns the same as size(). If it was, then this + function extracts the size of the original uncompressed data from the + stored stream. - \sa size(), compressionAlgorithm(), isFile() + \sa size(), uncompressedData(), isFile() +*/ +qint64 QResource::uncompressedSize() const +{ + Q_D(const QResource); + d->ensureInitialized(); + return d->uncompressedSize(); +} + +/*! + Returns direct access to a segment of read-only data, that this resource + represents. If the resource is compressed, the data returned is also + compressed. The caller must then decompress the data or use + uncompressedData(). If the resource is a directory, \c nullptr is returned. + + \sa uncompressedData(), size(), isFile() */ const uchar *QResource::data() const @@ -629,6 +723,44 @@ const uchar *QResource::data() const } /*! + \since 5.15 + + Returns the resource data, decompressing it first, if the data was stored + compressed. If the resource is a directory or an error occurs while + decompressing, a null QByteArray is returned. + + \note If the data was compressed, this function will decompress every time + it is called. The result is not cached between calls. + + \sa uncompressedData(), size(), isCompressed(), isFile() +*/ + +QByteArray QResource::uncompressedData() const +{ + Q_D(const QResource); + qint64 n = uncompressedSize(); + if (n < 0) + return QByteArray(); + if (n > std::numeric_limits<QByteArray::size_type>::max()) { + qWarning("QResource: compressed content does not fit into a QByteArray; use QFile instead"); + return QByteArray(); + } + if (d->compressionAlgo == NoCompression) + return QByteArray::fromRawData(reinterpret_cast<const char *>(d->data), n); + + // decompress + QByteArray result(n, Qt::Uninitialized); + n = d->decompress(result.data(), n); + if (n < 0) + result.clear(); + else + result.truncate(n); + return result; +} + +/*! + \since 5.8 + Returns the date and time when the file was last modified before packaging into a resource. */ @@ -1443,13 +1575,7 @@ bool QResourceFileEngine::link(const QString &) qint64 QResourceFileEngine::size() const { Q_D(const QResourceFileEngine); - if (!d->resource.isValid()) - return 0; - if (d->resource.compressionAlgorithm() != QResource::NoCompression) { - d->uncompress(); - return d->uncompressed.size(); - } - return d->resource.size(); + return d->resource.isValid() ? d->resource.uncompressedSize() : 0; } qint64 QResourceFileEngine::pos() const @@ -1486,7 +1612,7 @@ bool QResourceFileEngine::isSequential() const QAbstractFileEngine::FileFlags QResourceFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const { Q_D(const QResourceFileEngine); - QAbstractFileEngine::FileFlags ret = 0; + QAbstractFileEngine::FileFlags ret; if(!d->resource.isValid()) return ret; @@ -1578,7 +1704,7 @@ QAbstractFileEngine::Iterator *QResourceFileEngine::beginEntryList(QDir::Filters */ QAbstractFileEngine::Iterator *QResourceFileEngine::endEntryList() { - return 0; + return nullptr; } bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) @@ -1588,7 +1714,7 @@ bool QResourceFileEngine::extension(Extension extension, const ExtensionOption * const MapExtensionOption *options = (const MapExtensionOption*)(option); MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output); returnValue->address = d->map(options->offset, options->size, options->flags); - return (returnValue->address != 0); + return (returnValue->address != nullptr); } if (extension == UnMapExtension) { const UnMapExtensionOption *options = (const UnMapExtensionOption*)option; @@ -1607,22 +1733,21 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory Q_Q(QResourceFileEngine); Q_UNUSED(flags); - qint64 max = resource.size(); - if (resource.compressionAlgorithm() != QResource::NoCompression) { - uncompress(); - max = uncompressed.size(); - } - + qint64 max = resource.uncompressedSize(); qint64 end; if (offset < 0 || size <= 0 || !resource.isValid() || add_overflow(offset, size, &end) || end > max) { q->setError(QFile::UnspecifiedError, QString()); - return 0; + return nullptr; } const uchar *address = resource.data(); - if (resource.compressionAlgorithm() != QResource::NoCompression) + if (resource.compressionAlgorithm() != QResource::NoCompression) { + uncompress(); + if (uncompressed.isNull()) + return nullptr; address = reinterpret_cast<const uchar *>(uncompressed.constData()); + } return const_cast<uchar *>(address) + offset; } @@ -1635,41 +1760,10 @@ bool QResourceFileEnginePrivate::unmap(uchar *ptr) void QResourceFileEnginePrivate::uncompress() const { - if (uncompressed.isEmpty() && resource.size()) { - quint64 size; - switch (resource.compressionAlgorithm()) { - case QResource::NoCompression: - return; // nothing to do - - case QResource::ZlibCompression: -#ifndef QT_NO_COMPRESS - uncompressed = qUncompress(resource.data(), resource.size()); -#else - Q_ASSERT(!"QResourceFileEngine::open: Qt built without support for Zlib compression"); -#endif - break; - - case QResource::ZstdCompression: -#if QT_CONFIG(zstd) - size = ZSTD_getFrameContentSize(resource.data(), resource.size()); - if (!ZSTD_isError(size)) { - if (size >= MaxAllocSize) { - qWarning("QResourceFileEngine::open: content bigger than memory (size %lld)", size); - } else { - uncompressed = QByteArray(size, Qt::Uninitialized); - size = ZSTD_decompress(const_cast<char *>(uncompressed.data()), size, - resource.data(), resource.size()); - } - } - if (ZSTD_isError(size)) - qWarning("QResourceFileEngine::open: error decoding: %s", ZSTD_getErrorName(size)); -#else - Q_UNUSED(size); - Q_ASSERT(!"QResourceFileEngine::open: Qt built without support for Zstd compression"); -#endif - break; - } - } + if (resource.compressionAlgorithm() == QResource::NoCompression + || !uncompressed.isEmpty() || resource.size() == 0) + return; // nothing to do + uncompressed = resource.uncompressedData(); } #endif // !defined(QT_BOOTSTRAPPED) diff --git a/src/corelib/io/qresource.h b/src/corelib/io/qresource.h index 5ee8d5d266..52b0d74d29 100644 --- a/src/corelib/io/qresource.h +++ b/src/corelib/io/qresource.h @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2019 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -75,6 +76,8 @@ public: Compression compressionAlgorithm() const; qint64 size() const; const uchar *data() const; + qint64 uncompressedSize() const; + QByteArray uncompressedData() const; QDateTime lastModified() const; #if QT_DEPRECATED_SINCE(5, 13) diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp index 0a884a7df9..067ccda3df 100644 --- a/src/corelib/io/qsavefile.cpp +++ b/src/corelib/io/qsavefile.cpp @@ -116,7 +116,7 @@ QSaveFile::QSaveFile(const QString &name) Constructs a new file object to represent the file with the given \a name. */ QSaveFile::QSaveFile(const QString &name) - : QFileDevice(*new QSaveFilePrivate, 0) + : QFileDevice(*new QSaveFilePrivate, nullptr) { Q_D(QSaveFile); d->fileName = name; diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index e485310e86..779b6f72de 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -76,10 +76,6 @@ # include <ioLib.h> #endif -#ifdef Q_OS_WASM -#include <emscripten.h> -#endif - #include <algorithm> #include <stdlib.h> @@ -210,7 +206,7 @@ QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms) ConfFileHash *usedHash = usedHashFunc(); ConfFileCache *unusedCache = unusedCacheFunc(); - QConfFile *confFile = 0; + QConfFile *confFile = nullptr; const auto locker = qt_scoped_lock(settingsGlobalMutex); if (!(confFile = usedHash->value(absPath))) { @@ -234,7 +230,7 @@ void QConfFile::clearCache() // QSettingsPrivate QSettingsPrivate::QSettingsPrivate(QSettings::Format format) - : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true), + : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(nullptr), fallbacks(true), pendingChanges(false), status(QSettings::NoError) { } @@ -242,7 +238,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format) QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) : format(format), scope(scope), organizationName(organization), applicationName(application), - iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) + iniCodec(nullptr), fallbacks(true), pendingChanges(false), status(QSettings::NoError) { } @@ -295,7 +291,7 @@ after_loop: // see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp -#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) +#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM) QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) { @@ -931,8 +927,8 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, int idx) void QConfFileSettingsPrivate::initFormat() { extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini"); - readFunc = 0; - writeFunc = 0; + readFunc = nullptr; + writeFunc = nullptr; #if defined(Q_OS_MAC) caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity; #else @@ -1188,7 +1184,9 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false)); } +#ifndef Q_OS_WASM // wasm needs to delay access until after file sync initAccess(); +#endif } QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName, @@ -1551,13 +1549,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) perms |= QFile::ReadGroup | QFile::ReadOther; QFile(confFile->name).setPermissions(perms); } -#ifdef Q_OS_WASM - EM_ASM( - // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002 - FS.syncfs(false, function(err) { - }); - ); -#endif } else { setStatus(QSettings::AccessError); } @@ -3350,7 +3341,7 @@ bool QSettings::contains(const QString &key) const { Q_D(const QSettings); QString k = d->actualKey(key); - return d->get(k, 0); + return d->get(k, nullptr); } /*! diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index d18c96a06c..c30f099a72 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -57,6 +57,10 @@ #include "QtCore/qiodevice.h" #include "QtCore/qstack.h" #include "QtCore/qstringlist.h" + +#include <QtCore/qvariant.h> +#include "qsettings.h" + #ifndef QT_NO_QOBJECT #include "private/qobject_p.h" #endif @@ -253,6 +257,10 @@ protected: mutable QSettings::Status status; }; +#ifdef Q_OS_WASM +class QWasmSettingsPrivate; +#endif + class QConfFileSettingsPrivate : public QSettingsPrivate { public: @@ -281,7 +289,7 @@ public: private: void initFormat(); - void initAccess(); + virtual void initAccess(); void syncConfFile(QConfFile *confFile); bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); #ifdef Q_OS_MAC @@ -297,6 +305,9 @@ private: QString extension; Qt::CaseSensitivity caseSensitivity; int nextPosition; +#ifdef Q_OS_WASM + friend class QWasmSettingsPrivate; +#endif }; QT_END_NAMESPACE diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp new file mode 100644 index 0000000000..8d8f4b505c --- /dev/null +++ b/src/corelib/io/qsettings_wasm.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsettings.h" +#ifndef QT_NO_SETTINGS + +#include "qsettings_p.h" +#ifndef QT_NO_QOBJECT +#include "qcoreapplication.h" +#include <QFile> +#endif // QT_NO_QOBJECT +#include <QDebug> + +#include <QFileInfo> +#include <QDir> +#include <emscripten.h> + +QT_BEGIN_NAMESPACE + +static bool isReadReady = false; + +class QWasmSettingsPrivate : public QConfFileSettingsPrivate +{ +public: + QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization, + const QString &application); + ~QWasmSettingsPrivate(); + + bool get(const QString &key, QVariant *value) const override; + QStringList children(const QString &prefix, ChildSpec spec) const override; + void clear() override; + void sync() override; + void flush() override; + bool isWritable() const override; + + void syncToLocal(const char *data, int size); + void loadLocal(const QByteArray &filename); + void setReady(); + void initAccess() override; + +private: + QString databaseName; + QString id; +}; + +static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData); + + QFile file(wasm->fileName()); + QFileInfo fileInfo(wasm->fileName()); + QDir dir(fileInfo.path()); + if (!dir.exists()) + dir.mkpath(fileInfo.path()); + + if (file.open(QFile::WriteOnly)) { + file.write(reinterpret_cast<char *>(dataPtr), size); + file.close(); + wasm->setReady(); + } +} + +static void QWasmSettingsPrivate_onError(void *userData) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData); + if (wasm) + wasm->setStatus(QSettings::AccessError); +} + +static void QWasmSettingsPrivate_onStore(void *userData) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData); + if (wasm) + wasm->setStatus(QSettings::NoError); +} + +static void QWasmSettingsPrivate_onCheck(void *userData, int exists) +{ + QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData); + if (wasm) { + if (exists) + wasm->loadLocal(wasm->fileName().toLocal8Bit()); + else + wasm->setReady(); + } +} + +QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, + QSettings::Scope scope, + const QString &organization, + const QString &application) +{ + Q_UNUSED(format) + if (organization == QLatin1String("Qt")) + { + QString organizationDomain = QCoreApplication::organizationDomain(); + QString applicationName = QCoreApplication::applicationName(); + + QSettingsPrivate *newSettings; + newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName); + + newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization))); + if (!application.isEmpty()) + newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application))); + + return newSettings; + } + return new QWasmSettingsPrivate(scope, organization, application); +} + +QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization, + const QString &application) + : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application) +{ + setStatus(QSettings::AccessError); // access error until sandbox gets loaded + databaseName = organization; + id = application; + + emscripten_idb_async_exists("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast<void*>(this), + QWasmSettingsPrivate_onCheck, + QWasmSettingsPrivate_onError); +} + +QWasmSettingsPrivate::~QWasmSettingsPrivate() +{ +} + + void QWasmSettingsPrivate::initAccess() +{ + if (isReadReady) + QConfFileSettingsPrivate::initAccess(); +} + +bool QWasmSettingsPrivate::get(const QString &key, QVariant *value) const +{ + if (isReadReady) + return QConfFileSettingsPrivate::get(key, value); + + return false; +} + +QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const +{ + return QConfFileSettingsPrivate::children(prefix, spec); +} + +void QWasmSettingsPrivate::clear() +{ + QConfFileSettingsPrivate::clear(); + emscripten_idb_async_delete("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast<void*>(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); +} + +void QWasmSettingsPrivate::sync() +{ + QConfFileSettingsPrivate::sync(); + + QFile file(fileName()); + if (file.open(QFile::ReadOnly)) { + QByteArray dataPointer = file.readAll(); + + emscripten_idb_async_store("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast<void *>(dataPointer.data()), + dataPointer.length(), + reinterpret_cast<void*>(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); + } +} + +void QWasmSettingsPrivate::flush() +{ + sync(); +} + +bool QWasmSettingsPrivate::isWritable() const +{ + return isReadReady && QConfFileSettingsPrivate::isWritable(); +} + +void QWasmSettingsPrivate::syncToLocal(const char *data, int size) +{ + QFile file(fileName()); + + if (file.open(QFile::WriteOnly)) { + file.write(data, size + 1); + QByteArray data = file.readAll(); + + emscripten_idb_async_store("/home/web_user", + fileName().toLocal8Bit(), + reinterpret_cast<void *>(data.data()), + data.length(), + reinterpret_cast<void*>(this), + QWasmSettingsPrivate_onStore, + QWasmSettingsPrivate_onError); + setReady(); + } +} + +void QWasmSettingsPrivate::loadLocal(const QByteArray &filename) +{ + emscripten_idb_async_load("/home/web_user", + filename.data(), + reinterpret_cast<void*>(this), + QWasmSettingsPrivate_onLoad, + QWasmSettingsPrivate_onError); +} + +void QWasmSettingsPrivate::setReady() +{ + isReadReady = true; + setStatus(QSettings::NoError); + QConfFileSettingsPrivate::initAccess(); +} + +QT_END_NAMESPACE +#endif // QT_NO_SETTINGS diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index 7874b854e4..a5128a868b 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -48,7 +48,7 @@ #include <qcoreapplication.h> #endif -#if QT_HAS_INCLUDE(<paths.h>) +#if __has_include(<paths.h>) #include <paths.h> #endif @@ -359,22 +359,14 @@ QT_BEGIN_NAMESPACE /*! \fn QString QStandardPaths::writableLocation(StandardLocation type) - Returns the directory where files of \a type should be written to, or an empty string - if the location cannot be determined. - - \note The storage location returned can be a directory that does not exist; i.e., it - may need to be created by the system or the user. + \include standardpath/functiondocs.qdocinc writableLocation */ /*! \fn QStringList QStandardPaths::standardLocations(StandardLocation type) - Returns all the directories where files of \a type belong. - - The list of directories is sorted from high to low priority, starting with - writableLocation() if it can be determined. This list is empty if no locations - for \a type are defined. + \include standardpath/functiondocs.qdocinc standardLocations \sa writableLocation() */ @@ -398,11 +390,7 @@ static bool existsAsSpecified(const QString &path, QStandardPaths::LocateOptions } /*! - Tries to find a file or directory called \a fileName in the standard locations - for \a type. - - The full path to the first file or directory (depending on \a options) found is returned. - If no such file or directory can be found, an empty string is returned. + \include standardpath/functiondocs.qdocinc locate */ QString QStandardPaths::locate(StandardLocation type, const QString &fileName, LocateOptions options) { @@ -416,12 +404,7 @@ QString QStandardPaths::locate(StandardLocation type, const QString &fileName, L } /*! - Tries to find all files or directories called \a fileName in the standard locations - for \a type. - - The \a options flag allows to specify whether to look for files or directories. - - Returns the list of all the files that were found. + \include standardpath/functiondocs.qdocinc locateAll */ QStringList QStandardPaths::locateAll(StandardLocation type, const QString &fileName, LocateOptions options) { @@ -494,23 +477,7 @@ static inline QString #endif // Q_OS_WIN /*! - Finds the executable named \a executableName in the paths specified by \a paths, - or the system paths if \a paths is empty. - - On most operating systems the system path is determined by the PATH environment variable. - - The directories where to search for the executable can be set in the \a paths argument. - To search in both your own paths and the system paths, call findExecutable twice, once with - \a paths set and once with \a paths empty. - - Symlinks are not resolved, in order to preserve behavior for the case of executables - whose behavior depends on the name they are invoked with. - - \note On Windows, the usual executable extensions (from the PATHEXT environment variable) - are automatically appended, so that for instance findExecutable("foo") will find foo.exe - or foo.bat if present. - - Returns the absolute file path to the executable, or an empty string if not found. + \include standardpath/functiondocs.qdocinc findExecutable */ QString QStandardPaths::findExecutable(const QString &executableName, const QStringList &paths) { @@ -568,10 +535,7 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr } /*! - \fn QString QStandardPaths::displayName(StandardLocation type) - - Returns a localized display name for the given location \a type or - an empty QString if no relevant location can be found. + \include standardpath/functiondocs.qdocinc displayName */ #if !defined(Q_OS_MAC) && !defined(QT_BOOTSTRAPPED) @@ -628,23 +592,7 @@ QString QStandardPaths::displayName(StandardLocation type) /*! \fn void QStandardPaths::setTestModeEnabled(bool testMode) - If \a testMode is true, this enables a special "test mode" in - QStandardPaths, which changes writable locations - to point to test directories, in order to prevent auto tests from reading from - or writing to the current user's configuration. - - This affects the locations into which test programs might write files: - GenericDataLocation, DataLocation, ConfigLocation, GenericConfigLocation, - AppConfigLocation, GenericCacheLocation, CacheLocation. - Other locations are not affected. - - On Unix, \c XDG_DATA_HOME is set to \e ~/.qttest/share, \c XDG_CONFIG_HOME is - set to \e ~/.qttest/config, and \c XDG_CACHE_HOME is set to \e ~/.qttest/cache. - - On \macos, data goes to \e ~/.qttest/Application Support, cache goes to - \e ~/.qttest/Cache, and config goes to \e ~/.qttest/Preferences. - - On Windows, everything goes to a "qttest" directory under Application Data. + \include standardpath/functiondocs.qdocinc setTestModeEnabled */ static bool qsp_testMode = false; diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 1e72241e68..37b8a60c37 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -108,7 +108,7 @@ # endif // QT_LARGEFILE_SUPPORT #endif // Q_OS_BSD4 -#if QT_HAS_INCLUDE(<paths.h>) +#if __has_include(<paths.h>) # include <paths.h> #endif #ifndef _PATH_MOUNTED diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index acd31f4d84..55d13dad70 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -631,6 +631,12 @@ QString QTemporaryFilePrivate::defaultTemplateName() case sensitive. If the template is not present in the filename, QTemporaryFile appends the generated part to the filename given. + \note On Linux, QTemporaryFile will attempt to create unnamed temporary + files. If that succeeds, open() will return true but exists() will be + false. If you call fileName() or any function that calls it, + QTemporaryFile will give the file a name, so most applications will + not see a difference. + \sa QDir::tempPath(), QFile */ diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index a7650390f9..0a5f9256eb 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -823,7 +823,7 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to) QString output; const QChar *begin = input.constData() + from; const QChar *end = input.constData() + to; - if (qt_urlRecode(output, begin, end, nullptr, actions)) + if (qt_urlRecode(output, begin, end, {}, actions)) return output; return input.mid(from, to - from); |