summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/forkfd_qt.c15
-rw-r--r--src/corelib/io/forkfd_qt.cpp48
-rw-r--r--src/corelib/io/qabstractfileengine.cpp287
-rw-r--r--src/corelib/io/qabstractfileengine_p.h98
-rw-r--r--src/corelib/io/qbuffer.cpp131
-rw-r--r--src/corelib/io/qbuffer.h48
-rw-r--r--src/corelib/io/qdataurl.cpp70
-rw-r--r--src/corelib/io/qdataurl_p.h41
-rw-r--r--src/corelib/io/qdebug.cpp379
-rw-r--r--src/corelib/io/qdebug.h242
-rw-r--r--src/corelib/io/qdebug_p.h47
-rw-r--r--src/corelib/io/qdir.cpp790
-rw-r--r--src/corelib/io/qdir.h70
-rw-r--r--src/corelib/io/qdir_p.h69
-rw-r--r--src/corelib/io/qdirentryinfo_p.h156
-rw-r--r--src/corelib/io/qdiriterator.cpp388
-rw-r--r--src/corelib/io/qdiriterator.h40
-rw-r--r--src/corelib/io/qdirlisting.cpp673
-rw-r--r--src/corelib/io/qdirlisting.h119
-rw-r--r--src/corelib/io/qfile.cpp254
-rw-r--r--src/corelib/io/qfile.h117
-rw-r--r--src/corelib/io/qfile_p.h40
-rw-r--r--src/corelib/io/qfiledevice.cpp113
-rw-r--r--src/corelib/io/qfiledevice.h56
-rw-r--r--src/corelib/io/qfiledevice_p.h49
-rw-r--r--src/corelib/io/qfileinfo.cpp848
-rw-r--r--src/corelib/io/qfileinfo.h68
-rw-r--r--src/corelib/io/qfileinfo_p.h60
-rw-r--r--src/corelib/io/qfileselector.cpp67
-rw-r--r--src/corelib/io/qfileselector.h40
-rw-r--r--src/corelib/io/qfileselector_p.h42
-rw-r--r--src/corelib/io/qfilesystemengine.cpp80
-rw-r--r--src/corelib/io/qfilesystemengine_mac.mm40
-rw-r--r--src/corelib/io/qfilesystemengine_p.h54
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp751
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp255
-rw-r--r--src/corelib/io/qfilesystementry.cpp109
-rw-r--r--src/corelib/io/qfilesystementry_p.h86
-rw-r--r--src/corelib/io/qfilesystemiterator_p.h66
-rw-r--r--src/corelib/io/qfilesystemiterator_unix.cpp113
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp71
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h95
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp101
-rw-r--r--src/corelib/io/qfilesystemwatcher.h44
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.mm52
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h40
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp47
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify_p.h40
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp46
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue_p.h40
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h52
-rw-r--r--src/corelib/io/qfilesystemwatcher_polling.cpp76
-rw-r--r--src/corelib/io/qfilesystemwatcher_polling_p.h54
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp79
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h45
-rw-r--r--src/corelib/io/qfsfileengine.cpp143
-rw-r--r--src/corelib/io/qfsfileengine_iterator.cpp81
-rw-r--r--src/corelib/io/qfsfileengine_iterator_p.h52
-rw-r--r--src/corelib/io/qfsfileengine_p.h64
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp83
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp97
-rw-r--r--src/corelib/io/qiodevice.cpp133
-rw-r--r--src/corelib/io/qiodevice.h40
-rw-r--r--src/corelib/io/qiodevice_p.h41
-rw-r--r--src/corelib/io/qiodevicebase.h40
-rw-r--r--src/corelib/io/qipaddress.cpp102
-rw-r--r--src/corelib/io/qipaddress_p.h40
-rw-r--r--src/corelib/io/qlockfile.cpp153
-rw-r--r--src/corelib/io/qlockfile.h58
-rw-r--r--src/corelib/io/qlockfile_p.h62
-rw-r--r--src/corelib/io/qlockfile_unix.cpp46
-rw-r--r--src/corelib/io/qlockfile_win.cpp48
-rw-r--r--src/corelib/io/qloggingcategory.cpp177
-rw-r--r--src/corelib/io/qloggingcategory.h83
-rw-r--r--src/corelib/io/qloggingregistry.cpp136
-rw-r--r--src/corelib/io/qloggingregistry_p.h59
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp109
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h43
-rw-r--r--src/corelib/io/qntdll_p.h44
-rw-r--r--src/corelib/io/qprocess.cpp550
-rw-r--r--src/corelib/io/qprocess.h86
-rw-r--r--src/corelib/io/qprocess_darwin.mm40
-rw-r--r--src/corelib/io/qprocess_p.h96
-rw-r--r--src/corelib/io/qprocess_unix.cpp713
-rw-r--r--src/corelib/io/qprocess_win.cpp124
-rw-r--r--src/corelib/io/qresource.cpp150
-rw-r--r--src/corelib/io/qresource.h42
-rw-r--r--src/corelib/io/qresource_iterator.cpp78
-rw-r--r--src/corelib/io/qresource_iterator_p.h47
-rw-r--r--src/corelib/io/qresource_p.h46
-rw-r--r--src/corelib/io/qsavefile.cpp62
-rw-r--r--src/corelib/io/qsavefile.h46
-rw-r--r--src/corelib/io/qsavefile_p.h44
-rw-r--r--src/corelib/io/qsettings.cpp810
-rw-r--r--src/corelib/io/qsettings.h74
-rw-r--r--src/corelib/io/qsettings_mac.cpp93
-rw-r--r--src/corelib/io/qsettings_p.h98
-rw-r--r--src/corelib/io/qsettings_wasm.cpp498
-rw-r--r--src/corelib/io/qsettings_win.cpp88
-rw-r--r--src/corelib/io/qstandardpaths.cpp114
-rw-r--r--src/corelib/io/qstandardpaths.h44
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp234
-rw-r--r--src/corelib/io/qstandardpaths_haiku.cpp48
-rw-r--r--src/corelib/io/qstandardpaths_mac.mm79
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp254
-rw-r--r--src/corelib/io/qstandardpaths_win.cpp83
-rw-r--r--src/corelib/io/qstorageinfo.cpp76
-rw-r--r--src/corelib/io/qstorageinfo.h55
-rw-r--r--src/corelib/io/qstorageinfo_linux.cpp288
-rw-r--r--src/corelib/io/qstorageinfo_linux_p.h244
-rw-r--r--src/corelib/io/qstorageinfo_mac.cpp49
-rw-r--r--src/corelib/io/qstorageinfo_p.h161
-rw-r--r--src/corelib/io/qstorageinfo_stub.cpp25
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp509
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp59
-rw-r--r--src/corelib/io/qtemporarydir.cpp104
-rw-r--r--src/corelib/io/qtemporarydir.h61
-rw-r--r--src/corelib/io/qtemporaryfile.cpp157
-rw-r--r--src/corelib/io/qtemporaryfile.h81
-rw-r--r--src/corelib/io/qtemporaryfile_p.h47
-rw-r--r--src/corelib/io/qurl.cpp553
-rw-r--r--src/corelib/io/qurl.h67
-rw-r--r--src/corelib/io/qurl_p.h46
-rw-r--r--src/corelib/io/qurlidna.cpp196
-rw-r--r--src/corelib/io/qurlquery.cpp122
-rw-r--r--src/corelib/io/qurlquery.h59
-rw-r--r--src/corelib/io/qurlrecode.cpp42
-rw-r--r--src/corelib/io/qwindowspipereader.cpp48
-rw-r--r--src/corelib/io/qwindowspipereader_p.h42
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp44
-rw-r--r--src/corelib/io/qwindowspipewriter_p.h42
-rw-r--r--src/corelib/io/qzip.cpp1347
-rw-r--r--src/corelib/io/qzipreader_p.h87
-rw-r--r--src/corelib/io/qzipwriter_p.h77
134 files changed, 9938 insertions, 9226 deletions
diff --git a/src/corelib/io/forkfd_qt.c b/src/corelib/io/forkfd_qt.c
new file mode 100644
index 0000000000..7107b2c6a0
--- /dev/null
+++ b/src/corelib/io/forkfd_qt.c
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <QtCore/qglobal.h>
+
+#define FORKFD_NO_SPAWNFD
+#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
+# define NDEBUG
+#endif
+
+#include <forkfd.h>
+#include "../../3rdparty/forkfd/forkfd.c"
diff --git a/src/corelib/io/forkfd_qt.cpp b/src/corelib/io/forkfd_qt.cpp
deleted file mode 100644
index cf44874153..0000000000
--- a/src/corelib/io/forkfd_qt.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qglobal.h>
-
-#define FORKFD_NO_SPAWNFD
-#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
-# define NDEBUG
-#endif
-
-#include <forkfd.h>
-#include "../../3rdparty/forkfd/forkfd.c"
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index d6b2b6a10e..ea5ce13b5e 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qabstractfileengine_p.h"
#include "private/qfsfileengine_p.h"
@@ -46,7 +10,7 @@
#include "qreadwritelock.h"
#include "qvariant.h"
// built-in handlers
-#include "qdiriterator.h"
+#include "qdirlisting.h"
#include "qstringbuilder.h"
#include <QtCore/private/qfilesystementry_p.h>
@@ -55,6 +19,19 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static QString appendSlashIfNeeded(const QString &path)
+{
+ if (!path.isEmpty() && !path.endsWith(u'/')
+#ifdef Q_OS_ANDROID
+ && !path.startsWith("content:/"_L1)
+#endif
+ )
+ return QString{path + u'/'};
+ return path;
+}
+
/*!
\class QAbstractFileEngineHandler
\inmodule QtCore
@@ -101,17 +78,20 @@ QT_BEGIN_NAMESPACE
\sa QAbstractFileEngine, QAbstractFileEngine::create()
*/
-static QBasicAtomicInt qt_file_engine_handlers_in_use = Q_BASIC_ATOMIC_INITIALIZER(false);
+Q_CONSTINIT static QBasicAtomicInt qt_file_engine_handlers_in_use = Q_BASIC_ATOMIC_INITIALIZER(false);
/*
All application-wide handlers are stored in this list. The mutex must be
acquired to ensure thread safety.
*/
-Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive))
-static bool qt_abstractfileenginehandlerlist_shutDown = false;
+Q_GLOBAL_STATIC(QReadWriteLock, fileEngineHandlerMutex, QReadWriteLock::Recursive)
+Q_CONSTINIT static bool qt_abstractfileenginehandlerlist_shutDown = false;
class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
{
+ Q_DISABLE_COPY_MOVE(QAbstractFileEngineHandlerList)
public:
+ QAbstractFileEngineHandlerList() = default;
+
~QAbstractFileEngineHandlerList()
{
QWriteLocker locker(fileEngineHandlerMutex());
@@ -157,29 +137,27 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
Handles calls to custom file engine handlers.
*/
-QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
+std::unique_ptr<QAbstractFileEngine> qt_custom_file_engine_handler_create(const QString &path)
{
- QAbstractFileEngine *engine = nullptr;
-
if (qt_file_engine_handlers_in_use.loadRelaxed()) {
QReadLocker locker(fileEngineHandlerMutex());
// check for registered handlers that can load the file
- QAbstractFileEngineHandlerList *handlers = fileEngineHandlers();
- for (int i = 0; i < handlers->size(); i++) {
- if ((engine = handlers->at(i)->create(path)))
- break;
+ for (QAbstractFileEngineHandler *handler : std::as_const(*fileEngineHandlers())) {
+ if (auto engine = handler->create(path))
+ return engine;
}
}
- return engine;
+ return nullptr;
}
/*!
- \fn QAbstractFileEngine *QAbstractFileEngineHandler::create(const QString &fileName) const
+ \fn std::unique_ptr<QAbstractFileEngine> QAbstractFileEngineHandler::create(const QString &fileName) const
- Creates a file engine for file \a fileName. Returns 0 if this
- file handler cannot handle \a fileName.
+ If this file handler can handle \a fileName, this method creates a file
+ engine and returns it wrapped in a std::unique_ptr; otherwise returns
+ nullptr.
Example:
@@ -201,16 +179,15 @@ QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
\sa QAbstractFileEngineHandler
*/
-QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
+std::unique_ptr<QAbstractFileEngine> QAbstractFileEngine::create(const QString &fileName)
{
QFileSystemEntry entry(fileName);
QFileSystemMetaData metaData;
- QAbstractFileEngine *engine = QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, metaData);
+ auto engine = QFileSystemEngine::createLegacyEngine(entry, metaData);
#ifndef QT_NO_FSFILEENGINE
- if (!engine)
- // fall back to regular file engine
- return new QFSFileEngine(entry.filePath());
+ if (!engine) // fall back to regular file engine
+ engine = std::make_unique<QFSFileEngine>(entry.filePath());
#endif
return engine;
@@ -264,6 +241,8 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
the base name).
\value AbsoluteLinkTarget The full file name of the file that this file is a
link to. (This will be empty if this file is not a link.)
+ \value RawLinkPath The raw link path of the file that this file is a
+ link to. (This will be empty if this file is not a link.)
\value CanonicalName Often very similar to AbsoluteLinkTarget. Will return the true path to the file.
\value CanonicalPathName Same as CanonicalName, excluding the base name.
\value BundleName Returns the name of the bundle implies BundleType is set.
@@ -326,20 +305,6 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
*/
/*!
- \enum QAbstractFileEngine::FileTime
-
- These are used by the fileTime() function.
-
- \value BirthTime When the file was born (created).
- \value MetadataChangeTime When the file's metadata was last changed.
- \value ModificationTime When the file was most recently modified.
- \value AccessTime When the file was most recently accessed (e.g.
- read or written to).
-
- \sa setFileName()
-*/
-
-/*!
\enum QAbstractFileEngine::FileOwner
\value OwnerUser The user who owns the file.
@@ -469,7 +434,7 @@ bool QAbstractFileEngine::seek(qint64 pos)
Returns \c true if the file is a sequential access device; returns
false if the file is a direct access device.
- Operations involving size() and seek(int) are not valid on
+ Operations involving size() and seek(qint64) are not valid on
sequential devices.
*/
bool QAbstractFileEngine::isSequential() const
@@ -627,12 +592,15 @@ bool QAbstractFileEngine::isRelativePath() const
QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
{
QStringList ret;
- QDirIterator it(fileName(), filterNames, filters);
- while (it.hasNext()) {
- it.next();
- ret << it.fileName();
- }
+#ifdef QT_BOOTSTRAPPED
+ Q_UNUSED(filters);
+ Q_UNUSED(filterNames);
+ Q_UNREACHABLE_RETURN(ret);
+#else
+ for (const auto &dirEntry : QDirListing(fileName(), filterNames, filters))
+ ret.emplace_back(dirEntry.fileName());
return ret;
+#endif
}
/*!
@@ -732,7 +700,7 @@ QString QAbstractFileEngine::owner(FileOwner owner) const
\sa fileTime()
*/
-bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_UNUSED(newDate);
Q_UNUSED(time);
@@ -749,7 +717,7 @@ bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
\sa setFileName(), QDateTime, QDateTime::isValid(), FileTime
*/
-QDateTime QAbstractFileEngine::fileTime(FileTime time) const
+QDateTime QAbstractFileEngine::fileTime(QFile::FileTime time) const
{
Q_UNUSED(time);
return QDateTime();
@@ -811,10 +779,7 @@ bool QAbstractFileEngine::atEnd() const
uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
- MapExtensionOption option;
- option.offset = offset;
- option.size = size;
- option.flags = flags;
+ const MapExtensionOption option(offset, size, flags);
MapExtensionReturn r;
if (!extension(MapExtension, &option, &r))
return nullptr;
@@ -835,8 +800,7 @@ uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlag
*/
bool QAbstractFileEngine::unmap(uchar *address)
{
- UnMapExtensionOption options;
- options.address = address;
+ const UnMapExtensionOption options(address);
return extension(UnMapExtension, &options);
}
@@ -863,11 +827,12 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
\internal
If all you want is to iterate over entries in a directory, see
- QDirIterator instead. This class is only for custom file engine authors.
+ QDirListing instead. This class is useful only for custom file engine
+ authors.
QAbstractFileEngineIterator is a unidirectional single-use virtual
- iterator that plugs into QDirIterator, providing transparent proxy
- iteration for custom file engines.
+ iterator that plugs into QDirListing, providing transparent proxy
+ iteration for custom file engines (for example, QResourceFileEngine).
You can subclass QAbstractFileEngineIterator to provide an iterator when
writing your own file engine. To plug the iterator into your file system,
@@ -888,10 +853,11 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
You can call dirName() to get the directory name, nameFilters() to get a
stringlist of name filters, and filters() to get the entry filters.
- The pure virtual function hasNext() returns \c true if the current directory
- has at least one more entry (i.e., the directory name is valid and
- accessible, and we have not reached the end of the entry list), and false
- otherwise. Reimplement next() to seek to the next entry.
+ The pure virtual function advance(), as its name implies, advances the
+ iterator to the next entry in the current directory; if the operation
+ was successful this method returns \c true, otherwise it returns \c
+ false. You have to reimplement this function in your sub-class to work
+ with your file engine implementation.
The pure virtual function currentFileName() returns the name of the
current entry without advancing the iterator. The currentFilePath()
@@ -906,15 +872,7 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
Note: QAbstractFileEngineIterator does not deal with QDir::IteratorFlags;
it simply returns entries for a single directory.
- \sa QDirIterator
-*/
-
-/*!
- \enum QAbstractFileEngineIterator::EntryInfoType
- \internal
-
- This enum describes the different types of information that can be
- requested through the QAbstractFileEngineIterator::entryInfo() function.
+ \sa QDirListing
*/
/*!
@@ -924,56 +882,45 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
Synonym for QAbstractFileEngineIterator.
*/
-class QAbstractFileEngineIteratorPrivate
-{
-public:
- QString path;
- QDir::Filters filters;
- QStringList nameFilters;
- QFileInfo fileInfo;
-};
+/*!
+ \typedef QAbstractFileEngine::IteratorUniquePtr
+ \since 6.8
+
+ Synonym for std::unique_ptr<Iterator> (that is a
+ std::unique_ptr<QAbstractFileEngineIterator>).
+*/
/*!
Constructs a QAbstractFileEngineIterator, using the entry filters \a
filters, and wildcard name filters \a nameFilters.
*/
-QAbstractFileEngineIterator::QAbstractFileEngineIterator(QDir::Filters filters,
+QAbstractFileEngineIterator::QAbstractFileEngineIterator(const QString &path, QDir::Filters filters,
const QStringList &nameFilters)
- : d(new QAbstractFileEngineIteratorPrivate)
+ : m_filters(filters),
+ m_nameFilters(nameFilters),
+ m_path(appendSlashIfNeeded(path))
{
- d->nameFilters = nameFilters;
- d->filters = filters;
}
/*!
Destroys the QAbstractFileEngineIterator.
- \sa QDirIterator
+ \sa QDirListing
*/
QAbstractFileEngineIterator::~QAbstractFileEngineIterator()
{
}
/*!
- Returns the path for this iterator. QDirIterator is responsible for
- assigning this path; it cannot change during the iterator's lifetime.
+
+ Returns the path for this iterator. The path is set by beginEntryList().
+ The path should't be changed once iteration begins.
\sa nameFilters(), filters()
*/
QString QAbstractFileEngineIterator::path() const
{
- return d->path;
-}
-
-/*!
- \internal
-
- Sets the iterator path to \a path. This function is called from within
- QDirIterator.
-*/
-void QAbstractFileEngineIterator::setPath(const QString &path)
-{
- d->path = path;
+ return m_path;
}
/*!
@@ -983,7 +930,7 @@ void QAbstractFileEngineIterator::setPath(const QString &path)
*/
QStringList QAbstractFileEngineIterator::nameFilters() const
{
- return d->nameFilters;
+ return m_nameFilters;
}
/*!
@@ -993,7 +940,7 @@ QStringList QAbstractFileEngineIterator::nameFilters() const
*/
QDir::Filters QAbstractFileEngineIterator::filters() const
{
- return d->filters;
+ return m_filters;
}
/*!
@@ -1014,15 +961,10 @@ QDir::Filters QAbstractFileEngineIterator::filters() const
QString QAbstractFileEngineIterator::currentFilePath() const
{
QString name = currentFileName();
- if (!name.isNull()) {
- QString tmp = path();
- if (!tmp.isEmpty()) {
- if (!tmp.endsWith(QLatin1Char('/')))
- tmp.append(QLatin1Char('/'));
- name.prepend(tmp);
- }
- }
- return name;
+ if (name.isNull())
+ return name;
+
+ return path() + name;
}
/*!
@@ -1037,75 +979,42 @@ QString QAbstractFileEngineIterator::currentFilePath() const
QFileInfo QAbstractFileEngineIterator::currentFileInfo() const
{
QString path = currentFilePath();
- if (d->fileInfo.filePath() != path)
- d->fileInfo.setFile(path);
+ if (m_fileInfo.filePath() != path)
+ m_fileInfo.setFile(path);
// return a shallow copy
- return d->fileInfo;
+ return m_fileInfo;
}
/*!
- \internal
-
- Returns the entry info \a type for this iterator's current directory entry
- as a QVariant. If \a type is undefined for this entry, a null QVariant is
- returned.
-
- \sa QAbstractFileEngine::beginEntryList(), QDir::beginEntryList()
-*/
-QVariant QAbstractFileEngineIterator::entryInfo(EntryInfoType type) const
-{
- Q_UNUSED(type);
- return QVariant();
-}
-
-/*!
- \fn virtual QString QAbstractFileEngineIterator::next() = 0
+ \fn virtual bool QAbstractFileEngineIterator::advance() = 0
This pure virtual function advances the iterator to the next directory
- entry, and returns the file path to the current entry.
+ entry; if the operation was successful this method returns \c true,
+ otherwise it returs \c false.
This function can optionally make use of nameFilters() and filters() to
optimize its performance.
Reimplement this function in a subclass to advance the iterator.
-
- \sa QDirIterator::next()
*/
/*!
- \fn virtual bool QAbstractFileEngineIterator::hasNext() const = 0
-
- This pure virtual function returns \c true if there is at least one more
- entry in the current directory (i.e., the iterator path is valid and
- accessible, and the iterator has not reached the end of the entry list).
+ Returns a QAbstractFileEngine::IteratorUniquePtr, that can be used
+ to iterate over the entries in \a path, using \a filters for entry
+ filtering and \a filterNames for name filtering. This function is called
+ by QDirListing to initiate directory iteration.
- \sa QDirIterator::hasNext()
+ \sa QDirListing
*/
-
-/*!
- Returns an instance of a QAbstractFileEngineIterator using \a filters for
- entry filtering and \a filterNames for name filtering. This function is
- called by QDirIterator to initiate directory iteration.
-
- QDirIterator takes ownership of the returned instance, and deletes it when
- it's done.
-
- \sa QDirIterator
-*/
-QAbstractFileEngine::Iterator *QAbstractFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+QAbstractFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
+ Q_UNUSED(path);
Q_UNUSED(filters);
Q_UNUSED(filterNames);
- return nullptr;
-}
-
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QAbstractFileEngine::endEntryList()
-{
- return nullptr;
+ return {};
}
/*!
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 9649e67029..b2e0b248da 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTFILEENGINE_P_H
#define QABSTRACTFILEENGINE_P_H
@@ -55,6 +19,7 @@
#include "QtCore/qfile.h"
#include "QtCore/qdir.h"
+#include <memory>
#include <optional>
#ifdef open
@@ -109,18 +74,14 @@ public:
CanonicalPathName,
BundleName,
JunctionName,
+ RawLinkPath,
NFileNames // Must be last.
};
enum FileOwner {
OwnerUser,
OwnerGroup
};
- enum FileTime {
- AccessTime,
- BirthTime,
- MetadataChangeTime,
- ModificationTime
- };
+
virtual ~QAbstractFileEngine();
@@ -151,8 +112,8 @@ public:
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
- virtual bool setFileTime(const QDateTime &newDate, FileTime time);
- virtual QDateTime fileTime(FileTime time) const;
+ virtual bool setFileTime(const QDateTime &newDate, QFile::FileTime time);
+ virtual QDateTime fileTime(QFile::FileTime time) const;
virtual void setFileName(const QString &file);
virtual int handle() const;
virtual bool cloneTo(QAbstractFileEngine *target);
@@ -161,8 +122,11 @@ public:
bool unmap(uchar *ptr);
typedef QAbstractFileEngineIterator Iterator;
- virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
- virtual Iterator *endEntryList();
+ using IteratorUniquePtr = std::unique_ptr<Iterator>;
+
+ virtual IteratorUniquePtr
+ beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames);
+ virtual IteratorUniquePtr endEntryList() { return {}; }
virtual qint64 read(char *data, qint64 maxlen);
virtual qint64 readLine(char *data, qint64 maxlen);
@@ -183,26 +147,33 @@ public:
{};
class MapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(MapExtensionOption)
public:
qint64 offset;
qint64 size;
QFile::MemoryMapFlags flags;
+ constexpr MapExtensionOption(qint64 off, qint64 sz, QFile::MemoryMapFlags f)
+ : offset(off), size(sz), flags(f) {}
};
class MapExtensionReturn : public ExtensionReturn {
+ Q_DISABLE_COPY_MOVE(MapExtensionReturn)
public:
- uchar *address;
+ MapExtensionReturn() = default;
+ uchar *address = nullptr;
};
class UnMapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(UnMapExtensionOption)
public:
- uchar *address;
+ uchar *address = nullptr;
+ constexpr UnMapExtensionOption(uchar *p) : address(p) {}
};
virtual bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr);
virtual bool supportsExtension(Extension extension) const;
// Factory
- static QAbstractFileEngine *create(const QString &fileName);
+ static std::unique_ptr<QAbstractFileEngine> create(const QString &fileName);
protected:
void setError(QFile::FileError error, const QString &str);
@@ -220,21 +191,21 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFileEngine::FileFlags)
class Q_CORE_EXPORT QAbstractFileEngineHandler
{
+ Q_DISABLE_COPY_MOVE(QAbstractFileEngineHandler)
public:
QAbstractFileEngineHandler();
virtual ~QAbstractFileEngineHandler();
- virtual QAbstractFileEngine *create(const QString &fileName) const = 0;
+ virtual std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const = 0;
};
-class QAbstractFileEngineIteratorPrivate;
class Q_CORE_EXPORT QAbstractFileEngineIterator
{
public:
- QAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters);
+ QAbstractFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &nameFilters);
virtual ~QAbstractFileEngineIterator();
- virtual QString next() = 0;
- virtual bool hasNext() const = 0;
+ virtual bool advance() = 0;
QString path() const;
QStringList nameFilters() const;
@@ -242,19 +213,20 @@ public:
virtual QString currentFileName() const = 0;
virtual QFileInfo currentFileInfo() const;
- QString currentFilePath() const;
+ virtual QString currentFilePath() const;
protected:
- enum EntryInfoType {
- };
- virtual QVariant entryInfo(EntryInfoType type) const;
+ mutable QFileInfo m_fileInfo;
private:
Q_DISABLE_COPY_MOVE(QAbstractFileEngineIterator)
friend class QDirIterator;
friend class QDirIteratorPrivate;
- void setPath(const QString &path);
- QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
+ friend class QDirListingPrivate;
+
+ QDir::Filters m_filters;
+ QStringList m_nameFilters;
+ QString m_path;
};
class QAbstractFileEnginePrivate
@@ -273,7 +245,7 @@ public:
Q_DECLARE_PUBLIC(QAbstractFileEngine)
};
-QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path);
+std::unique_ptr<QAbstractFileEngine> qt_custom_file_engine_handler_create(const QString &path);
QT_END_NAMESPACE
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index 595fcd2724..763620692c 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbuffer.h"
#include <QtCore/qmetaobject.h>
#include "private/qiodevice_p.h"
+#include <limits>
+
QT_BEGIN_NAMESPACE
/** QBufferPrivate **/
@@ -49,15 +15,9 @@ class QBufferPrivate : public QIODevicePrivate
Q_DECLARE_PUBLIC(QBuffer)
public:
- QBufferPrivate()
- : buf(nullptr)
-#ifndef QT_NO_QOBJECT
- , writtenSinceLastEmit(0), signalConnectionCount(0), signalsEmitted(false)
-#endif
- { }
- ~QBufferPrivate() { }
+ QBufferPrivate() = default;
- QByteArray *buf;
+ QByteArray *buf = nullptr;
QByteArray defaultBuf;
qint64 peek(char *data, qint64 maxSize) override;
@@ -67,9 +27,9 @@ public:
// private slots
void _q_emitSignals();
- qint64 writtenSinceLastEmit;
- int signalConnectionCount;
- bool signalsEmitted;
+ qint64 writtenSinceLastEmit = 0;
+ int signalConnectionCount = 0;
+ bool signalsEmitted = false;
#endif
};
@@ -212,7 +172,7 @@ QBuffer::~QBuffer()
}
/*!
- Makes QBuffer uses the QByteArray pointed to by \a
+ Makes QBuffer use the QByteArray pointed to by \a
byteArray as its internal buffer. The caller is responsible for
ensuring that \a byteArray remains valid until the QBuffer is
destroyed, or until setBuffer() is called to change the buffer.
@@ -307,16 +267,31 @@ void QBuffer::setData(const QByteArray &data)
}
/*!
- \fn void QBuffer::setData(const char *data, int size)
-
\overload
Sets the contents of the internal buffer to be the first \a size
bytes of \a data.
+
+ \note In Qt versions prior to 6.5, this function took the length as
+ an \c{int} parameter, potentially truncating sizes.
*/
+void QBuffer::setData(const char *data, qsizetype size)
+{
+ Q_D(QBuffer);
+ if (isOpen()) {
+ qWarning("QBuffer::setData: Buffer is open");
+ return;
+ }
+ d->buf->replace(qsizetype(0), d->buf->size(), // ### QByteArray lacks assign(ptr, n)
+ data, size);
+}
/*!
\reimp
+
+ Unlike QFile, opening a QBuffer QIODevice::WriteOnly does not truncate it.
+ However, pos() is set to 0. Use QIODevice::Append or QIODevice::Truncate to
+ change either behavior.
*/
bool QBuffer::open(OpenMode flags)
{
@@ -366,18 +341,19 @@ qint64 QBuffer::size() const
bool QBuffer::seek(qint64 pos)
{
Q_D(QBuffer);
- if (pos > d->buf->size() && isWritable()) {
- if (seek(d->buf->size())) {
- const qint64 gapSize = pos - d->buf->size();
- if (write(QByteArray(gapSize, 0)) != gapSize) {
- qWarning("QBuffer::seek: Unable to fill gap");
- return false;
- }
- } else {
+ const auto oldBufSize = d->buf->size();
+ constexpr qint64 MaxSeekPos = (std::numeric_limits<decltype(oldBufSize)>::max)();
+ if (pos <= MaxSeekPos && pos > oldBufSize && isWritable()) {
+ QT_TRY {
+ d->buf->resize(qsizetype(pos), '\0');
+ } QT_CATCH(const std::bad_alloc &) {} // swallow, failure case is handled below
+ if (d->buf->size() != pos) {
+ qWarning("QBuffer::seek: Unable to fill gap");
return false;
}
- } else if (pos > d->buf->size() || pos < 0) {
- qWarning("QBuffer::seek: Invalid pos: %d", int(pos));
+ }
+ if (pos > d->buf->size() || pos < 0) {
+ qWarning("QBuffer::seek: Invalid pos: %lld", pos);
return false;
}
return QIODevice::seek(pos);
@@ -421,17 +397,19 @@ qint64 QBuffer::readData(char *data, qint64 len)
qint64 QBuffer::writeData(const char *data, qint64 len)
{
Q_D(QBuffer);
- int extraBytes = pos() + len - d->buf->size();
- if (extraBytes > 0) { // overflow
- int newSize = d->buf->size() + extraBytes;
- d->buf->resize(newSize);
- if (d->buf->size() != newSize) { // could not resize
+ const quint64 required = quint64(pos()) + quint64(len); // cannot overflow (pos() ≥ 0, len ≥ 0)
+
+ if (required > quint64(d->buf->size())) { // capacity exceeded
+ // The following must hold, since qsizetype covers half the virtual address space:
+ Q_ASSERT(required <= quint64((std::numeric_limits<qsizetype>::max)()));
+ d->buf->resize(qsizetype(required));
+ if (quint64(d->buf->size()) != required) { // could not resize
qWarning("QBuffer::writeData: Memory allocation error");
return -1;
}
}
- memcpy(d->buf->data() + pos(), data, int(len));
+ memcpy(d->buf->data() + pos(), data, size_t(len));
#ifndef QT_NO_QOBJECT
d->writtenSinceLastEmit += len;
@@ -444,15 +422,22 @@ qint64 QBuffer::writeData(const char *data, qint64 len)
}
#ifndef QT_NO_QOBJECT
+static bool is_tracked_signal(const QMetaMethod &signal)
+{
+ // dynamic initialization: minimize the number of guard variables:
+ static const struct {
+ QMetaMethod readyReadSignal = QMetaMethod::fromSignal(&QBuffer::readyRead);
+ QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(&QBuffer::bytesWritten);
+ } sigs;
+ return signal == sigs.readyReadSignal || signal == sigs.bytesWrittenSignal;
+}
/*!
\reimp
\internal
*/
void QBuffer::connectNotify(const QMetaMethod &signal)
{
- static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(&QBuffer::readyRead);
- static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(&QBuffer::bytesWritten);
- if (signal == readyReadSignal || signal == bytesWrittenSignal)
+ if (is_tracked_signal(signal))
d_func()->signalConnectionCount++;
}
@@ -463,9 +448,7 @@ void QBuffer::connectNotify(const QMetaMethod &signal)
void QBuffer::disconnectNotify(const QMetaMethod &signal)
{
if (signal.isValid()) {
- static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(&QBuffer::readyRead);
- static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(&QBuffer::bytesWritten);
- if (signal == readyReadSignal || signal == bytesWrittenSignal)
+ if (is_tracked_signal(signal))
d_func()->signalConnectionCount--;
} else {
d_func()->signalConnectionCount = 0;
diff --git a/src/corelib/io/qbuffer.h b/src/corelib/io/qbuffer.h
index c2aba92a10..4cbbfe7c52 100644
--- a/src/corelib/io/qbuffer.h
+++ b/src/corelib/io/qbuffer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBUFFER_H
#define QBUFFER_H
@@ -69,7 +33,10 @@ public:
void setBuffer(QByteArray *a);
void setData(const QByteArray &data);
- inline void setData(const char *data, int len);
+#if QT_CORE_REMOVED_SINCE(6, 5) && QT_POINTER_SIZE != 4
+ void setData(const char *data, int len) { setData(data, qsizetype(len)); }
+#endif
+ void setData(const char *data, qsizetype len);
const QByteArray &data() const;
bool open(OpenMode openMode) override;
@@ -96,9 +63,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_emitSignals())
};
-inline void QBuffer::setData(const char *adata, int alen)
-{ setData(QByteArray(adata, alen)); }
-
QT_END_NAMESPACE
#endif // QBUFFER_H
diff --git a/src/corelib/io/qdataurl.cpp b/src/corelib/io/qdataurl.cpp
index 9cb1b9abd0..65b934b3f6 100644
--- a/src/corelib/io/qdataurl.cpp
+++ b/src/corelib/io/qdataurl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qurl.h"
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals;
+
/*!
\internal
@@ -51,41 +17,45 @@ QT_BEGIN_NAMESPACE
*/
Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload)
{
- if (uri.scheme() != QLatin1String("data") || !uri.host().isEmpty())
+ if (uri.scheme() != "data"_L1 || !uri.host().isEmpty())
return false;
- mimeType = QLatin1String("text/plain;charset=US-ASCII");
+ mimeType = QStringLiteral("text/plain;charset=US-ASCII");
// the following would have been the correct thing, but
// reality often differs from the specification. People have
// data: URIs with ? and #
//QByteArray data = QByteArray::fromPercentEncoding(uri.path(QUrl::FullyEncoded).toLatin1());
- QByteArray data = QByteArray::fromPercentEncoding(uri.url(QUrl::FullyEncoded | QUrl::RemoveScheme).toLatin1());
+ const QByteArray dataArray =
+ QByteArray::fromPercentEncoding(uri.url(QUrl::FullyEncoded | QUrl::RemoveScheme).toLatin1());
+ QByteArrayView data = dataArray;
// parse it:
- int pos = data.indexOf(',');
+ const qsizetype pos = data.indexOf(',');
if (pos != -1) {
- payload = data.mid(pos + 1);
+ payload = data.mid(pos + 1).toByteArray();
data.truncate(pos);
data = data.trimmed();
// find out if the payload is encoded in Base64
- if (data.endsWith(";base64")) {
+ constexpr auto base64 = ";base64"_L1;
+ if (QLatin1StringView{data}.endsWith(base64, Qt::CaseInsensitive)) {
payload = QByteArray::fromBase64(payload);
- data.chop(7);
+ data.chop(base64.size());
}
- if (data.toLower().startsWith("charset")) {
- int i = 7; // strlen("charset")
+ QLatin1StringView textPlain;
+ constexpr auto charset = "charset"_L1;
+ if (QLatin1StringView{data}.startsWith(charset, Qt::CaseInsensitive)) {
+ qsizetype i = charset.size();
while (data.at(i) == ' ')
++i;
if (data.at(i) == '=')
- data.prepend("text/plain;");
+ textPlain = "text/plain;"_L1;
}
if (!data.isEmpty())
- mimeType = QLatin1String(data.trimmed());
-
+ mimeType = textPlain + QLatin1StringView(data.trimmed());
}
return true;
diff --git a/src/corelib/io/qdataurl_p.h b/src/corelib/io/qdataurl_p.h
index fd5c7df50b..2763056cc4 100644
--- a/src/corelib/io/qdataurl_p.h
+++ b/src/corelib/io/qdataurl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDATAURL_P_H
#define QDATAURL_P_H
@@ -55,7 +19,6 @@
#include "QtCore/qurl.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qstring.h"
-#include "QtCore/qpair.h"
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index a7ce66ad14..64b693fea5 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -1,76 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
-
-#ifdef QT_NO_DEBUG
-#undef QT_NO_DEBUG
-#endif
-#ifdef qDebug
-#undef qDebug
-#endif
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdebug.h"
#include "private/qdebug_p.h"
#include "qmetaobject.h"
+#include <private/qlogging_p.h>
#include <private/qtextstream_p.h>
#include <private/qtools_p.h>
-#include <ctype.h>
+
+#include <array>
+#include <q20chrono.h>
QT_BEGIN_NAMESPACE
-using QtMiscUtils::toHexUpper;
-using QtMiscUtils::toHexLower;
-using QtMiscUtils::fromHex;
+using namespace QtMiscUtils;
/*
Returns a human readable representation of the first \a maxSize
- characters in \a data.
+ characters in \a data. The size, \a len, is a 64-bit quantity to
+ avoid truncation due to implicit conversions in callers.
*/
-QByteArray QtDebugUtils::toPrintable(const char *data, int len, int maxSize)
+QByteArray QtDebugUtils::toPrintable(const char *data, qint64 len, qsizetype maxSize)
{
if (!data)
return "(null)";
QByteArray out;
- for (int i = 0; i < qMin(len, maxSize); ++i) {
+ for (qsizetype i = 0; i < qMin(len, maxSize); ++i) {
char c = data[i];
- if (isprint(c)) {
+ if (isAsciiPrintable(c)) {
out += c;
} else {
switch (c) {
@@ -192,15 +151,15 @@ QByteArray QtDebugUtils::toPrintable(const char *data, int len, int maxSize)
Flushes any pending data to be written and destroys the debug stream.
*/
-// Has been defined in the header / inlined before Qt 5.4
QDebug::~QDebug()
{
if (stream && !--stream->ref) {
- if (stream->space && stream->buffer.endsWith(QLatin1Char(' ')))
+ if (stream->space && stream->buffer.endsWith(u' '))
stream->buffer.chop(1);
if (stream->message_output) {
+ QInternalMessageLogContext ctxt(stream->context);
qt_message_output(stream->type,
- stream->context,
+ ctxt,
stream->buffer);
}
delete stream;
@@ -222,7 +181,7 @@ void QDebug::putUcs4(uint ucs4)
stream->ts << "\\u" << qSetFieldWidth(4);
else
stream->ts << "\\U" << qSetFieldWidth(8);
- stream->ts << Qt::hex << qSetPadChar(QLatin1Char('0')) << ucs4 << Qt::reset;
+ stream->ts << Qt::hex << qSetPadChar(u'0') << ucs4 << Qt::reset;
}
maybeQuote('\'');
}
@@ -230,17 +189,15 @@ void QDebug::putUcs4(uint ucs4)
// These two functions return true if the character should be printed by QDebug.
// For QByteArray, this is technically identical to US-ASCII isprint();
// for QString, we use QChar::isPrint, which requires a full UCS-4 decode.
-static inline bool isPrintable(uint ucs4)
-{ return QChar::isPrint(ucs4); }
-static inline bool isPrintable(ushort uc)
-{ return QChar::isPrint(uc); }
+static inline bool isPrintable(char32_t ucs4) { return QChar::isPrint(ucs4); }
+static inline bool isPrintable(char16_t uc) { return QChar::isPrint(uc); }
static inline bool isPrintable(uchar c)
-{ return c >= ' ' && c < 0x7f; }
+{ return isAsciiPrintable(c); }
template <typename Char>
-static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, int length, bool isUnicode = true)
+static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, size_t length, bool isUnicode = true)
{
- QChar quote(QLatin1Char('"'));
+ QChar quote(u'"');
d->write(&quote, 1);
bool lastWasHexEscape = false;
@@ -250,7 +207,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
if (Q_UNLIKELY(lastWasHexEscape)) {
if (fromHex(*p) != -1) {
// yes, insert it
- QChar quotes[] = { QLatin1Char('"'), QLatin1Char('"') };
+ QChar quotes[] = { quote, quote };
d->write(quotes, 2);
}
lastWasHexEscape = false;
@@ -258,7 +215,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
if (sizeof(Char) == sizeof(QChar)) {
// Surrogate characters are category Cs (Other_Surrogate), so isPrintable = false for them
- int runLength = 0;
+ qsizetype runLength = 0;
while (p + runLength != end &&
isPrintable(p[runLength]) && p[runLength] != '\\' && p[runLength] != '"')
++runLength;
@@ -274,8 +231,8 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
}
// print as an escape sequence (maybe, see below for surrogate pairs)
- int buflen = 2;
- ushort buf[sizeof "\\U12345678" - 1];
+ qsizetype buflen = 2;
+ char16_t buf[std::char_traits<char>::length("\\U12345678")];
buf[0] = '\\';
switch (*p) {
@@ -311,7 +268,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
if (QChar::isHighSurrogate(*p)) {
if ((p + 1) != end && QChar::isLowSurrogate(p[1])) {
// properly-paired surrogates
- uint ucs4 = QChar::surrogateToUcs4(*p, p[1]);
+ char32_t ucs4 = QChar::surrogateToUcs4(*p, p[1]);
if (isPrintable(ucs4)) {
buf[0] = *p;
buf[1] = p[1];
@@ -334,8 +291,8 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
// improperly-paired surrogates, fall through
}
buf[1] = 'u';
- buf[2] = toHexUpper(ushort(*p) >> 12);
- buf[3] = toHexUpper(ushort(*p) >> 8);
+ buf[2] = toHexUpper(char16_t(*p) >> 12);
+ buf[3] = toHexUpper(char16_t(*p) >> 8);
buf[4] = toHexUpper(*p >> 4);
buf[5] = toHexUpper(*p);
buflen = 6;
@@ -355,12 +312,12 @@ void QDebug::putString(const QChar *begin, size_t length)
if (stream->noQuotes) {
// no quotes, write the string directly too (no pretty-printing)
// this respects the QTextStream state, though
- stream->ts.d_ptr->putString(begin, int(length));
+ stream->ts.d_ptr->putString(begin, qsizetype(length));
} else {
// we'll reset the QTextStream formatting mechanisms, so save the state
QDebugStateSaver saver(*this);
stream->ts.d_ptr->params.reset();
- putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), int(length));
+ putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const char16_t *>(begin), length);
}
}
@@ -373,17 +330,188 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten
if (stream->noQuotes) {
// no quotes, write the string directly too (no pretty-printing)
// this respects the QTextStream state, though
- QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, int(length)) : QString::fromUtf8(begin, int(length));
+ QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, qsizetype(length))
+ : QString::fromUtf8(begin, qsizetype(length));
stream->ts.d_ptr->putString(string);
} else {
// we'll reset the QTextStream formatting mechanisms, so save the state
QDebugStateSaver saver(*this);
stream->ts.d_ptr->params.reset();
putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const uchar *>(begin),
- int(length), content == ContainsLatin1);
+ length, content == ContainsLatin1);
}
}
+static QByteArray timeUnit(qint64 num, qint64 den)
+{
+ using namespace std::chrono;
+ using namespace q20::chrono;
+
+ if (num == 1 && den > 1) {
+ // sub-multiple of seconds
+ char prefix = '\0';
+ auto tryprefix = [&](auto d, char c) {
+ static_assert(decltype(d)::num == 1, "not an SI prefix");
+ if (den == decltype(d)::den)
+ prefix = c;
+ };
+
+ // "u" should be "µ", but debugging output is not always UTF-8-safe
+ tryprefix(std::milli{}, 'm');
+ tryprefix(std::micro{}, 'u');
+ tryprefix(std::nano{}, 'n');
+ tryprefix(std::pico{}, 'p');
+ tryprefix(std::femto{}, 'f');
+ tryprefix(std::atto{}, 'a');
+ // uncommon ones later
+ tryprefix(std::centi{}, 'c');
+ tryprefix(std::deci{}, 'd');
+ if (prefix) {
+ char unit[3] = { prefix, 's' };
+ return QByteArray(unit, sizeof(unit) - 1);
+ }
+ }
+
+ const char *unit = nullptr;
+ if (num > 1 && den == 1) {
+ // multiple of seconds - but we don't use SI prefixes
+ auto tryunit = [&](auto d, const char *name) {
+ static_assert(decltype(d)::period::den == 1, "not a multiple of a second");
+ if (unit || num % decltype(d)::period::num)
+ return;
+ unit = name;
+ num /= decltype(d)::period::num;
+ };
+ tryunit(years{}, "yr");
+ tryunit(weeks{}, "wk");
+ tryunit(days{}, "d");
+ tryunit(hours{}, "h");
+ tryunit(minutes{}, "min");
+ }
+ if (!unit)
+ unit = "s";
+
+ if (num == 1 && den == 1)
+ return unit;
+ if (Q_UNLIKELY(num < 1 || den < 1))
+ return QString::asprintf("<invalid time unit %lld/%lld>", num, den).toLatin1();
+
+ // uncommon units: will return something like "[2/3]s"
+ // strlen("[/]min") = 6
+ char buf[2 * (std::numeric_limits<qint64>::digits10 + 2) + 10];
+ size_t len = 0;
+ auto appendChar = [&](char c) {
+ Q_ASSERT(len < sizeof(buf));
+ buf[len++] = c;
+ };
+ auto appendNumber = [&](qint64 value) {
+ if (value >= 10'000 && (value % 1000) == 0)
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%.6g", double(value)); // "1e+06"
+ else
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%lld", value);
+ };
+ appendChar('[');
+ appendNumber(num);
+ if (den != 1) {
+ appendChar('/');
+ appendNumber(den);
+ }
+ appendChar(']');
+ memcpy(buf + len, unit, strlen(unit));
+ return QByteArray(buf, len + strlen(unit));
+}
+
+/*!
+ \since 6.6
+ \internal
+ Helper to the std::chrono::duration debug streaming output.
+ */
+void QDebug::putTimeUnit(qint64 num, qint64 den)
+{
+ stream->ts << timeUnit(num, den); // ### optimize
+}
+
+namespace {
+
+#ifdef QT_SUPPORTS_INT128
+
+constexpr char Q_INT128_MIN_STR[] = "-170141183460469231731687303715884105728";
+
+constexpr int Int128BufferSize = sizeof(Q_INT128_MIN_STR);
+using Int128Buffer = std::array<char, Int128BufferSize>;
+ // numeric_limits<qint128>::digits10 may not exist
+
+static char *i128ToStringHelper(Int128Buffer &buffer, quint128 n)
+{
+ auto dst = buffer.data() + buffer.size();
+ *--dst = '\0'; // NUL-terminate
+ if (n == 0) {
+ *--dst = '0'; // and done
+ } else {
+ while (n != 0) {
+ *--dst = "0123456789"[n % 10];
+ n /= 10;
+ }
+ }
+ return dst;
+}
+#endif // QT_SUPPORTS_INT128
+
+[[maybe_unused]]
+static const char *int128Warning()
+{
+ const char *msg = "Qt was not compiled with int128 support.";
+ qWarning("%s", msg);
+ return msg;
+}
+
+} // unnamed namespace
+
+/*!
+ \since 6.7
+ \internal
+ Helper to the qint128 debug streaming output.
+ */
+void QDebug::putInt128([[maybe_unused]] const void *p)
+{
+#ifdef QT_SUPPORTS_INT128
+ Q_ASSERT(p);
+ qint128 i;
+ memcpy(&i, p, sizeof(i)); // alignment paranoia
+ if (i == Q_INT128_MIN) {
+ // -i is not representable, hardcode the result:
+ stream->ts << Q_INT128_MIN_STR;
+ } else {
+ Int128Buffer buffer;
+ auto dst = i128ToStringHelper(buffer, i < 0 ? -i : i);
+ if (i < 0)
+ *--dst = '-';
+ stream->ts << dst;
+ }
+ return;
+#endif // QT_SUPPORTS_INT128
+ stream->ts << int128Warning();
+}
+
+/*!
+ \since 6.7
+ \internal
+ Helper to the quint128 debug streaming output.
+ */
+void QDebug::putUInt128([[maybe_unused]] const void *p)
+{
+#ifdef QT_SUPPORTS_INT128
+ Q_ASSERT(p);
+ quint128 i;
+ memcpy(&i, p, sizeof(i)); // alignment paranoia
+ Int128Buffer buffer;
+ stream->ts << i128ToStringHelper(buffer, i);
+ return;
+#endif // QT_SUPPORTS_INT128
+ stream->ts << int128Warning();
+}
+
+
/*!
\fn QDebug::swap(QDebug &other)
\since 5.0
@@ -460,6 +588,29 @@ QDebug &QDebug::resetFormat()
/*!
+ \fn bool QDebug::quoteStrings() const
+ \since 6.7
+
+ Returns \c true if this QDebug instance will quote strings streamed into
+ it (which is the default).
+
+ \sa QDebugStateSaver, quote(), noquote(), setQuoteStrings()
+*/
+
+/*!
+ \fn void QDebug::setQuoteStrings(bool b)
+ \since 6.7
+
+ Enables quoting of strings streamed into this QDebug instance if \a b is
+ \c true; otherwise quoting is disabled.
+
+ The default is to quote strings.
+
+ \sa QDebugStateSaver, quote(), noquote(), quoteStrings()
+*/
+
+
+/*!
\fn QDebug &QDebug::quote()
\since 5.4
@@ -728,7 +879,7 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(QLatin1String t)
+ \fn QDebug &QDebug::operator<<(QLatin1StringView t)
Writes the string, \a t, to the stream and returns a reference to the
stream. Normally, QDebug prints the string inside quotes and transforms
@@ -798,6 +949,53 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 6.5
+ \fn template <typename Char, typename...Args> QDebug &QDebug::operator<<(const std::basic_string<Char, Args...> &s)
+ \fn template <typename Char, typename...Args> QDebug &QDebug::operator<<(std::basic_string_view<Char, Args...> s)
+
+ Writes the string or string-view \a s to the stream and returns a reference
+ to the stream.
+
+ These operators only participate in overload resolution if \c Char is one of
+ \list
+ \li char
+ \li char8_t (C++20 only)
+ \li char16_t
+ \li char32_t
+ \li wchar_t
+ \endlist
+*/
+
+/*!
+ \since 6.6
+ \fn template <typename Rep, typename Period> QDebug &QDebug::operator<<(std::chrono::duration<Rep, Period> duration)
+
+ Prints the time duration \a duration to the stream and returns a reference
+ to the stream. The printed string is the numeric representation of the
+ period followed by the time unit, similar to what the C++ Standard Library
+ would produce with \c{std::ostream}.
+
+ The unit is not localized.
+*/
+
+/*!
+ \fn template <typename T, QDebug::if_qint128<T>> QDebug::operator<<(T i)
+ \fn template <typename T, QDebug::if_quint128<T>> QDebug::operator<<(T i)
+ \since 6.7
+
+ Prints the textual representation of the 128-bit integer \a i.
+
+ \note This operator is only available if Qt supports 128-bit integer types.
+ If 128-bit integer types are available in your build, but the Qt libraries
+ were compiled without, the operator will print a warning instead.
+
+ \note Because the operator is a function template, no implicit conversions
+ are performed on its argument. It must be exactly qint128/quint128.
+
+ \sa QT_SUPPORTS_INT128
+*/
+
+/*!
\fn template <class T> QString QDebug::toString(T &&object)
\since 6.0
@@ -898,7 +1096,7 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
+ \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
\relates QDebug
Writes the contents of \a pair to \a debug. Both \c T1 and
@@ -906,11 +1104,12 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
+ \since 6.7
+ \fn template <class T> QDebug operator<<(QDebug debug, const std::optional<T> &opt)
\relates QDebug
- Writes the contents of \a pair to \a debug. Both \c T1 and
- \c T2 need to support streaming into QDebug.
+ Writes the contents of \a opt (or \c nullopt if not set) to \a debug.
+ \c T needs to support streaming into QDebug.
*/
/*!
@@ -946,6 +1145,13 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 6.7
+ \fn QDebug &QDebug::operator<<(std::nullopt_t)
+
+ Writes nullopt to the stream.
+*/
+
+/*!
\class QDebugStateSaver
\inmodule QtCore
\brief Convenience class for custom QDebug operators.
@@ -961,6 +1167,10 @@ QDebug &QDebug::resetFormat()
so that using << Qt::hex in a QDebug operator doesn't affect other QDebug
operators.
+ QDebugStateSaver is typically used in the implementation of an operator<<() for debugging:
+
+ \snippet customtype/customtypeexample.cpp custom type streaming operator
+
\since 5.1
*/
@@ -979,7 +1189,7 @@ public:
{
const bool currentSpaces = m_stream->space;
if (currentSpaces && !m_spaces)
- if (m_stream->buffer.endsWith(QLatin1Char(' ')))
+ if (m_stream->buffer.endsWith(u' '))
m_stream->buffer.chop(1);
m_stream->space = m_spaces;
@@ -1040,7 +1250,6 @@ void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, int value)
#ifndef QT_NO_QOBJECT
/*!
- \fn QDebug qt_QMetaEnum_debugOperator(QDebug &, int value, const QMetaObject *, const char *name)
\internal
Formats the given enum \a value for debug output.
@@ -1087,7 +1296,7 @@ QDebug qt_QMetaEnum_debugOperator(QDebug &dbg, qint64 value, const QMetaObject *
dbg << scope << u"::";
}
- const char *key = me.valueToKey(value);
+ const char *key = me.valueToKey(static_cast<int>(value));
const bool scoped = me.isScoped() || verbosity & 1;
if (scoped || !key)
dbg << me.enumName() << (!key ? u"(" : u"::");
@@ -1156,7 +1365,7 @@ QDebug qt_QMetaEnum_flagDebugOperator(QDebug &debug, quint64 value, const QMetaO
debug << '(';
}
- debug << me.valueToKeys(value);
+ debug << me.valueToKeys(static_cast<int>(value));
if (enumScope)
debug << ')';
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 2647f3da0f..4797bcd169 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -1,67 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDEBUG_H
#define QDEBUG_H
-#include <QtCore/qalgorithms.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmap.h>
+#if 0
+#pragma qt_class(QtDebug)
+#endif
+
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/qtypes.h>
#include <QtCore/qstring.h>
-#include <QtCore/qset.h>
-#include <QtCore/qvarlengtharray.h>
#include <QtCore/qcontiguouscache.h>
#include <QtCore/qsharedpointer.h>
// all these have already been included by various headers above, but don't rely on indirect includes:
-#include <vector>
+#include <chrono>
#include <list>
#include <map>
+#include <optional>
+#include <string>
+#include <string_view>
#include <utility>
+#include <vector>
-QT_BEGIN_NAMESPACE
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
+# include <QtCore/qlist.h>
+# include <QtCore/qmap.h>
+# include <QtCore/qset.h>
+# include <QtCore/qvarlengtharray.h>
+#endif
+QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QDebug : public QIODeviceBase
+class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
{
friend class QMessageLogger;
friend class QDebugStateSaver;
@@ -93,21 +67,24 @@ class Q_CORE_EXPORT QDebug : public QIODeviceBase
enum Latin1Content { ContainsBinary = 0, ContainsLatin1 };
- void putUcs4(uint ucs4);
- void putString(const QChar *begin, size_t length);
- void putByteArray(const char *begin, size_t length, Latin1Content content);
+ QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
+ QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
+ QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
+ QT7_ONLY(Q_CORE_EXPORT) void putTimeUnit(qint64 num, qint64 den);
+ QT7_ONLY(Q_CORE_EXPORT) void putInt128(const void *i);
+ QT7_ONLY(Q_CORE_EXPORT) void putUInt128(const void *i);
public:
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
explicit QDebug(QString *string) : stream(new Stream(string)) {}
explicit QDebug(QtMsgType t) : stream(new Stream(t)) {}
QDebug(const QDebug &o) : stream(o.stream) { ++stream->ref; }
- QDebug(QDebug &&other) noexcept : stream{qExchange(other.stream, nullptr)} {}
+ QDebug(QDebug &&other) noexcept : stream{std::exchange(other.stream, nullptr)} {}
inline QDebug &operator=(const QDebug &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QDebug)
~QDebug();
void swap(QDebug &other) noexcept { qt_ptr_swap(stream, other.stream); }
- QDebug &resetFormat();
+ QT7_ONLY(Q_CORE_EXPORT) QDebug &resetFormat();
inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
inline QDebug &nospace() { stream->space = false; return *this; }
@@ -120,6 +97,9 @@ public:
bool autoInsertSpaces() const { return stream->space; }
void setAutoInsertSpaces(bool b) { stream->space = b; }
+ [[nodiscard]] bool quoteStrings() const noexcept { return !stream->noQuotes; }
+ void setQuoteStrings(bool b) { stream->noQuotes = !b; }
+
inline QDebug &quote() { stream->noQuotes = false; return *this; }
inline QDebug &noquote() { stream->noQuotes = true; return *this; }
inline QDebug &maybeQuote(char c = '"') { if (!stream->noQuotes) stream->ts << c; return *this; }
@@ -129,7 +109,7 @@ public:
inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(unsigned short t) { stream->ts << t; return maybeSpace(); }
- inline QDebug &operator<<(char16_t t) { return *this << QChar(ushort(t)); }
+ inline QDebug &operator<<(char16_t t) { return *this << QChar(t); }
inline QDebug &operator<<(char32_t t) { putUcs4(t); return maybeSpace(); }
inline QDebug &operator<<(signed int t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(unsigned int t) { stream->ts << t; return maybeSpace(); }
@@ -137,20 +117,20 @@ public:
inline QDebug &operator<<(unsigned long t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(qint64 t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(quint64 t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(qfloat16 t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
inline QDebug &operator<<(const char16_t *t) { stream->ts << QStringView(t); return maybeSpace(); }
-#if QT_STRINGVIEW_LEVEL < 2
- inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
-#endif
+ inline QDebug &operator<<(const QString & t) { putString(t.constData(), size_t(t.size())); return maybeSpace(); }
inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); }
inline QDebug &operator<<(QUtf8StringView s) { putByteArray(reinterpret_cast<const char*>(s.data()), s.size(), ContainsBinary); return maybeSpace(); }
- inline QDebug &operator<<(QLatin1String t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); }
+ inline QDebug &operator<<(QLatin1StringView t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); }
inline QDebug &operator<<(const QByteArray & t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
inline QDebug &operator<<(QByteArrayView t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(std::nullptr_t) { stream->ts << "(nullptr)"; return maybeSpace(); }
+ inline QDebug &operator<<(std::nullopt_t) { stream->ts << "nullopt"; return maybeSpace(); }
inline QDebug &operator<<(QTextStreamFunction f) {
stream->ts << f;
return *this;
@@ -159,6 +139,89 @@ public:
inline QDebug &operator<<(QTextStreamManipulator m)
{ stream->ts << m; return *this; }
+#ifdef Q_QDOC
+ template <typename Char, typename...Args>
+ QDebug &operator<<(const std::basic_string<Char, Args...> &s);
+
+ template <typename Char, typename...Args>
+ QDebug &operator<<(std::basic_string_view<Char, Args...> s);
+#else
+ template <typename...Args>
+ QDebug &operator<<(const std::basic_string<char, Args...> &s)
+ { return *this << QUtf8StringView(s); }
+
+ template <typename...Args>
+ QDebug &operator<<(std::basic_string_view<char, Args...> s)
+ { return *this << QUtf8StringView(s); }
+
+#ifdef __cpp_char8_t
+ template <typename...Args>
+ QDebug &operator<<(const std::basic_string<char8_t, Args...> &s)
+ { return *this << QUtf8StringView(s); }
+
+ template <typename...Args>
+ QDebug &operator<<(std::basic_string_view<char8_t, Args...> s)
+ { return *this << QUtf8StringView(s); }
+#endif // __cpp_char8_t
+
+ template <typename...Args>
+ QDebug &operator<<(const std::basic_string<char16_t, Args...> &s)
+ { return *this << QStringView(s); }
+
+ template <typename...Args>
+ QDebug &operator<<(std::basic_string_view<char16_t, Args...> s)
+ { return *this << QStringView(s); }
+
+ template <typename...Args>
+ QDebug &operator<<(const std::basic_string<wchar_t, Args...> &s)
+ {
+ if constexpr (sizeof(wchar_t) == 2)
+ return *this << QStringView(s);
+ else
+ return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
+ }
+
+ template <typename...Args>
+ QDebug &operator<<(std::basic_string_view<wchar_t, Args...> s)
+ {
+ if constexpr (sizeof(wchar_t) == 2)
+ return *this << QStringView(s);
+ else
+ return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
+ }
+
+ template <typename...Args>
+ QDebug &operator<<(const std::basic_string<char32_t, Args...> &s)
+ { return *this << QString::fromUcs4(s.data(), s.size()); }
+
+ template <typename...Args>
+ QDebug &operator<<(std::basic_string_view<char32_t, Args...> s)
+ { return *this << QString::fromUcs4(s.data(), s.size()); }
+#endif // !Q_QDOC
+
+ template <typename Rep, typename Period>
+ QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
+ {
+ stream->ts << duration.count();
+ putTimeUnit(Period::num, Period::den);
+ return maybeSpace();
+ }
+
+#ifdef QT_SUPPORTS_INT128
+private:
+ // Constrained templates so they only match q(u)int128 without conversions.
+ // Also keeps these operators out of the ABI.
+ template <typename T>
+ using if_qint128 = std::enable_if_t<std::is_same_v<T, qint128>, bool>;
+ template <typename T>
+ using if_quint128 = std::enable_if_t<std::is_same_v<T, quint128>, bool>;
+public:
+ template <typename T, if_qint128<T> = true>
+ QDebug &operator<<(T i128) { putInt128(&i128); return maybeSpace(); }
+ template <typename T, if_quint128<T> = true>
+ QDebug &operator<<(T u128) { putUInt128(&u128); return maybeSpace(); }
+#endif // QT_SUPPORTS_INT128
+
template <typename T>
static QString toString(T &&object)
{
@@ -172,10 +235,12 @@ public:
Q_DECLARE_SHARED(QDebug)
class QDebugStateSaverPrivate;
-class Q_CORE_EXPORT QDebugStateSaver
+class QDebugStateSaver
{
public:
+ Q_NODISCARD_CTOR Q_CORE_EXPORT
QDebugStateSaver(QDebug &dbg);
+ Q_CORE_EXPORT
~QDebugStateSaver();
private:
Q_DISABLE_COPY(QDebugStateSaver)
@@ -248,66 +313,83 @@ template<typename Container, typename ...T>
using QDebugIfHasDebugStreamContainer =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDebug, Container, T>...>, QDebug>;
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template<typename T>
inline QDebugIfHasDebugStreamContainer<QList<T>, T> operator<<(QDebug debug, const QList<T> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "QList", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QList", vec);
}
template<typename T, qsizetype P>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QVarLengthArray<T, P> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "QVarLengthArray", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QVarLengthArray", vec);
}
template <typename T, typename Alloc>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "std::vector", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::vector", vec);
}
template <typename T, typename Alloc>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::list<T, Alloc> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "std::list", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::list", vec);
+}
+
+template <typename T>
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, std::initializer_list<T> list)
+{
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::initializer_list", list);
}
template <typename Key, typename T, typename Compare, typename Alloc>
inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
{
- return QtPrivate::printSequentialContainer(debug, "std::map", map); // yes, sequential: *it is std::pair
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::map", map); // yes, sequential: *it is std::pair
}
template <typename Key, typename T, typename Compare, typename Alloc>
inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
{
- return QtPrivate::printSequentialContainer(debug, "std::multimap", map); // yes, sequential: *it is std::pair
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::multimap", map); // yes, sequential: *it is std::pair
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMap<Key, T>, Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
{
- return QtPrivate::printAssociativeContainer(debug, "QMap", map);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMap", map);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMultiMap<Key, T>, Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
{
- return QtPrivate::printAssociativeContainer(debug, "QMultiMap", map);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiMap", map);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QHash<Key, T>, Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
{
- return QtPrivate::printAssociativeContainer(debug, "QHash", hash);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QHash", hash);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
{
- return QtPrivate::printAssociativeContainer(debug, "QMultiHash", hash);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiHash", hash);
+}
+
+template <class T>
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::optional<T> &opt)
+{
+ const QDebugStateSaver saver(debug);
+ if (!opt)
+ debug.nospace() << std::nullopt;
+ else
+ debug.nospace() << "std::optional(" << *opt << ')';
+ return debug;
}
template <class T1, class T2>
@@ -321,7 +403,7 @@ inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T
template <typename T>
inline QDebugIfHasDebugStreamContainer<QSet<T>, T> operator<<(QDebug debug, const QSet<T> &set)
{
- return QtPrivate::printSequentialContainer(debug, "QSet", set);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QSet", set);
}
template <class T>
@@ -329,7 +411,7 @@ inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QContiguousCache
{
const QDebugStateSaver saver(debug);
debug.nospace() << "QContiguousCache(";
- for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
+ for (qsizetype i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
debug << cache[i];
if (i != cache.lastIndex())
debug << ", ";
@@ -373,15 +455,12 @@ template <typename T>
QDebug operator<<(QDebug debug, const QSet<T> &set);
template <class T1, class T2>
-QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair);
-
-template <class T1, class T2>
QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair);
template <typename T>
QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache);
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
template <class T>
inline QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr)
@@ -410,7 +489,7 @@ void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, Int value)
debug.resetFormat();
debug.nospace() << "QFlags(" << Qt::hex << Qt::showbase;
bool needSeparator = false;
- for (uint i = 0; i < sizeofT * 8; ++i) {
+ for (size_t i = 0; i < sizeofT * 8; ++i) {
if (value & (Int(1) << i)) {
if (needSeparator)
debug << '|';
@@ -492,7 +571,7 @@ inline QDebug operator<<(QDebug debug, QKeyCombination combination)
return debug;
}
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
// We provide QDebug stream operators for commonly used Core Foundation
// and Core Graphics types, as well as NSObject. Additional CF/CG types
@@ -529,6 +608,7 @@ inline QDebug operator<<(QDebug debug, QKeyCombination combination)
QT_END_NAMESPACE
Q_FORWARD_DECLARE_CF_TYPE(CFString);
+struct objc_object;
Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_CF_TYPE)
QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_MUTABLE_CF_TYPE)
@@ -553,6 +633,10 @@ QT_BEGIN_NAMESPACE
}
// Defined in qcore_mac_objc.mm
+#if defined(__OBJC__)
+Q_CORE_EXPORT QDebug operator<<(QDebug, id);
+#endif
+Q_CORE_EXPORT QDebug operator<<(QDebug, objc_object *);
Q_CORE_EXPORT QDebug operator<<(QDebug, const NSObject *);
Q_CORE_EXPORT QDebug operator<<(QDebug, CFStringRef);
@@ -566,7 +650,7 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF
#undef QT_FORWARD_DECLARE_CG_TYPE
#undef QT_FORWARD_DECLARE_MUTABLE_CG_TYPE
-#endif // Q_OS_MAC
+#endif // Q_OS_DARWIN
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdebug_p.h b/src/corelib/io/qdebug_p.h
index 1ca632338f..810fc3b4b6 100644
--- a/src/corelib/io/qdebug_p.h
+++ b/src/corelib/io/qdebug_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDEBUG_P_H
#define QDEBUG_P_H
@@ -61,7 +25,7 @@ QT_BEGIN_NAMESPACE
namespace QtDebugUtils {
-Q_CORE_EXPORT QByteArray toPrintable(const char *data, int len, int maxSize);
+Q_CORE_EXPORT QByteArray toPrintable(const char *data, qint64 len, qsizetype maxSize);
// inline helpers for formatting basic classes.
@@ -114,11 +78,10 @@ static inline void formatNonNullQEnum(QDebug &debug, const char *prefix, QEnum v
template <class Enum>
static inline void formatQFlags(QDebug &debug, const QFlags<Enum> &value)
{
- const QMetaObject *metaObject = qt_getEnumMetaObject(Enum());
- const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(Enum())));
+ const QMetaEnum me = QMetaEnum::fromType<QFlags<Enum>>();
const QDebugStateSaver saver(debug);
debug.noquote();
- debug << me.valueToKeys(value);
+ debug << me.valueToKeys(value.toInt());
}
template <class Enum>
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index fbde6b69fd..9291201d88 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qdir.h"
@@ -45,7 +9,7 @@
#ifndef QT_NO_DEBUG_STREAM
#include "qdebug.h"
#endif
-#include "qdiriterator.h"
+#include "qdirlisting.h"
#include "qdatetime.h"
#include "qstring.h"
#if QT_CONFIG(regularexpression)
@@ -57,9 +21,10 @@
#include "qfilesystemengine_p.h"
#include <qstringbuilder.h>
-#ifdef QT_BUILD_CORE_LIB
-# include "qresource.h"
-# include "private/qcoreglobaldata_p.h"
+#ifndef QT_BOOTSTRAPPED
+# include <qcollator.h>
+# include "qreadwritelock.h"
+# include "qmutex.h"
#endif
#include <algorithm>
@@ -68,6 +33,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#if defined(Q_OS_WIN)
static QString driveSpec(const QString &path)
{
@@ -91,67 +58,65 @@ enum {
};
// Return the length of the root part of an absolute path, for use by cleanPath(), cd().
-static int rootLength(const QString &name, bool allowUncPaths)
+static qsizetype rootLength(QStringView name, bool allowUncPaths)
{
- const int len = name.length();
+ const qsizetype len = name.size();
// starts with double slash
- if (allowUncPaths && name.startsWith(QLatin1String("//"))) {
+ if (allowUncPaths && name.startsWith("//"_L1)) {
// Server name '//server/path' is part of the prefix.
- const int nextSlash = name.indexOf(QLatin1Char('/'), 2);
+ const qsizetype nextSlash = name.indexOf(u'/', 2);
return nextSlash >= 0 ? nextSlash + 1 : len;
}
#if defined(Q_OS_WIN)
- if (len >= 2 && name.at(1) == QLatin1Char(':')) {
+ if (len >= 2 && name.at(1) == u':') {
// Handle a possible drive letter
- return len > 2 && name.at(2) == QLatin1Char('/') ? 3 : 2;
+ return len > 2 && name.at(2) == u'/' ? 3 : 2;
}
#endif
- if (name.at(0) == QLatin1Char('/'))
+ if (name.at(0) == u'/')
return 1;
return 0;
}
//************* QDirPrivate
-QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_)
- : QSharedData()
- , fileListsInitialized(false)
- , nameFilters(nameFilters_)
- , sort(sort_)
- , filters(filters_)
+QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_,
+ QDir::SortFlags sort_, QDir::Filters filters_)
+ : QSharedData(), nameFilters(nameFilters_), sort(sort_), filters(filters_)
{
setPath(path.isEmpty() ? QString::fromLatin1(".") : path);
- bool empty = nameFilters.isEmpty();
- if (!empty) {
- empty = true;
- for (int i = 0; i < nameFilters.size(); ++i) {
- if (!nameFilters.at(i).isEmpty()) {
- empty = false;
- break;
- }
- }
- }
+ auto isEmpty = [](const auto &e) { return e.isEmpty(); };
+ const bool empty = std::all_of(nameFilters.cbegin(), nameFilters.cend(), isEmpty);
if (empty)
nameFilters = QStringList(QString::fromLatin1("*"));
}
QDirPrivate::QDirPrivate(const QDirPrivate &copy)
- : QSharedData(copy)
- , fileListsInitialized(false)
- , nameFilters(copy.nameFilters)
- , sort(copy.sort)
- , filters(copy.filters)
- , dirEntry(copy.dirEntry)
- , metaData(copy.metaData)
-{
+ : QSharedData(copy),
+ // mutex is not copied
+ nameFilters(copy.nameFilters),
+ sort(copy.sort),
+ filters(copy.filters),
+ // fileEngine is not copied
+ dirEntry(copy.dirEntry)
+{
+ QMutexLocker locker(&copy.fileCache.mutex);
+ fileCache.fileListsInitialized = copy.fileCache.fileListsInitialized.load();
+ fileCache.files = copy.fileCache.files;
+ fileCache.fileInfos = copy.fileCache.fileInfos;
+ fileCache.absoluteDirEntry = copy.fileCache.absoluteDirEntry;
+ fileCache.metaData = copy.fileCache.metaData;
}
bool QDirPrivate::exists() const
{
if (!fileEngine) {
- QFileSystemEngine::fillMetaData(dirEntry, metaData,
- QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); // always stat
- return metaData.exists() && metaData.isDirectory();
+ QMutexLocker locker(&fileCache.mutex);
+ QFileSystemEngine::fillMetaData(
+ dirEntry, fileCache.metaData,
+ QFileSystemMetaData::ExistsAttribute
+ | QFileSystemMetaData::DirectoryType); // always stat
+ return fileCache.metaData.exists() && fileCache.metaData.isDirectory();
}
const QAbstractFileEngine::FileFlags info =
fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
@@ -165,10 +130,10 @@ bool QDirPrivate::exists() const
// static
inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter)
{
- QChar sep(QLatin1Char(';'));
- int i = nameFilter.indexOf(sep, 0);
- if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1)
- sep = QChar(QLatin1Char(' '));
+ QChar sep(u';');
+ qsizetype i = nameFilter.indexOf(sep, 0);
+ if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
+ sep = QChar(u' ');
return sep;
}
@@ -186,64 +151,97 @@ inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar se
inline void QDirPrivate::setPath(const QString &path)
{
QString p = QDir::fromNativeSeparators(path);
- if (p.endsWith(QLatin1Char('/'))
- && p.length() > 1
+ if (p.endsWith(u'/')
+ && p.size() > 1
#if defined(Q_OS_WIN)
&& (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter()))
#endif
) {
- p.truncate(p.length() - 1);
+ p.truncate(p.size() - 1);
}
-
dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
- metaData.clear();
- initFileEngine();
- clearFileLists();
- absoluteDirEntry = QFileSystemEntry();
+ clearCache(IncludingMetaData);
+ fileCache.absoluteDirEntry = QFileSystemEntry();
}
-inline void QDirPrivate::clearFileLists()
+inline QString QDirPrivate::resolveAbsoluteEntry() const
{
- fileListsInitialized = false;
- files.clear();
- fileInfos.clear();
-}
+ QMutexLocker locker(&fileCache.mutex);
+ if (!fileCache.absoluteDirEntry.isEmpty())
+ return fileCache.absoluteDirEntry.filePath();
-inline void QDirPrivate::resolveAbsoluteEntry() const
-{
- if (!absoluteDirEntry.isEmpty() || dirEntry.isEmpty())
- return;
+ if (dirEntry.isEmpty())
+ return dirEntry.filePath();
QString absoluteName;
if (!fileEngine) {
if (!dirEntry.isRelative() && dirEntry.isClean()) {
- absoluteDirEntry = dirEntry;
- return;
+ fileCache.absoluteDirEntry = dirEntry;
+ return dirEntry.filePath();
}
absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
} else {
absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
}
-
- absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
+ auto absoluteFileSystemEntry =
+ QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
+ fileCache.absoluteDirEntry = absoluteFileSystemEntry;
+ return absoluteFileSystemEntry.filePath();
}
/* For sorting */
struct QDirSortItem
{
+ QDirSortItem() = default;
+ QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)
+ : item(fi)
+ {
+ // A dir e.g. "dirA.bar" doesn't have actually have an extension/suffix, when
+ // sorting by type such "suffix" should be ignored but that would complicate
+ // the code and uses can change the behavior by setting DirsFirst/DirsLast
+ if (sort.testAnyFlag(QDir::Type))
+ suffix_cache = item.suffix();
+ }
+
mutable QString filename_cache;
- mutable QString suffix_cache;
+ QString suffix_cache;
QFileInfo item;
};
-
class QDirSortItemComparator
{
QDir::SortFlags qt_cmp_si_sort_flags;
+
+#ifndef QT_BOOTSTRAPPED
+ QCollator *collator = nullptr;
+#endif
public:
- QDirSortItemComparator(QDir::SortFlags flags) : qt_cmp_si_sort_flags(flags) {}
+#ifndef QT_BOOTSTRAPPED
+ QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll = nullptr)
+ : qt_cmp_si_sort_flags(flags), collator(coll)
+ {
+ Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
+
+ if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
+ collator->setCaseSensitivity(Qt::CaseInsensitive);
+ }
+#else
+ QDirSortItemComparator(QDir::SortFlags flags)
+ : qt_cmp_si_sort_flags(flags)
+ {
+ }
+#endif
bool operator()(const QDirSortItem &, const QDirSortItem &) const;
+
+ int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
+ {
+#ifndef QT_BOOTSTRAPPED
+ if (collator)
+ return collator->compare(a, b);
+#endif
+ return a.compare(b, cs);
+ }
};
bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const
@@ -256,43 +254,25 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
return !f1->item.isDir();
+ const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
+ const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
+
qint64 r = 0;
int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
| (qt_cmp_si_sort_flags & QDir::Type)).toInt();
switch (sortBy) {
case QDir::Time: {
- QDateTime firstModified = f1->item.lastModified();
- QDateTime secondModified = f2->item.lastModified();
-
- // QDateTime by default will do all sorts of conversions on these to
- // find timezones, which is incredibly expensive. As we aren't
- // presenting these to the user, we don't care (at all) about the
- // local timezone, so force them to UTC to avoid that conversion.
- firstModified.setTimeSpec(Qt::UTC);
- secondModified.setTimeSpec(Qt::UTC);
-
+ const QDateTime firstModified = f1->item.lastModified(QTimeZone::UTC);
+ const QDateTime secondModified = f2->item.lastModified(QTimeZone::UTC);
r = firstModified.msecsTo(secondModified);
break;
}
case QDir::Size:
r = f2->item.size() - f1->item.size();
break;
- case QDir::Type:
- {
- bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
-
- if (f1->suffix_cache.isNull())
- f1->suffix_cache = ic ? f1->item.suffix().toLower()
- : f1->item.suffix();
- if (f2->suffix_cache.isNull())
- f2->suffix_cache = ic ? f2->item.suffix().toLower()
- : f2->item.suffix();
-
- r = qt_cmp_si_sort_flags & QDir::LocaleAware
- ? f1->suffix_cache.localeAwareCompare(f2->suffix_cache)
- : f1->suffix_cache.compare(f2->suffix_cache);
- }
+ case QDir::Type:
+ r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
break;
default:
;
@@ -300,69 +280,89 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
if (r == 0 && sortBy != QDir::Unsorted) {
// Still not sorted - sort by name
- bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
if (f1->filename_cache.isNull())
- f1->filename_cache = ic ? f1->item.fileName().toLower()
- : f1->item.fileName();
+ f1->filename_cache = f1->item.fileName();
if (f2->filename_cache.isNull())
- f2->filename_cache = ic ? f2->item.fileName().toLower()
- : f2->item.fileName();
+ f2->filename_cache = f2->item.fileName();
- r = qt_cmp_si_sort_flags & QDir::LocaleAware
- ? f1->filename_cache.localeAwareCompare(f2->filename_cache)
- : f1->filename_cache.compare(f2->filename_cache);
+ r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
}
if (qt_cmp_si_sort_flags & QDir::Reversed)
return r > 0;
return r < 0;
}
-inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
+inline void QDirPrivate::sortFileList(QDir::SortFlags sort, const QFileInfoList &l,
QStringList *names, QFileInfoList *infos)
{
- // names and infos are always empty lists or 0 here
- int n = l.size();
- if (n > 0) {
- if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
- if (infos)
- *infos = l;
- if (names) {
- for (int i = 0; i < n; ++i)
- names->append(l.at(i).fileName());
- }
+ Q_ASSERT(names || infos);
+ Q_ASSERT(!infos || infos->isEmpty());
+ Q_ASSERT(!names || names->isEmpty());
+
+ const qsizetype n = l.size();
+ if (n == 0)
+ return;
+
+ if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
+ if (infos)
+ *infos = l;
+
+ if (names) {
+ for (const QFileInfo &fi : l)
+ names->append(fi.fileName());
+ }
+ } else {
+ QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
+ for (qsizetype i = 0; i < n; ++i)
+ si[i] = QDirSortItem{l.at(i), sort};
+
+#ifndef QT_BOOTSTRAPPED
+ if (sort.testAnyFlag(QDir::LocaleAware)) {
+ QCollator coll;
+ std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
} else {
- QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
- for (int i = 0; i < n; ++i)
- si[i].item = l.at(i);
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
- // put them back in the list(s)
- if (infos) {
- for (int i = 0; i < n; ++i)
- infos->append(si[i].item);
- }
+ }
+#else
+ std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
+#endif // QT_BOOTSTRAPPED
+
+ // put them back in the list(s)
+ for (qsizetype i = 0; i < n; ++i) {
+ auto &fileInfo = si[i].item;
+ if (infos)
+ infos->append(fileInfo);
if (names) {
- for (int i = 0; i < n; ++i)
- names->append(si[i].item.fileName());
+ const bool cached = !si[i].filename_cache.isNull();
+ names->append(cached ? si[i].filename_cache : fileInfo.fileName());
}
}
}
}
+
inline void QDirPrivate::initFileLists(const QDir &dir) const
{
- if (!fileListsInitialized) {
+ QMutexLocker locker(&fileCache.mutex);
+ if (!fileCache.fileListsInitialized) {
QFileInfoList l;
- QDirIterator it(dir);
- while (it.hasNext())
- l.append(it.nextFileInfo());
- sortFileList(sort, l, &files, &fileInfos);
- fileListsInitialized = true;
+ for (const auto &dirEntry : QDirListing(dir))
+ l.emplace_back(dirEntry.fileInfo());
+
+ sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
+ fileCache.fileListsInitialized = true;
}
}
-inline void QDirPrivate::initFileEngine()
+inline void QDirPrivate::clearCache(MetaDataClearing mode)
{
- fileEngine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
+ QMutexLocker locker(&fileCache.mutex);
+ if (mode == IncludingMetaData)
+ fileCache.metaData.clear();
+ fileCache.fileListsInitialized = false;
+ fileCache.files.clear();
+ fileCache.fileInfos.clear();
+ fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
}
/*!
@@ -374,6 +374,7 @@ inline void QDirPrivate::initFileEngine()
\ingroup shared
\reentrant
+ \compares equality
A QDir is used to manipulate path names, access information
regarding paths and files, and manipulate the underlying file
@@ -529,8 +530,8 @@ inline void QDirPrivate::initFileEngine()
\snippet code/src_corelib_io_qdir.cpp 4
- (We could also use the static convenience function
- QFile::exists().)
+ (We could also use one of the static convenience functions
+ QFileInfo::exists() or QFile::exists().)
Traversing directories and reading a file:
@@ -541,7 +542,12 @@ inline void QDirPrivate::initFileEngine()
\snippet qdir-listfiles/main.cpp 0
- \sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(), {Find Files Example}
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
+
+ \sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(),
+ {Fetch More Example}
*/
/*!
@@ -645,7 +651,7 @@ void QDir::setPath(const QString &path)
*/
QString QDir::path() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->dirEntry.filePath();
}
@@ -659,9 +665,11 @@ QString QDir::path() const
*/
QString QDir::absolutePath() const
{
- const QDirPrivate* d = d_ptr.constData();
- d->resolveAbsoluteEntry();
- return d->absoluteDirEntry.filePath();
+ Q_D(const QDir);
+ if (!d->fileEngine)
+ return d->resolveAbsoluteEntry();
+
+ return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
}
/*!
@@ -682,9 +690,11 @@ QString QDir::absolutePath() const
*/
QString QDir::canonicalPath() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (!d->fileEngine) {
- QFileSystemEntry answer = QFileSystemEngine::canonicalName(d->dirEntry, d->metaData);
+ QMutexLocker locker(&d->fileCache.mutex);
+ QFileSystemEntry answer =
+ QFileSystemEngine::canonicalName(d->dirEntry, d->fileCache.metaData);
return answer.filePath();
}
return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
@@ -703,29 +713,31 @@ QString QDir::canonicalPath() const
*/
QString QDir::dirName() const
{
- const QDirPrivate* d = d_ptr.constData();
- return d->dirEntry.fileName();
+ Q_D(const QDir);
+ if (!d_ptr->fileEngine)
+ return d->dirEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
#ifdef Q_OS_WIN
-static int drivePrefixLength(const QString &path)
+static qsizetype drivePrefixLength(QStringView path)
{
// Used to extract path's drive for use as prefix for an "absolute except for drive" path
- const int size = path.length();
- int drive = 2; // length of drive prefix
+ const qsizetype size = path.size();
+ qsizetype drive = 2; // length of drive prefix
if (size > 1 && path.at(1).unicode() == ':') {
if (Q_UNLIKELY(!path.at(0).isLetter()))
return 0;
- } else if (path.startsWith(QLatin1String("//"))) {
+ } else if (path.startsWith("//"_L1)) {
// UNC path; use its //server/share part as "drive" - it's as sane a
// thing as we can do.
- for (int i = 2; i-- > 0; ) { // Scan two "path fragments":
+ for (int i = 0 ; i < 2 ; ++i) { // Scan two "path fragments":
while (drive < size && path.at(drive).unicode() == '/')
drive++;
if (drive >= size) {
qWarning("Base directory starts with neither a drive nor a UNC share: %s",
- qUtf8Printable(QDir::toNativeSeparators(path)));
+ qUtf8Printable(QDir::toNativeSeparators(path.toString())));
return 0;
}
while (drive < size && path.at(drive).unicode() != '/')
@@ -749,7 +761,7 @@ static bool treatAsAbsolute(const QString &path)
// a colon in the path.
// FIXME: relies on virtual file-systems having colons in their prefixes.
// The case of an MS-absolute C:/... path happens to work either way.
- return (path.contains(QLatin1Char(':')) && QFileInfo(path).isAbsolute())
+ return (path.contains(u':') && QFileInfo(path).isAbsolute())
|| QFileSystemEntry(path).isAbsolute();
}
@@ -767,22 +779,22 @@ QString QDir::filePath(const QString &fileName) const
if (treatAsAbsolute(fileName))
return fileName;
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
QString ret = d->dirEntry.filePath();
if (fileName.isEmpty())
return ret;
#ifdef Q_OS_WIN
- if (fileName.startsWith(QLatin1Char('/')) || fileName.startsWith(QLatin1Char('\\'))) {
+ if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
// Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
- const int drive = drivePrefixLength(ret);
+ const qsizetype drive = drivePrefixLength(ret);
return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
}
#endif // Q_OS_WIN
- if (ret.isEmpty() || ret.endsWith(QLatin1Char('/')))
+ if (ret.isEmpty() || ret.endsWith(u'/'))
return ret % fileName;
- return ret % QLatin1Char('/') % fileName;
+ return ret % u'/' % fileName;
}
/*!
@@ -798,16 +810,15 @@ QString QDir::absoluteFilePath(const QString &fileName) const
if (treatAsAbsolute(fileName))
return fileName;
- const QDirPrivate* d = d_ptr.constData();
- d->resolveAbsoluteEntry();
- const QString absoluteDirPath = d->absoluteDirEntry.filePath();
+ Q_D(const QDir);
+ QString absoluteDirPath = d->resolveAbsoluteEntry();
if (fileName.isEmpty())
return absoluteDirPath;
#ifdef Q_OS_WIN
// Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
- if (fileName.startsWith(QLatin1Char('/')) || fileName.startsWith(QLatin1Char('\\'))) {
+ if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
// Combine absoluteDirPath's drive with fileName
- const int drive = drivePrefixLength(absoluteDirPath);
+ const qsizetype drive = drivePrefixLength(absoluteDirPath);
if (Q_LIKELY(drive))
return QStringView{absoluteDirPath}.left(drive) % fileName;
@@ -816,8 +827,8 @@ QString QDir::absoluteFilePath(const QString &fileName) const
return QString();
}
#endif // Q_OS_WIN
- if (!absoluteDirPath.endsWith(QLatin1Char('/')))
- return absoluteDirPath % QLatin1Char('/') % fileName;
+ if (!absoluteDirPath.endsWith(u'/'))
+ return absoluteDirPath % u'/' % fileName;
return absoluteDirPath % fileName;
}
@@ -847,9 +858,10 @@ QString QDir::relativeFilePath(const QString &fileName) const
}
if (fileDrive.toLower() != dirDrive.toLower()
- || (file.startsWith(QLatin1String("//"))
- && !dir.startsWith(QLatin1String("//"))))
+ || (file.startsWith("//"_L1)
+ && !dir.startsWith("//"_L1))) {
return file;
+ }
dir.remove(0, dirDrive.size());
if (!fileDriveMissing)
@@ -857,8 +869,8 @@ QString QDir::relativeFilePath(const QString &fileName) const
#endif
QString result;
- const auto dirElts = dir.tokenize(QLatin1Char('/'), Qt::SkipEmptyParts);
- const auto fileElts = file.tokenize(QLatin1Char('/'), Qt::SkipEmptyParts);
+ const auto dirElts = dir.tokenize(u'/', Qt::SkipEmptyParts);
+ const auto fileElts = file.tokenize(u'/', Qt::SkipEmptyParts);
const auto dend = dirElts.end();
const auto fend = fileElts.end();
@@ -881,20 +893,20 @@ QString QDir::relativeFilePath(const QString &fileName) const
}
while (dit != dend) {
- result += QLatin1String("../");
+ result += "../"_L1;
++dit;
}
if (fit != fend) {
while (fit != fend) {
result += *fit++;
- result += QLatin1Char('/');
+ result += u'/';
}
result.chop(1);
}
if (result.isEmpty())
- result = QLatin1String(".");
+ result = "."_L1;
return result;
}
@@ -916,16 +928,16 @@ QString QDir::relativeFilePath(const QString &fileName) const
QString QDir::toNativeSeparators(const QString &pathName)
{
#if defined(Q_OS_WIN)
- int i = pathName.indexOf(QLatin1Char('/'));
+ qsizetype i = pathName.indexOf(u'/');
if (i != -1) {
QString n(pathName);
QChar * const data = n.data();
- data[i++] = QLatin1Char('\\');
+ data[i++] = u'\\';
for (; i < n.length(); ++i) {
- if (data[i] == QLatin1Char('/'))
- data[i] = QLatin1Char('\\');
+ if (data[i] == u'/')
+ data[i] = u'\\';
}
return n;
@@ -973,19 +985,19 @@ bool QDir::cd(const QString &dirName)
// Don't detach just yet.
const QDirPrivate * const d = d_ptr.constData();
- if (dirName.isEmpty() || dirName == QLatin1String("."))
+ if (dirName.isEmpty() || dirName == u'.')
return true;
QString newPath;
if (isAbsolutePath(dirName)) {
newPath = qt_cleanPath(dirName);
} else {
newPath = d->dirEntry.filePath();
- if (!newPath.endsWith(QLatin1Char('/')))
- newPath += QLatin1Char('/');
+ if (!newPath.endsWith(u'/'))
+ newPath += u'/';
newPath += dirName;
- if (dirName.indexOf(QLatin1Char('/')) >= 0
- || dirName == QLatin1String("..")
- || d->dirEntry.filePath() == QLatin1String(".")) {
+ if (dirName.indexOf(u'/') >= 0
+ || dirName == ".."_L1
+ || d->dirEntry.filePath() == u'.') {
bool ok;
newPath = qt_cleanPath(newPath, &ok);
if (!ok)
@@ -998,7 +1010,7 @@ bool QDir::cd(const QString &dirName)
while (dir.cdUp())
;
*/
- if (newPath.startsWith(QLatin1String(".."))) {
+ if (newPath.startsWith(".."_L1)) {
newPath = QFileInfo(newPath).absoluteFilePath();
}
}
@@ -1021,6 +1033,9 @@ bool QDir::cd(const QString &dirName)
otherwise returns \c false. Note that the logical cdUp() operation is
not performed if the new directory does not exist.
+ \note On Android, this is not supported for content URIs. For more information,
+ see \l {Android: DocumentFile.getParentFile()}{DocumentFile.getParentFile()}.
+
\sa cd(), isReadable(), exists(), path()
*/
bool QDir::cdUp()
@@ -1033,7 +1048,7 @@ bool QDir::cdUp()
*/
QStringList QDir::nameFilters() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->nameFilters;
}
@@ -1054,14 +1069,22 @@ QStringList QDir::nameFilters() const
*/
void QDir::setNameFilters(const QStringList &nameFilters)
{
- QDirPrivate* d = d_ptr.data();
- d->initFileEngine();
- d->clearFileLists();
-
+ Q_D(QDir);
+ d->clearCache(QDirPrivate::KeepMetaData);
d->nameFilters = nameFilters;
}
-#ifdef QT_BUILD_CORE_LIB
+#ifndef QT_BOOTSTRAPPED
+
+namespace {
+struct DirSearchPaths {
+ mutable QReadWriteLock mutex;
+ QHash<QString, QStringList> paths;
+};
+}
+
+Q_GLOBAL_STATIC(DirSearchPaths, dirSearchPaths)
+
/*!
\since 4.3
@@ -1084,24 +1107,24 @@ void QDir::setNameFilters(const QStringList &nameFilters)
*/
void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
{
- if (prefix.length() < 2) {
+ if (prefix.size() < 2) {
qWarning("QDir::setSearchPaths: Prefix must be longer than 1 character");
return;
}
- for (int i = 0; i < prefix.count(); ++i) {
- if (!prefix.at(i).isLetterOrNumber()) {
+ for (QChar ch : prefix) {
+ if (!ch.isLetterOrNumber()) {
qWarning("QDir::setSearchPaths: Prefix can only contain letters or numbers");
return;
}
}
- QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
- QHash<QString, QStringList> &paths = QCoreGlobalData::instance()->dirSearchPaths;
+ DirSearchPaths &conf = *dirSearchPaths;
+ const QWriteLocker lock(&conf.mutex);
if (searchPaths.isEmpty()) {
- paths.remove(prefix);
+ conf.paths.remove(prefix);
} else {
- paths.insert(prefix, searchPaths);
+ conf.paths.insert(prefix, searchPaths);
}
}
@@ -1117,8 +1140,9 @@ void QDir::addSearchPath(const QString &prefix, const QString &path)
if (path.isEmpty())
return;
- QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
- QCoreGlobalData::instance()->dirSearchPaths[prefix] += path;
+ DirSearchPaths &conf = *dirSearchPaths;
+ const QWriteLocker lock(&conf.mutex);
+ conf.paths[prefix] += path;
}
/*!
@@ -1130,18 +1154,22 @@ void QDir::addSearchPath(const QString &prefix, const QString &path)
*/
QStringList QDir::searchPaths(const QString &prefix)
{
- QReadLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
- return QCoreGlobalData::instance()->dirSearchPaths.value(prefix);
+ if (!dirSearchPaths.exists())
+ return QStringList();
+
+ const DirSearchPaths &conf = *dirSearchPaths;
+ const QReadLocker lock(&conf.mutex);
+ return conf.paths.value(prefix);
}
-#endif // QT_BUILD_CORE_LIB
+#endif // QT_BOOTSTRAPPED
/*!
Returns the value set by setFilter()
*/
QDir::Filters QDir::filter() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->filters;
}
@@ -1220,10 +1248,8 @@ QDir::Filters QDir::filter() const
*/
void QDir::setFilter(Filters filters)
{
- QDirPrivate* d = d_ptr.data();
- d->initFileEngine();
- d->clearFileLists();
-
+ Q_D(QDir);
+ d->clearCache(QDirPrivate::KeepMetaData);
d->filters = filters;
}
@@ -1234,7 +1260,7 @@ void QDir::setFilter(Filters filters)
*/
QDir::SortFlags QDir::sorting() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->sort;
}
@@ -1267,6 +1293,7 @@ QDir::SortFlags QDir::sorting() const
after the directories, again in reverse order.
*/
+#ifndef QT_BOOTSTRAPPED
/*!
Sets the sort order used by entryList() and entryInfoList().
@@ -1277,10 +1304,8 @@ QDir::SortFlags QDir::sorting() const
*/
void QDir::setSorting(SortFlags sort)
{
- QDirPrivate* d = d_ptr.data();
- d->initFileEngine();
- d->clearFileLists();
-
+ Q_D(QDir);
+ d->clearCache(QDirPrivate::KeepMetaData);
d->sort = sort;
}
@@ -1289,13 +1314,16 @@ void QDir::setSorting(SortFlags sort)
Equivalent to entryList().count().
+ \note In Qt versions prior to 6.5, this function returned \c{uint}, not
+ \c{qsizetype}.
+
\sa operator[](), entryList()
*/
-uint QDir::count() const
+qsizetype QDir::count(QT6_IMPL_NEW_OVERLOAD) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
d->initFileLists(*this);
- return d->files.count();
+ return d->fileCache.files.size();
}
/*!
@@ -1303,13 +1331,15 @@ uint QDir::count() const
names. Equivalent to entryList().at(index).
\a pos must be a valid index position in the list (i.e., 0 <= pos < count()).
+ \note In Qt versions prior to 6.5, \a pos was an \c{int}, not \c{qsizetype}.
+
\sa count(), entryList()
*/
-QString QDir::operator[](int pos) const
+QString QDir::operator[](qsizetype pos) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
d->initFileLists(*this);
- return d->files[pos];
+ return d->fileCache.files[pos];
}
/*!
@@ -1333,7 +1363,7 @@ QString QDir::operator[](int pos) const
*/
QStringList QDir::entryList(Filters filters, SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return entryList(d->nameFilters, filters, sort);
}
@@ -1356,7 +1386,7 @@ QStringList QDir::entryList(Filters filters, SortFlags sort) const
*/
QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return entryInfoList(d->nameFilters, filters, sort);
}
@@ -1379,24 +1409,34 @@ QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (filters == NoFilter)
filters = d->filters;
if (sort == NoSort)
sort = d->sort;
+ const bool needsSorting = (sort & QDir::SortByMask) != QDir::Unsorted;
+
if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
- d->initFileLists(*this);
- return d->files;
+ // Don't fill a QFileInfo cache if we just need names
+ if (needsSorting || d->fileCache.fileListsInitialized) {
+ d->initFileLists(*this);
+ return d->fileCache.files;
+ }
}
- QFileInfoList l;
- QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
- while (it.hasNext())
- l.append(it.nextFileInfo());
+ QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters);
QStringList ret;
- d->sortFileList(sort, l, &ret, nullptr);
+ if (needsSorting) {
+ QFileInfoList l;
+ for (const auto &dirEntry : dirList)
+ l.emplace_back(dirEntry.fileInfo());
+ d->sortFileList(sort, l, &ret, nullptr);
+ } else {
+ for (const auto &dirEntry : dirList)
+ ret.emplace_back(dirEntry.fileName());
+ }
return ret;
}
@@ -1419,7 +1459,7 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filters,
SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (filters == NoFilter)
filters = d->filters;
@@ -1428,17 +1468,17 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
d->initFileLists(*this);
- return d->fileInfos;
+ return d->fileCache.fileInfos;
}
QFileInfoList l;
- QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
- while (it.hasNext())
- l.append(it.nextFileInfo());
+ for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters))
+ l.emplace_back(dirEntry.fileInfo());
QFileInfoList ret;
d->sortFileList(sort, l, nullptr, &ret);
return ret;
}
+#endif // !QT_BOOTSTRAPPED
/*!
Creates a sub-directory called \a dirName.
@@ -1462,7 +1502,7 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
*/
bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
{
- const QDirPrivate *d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::mkdir: Empty or null file name");
@@ -1484,7 +1524,7 @@ bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
*/
bool QDir::mkdir(const QString &dirName) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::mkdir: Empty or null file name");
@@ -1508,7 +1548,7 @@ bool QDir::mkdir(const QString &dirName) const
*/
bool QDir::rmdir(const QString &dirName) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::rmdir: Empty or null file name");
@@ -1536,7 +1576,7 @@ bool QDir::rmdir(const QString &dirName) const
*/
bool QDir::mkpath(const QString &dirPath) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirPath.isEmpty()) {
qWarning("QDir::mkpath: Empty or null file name");
@@ -1562,7 +1602,7 @@ bool QDir::mkpath(const QString &dirPath) const
*/
bool QDir::rmpath(const QString &dirPath) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirPath.isEmpty()) {
qWarning("QDir::rmpath: Empty or null file name");
@@ -1575,6 +1615,7 @@ bool QDir::rmpath(const QString &dirPath) const
return d->fileEngine->rmdir(fn, true);
}
+#ifndef QT_BOOTSTRAPPED
/*!
\since 5.0
Removes the directory, including all its contents.
@@ -1603,12 +1644,11 @@ bool QDir::removeRecursively()
bool success = true;
const QString dirPath = path();
// not empty -- we must empty it first
- QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
- while (di.hasNext()) {
- const QFileInfo fi = di.nextFileInfo();
- const QString &filePath = di.filePath();
+ constexpr auto dirFilters = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
+ for (const auto &dirEntry : QDirListing(dirPath, dirFilters)) {
+ const QString &filePath = dirEntry.filePath();
bool ok;
- if (fi.isDir() && !fi.isSymLink()) {
+ if (dirEntry.isDir() && !dirEntry.isSymLink()) {
ok = QDir(filePath).removeRecursively(); // recursive
} else {
ok = QFile::remove(filePath);
@@ -1628,6 +1668,7 @@ bool QDir::removeRecursively()
return success;
}
+#endif // !QT_BOOTSTRAPPED
/*!
Returns \c true if the directory is readable \e and we can open files
@@ -1640,13 +1681,15 @@ bool QDir::removeRecursively()
*/
bool QDir::isReadable() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (!d->fileEngine) {
- if (!d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
- QFileSystemEngine::fillMetaData(d->dirEntry, d->metaData, QFileSystemMetaData::UserReadPermission);
-
- return d->metaData.permissions().testAnyFlag(QFile::ReadUser);
+ QMutexLocker locker(&d->fileCache.mutex);
+ if (!d->fileCache.metaData.hasFlags(QFileSystemMetaData::UserReadPermission)) {
+ QFileSystemEngine::fillMetaData(d->dirEntry, d->fileCache.metaData,
+ QFileSystemMetaData::UserReadPermission);
+ }
+ return d->fileCache.metaData.permissions().testAnyFlag(QFile::ReadUser);
}
const QAbstractFileEngine::FileFlags info =
@@ -1743,7 +1786,7 @@ bool QDir::isRelative() const
*/
bool QDir::makeAbsolute()
{
- const QDirPrivate *d = d_ptr.constData();
+ Q_D(const QDir);
std::unique_ptr<QDirPrivate> dir;
if (!!d->fileEngine) {
QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
@@ -1753,16 +1796,18 @@ bool QDir::makeAbsolute()
dir.reset(new QDirPrivate(*d_ptr.constData()));
dir->setPath(absolutePath);
} else { // native FS
- d->resolveAbsoluteEntry();
+ QString absoluteFilePath = d->resolveAbsoluteEntry();
dir.reset(new QDirPrivate(*d_ptr.constData()));
- dir->setPath(d->absoluteDirEntry.filePath());
+ dir->setPath(absoluteFilePath);
}
d_ptr = dir.release(); // actually detach
return true;
}
/*!
- Returns \c true if directory \a dir and this directory have the same
+ \fn bool QDir::operator==(const QDir &lhs, const QDir &rhs)
+
+ Returns \c true if directory \a lhs and directory \a rhs have the same
path and their sort and filter settings are the same; otherwise
returns \c false.
@@ -1770,10 +1815,10 @@ bool QDir::makeAbsolute()
\snippet code/src_corelib_io_qdir.cpp 10
*/
-bool QDir::operator==(const QDir &dir) const
+bool comparesEqual(const QDir &lhs, const QDir &rhs)
{
- const QDirPrivate *d = d_ptr.constData();
- const QDirPrivate *other = dir.d_ptr.constData();
+ const QDirPrivate *d = lhs.d_ptr.constData();
+ const QDirPrivate *other = rhs.d_ptr.constData();
if (d == other)
return true;
@@ -1797,18 +1842,18 @@ bool QDir::operator==(const QDir &dir) const
if (d->dirEntry.filePath() == other->dirEntry.filePath())
return true;
- if (exists()) {
- if (!dir.exists())
+ if (lhs.exists()) {
+ if (!rhs.exists())
return false; //can't be equal if only one exists
// Both exist, fallback to expensive canonical path computation
- return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0;
+ return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
} else {
- if (dir.exists())
+ if (rhs.exists())
return false; //can't be equal if only one exists
// Neither exists, compare absolute paths rather than canonical (which would be empty strings)
- d->resolveAbsoluteEntry();
- other->resolveAbsoluteEntry();
- return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0;
+ QString thisFilePath = d->resolveAbsoluteEntry();
+ QString otherFilePath = other->resolveAbsoluteEntry();
+ return thisFilePath.compare(otherFilePath, sensitive) == 0;
}
}
return false;
@@ -1833,11 +1878,10 @@ QDir &QDir::operator=(const QDir &dir)
*/
/*!
- \fn bool QDir::operator!=(const QDir &dir) const
+ \fn bool QDir::operator!=(const QDir &lhs, const QDir &rhs)
- Returns \c true if directory \a dir and this directory have different
- paths or different sort or filter settings; otherwise returns
- false.
+ Returns \c true if directory \a lhs and directory \a rhs have different
+ paths or different sort or filter settings; otherwise returns \c false.
Example:
@@ -1904,9 +1948,10 @@ bool QDir::exists(const QString &name) const
qWarning("QDir::exists: Empty or null file name");
return false;
}
- return QFile::exists(filePath(name));
+ return QFileInfo::exists(filePath(name));
}
+#ifndef QT_BOOTSTRAPPED
/*!
Returns whether the directory is empty.
@@ -1922,16 +1967,18 @@ bool QDir::exists(const QString &name) const
*/
bool QDir::isEmpty(Filters filters) const
{
- const auto d = d_ptr.constData();
- QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
- return !it.hasNext();
+ Q_D(const QDir);
+ QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters);
+ return dirList.cbegin() == dirList.cend();
}
+#endif // !QT_BOOTSTRAPPED
/*!
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
- "D:/", etc. On other operating systems, it returns a list containing
+ "D:/", etc. This does not return drives with ejectable media that are empty.
+ On other operating systems, it returns a list containing
just one root directory (i.e. "/").
\sa root(), rootPath()
@@ -2160,7 +2207,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
{
const bool allowUncPaths = flags.testAnyFlag(QDirPrivate::AllowUncPaths);
const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath);
- const int len = name.length();
+ const qsizetype len = name.size();
if (ok)
*ok = false;
@@ -2168,15 +2215,15 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
if (len == 0)
return name;
- int i = len - 1;
+ qsizetype i = len - 1;
QVarLengthArray<char16_t> outVector(len);
- int used = len;
+ qsizetype used = len;
char16_t *out = outVector.data();
- const ushort *p = reinterpret_cast<const ushort *>(name.data());
- const ushort *prefix = p;
- int up = 0;
+ const char16_t *p = reinterpret_cast<const char16_t *>(name.data());
+ const char16_t *prefix = p;
+ qsizetype up = 0;
- const int prefixLength = rootLength(name, allowUncPaths);
+ const qsizetype prefixLength = rootLength(name, allowUncPaths);
p += prefixLength;
i -= prefixLength;
@@ -2187,10 +2234,10 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
--i;
}
- auto isDot = [](const ushort *p, int i) {
+ auto isDot = [](const char16_t *p, qsizetype i) {
return i > 1 && p[i - 1] == '.' && p[i - 2] == '/';
};
- auto isDotDot = [](const ushort *p, int i) {
+ auto isDotDot = [](const char16_t *p, qsizetype i) {
return i > 2 && p[i - 1] == '.' && p[i - 2] == '.' && p[i - 3] == '/';
};
@@ -2293,7 +2340,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
// string only consists of a prefix followed by one or more slashes. Just skip the slash.
++used;
}
- for (int i = prefixLength - 1; i >= 0; --i)
+ for (qsizetype i = prefixLength - 1; i >= 0; --i)
out[--used] = prefix[i];
} else {
if (isEmpty) {
@@ -2311,7 +2358,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
// If path was not modified return the original value
if (used == 0)
return name;
- return QString::fromUtf16(out + used, len - used);
+ return QStringView(out + used, len - used).toString();
}
static QString qt_cleanPath(const QString &path, bool *ok)
@@ -2325,9 +2372,9 @@ static QString qt_cleanPath(const QString &path, bool *ok)
QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths ? QDirPrivate::AllowUncPaths : QDirPrivate::DefaultNormalization, ok);
// Strip away last slash except for root directories
- if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {
+ if (ret.size() > 1 && ret.endsWith(u'/')) {
#if defined (Q_OS_WIN)
- if (!(ret.length() == 3 && ret.at(1) == QLatin1Char(':')))
+ if (!(ret.length() == 3 && ret.at(1) == u':'))
#endif
ret.chop(1);
}
@@ -2371,10 +2418,8 @@ bool QDir::isRelativePath(const QString &path)
*/
void QDir::refresh() const
{
- QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data();
- d->metaData.clear();
- d->initFileEngine();
- d->clearFileLists();
+ QDirPrivate *d = const_cast<QDir *>(this)->d_func();
+ d->clearCache(QDirPrivate::IncludingMetaData);
}
/*!
@@ -2397,59 +2442,6 @@ QStringList QDir::nameFiltersFromString(const QString &nameFilter)
return QDirPrivate::splitFilters(nameFilter);
}
-/*!
- \macro void Q_INIT_RESOURCE(name)
- \relates QDir
-
- Initializes the resources specified by the \c .qrc file with the
- specified base \a name. Normally, when resources are built as part
- of the application, the resources are loaded automatically at
- startup. The Q_INIT_RESOURCE() macro is necessary on some platforms
- for resources stored in a static library.
-
- For example, if your application's resources are listed in a file
- called \c myapp.qrc, you can ensure that the resources are
- initialized at startup by adding this line to your \c main()
- function:
-
- \snippet code/src_corelib_io_qdir.cpp 13
-
- If the file name contains characters that cannot be part of a valid C++ function name
- (such as '-'), they have to be replaced by the underscore character ('_').
-
- \note This macro cannot be used in a namespace. It should be called from
- main(). If that is not possible, the following workaround can be used
- to init the resource \c myapp from the function \c{MyNamespace::myFunction}:
-
- \snippet code/src_corelib_io_qdir.cpp 14
-
- \sa Q_CLEANUP_RESOURCE(), {The Qt Resource System}
-*/
-
-/*!
- \since 4.1
- \macro void Q_CLEANUP_RESOURCE(name)
- \relates QDir
-
- Unloads the resources specified by the \c .qrc file with the base
- name \a name.
-
- Normally, Qt resources are unloaded automatically when the
- application terminates, but if the resources are located in a
- plugin that is being unloaded, call Q_CLEANUP_RESOURCE() to force
- removal of your resources.
-
- \note This macro cannot be used in a namespace. Please see the
- Q_INIT_RESOURCE documentation for a workaround.
-
- Example:
-
- \snippet code/src_corelib_io_qdir.cpp 15
-
- \sa Q_INIT_RESOURCE(), {The Qt Resource System}
-*/
-
-
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, QDir::Filters filters)
{
@@ -2457,25 +2449,25 @@ QDebug operator<<(QDebug debug, QDir::Filters filters)
debug.resetFormat();
QStringList flags;
if (filters == QDir::NoFilter) {
- flags << QLatin1String("NoFilter");
+ flags << "NoFilter"_L1;
} else {
- if (filters & QDir::Dirs) flags << QLatin1String("Dirs");
- if (filters & QDir::AllDirs) flags << QLatin1String("AllDirs");
- if (filters & QDir::Files) flags << QLatin1String("Files");
- if (filters & QDir::Drives) flags << QLatin1String("Drives");
- if (filters & QDir::NoSymLinks) flags << QLatin1String("NoSymLinks");
- if (filters & QDir::NoDot) flags << QLatin1String("NoDot");
- if (filters & QDir::NoDotDot) flags << QLatin1String("NoDotDot");
- if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << QLatin1String("AllEntries");
- if (filters & QDir::Readable) flags << QLatin1String("Readable");
- if (filters & QDir::Writable) flags << QLatin1String("Writable");
- if (filters & QDir::Executable) flags << QLatin1String("Executable");
- if (filters & QDir::Modified) flags << QLatin1String("Modified");
- if (filters & QDir::Hidden) flags << QLatin1String("Hidden");
- if (filters & QDir::System) flags << QLatin1String("System");
- if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
+ if (filters & QDir::Dirs) flags << "Dirs"_L1;
+ if (filters & QDir::AllDirs) flags << "AllDirs"_L1;
+ if (filters & QDir::Files) flags << "Files"_L1;
+ if (filters & QDir::Drives) flags << "Drives"_L1;
+ if (filters & QDir::NoSymLinks) flags << "NoSymLinks"_L1;
+ if (filters & QDir::NoDot) flags << "NoDot"_L1;
+ if (filters & QDir::NoDotDot) flags << "NoDotDot"_L1;
+ if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << "AllEntries"_L1;
+ if (filters & QDir::Readable) flags << "Readable"_L1;
+ if (filters & QDir::Writable) flags << "Writable"_L1;
+ if (filters & QDir::Executable) flags << "Executable"_L1;
+ if (filters & QDir::Modified) flags << "Modified"_L1;
+ if (filters & QDir::Hidden) flags << "Hidden"_L1;
+ if (filters & QDir::System) flags << "System"_L1;
+ if (filters & QDir::CaseSensitive) flags << "CaseSensitive"_L1;
}
- debug.noquote() << "QDir::Filters(" << flags.join(QLatin1Char('|')) << ')';
+ debug.noquote() << "QDir::Filters(" << flags.join(u'|') << ')';
return debug;
}
@@ -2487,18 +2479,18 @@ static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
debug << "QDir::SortFlags(NoSort)";
} else {
QString type;
- if ((sorting & QDir::SortByMask) == QDir::Name) type = QLatin1String("Name");
- if ((sorting & QDir::SortByMask) == QDir::Time) type = QLatin1String("Time");
- if ((sorting & QDir::SortByMask) == QDir::Size) type = QLatin1String("Size");
- if ((sorting & QDir::SortByMask) == QDir::Unsorted) type = QLatin1String("Unsorted");
+ if ((sorting & QDir::SortByMask) == QDir::Name) type = "Name"_L1;
+ if ((sorting & QDir::SortByMask) == QDir::Time) type = "Time"_L1;
+ if ((sorting & QDir::SortByMask) == QDir::Size) type = "Size"_L1;
+ if ((sorting & QDir::SortByMask) == QDir::Unsorted) type = "Unsorted"_L1;
QStringList flags;
- if (sorting & QDir::DirsFirst) flags << QLatin1String("DirsFirst");
- if (sorting & QDir::DirsLast) flags << QLatin1String("DirsLast");
- if (sorting & QDir::IgnoreCase) flags << QLatin1String("IgnoreCase");
- if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware");
- if (sorting & QDir::Type) flags << QLatin1String("Type");
- debug.noquote() << "QDir::SortFlags(" << type << '|' << flags.join(QLatin1Char('|')) << ')';
+ if (sorting & QDir::DirsFirst) flags << "DirsFirst"_L1;
+ if (sorting & QDir::DirsLast) flags << "DirsLast"_L1;
+ if (sorting & QDir::IgnoreCase) flags << "IgnoreCase"_L1;
+ if (sorting & QDir::LocaleAware) flags << "LocaleAware"_L1;
+ if (sorting & QDir::Type) flags << "Type"_L1;
+ debug.noquote() << "QDir::SortFlags(" << type << '|' << flags.join(u'|') << ')';
}
return debug;
}
@@ -2508,7 +2500,7 @@ QDebug operator<<(QDebug debug, const QDir &dir)
QDebugStateSaver save(debug);
debug.resetFormat();
debug << "QDir(" << dir.path() << ", nameFilters = {"
- << dir.nameFilters().join(QLatin1Char(','))
+ << dir.nameFilters().join(u',')
<< "}, "
<< dir.sorting()
<< ','
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index 7d7a483eae..53c0900f95 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIR_H
#define QDIR_H
+#include <QtCore/qcompare.h>
#include <QtCore/qstring.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
@@ -102,7 +67,7 @@ public:
QDir(const QString &path = QString());
QDir(const QString &path, const QString &nameFilter,
SortFlags sort = SortFlags(Name | IgnoreCase), Filters filter = AllEntries);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
QDir(const std::filesystem::path &path);
QDir(const std::filesystem::path &path, const QString &nameFilter,
SortFlags sort = SortFlags(Name | IgnoreCase), Filters filter = AllEntries);
@@ -127,7 +92,7 @@ public:
{ d_ptr.swap(other.d_ptr); }
void setPath(const QString &path);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
void setPath(const std::filesystem::path &path);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -139,7 +104,7 @@ public:
QString path() const;
QString absolutePath() const;
QString canonicalPath() const;
-#if QT_CONFIG(cxx17_filesystem) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
std::filesystem::path filesystemPath() const
{ return QtPrivate::toFilesystemPath(path()); }
std::filesystem::path filesystemAbsolutePath() const
@@ -148,9 +113,10 @@ public:
{ return QtPrivate::toFilesystemPath(canonicalPath()); }
#endif // QT_CONFIG(cxx17_filesystem)
+#ifndef QT_BOOTSTRAPPED
static void setSearchPaths(const QString &prefix, const QStringList &searchPaths);
static void addSearchPath(const QString &prefix, const QString &path);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
static void addSearchPath(const QString &prefix, const std::filesystem::path &path);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -160,6 +126,7 @@ public:
}
#endif // QT_CONFIG(cxx17_filesystem)
static QStringList searchPaths(const QString &prefix);
+#endif // QT_BOOTSTRAPPED
QString dirName() const;
QString filePath(const QString &fileName) const;
@@ -180,10 +147,16 @@ public:
SortFlags sorting() const;
void setSorting(SortFlags sort);
+#if QT_CORE_REMOVED_SINCE(6, 5)
uint count() const;
+#endif
+ qsizetype count(QT6_DECL_NEW_OVERLOAD) const;
bool isEmpty(Filters filters = Filters(AllEntries | NoDotAndDotDot)) const;
+#if QT_CORE_REMOVED_SINCE(6, 5) && QT_POINTER_SIZE != 4
QString operator[](int) const;
+#endif
+ QString operator[](qsizetype) const;
static QStringList nameFiltersFromString(const QString &nameFilter);
@@ -213,8 +186,10 @@ public:
inline bool isAbsolute() const { return !isRelative(); }
bool makeAbsolute();
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QDir &dir) const;
inline bool operator!=(const QDir &dir) const { return !operator==(dir); }
+#endif
bool remove(const QString &fileName);
bool rename(const QString &oldName, const QString &newName);
@@ -225,18 +200,18 @@ public:
constexpr static inline QChar listSeparator() noexcept
{
#if defined(Q_OS_WIN)
- return QLatin1Char(';');
+ return u';';
#else
- return QLatin1Char(':');
+ return u':';
#endif
}
static QChar separator()
{
#if defined(Q_OS_WIN)
- return QLatin1Char('\\');
+ return u'\\';
#else
- return QLatin1Char('/');
+ return u'/';
#endif
}
@@ -265,7 +240,10 @@ protected:
QSharedDataPointer<QDirPrivate> d_ptr;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QDir &lhs, const QDir &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QDir)
friend class QDirIterator;
+ friend class QDirListing;
// Q_DECLARE_PRIVATE equivalent for shared data pointers
QDirPrivate *d_func();
const QDirPrivate *d_func() const { return d_ptr.constData(); }
diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h
index af105de8db..7dce69c195 100644
--- a/src/corelib/io/qdir_p.h
+++ b/src/corelib/io/qdir_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIR_P_H
#define QDIR_P_H
@@ -54,6 +18,8 @@
#include "qfilesystementry_p.h"
#include "qfilesystemmetadata_p.h"
+#include <QtCore/qmutex.h>
+
#include <memory>
QT_BEGIN_NAMESPACE
@@ -73,14 +39,13 @@ public:
QDir::SortFlags sort_ = QDir::SortFlags(QDir::Name | QDir::IgnoreCase),
QDir::Filters filters_ = QDir::AllEntries);
- explicit QDirPrivate(const QDirPrivate &copy);
+ explicit QDirPrivate(const QDirPrivate &copy); // Copies everything except mutex and fileEngine
bool exists() const;
- void initFileEngine();
void initFileLists(const QDir &dir) const;
- static void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *);
+ static void sortFileList(QDir::SortFlags, const QFileInfoList &, QStringList *, QFileInfoList *);
static inline QChar getFilterSepChar(const QString &nameFilter);
@@ -88,13 +53,10 @@ public:
void setPath(const QString &path);
- void clearFileLists();
-
- void resolveAbsoluteEntry() const;
+ enum MetaDataClearing { KeepMetaData, IncludingMetaData };
+ void clearCache(MetaDataClearing mode);
- mutable bool fileListsInitialized;
- mutable QStringList files;
- mutable QFileInfoList fileInfos;
+ QString resolveAbsoluteEntry() const;
QStringList nameFilters;
QDir::SortFlags sort;
@@ -103,8 +65,17 @@ public:
std::unique_ptr<QAbstractFileEngine> fileEngine;
QFileSystemEntry dirEntry;
- mutable QFileSystemEntry absoluteDirEntry;
- mutable QFileSystemMetaData metaData;
+
+ struct FileCache
+ {
+ QMutex mutex;
+ QStringList files;
+ QFileInfoList fileInfos;
+ std::atomic<bool> fileListsInitialized = false;
+ QFileSystemEntry absoluteDirEntry;
+ QFileSystemMetaData metaData;
+ };
+ mutable FileCache fileCache;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDirPrivate::PathNormalizations)
diff --git a/src/corelib/io/qdirentryinfo_p.h b/src/corelib/io/qdirentryinfo_p.h
new file mode 100644
index 0000000000..7ed5391ff0
--- /dev/null
+++ b/src/corelib/io/qdirentryinfo_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDIRENTRYINFO_P_H
+#define QDIRENTRYINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qfileinfo_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDirEntryInfo
+{
+ const QFileSystemMetaData &ensureFilled(QFileSystemMetaData::MetaDataFlags what)
+ {
+ if (!metaData.hasFlags(what))
+ QFileSystemEngine::fillMetaData(entry, metaData, what);
+ return metaData;
+ }
+
+public:
+ const QFileInfo &fileInfo()
+ {
+ if (!fileInfoOpt) {
+ fileInfoOpt.emplace(new QFileInfoPrivate(entry, metaData));
+ metaData.clear();
+ }
+ return *fileInfoOpt;
+ }
+
+ QString fileName()
+ { return fileInfoOpt ? fileInfoOpt->fileName() : entry.fileName(); }
+ QString baseName()
+ { return fileInfoOpt ? fileInfoOpt->baseName() : entry.baseName(); }
+ QString completeBaseName() const
+ { return fileInfoOpt ? fileInfoOpt->completeBaseName() : entry.completeBaseName(); }
+ QString suffix() const
+ { return fileInfoOpt ? fileInfoOpt->suffix() : entry.suffix(); }
+ QString completeSuffix() const
+ { return fileInfoOpt ? fileInfoOpt->completeSuffix() : entry.completeSuffix(); }
+ QString filePath()
+ { return fileInfoOpt ? fileInfoOpt->filePath() : entry.filePath(); }
+
+ QString bundleName() { return fileInfo().bundleName(); }
+
+ QString canonicalFilePath()
+ {
+ // QFileInfo caches these strings
+ return fileInfo().canonicalFilePath();
+ }
+
+ QString absoluteFilePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absoluteFilePath();
+ }
+
+ QString absolutePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absolutePath();
+ }
+
+
+ bool isDir() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isDir();
+
+ return ensureFilled(QFileSystemMetaData::DirectoryType).isDirectory();
+ }
+
+ bool isFile() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isFile();
+
+ return ensureFilled(QFileSystemMetaData::FileType).isFile();
+ }
+
+ bool isSymLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymLink();
+
+ return ensureFilled(QFileSystemMetaData::LegacyLinkType).isLegacyLink();
+ }
+
+ bool isSymbolicLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymbolicLink();
+
+ return ensureFilled(QFileSystemMetaData::LinkType).isLink();
+ }
+
+ bool exists() {
+ if (fileInfoOpt)
+ return fileInfoOpt->exists();
+
+ return ensureFilled(QFileSystemMetaData::ExistsAttribute).exists();
+ }
+
+ bool isHidden() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isHidden();
+
+ return ensureFilled(QFileSystemMetaData::HiddenAttribute).isHidden();
+ }
+
+ bool isReadable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isReadable();
+
+ return ensureFilled(QFileSystemMetaData::UserReadPermission).isReadable();
+ }
+
+ bool isWritable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isWritable();
+
+ return ensureFilled(QFileSystemMetaData::UserWritePermission).isWritable();
+ }
+
+ bool isExecutable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isExecutable();
+
+ return ensureFilled(QFileSystemMetaData::UserExecutePermission).isExecutable();
+ }
+
+ qint64 size() { return fileInfo().size(); }
+
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz)
+ {
+ return fileInfo().fileTime(type, tz);
+ }
+
+private:
+ friend class QDirListingPrivate;
+ friend class QDirListing;
+
+ QFileSystemEntry entry;
+ QFileSystemMetaData metaData;
+ std::optional<QFileInfo> fileInfoOpt;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIRENTRYINFO_P_H
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 7e86aacdb1..3604e673e2 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\since 4.3
@@ -70,6 +34,9 @@
you cannot iterate directories in reverse order) and does not allow random
access.
+ \note This class is deprecated and may be removed in a Qt release. Use
+ QDirListing instead.
+
\sa QDir, QDir::entryList()
*/
@@ -92,6 +59,8 @@
#include "qdiriterator.h"
#include "qdir_p.h"
#include "qabstractfileengine_p.h"
+#include "qdirlisting.h"
+#include "qdirentryinfo_p.h"
#include <QtCore/qset.h>
#include <QtCore/qstack.h>
@@ -108,295 +77,74 @@
#include <QtCore/private/qduplicatetracker_p.h>
#include <memory>
+#include <stack>
+#include <vector>
QT_BEGIN_NAMESPACE
-template <class Iterator>
-class QDirIteratorPrivateIteratorStack : public QStack<Iterator *>
-{
-public:
- ~QDirIteratorPrivateIteratorStack()
- {
- qDeleteAll(*this);
- }
-};
+using namespace Qt::StringLiterals;
class QDirIteratorPrivate
{
-public:
- QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
- QDir::Filters _filters, QDirIterator::IteratorFlags flags, bool resolveEngine = true);
-
- void advance();
-
- bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
- void pushDirectory(const QFileInfo &fileInfo);
- void checkAndPushDirectory(const QFileInfo &);
- bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
-
- std::unique_ptr<QAbstractFileEngine> engine;
-
- QFileSystemEntry dirEntry;
- const QStringList nameFilters;
- const QDir::Filters filters;
- const QDirIterator::IteratorFlags iteratorFlags;
-
-#if QT_CONFIG(regularexpression)
- QList<QRegularExpression> nameRegExps;
-#endif
-
- QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators;
-#ifndef QT_NO_FILESYSTEMITERATOR
- QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators;
-#endif
-
- QFileInfo currentFileInfo;
- QFileInfo nextFileInfo;
+ static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)
+ {
+ using F = QDirListing::IteratorFlag;
+ QDirListing::IteratorFlags listerFlags;
- // Loop protection
- QDuplicateTracker<QString> visitedLinks;
-};
+ if (flags & QDirIterator::NoIteratorFlags)
+ listerFlags.setFlag(F::NoFlag);
+ if (flags & QDirIterator::FollowSymlinks)
+ listerFlags.setFlag(F::FollowSymlinks);
+ if (flags & QDirIterator::Subdirectories)
+ listerFlags.setFlag(F::Recursive);
-/*!
- \internal
-*/
-QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
- QDir::Filters _filters, QDirIterator::IteratorFlags flags, bool resolveEngine)
- : dirEntry(entry)
- , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters)
- , filters(QDir::NoFilter == _filters ? QDir::AllEntries : _filters)
- , iteratorFlags(flags)
-{
-#if QT_CONFIG(regularexpression)
- nameRegExps.reserve(nameFilters.size());
- for (const auto &filter : nameFilters) {
- auto re = QRegularExpression::fromWildcard(filter, (filters & QDir::CaseSensitive ?
- Qt::CaseSensitive : Qt::CaseInsensitive));
- nameRegExps.append(re);
+ return listerFlags;
}
-#endif
- QFileSystemMetaData metaData;
- if (resolveEngine)
- engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
- QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData));
-
- // Populate fields for hasNext() and next()
- pushDirectory(fileInfo);
- advance();
-}
-/*!
- \internal
-*/
-void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
-{
- QString path = fileInfo.filePath();
-
-#ifdef Q_OS_WIN
- if (fileInfo.isSymLink())
- path = fileInfo.canonicalFilePath();
-#endif
-
- if ((iteratorFlags & QDirIterator::FollowSymlinks)) {
- // Stop link loops
- if (visitedLinks.hasSeen(fileInfo.canonicalFilePath()))
- return;
+public:
+ QDirIteratorPrivate(const QDir &dir, QDirIterator::IteratorFlags flags)
+ : lister(dir, toDirListingFlags(flags))
+ {
+ init();
}
-
- if (engine) {
- engine->setFileName(path);
- QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
- if (it) {
- it->setPath(path);
- fileEngineIterators << it;
- } else {
- // No iterator; no entry list.
- }
- } else {
-#ifndef QT_NO_FILESYSTEMITERATOR
- QFileSystemIterator *it = new QFileSystemIterator(fileInfo.d_ptr->fileEntry,
- filters, nameFilters, iteratorFlags);
- nativeIterators << it;
-#else
- qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
-#endif
+ QDirIteratorPrivate(const QString &path, QDirIterator::IteratorFlags flags)
+ : lister(path, toDirListingFlags(flags))
+ {
+ init();
}
-}
-
-inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo)
-{
- checkAndPushDirectory(fileInfo);
-
- if (matchesFilters(fileName, fileInfo)) {
- currentFileInfo = nextFileInfo;
- nextFileInfo = fileInfo;
-
- //We found a matching entry.
- return true;
+ QDirIteratorPrivate(const QString &path, QDir::Filters filters,
+ QDirIterator::IteratorFlags flags)
+ : lister(path, filters, toDirListingFlags(flags))
+ {
+ init();
}
-
- return false;
-}
-
-/*!
- \internal
-*/
-void QDirIteratorPrivate::advance()
-{
- if (engine) {
- while (!fileEngineIterators.isEmpty()) {
- // Find the next valid iterator that matches the filters.
- QAbstractFileEngineIterator *it;
- while (it = fileEngineIterators.top(), it->hasNext()) {
- it->next();
- if (entryMatches(it->currentFileName(), it->currentFileInfo()))
- return;
- }
-
- fileEngineIterators.pop();
- delete it;
- }
- } else {
-#ifndef QT_NO_FILESYSTEMITERATOR
- QFileSystemEntry nextEntry;
- QFileSystemMetaData nextMetaData;
-
- while (!nativeIterators.isEmpty()) {
- // Find the next valid iterator that matches the filters.
- QFileSystemIterator *it;
- while (it = nativeIterators.top(), it->advance(nextEntry, nextMetaData)) {
- QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
-
- if (entryMatches(nextEntry.fileName(), info))
- return;
- nextMetaData = QFileSystemMetaData();
- }
-
- nativeIterators.pop();
- delete it;
- }
-#endif
+ QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
+ QDirIterator::IteratorFlags flags)
+ : lister(path, nameFilters, filters, toDirListingFlags(flags))
+ {
+ init();
}
- currentFileInfo = nextFileInfo;
- nextFileInfo = QFileInfo();
-}
-
-/*!
- \internal
- */
-void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
-{
- // If we're doing flat iteration, we're done.
- if (!(iteratorFlags & QDirIterator::Subdirectories))
- return;
-
- // Never follow non-directory entries
- if (!fileInfo.isDir())
- return;
-
- // Follow symlinks only when asked
- if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
- return;
-
- // Never follow . and ..
- QString fileName = fileInfo.fileName();
- if (QLatin1String(".") == fileName || QLatin1String("..") == fileName)
- return;
-
- // No hidden directories unless requested
- if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
- return;
-
- pushDirectory(fileInfo);
-}
-
-/*!
- \internal
-
- This convenience function implements the iterator's filtering logics and
- applies then to the current directory entry.
-
- It returns \c true if the current entry matches the filters (i.e., the
- current entry will be returned as part of the directory iteration);
- otherwise, false is returned.
-*/
-
-bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
-{
- if (fileName.isEmpty())
- return false;
-
- // filter . and ..?
- const int fileNameSize = fileName.size();
- const bool dotOrDotDot = fileName[0] == QLatin1Char('.')
- && ((fileNameSize == 1)
- ||(fileNameSize == 2 && fileName[1] == QLatin1Char('.')));
- if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
- return false;
- if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
- return false;
-
- // name filter
-#if QT_CONFIG(regularexpression)
- // Pass all entries through name filters, except dirs if the AllDirs
- if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
- bool matched = false;
- for (const auto &re : nameRegExps) {
- if (re.match(fileName).hasMatch()) {
- matched = true;
- break;
- }
- }
- if (!matched)
- return false;
- }
-#endif
- // skip symlinks
- const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
- const bool includeSystem = filters.testAnyFlag(QDir::System);
- if (skipSymlinks && fi.isSymLink()) {
- // The only reason to save this file is if it is a broken link and we are requesting system files.
- if (!includeSystem || fi.exists())
- return false;
+ void init()
+ {
+ it = lister.begin();
+ if (it != lister.end())
+ nextFileInfo = it->fileInfo();
}
- // filter hidden
- const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
- if (!includeHidden && !dotOrDotDot && fi.isHidden())
- return false;
-
- // filter system files
- if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink())
- || (!fi.exists() && fi.isSymLink())))
- return false;
-
- // skip directories
- const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
- if (skipDirs && fi.isDir())
- return false;
-
- // skip files
- const bool skipFiles = !(filters & QDir::Files);
- if (skipFiles && fi.isFile())
- // Basically we need a reason not to exclude this file otherwise we just eliminate it.
- return false;
-
- // filter permissions
- const bool filterPermissions = ((filters & QDir::PermissionMask)
- && (filters & QDir::PermissionMask) != QDir::PermissionMask);
- const bool doWritable = !filterPermissions || (filters & QDir::Writable);
- const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
- const bool doReadable = !filterPermissions || (filters & QDir::Readable);
- if (filterPermissions
- && ((doReadable && !fi.isReadable())
- || (doWritable && !fi.isWritable())
- || (doExecutable && !fi.isExecutable()))) {
- return false;
+ void advance()
+ {
+ currentFileInfo = nextFileInfo;
+ if (++it != lister.end()) {
+ nextFileInfo = it->fileInfo();
+ }
}
- return true;
-}
+ QDirListing lister;
+ QDirListing::const_iterator it = {};
+ QFileInfo currentFileInfo;
+ QFileInfo nextFileInfo;
+};
/*!
Constructs a QDirIterator that can iterate over \a dir's entrylist, using
@@ -414,9 +162,8 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
+ : d(new QDirIteratorPrivate(dir, flags))
{
- const QDirPrivate *other = dir.d_ptr.constData();
- d.reset(new QDirIteratorPrivate(other->dirEntry, other->nameFilters, other->filters, flags, bool(other->fileEngine)));
}
/*!
@@ -433,7 +180,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), filters, flags))
+ : d(new QDirIteratorPrivate(path, filters, flags))
{
}
@@ -450,7 +197,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), QDir::NoFilter, flags))
+ : d(new QDirIteratorPrivate(path, flags))
{
}
@@ -474,7 +221,7 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
*/
QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), nameFilters, filters, flags))
+ : d(new QDirIteratorPrivate(path, nameFilters, filters, flags))
{
}
@@ -500,7 +247,7 @@ QDirIterator::~QDirIterator()
QString QDirIterator::next()
{
d->advance();
- return filePath();
+ return d->currentFileInfo.filePath();
}
/*!
@@ -520,7 +267,7 @@ QString QDirIterator::next()
QFileInfo QDirIterator::nextFileInfo()
{
d->advance();
- return fileInfo();
+ return d->currentFileInfo;
}
/*!
@@ -531,14 +278,7 @@ QFileInfo QDirIterator::nextFileInfo()
*/
bool QDirIterator::hasNext() const
{
- if (d->engine)
- return !d->fileEngineIterators.isEmpty();
- else
-#ifndef QT_NO_FILESYSTEMITERATOR
- return !d->nativeIterators.isEmpty();
-#else
- return false;
-#endif
+ return d->it != d->lister.end();
}
/*!
@@ -581,7 +321,7 @@ QFileInfo QDirIterator::fileInfo() const
*/
QString QDirIterator::path() const
{
- return d->dirEntry.filePath();
+ return d->lister.iteratorPath();
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdiriterator.h b/src/corelib/io/qdiriterator.h
index f3a4b979ac..7fa612ebe0 100644
--- a/src/corelib/io/qdiriterator.h
+++ b/src/corelib/io/qdiriterator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRITERATOR_H
#define QDIRITERATOR_H
diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp
new file mode 100644
index 0000000000..008003e856
--- /dev/null
+++ b/src/corelib/io/qdirlisting.cpp
@@ -0,0 +1,673 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*!
+ \since 6.8
+ \class QDirListing
+ \inmodule QtCore
+ \brief The QDirListing class provides an STL-style iterator for directory entries.
+
+ You can use QDirListing to navigate entries of a directory one at a time.
+ It is similar to QDir::entryList() and QDir::entryInfoList(), but because
+ it lists entries one at a time instead of all at once, it scales better
+ and is more suitable for large directories. It also supports listing
+ directory contents recursively, and following symbolic links. Unlike
+ QDir::entryList(), QDirListing does not support sorting.
+
+ The QDirListing constructor takes a QDir or a directory path as
+ argument. Here's how to iterate over all entries recursively:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
+
+ Here's how to find and read all files filtered by name, recursively:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
+
+ Iterators constructed by QDirListing (QDirListing::const_iterator) are
+ forward-only (you cannot iterate directories in reverse order) and don't
+ allow random access. They can be used in ranged-for loops (or with STL
+ alogrithms that don't require random access iterators). Dereferencing
+ a valid iterator returns a QDirListing::DirEntry object. The (c)end()
+ iterator marks the end of the iteration. Dereferencing the end iterator
+ is undefiend behavior.
+
+ QDirListing::DirEntry offers a subset of QFileInfo's API (for example,
+ fileName(), filePath(), exists()). Internally, DirEntry only constructs
+ a QFileInfo object if needed, that is, if the info hasn't been already
+ fetched by other system functions. You can use DirEntry::fileInfo()
+ to get a QFileInfo. For example:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 3
+ \snippet code/src_corelib_io_qdirlisting.cpp 4
+
+ \sa QDir, QDir::entryList()
+*/
+
+/*! \enum QDirListing::IteratorFlag
+
+ This enum class describes flags can be used to configure the behavior of
+ QDirListing. These flags can be bitwise OR'ed together.
+
+ \value NoFlag The default value, representing no flags. The iterator
+ will return entries for the assigned path.
+
+ \value FollowSymlinks When combined with Recursive, this flag enables
+ iterating through all subdirectories of the assigned path, following
+ all symbolic links. Symbolic link loops (e.g., link => . or link =>
+ ..) are automatically detected and ignored.
+
+ \value Recursive List entries inside all subdirectories as well.
+*/
+
+#include "qdirlisting.h"
+#include "qdirentryinfo_p.h"
+
+#include "qdir_p.h"
+#include "qabstractfileengine_p.h"
+
+#include <QtCore/qset.h>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+#include <QtCore/private/qfilesystemiterator_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+#include <QtCore/private/qfilesystemengine_p.h>
+#include <QtCore/private/qfileinfo_p.h>
+#include <QtCore/private/qduplicatetracker_p.h>
+
+#include <memory>
+#include <stack>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+class QDirListingPrivate
+{
+public:
+ void init(bool resolveEngine);
+ void advance();
+
+ bool entryMatches(QDirEntryInfo &info);
+ void pushDirectory(QDirEntryInfo &info);
+ void pushInitialDirectory();
+
+ void checkAndPushDirectory(QDirEntryInfo &info);
+ bool matchesFilters(QDirEntryInfo &data) const;
+ bool hasIterators() const;
+
+ std::unique_ptr<QAbstractFileEngine> engine;
+ QDirEntryInfo initialEntryInfo;
+ QStringList nameFilters;
+ QDir::Filters filters;
+ QDirListing::IteratorFlags iteratorFlags;
+ QDirEntryInfo currentEntryInfo;
+
+#if QT_CONFIG(regularexpression)
+ QList<QRegularExpression> nameRegExps;
+#endif
+
+ using FEngineIteratorPtr = std::unique_ptr<QAbstractFileEngineIterator>;
+ std::stack<FEngineIteratorPtr, std::vector<FEngineIteratorPtr>> fileEngineIterators;
+#ifndef QT_NO_FILESYSTEMITERATOR
+ using FsIteratorPtr = std::unique_ptr<QFileSystemIterator>;
+ std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
+#endif
+
+ // Loop protection
+ QDuplicateTracker<QString> visitedLinks;
+};
+
+void QDirListingPrivate::init(bool resolveEngine = true)
+{
+ if (nameFilters.contains("*"_L1))
+ nameFilters.clear();
+
+ if (filters == QDir::NoFilter)
+ filters = QDir::AllEntries;
+
+#if QT_CONFIG(regularexpression)
+ nameRegExps.reserve(nameFilters.size());
+ const auto cs = filters.testAnyFlags(QDir::CaseSensitive) ? Qt::CaseSensitive
+ : Qt::CaseInsensitive;
+ for (const auto &filter : nameFilters)
+ nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs));
+#endif
+
+ if (resolveEngine) {
+ engine = QFileSystemEngine::createLegacyEngine(initialEntryInfo.entry,
+ initialEntryInfo.metaData);
+ }
+
+ pushDirectory(initialEntryInfo);
+}
+
+void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
+{
+ const QString path = [&entryInfo] {
+#ifdef Q_OS_WIN
+ if (entryInfo.isSymLink())
+ return entryInfo.canonicalFilePath();
+#endif
+ return entryInfo.filePath();
+ }();
+
+
+ if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowSymlinks)) {
+ // Stop link loops
+ if (visitedLinks.hasSeen(entryInfo.canonicalFilePath()))
+ return;
+ }
+
+ if (engine) {
+ engine->setFileName(path);
+ if (auto it = engine->beginEntryList(path, filters, nameFilters)) {
+ fileEngineIterators.emplace(std::move(it));
+ } else {
+ // No iterator; no entry list.
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QFileSystemEntry *fentry = nullptr;
+ if (entryInfo.fileInfoOpt)
+ fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry;
+ else
+ fentry = &entryInfo.entry;
+ nativeIterators.emplace(std::make_unique<QFileSystemIterator>(*fentry, filters));
+#else
+ qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
+#endif
+ }
+}
+
+bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo)
+{
+ checkAndPushDirectory(entryInfo);
+ return matchesFilters(entryInfo);
+}
+
+/*!
+ \internal
+
+ Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
+ QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
+ system methods, e.g. readdir() on Unix).
+
+ An iterator stack is used for holding the iterators.
+
+ A typical example of doing recursive iteration:
+ - while iterating directory A we find a sub-dir B
+ - an iterator for B is added to the iterator stack
+ - B's iterator is processed (the top() of the stack) first; then loop
+ goes back to processing A's iterator
+*/
+void QDirListingPrivate::advance()
+{
+ // Use get() in both code paths below because the iterator returned by top()
+ // may be invalidated due to reallocation when appending new iterators in
+ // pushDirectory().
+
+ if (engine) {
+ while (!fileEngineIterators.empty()) {
+ // Find the next valid iterator that matches the filters.
+ QAbstractFileEngineIterator *it;
+ while (it = fileEngineIterators.top().get(), it->advance()) {
+ QDirEntryInfo entryInfo;
+ entryInfo.fileInfoOpt = it->currentFileInfo();
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
+ return;
+ }
+ }
+
+ fileEngineIterators.pop();
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QDirEntryInfo entryInfo;
+ while (!nativeIterators.empty()) {
+ // Find the next valid iterator that matches the filters.
+ QFileSystemIterator *it;
+ while (it = nativeIterators.top().get(), it->advance(entryInfo.entry, entryInfo.metaData)) {
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
+ return;
+ }
+ entryInfo = {};
+ }
+
+ nativeIterators.pop();
+ }
+#endif
+ }
+}
+
+void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo)
+{
+ using F = QDirListing::IteratorFlag;
+ // If we're doing flat iteration, we're done.
+ if (!iteratorFlags.testAnyFlags(F::Recursive))
+ return;
+
+ // Never follow non-directory entries
+ if (!entryInfo.isDir())
+ return;
+
+ // Follow symlinks only when asked
+ if (!iteratorFlags.testAnyFlags(F::FollowSymlinks) && entryInfo.isSymLink())
+ return;
+
+ // Never follow . and ..
+ const QString &fileName = entryInfo.fileName();
+ if ("."_L1 == fileName || ".."_L1 == fileName)
+ return;
+
+ // No hidden directories unless requested
+ if (!filters.testAnyFlags(QDir::AllDirs | QDir::Hidden) && entryInfo.isHidden())
+ return;
+
+ pushDirectory(entryInfo);
+}
+
+/*!
+ \internal
+
+ This functions returns \c true if the current entry matches the filters
+ (i.e., the current entry will be returned as part of the directory
+ iteration); otherwise, \c false is returned.
+*/
+bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const
+{
+ const QString &fileName = entryInfo.fileName();
+ if (fileName.isEmpty())
+ return false;
+
+ // filter . and ..?
+ const qsizetype fileNameSize = fileName.size();
+ const bool dotOrDotDot = fileName[0] == u'.'
+ && ((fileNameSize == 1)
+ ||(fileNameSize == 2 && fileName[1] == u'.'));
+ if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
+ return false;
+ if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
+ return false;
+
+ // name filter
+#if QT_CONFIG(regularexpression)
+ // Pass all entries through name filters, except dirs if AllDirs is set
+ if (!nameRegExps.isEmpty() && !(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) {
+ auto regexMatchesName = [&fileName](const auto &re) {
+ return re.match(fileName).hasMatch();
+ };
+ if (std::none_of(nameRegExps.cbegin(), nameRegExps.cend(), regexMatchesName))
+ return false;
+ }
+#endif
+ // skip symlinks
+ const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
+ const bool includeSystem = filters.testAnyFlag(QDir::System);
+ if (skipSymlinks && entryInfo.isSymLink()) {
+ // The only reason to save this file is if it is a broken link and we are requesting system files.
+ if (!includeSystem || entryInfo.exists())
+ return false;
+ }
+
+ // filter hidden
+ const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
+ if (!includeHidden && !dotOrDotDot && entryInfo.isHidden())
+ return false;
+
+ // filter system files
+ if (!includeSystem) {
+ if (!entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink())
+ return false;
+ if (entryInfo.isSymLink() && !entryInfo.exists())
+ return false;
+ }
+
+ // skip directories
+ const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
+ if (skipDirs && entryInfo.isDir())
+ return false;
+
+ // skip files
+ const bool skipFiles = !(filters & QDir::Files);
+ if (skipFiles && entryInfo.isFile())
+ // Basically we need a reason not to exclude this file otherwise we just eliminate it.
+ return false;
+
+ // filter permissions
+ const auto perms = filters & QDir::PermissionMask;
+ const bool filterPermissions = perms != 0 && perms != QDir::PermissionMask;
+ if (filterPermissions) {
+ const bool doWritable = filters.testAnyFlags(QDir::Writable);
+ const bool doExecutable = filters.testAnyFlags(QDir::Executable);
+ const bool doReadable = filters.testAnyFlags(QDir::Readable);
+ if ((doReadable && !entryInfo.isReadable())
+ || (doWritable && !entryInfo.isWritable())
+ || (doExecutable && !entryInfo.isExecutable())) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QDirListingPrivate::hasIterators() const
+{
+ if (engine)
+ return !fileEngineIterators.empty();
+
+#if !defined(QT_NO_FILESYSTEMITERATOR)
+ return !nativeIterators.empty();
+#endif
+
+ return false;
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a dir's entries, using
+ \a dir's name filters and the QDir::Filters set in \a dir. You can pass
+ options via \a flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ The sorting in \a dir is ignored.
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a dir's QDir::Filters.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QDir &dir, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ const QDirPrivate *other = dir.d_ptr.constData();
+ d->initialEntryInfo.entry = other->dirEntry;
+ d->nameFilters = other->nameFilters;
+ d->filters = other->filters;
+ d->iteratorFlags = flags;
+ const bool resolveEngine = other->fileEngine ? true : false;
+ d->init(resolveEngine);
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path. Entries are
+ filtered according to \a filters. You can pass options via \a flags to
+ decide how the directory should be iterated.
+
+ By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
+ which provides the same behavior as in QDir::entryList().
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a filters.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QString &path, QDir::Filters filters, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->filters = filters;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path. You can pass
+ options via \a flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QString &path, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->filters = QDir::NoFilter;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path, using \a
+ nameFilters and \a filters. You can pass options via \a flags to decide
+ how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as QDir::entryList().
+
+ For example, the following iterator could be used to iterate over audio
+ files:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 2
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a flags.
+
+ \sa hasNext(), next(), IteratorFlags, QDir::setNameFilters()
+*/
+QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
+ IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->nameFilters = nameFilters;
+ d->filters = filters;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Destroys the QDirListing.
+*/
+QDirListing::~QDirListing() = default;
+
+/*!
+ Returns the directory path used to construct this QDirListing.
+*/
+QString QDirListing::iteratorPath() const
+{
+ return d->initialEntryInfo.filePath();
+}
+
+/*!
+ \fn QDirListing::const_iterator QDirListing::begin() const
+ \fn QDirListing::const_iterator QDirListing::cbegin() const
+ \fn QDirListing::const_iterator QDirListing::end() const
+ \fn QDirListing::const_iterator QDirListing::cend() const
+
+ begin()/cbegin() returns a QDirListing::const_iterator that enables
+ iterating over directory entries using a ranged-for loop; dereferencing
+ this iterator returns a \c{const QFileInfo &}.
+
+ end()/cend() return a sentinel const_iterator that signals the end of
+ the iteration. Dereferencing this iterator is undefined behavior.
+
+ For example:
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
+
+ Here's how to find and read all files filtered by name, recursively:
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
+
+ \note As this is a unidirectional (forward-only) iterator, calling
+ begin()/cbegin() more than once on the same QDirListing object could
+ result in unexpected behavior (for example, some entries being skipped).
+
+ \sa fileInfo(), fileName(), filePath()
+*/
+QDirListing::const_iterator QDirListing::begin() const
+{
+ const_iterator it{d.get()};
+ return ++it;
+}
+
+/*!
+ \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
+
+ Returns a \c{const QDirListing::DirEntry &} of the directory entry this
+ iterator points to.
+*/
+
+/*!
+ \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
+
+ Returns a \c{const QDirListing::DirEntry *} to the directory entry this
+ iterator points to.
+*/
+
+/*!
+ Advances the iterator and returns a reference to it.
+*/
+QDirListing::const_iterator &QDirListing::const_iterator::operator++()
+{
+ dirListPtr->advance();
+ if (!dirListPtr->hasIterators())
+ *this = {}; // All done, make `this` the end() iterator
+ return *this;
+}
+
+/*!
+ \fn QFileInfo QDirListing::DirEntry::fileInfo() const
+ \fn QString QDirListing::DirEntry::fileName() const
+ \fn QString QDirListing::DirEntry::baseName() const
+ \fn QString QDirListing::DirEntry::completeBaseName() const
+ \fn QString QDirListing::DirEntry::suffix() const
+ \fn QString QDirListing::DirEntry::bundleName() const
+ \fn QString QDirListing::DirEntry::completeSuffix() const
+ \fn QString QDirListing::DirEntry::filePath() const
+ \fn QString QDirListing::DirEntry::canonicalFilePath() const
+ \fn QString QDirListing::DirEntry::absoluteFilePath() const
+ \fn QString QDirListing::DirEntry::absolutePath() const
+ \fn bool QDirListing::DirEntry::isDir() const
+ \fn bool QDirListing::DirEntry::isFile() const
+ \fn bool QDirListing::DirEntry::isSymLink() const
+ \fn bool QDirListing::DirEntry::exists() const
+ \fn bool QDirListing::DirEntry::isHidden() const
+ \fn bool QDirListing::DirEntry::isReadable() const
+ \fn bool QDirListing::DirEntry::isWritable() const
+ \fn bool QDirListing::DirEntry::isExecutable() const
+ \fn qint64 QDirListing::DirEntry::size() const
+ \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
+ \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
+
+ See the QFileInfo methods with the same names.
+*/
+
+QFileInfo QDirListing::DirEntry::fileInfo() const
+{
+ return dirListPtr->currentEntryInfo.fileInfo();
+}
+
+QString QDirListing::DirEntry::fileName() const
+{
+ return dirListPtr->currentEntryInfo.fileName();
+}
+
+QString QDirListing::DirEntry::baseName() const
+{
+ return dirListPtr->currentEntryInfo.baseName();
+}
+
+QString QDirListing::DirEntry::completeBaseName() const
+{
+ return dirListPtr->currentEntryInfo.completeBaseName();
+}
+
+QString QDirListing::DirEntry::suffix() const
+{
+ return dirListPtr->currentEntryInfo.suffix();
+}
+
+QString QDirListing::DirEntry::bundleName() const
+{
+ return dirListPtr->currentEntryInfo.bundleName();
+}
+
+QString QDirListing::DirEntry::completeSuffix() const
+{
+ return dirListPtr->currentEntryInfo.completeSuffix();
+}
+
+QString QDirListing::DirEntry::filePath() const
+{
+ return dirListPtr->currentEntryInfo.filePath();
+}
+
+QString QDirListing::DirEntry::canonicalFilePath() const
+{
+ return dirListPtr->currentEntryInfo.canonicalFilePath();
+}
+
+QString QDirListing::DirEntry::absoluteFilePath() const
+{
+ return dirListPtr->currentEntryInfo.absoluteFilePath();
+}
+
+QString QDirListing::DirEntry::absolutePath() const
+{
+ return dirListPtr->currentEntryInfo.absolutePath();
+}
+
+bool QDirListing::DirEntry::isDir() const
+{
+ return dirListPtr->currentEntryInfo.isDir();
+}
+
+bool QDirListing::DirEntry::isFile() const
+{
+ return dirListPtr->currentEntryInfo.isFile();
+}
+
+bool QDirListing::DirEntry::isSymLink() const
+{
+ return dirListPtr->currentEntryInfo.isSymLink();
+}
+
+bool QDirListing::DirEntry::exists() const
+{
+ return dirListPtr->currentEntryInfo.exists();
+}
+
+bool QDirListing::DirEntry::isHidden() const
+{
+ return dirListPtr->currentEntryInfo.isHidden();
+}
+
+bool QDirListing::DirEntry::isReadable() const
+{
+ return dirListPtr->currentEntryInfo.isReadable();
+}
+
+bool QDirListing::DirEntry::isWritable() const
+{
+ return dirListPtr->currentEntryInfo.isWritable();
+}
+
+bool QDirListing::DirEntry::isExecutable() const
+{
+ return dirListPtr->currentEntryInfo.isExecutable();
+}
+
+qint64 QDirListing::DirEntry::size() const
+{
+ return dirListPtr->currentEntryInfo.size();
+}
+
+QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
+{
+ return dirListPtr->currentEntryInfo.fileTime(type, tz);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qdirlisting.h b/src/corelib/io/qdirlisting.h
new file mode 100644
index 0000000000..d19fe3c666
--- /dev/null
+++ b/src/corelib/io/qdirlisting.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDILISTING_H
+#define QDILISTING_H
+
+#include <QtCore/qdir.h>
+
+#include <iterator>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QDirListingPrivate;
+
+class Q_CORE_EXPORT QDirListing
+{
+public:
+ enum class IteratorFlag {
+ NoFlag = 0x0,
+ FollowSymlinks = 0x1,
+ Recursive = 0x2
+ };
+ Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
+
+ QDirListing(const QDir &dir, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, QDir::Filters filter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+
+ ~QDirListing();
+
+ QString iteratorPath() const;
+
+ class Q_CORE_EXPORT DirEntry
+ {
+ friend class QDirListing;
+ QDirListingPrivate *dirListPtr = nullptr;
+ public:
+ QString fileName() const;
+ QString baseName() const;
+ QString completeBaseName() const;
+ QString suffix() const;
+ QString bundleName() const;
+ QString completeSuffix() const;
+ QString filePath() const;
+ bool isDir() const;
+ bool isFile() const;
+ bool isSymLink() const;
+ bool exists() const;
+ bool isHidden() const;
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isExecutable() const;
+ QFileInfo fileInfo() const;
+ QString canonicalFilePath() const;
+ QString absoluteFilePath() const;
+ QString absolutePath() const;
+ qint64 size() const;
+
+ QDateTime birthTime(const QTimeZone &tz) const { return fileTime(QFile::FileBirthTime, tz); }
+ QDateTime metadataChangeTime(const QTimeZone &tz) const { return fileTime(QFile::FileMetadataChangeTime, tz); }
+ QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); }
+ QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); }
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz) const;
+ };
+
+ class const_iterator
+ {
+ friend class QDirListing;
+ const_iterator(QDirListingPrivate *dp) : dirListPtr(dp) { dirEntry.dirListPtr = dp; }
+ QDirListingPrivate *dirListPtr = nullptr;
+ DirEntry dirEntry;
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = DirEntry;
+ using difference_type = qint64;
+ using pointer = const value_type *;
+ using reference = const value_type &;
+
+ const_iterator() = default;
+ reference operator*() const { return dirEntry; }
+ pointer operator->() const { return &dirEntry; }
+ Q_CORE_EXPORT const_iterator &operator++();
+ const_iterator operator++(int) { auto tmp = *this; operator++(); return tmp; };
+ friend bool operator==(const const_iterator &lhs, const const_iterator &rhs)
+ {
+ // This is only used for the sentinel end iterator
+ return lhs.dirListPtr == nullptr && rhs.dirListPtr == nullptr;
+ }
+ friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs)
+ { return !(lhs == rhs); }
+ };
+
+ const_iterator begin() const;
+ const_iterator cbegin() const { return begin(); }
+ const_iterator end() const { return {}; }
+ const_iterator cend() const { return end(); }
+
+ // Qt compatibility
+ const_iterator constBegin() const { return begin(); }
+ const_iterator constEnd() const { return end(); }
+
+private:
+ Q_DISABLE_COPY(QDirListing)
+
+ std::unique_ptr<QDirListingPrivate> d;
+ friend class QDir;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirListing::IteratorFlags)
+
+QT_END_NAMESPACE
+
+#endif // QDILISTING_H
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index 2329613f45..52188dde51 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qdebug.h"
@@ -61,6 +25,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_DECL_COLD_FUNCTION
static bool file_already_open(QFile &file, const char *where = nullptr)
{
@@ -110,7 +76,7 @@ QFilePrivate::openExternalFile(QIODevice::OpenMode flags, FILE *fh, QFile::FileH
QAbstractFileEngine *QFilePrivate::engine() const
{
if (!fileEngine)
- fileEngine.reset(QAbstractFileEngine::create(fileName));
+ fileEngine = QAbstractFileEngine::create(fileName);
return fileEngine.get();
}
@@ -184,13 +150,20 @@ QAbstractFileEngine *QFilePrivate::engine() const
data and operator>>() to read it back. See the class
documentation for details.
- When you use QFile, QFileInfo, and QDir to access the file system
- with Qt, you can use Unicode file names. On Unix, these file
- names are converted to an 8-bit encoding. If you want to use
- standard C++ APIs (\c <cstdio> or \c <iostream>) or
- platform-specific APIs to access files instead of QFile, you can
- use the encodeName() and decodeName() functions to convert
- between Unicode file names and 8-bit file names.
+ \section1 Signals
+
+ Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
+ emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
+ implementation detail means that QFile is not suitable for reading and
+ writing certain types of files, such as device files on Unix platforms.
+
+ \section1 Platform Specific Issues
+
+ \l{Input/Output and Networking}{Qt APIs related to I/O} use UTF-16 based
+ QStrings to represent file paths. Standard C++ APIs (\c <cstdio> or
+ \c <iostream>) or platform-specific APIs however often need a 8-bit encoded
+ path. You can use encodeName() and decodeName() to convert between both
+ representations.
On Unix, there are some special system files (e.g. in \c /proc) for which
size() will always return 0, yet you may still be able to read more data
@@ -203,15 +176,6 @@ QAbstractFileEngine *QFilePrivate::engine() const
\snippet file/file.cpp 3
- \section1 Signals
-
- Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
- emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
- implementation detail means that QFile is not suitable for reading and
- writing certain types of files, such as device files on Unix platforms.
-
- \section1 Platform Specific Issues
-
File permissions are handled differently on Unix-like systems and
Windows. In a non \l{QIODevice::isWritable()}{writable}
directory on Unix-like systems, files cannot be created. This is not always
@@ -226,6 +190,8 @@ QAbstractFileEngine *QFilePrivate::engine() const
function mostly useless for NTFS volumes. It may still be of use for USB
sticks that use VFAT file systems. POSIX ACLs are not manipulated, either.
+ \include android-content-uri-limitations.qdocinc
+
\sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
*/
@@ -260,6 +226,15 @@ QFile::QFile(QObject *parent)
}
/*!
Constructs a new file object to represent the file with the given \a name.
+
+//! [qfile-explicit-constructor-note]
+ \note In versions up to and including Qt 6.8, this constructor is
+ implicit, for backward compatibility. Starting from Qt 6.9 this
+ constructor is unconditionally \c{explicit}. Users can force this
+ constructor to be \c{explicit} even in earlier versions of Qt by
+ defining the \c{QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH} macro
+ before including any Qt header.
+//! [qfile-explicit-constructor-note]
*/
QFile::QFile(const QString &name)
: QFileDevice(*new QFilePrivate, nullptr)
@@ -347,10 +322,10 @@ QFile::setFileName(const QString &name)
/*!
\fn QByteArray QFile::encodeName(const QString &fileName)
- Converts \a fileName to the local 8-bit
- encoding determined by the user's locale. This is sufficient for
- file names that the user chooses. File names hard-coded into the
- application should only use 7-bit ASCII filename characters.
+ Converts \a fileName to an 8-bit encoding that you can use in native
+ APIs. On Windows, the encoding is the one from active Windows (ANSI)
+ codepage. On other platforms, this is UTF-8, for \macos in decomposed
+ form (NFD).
\sa decodeName()
*/
@@ -484,6 +459,24 @@ QFile::remove(const QString &fileName)
and sets the fileName() to the path at which the file can be found within the trash;
otherwise returns \c false.
+//! [move-to-trash-common]
+ The time for this function to run is independent of the size of the file
+ being trashed. If this function is called on a directory, it may be
+ proportional to the number of files being trashed.
+
+ This function uses the Windows and \macos APIs to perform the trashing on
+ those two operating systems. Elsewhere (Unix systems), this function
+ implements the \l{FreeDesktop.org Trash specification version 1.0}.
+
+ \note When using the FreeDesktop.org Trash implementation, this function
+ will fail if it is unable to move the files to the trash location by way of
+ file renames and hardlinks. This condition arises if the file being trashed
+ resides on a volume (mount point) on which the current user does not have
+ permission to create the \c{.Trash} directory, or with some unusual
+ filesystem types or configurations (such as sub-volumes that aren't
+ themselves mount points).
+//! [move-to-trash-common]
+
\note On systems where the system API doesn't report the location of the file in the
trash, fileName() will be set to the null string once the file has been moved. On
systems that don't have a trash can, this function always returns false.
@@ -521,9 +514,12 @@ QFile::moveToTrash()
and sets \a pathInTrash (if provided) to the path at which the file can be found within
the trash; otherwise returns \c false.
+ \include qfile.cpp move-to-trash-common
+
\note On systems where the system API doesn't report the path of the file in the
trash, \a pathInTrash will be set to the null string once the file has been moved.
On systems that don't have a trash can, this function always returns false.
+
*/
bool
QFile::moveToTrash(const QString &fileName, QString *pathInTrash)
@@ -588,7 +584,7 @@ QFile::rename(const QString &newName)
return false;
}
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) && QT_CONFIG(temporaryfile)
// rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
// FS, such as FAT32. Move the file away and rename in 2 steps to work around.
QTemporaryFileName tfn(d->fileName);
@@ -616,7 +612,7 @@ QFile::rename(const QString &newName)
// report both errors
d->setError(QFile::RenameError,
tr("Error while renaming: %1").arg(error.toString())
- + QLatin1Char('\n')
+ + u'\n'
+ tr("Unable to restore from %1: %2").
arg(QDir::toNativeSeparators(tmp.filePath()), error2.toString()));
return false;
@@ -759,6 +755,9 @@ QFile::link(const QString &fileName, const QString &linkName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa setFileName()
*/
@@ -789,8 +788,8 @@ QFile::copy(const QString &newName)
error = true;
d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
} else {
- const auto fileTemplate = QLatin1String("%1/qt_temp.XXXXXX");
-#ifdef QT_NO_TEMPORARYFILE
+ const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1;
+#if !QT_CONFIG(temporaryfile)
QFile out(fileTemplate.arg(QFileInfo(newName).path()));
if (!out.open(QIODevice::ReadWrite))
error = true;
@@ -803,9 +802,9 @@ QFile::copy(const QString &newName)
}
#endif
if (error) {
+ d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
out.close();
close();
- d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
} else {
if (!d->engine()->cloneTo(out.d_func()->engine())) {
char block[4096];
@@ -817,7 +816,8 @@ QFile::copy(const QString &newName)
totalRead += in;
if (in != out.write(block, in)) {
close();
- d->setError(QFile::CopyError, tr("Failure to write block"));
+ d->setError(QFile::CopyError, tr("Failure to write block: %1")
+ .arg(out.errorString()));
error = true;
break;
}
@@ -837,10 +837,11 @@ QFile::copy(const QString &newName)
if (!out.rename(newName)) {
error = true;
close();
- d->setError(QFile::CopyError, tr("Cannot create %1 for output").arg(newName));
+ d->setError(QFile::CopyError, tr("Cannot create %1 for output: %2")
+ .arg(newName, out.errorString()));
}
}
-#ifdef QT_NO_TEMPORARYFILE
+#if !QT_CONFIG(temporaryfile)
if (error)
out.remove();
#else
@@ -867,6 +868,9 @@ QFile::copy(const QString &newName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa rename()
*/
@@ -889,6 +893,11 @@ QFile::copy(const QString &fileName, const QString &newName)
will try to create a new file before opening it. The file will be
created with mode 0666 masked by the umask on POSIX systems, and
with permissions inherited from the parent directory on Windows.
+ On Android, it's expected to have access permission to the parent
+ of the file name, otherwise, it won't be possible to create this
+ non-existing file.
+
+ \sa QT_USE_NODISCARD_FILE_OPEN
\sa QIODevice::OpenMode, setFileName()
*/
@@ -934,7 +943,7 @@ bool QFile::open(OpenMode mode)
such permissions will generate warnings when the Security tab of the Properties dialog
is opened. Granting the group all permissions granted to others avoids such warnings.
- \sa QIODevice::OpenMode, setFileName()
+ \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN
\since 6.3
*/
bool QFile::open(OpenMode mode, QFile::Permissions permissions)
@@ -991,7 +1000,7 @@ bool QFile::open(OpenMode mode, QFile::Permissions permissions)
you cannot use this QFile with a QFileInfo.
\endlist
- \sa close()
+ \sa close(), QT_USE_NODISCARD_FILE_OPEN
\b{Note for the Windows Platform}
@@ -1057,7 +1066,7 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
\warning Since this function opens the file without specifying the file name,
you cannot use this QFile with a QFileInfo.
- \sa close()
+ \sa close(), QT_USE_NODISCARD_FILE_OPEN
*/
bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
{
@@ -1177,6 +1186,8 @@ qint64 QFile::size() const
\since 6.0
Constructs a new file object to represent the file with the given \a name.
+
+ \include qfile.cpp qfile-explicit-constructor-note
*/
/*!
\fn QFile::QFile(const std::filesystem::path &name, QObject *parent)
@@ -1262,6 +1273,107 @@ qint64 QFile::size() const
*/
+/*!
+ \class QNtfsPermissionCheckGuard
+ \since 6.6
+ \inmodule QtCore
+ \brief The QNtfsPermissionCheckGuard class is a RAII class to manage NTFS
+ permission checking.
+
+ \ingroup io
+
+ For performance reasons, QFile, QFileInfo, and related classes do not
+ perform full ownership and permission (ACL) checking on NTFS file systems
+ by default. During the lifetime of any instance of this class, that
+ default is overridden and advanced checking is performed. This provides
+ a safe and easy way to manage enabling and disabling this change to the
+ default behavior.
+
+ Example:
+
+ \snippet ntfsp.cpp raii
+
+ This class is available only on Windows.
+
+ \section1 qt_ntfs_permission_lookup
+
+ Prior to Qt 6.6, the user had to directly manipulate the global variable
+ \c qt_ntfs_permission_lookup. However, this was a non-atomic global
+ variable and as such it was prone to data races.
+
+ The variable \c qt_ntfs_permission_lookup is therefore deprecated since Qt
+ 6.6.
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::QNtfsPermissionCheckGuard()
+
+ Creates a guard and calls the function qEnableNtfsPermissionChecks().
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::~QNtfsPermissionCheckGuard()
+
+ Destroys the guard and calls the function qDisableNtfsPermissionChecks().
+*/
+
+
+/*!
+ \fn bool qEnableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Enables permission checking on NTFS file systems. Returns \c true if the check
+ was already enabled before the call to this function, meaning that there
+ are other users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function, please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qDisableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Disables permission checking on NTFS file systems. Returns \c true if the
+ check is disabled, meaning that there are no more users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function and must (only) be called to match one earlier
+ call to qEnableNtfsPermissionChecks(). Please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qAreNtfsPermissionChecksEnabled()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Checks the status of the permission checks on NTFS file systems. Returns
+ \c true if the check is enabled.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h
index 71246751fe..058b2fa236 100644
--- a/src/corelib/io/qfile.h
+++ b/src/corelib/io/qfile.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILE_H
#define QFILE_H
@@ -47,7 +11,7 @@
#if QT_CONFIG(cxx17_filesystem)
#include <filesystem>
-#elif defined(Q_CLANG_QDOC)
+#elif defined(Q_QDOC)
namespace std {
namespace filesystem {
class path {
@@ -62,6 +26,34 @@ namespace std {
QT_BEGIN_NAMESPACE
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+
+#if QT_DEPRECATED_SINCE(6,6)
+QT_DEPRECATED_VERSION_X_6_6("Use QNtfsPermissionCheckGuard RAII class instead.")
+Q_CORE_EXPORT extern int qt_ntfs_permission_lookup; // defined in qfilesystemengine_win.cpp
+#endif
+
+Q_CORE_EXPORT bool qEnableNtfsPermissionChecks() noexcept;
+Q_CORE_EXPORT bool qDisableNtfsPermissionChecks() noexcept;
+Q_CORE_EXPORT bool qAreNtfsPermissionChecksEnabled() noexcept;
+
+class QNtfsPermissionCheckGuard
+{
+ Q_DISABLE_COPY_MOVE(QNtfsPermissionCheckGuard)
+public:
+ Q_NODISCARD_CTOR
+ QNtfsPermissionCheckGuard()
+ {
+ qEnableNtfsPermissionChecks();
+ }
+
+ ~QNtfsPermissionCheckGuard()
+ {
+ qDisableNtfsPermissionChecks();
+ }
+};
+#endif // Q_OS_WIN
+
#if QT_CONFIG(cxx17_filesystem)
namespace QtPrivate {
inline QString fromFilesystemPath(const std::filesystem::path &path)
@@ -90,6 +82,13 @@ using ForceFilesystemPath = typename std::enable_if_t<std::is_same_v<std::filesy
class QTemporaryFile;
class QFilePrivate;
+// ### Qt 7: remove this, and make constructors always explicit.
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)) || defined(QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH)
+# define QFILE_MAYBE_EXPLICIT explicit
+#else
+# define QFILE_MAYBE_EXPLICIT Q_IMPLICIT
+#endif
+
class Q_CORE_EXPORT QFile : public QFileDevice
{
#ifndef QT_NO_QOBJECT
@@ -99,12 +98,12 @@ class Q_CORE_EXPORT QFile : public QFileDevice
public:
QFile();
- QFile(const QString &name);
-#ifdef Q_CLANG_QDOC
- QFile(const std::filesystem::path &name);
+ QFILE_MAYBE_EXPLICIT QFile(const QString &name);
+#ifdef Q_QDOC
+ QFILE_MAYBE_EXPLICIT QFile(const std::filesystem::path &name);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
- QFile(const T &name) : QFile(QtPrivate::fromFilesystemPath(name))
+ QFILE_MAYBE_EXPLICIT QFile(const T &name) : QFile(QtPrivate::fromFilesystemPath(name))
{
}
#endif // QT_CONFIG(cxx17_filesystem)
@@ -113,7 +112,7 @@ public:
explicit QFile(QObject *parent);
QFile(const QString &name, QObject *parent);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
QFile(const std::filesystem::path &path, QObject *parent);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -125,12 +124,12 @@ public:
~QFile();
QString fileName() const override;
-#if QT_CONFIG(cxx17_filesystem) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
std::filesystem::path filesystemFileName() const
{ return QtPrivate::toFilesystemPath(fileName()); }
#endif
void setFileName(const QString &name);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
void setFileName(const std::filesystem::path &name);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -172,7 +171,7 @@ public:
bool exists() const;
static bool exists(const QString &fileName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
static bool exists(const std::filesystem::path &fileName);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -184,7 +183,7 @@ public:
QString symLinkTarget() const;
static QString symLinkTarget(const QString &fileName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
std::filesystem::path filesystemSymLinkTarget() const;
static std::filesystem::path filesystemSymLinkTarget(const std::filesystem::path &fileName);
#elif QT_CONFIG(cxx17_filesystem)
@@ -201,7 +200,7 @@ public:
bool remove();
static bool remove(const QString &fileName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
static bool remove(const std::filesystem::path &fileName);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -213,7 +212,7 @@ public:
bool moveToTrash();
static bool moveToTrash(const QString &fileName, QString *pathInTrash = nullptr);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
static bool moveToTrash(const std::filesystem::path &fileName, QString *pathInTrash = nullptr);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -225,7 +224,7 @@ public:
bool rename(const QString &newName);
static bool rename(const QString &oldName, const QString &newName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
bool rename(const std::filesystem::path &newName);
static bool rename(const std::filesystem::path &oldName,
const std::filesystem::path &newName);
@@ -245,7 +244,7 @@ public:
bool link(const QString &newName);
static bool link(const QString &fileName, const QString &newName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
bool link(const std::filesystem::path &newName);
static bool link(const std::filesystem::path &fileName,
const std::filesystem::path &newName);
@@ -265,7 +264,7 @@ public:
bool copy(const QString &newName);
static bool copy(const QString &fileName, const QString &newName);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
bool copy(const std::filesystem::path &newName);
static bool copy(const std::filesystem::path &fileName,
const std::filesystem::path &newName);
@@ -283,10 +282,10 @@ public:
}
#endif // QT_CONFIG(cxx17_filesystem)
- bool open(OpenMode flags) override;
- bool open(OpenMode flags, Permissions permissions);
- bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
- bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override;
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags, Permissions permissions);
+ QFILE_MAYBE_NODISCARD bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
+ QFILE_MAYBE_NODISCARD bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
qint64 size() const override;
@@ -297,7 +296,7 @@ public:
static Permissions permissions(const QString &filename);
bool setPermissions(Permissions permissionSpec) override;
static bool setPermissions(const QString &filename, Permissions permissionSpec);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
static Permissions permissions(const std::filesystem::path &filename);
static bool setPermissions(const std::filesystem::path &filename, Permissions permissionSpec);
#elif QT_CONFIG(cxx17_filesystem)
diff --git a/src/corelib/io/qfile_p.h b/src/corelib/io/qfile_p.h
index d866b8e8a2..e4e305309a 100644
--- a/src/corelib/io/qfile_p.h
+++ b/src/corelib/io/qfile_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILE_P_H
#define QFILE_P_H
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index ff8de7c0bb..431dc65f5b 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qfiledevice.h"
@@ -125,9 +89,9 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
\value ReadGroup The file is readable by the group.
\value WriteGroup The file is writable by the group.
\value ExeGroup The file is executable by the group.
- \value ReadOther The file is readable by anyone.
- \value WriteOther The file is writable by anyone.
- \value ExeOther The file is executable by anyone.
+ \value ReadOther The file is readable by others.
+ \value WriteOther The file is writable by others.
+ \value ExeOther The file is executable by others.
\warning Because of differences in the platforms supported by Qt,
the semantics of ReadUser, WriteUser and ExeUser are
@@ -145,6 +109,25 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
decrementing \c qt_ntfs_permission_lookup by 1.
\snippet ntfsp.cpp 1
+
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
+
+ \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is
+ deprecated. Please use the following alternatives.
+
+ The safe and easy way to manage permission checks is to use the RAII class
+ \c QNtfsPermissionCheckGuard.
+
+ \snippet ntfsp.cpp raii
+
+ If you need more fine-grained control, it is possible to manage the permission
+ with the following functions instead:
+
+ \snippet ntfsp.cpp free-funcs
+
*/
//************* QFileDevice
@@ -163,10 +146,10 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
QFileDevice is the base class for I/O devices that can read and write text and binary files
and \l{The Qt Resource System}{resources}. QFile offers the main functionality,
QFileDevice serves as a base class for sharing functionality with other file devices such
- as QTemporaryFile, by providing all the operations that can be done on files that have
- been opened by QFile or QTemporaryFile.
+ as QSaveFile, by providing all the operations that can be done on files that have
+ been opened by QFile or QSaveFile.
- \sa QFile, QTemporaryFile
+ \sa QFile, QSaveFile
*/
/*!
@@ -185,6 +168,35 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
handle is left open when the QFile object is destroyed.
*/
+/*!
+ \macro QT_USE_NODISCARD_FILE_OPEN
+ \macro QT_NO_USE_NODISCARD_FILE_OPEN
+ \relates QFileDevice
+ \since 6.8
+
+ File-related I/O classes (such as QFile, QSaveFile, QTemporaryFile)
+ have an \c{open()} method to open the file they act upon. It is
+ important to check the return value of the call to \c{open()}
+ before proceeding with reading or writing data into the file.
+
+ For this reason, starting with Qt 6.8, some overloads of \c{open()}
+ have been marked with the \c{[[nodiscard]]} attribute. Since this
+ change may raise warnings in existing codebases, user code can
+ opt-in or opt-out from having the attribute applied by defining
+ certain macros:
+
+ \list
+ \li If the \c{QT_USE_NODISCARD_FILE_OPEN} macro is defined,
+ overloads of \c{open()} are marked as \c{[[nodiscard]]}.
+ \li If the \c{QT_NO_USE_NODISCARD_FILE_OPEN} is defined, the
+ overloads of \c{open()} are \e{not} marked as \c{[[nodiscard]]}.
+ \li If neither macro is defined, then the default up to and
+ including Qt 6.9 is not to have the attribute. Starting from Qt 6.10,
+ the attribute is automatically applied.
+ \li If both macros are defined, the program is ill-formed.
+ \endlist
+*/
+
#ifdef QT_NO_QOBJECT
QFileDevice::QFileDevice()
: QIODevice(*new QFileDevicePrivate)
@@ -751,15 +763,6 @@ bool QFileDevice::unmap(uchar *address)
\sa setFileTime(), fileTime(), QFileInfo::fileTime()
*/
-static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
-{
- static_assert(int(QFileDevice::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
- static_assert(int(QFileDevice::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
- static_assert(int(QFileDevice::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
- static_assert(int(QFileDevice::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
- return QAbstractFileEngine::FileTime(time);
-}
-
/*!
\since 5.10
Returns the file time specified by \a time.
@@ -773,7 +776,7 @@ QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const
Q_D(const QFileDevice);
if (d->engine())
- return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time));
+ return d->engine()->fileTime(time);
return QDateTime();
}
@@ -796,7 +799,7 @@ bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fi
return false;
}
- if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) {
+ if (!d->fileEngine->setFileTime(newDate, fileTime)) {
d->setError(d->fileEngine->error(), d->fileEngine->errorString());
return false;
}
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index e6546a7eb8..5274025715 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILEDEVICE_H
#define QFILEDEVICE_H
@@ -48,6 +12,22 @@ QT_BEGIN_NAMESPACE
class QDateTime;
class QFileDevicePrivate;
+#if !defined(QT_USE_NODISCARD_FILE_OPEN) && !defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+# if QT_VERSION < QT_VERSION_CHECK(6, 10, 0)
+# define QT_NO_USE_NODISCARD_FILE_OPEN
+# else
+# define QT_USE_NODISCARD_FILE_OPEN
+# endif
+#endif
+
+#if defined(QT_USE_NODISCARD_FILE_OPEN) && defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+#error "Inconsistent macro definition for nodiscard QFile::open"
+#elif defined(QT_USE_NODISCARD_FILE_OPEN)
+#define QFILE_MAYBE_NODISCARD [[nodiscard]]
+#else /* QT_NO_USE_NODISCARD_FILE_OPEN */
+#define QFILE_MAYBE_NODISCARD
+#endif
+
class Q_CORE_EXPORT QFileDevice : public QIODevice
{
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfiledevice_p.h b/src/corelib/io/qfiledevice_p.h
index 2b97773c2f..72b43ed5a1 100644
--- a/src/corelib/io/qfiledevice_p.h
+++ b/src/corelib/io/qfiledevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILEDEVICE_P_H
#define QFILEDEVICE_P_H
@@ -62,6 +26,11 @@
# include <qt_windows.h>
# include <winnt.h> // for SECURITY_DESCRIPTOR
# include <optional>
+# if defined(QT_BOOTSTRAPPED)
+# define QT_FEATURE_fslibs -1
+# else
+# define QT_FEATURE_fslibs 1
+# endif // QT_BOOTSTRAPPED
#endif
QT_BEGIN_NAMESPACE
@@ -155,9 +124,11 @@ private:
static constexpr auto MaxACLSize =
sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) + SECURITY_MAX_SID_SIZE) * MaxNumACEs;
- SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
+#if QT_CONFIG(fslibs)
+ SECURITY_DESCRIPTOR sd;
alignas(DWORD) char aclStorage[MaxACLSize];
+#endif
};
#endif // Q_OS_UNIX
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index dcbfae0d3f..6bc0128aff 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qfileinfo.h"
@@ -46,6 +10,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QT_IMPL_METATYPE_EXTERN(QFileInfo)
QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
@@ -72,6 +38,9 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
case QAbstractFileEngine::AbsoluteLinkTarget:
ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
break;
+ case QAbstractFileEngine::RawLinkPath:
+ ret = QFileSystemEngine::getRawLinkPath(fileEntry, metaData).filePath();
+ break;
case QAbstractFileEngine::JunctionName:
ret = QFileSystemEngine::getJunctionTarget(fileEntry, metaData).filePath();
break;
@@ -97,7 +66,7 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
ret = fileEngine->fileName(name);
}
if (ret.isNull())
- ret = QLatin1String("");
+ ret = ""_L1;
if (cache_enabled)
fileNames[(int)name] = ret;
return ret;
@@ -121,7 +90,7 @@ QString QFileInfoPrivate::getFileOwner(QAbstractFileEngine::FileOwner own) const
ret = fileEngine->owner(own);
}
if (ret.isNull())
- ret = QLatin1String("");
+ ret = ""_L1;
if (cache_enabled)
fileOwners[(int)own] = ret;
return ret;
@@ -188,7 +157,7 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons
return fileFlags & request.toInt();
}
-QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const
+QDateTime &QFileInfoPrivate::getFileTime(QFile::FileTime request) const
{
Q_ASSERT(fileEngine); // should never be called when using the native FS
if (!cache_enabled)
@@ -196,16 +165,16 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
uint cf = 0;
switch (request) {
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
cf = CachedATime;
break;
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
cf = CachedBTime;
break;
- case QAbstractFileEngine::MetadataChangeTime:
+ case QFile::FileMetadataChangeTime:
cf = CachedMCTime;
break;
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
cf = CachedMTime;
break;
}
@@ -223,72 +192,84 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\class QFileInfo
\inmodule QtCore
\reentrant
- \brief The QFileInfo class provides system-independent file information.
+ \brief The QFileInfo class provides an OS-independent API to retrieve
+ information about file system entries.
\ingroup io
\ingroup shared
- QFileInfo provides information about a file's name and position
- (path) in the file system, its access rights and whether it is a
- directory or symbolic link, etc. The file's size and last
- modified/read times are also available. QFileInfo can also be
- used to obtain information about a Qt \l{resource
- system}{resource}.
-
- A QFileInfo can point to a file with either a relative or an
- absolute file path. Absolute file paths begin with the directory
- separator "/" (or with a drive specification on Windows). Relative
- file names begin with a directory name or a file name and specify
- a path relative to the current working directory. An example of an
- absolute path is the string "/tmp/quartz". A relative path might
- look like "src/fatlib". You can use the function isRelative() to
- check whether a QFileInfo is using a relative or an absolute file
- path. You can call the function makeAbsolute() to convert a
- relative QFileInfo's path to an absolute path.
+ \compares equality
+
+ QFileInfo provides information about a file system entry, such as its
+ name, path, access rights and whether it is a regular file, directory or
+ symbolic link. The entry's size and last modified/read times are also
+ available. QFileInfo can also be used to obtain information about a Qt
+ \l{resource system}{resource}.
+
+ A QFileInfo can point to a file system entry with either an absolute or
+ a relative path:
+ \list
+ \li \include qfileinfo.cpp absolute-path-unix-windows
+ \li \include qfileinfo.cpp relative-path-note
+ \endlist
+
+ An example of an absolute path is the string \c {"/tmp/quartz"}. A relative
+ path may look like \c {"src/fatlib"}. You can use the function isRelative()
+ to check whether a QFileInfo is using a relative or an absolute path. You
+ can call the function makeAbsolute() to convert a relative QFileInfo's
+ path to an absolute path.
+
+//! [qresource-virtual-fs-colon]
\note Paths starting with a colon (\e{:}) are always considered
absolute, as they denote a QResource.
+//! [qresource-virtual-fs-colon]
+
+ The file system entry path that the QFileInfo works on is set in the
+ constructor or later with setFile(). Use exists() to see if the entry
+ actually exists and size() to get its size.
+
+ The file system entry's type is obtained with isFile(), isDir(), and
+ isSymLink(). The symLinkTarget() function provides the absolute path of
+ the target the symlink points to.
+
+ The path elements of the file system entry can be extracted with path()
+ and fileName(). The fileName()'s parts can be extracted with baseName(),
+ suffix(), or completeSuffix(). QFileInfo objects referring to directories
+ created by Qt classes will not have a trailing directory separator
+ \c{'/'}. If you wish to use trailing separators in your own file info
+ objects, just append one to the entry's path given to the constructors
+ or setFile().
- The file that the QFileInfo works on is set in the constructor or
- later with setFile(). Use exists() to see if the file exists and
- size() to get its size.
+ Date and time related information are returned by birthTime(), fileTime(),
+ lastModified(), lastRead(), and metadataChangeTime().
+ Information about
+ access permissions can be obtained with isReadable(), isWritable(), and
+ isExecutable(). Ownership information can be obtained with
+ owner(), ownerId(), group(), and groupId(). You can also examine
+ permissions and ownership in a single statement using the permission()
+ function.
- The file's type is obtained with isFile(), isDir() and
- isSymLink(). The symLinkTarget() function provides the name of the file
- the symlink points to.
+ \section1 Symbolic Links and Shortcuts
- On Unix (including \macos and iOS), the property getter functions in this
- class return the properties such as times and size of the target file, not
- the symlink, because Unix handles symlinks transparently. Opening a symlink
- using QFile effectively opens the link's target. For example:
+ On Unix (including \macos and iOS), the property getter functions in
+ this class return the properties such as times and size of the target,
+ not the symlink, because Unix handles symlinks transparently. Opening
+ a symlink using QFile effectively opens the link's target. For example:
\snippet code/src_corelib_io_qfileinfo.cpp 0
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
- on Unix systems, the property getters return the size of the targeted file,
- not the \c .lnk file itself. This behavior is deprecated and will likely be
- removed in a future version of Qt, after which \c .lnk files will be treated
- as regular files.
+ on Unix systems, the property getters return the size of the target,
+ not the \c .lnk file itself. This behavior is deprecated and will likely
+ be removed in a future version of Qt, after which \c .lnk files will be
+ treated as regular files.
\snippet code/src_corelib_io_qfileinfo.cpp 1
- Elements of the file's name can be extracted with path() and
- fileName(). The fileName()'s parts can be extracted with
- baseName(), suffix() or completeSuffix(). QFileInfo objects to
- directories created by Qt classes will not have a trailing file
- separator. If you wish to use trailing separators in your own file
- info objects, just append one to the file name given to the constructors
- or setFile().
-
- The file's dates are returned by birthTime(), lastModified(), lastRead() and
- fileTime(). Information about the file's access permissions is
- obtained with isReadable(), isWritable() and isExecutable(). The
- file's ownership is available from owner(), ownerId(), group() and
- groupId(). You can examine a file's permissions and ownership in a
- single statement using the permission() function.
+ \section1 NTFS permissions
- \target NTFS permissions
- \note On NTFS file systems, ownership and permissions checking is
+ On NTFS file systems, ownership and permissions checking is
disabled by default for performance reasons. To enable it,
include the following line:
@@ -299,25 +280,54 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\snippet ntfsp.cpp 1
- \section1 Performance Issues
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
+
+ \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is
+ deprecated. Please use the following alternatives.
+
+ The safe and easy way to manage permission checks is to use the RAII class
+ \c QNtfsPermissionCheckGuard.
+
+ \snippet ntfsp.cpp raii
- Some of QFileInfo's functions query the file system, but for
- performance reasons, some functions only operate on the
- file name itself. For example: To return the absolute path of
- a relative file name, absolutePath() has to query the file system.
- The path() function, however, can work on the file name directly,
- and so it is faster.
+ If you need more fine-grained control, it is possible to manage the permission
+ with the following functions instead:
- \note To speed up performance, QFileInfo caches information about
- the file.
+ \snippet ntfsp.cpp free-funcs
- Because files can be changed by other users or programs, or
- even by other parts of the same program, there is a function that
- refreshes the file information: refresh(). If you want to switch
- off a QFileInfo's caching and force it to access the file system
- every time you request information from it call setCaching(false).
- If you want to make sure that all information is read from the
- file system, use stat().
+ \section1 Performance Considerations
+
+ Some of QFileInfo's functions have to query the file system, but for
+ performance reasons, some functions only operate on the path string.
+ For example: To return the absolute path of a relative entry's path,
+ absolutePath() has to query the file system. The path() function, however,
+ can work on the file name directly, and so it is faster.
+
+ QFileInfo also caches information about the file system entry it refers
+ to. Because the file system can be changed by other users or programs,
+ or even by other parts of the same program, there is a function that
+ refreshes the information stored in QFileInfo, namely refresh(). To switch
+ off a QFileInfo's caching (that is, force it to query the underlying file
+ system every time you request information from it), call setCaching(false).
+
+ Fetching information from the file system is typically done by calling
+ (possibly) expensive system functions, so QFileInfo (depending on the
+ implementation) might not fetch all the information from the file system
+ at construction. To make sure that all information is read from the file
+ system immediately, use the stat() member function.
+
+ \l{birthTime()}, \l{fileTime()}, \l{lastModified()}, \l{lastRead()},
+ and \l{metadataChangeTime()} return times in \e{local time} by default.
+ Since native file system API typically uses UTC, this requires a conversion.
+ If you don't actually need the local time, you can avoid this by requesting
+ the time in QTimeZone::UTC directly.
+
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
\sa QDir, QFile
*/
@@ -338,9 +348,8 @@ QFileInfo::QFileInfo(QFileInfoPrivate *p) : d_ptr(p)
}
/*!
- Constructs an empty QFileInfo object.
-
- Note that an empty QFileInfo object contain no file reference.
+ Constructs an empty QFileInfo object that doesn't refer to any file
+ system entry.
\sa setFile()
*/
@@ -349,12 +358,16 @@ QFileInfo::QFileInfo() : d_ptr(new QFileInfoPrivate())
}
/*!
- Constructs a new QFileInfo that gives information about the given
- file. The \a file can also include an absolute or relative path.
+ Constructs a QFileInfo that gives information about a file system entry
+ located at \a path that can be absolute or relative.
+
+//! [preserve-relative-path]
+ If \a path is relative, the QFileInfo will also have a relative path.
+//! [preserve-relative-path]
\sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
-QFileInfo::QFileInfo(const QString &file) : d_ptr(new QFileInfoPrivate(file))
+QFileInfo::QFileInfo(const QString &path) : d_ptr(new QFileInfoPrivate(path))
{
}
@@ -373,18 +386,20 @@ QFileInfo::QFileInfo(const QFileDevice &file) : d_ptr(new QFileInfoPrivate(file.
/*!
Constructs a new QFileInfo that gives information about the given
- \a file relative to the directory \a dir.
+ file system entry \a path that is relative to the directory \a dir.
+//! [preserve-relative-or-absolute]
If \a dir has a relative path, the QFileInfo will also have a
relative path.
- If \a file is an absolute path, then the directory specified
- by \a dir will be disregarded.
+ If \a path is absolute, then the directory specified by \a dir
+ will be disregarded.
+//! [preserve-relative-or-absolute]
\sa isRelative()
*/
-QFileInfo::QFileInfo(const QDir &dir, const QString &file)
- : d_ptr(new QFileInfoPrivate(dir.filePath(file)))
+QFileInfo::QFileInfo(const QDir &dir, const QString &path)
+ : d_ptr(new QFileInfoPrivate(dir.filePath(path)))
{
}
@@ -406,58 +421,57 @@ QFileInfo::~QFileInfo()
}
/*!
- \fn bool QFileInfo::operator!=(const QFileInfo &fileinfo) const
+ \fn bool QFileInfo::operator!=(const QFileInfo &lhs, const QFileInfo &rhs)
- Returns \c true if this QFileInfo object refers to a different file
- than the one specified by \a fileinfo; otherwise returns \c false.
+ Returns \c true if QFileInfo \a lhs refers to a different file system
+ entry than the one referred to by \a rhs; otherwise returns \c false.
\sa operator==()
*/
/*!
- Returns \c true if this QFileInfo object refers to a file in the same
- location as \a fileinfo; otherwise returns \c false.
+ \fn bool QFileInfo::operator==(const QFileInfo &lhs, const QFileInfo &rhs)
+
+ Returns \c true if QFileInfo \a lhs and QFileInfo \a rhs refer to the same
+ entry on the file system; otherwise returns \c false.
- Note that the result of comparing two empty QFileInfo objects,
- containing no file references (file paths that do not exist or
- are empty), is undefined.
+ Note that the result of comparing two empty QFileInfo objects, containing
+ no file system entry references (paths that do not exist or are empty),
+ is undefined.
- \warning This will not compare two different symbolic links
- pointing to the same file.
+ \warning This will not compare two different symbolic links pointing to
+ the same target.
- \warning Long and short file names that refer to the same file on Windows
- are treated as if they referred to different files.
+ \warning On Windows, long and short paths that refer to the same file
+ system entry are treated as if they referred to different entries.
\sa operator!=()
*/
-bool QFileInfo::operator==(const QFileInfo &fileinfo) const
+bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
{
- Q_D(const QFileInfo);
- // ### Qt 5: understand long and short file names on Windows
- // ### (GetFullPathName()).
- if (fileinfo.d_ptr == d_ptr)
+ if (rhs.d_ptr == lhs.d_ptr)
return true;
- if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed)
+ if (lhs.d_ptr->isDefaultConstructed || rhs.d_ptr->isDefaultConstructed)
return false;
// Assume files are the same if path is the same
- if (d->fileEntry.filePath() == fileinfo.d_ptr->fileEntry.filePath())
+ if (lhs.d_ptr->fileEntry.filePath() == rhs.d_ptr->fileEntry.filePath())
return true;
Qt::CaseSensitivity sensitive;
- if (d->fileEngine == nullptr || fileinfo.d_ptr->fileEngine == nullptr) {
- if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine
+ if (lhs.d_ptr->fileEngine == nullptr || rhs.d_ptr->fileEngine == nullptr) {
+ if (lhs.d_ptr->fileEngine != rhs.d_ptr->fileEngine) // one is native, the other is a custom file-engine
return false;
sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
} else {
- if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive())
+ if (lhs.d_ptr->fileEngine->caseSensitive() != rhs.d_ptr->fileEngine->caseSensitive())
return false;
- sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ sensitive = lhs.d_ptr->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
}
// Fallback to expensive canonical path computation
- return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0;
+ return lhs.canonicalFilePath().compare(rhs.canonicalFilePath(), sensitive) == 0;
}
/*!
@@ -478,24 +492,30 @@ QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo)
*/
/*!
- Sets the file that the QFileInfo provides information about to \a
- file.
+ Sets the path of the file system entry that this QFileInfo provides
+ information about to \a path that can be absolute or relative.
+
+//! [absolute-path-unix-windows]
+ On Unix, absolute paths begin with the directory separator \c {'/'}.
+ On Windows, absolute paths begin with a drive specification (for example,
+ \c {D:/}).
+//! [ absolute-path-unix-windows]
- The \a file can also include an absolute or relative file path.
- Absolute paths begin with the directory separator (e.g. "/" under
- Unix) or a drive specification (under Windows). Relative file
- names begin with a directory name or a file name and specify a
- path relative to the current directory.
+//! [relative-path-note]
+ Relative paths begin with a directory name or a regular file name and
+ specify a file system entry's path relative to the current working
+ directory.
+//! [relative-path-note]
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 2
\sa isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
-void QFileInfo::setFile(const QString &file)
+void QFileInfo::setFile(const QString &path)
{
bool caching = d_ptr.constData()->cache_enabled;
- *this = QFileInfo(file);
+ *this = QFileInfo(path);
d_ptr->cache_enabled = caching;
}
@@ -518,27 +538,29 @@ void QFileInfo::setFile(const QFileDevice &file)
/*!
\overload
- Sets the file that the QFileInfo provides information about to \a
- file in directory \a dir.
+ Sets the path of the file system entry that this QFileInfo provides
+ information about to \a path in directory \a dir.
- If \a file includes a relative path, the QFileInfo will also
- have a relative path.
+ \include qfileinfo.cpp preserve-relative-or-absolute
\sa isRelative()
*/
-void QFileInfo::setFile(const QDir &dir, const QString &file)
+void QFileInfo::setFile(const QDir &dir, const QString &path)
{
- setFile(dir.filePath(file));
+ setFile(dir.filePath(path));
}
/*!
- Returns an absolute path including the file name.
+ Returns the absolute full path to the file system entry this QFileInfo
+ refers to, including the entry's name.
+
+ \include qfileinfo.cpp absolute-path-unix-windows
+
+//! [windows-network-shares]
+ On Windows, the paths of network shares that are not mapped to a drive
+ letter begin with \c{//sharename/}.
+//! [windows-network-shares]
- The absolute path name consists of the full path and the file
- name. On Unix this will always begin with the root, '/',
- directory. On Windows this will always begin 'D:/' where D is a
- drive letter, except for network shares that are not mapped to a
- drive letter, in which case the path will begin '//sharename/'.
QFileInfo will uppercase drive letters. Note that QDir does not do
this. The code snippet below shows this.
@@ -557,15 +579,16 @@ QString QFileInfo::absoluteFilePath() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::AbsoluteName);
}
/*!
- Returns the canonical path including the file name, i.e. an absolute
- path without symbolic links or redundant "." or ".." elements.
+ Returns the file system entry's canonical path, including the entry's
+ name, that is, an absolute path without symbolic links or redundant
+ \c{'.'} or \c{'..'} elements.
- If the file does not exist, canonicalFilePath() returns an empty
+ If the entry does not exist, canonicalFilePath() returns an empty
string.
\sa filePath(), absoluteFilePath(), dir()
@@ -574,19 +597,18 @@ QString QFileInfo::canonicalFilePath() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::CanonicalName);
}
/*!
- Returns a file's path absolute path. This doesn't include the
- file name.
+ Returns the absolute path of the file system entry this QFileInfo refers to,
+ excluding the entry's name.
- On Unix the absolute path will always begin with the root, '/',
- directory. On Windows this will always begin 'D:/' where D is a
- drive letter, except for network shares that are not mapped to a
- drive letter, in which case the path will begin '//sharename/'.
+ \include qfileinfo.cpp absolute-path-unix-windows
+
+ \include qfileinfo.cpp windows-network-shares
In contrast to canonicalPath() symbolic links or redundant "." or
".." elements are not necessarily removed.
@@ -600,17 +622,16 @@ QString QFileInfo::absolutePath() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed) {
- return QLatin1String("");
- }
+ if (d->isDefaultConstructed)
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::AbsolutePathName);
}
/*!
- Returns the file's path canonical path (excluding the file name),
+ Returns the file system entry's canonical path (excluding the entry's name),
i.e. an absolute path without symbolic links or redundant "." or ".." elements.
- If the file does not exist, canonicalPath() returns an empty string.
+ If the entry does not exist, this method returns an empty string.
\sa path(), absolutePath()
*/
@@ -618,16 +639,16 @@ QString QFileInfo::canonicalPath() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::CanonicalPathName);
}
/*!
- Returns the file's path. This doesn't include the file name.
+ Returns the path of the file system entry this QFileInfo refers to,
+ excluding the entry's name.
- Note that, if this QFileInfo object is given a path ending in a
- slash, the name of the file is considered empty and this function
- will return the entire path.
+ \include qfileinfo.cpp path-ends-with-slash-empty-name-component
+ In this case, this function will return the entire path.
\sa filePath(), absolutePath(), canonicalPath(), dir(), fileName(), isRelative()
*/
@@ -635,29 +656,28 @@ QString QFileInfo::path() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->fileEntry.path();
}
/*!
\fn bool QFileInfo::isAbsolute() const
- Returns \c true if the file path is absolute, otherwise returns \c false (i.e.
- the path is relative).
+ Returns \c true if the file system entry's path is absolute, otherwise
+ returns \c false (that is, the path is relative).
- \note Paths starting with a colon (\e{:}) are always considered absolute, as
- they denote a QResource.
+ \include qfileinfo.cpp qresource-virtual-fs-colon
\sa isRelative()
*/
/*!
- Returns \c true if the file path is relative, otherwise returns \c
- false (i.e. the path is absolute). (E.g. under Unix a path is absolute
- if it begins with a "/").
+ Returns \c true if the file system entry's path is relative, otherwise
+ returns \c false (that is, the path is absolute).
+
+ \include qfileinfo.cpp absolute-path-unix-windows
- \note Paths starting with a colon (\e{:}) are always considered absolute,
- as they denote a QResource.
+ \include qfileinfo.cpp qresource-virtual-fs-colon
\sa isAbsolute()
*/
@@ -672,9 +692,9 @@ bool QFileInfo::isRelative() const
}
/*!
- Converts the file's path to an absolute path if it is not already in that form.
- Returns \c true to indicate that the path was converted; otherwise returns \c false
- to indicate that the path was already absolute.
+ If the file system entry's path is relative, this method converts it to
+ an absolute path and returns \c true; if the path is already absolute,
+ this method returns \c false.
\sa filePath(), isRelative()
*/
@@ -689,10 +709,11 @@ bool QFileInfo::makeAbsolute()
}
/*!
- Returns \c true if the file exists; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to exists;
+ otherwise returns \c false.
- \note If the file is a symlink that points to a non-existing
- file, false is returned.
+ \note If the entry is a symlink that points to a non-existing
+ target, this method returns \c false.
*/
bool QFileInfo::exists() const
{
@@ -710,24 +731,23 @@ bool QFileInfo::exists() const
/*!
\since 5.2
- Returns \c true if the \a file exists; otherwise returns \c false.
+ Returns \c true if the file system entry \a path exists; otherwise
+ returns \c false.
- \note If \a file is a symlink that points to a non-existing
- file, false is returned.
+ \note If \a path is a symlink that points to a non-existing
+ target, this method returns \c false.
\note Using this function is faster than using
- \c QFileInfo(file).exists() for file system access.
+ \c QFileInfo(path).exists() for file system access.
*/
-bool QFileInfo::exists(const QString &file)
+bool QFileInfo::exists(const QString &path)
{
- if (file.isEmpty())
+ if (path.isEmpty())
return false;
- QFileSystemEntry entry(file);
+ QFileSystemEntry entry(path);
QFileSystemMetaData data;
- std::unique_ptr<QAbstractFileEngine> engine
- {QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, data)};
// Expensive fallback to non-QFileSystemEngine implementation
- if (engine)
+ if (auto engine = QFileSystemEngine::createLegacyEngine(entry, data))
return QFileInfo(new QFileInfoPrivate(entry, data, std::move(engine))).exists();
QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
@@ -735,8 +755,9 @@ bool QFileInfo::exists(const QString &file)
}
/*!
- Refreshes the information about the file, i.e. reads in information
- from the file system the next time a cached property is fetched.
+ Refreshes the information about the file system entry this QFileInfo
+ refers to, that is, reads in information from the file system the next
+ time a cached property is fetched.
*/
void QFileInfo::refresh()
{
@@ -745,8 +766,8 @@ void QFileInfo::refresh()
}
/*!
- Returns the file name, including the path (which may be absolute
- or relative).
+ Returns the path of the file system entry this QFileInfo refers to;
+ the path may be absolute or relative.
\sa absoluteFilePath(), canonicalFilePath(), isRelative()
*/
@@ -754,18 +775,21 @@ QString QFileInfo::filePath() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->fileEntry.filePath();
}
/*!
- Returns the name of the file, excluding the path.
+ Returns the name of the file system entry this QFileInfo refers to,
+ excluding the path.
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 3
- Note that, if this QFileInfo object is given a path ending in a
- slash, the name of the file is considered empty.
+//! [path-ends-with-slash-empty-name-component]
+ \note If this QFileInfo is given a path ending with a directory separator
+ \c{'/'}, the entry's name part is considered empty.
+//! [path-ends-with-slash-empty-name-component]
\sa isRelative(), filePath(), baseName(), suffix()
*/
@@ -773,8 +797,10 @@ QString QFileInfo::fileName() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
- return d->fileEntry.fileName();
+ return ""_L1;
+ if (!d->fileEngine)
+ return d->fileEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
/*!
@@ -793,7 +819,7 @@ QString QFileInfo::bundleName() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::BundleName);
}
@@ -817,8 +843,10 @@ QString QFileInfo::baseName() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
- return d->fileEntry.baseName();
+ return ""_L1;
+ if (!d->fileEngine)
+ return d->fileEntry.baseName();
+ return QFileSystemEntry(d->fileEngine->fileName(QAbstractFileEngine::BaseName)).baseName();
}
/*!
@@ -836,8 +864,11 @@ QString QFileInfo::completeBaseName() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
- return d->fileEntry.completeBaseName();
+ return ""_L1;
+ if (!d->fileEngine)
+ return d->fileEntry.completeBaseName();
+ const QString fileEngineBaseName = d->fileEngine->fileName(QAbstractFileEngine::BaseName);
+ return QFileSystemEntry(fileEngineBaseName).completeBaseName();
}
/*!
@@ -855,7 +886,7 @@ QString QFileInfo::completeSuffix() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->fileEntry.completeSuffix();
}
@@ -878,15 +909,16 @@ QString QFileInfo::suffix() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->fileEntry.suffix();
}
/*!
- Returns the path of the object's parent directory as a QDir object.
+ Returns a QDir object representing the path of the parent directory of the
+ file system entry that this QFileInfo refers to.
- \b{Note:} The QDir returned always corresponds to the object's
+ \note The QDir returned always corresponds to the object's
parent directory, even if the QFileInfo represents a directory.
For each of the following, dir() returns the QDir
@@ -908,7 +940,10 @@ QDir QFileInfo::dir() const
}
/*!
- Returns the file's absolute path as a QDir object.
+ Returns a QDir object representing the absolute path of the parent
+ directory of the file system entry that this QFileInfo refers to.
+
+ \snippet code/src_corelib_io_qfileinfo.cpp 11
\sa dir(), filePath(), fileName(), isRelative()
*/
@@ -918,13 +953,13 @@ QDir QFileInfo::absoluteDir() const
}
/*!
- Returns \c true if the user can read the file; otherwise returns \c false.
+ Returns \c true if the user can read the file system entry this QFileInfo
+ refers to; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- readable (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\note If the \l{NTFS permissions} check has not been enabled, the result
- on Windows will merely reflect whether the file exists.
+ on Windows will merely reflect whether the entry exists.
\sa isWritable(), isExecutable(), permission()
*/
@@ -933,18 +968,18 @@ bool QFileInfo::isReadable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserReadPermission,
- [d]() { return (d->metaData.permissions() & QFile::ReadUser) != 0; },
+ [d]() { return d->metaData.isReadable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::ReadUserPerm); });
}
/*!
- Returns \c true if the user can write to the file; otherwise returns \c false.
+ Returns \c true if the user can write to the file system entry this
+ QFileInfo refers to; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- writeable (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\note If the \l{NTFS permissions} check has not been enabled, the result on
- Windows will merely reflect whether the file is marked as Read Only.
+ Windows will merely reflect whether the entry is marked as Read Only.
\sa isReadable(), isExecutable(), permission()
*/
@@ -953,15 +988,18 @@ bool QFileInfo::isWritable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserWritePermission,
- [d]() { return (d->metaData.permissions() & QFile::WriteUser) != 0; },
+ [d]() { return d->metaData.isWritable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::WriteUserPerm); });
}
/*!
- Returns \c true if the file is executable; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to is
+ executable; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- executable (not the symlink).
+//! [info-about-target-not-symlink]
+ If the file is a symlink, this function returns information about the
+ target, not the symlink.
+//! [info-about-target-not-symlink]
\sa isReadable(), isWritable(), permission()
*/
@@ -970,15 +1008,16 @@ bool QFileInfo::isExecutable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserExecutePermission,
- [d]() { return (d->metaData.permissions() & QFile::ExeUser) != 0; },
+ [d]() { return d->metaData.isExecutable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::ExeUserPerm); });
}
/*!
- Returns \c true if this is a `hidden' file; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to is
+ `hidden'; otherwise returns \c false.
\b{Note:} This function returns \c true for the special entries "." and
- ".." on Unix, even though QDir::entryList threats them as shown. And note
+ ".." on Unix, even though QDir::entryList treats them as shown. And note
that, since this function inspects the file name, on Unix it will inspect
the name of the symlink, if this file is a symlink, not the target's name.
@@ -1020,10 +1059,10 @@ bool QFileInfo::isNativePath() const
/*!
Returns \c true if this object points to a file or to a symbolic
link to a file. Returns \c false if the
- object points to something which isn't a file, such as a directory.
+ object points to something that is not a file (such as a directory)
+ or that does not exist.
- If the file is a symlink, this function returns true if the target is a
- regular file (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isDir(), isSymLink(), isBundle()
*/
@@ -1038,10 +1077,11 @@ bool QFileInfo::isFile() const
/*!
Returns \c true if this object points to a directory or to a symbolic
- link to a directory; otherwise returns \c false.
+ link to a directory. Returns \c false if the
+ object points to something that is not a directory (such as a file)
+ or that does not exist.
- If the file is a symlink, this function returns true if the target is a
- directory (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isFile(), isSymLink(), isBundle()
*/
@@ -1060,8 +1100,7 @@ bool QFileInfo::isDir() const
Returns \c true if this object points to a bundle or to a symbolic
link to a bundle on \macos and iOS; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is a
- bundle (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isDir(), isSymLink(), isFile()
*/
@@ -1075,8 +1114,8 @@ bool QFileInfo::isBundle() const
}
/*!
- Returns \c true if this object points to a symbolic link or shortcut;
- otherwise returns \c false.
+ Returns \c true if this object points to a symbolic link, shortcut,
+ or alias; otherwise returns \c false.
Symbolic links exist on Unix (including \macos and iOS) and Windows
and are typically created by the \c{ln -s} or \c{mklink} commands,
@@ -1084,15 +1123,18 @@ bool QFileInfo::isBundle() const
the \l{symLinkTarget()}{link's target}.
In addition, true will be returned for shortcuts (\c *.lnk files) on
- Windows. This behavior is deprecated and will likely change in a future
- version of Qt. Opening those will open the \c .lnk file itself.
+ Windows, and aliases on \macos. This behavior is deprecated and will
+ likely change in a future version of Qt. Opening a shortcut or alias
+ will open the \c .lnk or alias file itself.
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 9
- \note If the symlink points to a non existing file, exists() returns
- false.
+//! [symlink-target-exists-behavior]
+ \note exists() returns \c true if the symlink points to an existing
+ target, otherwise it returns \c false.
+//! [symlink-target-exists-behavior]
\sa isFile(), isDir(), symLinkTarget()
*/
@@ -1117,10 +1159,10 @@ bool QFileInfo::isSymLink() const
opens the \l{symLinkTarget()}{link's target}.
In contrast to isSymLink(), false will be returned for shortcuts
- (\c *.lnk files) on Windows. Use QFileInfo::isShortcut() instead.
+ (\c *.lnk files) on Windows and aliases on \macos. Use QFileInfo::isShortcut()
+ and QFileInfo::isAlias() instead.
- \note If the symlink points to a non existing file, exists() returns
- false.
+ \include qfileinfo.cpp symlink-target-exists-behavior
\sa isFile(), isDir(), isShortcut(), symLinkTarget()
*/
@@ -1160,6 +1202,29 @@ bool QFileInfo::isShortcut() const
[d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
}
+/*!
+ Returns \c true if this object points to an alias;
+ otherwise returns \c false.
+
+ \since 6.4
+
+ Aliases only exist on \macos. They are treated as regular files, so
+ opening an alias will open the file itself. In order to open the file
+ or directory an alias references use symLinkTarget().
+
+ \note Even if an alias points to a non existing file,
+ isAlias() returns true.
+
+ \sa isFile(), isDir(), isSymLink(), symLinkTarget()
+*/
+bool QFileInfo::isAlias() const
+{
+ Q_D(const QFileInfo);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::LegacyLinkType,
+ [d]() { return d->metaData.isAlias(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
+}
/*!
\since 5.15
@@ -1216,8 +1281,8 @@ bool QFileInfo::isRoot() const
link.
This name may not represent an existing file; it is only a string.
- QFileInfo::exists() returns \c true if the symlink points to an
- existing file.
+
+ \include qfileinfo.cpp symlink-target-exists-behavior
\sa exists(), isSymLink(), isDir(), isFile()
*/
@@ -1225,11 +1290,30 @@ QString QFileInfo::symLinkTarget() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::AbsoluteLinkTarget);
}
/*!
+ \since 6.6
+ Read the path the symlink references.
+
+ Returns the raw path referenced by the symbolic link, without resolving a relative
+ path relative to the directory containing the symbolic link. The returned string will
+ only be an absolute path if the symbolic link actually references it as such. Returns
+ an empty string if the object is not a symbolic link.
+
+ \sa symLinkTarget(), exists(), isSymLink(), isDir(), isFile()
+*/
+QString QFileInfo::readSymLink() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return {};
+ return d->getFileName(QAbstractFileEngine::RawLinkPath);
+}
+
+/*!
\since 6.2
Resolves an NTFS junction to the path it references.
@@ -1247,7 +1331,7 @@ QString QFileInfo::junctionTarget() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileName(QAbstractFileEngine::JunctionName);
}
@@ -1260,8 +1344,7 @@ QString QFileInfo::junctionTarget() const
milliseconds). On Windows, it will return an empty string unless
the \l{NTFS permissions} check has been enabled.
- If the file is a symlink, this function returns the owner of the target
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa ownerId(), group(), groupId()
*/
@@ -1269,7 +1352,7 @@ QString QFileInfo::owner() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileOwner(QAbstractFileEngine::OwnerUser);
}
@@ -1279,8 +1362,7 @@ QString QFileInfo::owner() const
On Windows and on systems where files do not have owners this
function returns ((uint) -2).
- If the file is a symlink, this function returns the id of the owner of the target
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa owner(), group(), groupId()
*/
@@ -1301,8 +1383,7 @@ uint QFileInfo::ownerId() const
This function can be time consuming under Unix (in the order of
milliseconds).
- If the file is a symlink, this function returns the owning group of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa groupId(), owner(), ownerId()
*/
@@ -1310,7 +1391,7 @@ QString QFileInfo::group() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return QLatin1String("");
+ return ""_L1;
return d->getFileOwner(QAbstractFileEngine::OwnerGroup);
}
@@ -1320,8 +1401,7 @@ QString QFileInfo::group() const
On Windows and on systems where files do not have groups this
function always returns (uint) -2.
- If the file is a symlink, this function returns the id of the group owning the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa group(), owner(), ownerId()
*/
@@ -1348,8 +1428,7 @@ uint QFileInfo::groupId() const
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 10
- If the file is a symlink, this function checks the permissions of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isReadable(), isWritable(), isExecutable()
*/
@@ -1374,8 +1453,7 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
\note The result might be inaccurate on Windows if the
\l{NTFS permissions} check has not been enabled.
- If the file is a symlink, this function returns the permissions of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
*/
QFile::Permissions QFileInfo::permissions() const
{
@@ -1393,8 +1471,7 @@ QFile::Permissions QFileInfo::permissions() const
Returns the file size in bytes. If the file does not exist or cannot be
fetched, 0 is returned.
- If the file is a symlink, the size of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa exists()
*/
@@ -1415,77 +1492,180 @@ qint64 QFileInfo::size() const
/*!
\fn QDateTime QFileInfo::birthTime() const
+
+ Returns the date and time when the file was created (born), in local time.
+
+ If the file birth time is not available, this function returns an invalid QDateTime.
+
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ This function overloads QFileInfo::birthTime(const QTimeZone &tz), and
+ returns the same as \c{birthTime(QTimeZone::LocalTime)}.
+
\since 5.10
- Returns the date and time when the file was created / born.
+ \sa lastModified(), lastRead(), metadataChangeTime(), fileTime()
+*/
+
+/*!
+ \fn QDateTime QFileInfo::birthTime(const QTimeZone &tz) const
+
+ Returns the date and time when the file was created (born).
+
+ \include qfileinfo.cpp file-times-in-time-zone
If the file birth time is not available, this function returns an invalid
QDateTime.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
- \sa lastModified(), lastRead(), metadataChangeTime()
+ \since 6.6
+ \sa lastModified(const QTimeZone &), lastRead(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
*/
/*!
\fn QDateTime QFileInfo::metadataChangeTime() const
+
+ Returns the date and time when the file's metadata was last changed,
+ in local time.
+
+ A metadata change occurs when the file is first created, but it also
+ occurs whenever the user writes or sets inode information (for example,
+ changing the file permissions).
+
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ This function overloads QFileInfo::metadataChangeTime(const QTimeZone &tz),
+ and returns the same as \c{metadataChangeTime(QTimeZone::LocalTime)}.
+
\since 5.10
- Returns the date and time when the file metadata was changed. A metadata
- change occurs when the file is created, but it also occurs whenever the
- user writes or sets inode information (for example, changing the file
- permissions).
+ \sa birthTime(), lastModified(), lastRead(), fileTime()
+*/
+
+/*!
+ \fn QDateTime QFileInfo::metadataChangeTime(const QTimeZone &tz) const
+
+ Returns the date and time when the file's metadata was last changed.
+ A metadata change occurs when the file is first created, but it also
+ occurs whenever the user writes or sets inode information (for example,
+ changing the file permissions).
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp file-times-in-time-zone
- \sa lastModified(), lastRead()
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ \since 6.6
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ lastRead(const QTimeZone &),
+ fileTime(QFileDevice::FileTime time, const QTimeZone &)
*/
/*!
\fn QDateTime QFileInfo::lastModified() const
- Returns the date and local time when the file was last modified.
+ Returns the date and time when the file was last modified.
+
+ \include qfileinfo.cpp info-about-target-not-symlink
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ This function overloads \l{QFileInfo::lastModified(const QTimeZone &)},
+ and returns the same as \c{lastModified(QTimeZone::LocalTime)}.
\sa birthTime(), lastRead(), metadataChangeTime(), fileTime()
*/
/*!
+ \fn QDateTime QFileInfo::lastModified(const QTimeZone &tz) const
+
+ Returns the date and time when the file was last modified.
+
+ \include qfileinfo.cpp file-times-in-time-zone
+
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ \since 6.6
+ \sa birthTime(const QTimeZone &), lastRead(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
+*/
+
+/*!
\fn QDateTime QFileInfo::lastRead() const
- Returns the date and local time when the file was last read (accessed).
+ Returns the date and time when the file was last read (accessed).
- On platforms where this information is not available, returns the
- same as lastModified().
+ On platforms where this information is not available, returns the same
+ time as lastModified().
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ This function overloads \l{QFileInfo::lastRead(const QTimeZone &)},
+ and returns the same as \c{lastRead(QTimeZone::LocalTime)}.
\sa birthTime(), lastModified(), metadataChangeTime(), fileTime()
*/
/*!
+ \fn QDateTime QFileInfo::lastRead(const QTimeZone &tz) const
+
+ Returns the date and time when the file was last read (accessed).
+
+ \include qfileinfo.cpp file-times-in-time-zone
+
+ On platforms where this information is not available, returns the same
+ time as lastModified().
+
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ \since 6.6
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
+*/
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+/*!
+ Returns the file time specified by \a time.
+
+ If the time cannot be determined, an invalid date time is returned.
+
+ \include qfileinfo.cpp info-about-target-not-symlink
+
+ This function overloads
+ \l{QFileInfo::fileTime(QFileDevice::FileTime, const QTimeZone &)},
+ and returns the same as \c{fileTime(time, QTimeZone::LocalTime)}.
+
\since 5.10
+ \sa birthTime(), lastModified(), lastRead(), metadataChangeTime()
+*/
+QDateTime QFileInfo::fileTime(QFile::FileTime time) const {
+ return fileTime(time, QTimeZone::LocalTime);
+}
+#endif
+
+/*!
+ Returns the file time specified by \a time.
+
+//! [file-times-in-time-zone]
+ The returned time is in the time zone specified by \a tz. For example,
+ you can use QTimeZone::LocalTime or QTimeZone::UTC to get the time in
+ the Local time zone or UTC, respectively. Since native file system API
+ typically uses UTC, using QTimeZone::UTC is often faster, as it does not
+ require any conversions.
+//! [file-times-in-time-zone]
- Returns the file time specified by \a time. If the time cannot be
- determined, an invalid date time is returned.
+ If the time cannot be determined, an invalid date time is returned.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
- \sa QFile::FileTime, QDateTime::isValid()
+ \since 6.6
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &),
+ QDateTime::isValid()
*/
-QDateTime QFileInfo::fileTime(QFile::FileTime time) const
+QDateTime QFileInfo::fileTime(QFile::FileTime time, const QTimeZone &tz) const
{
- static_assert(int(QFile::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
- static_assert(int(QFile::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
- static_assert(int(QFile::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
- static_assert(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
-
Q_D(const QFileInfo);
- auto fetime = QAbstractFileEngine::FileTime(time);
QFileSystemMetaData::MetaDataFlags flag;
switch (time) {
case QFile::FileAccessTime:
@@ -1502,10 +1682,11 @@ QDateTime QFileInfo::fileTime(QFile::FileTime time) const
break;
}
- return d->checkAttribute<QDateTime>(
- flag,
- [=]() { return d->metaData.fileTime(fetime).toLocalTime(); },
- [=]() { return d->getFileTime(fetime).toLocalTime(); });
+ auto fsLambda = [d, time]() { return d->metaData.fileTime(time); };
+ auto engineLambda = [d, time]() { return d->getFileTime(time); };
+ const auto dt =
+ d->checkAttribute<QDateTime>(flag, std::move(fsLambda), std::move(engineLambda));
+ return dt.toTimeZone(tz);
}
/*!
@@ -1589,24 +1770,22 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
\sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
/*!
- \fn QFileInfo::QFileInfo(const QDir &dir, const std::filesystem::path &file)
+ \fn QFileInfo::QFileInfo(const QDir &dir, const std::filesystem::path &path)
\since 6.0
- Constructs a new QFileInfo that gives information about the given
- \a file relative to the directory \a dir.
+ Constructs a new QFileInfo that gives information about the file system
+ entry at \a path that is relative to the directory \a dir.
- If \a dir has a relative path, the QFileInfo will also have a
- relative path.
-
- If \a file is an absolute path, then the directory specified
- by \a dir will be disregarded.
+ \include qfileinfo.cpp preserve-relative-or-absolute
*/
/*!
- \fn void QFileInfo::setFile(const std::filesystem::path &file)
+ \fn void QFileInfo::setFile(const std::filesystem::path &path)
\since 6.0
- Sets the file that the QFileInfo provides information about to \a
- file.
+ Sets the path of file system entry that this QFileInfo provides
+ information about to \a path.
+
+ \include qfileinfo.cpp preserve-relative-path
*/
/*!
\fn std::filesystem::path QFileInfo::filesystemFilePath() const
@@ -1658,6 +1837,13 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
\sa symLinkTarget()
*/
/*!
+ \fn std::filesystem::path QFileInfo::filesystemReadSymLink() const
+ \since 6.6
+
+ Returns readSymLink() as a \c{std::filesystem::path}.
+ \sa readSymLink()
+*/
+/*!
\fn std::filesystem::path QFileInfo::filesystemJunctionTarget() const
\since 6.2
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index f2260db410..72c8519446 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -1,50 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILEINFO_H
#define QFILEINFO_H
+#include <QtCore/qcompare.h>
#include <QtCore/qfile.h>
#include <QtCore/qlist.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
QT_BEGIN_NAMESPACE
@@ -56,6 +22,7 @@ class QFileInfoPrivate;
class Q_CORE_EXPORT QFileInfo
{
friend class QDirIteratorPrivate;
+ friend class QDirListingPrivate;
public:
explicit QFileInfo(QFileInfoPrivate *d);
@@ -70,7 +37,7 @@ public:
QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QFileDevice &file);
QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QDir &dir, const QString &file);
QFileInfo(const QFileInfo &fileinfo);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
QFileInfo(const std::filesystem::path &file);
QFileInfo(const QDir &dir, const std::filesystem::path &file);
#elif QT_CONFIG(cxx17_filesystem)
@@ -93,13 +60,15 @@ public:
void swap(QFileInfo &other) noexcept
{ d_ptr.swap(other.d_ptr); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QFileInfo &fileinfo) const;
inline bool operator!=(const QFileInfo &fileinfo) const { return !(operator==(fileinfo)); }
+#endif
void setFile(const QString &file);
void setFile(const QFileDevice &file);
void setFile(const QDir &dir, const QString &file);
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
void setFile(const std::filesystem::path &file);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
@@ -113,7 +82,7 @@ public:
QString filePath() const;
QString absoluteFilePath() const;
QString canonicalFilePath() const;
-#if QT_CONFIG(cxx17_filesystem) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
std::filesystem::path filesystemFilePath() const
{ return QtPrivate::toFilesystemPath(filePath()); }
std::filesystem::path filesystemAbsoluteFilePath() const
@@ -131,7 +100,7 @@ public:
QString path() const;
QString absolutePath() const;
QString canonicalPath() const;
-#if QT_CONFIG(cxx17_filesystem) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
std::filesystem::path filesystemPath() const { return QtPrivate::toFilesystemPath(path()); }
std::filesystem::path filesystemAbsolutePath() const
{ return QtPrivate::toFilesystemPath(absolutePath()); }
@@ -156,17 +125,22 @@ public:
bool isSymLink() const;
bool isSymbolicLink() const;
bool isShortcut() const;
+ bool isAlias() const;
bool isJunction() const;
bool isRoot() const;
bool isBundle() const;
QString symLinkTarget() const;
+ QString readSymLink() const;
QString junctionTarget() const;
-#if QT_CONFIG(cxx17_filesystem) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
std::filesystem::path filesystemSymLinkTarget() const
{ return QtPrivate::toFilesystemPath(symLinkTarget()); }
+ std::filesystem::path filesystemReadSymLink() const
+ { return QtPrivate::toFilesystemPath(readSymLink()); }
+
std::filesystem::path filesystemJunctionTarget() const
{ return QtPrivate::toFilesystemPath(junctionTarget()); }
#endif // QT_CONFIG(cxx17_filesystem)
@@ -187,6 +161,12 @@ public:
QDateTime lastRead() const { return fileTime(QFile::FileAccessTime); }
QDateTime fileTime(QFile::FileTime time) const;
+ QDateTime birthTime(const QTimeZone &tz) const { return fileTime(QFile::FileBirthTime, tz); }
+ QDateTime metadataChangeTime(const QTimeZone &tz) const { return fileTime(QFile::FileMetadataChangeTime, tz); }
+ QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); }
+ QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); }
+ QDateTime fileTime(QFile::FileTime time, const QTimeZone &tz) const;
+
bool caching() const;
void setCaching(bool on);
void stat();
@@ -195,6 +175,8 @@ protected:
QSharedDataPointer<QFileInfoPrivate> d_ptr;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QFileInfo)
QFileInfoPrivate* d_func();
inline const QFileInfoPrivate* d_func() const
{
diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h
index 8b02c8ab8b..4091a7464a 100644
--- a/src/corelib/io/qfileinfo_p.h
+++ b/src/corelib/io/qfileinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILEINFO_P_H
#define QFILEINFO_P_H
@@ -91,7 +55,7 @@ public:
: QSharedData(copy),
fileEntry(copy.fileEntry),
metaData(copy.metaData),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(false),
@@ -102,7 +66,7 @@ public:
{}
inline QFileInfoPrivate(const QString &file)
: fileEntry(file),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(file.isEmpty()),
@@ -117,7 +81,7 @@ public:
: QSharedData(),
fileEntry(file),
metaData(data),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
isDefaultConstructed(false),
cache_enabled(true), fileFlags(0), fileSize(0)
@@ -158,7 +122,7 @@ public:
}
uint getFileFlags(QAbstractFileEngine::FileFlags) const;
- QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
+ QDateTime &getFileTime(QFile::FileTime) const;
QString getFileName(QAbstractFileEngine::FileName) const;
QString getFileOwner(QAbstractFileEngine::FileOwner own) const;
@@ -169,7 +133,7 @@ public:
mutable QString fileNames[QAbstractFileEngine::NFileNames];
mutable QString fileOwners[2]; // QAbstractFileEngine::FileOwner: OwnerUser and OwnerGroup
- mutable QDateTime fileTimes[4]; // QAbstractFileEngine::FileTime: BirthTime, MetadataChangeTime, ModificationTime, AccessTime
+ mutable QDateTime fileTimes[4]; // QFile::FileTime: FileBirthTime, FileMetadataChangeTime, FileModificationTime, FileAccessTime
mutable uint cachedFlags : 30;
bool const isDefaultConstructed : 1; // QFileInfo is a default constructed instance
@@ -182,8 +146,8 @@ public:
{ if (cache_enabled) cachedFlags |= c; }
template <typename Ret, typename FSLambda, typename EngineLambda>
- Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
- const EngineLambda &engineLambda) const
+ Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags,
+ FSLambda fsLambda, EngineLambda engineLambda) const
{
if (isDefaultConstructed)
return defaultValue;
@@ -197,10 +161,10 @@ public:
}
template <typename Ret, typename FSLambda, typename EngineLambda>
- Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
- const EngineLambda &engineLambda) const
+ Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, FSLambda fsLambda,
+ EngineLambda engineLambda) const
{
- return checkAttribute(Ret(), fsFlags, fsLambda, engineLambda);
+ return checkAttribute(Ret(), std::move(fsFlags), std::move(fsLambda), engineLambda);
}
};
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index dd6257a885..7f5480c274 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfileselector.h"
#include "qfileselector_p.h"
@@ -52,11 +16,13 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
//Environment variable to allow tooling full control of file selectors
static const char env_override[] = "QT_NO_BUILTIN_SELECTORS";
Q_GLOBAL_STATIC(QFileSelectorSharedData, sharedData);
-static QBasicMutex sharedDataMutex;
+Q_CONSTINIT static QBasicMutex sharedDataMutex;
QFileSelectorPrivate::QFileSelectorPrivate()
: QObjectPrivate()
@@ -196,9 +162,9 @@ QString QFileSelector::select(const QString &filePath) const
static bool isLocalScheme(const QString &file)
{
- bool local = file == QLatin1String("qrc");
+ bool local = file == "qrc"_L1;
#ifdef Q_OS_ANDROID
- local |= file == QLatin1String("assets");
+ local |= file == "assets"_L1;
#endif
return local;
}
@@ -217,11 +183,11 @@ QUrl QFileSelector::select(const QUrl &filePath) const
return filePath;
QUrl ret(filePath);
if (isLocalScheme(filePath.scheme())) {
- QLatin1String scheme(":");
+ auto scheme = ":"_L1;
#ifdef Q_OS_ANDROID
// use other scheme because ":" means "qrc" here
- if (filePath.scheme() == QLatin1String("assets"))
- scheme = QLatin1String("assets:");
+ if (filePath.scheme() == "assets"_L1)
+ scheme = "assets:"_L1;
#endif
QString equivalentPath = scheme + filePath.path();
@@ -244,19 +210,20 @@ QUrl QFileSelector::select(const QUrl &filePath) const
return ret;
}
-QString QFileSelectorPrivate::selectionHelper(const QString &path, const QString &fileName, const QStringList &selectors, const QChar &indicator)
+QString QFileSelectorPrivate::selectionHelper(const QString &path, const QString &fileName,
+ const QStringList &selectors, QChar indicator)
{
/* selectionHelper does a depth-first search of possible selected files. Because there is strict
selector ordering in the API, we can stop checking as soon as we find the file in a directory
which does not contain any other valid selector directories.
*/
- Q_ASSERT(path.isEmpty() || path.endsWith(QLatin1Char('/')));
+ Q_ASSERT(path.isEmpty() || path.endsWith(u'/'));
for (const QString &s : selectors) {
QString prospectiveBase = path;
if (!indicator.isNull())
prospectiveBase += indicator;
- prospectiveBase += s + QLatin1Char('/');
+ prospectiveBase += s + u'/';
QStringList remainingSelectors = selectors;
remainingSelectors.removeAll(s);
if (!QDir(prospectiveBase).exists())
@@ -328,7 +295,7 @@ void QFileSelectorPrivate::updateSelectors()
QLatin1Char pathSep(',');
QStringList envSelectors = QString::fromLatin1(qgetenv("QT_FILE_SELECTORS"))
.split(pathSep, Qt::SkipEmptyParts);
- if (envSelectors.count())
+ if (envSelectors.size())
sharedData->staticSelectors << envSelectors;
if (!qEnvironmentVariableIsEmpty(env_override))
@@ -356,7 +323,7 @@ QStringList QFileSelectorPrivate::platformSelectors()
ret << QSysInfo::kernelType();
# endif
QString productName = QSysInfo::productType();
- if (productName != QLatin1String("unknown"))
+ if (productName != "unknown"_L1)
ret << productName; // "opensuse", "fedora", "osx", "ios", "android"
#endif
return ret;
diff --git a/src/corelib/io/qfileselector.h b/src/corelib/io/qfileselector.h
index c9c2f564f6..bb840fe083 100644
--- a/src/corelib/io/qfileselector.h
+++ b/src/corelib/io/qfileselector.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESELECTOR_H
#define QFILESELECTOR_H
diff --git a/src/corelib/io/qfileselector_p.h b/src/corelib/io/qfileselector_p.h
index 024d0b190d..bc0593bca6 100644
--- a/src/corelib/io/qfileselector_p.h
+++ b/src/corelib/io/qfileselector_p.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESELECTOR_P_H
#define QFILESELECTOR_P_H
@@ -71,7 +35,7 @@ public:
static QStringList platformSelectors();
static void addStatics(const QStringList &); //For loading GUI statics from other Qt modules
static QString selectionHelper(const QString &path, const QString &fileName,
- const QStringList &selectors, const QChar &indicator = QLatin1Char('+'));
+ const QStringList &selectors, QChar indicator = u'+');
QFileSelectorPrivate();
QString select(const QString &filePath) const;
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
index f00aba78c3..d8b215816c 100644
--- a/src/corelib/io/qfilesystemengine.cpp
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemengine_p.h"
#include <QtCore/qdir.h>
@@ -61,9 +25,9 @@ QString QFileSystemEngine::slowCanonicalized(const QString &path)
return path;
QFileInfo fi;
- const QChar slash(QLatin1Char('/'));
+ const QChar slash(u'/');
QString tmpPath = path;
- int separatorPos = 0;
+ qsizetype separatorPos = 0;
QSet<QString> nonSymlinks;
QDuplicateTracker<QString> known;
@@ -74,7 +38,7 @@ QString QFileSystemEngine::slowCanonicalized(const QString &path)
if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
// UNC, skip past the first two elements
separatorPos = tmpPath.indexOf(slash, 2);
- } else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
+ } else if (tmpPath.size() >= 3 && tmpPath.at(1) == u':' && tmpPath.at(2) == slash) {
// volume root, skip since it can not be a symlink
separatorPos = 2;
}
@@ -119,12 +83,11 @@ static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &d
return true;
}
-static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
+static inline bool _q_checkEntry(std::unique_ptr<QAbstractFileEngine> &engine, bool resolvingEntry)
{
if (resolvingEntry) {
if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
- delete engine;
- engine = nullptr;
+ engine.reset();
return false;
}
}
@@ -132,22 +95,23 @@ static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEnt
return true;
}
-static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
- QAbstractFileEngine *&engine, bool resolvingEntry = false)
+static bool _q_createLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
+ std::unique_ptr<QAbstractFileEngine> &engine,
+ bool resolvingEntry = false)
{
QString const &filePath = entry.filePath();
if ((engine = qt_custom_file_engine_handler_create(filePath)))
return _q_checkEntry(engine, resolvingEntry);
#if defined(QT_BUILD_CORE_LIB)
- for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
+ for (qsizetype prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
QChar const ch = filePath[prefixSeparator];
- if (ch == QLatin1Char('/'))
+ if (ch == u'/')
break;
- if (ch == QLatin1Char(':')) {
+ if (ch == u':') {
if (prefixSeparator == 0) {
- engine = new QResourceFileEngine(filePath);
+ engine = std::make_unique<QResourceFileEngine>(filePath);
return _q_checkEntry(engine, resolvingEntry);
}
@@ -155,10 +119,11 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
break;
const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
- for (int i = 0; i < paths.count(); i++) {
- entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % QStringView{filePath}.mid(prefixSeparator + 1)));
+ for (int i = 0; i < paths.size(); i++) {
+ entry = QFileSystemEntry(QDir::cleanPath(
+ paths.at(i) % u'/' % QStringView{filePath}.mid(prefixSeparator + 1)));
// Recurse!
- if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
+ if (_q_createLegacyEngine_recursive(entry, data, engine, true))
return true;
}
@@ -188,12 +153,13 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
QFileSystemEngine API should be used to query and interact with the file
system object.
*/
-QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
- QFileSystemEntry &entry, QFileSystemMetaData &data) {
+std::unique_ptr<QAbstractFileEngine>
+QFileSystemEngine::createLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data)
+{
QFileSystemEntry copy = entry;
- QAbstractFileEngine *engine = nullptr;
+ std::unique_ptr<QAbstractFileEngine> engine;
- if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
+ if (_q_createLegacyEngine_recursive(copy, data, engine))
// Reset entry to resolved copy.
entry = copy;
else
diff --git a/src/corelib/io/qfilesystemengine_mac.mm b/src/corelib/io/qfilesystemengine_mac.mm
index 02765322f8..e3f567b7a4 100644
--- a/src/corelib/io/qfilesystemengine_mac.mm
+++ b/src/corelib/io/qfilesystemengine_mac.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qfilesystemengine_p.h"
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index 6fac1ae4be..814915407e 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMENGINE_P_H
#define QFILESYSTEMENGINE_P_H
@@ -56,6 +20,7 @@
#include "qfilesystemmetadata_p.h"
#include <QtCore/private/qsystemerror_p.h>
+#include <memory>
#include <optional>
QT_BEGIN_NAMESPACE
@@ -103,6 +68,8 @@ public:
}
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
+ static QFileSystemEntry getRawLinkPath(const QFileSystemEntry &link,
+ QFileSystemMetaData &data);
static QFileSystemEntry getJunctionTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
@@ -128,7 +95,7 @@ public:
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
static QByteArray id(int fd);
static bool setFileTime(int fd, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static bool setPermissions(int fd, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = nullptr);
#endif
@@ -143,7 +110,7 @@ public:
QFileSystemMetaData::MetaDataFlags what);
static QByteArray id(HANDLE fHandle);
static bool setFileTime(HANDLE fHandle, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
static QString nativeAbsoluteFilePath(const QString &path);
static bool isDirPath(const QString &path, bool *existed);
@@ -170,13 +137,14 @@ public:
// unused, therefore not implemented
static bool setFileTime(const QFileSystemEntry &entry, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static bool setCurrentPath(const QFileSystemEntry &entry);
static QFileSystemEntry currentPath();
- static QAbstractFileEngine *resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry,
- QFileSystemMetaData &data);
+ static std::unique_ptr<QAbstractFileEngine>
+ createLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data);
+
private:
static QString slowCanonicalized(const QString &path);
#if defined(Q_OS_WIN)
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 6e8229daec..bda2962f8d 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -1,63 +1,34 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qfilesystemengine_p.h"
#include "qfile.h"
#include "qstorageinfo.h"
+#include "qurl.h"
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/private/qfiledevice_p.h>
+#include <QtCore/private/qfunctions_p.h>
#include <QtCore/qvarlengtharray.h>
#ifndef QT_BOOTSTRAPPED
# include <QtCore/qstandardpaths.h>
+# include <QtCore/private/qtemporaryfile_p.h>
#endif // QT_BOOTSTRAPPED
+#include <grp.h>
#include <pwd.h>
#include <stdlib.h> // for realpath()
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
+#include <chrono>
+#include <memory> // for std::unique_ptr
+
#if __has_include(<paths.h>)
# include <paths.h>
#endif
@@ -65,9 +36,14 @@
# define _PATH_TMP "/tmp"
#endif
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
# include <QtCore/private/qcore_mac_p.h>
# include <CoreFoundation/CFBundle.h>
+# include <UniformTypeIdentifiers/UTType.h>
+# include <UniformTypeIdentifiers/UTCoreTypes.h>
+# include <Foundation/Foundation.h>
+# include <sys/clonefile.h>
+# include <copyfile.h>
#endif
#ifdef Q_OS_MACOS
@@ -78,15 +54,6 @@
#include <MobileCoreServices/MobileCoreServices.h>
#endif
-#if defined(Q_OS_DARWIN)
-# include <sys/clonefile.h>
-# include <copyfile.h>
-// We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but
-// we need these declarations:
-Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
-extern "C" NSString *NSTemporaryDirectory();
-#endif
-
#if defined(Q_OS_LINUX)
# include <sys/ioctl.h>
# include <sys/sendfile.h>
@@ -111,6 +78,8 @@ struct statx { mode_t stx_mode; }; // dummy
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
enum {
#ifdef Q_OS_ANDROID
// On Android, the link(2) system call has been observed to always fail
@@ -154,10 +123,9 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
QString suffix = info.suffix();
if (suffix.length() > 0) {
- // First step: is the extension known ?
- QCFType<CFStringRef> extensionRef = suffix.toCFString();
- QCFType<CFStringRef> uniformTypeIdentifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extensionRef, NULL);
- if (UTTypeConformsTo(uniformTypeIdentifier, kUTTypeBundle))
+ // First step: is it a bundle?
+ const auto *utType = [UTType typeWithFilenameExtension:suffix.toNSString()];
+ if ([utType conformsToType:UTTypeBundle])
return true;
// Second step: check if an application knows the package type
@@ -178,7 +146,7 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, application);
CFStringRef identifier = CFBundleGetIdentifier(bundle);
QString applicationId = QString::fromCFString(identifier);
- if (applicationId != QLatin1String("com.apple.finder"))
+ if (applicationId != "com.apple.finder"_L1)
return true;
}
#endif
@@ -191,51 +159,39 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
namespace {
namespace GetFileTimes {
-#if !QT_CONFIG(futimens) && (QT_CONFIG(futimes))
-template <typename T>
-static inline typename std::enable_if_t<(&T::st_atim, &T::st_mtim, true)> get(const T *p, struct timeval *access, struct timeval *modification)
+qint64 time_t_toMsecs(time_t t)
{
- access->tv_sec = p->st_atim.tv_sec;
- access->tv_usec = p->st_atim.tv_nsec / 1000;
-
- modification->tv_sec = p->st_mtim.tv_sec;
- modification->tv_usec = p->st_mtim.tv_nsec / 1000;
+ using namespace std::chrono;
+ return milliseconds{seconds{t}}.count();
}
-template <typename T>
-static inline typename std::enable_if_t<(&T::st_atimespec, &T::st_mtimespec, true)> get(const T *p, struct timeval *access, struct timeval *modification)
+// fallback set
+[[maybe_unused]] qint64 atime(const QT_STATBUF &statBuffer, ulong)
{
- access->tv_sec = p->st_atimespec.tv_sec;
- access->tv_usec = p->st_atimespec.tv_nsec / 1000;
-
- modification->tv_sec = p->st_mtimespec.tv_sec;
- modification->tv_usec = p->st_mtimespec.tv_nsec / 1000;
+ return time_t_toMsecs(statBuffer.st_atime);
}
-
-# ifndef st_atimensec
-// if "st_atimensec" is defined, this would expand to invalid C++
-template <typename T>
-static inline typename std::enable_if_t<(&T::st_atimensec, &T::st_mtimensec, true)> get(const T *p, struct timeval *access, struct timeval *modification)
+[[maybe_unused]] qint64 birthtime(const QT_STATBUF &, ulong)
{
- access->tv_sec = p->st_atime;
- access->tv_usec = p->st_atimensec / 1000;
-
- modification->tv_sec = p->st_mtime;
- modification->tv_usec = p->st_mtimensec / 1000;
+ return Q_INT64_C(0);
}
-# endif
-#endif
-
-qint64 timespecToMSecs(const timespec &spec)
+[[maybe_unused]] qint64 ctime(const QT_STATBUF &statBuffer, ulong)
{
- return (qint64(spec.tv_sec) * 1000) + (spec.tv_nsec / 1000000);
+ return time_t_toMsecs(statBuffer.st_ctime);
+}
+[[maybe_unused]] qint64 mtime(const QT_STATBUF &statBuffer, ulong)
+{
+ return time_t_toMsecs(statBuffer.st_mtime);
}
-// fallback set
-[[maybe_unused]] qint64 atime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_atime) * 1000; }
-[[maybe_unused]] qint64 birthtime(const QT_STATBUF &, ulong) { return Q_INT64_C(0); }
-[[maybe_unused]] qint64 ctime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_ctime) * 1000; }
-[[maybe_unused]] qint64 mtime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_mtime) * 1000; }
+// T is either a stat.timespec or statx.statx_timestamp,
+// both have tv_sec and tv_nsec members
+template<typename T>
+qint64 timespecToMSecs(const T &spec)
+{
+ using namespace std::chrono;
+ const nanoseconds nsecs = seconds{spec.tv_sec} + nanoseconds{spec.tv_nsec};
+ return duration_cast<milliseconds>(nsecs).count();
+}
// Xtim, POSIX.1-2008
template <typename T>
@@ -370,17 +326,12 @@ inline void QFileSystemMetaData::fillFromStatxBuf(const struct statx &statxBuffe
size_ = qint64(statxBuffer.stx_size);
// Times
- auto toMSecs = [](struct statx_timestamp ts)
- {
- return qint64(ts.tv_sec) * 1000 + (ts.tv_nsec / 1000000);
- };
- accessTime_ = toMSecs(statxBuffer.stx_atime);
- metadataChangeTime_ = toMSecs(statxBuffer.stx_ctime);
- modificationTime_ = toMSecs(statxBuffer.stx_mtime);
- if (statxBuffer.stx_mask & STATX_BTIME)
- birthTime_ = toMSecs(statxBuffer.stx_btime);
- else
- birthTime_ = 0;
+ using namespace GetFileTimes;
+ accessTime_ = timespecToMSecs(statxBuffer.stx_atime);
+ metadataChangeTime_ = timespecToMSecs(statxBuffer.stx_ctime);
+ modificationTime_ = timespecToMSecs(statxBuffer.stx_mtime);
+ const bool birthMask = statxBuffer.stx_mask & STATX_BTIME;
+ birthTime_ = birthMask ? timespecToMSecs(statxBuffer.stx_btime) : 0;
userId_ = statxBuffer.stx_uid;
groupId_ = statxBuffer.stx_gid;
@@ -623,7 +574,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
Q_CHECK_FILE_NAME(link, link);
QByteArray s = qt_readlink(link.nativeFilePath().constData());
- if (s.length() > 0) {
+ if (s.size() > 0) {
QString ret;
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
@@ -631,15 +582,15 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
QDir parent(link.filePath());
parent.cdUp();
ret = parent.path();
- if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
- ret += QLatin1Char('/');
+ if (!ret.isEmpty() && !ret.endsWith(u'/'))
+ ret += u'/';
}
ret += QFile::decodeName(s);
- if (!ret.startsWith(QLatin1Char('/')))
- ret.prepend(absoluteName(link).path() + QLatin1Char('/'));
+ if (!ret.startsWith(u'/'))
+ ret.prepend(absoluteName(link).path() + u'/');
ret = QDir::cleanPath(ret);
- if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
+ if (ret.size() > 1 && ret.endsWith(u'/'))
ret.chop(1);
return QFileSystemEntry(ret);
}
@@ -677,45 +628,60 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
}
//static
+QFileSystemEntry QFileSystemEngine::getRawLinkPath(const QFileSystemEntry &link,
+ QFileSystemMetaData &data)
+{
+ Q_UNUSED(data)
+ const QByteArray path = qt_readlink(link.nativeFilePath().constData());
+ const QString ret = QFile::decodeName(path);
+ return QFileSystemEntry(ret);
+}
+
+//static
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
{
Q_CHECK_FILE_NAME(entry, entry);
-#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
// realpath(X,0) is not supported
Q_UNUSED(data);
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
#else
- char stack_result[PATH_MAX+1];
- char *resolved_name = nullptr;
+# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
+ // used to store the result of realpath in case where realpath cannot allocate itself
+ char stack_result[PATH_MAX + 1];
+#else
+ // enables unconditionally passing stack_result below
+ std::nullptr_t stack_result = nullptr;
+# endif
+ auto resolved_path_deleter = [&](char *ptr) {
+ // frees resolved_name if it was allocated by realpath
+# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
+ // ptr is either null, or points to stack_result
+ Q_ASSERT(!ptr || ptr == stack_result);
+ return;
+#else
+ free(ptr);
+# endif
+ };
+ std::unique_ptr<char, decltype (resolved_path_deleter)> resolved_name {nullptr, resolved_path_deleter};
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
// On some Android and macOS versions, realpath() will return a path even if
// it does not exist. To work around this, we check existence in advance.
if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
- if (!data.exists()) {
+ if (!data.exists())
errno = ENOENT;
- } else {
- resolved_name = stack_result;
- }
- if (resolved_name && realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
- resolved_name = nullptr;
+ else
+ resolved_name.reset(realpath(entry.nativeFilePath().constData(), stack_result));
# else
-# if _POSIX_VERSION >= 200801L // ask realpath to allocate memory
- resolved_name = realpath(entry.nativeFilePath().constData(), nullptr);
-# else
- resolved_name = stack_result;
- if (realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
- resolved_name = nullptr;
-# endif
+ resolved_name.reset(realpath(entry.nativeFilePath().constData(), stack_result));
# endif
if (resolved_name) {
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
- QString canonicalPath = QDir::cleanPath(QFile::decodeName(resolved_name));
- if (resolved_name != stack_result)
- free(resolved_name);
+ QString canonicalPath = QDir::cleanPath(QFile::decodeName(resolved_name.get()));
return QFileSystemEntry(canonicalPath);
} else if (errno == ENOENT || errno == ENOTDIR) { // file doesn't exist
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
@@ -740,13 +706,13 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
QFileSystemEntry cur(currentPath());
result = cur.nativeFilePath();
}
- if (!orig.isEmpty() && !(orig.length() == 1 && orig[0] == '.')) {
+ if (!orig.isEmpty() && !(orig.size() == 1 && orig[0] == '.')) {
if (!result.isEmpty() && !result.endsWith('/'))
result.append('/');
result.append(orig);
}
- if (result.length() == 1 && result[0] == '/')
+ if (result.size() == 1 && result[0] == '/')
return QFileSystemEntry(result, QFileSystemEntry::FromNativePath());
const bool isDir = result.endsWith('/');
@@ -757,7 +723,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
QFileSystemEntry resultingEntry(result, QFileSystemEntry::FromNativePath());
QString stringVersion = QDir::cleanPath(resultingEntry.filePath());
if (isDir)
- stringVersion.append(QLatin1Char('/'));
+ stringVersion.append(u'/');
return QFileSystemEntry(stringVersion);
}
@@ -796,7 +762,7 @@ QByteArray QFileSystemEngine::id(int fd)
QString QFileSystemEngine::resolveUserName(uint userId)
{
#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
- int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+ long size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
if (size_max == -1)
size_max = 1024;
QVarLengthArray<char, 1024> buf(size_max);
@@ -822,7 +788,7 @@ QString QFileSystemEngine::resolveUserName(uint userId)
QString QFileSystemEngine::resolveGroupName(uint groupId)
{
#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
- int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+ long size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
if (size_max == -1)
size_max = 1024;
QVarLengthArray<char, 1024> buf(size_max);
@@ -838,7 +804,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId)
struct group entry;
// Some large systems have more members than the POSIX max size
// Loop over by doubling the buffer size (upper limit 250k)
- for (unsigned size = size_max; size < 256000; size += size)
+ for (long size = size_max; size < 256000; size += size)
{
buf.resize(size);
// ERANGE indicates that the buffer was too small
@@ -851,7 +817,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId)
#endif
if (gr)
return QFile::decodeName(QByteArray(gr->gr_name));
-#else // Integrity || WASM
+#else // Integrity || WASM || VxWorks
Q_UNUSED(groupId);
#endif
return QString();
@@ -884,6 +850,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
what |= QFileSystemMetaData::DirectoryType;
}
+ if (what & QFileSystemMetaData::AliasType)
+ what |= QFileSystemMetaData::LinkType;
#endif
#ifdef UF_HIDDEN
if (what & QFileSystemMetaData::HiddenAttribute) {
@@ -1019,8 +987,11 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
#if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::AliasType) {
- if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
- data.entryFlags |= QFileSystemMetaData::AliasType;
+ if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey)) {
+ // kCFURLIsAliasFileKey includes symbolic links, so filter those out
+ if (!(data.entryFlags & QFileSystemMetaData::LinkType))
+ data.entryFlags |= QFileSystemMetaData::AliasType;
+ }
data.knownFlagsMask |= QFileSystemMetaData::AliasType;
}
@@ -1035,7 +1006,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (what & QFileSystemMetaData::HiddenAttribute
&& !data.isHidden()) {
QString fileName = entry.fileName();
- if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
+ if (fileName.startsWith(u'.')
#if defined(Q_OS_DARWIN)
|| (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
#endif
@@ -1131,7 +1102,7 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, mode_t mode
return false;
// mkdir failed because the parent dir doesn't exist, so try to create it
- int slash = nativeName.lastIndexOf('/');
+ qsizetype slash = nativeName.lastIndexOf('/');
if (slash < 1)
return false;
@@ -1149,22 +1120,21 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, mode_t mode
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents,
std::optional<QFile::Permissions> permissions)
{
- QString dirName = entry.filePath();
+ QByteArray dirName = entry.nativeFilePath();
Q_CHECK_FILE_NAME(dirName, false);
// Darwin doesn't support trailing /'s, so remove for everyone
- while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/')))
+ while (dirName.size() > 1 && dirName.endsWith(u'/'))
dirName.chop(1);
// try to mkdir this directory
- QByteArray nativeName = QFile::encodeName(dirName);
mode_t mode = permissions ? QtPrivate::toMode_t(*permissions) : 0777;
- if (QT_MKDIR(nativeName, mode) == 0)
+ if (QT_MKDIR(dirName, mode) == 0)
return true;
if (!createParents)
return false;
- return createDirectoryWithParents(nativeName, mode, false);
+ return createDirectoryWithParents(dirName, mode, false);
}
//static
@@ -1174,7 +1144,7 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo
if (removeEmptyParents) {
QString dirName = QDir::cleanPath(entry.filePath());
- for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
+ for (qsizetype oldslash = 0, slash=dirName.size(); slash > 0; oldslash = slash) {
const QByteArray chunk = QFile::encodeName(dirName.left(slash));
QT_STATBUF st;
if (QT_STAT(chunk.constData(), &st) != -1) {
@@ -1204,42 +1174,169 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
return false;
}
-#ifndef Q_OS_DARWIN
+#ifdef Q_OS_DARWIN
+// see qfilesystemengine_mac.mm
+#elif defined(QT_BOOTSTRAPPED) || !defined(AT_FDCWD)
+// bootstrapped tools don't need this, and we don't want QStorageInfo
+//static
+bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &, QFileSystemEntry &,
+ QSystemError &error)
+{
+ error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
+ return false;
+}
+#else
/*
Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
*/
-// bootstrapped tools don't need this, and we don't want QStorageInfo
-#ifndef QT_BOOTSTRAPPED
-static QString freeDesktopTrashLocation(const QString &sourcePath)
+namespace {
+struct FreeDesktopTrashOperation
{
- auto makeTrashDir = [](const QDir &topDir, const QString &trashDir) -> QString {
- auto ownerPerms = QFileDevice::ReadOwner
- | QFileDevice::WriteOwner
- | QFileDevice::ExeOwner;
- QString targetDir = topDir.filePath(trashDir);
- // deliberately not using mkpath, since we want to fail if topDir doesn't exist
- if (topDir.mkdir(trashDir))
- QFile::setPermissions(targetDir, ownerPerms);
- if (QFileInfo(targetDir).isDir())
- return targetDir;
- return QString();
- };
- auto isSticky = [](const QFileInfo &fileInfo) -> bool {
- struct stat st;
- if (stat(QFile::encodeName(fileInfo.absoluteFilePath()).constData(), &st) == 0)
- return st.st_mode & S_ISVTX;
+ /*
+ "A trash directory contains two subdirectories, named info and files."
+ */
+ QString trashPath;
+ int filesDirFd = -1;
+ int infoDirFd = -1;
+ qsizetype volumePrefixLength = 0;
- return false;
- };
+ // relative file paths to the filesDirFd and infoDirFd from above
+ QByteArray tempTrashFileName;
+ QByteArray infoFilePath;
+
+ int infoFileFd = -1; // if we've already opened it
+ ~FreeDesktopTrashOperation()
+ {
+ close();
+ }
+
+ constexpr bool isTrashDirOpen() const { return filesDirFd != -1 && infoDirFd != -1; }
+
+ void close()
+ {
+ int savedErrno = errno;
+ if (infoFileFd != -1) {
+ Q_ASSERT(infoDirFd != -1);
+ Q_ASSERT(!infoFilePath.isEmpty());
+ Q_ASSERT(!trashPath.isEmpty());
+
+ QT_CLOSE(infoFileFd);
+ unlinkat(infoDirFd, infoFilePath, 0);
+ infoFileFd = -1;
+ }
+ if (!tempTrashFileName.isEmpty()) {
+ Q_ASSERT(filesDirFd != -1);
+ unlinkat(filesDirFd, tempTrashFileName, 0);
+ }
+ if (filesDirFd >= 0)
+ QT_CLOSE(filesDirFd);
+ if (infoDirFd >= 0)
+ QT_CLOSE(infoDirFd);
+ filesDirFd = infoDirFd = -1;
+ errno = savedErrno;
+ }
+
+ bool tryCreateInfoFile(const QString &filePath, QSystemError &error)
+ {
+ QByteArray p = QFile::encodeName(filePath) + ".trashinfo";
+ infoFileFd = qt_safe_openat(infoDirFd, p, QT_OPEN_RDWR | QT_OPEN_CREAT | QT_OPEN_EXCL, 0666);
+ if (infoFileFd < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+ infoFilePath = std::move(p);
+ return true;
+ }
+
+ void commit()
+ {
+ QT_CLOSE(infoFileFd);
+ infoFileFd = -1;
+ tempTrashFileName = {};
+ }
+
+ // opens a directory and returns the file descriptor
+ static int openDirFd(int dfd, const char *path, int mode = 0)
+ {
+ mode |= QT_OPEN_RDONLY | O_NOFOLLOW | O_DIRECTORY;
+ return qt_safe_openat(dfd, path, mode);
+ }
+
+ // opens an XDG Trash directory that is a subdirectory of dfd, creating if necessary
+ static int openOrCreateDir(int dfd, const char *path)
+ {
+ // try to open it as a dir, first
+ int fd = openDirFd(dfd, path);
+ if (fd >= 0 || errno != ENOENT)
+ return fd;
+
+ // try to mkdirat
+ if (mkdirat(dfd, path, 0700) < 0)
+ return -1;
+
+ // try to open it again
+ return openDirFd(dfd, path);
+ }
+
+ // opens or makes the XDG Trash hierarchy on parentfd (may be -1) called targetDir
+ bool getTrashDir(int parentfd, QString targetDir, const QFileSystemEntry &source,
+ QSystemError &error)
+ {
+ if (parentfd == AT_FDCWD)
+ trashPath = targetDir;
+ QByteArray nativePath = QFile::encodeName(targetDir);
+
+ // open the directory
+ int trashfd = openOrCreateDir(parentfd, nativePath);
+ if (trashfd < 0 && errno != ENOENT) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
- QString trash;
- const QStorageInfo sourceStorage(sourcePath);
- const QStorageInfo homeStorage(QDir::home());
- // We support trashing of files outside the users home partition
- if (sourceStorage != homeStorage) {
- const QLatin1String dotTrash(".Trash");
- QDir topDir(sourceStorage.rootPath());
+ // check if it is ours (even if we've just mkdirat'ed it)
+ if (QT_STATBUF st; QT_FSTAT(trashfd, &st) < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ } else if (st.st_uid != getuid()) {
+ error = QSystemError(EPERM, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ filesDirFd = openOrCreateDir(trashfd, "files");
+ if (filesDirFd >= 0) {
+ // try to link our file-to-be-trashed here
+ QTemporaryFileName tfn("XXXXXX"_L1);
+ for (int i = 0; i < 16; ++i) {
+ QByteArray attempt = tfn.generateNext();
+ if (linkat(AT_FDCWD, source.nativeFilePath(), filesDirFd, attempt, 0) == 0) {
+ tempTrashFileName = std::move(attempt);
+ break;
+ }
+ if (errno != EEXIST)
+ break;
+ }
+
+ // man 2 link on Linux has:
+ // EPERM The filesystem containing oldpath and newpath does not
+ // support the creation of hard links.
+ // EPERM oldpath is a directory.
+ // EPERM oldpath is marked immutable or append‐only.
+ // EMLINK The file referred to by oldpath already has the maximum
+ // number of links to it.
+ if (!tempTrashFileName.isEmpty() || errno == EPERM || errno == EMLINK)
+ infoDirFd = openOrCreateDir(trashfd, "info");
+ }
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ if (infoDirFd < 0)
+ close();
+ QT_CLOSE(trashfd);
+ return infoDirFd >= 0;
+ }
+
+ bool openMountPointTrashLocation(const QFileSystemEntry &source,
+ const QStorageInfo &sourceStorage, QSystemError &error)
+ {
/*
Method 1:
"An administrator can create an $topdir/.Trash directory. The permissions on this
@@ -1250,21 +1347,31 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
(if it supports trashing in top directories) MUST check for the presence
of $topdir/.Trash."
*/
- const QString userID = QString::number(::getuid());
- if (topDir.cd(dotTrash)) {
- const QFileInfo trashInfo(topDir.path());
- // we MUST check that the sticky bit is set, and that it is not a symlink
- if (trashInfo.isSymLink()) {
+ const auto dotTrash = "/.Trash"_L1;
+ const QString userID = QString::number(::getuid());
+ QFileSystemEntry dotTrashDir(sourceStorage.rootPath() + dotTrash);
+
+ // we MUST check that the sticky bit is set, and that it is not a symlink
+ int genericTrashFd = openDirFd(AT_FDCWD, dotTrashDir.nativeFilePath());
+ QT_STATBUF st = {};
+ if (genericTrashFd < 0 && errno != ENOENT && errno != EACCES) {
+ // O_DIRECTORY + O_NOFOLLOW produces ENOTDIR on Linux
+ if (QT_LSTAT(dotTrashDir.nativeFilePath(), &st) == 0 && S_ISLNK(st.st_mode)) {
// we SHOULD report the failed check to the administrator
qCritical("Warning: '%s' is a symlink to '%s'",
- trashInfo.absoluteFilePath().toLocal8Bit().constData(),
- trashInfo.symLinkTarget().toLatin1().constData());
- } else if (!isSticky(trashInfo)) {
+ dotTrashDir.nativeFilePath().constData(),
+ qt_readlink(dotTrashDir.nativeFilePath()).constData());
+ error = QSystemError(ELOOP, QSystemError::StandardLibraryError);
+ }
+ } else if (genericTrashFd >= 0) {
+ QT_FSTAT(genericTrashFd, &st);
+ if ((st.st_mode & S_ISVTX) == 0) {
// we SHOULD report the failed check to the administrator
qCritical("Warning: '%s' doesn't have sticky bit set!",
- trashInfo.absoluteFilePath().toLocal8Bit().constData());
- } else if (trashInfo.isDir()) {
+ dotTrashDir.nativeFilePath().constData());
+ error = QSystemError(EPERM, QSystemError::StandardLibraryError);
+ } else {
/*
"If the directory exists and passes the checks, a subdirectory of the
$topdir/.Trash directory is to be used as the user's trash directory
@@ -1274,9 +1381,14 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
the implementation MUST immediately create it, without any warnings or
delays for the user."
*/
- trash = makeTrashDir(topDir, userID);
+ if (getTrashDir(genericTrashFd, userID, source, error)) {
+ // recreate the resulting path
+ trashPath = dotTrashDir.filePath() + u'/' + userID;
+ }
}
+ QT_CLOSE(genericTrashFd);
}
+
/*
Method 2:
"If an $topdir/.Trash directory is absent, an $topdir/.Trash-$uid directory is to be
@@ -1284,138 +1396,146 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
file, if an $topdir/.Trash-$uid directory does not exist, the implementation MUST
immediately create it, without any warnings or delays for the user."
*/
- if (trash.isEmpty()) {
- topDir = QDir(sourceStorage.rootPath());
- const QString userTrashDir = dotTrash + QLatin1Char('-') + userID;
- trash = makeTrashDir(topDir, userTrashDir);
+ if (!isTrashDirOpen())
+ getTrashDir(AT_FDCWD, sourceStorage.rootPath() + dotTrash + u'-' + userID, source, error);
+
+ if (isTrashDirOpen()) {
+ volumePrefixLength = sourceStorage.rootPath().size();
+ if (volumePrefixLength == 1)
+ volumePrefixLength = 0; // isRoot
+ else
+ ++volumePrefixLength; // to include the slash
}
+ return isTrashDirOpen();
}
- /*
- "If both (1) and (2) fail [...], the implementation MUST either trash the
- file into the user's “home trash” or refuse to trash it."
-
- We trash the file into the user's home trash.
- "Its name and location are $XDG_DATA_HOME/Trash"; $XDG_DATA_HOME is what
- QStandardPaths returns for GenericDataLocation. If that doesn't exist, then
- we are not running on a freedesktop.org-compliant environment, and give up.
- */
- if (trash.isEmpty()) {
- QDir topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
- trash = makeTrashDir(topDir, QLatin1String("Trash"));
- if (!QFileInfo(trash).isDir()) {
- qWarning("Unable to establish trash directory in %s",
- topDir.path().toLocal8Bit().constData());
- }
+ bool openHomeTrashLocation(const QFileSystemEntry &source, QSystemError &error)
+ {
+ QString topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+ return getTrashDir(AT_FDCWD, topDir + "/Trash"_L1, source, error);
}
- return trash;
-}
-#endif // QT_BOOTSTRAPPED
+ bool findTrashFor(const QFileSystemEntry &source, QSystemError &error)
+ {
+ /*
+ First, try the standard Trash in $XDG_DATA_DIRS:
+ "Its name and location are $XDG_DATA_HOME/Trash"; $XDG_DATA_HOME is what
+ QStandardPaths returns for GenericDataLocation. If that doesn't exist, then
+ we are not running on a freedesktop.org-compliant environment, and give up.
+ */
+ if (openHomeTrashLocation(source, error))
+ return true;
+ if (error.errorCode != EXDEV)
+ return false;
+
+ // didn't work, try to find the trash outside the home filesystem
+ const QStorageInfo sourceStorage(source.filePath());
+ if (!sourceStorage.isValid())
+ return false;
+ return openMountPointTrashLocation(source, sourceStorage, error);
+ }
+};
+} // unnamed namespace
//static
bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
QFileSystemEntry &newLocation, QSystemError &error)
{
-#ifdef QT_BOOTSTRAPPED
- Q_UNUSED(source);
- Q_UNUSED(newLocation);
- error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
- return false;
-#else
- const QFileInfo sourceInfo(source.filePath());
- if (!sourceInfo.exists()) {
- error = QSystemError(ENOENT, QSystemError::StandardLibraryError);
+ const QFileSystemEntry sourcePath = [&] {
+ if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) {
+ path.chop(1);
+ return absoluteName(QFileSystemEntry(path));
+ }
+ return absoluteName(source);
+ }();
+ FreeDesktopTrashOperation op;
+ if (!op.findTrashFor(sourcePath, error))
return false;
- }
- const QString sourcePath = sourceInfo.absoluteFilePath();
- QDir trashDir(freeDesktopTrashLocation(sourcePath));
- if (!trashDir.exists())
- return false;
- /*
- "A trash directory contains two subdirectories, named info and files."
- */
- const QLatin1String filesDir("files");
- const QLatin1String infoDir("info");
- trashDir.mkdir(filesDir);
- int savedErrno = errno;
- trashDir.mkdir(infoDir);
- if (!savedErrno)
- savedErrno = errno;
- if (!trashDir.exists(filesDir) || !trashDir.exists(infoDir)) {
- error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
- return false;
- }
/*
"The $trash/files directory contains the files and directories that were trashed.
The names of files in this directory are to be determined by the implementation;
the only limitation is that they must be unique within the directory. Even if a
file with the same name and location gets trashed many times, each subsequent
trashing must not overwrite a previous copy."
- */
- const QString trashedName = sourceInfo.isDir()
- ? QDir(sourcePath).dirName()
- : sourceInfo.fileName();
- QString uniqueTrashedName = QLatin1Char('/') + trashedName;
- QString infoFileName;
- int counter = 0;
- QFile infoFile;
- auto makeUniqueTrashedName = [trashedName, &counter]() -> QString {
- ++counter;
- return QString(QLatin1String("/%1-%2"))
- .arg(trashedName)
- .arg(counter, 4, 10, QLatin1Char('0'));
- };
- do {
- while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName))
- uniqueTrashedName = makeUniqueTrashedName();
- /*
- "The $trash/info directory contains an "information file" for every file and directory
- in $trash/files. This file MUST have exactly the same name as the file or directory in
- $trash/files, plus the extension ".trashinfo"
- [...]
- When trashing a file or directory, the implementation MUST create the corresponding
- file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion,
- so that if two processes try to trash files with the same filename this will result
- in two different trash files. On Unix-like systems this is done by generating a
- filename, and then opening with O_EXCL. If that succeeds the creation was atomic
- (at least on the same machine), if it fails you need to pick another filename."
- */
- infoFileName = trashDir.filePath(infoDir)
- + uniqueTrashedName + QLatin1String(".trashinfo");
- infoFile.setFileName(infoFileName);
- if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text))
- uniqueTrashedName = makeUniqueTrashedName();
- } while (!infoFile.isOpen());
- const QString targetPath = trashDir.filePath(filesDir) + uniqueTrashedName;
- const QFileSystemEntry target(targetPath);
-
- /*
- We might fail to rename if source and target are on different file systems.
- In that case, we don't try further, i.e. copying and removing the original
- is usually not what the user would expect to happen.
+ We first try the unchanged base name, then try something different if it collides.
+
+ "The $trash/info directory contains an "information file" for every file and directory
+ in $trash/files. This file MUST have exactly the same name as the file or directory in
+ $trash/files, plus the extension ".trashinfo"
+ [...]
+ When trashing a file or directory, the implementation MUST create the corresponding
+ file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion,
+ so that if two processes try to trash files with the same filename this will result
+ in two different trash files. On Unix-like systems this is done by generating a
+ filename, and then opening with O_EXCL. If that succeeds the creation was atomic
+ (at least on the same machine), if it fails you need to pick another filename."
*/
- if (!renameFile(source, target, error)) {
- infoFile.close();
- infoFile.remove();
- return false;
+ QString uniqueTrashedName = sourcePath.fileName();
+ if (!op.tryCreateInfoFile(uniqueTrashedName, error) && error.errorCode == EEXIST) {
+ // we'll use a counter, starting with the file's inode number to avoid
+ // collisions
+ qulonglong counter;
+ if (QT_STATBUF st; Q_LIKELY(QT_STAT(source.nativeFilePath(), &st) == 0)) {
+ counter = st.st_ino;
+ } else {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ QString uniqueTrashBase = std::move(uniqueTrashedName);
+ for (;;) {
+ uniqueTrashedName = QString::asprintf("%ls-%llu", qUtf16Printable(uniqueTrashBase),
+ counter++);
+ if (op.tryCreateInfoFile(uniqueTrashedName, error))
+ break;
+ if (error.errorCode != EEXIST)
+ return false;
+ };
}
QByteArray info =
"[Trash Info]\n"
- "Path=" + sourcePath.toUtf8() + "\n"
- "DeletionDate=" + QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-ddThh:mm:ss")).toUtf8()
+ "Path=" + QUrl::toPercentEncoding(source.filePath().mid(op.volumePrefixLength), "/") + "\n"
+ "DeletionDate=" + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8()
+ "\n";
- infoFile.write(info);
- infoFile.close();
+ if (QT_WRITE(op.infoFileFd, info.data(), info.size()) < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ /*
+ If we've already linked the file-to-be-trashed into the trash
+ directory, we know it's in the same mountpoint and we won't get ENOSPC
+ renaming the temporary file to the target name either.
+ */
+ bool renamed;
+ if (op.tempTrashFileName.isEmpty()) {
+ /*
+ We did not get a link (we're trying to trash a directory or on a
+ filesystem that doesn't support hardlinking), so rename straight
+ from the original name. We might fail to rename if source and target
+ are on different file systems.
+ */
+ renamed = renameat(AT_FDCWD, source.nativeFilePath(), op.filesDirFd,
+ QFile::encodeName(uniqueTrashedName)) == 0;
+ } else {
+ renamed = renameat(op.filesDirFd, op.tempTrashFileName, op.filesDirFd,
+ QFile::encodeName(uniqueTrashedName)) == 0;
+ if (renamed)
+ removeFile(source, error); // success, delete the original file
+ }
+ if (!renamed) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
- newLocation = QFileSystemEntry(targetPath);
+ op.commit();
+ newLocation = QFileSystemEntry(op.trashPath + "/files/"_L1 + uniqueTrashedName);
return true;
-#endif // QT_BOOTSTRAPPED
}
-#endif // Q_OS_DARWIN
+#endif // !Q_OS_DARWIN && !QT_BOOTSTRAPPED
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
@@ -1563,28 +1683,22 @@ bool QFileSystemEngine::setPermissions(int fd, QFile::Permissions permissions, Q
}
//static
-bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractFileEngine::FileTime time, QSystemError &error)
+bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QFile::FileTime time, QSystemError &error)
{
- if (!newDate.isValid() || time == QAbstractFileEngine::BirthTime ||
- time == QAbstractFileEngine::MetadataChangeTime) {
+ if (!newDate.isValid()
+ || time == QFile::FileBirthTime || time == QFile::FileMetadataChangeTime) {
error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
return false;
}
#if QT_CONFIG(futimens)
- struct timespec ts[2];
+ // UTIME_OMIT: leave file timestamp unchanged
+ struct timespec ts[2] = {{0, UTIME_OMIT}, {0, UTIME_OMIT}};
- ts[0].tv_sec = ts[1].tv_sec = 0;
- ts[0].tv_nsec = ts[1].tv_nsec = UTIME_OMIT;
-
- const qint64 msecs = newDate.toMSecsSinceEpoch();
-
- if (time == QAbstractFileEngine::AccessTime) {
- ts[0].tv_sec = msecs / 1000;
- ts[0].tv_nsec = (msecs % 1000) * 1000000;
- } else if (time == QAbstractFileEngine::ModificationTime) {
- ts[1].tv_sec = msecs / 1000;
- ts[1].tv_nsec = (msecs % 1000) * 1000000;
+ if (time == QFile::FileAccessTime || time == QFile::FileModificationTime) {
+ const int idx = time == QFile::FileAccessTime ? 0 : 1;
+ const std::chrono::milliseconds msecs{newDate.toMSecsSinceEpoch()};
+ ts[idx] = durationToTimespec(msecs);
}
if (futimens(fd, ts) == -1) {
@@ -1593,33 +1707,6 @@ bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractF
}
return true;
-#elif QT_CONFIG(futimes)
- struct timeval tv[2];
- QT_STATBUF st;
-
- if (QT_FSTAT(fd, &st) == -1) {
- error = QSystemError(errno, QSystemError::StandardLibraryError);
- return false;
- }
-
- GetFileTimes::get(&st, &tv[0], &tv[1]);
-
- const qint64 msecs = newDate.toMSecsSinceEpoch();
-
- if (time == QAbstractFileEngine::AccessTime) {
- tv[0].tv_sec = msecs / 1000;
- tv[0].tv_usec = (msecs % 1000) * 1000;
- } else if (time == QAbstractFileEngine::ModificationTime) {
- tv[1].tv_sec = msecs / 1000;
- tv[1].tv_usec = (msecs % 1000) * 1000;
- }
-
- if (futimes(fd, tv) == -1) {
- error = QSystemError(errno, QSystemError::StandardLibraryError);
- return false;
- }
-
- return true;
#else
Q_UNUSED(fd);
error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
@@ -1637,13 +1724,13 @@ QString QFileSystemEngine::homePath()
QString QFileSystemEngine::rootPath()
{
- return QLatin1String("/");
+ return u"/"_s;
}
QString QFileSystemEngine::tempPath()
{
#ifdef QT_UNIX_TEMP_PATH_OVERRIDE
- return QLatin1String(QT_UNIX_TEMP_PATH_OVERRIDE);
+ return QT_UNIX_TEMP_PATH_OVERRIDE ""_L1;
#else
QString temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty()) {
@@ -1653,7 +1740,7 @@ QString QFileSystemEngine::tempPath()
temp = QString::fromCFString((CFStringRef)nsPath);
#endif
} else {
- temp = QLatin1String(_PATH_TMP);
+ temp = _PATH_TMP ""_L1;
}
}
return QDir(QDir::cleanPath(temp)).canonicalPath();
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 60285cfea8..3ec32e31a1 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemengine_p.h"
#include "qoperatingsystemversion.h"
@@ -56,6 +20,7 @@
#if QT_CONFIG(regularexpression)
#include "qregularexpression.h"
#endif
+#include "qstring.h"
#include <sys/types.h>
#include <direct.h>
@@ -72,6 +37,8 @@
#define SECURITY_WIN32
#include <security.h>
+#include <QtCore/private/qfunctions_win_p.h>
+
#ifndef SPI_GETPLATFORMTYPE
#define SPI_GETPLATFORMTYPE 257
#endif
@@ -137,12 +104,6 @@ typedef struct _REPARSE_DATA_BUFFER {
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
-#if defined(QT_BOOTSTRAPPED)
-# define QT_FEATURE_fslibs -1
-#else
-# define QT_FEATURE_fslibs 1
-#endif // QT_BOOTSTRAPPED
-
#if QT_CONFIG(fslibs)
#include <aclapi.h>
#include <authz.h>
@@ -151,9 +112,12 @@ static PSID currentUserSID = nullptr;
static PSID currentGroupSID = nullptr;
static PSID worldSID = nullptr;
static HANDLE currentUserImpersonatedToken = nullptr;
+#endif // fslibs
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+#if QT_CONFIG(fslibs)
namespace {
struct GlobalSid
{
@@ -407,20 +371,46 @@ constexpr NonSpecificPermissions toNonSpecificPermissions(PermissionTag tag,
return NonSpecificPermissions::fromInt((permissions.toInt() >> int(tag)) & 0x7);
}
+[[maybe_unused]] // Not currently used; included to show how to do it (without bit-rotting).
constexpr QFileDevice::Permissions toSpecificPermissions(PermissionTag tag,
NonSpecificPermissions permissions)
{
return QFileDevice::Permissions::fromInt(permissions.toInt() << int(tag));
}
-QT_END_NAMESPACE
-
} // anonymous namespace
#endif // QT_CONFIG(fslibs)
-QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(6,6)
+int qt_ntfs_permission_lookup = 0;
+#endif
+
+static QBasicAtomicInt qt_ntfs_permission_lookup_v2 = Q_BASIC_ATOMIC_INITIALIZER(0);
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+bool qEnableNtfsPermissionChecks() noexcept
+{
+ return qt_ntfs_permission_lookup_v2.fetchAndAddRelaxed(1)
+QT_IF_DEPRECATED_SINCE(6, 6, /*nothing*/, + qt_ntfs_permission_lookup)
+ != 0;
+}
+
+bool qDisableNtfsPermissionChecks() noexcept
+{
+ return qt_ntfs_permission_lookup_v2.fetchAndSubRelaxed(1)
+QT_IF_DEPRECATED_SINCE(6, 6, /*nothing*/, + qt_ntfs_permission_lookup)
+ == 1;
+}
-Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
+bool qAreNtfsPermissionChecksEnabled() noexcept
+{
+ return qt_ntfs_permission_lookup_v2.loadRelaxed()
+QT_IF_DEPRECATED_SINCE(6, 6, /*nothing*/, + qt_ntfs_permission_lookup)
+ ;
+}
+QT_WARNING_POP
/*!
\class QNativeFilePermissions
@@ -476,8 +466,8 @@ QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permis
ACCESS_MASK denyMask, allowMask;
};
- auto makeMasks = [this, isDir](NonSpecificPermissions allowPermissions,
- NonSpecificPermissions denyPermissions, bool owner) {
+ auto makeMasks = [isDir](NonSpecificPermissions allowPermissions,
+ NonSpecificPermissions denyPermissions, bool owner) {
constexpr ACCESS_MASK AllowRead = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA;
constexpr ACCESS_MASK DenyRead = FILE_READ_DATA | FILE_READ_EA;
@@ -593,6 +583,9 @@ QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permis
sa.bInheritHandle = FALSE;
isNull = false;
+#else
+ Q_UNUSED(perms);
+ Q_UNUSED(isDir);
#endif // QT_CONFIG(fslibs)
ok = true;
}
@@ -602,7 +595,7 @@ QNativeFilePermissions::QNativeFilePermissions(std::optional<QFileDevice::Permis
Return pointer to a \c SECURITY_ATTRIBUTES object describing the permissions.
The returned pointer many be null if default permissions were requested or
- during bootstrap. The calles must call \c isOk() to check if the object
+ during bootstrap. The callers must call \c isOk() to check if the object
was successfully constructed before using this method.
*/
SECURITY_ATTRIBUTES *QNativeFilePermissions::securityAttributes()
@@ -681,14 +674,14 @@ static QString readSymLink(const QFileSystemEntry &link)
#if QT_CONFIG(fslibs) && QT_CONFIG(regularexpression)
initGlobalSid();
- QRegularExpression matchVolumeRe(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"),
+ QRegularExpression matchVolumeRe("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"_L1,
QRegularExpression::CaseInsensitiveOption);
auto matchVolume = matchVolumeRe.match(result);
if (matchVolume.hasMatch()) {
Q_ASSERT(matchVolume.capturedStart() == 0);
DWORD len;
wchar_t buffer[MAX_PATH];
- const QString volumeName = QLatin1String("\\\\?\\") + matchVolume.captured();
+ const QString volumeName = "\\\\?\\"_L1 + matchVolume.captured();
if (GetVolumePathNamesForVolumeName(reinterpret_cast<LPCWSTR>(volumeName.utf16()),
buffer, MAX_PATH, &len)
!= 0) {
@@ -705,21 +698,16 @@ static QString readLink(const QFileSystemEntry &link)
#if QT_CONFIG(fslibs)
QString ret;
- bool neededCoInit = false;
IShellLink *psl; // pointer to IShellLink i/f
WIN32_FIND_DATA wfd;
wchar_t szGotPath[MAX_PATH];
+ QComHelper comHelper;
+
// Get pointer to the IShellLink interface.
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
(LPVOID *)&psl);
- if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(nullptr);
- hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
- (LPVOID *)&psl);
- }
if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
IPersistFile *ppf;
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
@@ -735,8 +723,6 @@ static QString readLink(const QFileSystemEntry &link)
}
psl->Release();
}
- if (neededCoInit)
- CoUninitialize();
return ret;
#else
@@ -748,10 +734,10 @@ static QString readLink(const QFileSystemEntry &link)
static bool uncShareExists(const QString &server)
{
// This code assumes the UNC path is always like \\?\UNC\server...
- const auto parts = QStringView{server}.split(QLatin1Char('\\'), Qt::SkipEmptyParts);
+ const auto parts = QStringView{server}.split(u'\\', Qt::SkipEmptyParts);
if (parts.count() >= 3) {
QStringList shares;
- if (QFileSystemEngine::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(2), &shares))
+ if (QFileSystemEngine::uncListSharesOnServer("\\\\"_L1 + parts.at(2), &shares))
return parts.count() < 4
|| shares.contains(parts.at(3).toString(), Qt::CaseInsensitive);
}
@@ -761,11 +747,11 @@ static bool uncShareExists(const QString &server)
static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
{
// path should not end with a trailing slash
- while (path.endsWith(QLatin1Char('\\')))
+ while (path.endsWith(u'\\'))
path.chop(1);
// can't handle drives
- if (!path.endsWith(QLatin1Char(':'))) {
+ if (!path.endsWith(u':')) {
HANDLE hFind = ::FindFirstFile((wchar_t*)path.utf16(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
::FindClose(hFind);
@@ -776,7 +762,6 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
return false;
}
-#if defined(__IFileOperation_INTERFACE_DEFINED__)
class FileOperationProgressSink : public IFileOperationProgressSink
{
public:
@@ -837,9 +822,10 @@ public:
return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL;
}
HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD /* dwFlags */, IShellItem * /* psiItem */,
- HRESULT /* hrDelete */,
+ HRESULT hrDelete,
IShellItem *psiNewlyCreated) override
{
+ deleteResult = hrDelete;
if (psiNewlyCreated) {
wchar_t *pszName = nullptr;
psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
@@ -860,10 +846,10 @@ public:
HRESULT STDMETHODCALLTYPE ResumeTimer() override { return S_OK; }
QString targetPath;
+ HRESULT deleteResult = S_OK;
private:
ULONG ref;
};
-#endif
bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list)
{
@@ -900,6 +886,18 @@ void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
QFileSystemMetaData &data)
{
+ QFileSystemEntry ret = getRawLinkPath(link, data);
+ if (!ret.isEmpty() && ret.isRelative()) {
+ QString target = absoluteName(link).path() + u'/' + ret.filePath();
+ ret = QFileSystemEntry(QDir::cleanPath(target));
+ }
+ return ret;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::getRawLinkPath(const QFileSystemEntry &link,
+ QFileSystemMetaData &data)
+{
Q_CHECK_FILE_NAME(link, link);
if (data.missingFlags(QFileSystemMetaData::LinkType))
@@ -910,12 +908,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
target = readLink(link);
else if (data.isLink())
target = readSymLink(link);
- QFileSystemEntry ret(target);
- if (!target.isEmpty() && ret.isRelative()) {
- target.prepend(absoluteName(link).path() + QLatin1Char('/'));
- ret = QFileSystemEntry(QDir::cleanPath(target));
- }
- return ret;
+ return QFileSystemEntry(target);
}
//static
@@ -932,7 +925,7 @@ QFileSystemEntry QFileSystemEngine::junctionTarget(const QFileSystemEntry &link,
target = readSymLink(link);
QFileSystemEntry ret(target);
if (!target.isEmpty() && ret.isRelative()) {
- target.prepend(absoluteName(link).path() + QLatin1Char('/'));
+ target.prepend(absoluteName(link).path() + u'/');
ret = QFileSystemEntry(QDir::cleanPath(target));
}
return ret;
@@ -975,8 +968,8 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
// (which is an invalid filename) this function will strip the space off and viola,
// the file is later reported as existing. Therefore, we re-add the whitespace that
// was at the end of path in order to keep the filename invalid.
- if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' '))
- absPath.append(QLatin1Char(' '));
+ if (!path.isEmpty() && path.at(path.size() - 1) == u' ')
+ absPath.append(u' ');
return absPath;
}
@@ -993,17 +986,17 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
else
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
} else {
- ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
+ ret = QDir::cleanPath(QDir::currentPath() + u'/' + entry.filePath());
}
// The path should be absolute at this point.
// From the docs :
// Absolute paths begin with the directory separator "/"
// (optionally preceded by a drive specification under Windows).
- if (ret.at(0) != QLatin1Char('/')) {
+ if (ret.at(0) != u'/') {
Q_ASSERT(ret.length() >= 2);
Q_ASSERT(ret.at(0).isLetter());
- Q_ASSERT(ret.at(1) == QLatin1Char(':'));
+ Q_ASSERT(ret.at(1) == u':');
// Force uppercase drive letters.
ret[0] = ret.at(0).toUpper();
@@ -1076,7 +1069,7 @@ QByteArray QFileSystemEngine::id(HANDLE fHandle)
//static
bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
- QAbstractFileEngine::FileTime time, QSystemError &error)
+ QFile::FileTime time, QSystemError &error)
{
FILETIME fTime;
FILETIME *pLastWrite = nullptr;
@@ -1084,15 +1077,15 @@ bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
FILETIME *pCreationTime = nullptr;
switch (time) {
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
pLastWrite = &fTime;
break;
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
pLastAccess = &fTime;
break;
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
pCreationTime = &fTime;
break;
@@ -1115,8 +1108,7 @@ QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEng
{
QString name;
#if QT_CONFIG(fslibs)
- extern int qt_ntfs_permission_lookup;
- if (qt_ntfs_permission_lookup > 0) {
+ if (qAreNtfsPermissionChecksEnabled()) {
initGlobalSid();
{
PSID pOwner = 0;
@@ -1170,7 +1162,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
QFileSystemMetaData::MetaDataFlags what)
{
#if QT_CONFIG(fslibs)
- if (qt_ntfs_permission_lookup > 0) {
+ if (qAreNtfsPermissionChecksEnabled()) {
initGlobalSid();
QString fname = entry.nativeFilePath();
@@ -1196,7 +1188,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
// Check for generic permissions and file-specific bits that most closely
// represent POSIX permissions.
- // Contants like FILE_GENERIC_{READ,WRITE,EXECUTE} cannot be used
+ // Constants like FILE_GENERIC_{READ,WRITE,EXECUTE} cannot be used
// here because they contain permission bits shared between all of them.
if (accessMask & (GENERIC_READ | FILE_READ_DATA))
data.entryFlags |= readFlags;
@@ -1263,9 +1255,8 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
QString fname = entry.filePath();
QString ext = fname.right(4).toLower();
- if (data.isDirectory() || ext == QLatin1String(".exe") || ext == QLatin1String(".com")
- || ext == QLatin1String(".bat") || ext == QLatin1String(".pif")
- || ext == QLatin1String(".cmd")) {
+ if (data.isDirectory() || ext == ".exe"_L1 || ext == ".com"_L1
+ || ext == ".bat"_L1 || ext == ".pif"_L1 || ext == ".cmd"_L1) {
data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission
| QFileSystemMetaData::GroupExecutePermission
| QFileSystemMetaData::OtherExecutePermission
@@ -1300,7 +1291,7 @@ static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaDa
DWORD drivesBitmask = ::GetLogicalDrives();
::SetErrorMode(oldErrorMode);
int drivebit =
- 1 << (fname.filePath().at(0).toUpper().unicode() - QLatin1Char('A').unicode());
+ 1 << (fname.filePath().at(0).toUpper().unicode() - u'A');
if (drivesBitmask & drivebit) {
fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
entryExists = true;
@@ -1308,7 +1299,7 @@ static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaDa
} else {
const QString &path = fname.nativeFilePath();
bool is_dir = false;
- if (path.startsWith(QLatin1String("\\\\?\\UNC"))) {
+ if (path.startsWith("\\\\?\\UNC"_L1)) {
// UNC - stat doesn't work for all cases (Windows bug)
int s = path.indexOf(path.at(0),7);
if (s > 0) {
@@ -1397,7 +1388,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
// Check for ".lnk": Directories named ".lnk" should be skipped, corrupted
// link files should still be detected as links.
const QString origFilePath = entry.filePath();
- if (origFilePath.endsWith(QLatin1String(".lnk")) && !isDirPath(origFilePath, nullptr)) {
+ if (origFilePath.endsWith(".lnk"_L1) && !isDirPath(origFilePath, nullptr)) {
data.entryFlags |= QFileSystemMetaData::WinLnkType;
fname = QFileSystemEntry(readLink(entry));
} else {
@@ -1470,8 +1461,8 @@ static inline bool rmDir(const QString &path)
bool QFileSystemEngine::isDirPath(const QString &dirPath, bool *existed)
{
QString path = dirPath;
- if (path.length() == 2 && path.at(1) == QLatin1Char(':'))
- path += QLatin1Char('\\');
+ if (path.length() == 2 && path.at(1) == u':')
+ path += u'\\';
const QString longPath = QFSFileEnginePrivate::longFileName(path);
DWORD fileAttrib = ::GetFileAttributes(reinterpret_cast<const wchar_t*>(longPath.utf16()));
@@ -1500,11 +1491,11 @@ static bool createDirectoryWithParents(const QString &nativeName,
bool shouldMkdirFirst = true)
{
const auto isUNCRoot = [](const QString &nativeName) {
- return nativeName.startsWith(QLatin1String("\\\\"))
+ return nativeName.startsWith("\\\\"_L1)
&& nativeName.count(QDir::separator()) <= 3;
};
const auto isDriveName = [](const QString &nativeName) {
- return nativeName.size() == 2 && nativeName.at(1) == QLatin1Char(':');
+ return nativeName.size() == 2 && nativeName.at(1) == u':';
};
const auto isDir = [](const QString &nativeName) {
bool exists = false;
@@ -1572,7 +1563,7 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
const auto chunkRef = QStringView{dirName}.left(slash);
if (chunkRef.length() == 2 && chunkRef.at(0).isLetter()
- && chunkRef.at(1) == QLatin1Char(':')) {
+ && chunkRef.at(1) == u':') {
break;
}
const QString chunk = chunkRef.toString();
@@ -1592,8 +1583,8 @@ QString QFileSystemEngine::rootPath()
{
QString ret = QString::fromLatin1(qgetenv("SystemDrive"));
if (ret.isEmpty())
- ret = QLatin1String("c:");
- ret.append(QLatin1Char('/'));
+ ret = "c:"_L1;
+ ret.append(u'/');
return ret;
}
@@ -1651,13 +1642,13 @@ QString QFileSystemEngine::tempPath()
QString::fromWCharArray(tempPath, len);
}
if (!ret.isEmpty()) {
- while (ret.endsWith(QLatin1Char('\\')))
+ while (ret.endsWith(u'\\'))
ret.chop(1);
ret = QDir::fromNativeSeparators(ret);
}
if (ret.isEmpty()) {
- ret = QLatin1String("C:/tmp");
- } else if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
+ ret = "C:/tmp"_L1;
+ } else if (ret.length() >= 2 && ret[1] == u':')
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
return ret;
}
@@ -1680,23 +1671,20 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
QFileSystemEntry QFileSystemEngine::currentPath()
{
- QString ret;
- DWORD size = 0;
- wchar_t currentName[PATH_MAX];
- size = ::GetCurrentDirectory(PATH_MAX, currentName);
- if (size != 0) {
- if (size > PATH_MAX) {
- wchar_t *newCurrentName = new wchar_t[size];
- if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0)
- ret = QString::fromWCharArray(newCurrentName, size);
- delete [] newCurrentName;
- } else {
- ret = QString::fromWCharArray(currentName, size);
- }
+ QString ret(PATH_MAX, Qt::Uninitialized);
+ DWORD size = GetCurrentDirectoryW(PATH_MAX, reinterpret_cast<wchar_t *>(ret.data()));
+ if (size > PATH_MAX) {
+ // try again after enlarging the buffer
+ ret.resize(size);
+ size = GetCurrentDirectoryW(size, reinterpret_cast<wchar_t *>(ret.data()));
+
+ // note: the current directory may have changed underneath us; if the
+ // new one is even bigger, we may return a truncated string!
}
- if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
+ if (size >= 2 && ret.at(1) == u':')
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
- return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
+ ret.resize(size);
+ return QFileSystemEntry(std::move(ret), QFileSystemEntry::FromNativePath());
}
//static
@@ -1704,18 +1692,11 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
QSystemError &error)
{
bool ret = false;
+ QComHelper comHelper;
IShellLink *psl = nullptr;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void **>(&psl));
- bool neededCoInit = false;
- if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
- neededCoInit = true;
- CoInitialize(nullptr);
- hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink,
- reinterpret_cast<void **>(&psl));
- }
-
if (SUCCEEDED(hres)) {
const auto name = QDir::toNativeSeparators(source.filePath());
const auto pathName = QDir::toNativeSeparators(source.path());
@@ -1735,9 +1716,6 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
if (!ret)
error = QSystemError(::GetLastError(), QSystemError::NativeError);
- if (neededCoInit)
- CoUninitialize();
-
return ret;
}
@@ -1805,8 +1783,8 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
// we need the "display name" of the file, so can't use nativeAbsoluteFilePath
const QString sourcePath = QDir::toNativeSeparators(absoluteName(source).filePath());
-# if defined(__IFileOperation_INTERFACE_DEFINED__)
- CoInitialize(nullptr);
+ QComHelper comHelper;
+
IFileOperation *pfo = nullptr;
IShellItem *deleteItem = nullptr;
FileOperationProgressSink *sink = nullptr;
@@ -1819,7 +1797,6 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
deleteItem->Release();
if (pfo)
pfo->Release();
- CoUninitialize();
if (!SUCCEEDED(hres))
error = QSystemError(hres, QSystemError::NativeError);
});
@@ -1840,11 +1817,13 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
hres = pfo->PerformOperations();
if (!SUCCEEDED(hres))
return false;
- newLocation = QFileSystemEntry(sink->targetPath);
-# endif // no IFileOperation in SDK (mingw, likely) - fall back to SHFileOperation
+ if (!SUCCEEDED(sink->deleteResult)) {
+ error = QSystemError(sink->deleteResult, QSystemError::NativeError);
+ return false;
+ }
+ newLocation = QFileSystemEntry(sink->targetPath);
return true;
-
}
//static
@@ -1883,7 +1862,7 @@ static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
FileTimeToSystemTime(time, &sTime);
return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
- Qt::UTC);
+ QTimeZone::UTC);
}
QDateTime QFileSystemMetaData::birthTime() const
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index bb39a46642..ac1691d30e 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystementry_p.h"
@@ -48,14 +12,20 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+// Assigned to m_lastSeparator and m_firstDotInFileName to indicate resolveFilePath()
+// hasn't been called yet
+constexpr int Uninitialized = -2;
+
#ifdef Q_OS_WIN
static bool isUncRoot(const QString &server)
{
QString localPath = QDir::toNativeSeparators(server);
- if (!localPath.startsWith(QLatin1String("\\\\")))
+ if (!localPath.startsWith("\\\\"_L1))
return false;
- int idx = localPath.indexOf(QLatin1Char('\\'), 2);
+ int idx = localPath.indexOf(u'\\', 2);
if (idx == -1 || idx + 1 == localPath.length())
return true;
@@ -65,8 +35,8 @@ static bool isUncRoot(const QString &server)
static inline QString fixIfRelativeUncPath(const QString &path)
{
QString currentPath = QDir::currentPath();
- if (currentPath.startsWith(QLatin1String("//")))
- return currentPath % QChar(QLatin1Char('/')) % path;
+ if (currentPath.startsWith("//"_L1))
+ return currentPath % QChar(u'/') % path;
return path;
}
#endif
@@ -85,8 +55,8 @@ QFileSystemEntry::QFileSystemEntry()
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -98,8 +68,8 @@ QFileSystemEntry::QFileSystemEntry(const QString &filePath)
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /* dummy */)
: m_filePath(filePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -110,8 +80,8 @@ QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /*
*/
QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath /* dummy */)
: m_nativeFilePath(nativeFilePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -119,8 +89,8 @@ QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativeP
QFileSystemEntry::QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
m_nativeFilePath(nativeFilePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -166,7 +136,7 @@ QString QFileSystemEntry::fileName() const
{
findLastSeparator();
#if defined(Q_OS_WIN)
- if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == u':')
return m_filePath.mid(2);
#endif
return m_filePath.mid(m_lastSeparator + 1);
@@ -177,15 +147,15 @@ QString QFileSystemEntry::path() const
findLastSeparator();
if (m_lastSeparator == -1) {
#if defined(Q_OS_WIN)
- if (m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ if (m_filePath.length() >= 2 && m_filePath.at(1) == u':')
return m_filePath.left(2);
#endif
- return QString(QLatin1Char('.'));
+ return QString(u'.');
}
if (m_lastSeparator == 0)
- return QString(QLatin1Char('/'));
+ return QString(u'/');
#if defined(Q_OS_WIN)
- if (m_lastSeparator == 2 && m_filePath.at(1) == QLatin1Char(':'))
+ if (m_lastSeparator == 2 && m_filePath.at(1) == u':')
return m_filePath.left(m_lastSeparator + 1);
#endif
return m_filePath.left(m_lastSeparator);
@@ -201,7 +171,7 @@ QString QFileSystemEntry::baseName() const
length--;
}
#if defined(Q_OS_WIN)
- if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == u':')
return m_filePath.mid(2, length - 2);
#endif
return m_filePath.mid(m_lastSeparator + 1, length);
@@ -217,7 +187,7 @@ QString QFileSystemEntry::completeBaseName() const
length--;
}
#if defined(Q_OS_WIN)
- if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == u':')
return m_filePath.mid(2, length - 2);
#endif
return m_filePath.mid(m_lastSeparator + 1, length);
@@ -259,8 +229,8 @@ bool QFileSystemEntry::isAbsolute() const
&& m_filePath.at(1).unicode() == ':'
&& m_filePath.at(2).unicode() == '/')
|| (m_filePath.length() >= 2
- && m_filePath.at(0) == QLatin1Char('/')
- && m_filePath.at(1) == QLatin1Char('/')));
+ && m_filePath.at(0) == u'/'
+ && m_filePath.at(1) == u'/'));
}
#else
bool QFileSystemEntry::isRelative() const
@@ -285,8 +255,8 @@ bool QFileSystemEntry::isDriveRoot() const
bool QFileSystemEntry::isDriveRootPath(const QString &path)
{
return (path.length() == 3
- && path.at(0).isLetter() && path.at(1) == QLatin1Char(':')
- && path.at(2) == QLatin1Char('/'));
+ && path.at(0).isLetter() && path.at(1) == u':'
+ && path.at(2) == u'/');
}
QString QFileSystemEntry::removeUncOrLongPathPrefix(QString path)
@@ -320,7 +290,7 @@ QString QFileSystemEntry::removeUncOrLongPathPrefix(QString path)
bool QFileSystemEntry::isRootPath(const QString &path)
{
- if (path == QLatin1String("/")
+ if (path == "/"_L1
#if defined(Q_OS_WIN)
|| isDriveRootPath(path)
|| isUncRoot(path)
@@ -337,19 +307,24 @@ bool QFileSystemEntry::isRoot() const
return isRootPath(m_filePath);
}
+bool QFileSystemEntry::isEmpty() const
+{
+ return m_filePath.isEmpty() && m_nativeFilePath.isEmpty();
+}
+
// private methods
void QFileSystemEntry::findLastSeparator() const
{
- if (m_lastSeparator == -2) {
+ if (m_lastSeparator == Uninitialized) {
resolveFilePath();
- m_lastSeparator = m_filePath.lastIndexOf(QLatin1Char('/'));
+ m_lastSeparator = m_filePath.lastIndexOf(u'/');
}
}
void QFileSystemEntry::findFileNameSeparators() const
{
- if (m_firstDotInFileName == -2) {
+ if (m_firstDotInFileName == Uninitialized) {
resolveFilePath();
int firstDotInFileName = -1;
int lastDotInFileName = -1;
@@ -402,7 +377,7 @@ bool QFileSystemEntry::isClean() const
bool dotok = true; // checking for ".." or "." starts to relative paths
bool slashok = true;
for (QString::const_iterator iter = m_filePath.constBegin(); iter != m_filePath.constEnd(); ++iter) {
- if (*iter == QLatin1Char('/')) {
+ if (*iter == u'/') {
if (dots == 1 || dots == 2)
return false; // path contains "./" or "../"
if (!slashok)
@@ -412,7 +387,7 @@ bool QFileSystemEntry::isClean() const
slashok = false;
} else if (dotok) {
slashok = true;
- if (*iter == QLatin1Char('.')) {
+ if (*iter == u'.') {
dots++;
if (dots > 2)
dotok = false;
diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h
index ba0c7812e9..8b5d506b0b 100644
--- a/src/corelib/io/qfilesystementry_p.h
+++ b/src/corelib/io/qfilesystementry_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMENTRY_P_H
#define QFILESYSTEMENTRY_P_H
@@ -69,36 +33,34 @@ public:
struct FromNativePath{};
struct FromInternalPath{};
- QFileSystemEntry();
- explicit QFileSystemEntry(const QString &filePath);
-
- QFileSystemEntry(const QString &filePath, FromInternalPath dummy);
- QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath dummy);
- QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath);
-
- QString filePath() const;
- QString fileName() const;
- QString path() const;
- NativePath nativeFilePath() const;
- QString baseName() const;
- QString completeBaseName() const;
- QString suffix() const;
- QString completeSuffix() const;
- bool isAbsolute() const;
- bool isRelative() const;
- bool isClean() const;
+ Q_AUTOTEST_EXPORT QFileSystemEntry();
+ Q_AUTOTEST_EXPORT explicit QFileSystemEntry(const QString &filePath);
+
+ Q_AUTOTEST_EXPORT QFileSystemEntry(const QString &filePath, FromInternalPath dummy);
+ Q_AUTOTEST_EXPORT QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath dummy);
+ Q_AUTOTEST_EXPORT QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath);
+
+ Q_AUTOTEST_EXPORT QString filePath() const;
+ Q_AUTOTEST_EXPORT QString fileName() const;
+ Q_AUTOTEST_EXPORT QString path() const;
+ Q_AUTOTEST_EXPORT NativePath nativeFilePath() const;
+ Q_AUTOTEST_EXPORT QString baseName() const;
+ Q_AUTOTEST_EXPORT QString completeBaseName() const;
+ Q_AUTOTEST_EXPORT QString suffix() const;
+ Q_AUTOTEST_EXPORT QString completeSuffix() const;
+ Q_AUTOTEST_EXPORT bool isAbsolute() const;
+ Q_AUTOTEST_EXPORT bool isRelative() const;
+ Q_AUTOTEST_EXPORT bool isClean() const;
#if defined(Q_OS_WIN)
- bool isDriveRoot() const;
+ Q_AUTOTEST_EXPORT bool isDriveRoot() const;
static bool isDriveRootPath(const QString &path);
static QString removeUncOrLongPathPrefix(QString path);
#endif
- bool isRoot() const;
+ Q_AUTOTEST_EXPORT bool isRoot() const;
+
+ Q_AUTOTEST_EXPORT bool isEmpty() const;
- bool isEmpty() const
- {
- return m_filePath.isEmpty() && m_nativeFilePath.isEmpty();
- }
void clear()
{
*this = QFileSystemEntry();
diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h
index 5e4e424e69..2973b85cd2 100644
--- a/src/corelib/io/qfilesystemiterator_p.h
+++ b/src/corelib/io/qfilesystemiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMITERATOR_P_H
#define QFILESYSTEMITERATOR_P_H
@@ -56,44 +20,48 @@
#ifndef QT_NO_FILESYSTEMITERATOR
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
#include <QtCore/qstringlist.h>
#include <QtCore/private/qfilesystementry_p.h>
#include <QtCore/private/qfilesystemmetadata_p.h>
-// Platform-specific headers
#if !defined(Q_OS_WIN)
-#include <QtCore/qscopedpointer.h>
+#include <private/qstringconverter_p.h>
#endif
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QFileSystemIterator
{
public:
- QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags
- = QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
+ QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters);
~QFileSystemIterator();
bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData);
private:
- QFileSystemEntry::NativePath nativePath;
+ QString dirPath;
// Platform-specific data
#if defined(Q_OS_WIN)
- QString dirPath;
+ QFileSystemEntry::NativePath nativePath;
HANDLE findFileHandle;
QStringList uncShares;
bool uncFallback;
int uncShareIndex;
bool onlyDirs;
#else
- QT_DIR *dir;
- QT_DIRENT *dirEntry;
- int lastError;
+ struct DirStreamCloser {
+ void operator()(QT_DIR *dir) { if (dir) QT_CLOSEDIR(dir); }
+ };
+ using DirPtr = std::unique_ptr<QT_DIR, DirStreamCloser>;
+ DirPtr dir;
+
+ QT_DIRENT *dirEntry = nullptr;
+ int lastError = 0;
+ QStringDecoder toUtf16;
#endif
Q_DISABLE_COPY_MOVE(QFileSystemIterator)
diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
index cf01eeff15..a1130728ef 100644
--- a/src/corelib/io/qfilesystemiterator_unix.cpp
+++ b/src/corelib/io/qfilesystemiterator_unix.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "qfilesystemiterator_p.h"
-#include <private/qstringconverter_p.h>
-
#ifndef QT_NO_FILESYSTEMITERATOR
+#include <qvarlengtharray.h>
+
#include <memory>
#include <stdlib.h>
@@ -51,53 +15,66 @@
QT_BEGIN_NAMESPACE
-static bool checkNameDecodable(const char *d_name, qsizetype len)
-{
- // This function is called in a loop from advance() below, but the loop is
- // usually run only once.
-
- return QUtf8::isValidUtf8(QByteArrayView(d_name, len)).isValidUtf8;
-}
-
-QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
- : nativePath(entry.nativeFilePath())
- , dir(nullptr)
- , dirEntry(nullptr)
- , lastError(0)
+/*
+ Native filesystem iterator, which uses ::opendir()/readdir()/dirent from the system
+ libraries to iterate over the directory represented by \a entry.
+*/
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
+ : dirPath(entry.filePath()),
+ toUtf16(QStringDecoder::Utf8)
{
Q_UNUSED(filters);
- Q_UNUSED(nameFilters);
- Q_UNUSED(flags);
- if ((dir = QT_OPENDIR(nativePath.constData())) == nullptr) {
+ dir.reset(QT_OPENDIR(entry.nativeFilePath().constData()));
+ if (!dir) {
lastError = errno;
} else {
- if (!nativePath.endsWith('/'))
- nativePath.append('/');
+ if (!dirPath.endsWith(u'/'))
+ dirPath.append(u'/');
}
}
-QFileSystemIterator::~QFileSystemIterator()
-{
- if (dir)
- QT_CLOSEDIR(dir);
-}
+QFileSystemIterator::~QFileSystemIterator() = default;
bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
{
+ auto asFileEntry = [this](QStringView name) {
+#ifdef Q_OS_DARWIN
+ // must match QFile::decodeName
+ QString normalized = name.toString().normalized(QString::NormalizationForm_C);
+ name = normalized;
+#endif
+ return QFileSystemEntry(dirPath + name, QFileSystemEntry::FromInternalPath());
+ };
if (!dir)
return false;
for (;;) {
- dirEntry = QT_READDIR(dir);
+ // From readdir man page:
+ // If the end of the directory stream is reached, NULL is returned and errno is
+ // not changed. If an error occurs, NULL is returned and errno is set to indicate
+ // the error. To distinguish end of stream from an error, set errno to zero before
+ // calling readdir() and then check the value of errno if NULL is returned.
+ errno = 0;
+ dirEntry = QT_READDIR(dir.get());
if (dirEntry) {
- qsizetype len = strlen(dirEntry->d_name);
- if (checkNameDecodable(dirEntry->d_name, len)) {
- fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name, len), QFileSystemEntry::FromNativePath());
+ // POSIX allows readdir() to return a file name in struct dirent that
+ // extends past the end of the d_name array (it's a char[1] array on QNX, for
+ // example). Therefore, we *must* call strlen() on it to get the actual length
+ // of the file name. See:
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html#tag_13_07_05
+ QByteArrayView name(dirEntry->d_name, strlen(dirEntry->d_name));
+ // name.size() is sufficient here, see QUtf8::convertToUnicode() for details
+ QVarLengthArray<char16_t> buffer(name.size());
+ auto *end = toUtf16.appendToBuffer(buffer.data(), name);
+ buffer.resize(end - buffer.constData());
+ if (!toUtf16.hasError()) {
+ fileEntry = asFileEntry(buffer);
metaData.fillFromDirEnt(*dirEntry);
return true;
+ } else {
+ errno = EILSEQ; // Invalid or incomplete multibyte or wide character
}
} else {
break;
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index ac52dacdce..7644a1a078 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
@@ -46,30 +10,29 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
bool done = true;
-QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
- : nativePath(entry.nativeFilePath())
- , dirPath(entry.filePath())
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
+ : dirPath(entry.filePath())
+ , nativePath(entry.nativeFilePath())
, findFileHandle(INVALID_HANDLE_VALUE)
, uncFallback(false)
, uncShareIndex(0)
, onlyDirs(false)
{
- Q_UNUSED(nameFilters);
- Q_UNUSED(flags);
- if (nativePath.endsWith(u".lnk"_qs) && !QFileSystemEngine::isDirPath(dirPath, nullptr)) {
+ if (nativePath.endsWith(u".lnk"_s) && !QFileSystemEngine::isDirPath(dirPath, nullptr)) {
QFileSystemMetaData metaData;
QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData);
nativePath = link.nativeFilePath();
}
- if (!nativePath.endsWith(QLatin1Char('\\')))
- nativePath.append(QLatin1Char('\\'));
- nativePath.append(QLatin1Char('*'));
+ if (!nativePath.endsWith(u'\\'))
+ nativePath.append(u'\\');
+ nativePath.append(u'*');
// In MSVC2015+ case we prepend //?/ for longer file-name support
- if (!dirPath.endsWith(QLatin1Char('/')))
- dirPath.append(QLatin1Char('/'));
+ if (!dirPath.endsWith(u'/'))
+ dirPath.append(u'/');
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
onlyDirs = true;
}
@@ -97,10 +60,10 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
findFileHandle = FindFirstFileEx((const wchar_t *)nativePath.utf16(), FINDEX_INFO_LEVELS(infoLevel), &findData,
FINDEX_SEARCH_OPS(searchOps), 0, dwAdditionalFlags);
if (findFileHandle == INVALID_HANDLE_VALUE) {
- if (nativePath.startsWith(QLatin1String("\\\\?\\UNC\\"))) {
- const auto parts = QStringView{nativePath}.split(QLatin1Char('\\'), Qt::SkipEmptyParts);
+ if (nativePath.startsWith("\\\\?\\UNC\\"_L1)) {
+ const auto parts = QStringView{nativePath}.split(u'\\', Qt::SkipEmptyParts);
if (parts.count() == 4 && QFileSystemEngine::uncListSharesOnServer(
- QLatin1String("\\\\") + parts.at(2), &uncShares)) {
+ "\\\\"_L1 + parts.at(2), &uncShares)) {
if (uncShares.isEmpty())
return false; // No shares found in the server
uncFallback = true;
@@ -129,7 +92,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
QString fileName = QString::fromWCharArray(findData.cFileName);
fileEntry = QFileSystemEntry(dirPath + fileName);
metaData = QFileSystemMetaData();
- if (!fileName.endsWith(QLatin1String(".lnk"))) {
+ if (!fileName.endsWith(".lnk"_L1)) {
metaData.fillFromFindData(findData, true);
}
return true;
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 6340e204db..c10b66afaf 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMMETADATA_P_H
#define QFILESYSTEMMETADATA_P_H
@@ -54,6 +18,7 @@
#include "qplatformdefs.h"
#include <QtCore/qglobal.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
#include <QtCore/private/qabstractfileengine_p.h>
// Platform-specific includes
@@ -221,11 +186,15 @@ public:
QDateTime metadataChangeTime() const;
QDateTime modificationTime() const;
- QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
+ QDateTime fileTime(QFile::FileTime time) const;
uint userId() const;
uint groupId() const;
uint ownerId(QAbstractFileEngine::FileOwner owner) const;
+ bool isReadable() const { return permissions().testAnyFlags(QFile::ReadUser); }
+ bool isWritable() const { return permissions().testAnyFlags(QFile::WriteUser); }
+ bool isExecutable() const { return permissions().testAnyFlags(QFile::ExeUser); }
+
#ifdef Q_OS_UNIX
void fillFromStatxBuf(const struct statx &statBuffer);
void fillFromStatBuf(const QT_STATBUF &statBuffer);
@@ -243,7 +212,7 @@ private:
MetaDataFlags knownFlagsMask;
MetaDataFlags entryFlags;
- qint64 size_;
+ qint64 size_ = 0;
// Platform-specific data goes here:
#if defined(Q_OS_WIN)
@@ -254,13 +223,13 @@ private:
FILETIME lastWriteTime_;
#else
// msec precision
- qint64 accessTime_;
- qint64 birthTime_;
- qint64 metadataChangeTime_;
- qint64 modificationTime_;
+ qint64 accessTime_ = 0;
+ qint64 birthTime_ = 0;
+ qint64 metadataChangeTime_ = 0;
+ qint64 modificationTime_ = 0;
- uint userId_;
- uint groupId_;
+ uint userId_ = (uint) -2;
+ uint groupId_ = (uint) -2;
#endif
};
@@ -278,19 +247,19 @@ inline bool QFileSystemMetaData::isAlias() const { return fal
#endif
#if defined(Q_OS_UNIX) || defined (Q_OS_WIN)
-inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
+inline QDateTime QFileSystemMetaData::fileTime(QFile::FileTime time) const
{
switch (time) {
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
return modificationTime();
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
return accessTime();
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
return birthTime();
- case QAbstractFileEngine::MetadataChangeTime:
+ case QFile::FileMetadataChangeTime:
return metadataChangeTime();
}
@@ -300,13 +269,29 @@ inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime tim
#if defined(Q_OS_UNIX)
inline QDateTime QFileSystemMetaData::birthTime() const
-{ return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_, Qt::UTC) : QDateTime(); }
+{
+ return birthTime_
+ ? QDateTime::fromMSecsSinceEpoch(birthTime_, QTimeZone::UTC)
+ : QDateTime();
+}
inline QDateTime QFileSystemMetaData::metadataChangeTime() const
-{ return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_, Qt::UTC) : QDateTime(); }
+{
+ return metadataChangeTime_
+ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_, QTimeZone::UTC)
+ : QDateTime();
+}
inline QDateTime QFileSystemMetaData::modificationTime() const
-{ return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(modificationTime_, Qt::UTC) : QDateTime(); }
+{
+ return modificationTime_
+ ? QDateTime::fromMSecsSinceEpoch(modificationTime_, QTimeZone::UTC)
+ : QDateTime();
+}
inline QDateTime QFileSystemMetaData::accessTime() const
-{ return accessTime_ ? QDateTime::fromMSecsSinceEpoch(accessTime_, Qt::UTC) : QDateTime(); }
+{
+ return accessTime_
+ ? QDateTime::fromMSecsSinceEpoch(accessTime_, QTimeZone::UTC)
+ : QDateTime();
+}
inline uint QFileSystemMetaData::userId() const { return userId_; }
inline uint QFileSystemMetaData::groupId() const { return groupId_; }
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index bd5a73da84..7138f8260b 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_p.h"
@@ -67,6 +31,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_LOGGING_CATEGORY(lcWatcher, "qt.core.filesystemwatcher")
QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent)
@@ -92,29 +58,29 @@ QFileSystemWatcherPrivate::QFileSystemWatcherPrivate()
{
}
+void QFileSystemWatcherPrivate::connectEngine(QFileSystemWatcherEngine *engine)
+{
+ QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::fileChanged,
+ this, &QFileSystemWatcherPrivate::fileChanged);
+ QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::directoryChanged,
+ this, &QFileSystemWatcherPrivate::directoryChanged);
+}
+
void QFileSystemWatcherPrivate::init()
{
Q_Q(QFileSystemWatcher);
native = createNativeEngine(q);
if (native) {
- QObject::connect(native,
- SIGNAL(fileChanged(QString,bool)),
- q,
- SLOT(_q_fileChanged(QString,bool)));
- QObject::connect(native,
- SIGNAL(directoryChanged(QString,bool)),
- q,
- SLOT(_q_directoryChanged(QString,bool)));
+ connectEngine(native);
#if defined(Q_OS_WIN)
- QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
- &QWindowsFileSystemWatcherEngine::driveLockForRemoval,
- q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); });
- QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
- &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed,
- q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); });
- QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
- &QWindowsFileSystemWatcherEngine::driveRemoved,
- q, [this] (const QString &p) { _q_winDriveRemoved(p); });
+ auto *windowsWatcher = static_cast<QWindowsFileSystemWatcherEngine *>(native);
+ using WinE = QWindowsFileSystemWatcherEngine;
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemoval,
+ this, &QFileSystemWatcherPrivate::winDriveLockForRemoval);
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemovalFailed,
+ this, &QFileSystemWatcherPrivate::winDriveLockForRemovalFailed);
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveRemoved,
+ this, &QFileSystemWatcherPrivate::winDriveRemoved);
#endif // Q_OS_WIN
}
}
@@ -126,17 +92,10 @@ void QFileSystemWatcherPrivate::initPollerEngine()
Q_Q(QFileSystemWatcher);
poller = new QPollingFileSystemWatcherEngine(q); // that was a mouthful
- QObject::connect(poller,
- SIGNAL(fileChanged(QString,bool)),
- q,
- SLOT(_q_fileChanged(QString,bool)));
- QObject::connect(poller,
- SIGNAL(directoryChanged(QString,bool)),
- q,
- SLOT(_q_directoryChanged(QString,bool)));
+ connectEngine(poller);
}
-void QFileSystemWatcherPrivate::_q_fileChanged(const QString &path, bool removed)
+void QFileSystemWatcherPrivate::fileChanged(const QString &path, bool removed)
{
Q_Q(QFileSystemWatcher);
qCDebug(lcWatcher) << "file changed" << path << "removed?" << removed << "watching?" << files.contains(path);
@@ -149,7 +108,7 @@ void QFileSystemWatcherPrivate::_q_fileChanged(const QString &path, bool removed
emit q->fileChanged(path, QFileSystemWatcher::QPrivateSignal());
}
-void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool removed)
+void QFileSystemWatcherPrivate::directoryChanged(const QString &path, bool removed)
{
Q_Q(QFileSystemWatcher);
qCDebug(lcWatcher) << "directory changed" << path << "removed?" << removed << "watching?" << directories.contains(path);
@@ -164,7 +123,7 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
#if defined(Q_OS_WIN)
-void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+void QFileSystemWatcherPrivate::winDriveLockForRemoval(const QString &path)
{
// Windows: Request to lock a (removable/USB) drive for removal, release
// its paths under watch, temporarily storing them should the lock fail.
@@ -181,7 +140,7 @@ void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
}
}
-void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+void QFileSystemWatcherPrivate::winDriveLockForRemovalFailed(const QString &path)
{
// Windows: Request to lock a (removable/USB) drive failed (blocked by other
// application), restore the watched paths.
@@ -195,7 +154,7 @@ void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &p
}
}
-void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+void QFileSystemWatcherPrivate::winDriveRemoved(const QString &path)
{
// Windows: Drive finally removed, clear out paths stored in lock request.
if (!path.isEmpty())
@@ -364,14 +323,14 @@ QStringList QFileSystemWatcher::addPaths(const QStringList &paths)
#ifdef QT_BUILD_INTERNAL
const QString on = objectName();
- if (Q_UNLIKELY(on.startsWith(QLatin1String("_qt_autotest_force_engine_")))) {
+ if (Q_UNLIKELY(on.startsWith("_qt_autotest_force_engine_"_L1))) {
// Autotest override case - use the explicitly selected engine only
const auto forceName = QStringView{on}.mid(26);
- if (forceName == QLatin1String("poller")) {
+ if (forceName == "poller"_L1) {
qCDebug(lcWatcher, "QFileSystemWatcher: skipping native engine, using only polling engine");
d_func()->initPollerEngine();
return d->poller;
- } else if (forceName == QLatin1String("native")) {
+ } else if (forceName == "native"_L1) {
qCDebug(lcWatcher, "QFileSystemWatcher: skipping polling engine, using only native engine");
return d->native;
}
diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h
index cd64115f8f..668bc143b2 100644
--- a/src/corelib/io/qfilesystemwatcher.h
+++ b/src/corelib/io/qfilesystemwatcher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_H
#define QFILESYSTEMWATCHER_H
@@ -70,10 +34,6 @@ public:
Q_SIGNALS:
void fileChanged(const QString &path, QPrivateSignal);
void directoryChanged(const QString &path, QPrivateSignal);
-
-private:
- Q_PRIVATE_SLOT(d_func(), void _q_fileChanged(const QString &path, bool removed))
- Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &path, bool removed))
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm
index b6d285cec3..0d9b84890a 100644
--- a/src/corelib/io/qfilesystemwatcher_fsevents.mm
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qplatformdefs.h>
@@ -217,8 +181,8 @@ void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef stream
lastReceivedEvent = qMax(lastReceivedEvent, eventIds[i]);
QString path = QFile::decodeName(eventPaths[i]);
- if (path.endsWith(QDir::separator()))
- path = path.mid(0, path.size() - 1);
+ if (path.size() > 1 && path.endsWith(QDir::separator()))
+ path.chop(1);
if (eFlags & kFSEventStreamEventFlagMustScanSubDirs) {
DEBUG("\tmust rescan directory because of coalesced events");
@@ -346,8 +310,8 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
auto sg = qScopeGuard([&]{ unhandled.push_back(path); });
QString origPath = path.normalized(QString::NormalizationForm_C);
QString realPath = origPath;
- if (realPath.endsWith(QDir::separator()))
- realPath = realPath.mid(0, realPath.size() - 1);
+ if (realPath.size() > 1 && realPath.endsWith(QDir::separator()))
+ realPath.chop(1);
QString watchedPath, parentPath;
realPath = QFileInfo(realPath).canonicalFilePath();
@@ -437,8 +401,8 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat
for (const QString &origPath : paths) {
auto sg = qScopeGuard([&]{ unhandled.push_back(origPath); });
QString realPath = origPath;
- if (realPath.endsWith(QDir::separator()))
- realPath = realPath.mid(0, realPath.size() - 1);
+ if (realPath.size() > 1 && realPath.endsWith(QDir::separator()))
+ realPath.chop(1);
QFileInfo fi(realPath);
realPath = fi.canonicalFilePath();
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
index ad23805afb..173ad1d52d 100644
--- a/src/corelib/io/qfilesystemwatcher_fsevents_p.h
+++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_FSEVENTS_P_H
#define QFILESYSTEMWATCHER_FSEVENTS_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index 27e0b13b0b..e60f688110 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_inotify_p.h"
@@ -253,13 +217,14 @@ QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd, QObject
notifier(fd, QSocketNotifier::Read, this)
{
fcntl(inotifyFd, F_SETFD, FD_CLOEXEC);
- connect(&notifier, SIGNAL(activated(QSocketDescriptor)), SLOT(readFromInotify()));
+ QObject::connect(&notifier, &QSocketNotifier::activated,
+ this, &QInotifyFileSystemWatcherEngine::readFromInotify);
}
QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine()
{
notifier.setEnabled(false);
- for (int id : qAsConst(pathToID))
+ for (int id : std::as_const(pathToID))
inotify_rm_watch(inotifyFd, id < 0 ? -id : id);
::close(inotifyFd);
@@ -370,7 +335,7 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
return;
QVarLengthArray<char, 4096> buffer(buffSize);
- buffSize = read(inotifyFd, buffer.data(), buffSize);
+ buffSize = int(read(inotifyFd, buffer.data(), buffSize));
char *at = buffer.data();
char * const end = at + buffSize;
diff --git a/src/corelib/io/qfilesystemwatcher_inotify_p.h b/src/corelib/io/qfilesystemwatcher_inotify_p.h
index b63729cde4..05f87df14c 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify_p.h
+++ b/src/corelib/io/qfilesystemwatcher_inotify_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_INOTIFY_P_H
#define QFILESYSTEMWATCHER_INOTIFY_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
index 06383a103a..7a9be337bf 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp
+++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qplatformdefs.h>
@@ -87,7 +51,7 @@ QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
notifier.setEnabled(false);
close(kqfd);
- for (int id : qAsConst(pathToID))
+ for (int id : std::as_const(pathToID))
::close(id < 0 ? -id : id);
}
@@ -201,7 +165,7 @@ void QKqueueFileSystemWatcherEngine::readFromKqueue()
int r;
struct kevent kev;
struct timespec ts = { 0, 0 }; // 0 ts, because we want to poll
- EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts));
+ QT_EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts));
if (r < 0) {
perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
return;
@@ -254,3 +218,5 @@ void QKqueueFileSystemWatcherEngine::readFromKqueue()
}
QT_END_NAMESPACE
+
+#include "moc_qfilesystemwatcher_kqueue_p.cpp"
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue_p.h b/src/corelib/io/qfilesystemwatcher_kqueue_p.h
index ec92e1d667..05844d5be9 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue_p.h
+++ b/src/corelib/io/qfilesystemwatcher_kqueue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_KQUEUE_P_H
#define QFILESYSTEMWATCHER_KQUEUE_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index cecfe03ff5..c34e3e2408 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_P_H
#define QFILESYSTEMWATCHER_P_H
@@ -105,13 +69,15 @@ public:
QStringList files, directories;
// private slots
- void _q_fileChanged(const QString &path, bool removed);
- void _q_directoryChanged(const QString &path, bool removed);
+ void fileChanged(const QString &path, bool removed);
+ void directoryChanged(const QString &path, bool removed);
+
+ void connectEngine(QFileSystemWatcherEngine *e);
#if defined(Q_OS_WIN)
- void _q_winDriveLockForRemoval(const QString &);
- void _q_winDriveLockForRemovalFailed(const QString &);
- void _q_winDriveRemoved(const QString &);
+ void winDriveLockForRemoval(const QString &);
+ void winDriveLockForRemovalFailed(const QString &);
+ void winDriveRemoved(const QString &);
private:
QHash<QChar, QStringList> temporarilyRemovedPaths;
diff --git a/src/corelib/io/qfilesystemwatcher_polling.cpp b/src/corelib/io/qfilesystemwatcher_polling.cpp
index 6920eab258..d34c8c49e8 100644
--- a/src/corelib/io/qfilesystemwatcher_polling.cpp
+++ b/src/corelib/io/qfilesystemwatcher_polling.cpp
@@ -1,53 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemwatcher_polling_p.h"
+
+#include <QtCore/qlatin1stringview.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qtimer.h>
+#include <chrono>
+
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static constexpr auto PollingInterval = 1s;
+
QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent),
- timer(this)
+ : QFileSystemWatcherEngine(parent)
{
- connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
}
QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
@@ -64,8 +36,8 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
if (directories->contains(path))
continue;
directories->append(path);
- if (!path.endsWith(QLatin1Char('/')))
- fi = QFileInfo(path + QLatin1Char('/'));
+ if (!path.endsWith(u'/'))
+ fi = QFileInfo(path + u'/');
this->directories.insert(path, fi);
} else {
if (files->contains(path))
@@ -76,10 +48,17 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
sg.dismiss();
}
+ std::chrono::milliseconds interval = PollingInterval;
+#ifdef QT_BUILD_INTERNAL
+ if (Q_UNLIKELY(parent()->objectName().startsWith("_qt_autotest_force_engine_"_L1))) {
+ interval = 10ms; // Special case to speed up the unittests
+ }
+#endif
+
if ((!this->files.isEmpty() ||
!this->directories.isEmpty()) &&
!timer.isActive()) {
- timer.start(PollingInterval);
+ timer.start(interval, this);
}
return unhandled;
@@ -108,8 +87,11 @@ QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &path
return unhandled;
}
-void QPollingFileSystemWatcherEngine::timeout()
+void QPollingFileSystemWatcherEngine::timerEvent(QTimerEvent *e)
{
+ if (e->timerId() != timer.timerId())
+ return QFileSystemWatcherEngine::timerEvent(e);
+
for (auto it = files.begin(), end = files.end(); it != end; /*erasing*/) {
QString path = it.key();
QFileInfo fi(path);
@@ -127,8 +109,8 @@ void QPollingFileSystemWatcherEngine::timeout()
for (auto it = directories.begin(), end = directories.end(); it != end; /*erasing*/) {
QString path = it.key();
QFileInfo fi(path);
- if (!path.endsWith(QLatin1Char('/')))
- fi = QFileInfo(path + QLatin1Char('/'));
+ if (!path.endsWith(u'/'))
+ fi = QFileInfo(path + u'/');
if (!fi.exists()) {
it = directories.erase(it);
emit directoryChanged(path, true);
diff --git a/src/corelib/io/qfilesystemwatcher_polling_p.h b/src/corelib/io/qfilesystemwatcher_polling_p.h
index e60132381b..b65ff05575 100644
--- a/src/corelib/io/qfilesystemwatcher_polling_p.h
+++ b/src/corelib/io/qfilesystemwatcher_polling_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_POLLING_P_H
#define QFILESYSTEMWATCHER_POLLING_P_H
@@ -51,11 +15,11 @@
// We mean it.
//
+#include <QtCore/qbasictimer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qmutex.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdir.h>
-#include <QtCore/qtimer.h>
#include <QtCore/qhash.h>
#include "qfilesystemwatcher_p.h"
@@ -63,8 +27,6 @@
QT_REQUIRE_CONFIG(filesystemwatcher);
QT_BEGIN_NAMESPACE
-enum { PollingInterval = 1000 };
-
class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
@@ -82,7 +44,7 @@ class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
: ownerId(fileInfo.ownerId()),
groupId(fileInfo.groupId()),
permissions(fileInfo.permissions()),
- lastModified(fileInfo.lastModified())
+ lastModified(fileInfo.lastModified(QTimeZone::UTC))
{
if (fileInfo.isDir()) {
entries = fileInfo.absoluteDir().entryList(QDir::AllEntries);
@@ -101,7 +63,7 @@ class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
return (ownerId != fileInfo.ownerId()
|| groupId != fileInfo.groupId()
|| permissions != fileInfo.permissions()
- || lastModified != fileInfo.lastModified());
+ || lastModified != fileInfo.lastModified(QTimeZone::UTC));
}
};
@@ -113,11 +75,11 @@ public:
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
-private Q_SLOTS:
- void timeout();
+private:
+ void timerEvent(QTimerEvent *) final;
private:
- QTimer timer;
+ QBasicTimer timer;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index 5d8a5b3682..5418265ba2 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_win_p.h"
@@ -63,6 +27,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// #define WINQFSW_DEBUG
#ifdef WINQFSW_DEBUG
# define DEBUG qDebug
@@ -75,8 +41,8 @@ static Qt::HANDLE createChangeNotification(const QString &path, uint flags)
// Volume and folder paths need a trailing slash for proper notification
// (e.g. "c:" -> "c:/").
QString nativePath = QDir::toNativeSeparators(path);
- if ((flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) == 0 && !nativePath.endsWith(QLatin1Char('\\')))
- nativePath.append(QLatin1Char('\\'));
+ if ((flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) == 0 && !nativePath.endsWith(u'\\'))
+ nativePath.append(u'\\');
const HANDLE result = FindFirstChangeNotification(reinterpret_cast<const wchar_t *>(nativePath.utf16()),
FALSE, flags);
DEBUG() << __FUNCTION__ << nativePath << Qt::hex << Qt::showbase << flags << "returns" << result;
@@ -274,7 +240,7 @@ bool QWindowsRemovableDriveListener::nativeEventFilter(const QByteArray &, void
// Set up listening for WM_DEVICECHANGE+DBT_CUSTOMEVENT for a removable drive path,
void QWindowsRemovableDriveListener::addPath(const QString &p)
{
- const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':')
+ const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == u':'
? wchar_t(p.at(0).toUpper().unicode()) : L'\0';
if (!drive)
return;
@@ -351,9 +317,9 @@ QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
- for (auto *thread : qAsConst(threads))
+ for (auto *thread : std::as_const(threads))
thread->stop();
- for (auto *thread : qAsConst(threads))
+ for (auto *thread : std::as_const(threads))
thread->wait();
qDeleteAll(threads);
}
@@ -366,12 +332,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
- QString normalPath = path;
- if ((normalPath.endsWith(QLatin1Char('/')) && !normalPath.endsWith(QLatin1String(":/")))
- || (normalPath.endsWith(QLatin1Char('\\')) && !normalPath.endsWith(QLatin1String(":\\")))) {
- normalPath.chop(1);
- }
- QFileInfo fileInfo(normalPath);
+ QFileInfo fileInfo(path);
fileInfo.stat();
if (!fileInfo.exists())
continue;
@@ -385,7 +346,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
continue;
}
- DEBUG() << "Looking for a thread/handle for" << normalPath;
+ DEBUG() << "Looking for a thread/handle for" << fileInfo.path();
const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath();
const uint flags = isDir
@@ -467,7 +428,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
// now look for a thread to insert
bool found = false;
- for (QWindowsFileSystemWatcherEngineThread *thread : qAsConst(threads)) {
+ for (QWindowsFileSystemWatcherEngineThread *thread : std::as_const(threads)) {
const auto locker = qt_scoped_lock(thread->mutex);
if (thread->handles.count() < MAXIMUM_WAIT_OBJECTS) {
DEBUG() << "Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath()
@@ -529,11 +490,8 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
- QString normalPath = path;
- if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\')))
- normalPath.chop(1);
- QFileInfo fileInfo(normalPath);
- DEBUG() << "removing" << normalPath;
+ QFileInfo fileInfo(path);
+ DEBUG() << "removing" << fileInfo.path();
QString absolutePath = fileInfo.absoluteFilePath();
QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end;
end = threads.end();
@@ -620,7 +578,7 @@ QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread()
CloseHandle(handles.at(0));
handles[0] = INVALID_HANDLE_VALUE;
- for (HANDLE h : qAsConst(handles)) {
+ for (HANDLE h : std::as_const(handles)) {
if (h == INVALID_HANDLE_VALUE)
continue;
FindCloseChangeNotification(h);
@@ -631,10 +589,10 @@ Q_DECL_COLD_FUNCTION
static QString msgFindNextFailed(const QWindowsFileSystemWatcherEngineThread::PathInfoHash &pathInfos)
{
QString str;
- str += QLatin1String("QFileSystemWatcher: FindNextChangeNotification failed for");
+ str += "QFileSystemWatcher: FindNextChangeNotification failed for"_L1;
for (const QWindowsFileSystemWatcherEngine::PathInfo &pathInfo : pathInfos)
- str += QLatin1String(" \"") + QDir::toNativeSeparators(pathInfo.absolutePath) + QLatin1Char('"');
- str += QLatin1Char(' ');
+ str += " \""_L1 + QDir::toNativeSeparators(pathInfo.absolutePath) + u'"';
+ str += u' ';
return str;
}
@@ -750,3 +708,4 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
QT_END_NAMESPACE
# include "qfilesystemwatcher_win.moc"
+# include "moc_qfilesystemwatcher_win_p.cpp"
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index 778ed8ce23..79cec00c39 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFILESYSTEMWATCHER_WIN_P_H
#define QFILESYSTEMWATCHER_WIN_P_H
@@ -140,7 +104,10 @@ public:
Q_DECLARE_TYPEINFO(QFileSystemWatcherPathKey, Q_RELOCATABLE_TYPE);
-inline size_t qHash(const QFileSystemWatcherPathKey &key) { return qHash(key.toCaseFolded()); }
+inline size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed = 0)
+{
+ return qHash(key.toCaseFolded(), seed);
+}
class QWindowsFileSystemWatcherEngineThread : public QThread
{
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 4ba35abacb..f49106edd4 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfsfileengine_p.h"
#include "qfsfileengine_iterator_p.h"
#include "qfilesystemengine_p.h"
#include "qdatetime.h"
-#include "qdiriterator.h"
#include "qset.h"
#include <QtCore/qdebug.h>
@@ -54,12 +17,14 @@
#endif
#include <stdio.h>
#include <stdlib.h>
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
# include <private/qcore_mac_p.h>
#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#ifdef Q_OS_WIN
# ifndef S_ISREG
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
@@ -173,14 +138,14 @@ ProcessOpenModeResult processOpenModeFlags(QIODevice::OpenMode openMode)
result.ok = false;
if ((openMode & QFile::NewOnly) && (openMode & QFile::ExistingOnly)) {
qWarning("NewOnly and ExistingOnly are mutually exclusive");
- result.error = QLatin1String("NewOnly and ExistingOnly are mutually exclusive");
+ result.error = "NewOnly and ExistingOnly are mutually exclusive"_L1;
return result;
}
if ((openMode & QFile::ExistingOnly) && !(openMode & (QFile::ReadOnly | QFile::WriteOnly))) {
qWarning("ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite");
- result.error = QLatin1String(
- "ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite");
+ result.error =
+ "ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite"_L1;
return result;
}
@@ -235,7 +200,7 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode,
Q_D(QFSFileEngine);
if (d->fileEntry.isEmpty()) {
qWarning("QFSFileEngine::open: No file name specified");
- setError(QFile::OpenError, QLatin1String("No file name specified"));
+ setError(QFile::OpenError, "No file name specified"_L1);
return false;
}
@@ -307,7 +272,7 @@ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
if (ret != 0) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
this->openMode = QIODevice::NotOpen;
this->fh = nullptr;
@@ -362,14 +327,14 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
// Seek to the end when in Append mode.
if (openMode & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
this->openMode = QIODevice::NotOpen;
this->fd = -1;
@@ -428,7 +393,7 @@ bool QFSFileEnginePrivate::closeFdFh()
if (!flushed || !closed) {
if (flushed) {
// If not flushed, we want the flush error to fall through.
- q->setError(QFile::UnspecifiedError, QSystemError::stdString());
+ q->setError(QFile::UnspecifiedError, QSystemError::stdString(errno));
}
return false;
}
@@ -480,7 +445,7 @@ bool QFSFileEnginePrivate::flushFh()
if (ret != 0) {
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
return false;
}
return true;
@@ -502,7 +467,7 @@ void QFSFileEnginePrivate::unmapAll()
{
if (!maps.isEmpty()) {
const QList<uchar*> keys = maps.keys(); // Make a copy since unmap() modifies the map.
- for (int i = 0; i < keys.count(); ++i)
+ for (int i = 0; i < keys.size(); ++i)
unmap(keys.at(i));
}
}
@@ -555,11 +520,11 @@ bool QFSFileEngine::seek(qint64 pos)
/*!
\reimp
*/
-QDateTime QFSFileEngine::fileTime(FileTime time) const
+QDateTime QFSFileEngine::fileTime(QFile::FileTime time) const
{
Q_D(const QFSFileEngine);
- if (time == AccessTime) {
+ if (time == QFile::FileAccessTime) {
// always refresh for the access time
d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
}
@@ -595,14 +560,14 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
- q->setError(QFile::ReadError, QSystemError::stdString());
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
return false;
}
} else {
// Unbuffered stdio mode.
if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
+ q->setError(QFile::PositionError, QSystemError::stdString(errno));
qWarning("QFile::at: Cannot set file position %lld", pos);
- q->setError(QFile::PositionError, QSystemError::stdString());
return false;
}
}
@@ -655,17 +620,15 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
// Buffered stdlib mode.
size_t result;
- bool retry = true;
do {
result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
- eof = feof(fh);
- if (retry && eof && result == 0) {
+ eof = feof(fh); // Doesn't change errno
+ if (eof && result == 0) {
// On OS X, this is needed, e.g., if a file was written to
// through another stream since our last read. See test
// tst_QFile::appendAndRead
QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
- retry = false;
- continue;
+ break;
}
readBytes += result;
} while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
@@ -685,12 +648,13 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
result = QT_READ(fd, data + readBytes, chunkSize);
} while (result > 0 && (readBytes += result) < len);
- eof = !(result == -1);
+ // QT_READ (::read()) returns 0 to indicate end-of-file
+ eof = result == 0;
}
if (!eof && readBytes == 0) {
readBytes = -1;
- q->setError(QFile::ReadError, QSystemError::stdString());
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
}
return readBytes;
@@ -735,8 +699,8 @@ qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
// does the same, so we'd get two '\0' at the end - passing maxlen + 1
// solves this.
if (!fgets(data, int(maxlen + 1), fh)) {
- if (!feof(fh))
- q->setError(QFile::ReadError, QSystemError::stdString());
+ if (!feof(fh)) // Doesn't change errno
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
return -1; // error
}
@@ -813,7 +777,8 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
if (len && writtenBytes == 0) {
writtenBytes = -1;
- q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, QSystemError::stdString());
+ q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
+ QSystemError::stdString(errno));
} else {
// reset the cached size, if any
metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
@@ -826,18 +791,13 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
/*!
\internal
*/
-QAbstractFileEngine::Iterator *QFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+QFSFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return new QFSFileEngineIterator(filters, filterNames);
+ return std::make_unique<QFSFileEngineIterator>(path, filters, filterNames);
}
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QFSFileEngine::endEntryList()
-{
- return nullptr;
-}
#endif // QT_NO_FILESYSTEMITERATOR
/*!
@@ -940,7 +900,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QAbstractFileEngine::FileTime time)
+/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
\reimp
*/
@@ -1030,29 +990,32 @@ bool QFSFileEngine::remove()
return ret;
}
-/*!
- \reimp
+/*
+ An alternative to setFileName() when you have already constructed
+ a QFileSystemEntry.
*/
-bool QFSFileEngine::rename(const QString &newName)
+void QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
{
Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
- setError(QFile::RenameError, error.toString());
- return ret;
+ d->init();
+ d->fileEntry = std::move(entry);
}
-/*!
- \reimp
-*/
-bool QFSFileEngine::renameOverwrite(const QString &newName)
+
+bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
{
Q_D(QFSFileEngine);
+
+ auto func = mode == Rename ? QFileSystemEngine::renameFile
+ : QFileSystemEngine::renameOverwriteFile;
QSystemError error;
- bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
+ auto newEntry = QFileSystemEntry(newName);
+ const bool ret = func(d->fileEntry, newEntry, error);
+ if (!ret) {
setError(QFile::RenameError, error.toString());
- return ret;
+ return false;
+ }
+ setFileEntry(std::move(newEntry));
+ return true;
}
/*!
diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp
index 2494ea856c..fb0332f7f3 100644
--- a/src/corelib/io/qfsfileengine_iterator.cpp
+++ b/src/corelib/io/qfsfileengine_iterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfsfileengine_iterator_p.h"
#include "qfileinfo_p.h"
@@ -45,9 +9,10 @@
QT_BEGIN_NAMESPACE
-QFSFileEngineIterator::QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames)
- : QAbstractFileEngineIterator(filters, filterNames)
- , done(false)
+QFSFileEngineIterator::QFSFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
+ : QAbstractFileEngineIterator(path, filters, filterNames),
+ nativeIterator(new QFileSystemIterator(QFileSystemEntry(path), filters))
{
}
@@ -55,48 +20,30 @@ QFSFileEngineIterator::~QFSFileEngineIterator()
{
}
-bool QFSFileEngineIterator::hasNext() const
+bool QFSFileEngineIterator::advance()
{
- if (!done && !nativeIterator) {
- nativeIterator.reset(new QFileSystemIterator(QFileSystemEntry(path()),
- filters(), nameFilters()));
- advance();
- }
-
- return !done;
-}
-
-QString QFSFileEngineIterator::next()
-{
- if (!hasNext())
- return QString();
-
- advance();
- return currentFilePath();
-}
-
-void QFSFileEngineIterator::advance() const
-{
- currentInfo = nextInfo;
+ if (!nativeIterator)
+ return false;
QFileSystemEntry entry;
QFileSystemMetaData data;
if (nativeIterator->advance(entry, data)) {
- nextInfo = QFileInfo(new QFileInfoPrivate(entry, data));
+ m_fileInfo = QFileInfo(new QFileInfoPrivate(entry, data));
+ return true;
} else {
- done = true;
nativeIterator.reset();
+ return false;
}
}
QString QFSFileEngineIterator::currentFileName() const
{
- return currentInfo.fileName();
+ return m_fileInfo.fileName();
}
QFileInfo QFSFileEngineIterator::currentFileInfo() const
{
- return currentInfo;
+ return m_fileInfo;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h
index bde00bf578..b91c5d9973 100644
--- a/src/corelib/io/qfsfileengine_iterator_p.h
+++ b/src/corelib/io/qfsfileengine_iterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFSFILEENGINE_ITERATOR_P_H
#define QFSFILEENGINE_ITERATOR_P_H
@@ -59,27 +23,19 @@
QT_BEGIN_NAMESPACE
-class QFSFileEngineIteratorPrivate;
-class QFSFileEngineIteratorPlatformSpecificData;
-
class QFSFileEngineIterator : public QAbstractFileEngineIterator
{
public:
- QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
+ QFSFileEngineIterator(const QString &path, QDir::Filters filters, const QStringList &filterNames);
~QFSFileEngineIterator();
- QString next() override;
- bool hasNext() const override;
+ bool advance() override;
QString currentFileName() const override;
QFileInfo currentFileInfo() const override;
private:
- void advance() const;
mutable QScopedPointer<QFileSystemIterator> nativeIterator;
- mutable QFileInfo currentInfo;
- mutable QFileInfo nextInfo;
- mutable bool done;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 4ebba61bb6..dfc40e20b6 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFSFILEENGINE_P_H
#define QFSFILEENGINE_P_H
@@ -96,8 +60,12 @@ public:
bool isSequential() const override;
bool remove() override;
bool copy(const QString &newName) override;
- bool rename(const QString &newName) override;
- bool renameOverwrite(const QString &newName) override;
+
+ bool rename(const QString &newName) override
+ { return rename_helper(newName, Rename); }
+ bool renameOverwrite(const QString &newName) override
+ { return rename_helper(newName, RenameOverwrite); }
+
bool link(const QString &newName) override;
bool mkdir(const QString &dirName, bool createParentDirectories,
std::optional<QFile::Permissions> permissions) const override;
@@ -112,14 +80,15 @@ public:
QString fileName(FileName file) const override;
uint ownerId(FileOwner) const override;
QString owner(FileOwner) const override;
- bool setFileTime(const QDateTime &newDate, FileTime time) override;
- QDateTime fileTime(FileTime time) const override;
+ bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override;
+ QDateTime fileTime(QFile::FileTime time) const override;
void setFileName(const QString &file) override;
+ void setFileEntry(QFileSystemEntry &&entry);
int handle() const override;
#ifndef QT_NO_FILESYSTEMITERATOR
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
#endif
qint64 read(char *data, qint64 maxlen) override;
@@ -146,6 +115,10 @@ public:
protected:
QFSFileEngine(QFSFileEnginePrivate &dd);
+
+private:
+ enum RenameMode : int { Rename, RenameOverwrite };
+ bool rename_helper(const QString &newName, RenameMode mode);
};
class Q_AUTOTEST_EXPORT QFSFileEnginePrivate : public QAbstractFileEnginePrivate
@@ -187,6 +160,9 @@ public:
#ifndef Q_OS_WIN
bool isSequentialFdFh() const;
#endif
+#ifdef Q_OS_WIN
+ bool nativeRenameOverwrite(const QFileSystemEntry &newEntry);
+#endif
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index d071c85cb3..5806689182 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "private/qabstractfileengine_p.h"
@@ -101,7 +65,7 @@ static inline QString msgOpenDirectory()
#if QT_CONFIG(translation)
return QIODevice::tr(message);
#else
- return QLatin1String(message);
+ return QLatin1StringView(message);
#endif
}
@@ -151,14 +115,14 @@ bool QFSFileEnginePrivate::nativeOpenImpl(QIODevice::OpenMode openMode, mode_t m
// Seek to the end when in Append mode.
if (flags & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
+ qt_error_string(errno));
return false;
}
}
@@ -196,9 +160,9 @@ bool QFSFileEnginePrivate::nativeSyncToDisk()
Q_Q(QFSFileEngine);
int ret;
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
- EINTR_LOOP(ret, fdatasync(nativeHandle()));
+ QT_EINTR_LOOP(ret, fdatasync(nativeHandle()));
#else
- EINTR_LOOP(ret, fsync(nativeHandle()));
+ QT_EINTR_LOOP(ret, fsync(nativeHandle()));
#endif
if (ret != 0)
q->setError(QFile::WriteError, qt_error_string(errno));
@@ -257,7 +221,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len)
}
if (readBytes == 0 && !feof(fh)) {
// if we didn't read anything and we're not at EOF, it must be an error
- q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ q->setError(QFile::ReadError, qt_error_string(errno));
return -1;
}
return readBytes;
@@ -486,6 +450,12 @@ QString QFSFileEngine::fileName(FileName file) const
return entry.filePath();
}
return QString();
+ case RawLinkPath:
+ if (d->isSymlink()) {
+ QFileSystemEntry entry = QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData);
+ return entry.filePath();
+ }
+ return QString();
case JunctionName:
return QString();
case DefaultName:
@@ -498,7 +468,8 @@ QString QFSFileEngine::fileName(FileName file) const
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
- return d->fileEntry.filePath().length() ? d->fileEntry.filePath().at(0) != QLatin1Char('/') : true;
+ const QString fp = d->fileEntry.filePath();
+ return fp.isEmpty() || fp.at(0) != u'/';
}
uint QFSFileEngine::ownerId(FileOwner own) const
@@ -524,6 +495,10 @@ bool QFSFileEngine::setPermissions(uint perms)
Q_D(QFSFileEngine);
QSystemError error;
bool ok;
+
+ // clear cached state (if any)
+ d->metaData.clearFlags(QFileSystemMetaData::Permissions);
+
if (d->fd != -1)
ok = QFileSystemEngine::setPermissions(d->fd, QFile::Permissions(perms), error);
else
@@ -550,7 +525,7 @@ bool QFSFileEngine::setSize(qint64 size)
return ret;
}
-bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_D(QFSFileEngine);
@@ -585,16 +560,16 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
Q_Q(QFSFileEngine);
if (openMode == QIODevice::NotOpen) {
- q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
+ q->setError(QFile::PermissionsError, qt_error_string(EACCES));
return nullptr;
}
if (offset < 0 || offset > maxFileOffset
- || size < 0 || quint64(size) > quint64(size_t(-1))) {
- q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
+ || size <= 0
+ || quint64(size) > quint64(size_t(-1))) {
+ q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
return nullptr;
}
-
// If we know the mapping will extend beyond EOF, fail early to avoid
// undefined behavior. Otherwise, let mmap have its say.
if (doStat(QFileSystemMetaData::SizeAttribute)
@@ -619,7 +594,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
int extra = offset % pageSize;
if (quint64(size + extra) > quint64((size_t)-1)) {
- q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
+ q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
return nullptr;
}
@@ -637,16 +612,16 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
switch(errno) {
case EBADF:
- q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
+ q->setError(QFile::PermissionsError, qt_error_string(EACCES));
break;
case ENFILE:
case ENOMEM:
- q->setError(QFile::ResourceError, qt_error_string(int(errno)));
+ q->setError(QFile::ResourceError, qt_error_string(errno));
break;
case EINVAL:
// size are out of bounds
default:
- q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
+ q->setError(QFile::UnspecifiedError, qt_error_string(errno));
break;
}
return nullptr;
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 60e25d34f1..4ac305f49b 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformdefs.h"
#include "private/qabstractfileengine_p.h"
@@ -63,17 +27,21 @@
#define SECURITY_WIN32
#include <security.h>
+#include <memory>
+
#ifndef PATH_MAX
#define PATH_MAX FILENAME_MAX
#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static inline bool isUncPath(const QString &path)
{
// Starts with \\, but not \\.
- return (path.startsWith(QLatin1String("\\\\"))
- && path.size() > 2 && path.at(2) != QLatin1Char('.'));
+ return (path.startsWith("\\\\"_L1)
+ && path.size() > 2 && path.at(2) != u'.');
}
/*!
@@ -81,13 +49,13 @@ static inline bool isUncPath(const QString &path)
*/
QString QFSFileEnginePrivate::longFileName(const QString &path)
{
- if (path.startsWith(QLatin1String("\\\\.\\")))
+ if (path.startsWith("\\\\.\\"_L1))
return path;
QString absPath = QFileSystemEngine::nativeAbsoluteFilePath(path);
- QString prefix = QLatin1String("\\\\?\\");
+ QString prefix = "\\\\?\\"_L1;
if (isUncPath(absPath)) {
- prefix.append(QLatin1String("UNC\\")); // "\\\\?\\UNC\\"
+ prefix.append("UNC\\"_L1); // "\\\\?\\UNC\\"
absPath.remove(0, 2);
}
return prefix + absPath;
@@ -428,6 +396,35 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
|| (fileType == FILE_TYPE_PIPE);
}
+bool QFSFileEnginePrivate::nativeRenameOverwrite(const QFileSystemEntry &newEntry)
+{
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return false;
+ const QString newFilePath = newEntry.nativeFilePath();
+ const size_t nameByteLength = newFilePath.length() * sizeof(wchar_t);
+ if (nameByteLength + sizeof(wchar_t) > std::numeric_limits<DWORD>::max())
+ return false;
+
+ constexpr size_t RenameInfoSize = sizeof(FILE_RENAME_INFO);
+ const size_t renameDataSize = RenameInfoSize + nameByteLength + sizeof(wchar_t);
+ QVarLengthArray<char> v(qsizetype(renameDataSize), 0);
+
+ auto *renameInfo = q20::construct_at(reinterpret_cast<FILE_RENAME_INFO *>(v.data()));
+ auto renameInfoRAII = qScopeGuard([&] { std::destroy_at(renameInfo); });
+ renameInfo->ReplaceIfExists = TRUE;
+ renameInfo->RootDirectory = nullptr;
+ renameInfo->FileNameLength = DWORD(nameByteLength);
+ memcpy(renameInfo->FileName, newFilePath.data(), nameByteLength);
+
+ bool res = SetFileInformationByHandle(fileHandle, FileRenameInfo, renameInfo,
+ DWORD(renameDataSize));
+ if (!res) {
+ DWORD error = GetLastError();
+ q_func()->setError(QFile::RenameError, qt_error_string(int(error)));
+ }
+ return res;
+}
+
bool QFSFileEngine::caseSensitive() const
{
return false;
@@ -438,7 +435,7 @@ QString QFSFileEngine::currentPath(const QString &fileName)
QString ret;
//if filename is a drive: then get the pwd of that drive
if (fileName.length() >= 2 &&
- fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) {
+ fileName.at(0).isLetter() && fileName.at(1) == u':') {
int drv = fileName.toUpper().at(0).toLatin1() - 'A' + 1;
if (_getdrive() != drv) {
wchar_t buf[PATH_MAX];
@@ -450,7 +447,7 @@ QString QFSFileEngine::currentPath(const QString &fileName)
//just the pwd
ret = QFileSystemEngine::currentPath().filePath();
}
- if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
+ if (ret.length() >= 2 && ret[1] == u':')
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
return ret;
}
@@ -653,6 +650,8 @@ QString QFSFileEngine::fileName(FileName file) const
}
case AbsoluteLinkTarget:
return QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData).filePath();
+ case RawLinkPath:
+ return QFileSystemEngine::getRawLinkPath(d->fileEntry, d->metaData).filePath();
case BundleName:
return QString();
case JunctionName:
@@ -689,6 +688,10 @@ bool QFSFileEngine::setPermissions(uint perms)
{
Q_D(QFSFileEngine);
QSystemError error;
+
+ // clear cached state (if any)
+ d->metaData.clearFlags(QFileSystemMetaData::Permissions);
+
bool ret = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error);
if (!ret)
setError(QFile::PermissionsError, error.toString());
@@ -734,7 +737,7 @@ bool QFSFileEngine::setSize(qint64 size)
return false;
}
-bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_D(QFSFileEngine);
@@ -743,7 +746,7 @@ bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
return false;
}
- if (!newDate.isValid() || time == QAbstractFileEngine::MetadataChangeTime) {
+ if (!newDate.isValid() || time == QFile::FileMetadataChangeTime) {
setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
return false;
}
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 57d26884ee..b0029e2af7 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QIODEVICE_DEBUG
@@ -45,48 +9,42 @@
#include "qfile.h"
#include "qstringlist.h"
#include "qdir.h"
-#include "private/qbytearray_p.h"
+#include "private/qtools_p.h"
#include <algorithm>
-#ifdef QIODEVICE_DEBUG
-# include <ctype.h>
-#endif
-
QT_BEGIN_NAMESPACE
-#ifdef QIODEVICE_DEBUG
-void debugBinaryString(const QByteArray &input)
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+
+[[maybe_unused]]
+static void debugBinaryString(const char *input, qint64 maxlen)
{
QByteArray tmp;
- int startOffset = 0;
- for (int i = 0; i < input.size(); ++i) {
+ qlonglong startOffset = 0;
+ for (qint64 i = 0; i < maxlen; ++i) {
tmp += input[i];
- if ((i % 16) == 15 || i == (input.size() - 1)) {
- printf("\n%15d:", startOffset);
+ if ((i % 16) == 15 || i == (maxlen - 1)) {
+ printf("\n%15lld:", startOffset);
startOffset += tmp.size();
- for (int j = 0; j < tmp.size(); ++j)
+ for (qsizetype j = 0; j < tmp.size(); ++j)
printf(" %02x", int(uchar(tmp[j])));
- for (int j = tmp.size(); j < 16 + 1; ++j)
+ for (qsizetype j = tmp.size(); j < 16 + 1; ++j)
printf(" ");
- for (int j = 0; j < tmp.size(); ++j)
- printf("%c", isprint(int(uchar(tmp[j]))) ? tmp[j] : '.');
+ for (qsizetype j = 0; j < tmp.size(); ++j)
+ printf("%c", isAsciiPrintable(tmp[j]) ? tmp[j] : '.');
tmp.clear();
}
}
printf("\n\n");
}
-void debugBinaryString(const char *data, qint64 maxlen)
-{
- debugBinaryString(QByteArray(data, maxlen));
-}
-#endif
-
#define Q_VOID
+Q_DECL_COLD_FUNCTION
static void checkWarnMessage(const QIODevice *device, const char *function, const char *what)
{
#ifndef QT_NO_WARNING_OUTPUT
@@ -130,9 +88,9 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons
#define CHECK_MAXBYTEARRAYSIZE(function) \
do { \
- if (maxSize >= MaxByteArraySize) { \
+ if (maxSize >= QByteArray::max_size()) { \
checkWarnMessage(this, #function, "maxSize argument exceeds QByteArray size limit"); \
- maxSize = MaxByteArraySize - 1; \
+ maxSize = QByteArray::max_size() - 1; \
} \
} while (0)
@@ -1051,7 +1009,7 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
*data = c;
#if defined QIODEVICE_DEBUG
printf("%p \tread 0x%hhx (%c) returning 1 (shortcut)\n", this,
- int(c), isprint(c) ? c : '?');
+ int(c), isAsciiPrintable(c) ? c : '?');
#endif
if (d->buffer.isEmpty())
readData(data, 0);
@@ -1244,13 +1202,13 @@ QByteArray QIODevice::read(qint64 maxSize)
CHECK_MAXLEN(read, result);
CHECK_MAXBYTEARRAYSIZE(read);
- result.resize(int(maxSize));
+ result.resize(qsizetype(maxSize));
qint64 readBytes = d->read(result.data(), result.size());
if (readBytes <= 0)
result.clear();
else
- result.resize(int(readBytes));
+ result.resize(qsizetype(readBytes));
return result;
}
@@ -1261,7 +1219,9 @@ QByteArray QIODevice::read(qint64 maxSize)
This function has no way of reporting errors; returning an empty
QByteArray can mean either that no data was currently available
- for reading, or that an error occurred.
+ for reading, or that an error occurred. This function also has no
+ way of indicating that more data may have been available and
+ couldn't be read.
*/
QByteArray QIODevice::readAll()
{
@@ -1282,7 +1242,7 @@ QByteArray QIODevice::readAll()
: d->buffer.size());
qint64 readResult;
do {
- if (readBytes + readChunkSize >= MaxByteArraySize) {
+ if (readBytes + readChunkSize >= QByteArray::max_size()) {
// If resize would fail, don't read more, return what we have.
break;
}
@@ -1295,10 +1255,9 @@ QByteArray QIODevice::readAll()
} while (readResult > 0);
} else {
// Read it all in one go.
- // If resize fails, don't read anything.
readBytes -= d->pos;
- if (readBytes >= MaxByteArraySize)
- return QByteArray();
+ if (readBytes >= QByteArray::max_size())
+ readBytes = QByteArray::max_size();
result.resize(readBytes);
readBytes = d->read(result.data(), readBytes);
}
@@ -1306,7 +1265,7 @@ QByteArray QIODevice::readAll()
if (readBytes <= 0)
result.clear();
else
- result.resize(int(readBytes));
+ result.resize(qsizetype(readBytes));
return result;
}
@@ -1367,7 +1326,7 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
#if defined QIODEVICE_DEBUG
printf("%p \treturning %lld, d->pos = %lld, d->buffer.size() = %lld, size() = %lld\n",
this, readBytes, d->pos, d->buffer.size(), size());
- debugBinaryString(data, int(readBytes));
+ debugBinaryString(data, readBytes);
#endif
return readBytes;
@@ -1411,7 +1370,7 @@ qint64 QIODevicePrivate::readLine(char *data, qint64 maxSize)
#if defined QIODEVICE_DEBUG
printf("%p \tread from buffer: %lld bytes, last character read: %hhx\n", q,
readSoFar, data[readSoFar - 1]);
- debugBinaryString(data, int(readSoFar));
+ debugBinaryString(data, readSoFar);
#endif
if (data[readSoFar - 1] == '\n') {
if (openMode & QIODevice::Text) {
@@ -1438,7 +1397,7 @@ qint64 QIODevicePrivate::readLine(char *data, qint64 maxSize)
printf("%p \tread from readLineData: %lld bytes, readSoFar = %lld bytes\n", q,
readBytes, readSoFar);
if (readBytes > 0) {
- debugBinaryString(data, int(readSoFar + readBytes));
+ debugBinaryString(data, readSoFar + readBytes);
}
#endif
if (readBytes < 0) {
@@ -1489,19 +1448,19 @@ QByteArray QIODevice::readLine(qint64 maxSize)
qint64 readBytes = 0;
if (maxSize == 0) {
// Size is unknown, read incrementally.
- maxSize = MaxByteArraySize - 1;
+ maxSize = QByteArray::max_size() - 1;
// The first iteration needs to leave an extra byte for the terminating null
result.resize(1);
qint64 readResult;
do {
- result.resize(int(qMin(maxSize, qint64(result.size() + d->buffer.chunkSize()))));
+ result.resize(qsizetype(qMin(maxSize, qint64(result.size() + d->buffer.chunkSize()))));
readResult = d->readLine(result.data() + readBytes, result.size() - readBytes);
if (readResult > 0 || readBytes == 0)
readBytes += readResult;
} while (readResult == d->buffer.chunkSize()
- && result[int(readBytes - 1)] != '\n');
+ && result[qsizetype(readBytes - 1)] != '\n');
} else {
CHECK_LINEMAXLEN(readLine, result);
CHECK_MAXBYTEARRAYSIZE(readLine);
@@ -1541,7 +1500,7 @@ qint64 QIODevice::readLineData(char *data, qint64 maxSize)
Q_D(QIODevice);
qint64 readSoFar = 0;
char c;
- int lastReadReturn = 0;
+ qint64 lastReadReturn = 0;
d->baseReadLineDataCalled = true;
while (readSoFar < maxSize && (lastReadReturn = read(&c, 1)) == 1) {
@@ -1831,7 +1790,7 @@ void QIODevice::ungetChar(char c)
}
#if defined QIODEVICE_DEBUG
- printf("%p QIODevice::ungetChar(0x%hhx '%c')\n", this, c, isprint(c) ? c : '?');
+ printf("%p QIODevice::ungetChar(0x%hhx '%c')\n", this, c, isAsciiPrintable(c) ? c : '?');
#endif
d->buffer.ungetChar(c);
@@ -2170,7 +2129,7 @@ QString QIODevice::errorString() const
Q_D(const QIODevice);
if (d->errorString.isEmpty()) {
#ifdef QT_NO_QOBJECT
- return QLatin1String(QT_TRANSLATE_NOOP(QIODevice, "Unknown error"));
+ return QLatin1StringView(QT_TRANSLATE_NOOP(QIODevice, "Unknown error"));
#else
return tr("Unknown error");
#endif
@@ -2245,23 +2204,23 @@ QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
debug << "OpenMode(";
QStringList modeList;
if (modes == QIODevice::NotOpen) {
- modeList << QLatin1String("NotOpen");
+ modeList << "NotOpen"_L1;
} else {
if (modes & QIODevice::ReadOnly)
- modeList << QLatin1String("ReadOnly");
+ modeList << "ReadOnly"_L1;
if (modes & QIODevice::WriteOnly)
- modeList << QLatin1String("WriteOnly");
+ modeList << "WriteOnly"_L1;
if (modes & QIODevice::Append)
- modeList << QLatin1String("Append");
+ modeList << "Append"_L1;
if (modes & QIODevice::Truncate)
- modeList << QLatin1String("Truncate");
+ modeList << "Truncate"_L1;
if (modes & QIODevice::Text)
- modeList << QLatin1String("Text");
+ modeList << "Text"_L1;
if (modes & QIODevice::Unbuffered)
- modeList << QLatin1String("Unbuffered");
+ modeList << "Unbuffered"_L1;
}
std::sort(modeList.begin(), modeList.end());
- debug << modeList.join(QLatin1Char('|'));
+ debug << modeList.join(u'|');
debug << ')';
return debug;
}
diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h
index fd97e8d1e5..7844e0f125 100644
--- a/src/corelib/io/qiodevice.h
+++ b/src/corelib/io/qiodevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIODEVICE_H
#define QIODEVICE_H
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index e9a8af0855..f69c055ac5 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIODEVICE_P_H
#define QIODEVICE_P_H
@@ -75,6 +39,7 @@ class Q_CORE_EXPORT QIODevicePrivate
#endif
{
Q_DECLARE_PUBLIC(QIODevice)
+ Q_DISABLE_COPY_MOVE(QIODevicePrivate)
public:
QIODevicePrivate();
diff --git a/src/corelib/io/qiodevicebase.h b/src/corelib/io/qiodevicebase.h
index 3c6ca89f7a..aab63d4351 100644
--- a/src/corelib/io/qiodevicebase.h
+++ b/src/corelib/io/qiodevicebase.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIODEVICEBASE_H
#define QIODEVICEBASE_H
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index 93a74ccd09..c2b274f8b5 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qipaddress_p.h"
#include "private/qlocale_tools_p.h"
@@ -44,20 +8,23 @@
#include "qvarlengtharray.h"
QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
namespace QIPAddressUtils {
-static QString number(quint8 val, int base = 10)
+static QString number(quint8 val)
{
QString zero = QStringLiteral("0");
- return val ? qulltoa(val, base, zero) : zero;
+ return val ? qulltoa(val, 10, zero) : zero;
}
typedef QVarLengthArray<char, 64> Buffer;
static const QChar *checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
{
- const ushort *const ubegin = reinterpret_cast<const ushort *>(begin);
- const ushort *const uend = reinterpret_cast<const ushort *>(end);
- const ushort *src = ubegin;
+ const auto *const ubegin = reinterpret_cast<const char16_t *>(begin);
+ const auto *const uend = reinterpret_cast<const char16_t *>(end);
+ auto *src = ubegin;
buffer.resize(uend - ubegin + 1);
char *dst = buffer.data();
@@ -93,14 +60,12 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
ptr[1] != '.' && ptr[1] != '\0')
return false;
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 0, &ok);
- quint32 x = ll;
- if (!ok || endptr == ptr || ll != x)
+ auto [ll, used] = qstrntoull(ptr, stop - ptr, 0);
+ const quint32 x = quint32(ll);
+ if (used <= 0 || ll != x)
return false;
- if (*endptr == '.' || dotCount == 3) {
+ if (ptr[used] == '.' || dotCount == 3) {
if (x & ~0xff)
return false;
address <<= 8;
@@ -115,15 +80,13 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
}
address |= x;
- if (dotCount == 3 && *endptr != '\0')
- return false;
- else if (dotCount == 3 || *endptr == '\0')
- return true;
- if (*endptr != '.')
+ if (dotCount == 3 || ptr[used] == '\0')
+ return ptr[used] == '\0';
+ if (ptr[used] != '.')
return false;
++dotCount;
- ptr = endptr + 1;
+ ptr += used + 1;
}
return false;
}
@@ -132,12 +95,9 @@ void toString(QString &appendTo, IPv4Address address)
{
// reconstructing is easy
// use the fast operator% that pre-calculates the size
- appendTo += number(address >> 24)
- % QLatin1Char('.')
- % number(address >> 16)
- % QLatin1Char('.')
- % number(address >> 8)
- % QLatin1Char('.')
+ appendTo += number(address >> 24) % u'.'
+ % number(address >> 16) % u'.'
+ % number(address >> 8) % u'.'
% number(address);
}
@@ -214,18 +174,16 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
continue;
}
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 16, &ok);
+ auto [ll, used] = qstrntoull(ptr, stop - ptr, 16);
quint16 x = ll;
// Reject malformed fields:
// - failed to parse
// - too many hex digits
- if (!ok || endptr > ptr + 4)
+ if (used <= 0 || used > 4)
return begin + (ptr - buffer.data());
- if (*endptr == '.') {
+ if (ptr[used] == '.') {
// this could be an IPv4 address
// it's only valid in the last element
if (pos != 12)
@@ -245,11 +203,11 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
address[pos++] = x >> 8;
address[pos++] = x & 0xff;
- if (*endptr == '\0')
+ if (ptr[used] == '\0')
break;
- if (*endptr != ':')
- return begin + (endptr - buffer.data());
- ptr = endptr + 1;
+ if (ptr[used] != ':')
+ return begin + (used + ptr - buffer.data());
+ ptr += used + 1;
}
return pos == 16 ? nullptr : end;
}
@@ -285,7 +243,7 @@ void toString(QString &appendTo, const IPv6Address address)
if (address[12] != 0 || address[13] != 0 || address[14] != 0) {
embeddedIp4 = true;
} else if (address[15] == 0) {
- appendTo.append(QLatin1String("::"));
+ appendTo.append("::"_L1);
return;
}
}
diff --git a/src/corelib/io/qipaddress_p.h b/src/corelib/io/qipaddress_p.h
index ea31e5883d..af3ab52dfd 100644
--- a/src/corelib/io/qipaddress_p.h
+++ b/src/corelib/io/qipaddress_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIPADDRESS_P_H
#define QIPADDRESS_P_H
diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp
index e6812cedde..0eb6acb694 100644
--- a/src/corelib/io/qlockfile.cpp
+++ b/src/corelib/io/qlockfile.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlockfile.h"
#include "qlockfile_p.h"
@@ -50,6 +14,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace {
struct LockFileInfo
{
@@ -94,7 +60,7 @@ static QString machineName()
When protecting for a short-term operation, it is acceptable to call lock() and wait
until any running operation finishes.
When protecting a resource over a long time, however, the application should always
- call setStaleLockTime(0) and then tryLock() with a short timeout, in order to
+ call setStaleLockTime(0ms) and then tryLock() with a short timeout, in order to
warn the user that the resource is locked.
If the process holding the lock crashes, the lock file stays on disk and can prevent
@@ -172,20 +138,24 @@ QString QLockFile::fileName() const
meanwhile, so one way to detect a stale lock file is by the fact that
it has been around for a long time.
+ This is an overloaded function, equivalent to calling:
+ \code
+ setStaleLockTime(std::chrono::milliseconds{staleLockTime});
+ \endcode
+
\sa staleLockTime()
*/
void QLockFile::setStaleLockTime(int staleLockTime)
{
- Q_D(QLockFile);
- d->staleLockTime = staleLockTime;
+ setStaleLockTime(std::chrono::milliseconds{staleLockTime});
}
-/*! \fn void QLockFile::setStaleLockTime(std::chrono::milliseconds value)
- \overload
+/*!
\since 6.2
- Sets the interval after which a lock file is considered stale to \a value.
- The default value is 30 seconds.
+ Sets the interval after which a lock file is considered stale to \a staleLockTime.
+ The default value is 30s.
+
If your application typically keeps the file locked for more than 30 seconds
(for instance while saving megabytes of data for 2 minutes), you should set
a bigger value using setStaleLockTime().
@@ -198,6 +168,11 @@ void QLockFile::setStaleLockTime(int staleLockTime)
\sa staleLockTime()
*/
+void QLockFile::setStaleLockTime(std::chrono::milliseconds staleLockTime)
+{
+ Q_D(QLockFile);
+ d->staleLockTime = staleLockTime;
+}
/*!
Returns the time in milliseconds after which
@@ -207,8 +182,7 @@ void QLockFile::setStaleLockTime(int staleLockTime)
*/
int QLockFile::staleLockTime() const
{
- Q_D(const QLockFile);
- return d->staleLockTime;
+ return int(staleLockTimeAsDuration().count());
}
/*! \fn std::chrono::milliseconds QLockFile::staleLockTimeAsDuration() const
@@ -220,6 +194,11 @@ int QLockFile::staleLockTime() const
\sa setStaleLockTime()
*/
+std::chrono::milliseconds QLockFile::staleLockTimeAsDuration() const
+{
+ Q_D(const QLockFile);
+ return d->staleLockTime;
+}
/*!
Returns \c true if the lock was acquired by this QLockFile instance,
@@ -250,7 +229,7 @@ bool QLockFile::isLocked() const
*/
bool QLockFile::lock()
{
- return tryLock(-1);
+ return tryLock(std::chrono::milliseconds::max());
}
/*!
@@ -275,10 +254,38 @@ bool QLockFile::lock()
*/
bool QLockFile::tryLock(int timeout)
{
+ return tryLock(std::chrono::milliseconds{ timeout });
+}
+
+/*!
+ \overload
+ \since 6.2
+
+ Attempts to create the lock file. This function returns \c true if the
+ lock was obtained; otherwise it returns \c false. If another process (or
+ another thread) has created the lock file already, this function will
+ wait for at most \a timeout for the lock file to become available.
+
+ If the lock was obtained, it must be released with unlock()
+ before another process (or thread) can successfully lock it.
+
+ Calling this function multiple times on the same lock from the same
+ thread without unlocking first is not allowed, this function will
+ \e always return false when attempting to lock the file recursively.
+
+ \sa lock(), unlock()
+*/
+bool QLockFile::tryLock(std::chrono::milliseconds timeout)
+{
+ using namespace std::chrono_literals;
+ using Msec = std::chrono::milliseconds;
+
Q_D(QLockFile);
- QDeadlineTimer timer(qMax(timeout, -1)); // QDT only takes -1 as "forever"
- int sleepTime = 100;
- forever {
+
+ QDeadlineTimer timer(timeout < 0ms ? Msec::max() : timeout);
+
+ Msec sleepTime = 100ms;
+ while (true) {
d->lockError = d->tryLock_sys();
switch (d->lockError) {
case NoError:
@@ -289,11 +296,11 @@ bool QLockFile::tryLock(int timeout)
return false;
case LockFailedError:
if (!d->isLocked && d->isApparentlyStale()) {
- if (Q_UNLIKELY(QFileInfo(d->fileName).lastModified() > QDateTime::currentDateTimeUtc()))
+ if (Q_UNLIKELY(QFileInfo(d->fileName).lastModified(QTimeZone::UTC) > QDateTime::currentDateTimeUtc()))
qInfo("QLockFile: Lock file '%ls' has a modification time in the future", qUtf16Printable(d->fileName));
// Stale lock from another thread/process
// Ensure two processes don't remove it at the same time
- QLockFile rmlock(d->fileName + QLatin1String(".rmlock"));
+ QLockFile rmlock(d->fileName + ".rmlock"_L1);
if (rmlock.tryLock()) {
if (d->isApparentlyStale() && d->removeStaleLock())
continue;
@@ -302,39 +309,21 @@ bool QLockFile::tryLock(int timeout)
break;
}
- int remainingTime = timer.remainingTime();
- if (remainingTime == 0)
+ auto remainingTime = std::chrono::duration_cast<Msec>(timer.remainingTimeAsDuration());
+ if (remainingTime == 0ms)
return false;
- else if (uint(sleepTime) > uint(remainingTime))
+
+ if (sleepTime > remainingTime)
sleepTime = remainingTime;
- QThread::msleep(sleepTime);
- if (sleepTime < 5 * 1000)
+ QThread::sleep(sleepTime);
+ if (sleepTime < 5s)
sleepTime *= 2;
}
// not reached
return false;
}
-/*! \fn bool QLockFile::tryLock(std::chrono::milliseconds timeout)
- \overload
- \since 6.2
-
- Attempts to create the lock file. This function returns \c true if the
- lock was obtained; otherwise it returns \c false. If another process (or
- another thread) has created the lock file already, this function will
- wait for at most \a timeout for the lock file to become available.
-
- If the lock was obtained, it must be released with unlock()
- before another process (or thread) can successfully lock it.
-
- Calling this function multiple times on the same lock from the same
- thread without unlocking first is not allowed, this function will
- \e always return false when attempting to lock the file recursively.
-
- \sa lock(), unlock()
-*/
-
/*!
\fn void QLockFile::unlock()
Releases the lock, by deleting the lock file.
@@ -447,8 +436,10 @@ bool QLockFilePrivate::isApparentlyStale() const
}
}
- const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTimeUtc());
- return staleLockTime > 0 && qAbs(age) > staleLockTime;
+ const QDateTime lastMod = QFileInfo(fileName).lastModified(QTimeZone::UTC);
+ using namespace std::chrono;
+ const milliseconds age{lastMod.msecsTo(QDateTime::currentDateTimeUtc())};
+ return staleLockTime > 0ms && abs(age) > staleLockTime;
}
/*!
diff --git a/src/corelib/io/qlockfile.h b/src/corelib/io/qlockfile.h
index aa5ad5e772..af481ab59b 100644
--- a/src/corelib/io/qlockfile.h
+++ b/src/corelib/io/qlockfile.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCKFILE_H
#define QLOCKFILE_H
@@ -43,9 +7,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qscopedpointer.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -60,22 +22,16 @@ public:
QString fileName() const;
bool lock();
- bool tryLock(int timeout = 0);
+ bool tryLock(int timeout);
void unlock();
void setStaleLockTime(int);
int staleLockTime() const;
-#if __has_include(<chrono>)
- bool tryLock(std::chrono::milliseconds timeout) { return tryLock(int(timeout.count())); }
+ bool tryLock(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero());
- void setStaleLockTime(std::chrono::milliseconds value) { setStaleLockTime(int(value.count())); }
-
- std::chrono::milliseconds staleLockTimeAsDuration() const
- {
- return std::chrono::milliseconds(staleLockTime());
- }
-#endif
+ void setStaleLockTime(std::chrono::milliseconds value);
+ std::chrono::milliseconds staleLockTimeAsDuration() const;
bool isLocked() const;
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h
index 5b69347206..299b13b21a 100644
--- a/src/corelib/io/qlockfile_p.h
+++ b/src/corelib/io/qlockfile_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCKFILE_P_H
#define QLOCKFILE_P_H
@@ -68,15 +32,7 @@ class QLockFilePrivate
{
public:
QLockFilePrivate(const QString &fn)
- : fileName(fn),
-#ifdef Q_OS_WIN
- fileHandle(INVALID_HANDLE_VALUE),
-#else
- fileHandle(-1),
-#endif
- staleLockTime(30 * 1000), // 30 seconds
- lockError(QLockFile::NoError),
- isLocked(false)
+ : fileName(fn)
{
}
QLockFile::LockError tryLock_sys();
@@ -91,14 +47,16 @@ public:
static bool isProcessRunning(qint64 pid, const QString &appname);
QString fileName;
+
#ifdef Q_OS_WIN
- Qt::HANDLE fileHandle;
+ Qt::HANDLE fileHandle = INVALID_HANDLE_VALUE;
#else
- int fileHandle;
+ int fileHandle = -1;
#endif
- int staleLockTime; // "int milliseconds" is big enough for 24 days
- QLockFile::LockError lockError;
- bool isLocked;
+
+ std::chrono::milliseconds staleLockTime = std::chrono::seconds{30};
+ QLockFile::LockError lockError = QLockFile::NoError;
+ bool isLocked = false;
static int getLockFileHandle(QLockFile *f)
{
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 6dcd548441..47aff8b973 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** Copyright (C) 2017 Intel Corporation.
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
+// Copyright (C) 2017 Intel Corporation.
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qlockfile_p.h"
@@ -206,7 +170,7 @@ bool QLockFilePrivate::removeStaleLock()
bool QLockFilePrivate::isProcessRunning(qint64 pid, const QString &appname)
{
- if (::kill(pid, 0) == -1 && errno == ESRCH)
+ if (::kill(pid_t(pid), 0) == -1 && errno == ESRCH)
return false; // PID doesn't exist anymore
const QString processName = processNameByPid(pid);
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index 6c0d2c1f8d..b9d7721517 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qlockfile_p.h"
#include "private/qfilesystementry_p.h"
@@ -142,10 +106,10 @@ QString QLockFilePrivate::processNameByPid(qint64 pid)
if (!length)
return QString();
QString name = QString::fromWCharArray(buf, length);
- int i = name.lastIndexOf(QLatin1Char('\\'));
+ int i = name.lastIndexOf(u'\\');
if (i >= 0)
name.remove(0, i + 1);
- i = name.lastIndexOf(QLatin1Char('.'));
+ i = name.lastIndexOf(u'.');
if (i >= 0)
name.truncate(i);
return name;
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
index 9d08a2cdac..10763dd65a 100644
--- a/src/corelib/io/qloggingcategory.cpp
+++ b/src/corelib/io/qloggingcategory.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qloggingcategory.h"
#include "qloggingregistry_p.h"
@@ -43,21 +7,7 @@
QT_BEGIN_NAMESPACE
const char qtDefaultCategoryName[] = "default";
-
-Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
- (qtDefaultCategoryName))
-
-#ifndef Q_ATOMIC_INT8_IS_SUPPORTED
-static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
-{
- const int bit = 1 << shift;
-
- if (enable)
- atomic->fetchAndOrRelaxed(bit);
- else
- atomic->fetchAndAndRelaxed(~bit);
-}
-#endif
+Q_GLOBAL_STATIC(QLoggingCategory, qtDefaultCategory, qtDefaultCategoryName)
/*!
\class QLoggingCategory
@@ -70,7 +20,8 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
QLoggingCategory represents a certain logging category - identified by a
string - at runtime. A category can be configured to enable or disable
- logging of messages per message type.
+ logging of messages per message type. An exception are fatal messages,
+ which are always enabled.
To check whether a message type is enabled or not, use one of these methods:
\l isDebugEnabled(), \l isInfoEnabled(), \l isWarningEnabled(), and
@@ -89,6 +40,9 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
\snippet qloggingcategory/main.cpp 1
+ There is also the Q_DECLARE_EXPORTED_LOGGING_CATEGORY() macro in
+ order to use a logging category across library boundaries.
+
Category names are free text; to configure categories using \l{Logging Rules}, their
names should follow this convention:
\list
@@ -126,7 +80,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
If no argument is passed, all messages are logged. Only Qt internal categories
which start with \c{qt} are handled differently: For these, only messages of type
- \c QtInfoMsg, \c QtWarningMsg, and \c QtCriticalMsg are logged by default.
+ \c QtInfoMsg, \c QtWarningMsg, \c QtCriticalMsg, and \c QFatalMsg are logged by default.
\note Logging categories are not affected by your C++ build configuration.
That is, whether messages are printed does not change depending on whether
@@ -326,17 +280,10 @@ bool QLoggingCategory::isEnabled(QtMsgType msgtype) const
void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
{
switch (type) {
-#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
case QtDebugMsg: bools.enabledDebug.storeRelaxed(enable); break;
case QtInfoMsg: bools.enabledInfo.storeRelaxed(enable); break;
case QtWarningMsg: bools.enabledWarning.storeRelaxed(enable); break;
case QtCriticalMsg: bools.enabledCritical.storeRelaxed(enable); break;
-#else
- case QtDebugMsg: setBoolLane(&enabled, enable, DebugShift); break;
- case QtInfoMsg: setBoolLane(&enabled, enable, InfoShift); break;
- case QtWarningMsg: setBoolLane(&enabled, enable, WarningShift); break;
- case QtCriticalMsg: setBoolLane(&enabled, enable, CriticalShift); break;
-#endif
case QtFatalMsg: break;
}
}
@@ -346,7 +293,7 @@ void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
Returns the object itself. This allows for both: a QLoggingCategory variable, and
a factory method that returns a QLoggingCategory, to be used in \l qCDebug(),
- \l qCWarning(), or \l qCCritical() macros.
+ \l qCWarning(), \l qCCritical(), or \l qCFatal() macros.
*/
/*!
@@ -354,7 +301,7 @@ void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
Returns the object itself. This allows for both: a QLoggingCategory variable, and
a factory method that returns a QLoggingCategory, to be used in \l qCDebug(),
- \l qCWarning(), or \l qCCritical() macros.
+ \l qCWarning(), \l qCCritical(), or \l qCFatal() macros.
*/
/*!
@@ -381,13 +328,27 @@ QLoggingCategory *QLoggingCategory::defaultCategory()
*/
/*!
- Installs a function \a filter that is used to determine which categories
- and message types should be enabled. Returns a pointer to the previous
- installed filter.
-
- Every QLoggingCategory object created is passed to the filter, and the
- filter is free to change the respective category configuration with
- \l setEnabled().
+ \brief Take control of how logging categories are configured.
+
+ Installs a function \a filter that is used to determine which categories and
+ message types should be enabled. If \a filter is \nullptr, the default
+ message filter is reinstated. Returns a pointer to the previously-installed
+ filter.
+
+ Every QLoggingCategory object that already exists is passed to the filter
+ before \c installFilter() returns, and the filter is free to change each
+ category's configuration with \l setEnabled(). Any category it doesn't
+ change will retain the configuration it was given by the prior filter, so
+ the new filter does not need to delegate to the prior filter during this
+ initial pass over existing categories.
+
+ Any new categories added later will be passed to the new filter; a filter
+ that only aims to tweak the configuration of a select few categories, rather
+ than completely overriding the logging policy, can first pass the new
+ category to the prior filter, to give it its standard configuration, and
+ then tweak that as desired, if it is one of the categories of specific
+ interest to the filter. The code that installs the new filter can record the
+ return from \c installFilter() for the filter to use in such later calls.
When you define your filter, note that it can be called from different threads; but never
concurrently. This filter cannot call any static functions from QLoggingCategory.
@@ -395,6 +356,10 @@ QLoggingCategory *QLoggingCategory::defaultCategory()
Example:
\snippet qloggingcategory/main.cpp 21
+ installed (in \c{main()}, for example) by
+
+ \snippet qloggingcategory/main.cpp 22
+
Alternatively, you can configure the default filter via \l setFilterRules().
*/
QLoggingCategory::CategoryFilter
@@ -592,9 +557,49 @@ void QLoggingCategory::setFilterRules(const QString &rules)
\sa qCritical()
*/
+
+/*!
+ \macro qCFatal(category)
+ \relates QLoggingCategory
+ \since 6.5
+
+ Returns an output stream for fatal messages in the logging category,
+ \a category.
+
+ If you are using the \b{default message handler}, the returned stream will abort
+ to create a core dump. On Windows, for debug builds, this function will
+ report a \c _CRT_ERROR enabling you to connect a debugger to the application.
+
+ Example:
+
+ \snippet qloggingcategory/main.cpp 16
+
+ \sa qFatal()
+*/
+
+/*!
+ \macro qCFatal(category, const char *message, ...)
+ \relates QLoggingCategory
+ \since 6.5
+
+ Logs a fatal message, \a message, in the logging category, \a category.
+ \a message may contain place holders to be replaced by additional arguments,
+ similar to the C printf() function.
+
+ Example:
+
+ \snippet qloggingcategory/main.cpp 17
+
+ If you are using the \b{default message handler}, this function will abort
+ to create a core dump. On Windows, for debug builds, this function will
+ report a \c _CRT_ERROR enabling you to connect a debugger to the application.
+
+ \sa qFatal()
+*/
+
/*!
\macro Q_DECLARE_LOGGING_CATEGORY(name)
- \sa Q_LOGGING_CATEGORY()
+ \sa Q_LOGGING_CATEGORY(), Q_DECLARE_EXPORTED_LOGGING_CATEGORY()
\relates QLoggingCategory
\since 5.2
@@ -605,8 +610,31 @@ void QLoggingCategory::setFilterRules(const QString &rules)
*/
/*!
+ \macro Q_DECLARE_EXPORTED_LOGGING_CATEGORY(name, EXPORT_MACRO)
+ \sa Q_LOGGING_CATEGORY(), Q_DECLARE_LOGGING_CATEGORY()
+ \relates QLoggingCategory
+ \since 6.5
+
+ Declares a logging category \a name. The macro can be used to declare
+ a common logging category shared in different parts of the program.
+
+ This works exactly like Q_DECLARE_LOGGING_CATEGORY(). However,
+ the logging category declared by this macro is additionally
+ qualified with \a EXPORT_MACRO. This is useful if the logging
+ category needs to be exported from a dynamic library.
+
+ For example:
+
+ \code
+ Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcCore, LIB_EXPORT_MACRO)
+ \endcode
+
+ This macro must be used outside of a class or function.
+*/
+
+/*!
\macro Q_LOGGING_CATEGORY(name, string)
- \sa Q_DECLARE_LOGGING_CATEGORY()
+ \sa Q_DECLARE_LOGGING_CATEGORY(), Q_DECLARE_EXPORTED_LOGGING_CATEGORY()
\relates QLoggingCategory
\since 5.2
@@ -634,8 +662,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
with a specific name. The implicitly-defined QLoggingCategory object is
created on first use, in a thread-safe manner.
- This macro must be used outside of a class or method. It is only defined
- if variadic macros are supported.
+ This macro must be used outside of a class or method.
*/
QT_END_NAMESPACE
diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h
index 5a66bb2e68..7c32beea1a 100644
--- a/src/corelib/io/qloggingcategory.h
+++ b/src/corelib/io/qloggingcategory.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOGGINGCATEGORY_H
#define QLOGGINGCATEGORY_H
@@ -55,17 +19,11 @@ public:
bool isEnabled(QtMsgType type) const;
void setEnabled(QtMsgType type, bool enable);
-#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
bool isDebugEnabled() const { return bools.enabledDebug.loadRelaxed(); }
bool isInfoEnabled() const { return bools.enabledInfo.loadRelaxed(); }
bool isWarningEnabled() const { return bools.enabledWarning.loadRelaxed(); }
bool isCriticalEnabled() const { return bools.enabledCritical.loadRelaxed(); }
-#else
- bool isDebugEnabled() const { return enabled.loadRelaxed() >> DebugShift & 1; }
- bool isInfoEnabled() const { return enabled.loadRelaxed() >> InfoShift & 1; }
- bool isWarningEnabled() const { return enabled.loadRelaxed() >> WarningShift & 1; }
- bool isCriticalEnabled() const { return enabled.loadRelaxed() >> CriticalShift & 1; }
-#endif
+
const char *categoryName() const { return name; }
// allows usage of both factory method and variable in qCX macros
@@ -85,19 +43,11 @@ private:
Q_DECL_UNUSED_MEMBER void *d; // reserved for future use
const char *name;
-#ifdef Q_BIG_ENDIAN
- enum { DebugShift = 0, WarningShift = 8, CriticalShift = 16, InfoShift = 24 };
-#else
- enum { DebugShift = 24, WarningShift = 16, CriticalShift = 8, InfoShift = 0};
-#endif
-
struct AtomicBools {
-#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
QBasicAtomicInteger<bool> enabledDebug;
QBasicAtomicInteger<bool> enabledWarning;
QBasicAtomicInteger<bool> enabledCritical;
QBasicAtomicInteger<bool> enabledInfo;
-#endif
};
union {
AtomicBools bools;
@@ -112,16 +62,11 @@ template <QtMsgType Which> struct QLoggingCategoryMacroHolder
static const bool IsOutputEnabled;
const QLoggingCategory *category = nullptr;
bool control = false;
- QLoggingCategoryMacroHolder(const QLoggingCategory &cat)
+ explicit QLoggingCategoryMacroHolder(const QLoggingCategory &cat)
{
if (IsOutputEnabled)
init(cat);
}
- QLoggingCategoryMacroHolder(QMessageLogger::CategoryFunction catfunc)
- {
- if (IsOutputEnabled)
- init(catfunc());
- }
void init(const QLoggingCategory &cat) noexcept
{
category = &cat;
@@ -134,12 +79,16 @@ template <QtMsgType Which> struct QLoggingCategoryMacroHolder
control = cat.isInfoEnabled();
} else if constexpr (Which == QtWarningMsg) {
control = cat.isWarningEnabled();
- } else {
+ } else if constexpr (Which == QtCriticalMsg) {
control = cat.isCriticalEnabled();
+ } else if constexpr (Which == QtFatalMsg) {
+ control = true;
+ } else {
+ static_assert(QtPrivate::value_dependent_false<Which>(), "Unknown Qt message type");
}
}
- operator const char *() const { return category->categoryName(); }
- operator bool() const { return Q_UNLIKELY(control); }
+ const char *name() const { return category->categoryName(); }
+ explicit operator bool() const { return Q_UNLIKELY(control); }
};
template <QtMsgType Which> const bool QLoggingCategoryMacroHolder<Which>::IsOutputEnabled = true;
@@ -155,7 +104,10 @@ template <> const bool QLoggingCategoryMacroHolder<QtWarningMsg>::IsOutputEnable
} // unnamed namespace
#define Q_DECLARE_LOGGING_CATEGORY(name) \
- extern const QLoggingCategory &name();
+ const QLoggingCategory &name();
+
+#define Q_DECLARE_EXPORTED_LOGGING_CATEGORY(name, export_macro) \
+ export_macro Q_DECLARE_LOGGING_CATEGORY(name)
#define Q_LOGGING_CATEGORY(name, ...) \
const QLoggingCategory &name() \
@@ -165,13 +117,14 @@ template <> const bool QLoggingCategoryMacroHolder<QtWarningMsg>::IsOutputEnable
}
#define QT_MESSAGE_LOGGER_COMMON(category, level) \
- for (QLoggingCategoryMacroHolder<level> qt_category(category); qt_category; qt_category.control = false) \
- QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, qt_category)
+ for (QLoggingCategoryMacroHolder<level> qt_category((category)()); qt_category; qt_category.control = false) \
+ QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, qt_category.name())
#define qCDebug(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtDebugMsg).debug(__VA_ARGS__)
#define qCInfo(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtInfoMsg).info(__VA_ARGS__)
#define qCWarning(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtWarningMsg).warning(__VA_ARGS__)
#define qCCritical(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtCriticalMsg).critical(__VA_ARGS__)
+#define qCFatal(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtFatalMsg).fatal(__VA_ARGS__)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 73b98190a7..b4181a2fa6 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qloggingregistry_p.h"
@@ -60,14 +24,15 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry)
/*!
\internal
Constructs a logging rule with default values.
*/
-QLoggingRule::QLoggingRule() :
- enabled(false)
+QLoggingRule::QLoggingRule()
{
}
@@ -75,9 +40,7 @@ QLoggingRule::QLoggingRule() :
\internal
Constructs a logging rule.
*/
-QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) :
- messageType(-1),
- enabled(enabled)
+QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) : enabled(enabled)
{
parse(pattern);
}
@@ -87,7 +50,7 @@ QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) :
Return value 1 means filter passed, 0 means filter doesn't influence this
category, -1 means category doesn't pass this filter.
*/
-int QLoggingRule::pass(QLatin1String cat, QtMsgType msgType) const
+int QLoggingRule::pass(QLatin1StringView cat, QtMsgType msgType) const
{
// check message type
if (messageType > -1 && messageType != msgType)
@@ -101,7 +64,7 @@ int QLoggingRule::pass(QLatin1String cat, QtMsgType msgType) const
return 0;
}
- const int idx = cat.indexOf(category);
+ const qsizetype idx = cat.indexOf(category);
if (idx >= 0) {
if (flags == MidFilter) {
// matches somewhere
@@ -112,7 +75,7 @@ int QLoggingRule::pass(QLatin1String cat, QtMsgType msgType) const
return (enabled ? 1 : -1);
} else if (flags == RightFilter) {
// matches right
- if (idx == (cat.size() - category.count()))
+ if (idx == (cat.size() - category.size()))
return (enabled ? 1 : -1);
}
}
@@ -133,34 +96,35 @@ void QLoggingRule::parse(QStringView pattern)
QStringView p;
// strip trailing ".messagetype"
- if (pattern.endsWith(QLatin1String(".debug"))) {
+ if (pattern.endsWith(".debug"_L1)) {
p = pattern.chopped(6); // strlen(".debug")
messageType = QtDebugMsg;
- } else if (pattern.endsWith(QLatin1String(".info"))) {
+ } else if (pattern.endsWith(".info"_L1)) {
p = pattern.chopped(5); // strlen(".info")
messageType = QtInfoMsg;
- } else if (pattern.endsWith(QLatin1String(".warning"))) {
+ } else if (pattern.endsWith(".warning"_L1)) {
p = pattern.chopped(8); // strlen(".warning")
messageType = QtWarningMsg;
- } else if (pattern.endsWith(QLatin1String(".critical"))) {
+ } else if (pattern.endsWith(".critical"_L1)) {
p = pattern.chopped(9); // strlen(".critical")
messageType = QtCriticalMsg;
} else {
p = pattern;
}
- if (!p.contains(QLatin1Char('*'))) {
+ const QChar asterisk = u'*';
+ if (!p.contains(asterisk)) {
flags = FullText;
} else {
- if (p.endsWith(QLatin1Char('*'))) {
+ if (p.endsWith(asterisk)) {
flags |= LeftFilter;
p = p.chopped(1);
}
- if (p.startsWith(QLatin1Char('*'))) {
+ if (p.startsWith(asterisk)) {
flags |= RightFilter;
p = p.mid(1);
}
- if (p.contains(QLatin1Char('*'))) // '*' only supported at start/end
+ if (p.contains(asterisk)) // '*' only supported at start/end
flags = PatternFlags();
}
@@ -216,33 +180,33 @@ void QLoggingSettingsParser::parseNextLine(QStringView line)
line = line.trimmed();
// comment
- if (line.startsWith(QLatin1Char(';')))
+ if (line.startsWith(u';'))
return;
- if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
+ if (line.startsWith(u'[') && line.endsWith(u']')) {
// new section
auto sectionName = line.mid(1).chopped(1).trimmed();
- m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0;
+ m_inRulesSection = sectionName.compare("rules"_L1, Qt::CaseInsensitive) == 0;
return;
}
if (m_inRulesSection) {
- int equalPos = line.indexOf(QLatin1Char('='));
+ const qsizetype equalPos = line.indexOf(u'=');
if (equalPos != -1) {
- if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
+ if (line.lastIndexOf(u'=') == equalPos) {
const auto key = line.left(equalPos).trimmed();
#if QT_CONFIG(settings)
QString tmp;
- QSettingsPrivate::iniUnescapedKey(key.toUtf8(), 0, key.length(), tmp);
+ QSettingsPrivate::iniUnescapedKey(key.toUtf8(), tmp);
QStringView pattern = qToStringViewIgnoringNull(tmp);
#else
QStringView pattern = key;
#endif
const auto valueStr = line.mid(equalPos + 1).trimmed();
int value = -1;
- if (valueStr == QLatin1String("true"))
+ if (valueStr == "true"_L1)
value = 1;
- else if (valueStr == QLatin1String("false"))
+ else if (valueStr == "false"_L1)
value = 0;
QLoggingRule rule(pattern, (value == 1));
if (rule.flags != 0 && (value != -1))
@@ -277,20 +241,29 @@ QLoggingRegistry::QLoggingRegistry()
static bool qtLoggingDebug()
{
- static const bool debugEnv = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
+ static const bool debugEnv = [] {
+ bool debug = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
+ if (debug)
+ debugMsg("QT_LOGGING_DEBUG environment variable is set.");
+ return debug;
+ }();
return debugEnv;
}
static QList<QLoggingRule> loadRulesFromFile(const QString &filePath)
{
+ if (qtLoggingDebug()) {
+ debugMsg("Checking \"%s\" for rules",
+ QDir::toNativeSeparators(filePath).toUtf8().constData());
+ }
+
QFile file(filePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- if (qtLoggingDebug())
- debugMsg("Loading \"%s\" ...",
- QDir::toNativeSeparators(file.fileName()).toUtf8().constData());
QTextStream stream(&file);
QLoggingSettingsParser parser;
parser.setContent(stream);
+ if (qtLoggingDebug())
+ debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
return parser.rules();
}
return QList<QLoggingRule>();
@@ -303,19 +276,30 @@ static QList<QLoggingRule> loadRulesFromFile(const QString &filePath)
*/
void QLoggingRegistry::initializeRules()
{
+ if (qtLoggingDebug()) {
+ debugMsg("Initializing the rules database ...");
+ debugMsg("Checking %s environment variable", "QTLOGGING_CONF");
+ }
QList<QLoggingRule> er, qr, cr;
// get rules from environment
const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
if (!rulesFilePath.isEmpty())
er = loadRulesFromFile(QFile::decodeName(rulesFilePath));
+ if (qtLoggingDebug())
+ debugMsg("Checking %s environment variable", "QT_LOGGING_RULES");
+
const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
if (!rulesSrc.isEmpty()) {
- QTextStream stream(rulesSrc);
- QLoggingSettingsParser parser;
- parser.setImplicitRulesSection(true);
- parser.setContent(stream);
- er += parser.rules();
+ QTextStream stream(rulesSrc);
+ QLoggingSettingsParser parser;
+ parser.setImplicitRulesSection(true);
+ parser.setContent(stream);
+
+ if (qtLoggingDebug())
+ debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
+
+ er += parser.rules();
}
const QString configFileName = QStringLiteral("qtlogging.ini");
@@ -380,10 +364,10 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
for enabling debugging by default for category \a categoryName. The
category name must start with "qt."
*/
-void QLoggingRegistry::registerEnvironmentOverrideForCategory(QByteArrayView categoryName,
- QByteArrayView environment)
+void QLoggingRegistry::registerEnvironmentOverrideForCategory(const char *categoryName,
+ const char *environment)
{
- qtCategoryEnvironmentOverrides.insert(categoryName, environment);
+ qtCategoryEnvironmentOverrides.insert_or_assign(categoryName, environment);
}
/*!
@@ -475,11 +459,11 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
if (it == reg->qtCategoryEnvironmentOverrides.end())
debug = false;
else
- debug = qEnvironmentVariableIntValue(it.value().data());
+ debug = qEnvironmentVariableIntValue(it->second);
}
}
- const auto categoryName = QLatin1String(cat->categoryName());
+ const auto categoryName = QLatin1StringView(cat->categoryName());
for (const auto &ruleSet : reg->ruleSets) {
for (const auto &rule : ruleSet) {
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 0009d8d2ea..92b96f0ba4 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOGGINGREGISTRY_P_H
#define QLOGGINGREGISTRY_P_H
@@ -54,11 +18,13 @@
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qlist.h>
-#include <QtCore/qmap.h>
+#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qtextstream.h>
+#include <map>
+
class tst_QLoggingRegistry;
QT_BEGIN_NAMESPACE
@@ -78,7 +44,7 @@ class Q_AUTOTEST_EXPORT QLoggingRule
public:
QLoggingRule();
QLoggingRule(QStringView pattern, bool enabled);
- int pass(QLatin1String categoryName, QtMsgType type) const;
+ int pass(QLatin1StringView categoryName, QtMsgType type) const;
enum PatternFlag {
FullText = 0x1,
@@ -89,9 +55,9 @@ public:
Q_DECLARE_FLAGS(PatternFlags, PatternFlag)
QString category;
- int messageType;
+ int messageType = -1;
PatternFlags flags;
- bool enabled;
+ bool enabled = false;
private:
void parse(QStringView pattern);
@@ -120,6 +86,7 @@ private:
class Q_AUTOTEST_EXPORT QLoggingRegistry
{
+ Q_DISABLE_COPY_MOVE(QLoggingRegistry)
public:
QLoggingRegistry();
@@ -131,7 +98,7 @@ public:
#ifndef QT_BUILD_INTERNAL
Q_CORE_EXPORT // always export from QtCore
#endif
- void registerEnvironmentOverrideForCategory(QByteArrayView categoryName, QByteArrayView environment);
+ void registerEnvironmentOverrideForCategory(const char *categoryName, const char *environment);
void setApiRules(const QString &content);
@@ -161,7 +128,7 @@ private:
QList<QLoggingRule> ruleSets[NumRuleSets];
QHash<QLoggingCategory *, QtMsgType> categories;
QLoggingCategory::CategoryFilter categoryFilter;
- QMap<QByteArrayView, QByteArrayView> qtCategoryEnvironmentOverrides;
+ std::map<QByteArrayView, const char *> qtCategoryEnvironmentOverrides;
friend class ::tst_QLoggingRegistry;
};
@@ -174,12 +141,12 @@ public:
{}
private:
- static const char *registerOverride(QByteArrayView categoryName, QByteArrayView environment)
+ static const char *registerOverride(const char *categoryName, const char *environment)
{
QLoggingRegistry *c = QLoggingRegistry::instance();
if (c)
c->registerEnvironmentOverrideForCategory(categoryName, environment);
- return categoryName.data();
+ return categoryName;
}
};
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
index 73075c532f..260fea7969 100644
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnoncontiguousbytedevice_p.h"
#include <qbuffer.h>
@@ -136,14 +100,18 @@ QNonContiguousByteDevice::~QNonContiguousByteDevice()
}
// FIXME we should scrap this whole implementation and instead change the ByteArrayImpl to be able to cope with sub-arrays?
-QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice()
+QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b)
+ : QNonContiguousByteDevice(),
+ buffer(b),
+ byteArray(QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(),
+ buffer->size() - buffer->pos())),
+ arrayImpl(new QNonContiguousByteDeviceByteArrayImpl(&byteArray))
{
- buffer = b;
- byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos());
- arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray);
arrayImpl->setParent(this);
- connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead()));
- connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64)));
+ connect(arrayImpl, &QNonContiguousByteDevice::readyRead, this,
+ &QNonContiguousByteDevice::readyRead);
+ connect(arrayImpl, &QNonContiguousByteDevice::readProgress, this,
+ &QNonContiguousByteDevice::readProgress);
}
QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl()
@@ -175,9 +143,9 @@ qint64 QNonContiguousByteDeviceBufferImpl::size() const
return arrayImpl->size();
}
-QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0)
+QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba)
+ : QNonContiguousByteDevice(), byteArray(ba), currentPosition(0)
{
- byteArray = ba;
}
QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl()
@@ -281,14 +249,19 @@ qint64 QNonContiguousByteDeviceRingBufferImpl::size() const
QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
: QNonContiguousByteDevice(),
- currentReadBuffer(nullptr), currentReadBufferSize(16*1024),
- currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
- eof(false)
+ device(d),
+ currentReadBuffer(nullptr),
+ currentReadBufferSize(16 * 1024),
+ currentReadBufferAmount(0),
+ currentReadBufferPosition(0),
+ totalAdvancements(0),
+ eof(false),
+ initialPosition(d->pos())
{
- device = d;
- initialPosition = d->pos();
- connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
- connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
+ connect(device, &QIODevice::readyRead, this,
+ &QNonContiguousByteDevice::readyRead);
+ connect(device, &QIODevice::readChannelFinished, this,
+ &QNonContiguousByteDevice::readyRead);
}
QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
@@ -298,7 +271,7 @@ QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
const char *QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
{
- if (eof == true) {
+ if (eof) {
len = -1;
return nullptr;
}
@@ -314,7 +287,8 @@ const char *QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng
return currentReadBuffer->data() + currentReadBufferPosition;
}
- qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize));
+ qint64 haveRead = device->read(currentReadBuffer->data(),
+ qMin(maximumLength, currentReadBufferSize));
if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
eof = true;
@@ -348,7 +322,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
if (currentReadBufferPosition > currentReadBufferAmount) {
qint64 i = currentReadBufferPosition - currentReadBufferAmount;
while (i > 0) {
- if (device->getChar(nullptr) == false) {
+ if (!device->getChar(nullptr)) {
emit readProgress(totalAdvancements - i, size());
return false; // ### FIXME handle eof
}
@@ -364,7 +338,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() const
{
- return eof == true;
+ return eof;
}
bool QNonContiguousByteDeviceIoDeviceImpl::reset()
@@ -403,18 +377,16 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() const
return device->pos();
}
-QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)nullptr)
+QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd)
+ : QIODevice(nullptr), byteDevice(bd)
{
- byteDevice = bd;
- connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ connect(bd, &QNonContiguousByteDevice::readyRead, this, &QIODevice::readyRead);
open(ReadOnly);
}
QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()
-{
-
-}
+ = default;
bool QByteDeviceWrappingIoDevice::isSequential() const
{
@@ -519,9 +491,10 @@ std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::creat
\internal
*/
-QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
+QNonContiguousByteDevice *
+QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
{
- return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer);
+ return new QNonContiguousByteDeviceRingBufferImpl(std::move(ringBuffer));
}
/*!
@@ -529,7 +502,8 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_pt
\internal
*/
-std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer)
+std::shared_ptr<QNonContiguousByteDevice>
+QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer)
{
return std::make_shared<QNonContiguousByteDeviceRingBufferImpl>(std::move(ringBuffer));
}
@@ -551,7 +525,8 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *by
\internal
*/
-std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QByteArray *byteArray)
+std::shared_ptr<QNonContiguousByteDevice>
+QNonContiguousByteDeviceFactory::createShared(QByteArray *byteArray)
{
return std::make_shared<QNonContiguousByteDeviceByteArrayImpl>(byteArray);
}
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
index 94d8e5ef9c..eb75034c6a 100644
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNONCONTIGUOUSBYTEDEVICE_P_H
#define QNONCONTIGUOUSBYTEDEVICE_P_H
@@ -102,6 +66,7 @@ public:
class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice
{
+ Q_OBJECT
public:
explicit QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba);
~QNonContiguousByteDeviceByteArrayImpl();
@@ -119,6 +84,7 @@ protected:
class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice
{
+ Q_OBJECT
public:
explicit QNonContiguousByteDeviceRingBufferImpl(std::shared_ptr<QRingBuffer> rb);
~QNonContiguousByteDeviceRingBufferImpl();
@@ -179,6 +145,7 @@ protected:
// ... and the reverse thing
class QByteDeviceWrappingIoDevice : public QIODevice
{
+ Q_OBJECT
public:
explicit QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd);
~QByteDeviceWrappingIoDevice();
diff --git a/src/corelib/io/qntdll_p.h b/src/corelib/io/qntdll_p.h
index caf34ddb5f..1669d4a6dd 100644
--- a/src/corelib/io/qntdll_p.h
+++ b/src/corelib/io/qntdll_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNTDLL_P_H
#define QNTDLL_P_H
@@ -51,6 +15,8 @@
// We mean it.
//
+#include <QtCore/private/qglobal_p.h>
+
#include <winternl.h>
QT_BEGIN_NAMESPACE
@@ -68,7 +34,7 @@ typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
ULONG ByteOffsetForPartitionAlignment;
} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
-#if !defined(Q_CC_CLANG) && !defined(Q_CC_MINGW)
+#if !defined(Q_CC_MINGW)
// keep the following enumeration as is, taken from
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_fsinfoclass
// Unfortunately we can't include the wdm.h header, so we duplicate the code here.
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 23c90daff4..108ee0b7c3 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QPROCESS_DEBUG
@@ -71,6 +35,8 @@ QT_BEGIN_NAMESPACE
\reentrant
\since 4.6
+ \compares equality
+
A process's environment is composed of a set of key=value pairs known as
environment variables. The QProcessEnvironment class wraps that concept
and allows easy manipulation of those variables. It's meant to be used
@@ -98,7 +64,7 @@ QStringList QProcessEnvironmentPrivate::toList() const
QStringList result;
result.reserve(vars.size());
for (auto it = vars.cbegin(), end = vars.cend(); it != end; ++it)
- result << nameToString(it.key()) + QLatin1Char('=') + valueToString(it.value());
+ result << nameToString(it.key()) + u'=' + valueToString(it.value());
return result;
}
@@ -108,7 +74,7 @@ QProcessEnvironment QProcessEnvironmentPrivate::fromList(const QStringList &list
QStringList::ConstIterator it = list.constBegin(),
end = list.constEnd();
for ( ; it != end; ++it) {
- int pos = it->indexOf(QLatin1Char('='), 1);
+ const qsizetype pos = it->indexOf(u'=', 1);
if (pos < 1)
continue;
@@ -148,15 +114,27 @@ void QProcessEnvironmentPrivate::insert(const QProcessEnvironmentPrivate &other)
}
/*!
+ \enum QProcessEnvironment::Initialization
+
+ This enum contains a token that is used to disambiguate constructors.
+
+ \value InheritFromParent A QProcessEnvironment will be created that, when
+ set on a QProcess, causes it to inherit variables from its parent.
+
+ \since 6.3
+*/
+
+/*!
Creates a new QProcessEnvironment object. This constructor creates an
empty environment. If set on a QProcess, this will cause the current
- environment variables to be removed.
+ environment variables to be removed (except for PATH and SystemRoot
+ on Windows).
*/
QProcessEnvironment::QProcessEnvironment() : d(new QProcessEnvironmentPrivate) { }
/*!
Creates an object that when set on QProcess will cause it to be executed with
- environment variables inherited from the parent process.
+ environment variables inherited from its parent process.
\note The created object does not store any environment variables by itself,
it just indicates to QProcess to arrange for inheriting the environment at the
@@ -172,7 +150,7 @@ QProcessEnvironment::QProcessEnvironment() : d(new QProcessEnvironmentPrivate) {
\sa inheritsFromParent(), systemEnvironment()
\since 6.3
*/
-QProcessEnvironment::QProcessEnvironment(QProcessEnvironment::Initialization) : d(nullptr) { }
+QProcessEnvironment::QProcessEnvironment(QProcessEnvironment::Initialization) noexcept { }
/*!
Frees the resources associated with this QProcessEnvironment object.
@@ -208,15 +186,17 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o
*/
/*!
- \fn bool QProcessEnvironment::operator !=(const QProcessEnvironment &other) const
+ \fn bool QProcessEnvironment::operator!=(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
- Returns \c true if this and the \a other QProcessEnvironment objects are different.
+ Returns \c true if the process environment objects \a lhs and \a rhs are different.
\sa operator==()
*/
/*!
- Returns \c true if this and the \a other QProcessEnvironment objects are equal.
+ \fn bool QProcessEnvironment::operator==(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
+
+ Returns \c true if the process environment objects \a lhs and \a rhs are equal.
Two QProcessEnvironment objects are considered equal if they have the same
set of key=value pairs. The comparison of keys is done case-sensitive on
@@ -224,12 +204,12 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o
\sa operator!=(), contains()
*/
-bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
+bool comparesEqual(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
{
- if (d == other.d)
+ if (lhs.d == rhs.d)
return true;
- return d && other.d && d->vars == other.d->vars;
+ return lhs.d && rhs.d && lhs.d->vars == rhs.d->vars;
}
/*!
@@ -476,6 +456,97 @@ void QProcessPrivate::Channel::clear()
\note QProcess is not supported on VxWorks, iOS, tvOS, or watchOS.
+ \section1 Finding the Executable
+
+ The program to be run can be set either by calling setProgram() or directly
+ in the start() call. The effect of calling start() with the program name
+ and arguments is equivalent to calling setProgram() and setArguments()
+ before that function and then calling the overload without those
+ parameters.
+
+ QProcess interprets the program name in one of three different ways,
+ similar to how Unix shells and the Windows command interpreter operate in
+ their own command-lines:
+
+ \list
+ \li If the program name is an absolute path, then that is the exact
+ executable that will be launched and QProcess performs no searching.
+
+ \li If the program name is a relative path with more than one path
+ component (that is, it contains at least one slash), the starting
+ directory where that relative path is searched is OS-dependent: on
+ Windows, it's the parent process' current working dir, while on Unix it's
+ the one set with setWorkingDirectory().
+
+ \li If the program name is a plain file name with no slashes, the
+ behavior is operating-system dependent. On Unix systems, QProcess will
+ search the \c PATH environment variable; on Windows, the search is
+ performed by the OS and will first the parent process' current directory
+ before the \c PATH environment variable (see the documentation for
+ \l{CreateProcess} for the full list).
+ \endlist
+
+ To avoid platform-dependent behavior or any issues with how the current
+ application was launched, it is advisable to always pass an absolute path
+ to the executable to be launched. For auxiliary binaries shipped with the
+ application, one can construct such a path starting with
+ QCoreApplication::applicationDirPath(). Similarly, to explicitly run an
+ executable that is to be found relative to the directory set with
+ setWorkingDirectory(), use a program path starting with "./" or "../" as
+ the case may be.
+
+ On Windows, the ".exe" suffix is not required for most uses, except those
+ outlined in the \l{CreateProcess} documentation. Additionally, QProcess
+ will convert the Unix-style forward slashes to Windows path backslashes for
+ the program name. This allows code using QProcess to be written in a
+ cross-platform manner, as shown in the examples above.
+
+ QProcess does not support directly executing Unix shell or Windows command
+ interpreter built-in functions, such as \c{cmd.exe}'s \c dir command or the
+ Bourne shell's \c export. On Unix, even though many shell built-ins are
+ also provided as separate executables, their behavior may differ from those
+ implemented as built-ins. To run those commands, one should explicitly
+ execute the interpreter with suitable options. For Unix systems, launch
+ "/bin/sh" with two arguments: "-c" and a string with the command-line to be
+ run. For Windows, due to the non-standard way \c{cmd.exe} parses its
+ command-line, use setNativeArguments() (for example, "/c dir d:").
+
+ \section1 Environment variables
+
+ The QProcess API offers methods to manipulate the environment variables
+ that the child process will see. By default, the child process will have a
+ copy of the current process environment variables that exist at the time
+ the start() function is called. This means that any modifications performed
+ using qputenv() prior to that call will be reflected in the child process'
+ environment. Note that QProcess makes no attempt to prevent race conditions
+ with qputenv() happening in other threads, so it is recommended to avoid
+ qputenv() after the application's initial start up.
+
+ The environment for a specific child can be modified using the
+ processEnvironment() and setProcessEnvironment() functions, which use the
+ \l QProcessEnvironment class. By default, processEnvironment() will return
+ an object for which QProcessEnvironment::inheritsFromParent() is true.
+ Setting an environment that does not inherit from the parent will cause
+ QProcess to use exactly that environment for the child when it is started.
+
+ The normal scenario starts from the current environment by calling
+ QProcessEnvironment::systemEnvironment() and then proceeds to adding,
+ changing, or removing specific variables. The resulting variable roster can
+ then be applied to a QProcess with setProcessEnvironment().
+
+ It is possible to remove all variables from the environment or to start
+ from an empty environment, using the QProcessEnvironment() default
+ constructor. This is not advisable outside of controlled and
+ system-specific conditions, as there may be system variables that are set
+ in the current process environment and are required for proper execution
+ of the child process.
+
+ On Windows, QProcess will copy the current process' \c "PATH" and \c
+ "SystemRoot" environment variables if they were unset. It is not possible
+ to unset them completely, but it is possible to set them to empty values.
+ Setting \c "PATH" to empty on Windows will likely cause the child process
+ to fail to start.
+
\section1 Communicating via Channels
Processes have two predefined output channels: The standard
@@ -524,11 +595,6 @@ void QProcessPrivate::Channel::clear()
command line option; X11 applications generally accept a
\c{-geometry} command line option.
- \note On QNX, setting the working directory may cause all
- application threads, with the exception of the QProcess caller
- thread, to temporarily freeze during the spawning process,
- owing to a limitation in the operating system.
-
\section1 Synchronous Process API
QProcess provides a set of functions which allow it to be used
@@ -556,15 +622,6 @@ void QProcessPrivate::Channel::clear()
\snippet process/process.cpp 0
- \section1 Notes for Windows Users
-
- Some Windows commands (for example, \c dir) are not provided by
- separate applications, but by the command interpreter itself.
- If you attempt to use QProcess to execute these commands directly,
- it won't work. One possible solution is to execute the command
- interpreter itself (\c{cmd.exe} on some Windows systems), and ask
- the interpreter to execute the desired command.
-
\sa QBuffer, QFile, QTcpSocket
*/
@@ -752,6 +809,98 @@ void QProcessPrivate::Channel::clear()
*/
/*!
+ \class QProcess::UnixProcessParameters
+ \inmodule QtCore
+ \note This struct is only available on Unix platforms
+ \since 6.6
+
+ This struct can be used to pass extra, Unix-specific configuration for the
+ child process using QProcess::setUnixProcessParameters().
+
+ Its members are:
+ \list
+ \li UnixProcessParameters::flags Flags, see QProcess::UnixProcessFlags
+ \li UnixProcessParameters::lowestFileDescriptorToClose The lowest file
+ descriptor to close.
+ \endlist
+
+ When the QProcess::UnixProcessFlags::CloseFileDescriptors flag is set in
+ the \c flags field, QProcess closes the application's open file descriptors
+ before executing the child process. The descriptors 0, 1, and 2 (that is,
+ \c stdin, \c stdout, and \c stderr) are left alone, along with the ones
+ numbered lower than the value of the \c lowestFileDescriptorToClose field.
+
+ All of the settings above can also be manually achieved by calling the
+ respective POSIX function from a handler set with
+ QProcess::setChildProcessModifier(). This structure allows QProcess to deal
+ with any platform-specific differences, benefit from certain optimizations,
+ and reduces code duplication. Moreover, if any of those functions fail,
+ QProcess will enter QProcess::FailedToStart state, while the child process
+ modifier callback is not allowed to fail.
+
+ \sa QProcess::setUnixProcessParameters(), QProcess::setChildProcessModifier()
+*/
+
+/*!
+ \enum QProcess::UnixProcessFlag
+ \since 6.6
+
+ These flags can be used in the \c flags field of \l UnixProcessParameters.
+
+ \value CloseFileDescriptors Close all file descriptors above the threshold
+ defined by \c lowestFileDescriptorToClose, preventing any currently
+ open descriptor in the parent process from accidentally leaking to the
+ child. The \c stdin, \c stdout, and \c stderr file descriptors are
+ never closed.
+
+ \value [since 6.7] CreateNewSession Starts a new process session, by calling
+ \c{setsid(2)}. This allows the child process to outlive the session
+ the current process is in. This is one of the steps that
+ startDetached() takes to allow the process to detach, and is also one
+ of the steps to daemonize a process.
+
+ \value [since 6.7] DisconnectControllingTerminal Requests that the process
+ disconnect from its controlling terminal, if it has one. If it has
+ none, nothing happens. Processes still connected to a controlling
+ terminal may get a Hang Up (\c SIGHUP) signal if the terminal
+ closes, or one of the other terminal-control signals (\c SIGTSTP, \c
+ SIGTTIN, \c SIGTTOU). Note that on some operating systems, a process
+ may only disconnect from the controlling terminal if it is the
+ session leader, meaning the \c CreateNewSession flag may be
+ required. Like it, this is one of the steps to daemonize a process.
+
+ \value IgnoreSigPipe Always sets the \c SIGPIPE signal to ignored
+ (\c SIG_IGN), even if the \c ResetSignalHandlers flag was set. By
+ default, if the child attempts to write to its standard output or
+ standard error after the respective channel was closed with
+ QProcess::closeReadChannel(), it would get the \c SIGPIPE signal and
+ terminate immediately; with this flag, the write operation fails
+ without a signal and the child may continue executing.
+
+ \value [since 6.7] ResetIds Drops any retained, effective user or group
+ ID the current process may still have (see \c{setuid(2)} and
+ \c{setgid(2)}, plus QCoreApplication::setSetuidAllowed()). This is
+ useful if the current process was setuid or setgid and does not wish
+ the child process to retain the elevated privileges.
+
+ \value ResetSignalHandlers Resets all Unix signal handlers back to their
+ default state (that is, pass \c SIG_DFL to \c{signal(2)}). This flag
+ is useful to ensure any ignored (\c SIG_IGN) signal does not affect
+ the child's behavior.
+
+ \value UseVFork Requests that QProcess use \c{vfork(2)} to start the child
+ process. Use this flag to indicate that the callback function set
+ with setChildProcessModifier() is safe to execute in the child side of
+ a \c{vfork(2)}; that is, the callback does not modify any non-local
+ variables (directly or through any function it calls), nor attempts
+ to communicate with the parent process. It is implementation-defined
+ if QProcess will actually use \c{vfork(2)} and if \c{vfork(2)} is
+ different from standard \c{fork(2)}.
+
+ \sa setUnixProcessParameters(), unixProcessParameters()
+*/
+
+/*!
\fn void QProcess::errorOccurred(QProcess::ProcessError error)
\since 5.6
@@ -869,7 +1018,7 @@ void QProcessPrivate::setErrorAndEmit(QProcess::ProcessError error, const QStrin
Q_Q(QProcess);
Q_ASSERT(error != QProcess::UnknownError);
setError(error, description);
- emit q->errorOccurred(processError);
+ emit q->errorOccurred(QProcess::ProcessError(processError));
}
/*!
@@ -1092,10 +1241,8 @@ void QProcessPrivate::processFinished()
cleanup();
- if (crashed) {
- exitStatus = QProcess::CrashExit;
+ if (exitStatus == QProcess::CrashExit)
setErrorAndEmit(QProcess::Crashed);
- }
// we received EOF now:
emit q->readChannelFinished();
@@ -1103,7 +1250,7 @@ void QProcessPrivate::processFinished()
//emit q->standardOutputClosed();
//emit q->standardErrorClosed();
- emit q->finished(exitCode, exitStatus);
+ emit q->finished(exitCode, QProcess::ExitStatus(exitStatus));
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::processFinished(): process is dead");
@@ -1188,7 +1335,7 @@ QProcess::~QProcess()
QProcess::ProcessChannelMode QProcess::processChannelMode() const
{
Q_D(const QProcess);
- return d->processChannelMode;
+ return ProcessChannelMode(d->processChannelMode);
}
/*!
@@ -1218,7 +1365,7 @@ void QProcess::setProcessChannelMode(ProcessChannelMode mode)
QProcess::InputChannelMode QProcess::inputChannelMode() const
{
Q_D(const QProcess);
- return d->inputChannelMode;
+ return InputChannelMode(d->inputChannelMode);
}
/*!
@@ -1356,6 +1503,9 @@ void QProcess::setStandardInputFile(const QString &fileName)
Calling setStandardOutputFile() after the process has started has
no effect.
+ If \a fileName is an empty string, it stops redirecting the standard
+ output. This is useful for restoring the standard output after redirection.
+
\sa setStandardInputFile(), setStandardErrorFile(),
setStandardOutputProcess()
*/
@@ -1415,7 +1565,7 @@ void QProcess::setStandardOutputProcess(QProcess *destination)
dto->stdinChannel.pipeFrom(dfrom);
}
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
/*!
\since 4.7
@@ -1499,12 +1649,12 @@ void QProcess::setCreateProcessArgumentsModifier(CreateProcessArgumentModifier m
\note This function is only available on Unix platforms.
- \sa setChildProcessModifier()
+ \sa setChildProcessModifier(), unixProcessParameters()
*/
std::function<void(void)> QProcess::childProcessModifier() const
{
Q_D(const QProcess);
- return d->childProcessModifier;
+ return d->unixExtras ? d->unixExtras->childProcessModifier : std::function<void(void)>();
}
/*!
@@ -1513,20 +1663,28 @@ std::function<void(void)> QProcess::childProcessModifier() const
Sets the \a modifier function for the child process, for Unix systems
(including \macos; for Windows, see setCreateProcessArgumentsModifier()).
The function contained by the \a modifier argument will be invoked in the
- child process after \c{fork()} is completed and QProcess has set up the
- standard file descriptors for the child process, but before \c{execve()},
- inside start(). The modifier is useful to change certain properties of the
- child process, such as setting up additional file descriptors or closing
- others, changing the nice level, disconnecting from the controlling TTY,
- etc.
+ child process after \c{fork()} or \c{vfork()} is completed and QProcess has
+ set up the standard file descriptors for the child process, but before
+ \c{execve()}, inside start().
The following shows an example of setting up a child process to run without
privileges:
\snippet code/src_corelib_io_qprocess.cpp 4
- If the modifier function needs to exit the process, remember to use
- \c{_exit()}, not \c{exit()}.
+ If the modifier function experiences a failure condition, it can use
+ failChildProcessModifier() to report the situation to the QProcess caller.
+ Alternatively, it may use other methods of stopping the process, like
+ \c{_exit()}, or \c{abort()}.
+
+ Certain properties of the child process, such as closing all extraneous
+ file descriptors or disconnecting from the controlling TTY, can be more
+ readily achieved by using setUnixProcessParameters(), which can detect
+ failure and report a \l{QProcess::}{FailedToStart} condition. The modifier
+ is useful to change certain uncommon properties of the child process, such
+ as setting up additional file descriptors. If both a child process modifier
+ and Unix process parameters are set, the modifier is run before these
+ parameters are applied.
\note In multithreaded applications, this function must be careful not to
call any functions that may lock mutexes that may have been in use in
@@ -1534,12 +1692,125 @@ std::function<void(void)> QProcess::childProcessModifier() const
"async-signal-safe" is advised). Most of the Qt API is unsafe inside this
callback, including qDebug(), and may lead to deadlocks.
- \sa childProcessModifier()
+ \note If the UnixProcessParameters::UseVFork flag is set via
+ setUnixProcessParameters(), QProcess may use \c{vfork()} semantics to
+ start the child process, so this function must obey even stricter
+ constraints. First, because it is still sharing memory with the parent
+ process, it must not write to any non-local variable and must obey proper
+ ordering semantics when reading from them, to avoid data races. Second,
+ even more library functions may misbehave; therefore, this function should
+ only make use of low-level system calls, such as \c{read()},
+ \c{write()}, \c{setsid()}, \c{nice()}, and similar.
+
+ \sa childProcessModifier(), failChildProcessModifier(), setUnixProcessParameters()
*/
void QProcess::setChildProcessModifier(const std::function<void(void)> &modifier)
{
Q_D(QProcess);
- d->childProcessModifier = modifier;
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->childProcessModifier = modifier;
+}
+
+/*!
+ \fn void QProcess::failChildProcessModifier(const char *description, int error) noexcept
+ \since 6.7
+
+ This functions can be used inside the modifier set with
+ setChildProcessModifier() to indicate an error condition was encountered.
+ When the modifier calls these functions, QProcess will emit errorOccurred()
+ with code QProcess::FailedToStart in the parent process. The \a description
+ can be used to include some information in errorString() to help diagnose
+ the problem, usually the name of the call that failed, similar to the C
+ Library function \c{perror()}. Additionally, the \a error parameter can be
+ an \c{<errno.h>} error code whose text form will also be included.
+
+ For example, a child modifier could prepare an extra file descriptor for
+ the child process this way:
+
+ \code
+ process.setChildProcessModifier([fd, &process]() {
+ if (dup2(fd, TargetFileDescriptor) < 0)
+ process.failChildProcessModifier(errno, "aux comm channel");
+ });
+ process.start();
+ \endcode
+
+ Where \c{fd} is a file descriptor currently open in the parent process. If
+ the \c{dup2()} system call resulted in an \c EBADF condition, the process
+ errorString() could be "Child process modifier reported error: aux comm
+ channel: Bad file descriptor".
+
+ This function does not return to the caller. Using it anywhere except in
+ the child modifier and with the correct QProcess object is undefined
+ behavior.
+
+ \note The implementation imposes a length limit to the \a description
+ parameter to about 500 characters. This does not include the text from the
+ \a error code.
+
+ \sa setChildProcessModifier(), setUnixProcessParameters()
+*/
+
+/*!
+ \since 6.6
+ Returns the \l UnixProcessParameters object describing extra flags and
+ settings that will be applied to the child process on Unix systems. The
+ default settings correspond to a default-constructed UnixProcessParameters.
+
+ \note This function is only available on Unix platforms.
+
+ \sa childProcessModifier()
+*/
+auto QProcess::unixProcessParameters() const noexcept -> UnixProcessParameters
+{
+ Q_D(const QProcess);
+ return d->unixExtras ? d->unixExtras->processParameters : UnixProcessParameters{};
+}
+
+/*!
+ \since 6.6
+ Sets the extra settings and parameters for the child process on Unix
+ systems to be \a params. This function can be used to ask QProcess to
+ modify the child process before launching the target executable.
+
+ This function can be used to change certain properties of the child
+ process, such as closing all extraneous file descriptors, changing the nice
+ level of the child, or disconnecting from the controlling TTY. For more
+ fine-grained control of the child process or to modify it in other ways,
+ use the setChildProcessModifier() function. If both a child process
+ modifier and Unix process parameters are set, the modifier is run before
+ these parameters are applied.
+
+ \note This function is only available on Unix platforms.
+
+ \sa unixProcessParameters(), setChildProcessModifier()
+*/
+void QProcess::setUnixProcessParameters(const UnixProcessParameters &params)
+{
+ Q_D(QProcess);
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->processParameters = params;
+}
+
+/*!
+ \since 6.6
+ \overload
+
+ Sets the extra settings for the child process on Unix systems to \a
+ flagsOnly. This is the same as the overload with just the \c flags field
+ set.
+ \note This function is only available on Unix platforms.
+
+ \sa unixProcessParameters(), setChildProcessModifier()
+*/
+void QProcess::setUnixProcessParameters(UnixProcessFlags flagsOnly)
+{
+ Q_D(QProcess);
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->processParameters = { flagsOnly };
}
#endif
@@ -1563,9 +1834,6 @@ QString QProcess::workingDirectory() const
process in this directory. The default behavior is to start the
process in the working directory of the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
\sa workingDirectory(), start()
*/
void QProcess::setWorkingDirectory(const QString &dir)
@@ -1633,7 +1901,7 @@ qint64 QProcess::bytesToWrite() const
QProcess::ProcessError QProcess::error() const
{
Q_D(const QProcess);
- return d->processError;
+ return ProcessError(d->processError);
}
/*!
@@ -1644,7 +1912,7 @@ QProcess::ProcessError QProcess::error() const
QProcess::ProcessState QProcess::state() const
{
Q_D(const QProcess);
- return d->processState;
+ return ProcessState(d->processState);
}
/*!
@@ -1691,7 +1959,8 @@ QStringList QProcess::environment() const
Note how, on Windows, environment variable names are case-insensitive.
- \sa processEnvironment(), QProcessEnvironment::systemEnvironment(), setEnvironment()
+ \sa processEnvironment(), QProcessEnvironment::systemEnvironment(),
+ {Environment variables}
*/
void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)
{
@@ -1701,12 +1970,12 @@ void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)
/*!
\since 4.6
- Returns the environment that QProcess will pass to its child
- process, or an empty object if no environment has been set using
- setEnvironment() or setProcessEnvironment(). If no environment has
- been set, the environment of the calling process will be used.
+ Returns the environment that QProcess will pass to its child process. If no
+ environment has been set using setProcessEnvironment(), this method returns
+ an object indicating the environment will be inherited from the parent.
- \sa setProcessEnvironment(), setEnvironment(), QProcessEnvironment::isEmpty()
+ \sa setProcessEnvironment(), QProcessEnvironment::inheritsFromParent(),
+ {Environment variables}
*/
QProcessEnvironment QProcess::processEnvironment() const
{
@@ -1720,7 +1989,8 @@ QProcessEnvironment QProcess::processEnvironment() const
Returns \c true if the process was started successfully; otherwise
returns \c false (if the operation timed out or if an error
- occurred).
+ occurred). If the process had already started successfully before this
+ function, it returns immediately.
This function can operate without an event loop. It is
useful when writing non-GUI applications and when performing
@@ -1731,9 +2001,6 @@ QProcessEnvironment QProcess::processEnvironment() const
If msecs is -1, this function will not time out.
- \note On some UNIX operating systems, this function may return true but
- the process may later report a QProcess::FailedToStart error.
-
\sa started(), waitForReadyRead(), waitForBytesWritten(), waitForFinished()
*/
bool QProcess::waitForStarted(int msecs)
@@ -1841,8 +2108,7 @@ void QProcess::setProcessState(ProcessState state)
*/
auto QProcess::setupChildProcess() -> Use_setChildProcessModifier_Instead
{
- Q_UNREACHABLE();
- return {};
+ Q_UNREACHABLE_RETURN({});
}
#endif
@@ -1884,27 +2150,38 @@ QByteArray QProcess::readAllStandardOutput()
*/
QByteArray QProcess::readAllStandardError()
{
- ProcessChannel tmp = readChannel();
- setReadChannel(StandardError);
- QByteArray data = readAll();
- setReadChannel(tmp);
+ Q_D(QProcess);
+ QByteArray data;
+ if (d->processChannelMode == MergedChannels) {
+ qWarning("QProcess::readAllStandardError: Called with MergedChannels");
+ } else {
+ ProcessChannel tmp = readChannel();
+ setReadChannel(StandardError);
+ data = readAll();
+ setReadChannel(tmp);
+ }
return data;
}
/*!
Starts the given \a program in a new process, passing the command line
- arguments in \a arguments.
+ arguments in \a arguments. See setProgram() for information about how
+ QProcess searches for the executable to be run. The OpenMode is set to \a
+ mode. No further splitting of the arguments is performed.
The QProcess object will immediately enter the Starting state. If the
process starts successfully, QProcess will emit started(); otherwise,
- errorOccurred() will be emitted.
-
- \note Processes are started asynchronously, which means the started()
- and errorOccurred() signals may be delayed. Call waitForStarted() to make
- sure the process has started (or has failed to start) and those signals
- have been emitted.
-
- \note No further splitting of the arguments is performed.
+ errorOccurred() will be emitted. Do note that on platforms that are able to
+ start child processes synchronously (notably Windows), those signals will
+ be emitted before this function returns and this QProcess object will
+ transition to either QProcess::Running or QProcess::NotRunning state,
+ respectively. On others paltforms, the started() and errorOccurred()
+ signals will be delayed.
+
+ Call waitForStarted() to make sure the process has started (or has failed
+ to start) and those signals have been emitted. It is safe to call that
+ function even if the process starting state is already known, though the
+ signal will not be emitted again.
\b{Windows:} The arguments are quoted and joined into a command line
that is compatible with the \c CommandLineToArgvW() Windows function.
@@ -1913,12 +2190,16 @@ QByteArray QProcess::readAllStandardError()
not follow the \c CommandLineToArgvW() rules is cmd.exe and, by
consequence, all batch scripts.
- The OpenMode is set to \a mode.
-
If the QProcess object is already running a process, a warning may be
printed at the console, and the existing process will continue running
unaffected.
+ \note Success at starting the child process only implies the operating
+ system has successfully created the process and assigned the resources
+ every process has, such as its process ID. The child process may crash or
+ otherwise fail very early and thus not produce its expected output. On most
+ operating systems, this may include dynamic linking errors.
+
\sa processId(), started(), waitForStarted(), setNativeArguments()
*/
void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
@@ -2000,6 +2281,10 @@ void QProcess::start(OpenMode mode)
void QProcess::startCommand(const QString &command, OpenMode mode)
{
QStringList args = splitCommand(command);
+ if (args.isEmpty()) {
+ qWarning("QProcess::startCommand: empty or whitespace-only command was provided");
+ return;
+ }
const QString program = args.takeFirst();
start(program, args, mode);
}
@@ -2019,9 +2304,6 @@ void QProcess::startCommand(const QString &command, OpenMode mode)
If workingDirectory() is empty, the working directory is inherited
from the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
If the function is successful then *\a pid is set to the process identifier
of the started process; otherwise, it's set to -1. Note that the child
process may exit and the PID may become invalid without notice.
@@ -2154,7 +2436,7 @@ QStringList QProcess::splitCommand(QStringView command)
// "hello world". three consecutive double quotes represent
// the quote character itself.
for (int i = 0; i < command.size(); ++i) {
- if (command.at(i) == QLatin1Char('"')) {
+ if (command.at(i) == u'"') {
++quoteCount;
if (quoteCount == 3) {
// third consecutive quote
@@ -2202,7 +2484,12 @@ QString QProcess::program() const
Set the \a program to use when starting the process.
This function must be called before start().
- \sa start(), setArguments(), program()
+ If \a program is an absolute path, it specifies the exact executable that
+ will be launched. Relative paths will be resolved in a platform-specific
+ manner, which includes searching the \c PATH environment variable (see
+ \l{Finding the Executable} for details).
+
+ \sa start(), setArguments(), program(), QStandardPaths::findExecutable()
*/
void QProcess::setProgram(const QString &program)
{
@@ -2304,7 +2591,7 @@ int QProcess::exitCode() const
QProcess::ExitStatus QProcess::exitStatus() const
{
Q_D(const QProcess);
- return d->exitStatus;
+ return ExitStatus(d->exitStatus);
}
/*!
@@ -2365,18 +2652,6 @@ bool QProcess::startDetached(const QString &program,
return process.startDetached(pid);
}
-QT_BEGIN_INCLUDE_NAMESPACE
-#if defined(Q_OS_MACOS)
-# include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#elif defined(QT_PLATFORM_UIKIT)
- static char *qt_empty_environ[] = { 0 };
-#define environ qt_empty_environ
-#elif !defined(Q_OS_WIN)
- extern char **environ;
-#endif
-QT_END_INCLUDE_NAMESPACE
-
/*!
\since 4.1
@@ -2398,12 +2673,7 @@ QT_END_INCLUDE_NAMESPACE
*/
QStringList QProcess::systemEnvironment()
{
- QStringList tmp;
- char *entry = nullptr;
- int count = 0;
- while ((entry = environ[count++]))
- tmp << QString::fromLocal8Bit(entry);
- return tmp;
+ return QProcessEnvironment::systemEnvironment().toStringList();
}
/*!
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 97b586a2b4..34724a6794 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPROCESS_H
#define QPROCESS_H
+#include <QtCore/qcompare.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qshareddata.h>
@@ -48,7 +14,7 @@
QT_REQUIRE_CONFIG(processenvironment);
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
struct _PROCESS_INFORMATION;
struct _SECURITY_ATTRIBUTES;
struct _STARTUPINFOW;
@@ -68,7 +34,7 @@ public:
enum Initialization { InheritFromParent };
QProcessEnvironment();
- QProcessEnvironment(Initialization);
+ QProcessEnvironment(Initialization) noexcept;
QProcessEnvironment(const QProcessEnvironment &other);
~QProcessEnvironment();
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QProcessEnvironment)
@@ -76,9 +42,11 @@ public:
void swap(QProcessEnvironment &other) noexcept { d.swap(other.d); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QProcessEnvironment &other) const;
inline bool operator!=(const QProcessEnvironment &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
+#endif
bool isEmpty() const;
[[nodiscard]] bool inheritsFromParent() const;
@@ -98,6 +66,9 @@ public:
static QProcessEnvironment systemEnvironment();
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QProcessEnvironment &lhs,
+ const QProcessEnvironment &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QProcessEnvironment)
friend class QProcessPrivate;
friend class QProcessEnvironmentPrivate;
QSharedDataPointer<QProcessEnvironmentPrivate> d;
@@ -186,7 +157,7 @@ public:
void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate);
void setStandardOutputProcess(QProcess *destination);
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
QString nativeArguments() const;
void setNativeArguments(const QString &arguments);
struct CreateProcessArguments
@@ -205,10 +176,33 @@ public:
typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier;
CreateProcessArgumentModifier createProcessArgumentsModifier() const;
void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier);
-#endif // Q_OS_WIN || Q_CLANG_QDOC
-#if defined(Q_OS_UNIX) || defined(Q_CLANG_QDOC)
+#endif // Q_OS_WIN || Q_QDOC
+#if defined(Q_OS_UNIX) || defined(Q_QDOC)
std::function<void(void)> childProcessModifier() const;
void setChildProcessModifier(const std::function<void(void)> &modifier);
+ Q_NORETURN void failChildProcessModifier(const char *description, int error = 0) noexcept;
+
+ enum class UnixProcessFlag : quint32 {
+ ResetSignalHandlers = 0x0001, // like POSIX_SPAWN_SETSIGDEF
+ IgnoreSigPipe = 0x0002,
+ // some room if we want to add IgnoreSigHup or so
+ CloseFileDescriptors = 0x0010,
+ UseVFork = 0x0020, // like POSIX_SPAWN_USEVFORK
+ CreateNewSession = 0x0040, // like POSIX_SPAWN_SETSID
+ DisconnectControllingTerminal = 0x0080,
+ ResetIds = 0x0100, // like POSIX_SPAWN_RESETIDS
+ };
+ Q_DECLARE_FLAGS(UnixProcessFlags, UnixProcessFlag)
+ struct UnixProcessParameters
+ {
+ UnixProcessFlags flags = {};
+ int lowestFileDescriptorToClose = 0;
+
+ quint32 _reserved[6] {};
+ };
+ UnixProcessParameters unixProcessParameters() const noexcept;
+ void setUnixProcessParameters(const UnixProcessParameters &params);
+ void setUnixProcessParameters(UnixProcessFlags flagsOnly);
#endif
QString workingDirectory() const;
@@ -292,6 +286,10 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_processDied())
};
+#ifdef Q_OS_UNIX
+Q_DECLARE_OPERATORS_FOR_FLAGS(QProcess::UnixProcessFlags)
+#endif
+
#endif // QT_CONFIG(process)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_darwin.mm b/src/corelib/io/qprocess_darwin.mm
index 2c3c296cb4..29b6c6f25d 100644
--- a/src/corelib/io/qprocess_darwin.mm
+++ b/src/corelib/io/qprocess_darwin.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qprocess_p.h>
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index aec8f458fc..9510101e74 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPROCESS_P_H
#define QPROCESS_P_H
@@ -295,29 +259,12 @@ public:
bool _q_startupNotification();
void _q_processDied();
- QProcess::ProcessChannelMode processChannelMode = QProcess::SeparateChannels;
- QProcess::InputChannelMode inputChannelMode = QProcess::ManagedInputChannel;
- QProcess::ProcessError processError = QProcess::UnknownError;
- QProcess::ProcessState processState = QProcess::NotRunning;
- QString workingDirectory;
-#ifdef Q_OS_WIN
- Q_PROCESS_INFORMATION *pid = nullptr;
-#else
- qint64 pid = 0;
-#endif
-
- bool emittedReadyRead = false;
- bool emittedBytesWritten = false;
-
Channel stdinChannel;
Channel stdoutChannel;
Channel stderrChannel;
bool openChannels();
bool openChannelsForDetached();
bool openChannel(Channel &channel);
-#if defined(Q_OS_UNIX)
- void commitChannels();
-#endif
void closeChannel(Channel *channel);
void closeWriteChannel();
void closeChannels();
@@ -325,26 +272,38 @@ public:
QString program;
QStringList arguments;
+ QString workingDirectory;
+ QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
#if defined(Q_OS_WIN)
QString nativeArguments;
QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs;
+ QWinEventNotifier *processFinishedNotifier = nullptr;
+ Q_PROCESS_INFORMATION *pid = nullptr;
#else
- std::function<void(void)> childProcessModifier;
-#endif
- QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
-
-#ifdef Q_OS_UNIX
- Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
+ struct UnixExtras {
+ std::function<void(void)> childProcessModifier;
+ QProcess::UnixProcessParameters processParameters;
+ };
+ std::unique_ptr<UnixExtras> unixExtras;
QSocketNotifier *stateNotifier = nullptr;
+ Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
+ pid_t pid = 0;
int forkfd = -1;
-#else
- QWinEventNotifier *processFinishedNotifier = nullptr;
#endif
+ int exitCode = 0;
+ quint8 processState = QProcess::NotRunning;
+ quint8 exitStatus = QProcess::NormalExit;
+ quint8 processError = QProcess::UnknownError;
+ quint8 processChannelMode = QProcess::SeparateChannels;
+ quint8 inputChannelMode = QProcess::ManagedInputChannel;
+ bool emittedReadyRead = false;
+ bool emittedBytesWritten = false;
+
void start(QIODevice::OpenMode mode);
void startProcess();
#if defined(Q_OS_UNIX)
- void execChild(const char *workingDirectory, char **argv, char **envp);
+ void commitChannels() const;
#endif
bool processStarted(QString *errorMessage = nullptr);
void processFinished();
@@ -363,10 +322,6 @@ public:
bool startDetached(qint64 *pPid);
- int exitCode = 0;
- QProcess::ExitStatus exitStatus = QProcess::NormalExit;
- bool crashed = false;
-
bool waitForStarted(const QDeadlineTimer &deadline);
bool waitForReadyRead(const QDeadlineTimer &deadline);
bool waitForBytesWritten(const QDeadlineTimer &deadline);
@@ -379,6 +334,9 @@ public:
void cleanup();
void setError(QProcess::ProcessError error, const QString &description = QString());
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
+
+ const QProcessEnvironmentPrivate *environmentPrivate() const
+ { return environment.d.constData(); }
};
#endif // QT_CONFIG(process)
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 91005b0b67..5c696433fd 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2021 Intel Corporation.
-** Copyright (C) 2021 Alex Trotsenko.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2021 Alex Trotsenko.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QPROCESS_DEBUG
#include "qdebug.h"
@@ -50,7 +14,7 @@
#include "private/qcore_unix_p.h"
#include "private/qlocking_p.h"
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
#include <private/qcore_mac_p.h>
#endif
@@ -72,18 +36,42 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if __has_include(<paths.h>)
+# include <paths.h>
+#endif
+#if __has_include(<linux/close_range.h>)
+// FreeBSD's is in <unistd.h>
+# include <linux/close_range.h>
+#endif
#if QT_CONFIG(process)
#include <forkfd.h>
#endif
+#ifndef O_PATH
+# define O_PATH 0
+#endif
+#ifndef _PATH_DEV
+# define _PATH_DEV "/dev/"
+#endif
+#ifndef _PATH_TTY
+# define _PATH_TTY _PATH_DEV "tty"
+#endif
+
+#ifdef Q_OS_FREEBSD
+__attribute__((weak))
+#endif
+extern char **environ;
+
QT_BEGIN_NAMESPACE
-#if !defined(Q_OS_DARWIN)
+using namespace Qt::StringLiterals;
-QT_BEGIN_INCLUDE_NAMESPACE
-extern char **environ;
-QT_END_INCLUDE_NAMESPACE
+#if !defined(Q_OS_DARWIN)
QProcessEnvironment QProcessEnvironment::systemEnvironment()
{
@@ -106,6 +94,70 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment()
#if QT_CONFIG(process)
+namespace QtVforkSafe {
+// Certain libc functions we need to call in the child process scenario aren't
+// safe under vfork() because they do more than just place the system call to
+// the kernel and set errno on return. For those, we'll create a function
+// pointer like:
+// static constexpr auto foobar = __libc_foobar;
+// while for all other OSes, it'll be
+// using ::foobar;
+// allowing the code for the child side of the vfork to simply use
+// QtVforkSafe::foobar(args);
+//
+// Currently known issues are:
+//
+// - FreeBSD's libthr sigaction() wrapper locks a rwlock
+// https://github.com/freebsd/freebsd-src/blob/8dad5ece49479ba6cdcd5bb4c2799bbd61add3e6/lib/libthr/thread/thr_sig.c#L575-L641
+// - MUSL's sigaction() locks a mutex if the signal is SIGABR
+// https://github.com/bminor/musl/blob/718f363bc2067b6487900eddc9180c84e7739f80/src/signal/sigaction.c#L63-L85
+//
+// All other functions called in the child side are vfork-safe, provided that
+// PThread cancellation is disabled and Unix signals are blocked.
+#if defined(__MUSL__)
+# define LIBC_PREFIX __libc_
+#elif defined(Q_OS_FREEBSD)
+// will cause QtCore to link to ELF version "FBSDprivate_1.0"
+# define LIBC_PREFIX _
+#endif
+
+#ifdef LIBC_PREFIX
+# define CONCAT(x, y) CONCAT2(x, y)
+# define CONCAT2(x, y) x ## y
+# define DECLARE_FUNCTIONS(NAME) \
+ extern decltype(::NAME) CONCAT(LIBC_PREFIX, NAME); \
+ static constexpr auto NAME = std::addressof(CONCAT(LIBC_PREFIX, NAME));
+#else // LIBC_PREFIX
+# define DECLARE_FUNCTIONS(NAME) using ::NAME;
+#endif // LIBC_PREFIX
+
+extern "C" {
+DECLARE_FUNCTIONS(sigaction)
+}
+
+#undef LIBC_PREFIX
+#undef DECLARE_FUNCTIONS
+
+// similar to qt_ignore_sigpipe() in qcore_unix_p.h, but vfork-safe
+static void change_sigpipe(decltype(SIG_DFL) new_handler)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = new_handler;
+ sigaction(SIGPIPE, &sa, nullptr);
+}
+} // namespace QtVforkSafe
+
+static int opendirfd(QByteArray encodedName)
+{
+ // We append "/." to the name to ensure that the directory is actually
+ // traversable (i.e., has the +x bit set). This avoids later problems
+ // with fchdir().
+ if (encodedName != "/" && !encodedName.endsWith("/."))
+ encodedName += "/.";
+ return qt_safe_open(encodedName, QT_OPEN_RDONLY | O_DIRECTORY | O_PATH);
+}
+
namespace {
struct AutoPipe
{
@@ -129,22 +181,13 @@ struct AutoPipe
struct ChildError
{
- qint64 code;
- char function[8];
-};
-
-// Used for argv and envp arguments to execve()
-struct CharPointerList
-{
- std::unique_ptr<char *[]> pointers;
-
- CharPointerList(const QString &argv0, const QStringList &args);
- explicit CharPointerList(const QProcessEnvironmentPrivate *env);
-
-private:
- QByteArray data;
- void updatePointers(qsizetype count);
+ int code;
+ char function[_POSIX_PIPE_BUF - sizeof(code)];
};
+static_assert(std::is_trivial_v<ChildError>);
+#ifdef PIPE_BUF
+static_assert(PIPE_BUF >= sizeof(ChildError)); // PIPE_BUF may be bigger
+#endif
struct QProcessPoller
{
@@ -179,10 +222,139 @@ QProcessPoller::QProcessPoller(const QProcessPrivate &proc)
int QProcessPoller::poll(const QDeadlineTimer &deadline)
{
- return qt_poll_msecs(pfds, n_pfds, deadline.remainingTime());
+ return qt_safe_poll(pfds, n_pfds, deadline);
}
-CharPointerList::CharPointerList(const QString &program, const QStringList &args)
+struct QChildProcess
+{
+ // Used for argv and envp arguments to execve()
+ struct CharPointerList
+ {
+ std::unique_ptr<char *[]> pointers;
+
+ CharPointerList(const QString &argv0, const QStringList &args);
+ explicit CharPointerList(const QProcessEnvironmentPrivate *env);
+ /*implicit*/ operator char **() const { return pointers.get(); }
+
+ private:
+ QByteArray data;
+ void updatePointers(qsizetype count);
+ };
+
+ const QProcessPrivate *d;
+ CharPointerList argv;
+ CharPointerList envp;
+ sigset_t oldsigset;
+ int workingDirectory = -2;
+ bool isUsingVfork = usingVfork();
+
+ bool ok() const
+ {
+ return workingDirectory != -1;
+ }
+
+ QChildProcess(QProcessPrivate *d)
+ : d(d), argv(resolveExecutable(d->program), d->arguments),
+ envp(d->environmentPrivate())
+ {
+ // Block Unix signals, to ensure the user's handlers aren't run in the
+ // child side and do something weird, especially if the handler and the
+ // user of QProcess are completely different codebases.
+ maybeBlockSignals();
+
+ // Disable PThread cancellation until the child has successfully been
+ // executed. We make a number of POSIX calls in the child that are thread
+ // cancellation points and could cause an unexpected stack unwind. That
+ // would be bad enough with regular fork(), but it's likely fatal with
+ // vfork().
+ disableThreadCancellations();
+
+ if (!d->workingDirectory.isEmpty()) {
+ workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory));
+ if (workingDirectory < 0) {
+ d->setErrorAndEmit(QProcess::FailedToStart, "chdir: "_L1 + qt_error_string());
+ d->cleanup();
+ }
+ }
+
+ }
+ ~QChildProcess() noexcept(false)
+ {
+ if (workingDirectory >= 0)
+ close(workingDirectory);
+
+ restoreThreadCancellations();
+ restoreSignalMask();
+ }
+
+ void maybeBlockSignals() noexcept
+ {
+ // We only block Unix signals if we're using vfork(), to avoid a
+ // changing behavior to the user's modifier and because in some OSes
+ // this action would block crashing signals too.
+ if (isUsingVfork) {
+ sigset_t emptyset;
+ sigfillset(&emptyset);
+ pthread_sigmask(SIG_SETMASK, &emptyset, &oldsigset);
+ }
+ }
+
+ void restoreSignalMask() const noexcept
+ {
+ if (isUsingVfork)
+ pthread_sigmask(SIG_SETMASK, &oldsigset, nullptr);
+ }
+
+ bool usingVfork() const noexcept;
+
+ template <typename Lambda> int doFork(Lambda &&childLambda)
+ {
+ pid_t pid;
+ if (isUsingVfork) {
+ QT_IGNORE_DEPRECATIONS(pid = vfork();)
+ } else {
+ pid = fork();
+ }
+ if (pid == 0)
+ _exit(childLambda());
+ return pid;
+ }
+
+ int startChild(pid_t *pid)
+ {
+ int ffdflags = FFD_CLOEXEC | (isUsingVfork ? 0 : FFD_USE_FORK);
+ return ::vforkfd(ffdflags, pid, &QChildProcess::startProcess, this);
+ }
+
+private:
+ Q_NORETURN void startProcess() const noexcept;
+ static int startProcess(void *self) noexcept
+ {
+ static_cast<QChildProcess *>(self)->startProcess();
+ Q_UNREACHABLE_RETURN(-1);
+ }
+
+#if defined(PTHREAD_CANCEL_DISABLE)
+ int oldstate;
+ void disableThreadCancellations() noexcept
+ {
+ // the following is *not* noexcept, but it won't throw while disabling
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
+ }
+ void restoreThreadCancellations() noexcept(false)
+ {
+ // this doesn't touch errno
+ pthread_setcancelstate(oldstate, nullptr);
+ }
+#else
+ void disableThreadCancellations() noexcept {}
+ void restoreThreadCancellations() {}
+#endif
+
+ static QString resolveExecutable(const QString &program);
+};
+
+QChildProcess::CharPointerList::CharPointerList(const QString &program, const QStringList &args)
{
qsizetype count = 1 + args.size();
pointers.reset(new char *[count + 1]);
@@ -205,7 +377,7 @@ CharPointerList::CharPointerList(const QString &program, const QStringList &args
updatePointers(count);
}
-CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
+QChildProcess::CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
{
if (!environment)
return;
@@ -231,7 +403,7 @@ CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
updatePointers(count);
}
-void CharPointerList::updatePointers(qsizetype count)
+void QChildProcess::CharPointerList::updatePointers(qsizetype count)
{
char *const base = const_cast<char *>(data.constBegin());
for (qsizetype i = 0; i < count; ++i)
@@ -252,7 +424,8 @@ static int qt_create_pipe(int *pipe)
qt_safe_close(pipe[1]);
int pipe_ret = qt_safe_pipe(pipe);
if (pipe_ret != 0) {
- qErrnoWarning("QProcessPrivate::createPipe: Cannot create pipe %p", pipe);
+ QScopedValueRollback rollback(errno);
+ qErrnoWarning("QProcess: Cannot create pipe");
}
return pipe_ret;
}
@@ -301,8 +474,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
if (channel.type == Channel::Normal) {
// we're piping this channel to our own process
- if (qt_create_pipe(channel.pipe) != 0)
+ if (qt_create_pipe(channel.pipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
// create the socket notifiers
if (threadData.loadRelaxed()->hasEventDispatcher()) {
@@ -350,7 +525,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
setErrorAndEmit(QProcess::FailedToStart,
QProcess::tr("Could not open input redirection for reading"));
}
- cleanup();
return false;
} else {
Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
@@ -382,8 +556,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
Q_PIPE pipe[2] = { -1, -1 };
- if (qt_create_pipe(pipe) != 0)
+ if (qt_create_pipe(pipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
sink->pipe[0] = pipe[0];
source->pipe[1] = pipe[1];
@@ -392,7 +568,7 @@ bool QProcessPrivate::openChannel(Channel &channel)
}
}
-void QProcessPrivate::commitChannels()
+void QProcessPrivate::commitChannels() const
{
// copy the stdin socket if asked to (without closing on exec)
if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
@@ -410,19 +586,19 @@ void QProcessPrivate::commitChannels()
}
}
-static QString resolveExecutable(const QString &program)
+inline QString QChildProcess::resolveExecutable(const QString &program)
{
#ifdef Q_OS_DARWIN
// allow invoking of .app bundles on the Mac.
QFileInfo fileInfo(program);
- if (program.endsWith(QLatin1String(".app")) && fileInfo.isDir()) {
+ if (program.endsWith(".app"_L1) && fileInfo.isDir()) {
QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,
QCFString(fileInfo.absoluteFilePath()),
kCFURLPOSIXPathStyle, true);
{
// CFBundle is not reentrant, since CFBundleCreate might return a reference
// to a cached bundle object. Protect the bundle calls with a mutex lock.
- static QBasicMutex cfbundleMutex;
+ Q_CONSTINIT static QBasicMutex cfbundleMutex;
const auto locker = qt_scoped_lock(cfbundleMutex);
QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
// 'executableURL' can be either relative or absolute ...
@@ -437,25 +613,86 @@ static QString resolveExecutable(const QString &program)
}
#endif
- if (!program.contains(QLatin1Char('/'))) {
- QString exeFilePath = QStandardPaths::findExecutable(program);
- if (!exeFilePath.isEmpty())
- return exeFilePath;
+ if (!program.contains(u'/')) {
+ // findExecutable() returns its argument if it's an absolute path,
+ // otherwise it searches $PATH; returns empty if not found (we handle
+ // that case much later)
+ return QStandardPaths::findExecutable(program);
}
return program;
}
+extern "C" {
+__attribute__((weak)) pid_t __interceptor_vfork();
+}
+
+inline bool globalUsingVfork() noexcept
+{
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
+ // ASan writes to global memory, so we mustn't use vfork().
+ return false;
+#endif
+#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
+ // Ditto, apparently
+ return false;
+#endif
+#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
+ // some broken environments are known to have problems with the new Linux
+ // API, so we have a way for users to opt-out during configure time (see
+ // QTBUG-86285)
+ return false;
+#endif
+#if defined(Q_OS_DARWIN)
+ // Using vfork() for startDetached() is causing problems. We don't know
+ // why: without the tools to investigate why it happens, we didn't bother.
+ return false;
+#endif
+
+ // Dynamically detect whether libasan or libtsan are loaded into the
+ // process' memory. We need this because the user's code may be compiled
+ // with ASan or TSan, but not Qt.
+ return __interceptor_vfork == nullptr;
+}
+
+inline bool QChildProcess::usingVfork() const noexcept
+{
+ if (!globalUsingVfork())
+ return false;
+
+ if (!d->unixExtras || !d->unixExtras->childProcessModifier)
+ return true; // no modifier was supplied
+
+ // if a modifier was supplied, use fork() unless the user opts in to
+ // vfork()
+ auto flags = d->unixExtras->processParameters.flags;
+ return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
+}
+
+#ifdef QT_BUILD_INTERNAL
+Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept
+{
+ return globalUsingVfork();
+}
+#endif
+
void QProcessPrivate::startProcess()
{
Q_Q(QProcess);
+ q->setProcessState(QProcess::Starting);
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::startProcess()");
#endif
// Initialize pipes
- if (!openChannels() || qt_create_pipe(childStartedPipe) != 0) {
- setErrorAndEmit(QProcess::FailedToStart, qt_error_string(errno));
+ if (!openChannels()) {
+ // openChannel sets the error string
+ Q_ASSERT(!errorString.isEmpty());
+ cleanup();
+ return;
+ }
+ if (qt_create_pipe(childStartedPipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
cleanup();
return;
}
@@ -470,30 +707,15 @@ void QProcessPrivate::startProcess()
q, SLOT(_q_startupNotification()));
}
- // Start the process (platform dependent)
- q->setProcessState(QProcess::Starting);
-
// Prepare the arguments and the environment
- const CharPointerList argv(resolveExecutable(program), arguments);
- const CharPointerList envp(environment.d.constData());
-
- // Encode the working directory if it's non-empty, otherwise just pass 0.
- const char *workingDirPtr = nullptr;
- QByteArray encodedWorkingDirectory;
- if (!workingDirectory.isEmpty()) {
- encodedWorkingDirectory = QFile::encodeName(workingDirectory);
- workingDirPtr = encodedWorkingDirectory.constData();
+ QChildProcess childProcess(this);
+ if (!childProcess.ok()) {
+ Q_ASSERT(processError != QProcess::UnknownError);
+ return;
}
- int ffdflags = FFD_CLOEXEC;
-
- // QTBUG-86285
-#if !QT_CONFIG(forkfd_pidfd)
- ffdflags |= FFD_USE_FORK;
-#endif
-
- pid_t childPid;
- forkfd = ::forkfd(ffdflags , &childPid);
+ // Start the child.
+ forkfd = childProcess.startChild(&pid);
int lastForkErrno = errno;
if (forkfd == -1) {
@@ -508,13 +730,6 @@ void QProcessPrivate::startProcess()
return;
}
- // Start the child.
- if (forkfd == FFD_CHILD_PROCESS) {
- execChild(workingDirPtr, argv.pointers.get(), envp.pointers.get());
- ::_exit(-1);
- }
-
- pid = qint64(childPid);
Q_ASSERT(pid > 0);
// parent
@@ -546,47 +761,187 @@ void QProcessPrivate::startProcess()
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
}
-void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp)
+// we need an errno number to use to indicate the child process modifier threw,
+// something the regular operations shouldn't set.
+static constexpr int FakeErrnoForThrow = std::numeric_limits<int>::max();
+
+static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
+{
+ // ChildError is less than the POSIX pipe buffer atomic size, so the read
+ // must not have been truncated
+ Q_ASSERT(bytesRead == sizeof(err));
+
+ qsizetype len = qstrnlen(err.function, sizeof(err.function));
+ QString complement = QString::fromUtf8(err.function, len);
+ if (err.code == FakeErrnoForThrow)
+ return QProcess::tr("Child process modifier threw an exception: %1")
+ .arg(std::move(complement));
+ if (err.code == 0)
+ return QProcess::tr("Child process modifier reported error: %1")
+ .arg(std::move(complement));
+ if (err.code < 0)
+ return QProcess::tr("Child process modifier reported error: %1: %2")
+ .arg(std::move(complement), qt_error_string(-err.code));
+ return QProcess::tr("Child process set up failed: %1: %2")
+ .arg(std::move(complement), qt_error_string(err.code));
+}
+
+Q_NORETURN void
+failChildProcess(const QProcessPrivate *d, const char *description, int code) noexcept
{
- ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
+ ChildError error = {};
+ error.code = code;
+ qstrncpy(error.function, description, sizeof(error.function));
+ qt_safe_write(d->childStartedPipe[1], &error, sizeof(error));
+ _exit(-1);
+}
- ChildError error = { 0, {} }; // force zeroing of function[8]
+void QProcess::failChildProcessModifier(const char *description, int error) noexcept
+{
+ // We signal user errors with negative errnos
+ failChildProcess(d_func(), description, -error);
+}
+
+// See IMPORTANT notice below
+static const char *applyProcessParameters(const QProcess::UnixProcessParameters &params)
+{
+ // Apply Unix signal handler parameters.
+ // We don't expect signal() to fail, so we ignore its return value
+ bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
+ if (ignore_sigpipe)
+ QtVforkSafe::change_sigpipe(SIG_IGN);
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) {
+ struct sigaction sa = {};
+ sa.sa_handler = SIG_DFL;
+ for (int sig = 1; sig < NSIG; ++sig) {
+ if (!ignore_sigpipe || sig != SIGPIPE)
+ QtVforkSafe::sigaction(sig, &sa, nullptr);
+ }
+
+ // and unmask all signals
+ sigset_t set;
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, nullptr);
+ }
+
+ // Close all file descriptors above stderr.
+ // This isn't expected to fail, so we ignore close()'s return value.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
+ int r = -1;
+ int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
+#if QT_CONFIG(close_range)
+ // On FreeBSD, this probably won't fail.
+ // On Linux, this will fail with ENOSYS before kernel 5.9.
+ r = close_range(fd, INT_MAX, 0);
+#endif
+ if (r == -1) {
+ // We *could* read /dev/fd to find out what file descriptors are
+ // open, but we won't. We CANNOT use opendir() here because it
+ // allocates memory. Using getdents(2) plus either strtoul() or
+ // std::from_chars() would be acceptable.
+ int max_fd = INT_MAX;
+ if (struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit) == 0)
+ max_fd = limit.rlim_cur;
+ for ( ; fd < max_fd; ++fd)
+ close(fd);
+ }
+ }
+ // Apply session and process group settings. This may fail.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
+ if (setsid() < 0)
+ return "setsid";
+ }
+
+ // Disconnect from the controlling TTY. This probably won't fail. Must be
+ // done after the session settings from above.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
+ if (int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
+ // we still have a controlling TTY; give it up
+ int r = ioctl(fd, TIOCNOTTY);
+ int savedErrno = errno;
+ close(fd);
+ if (r != 0) {
+ errno = savedErrno;
+ return "ioctl";
+ }
+ }
+ }
+
+ // Apply UID and GID parameters last. This isn't expected to fail either:
+ // either we're trying to impersonate what we already are, or we're EUID or
+ // EGID root, in which case we are allowed to do this.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
+ int r = setgid(getgid());
+ r = setuid(getuid());
+ (void) r;
+ }
+
+ return nullptr;
+}
+
+// the noexcept here adds an extra layer of protection
+static void callChildProcessModifier(const QProcessPrivate *d) noexcept
+{
+ QT_TRY {
+ if (d->unixExtras->childProcessModifier)
+ d->unixExtras->childProcessModifier();
+ } QT_CATCH (std::exception &e) {
+ failChildProcess(d, e.what(), FakeErrnoForThrow);
+ } QT_CATCH (...) {
+ failChildProcess(d, "throw", FakeErrnoForThrow);
+ }
+}
+
+// IMPORTANT:
+//
+// This function is called in a vfork() context on some OSes (notably, Linux
+// with forkfd), so it MUST NOT modify any non-local variable because it's
+// still sharing memory with the parent process.
+void QChildProcess::startProcess() const noexcept
+{
// Render channels configuration.
- commitChannels();
+ d->commitChannels();
// make sure this fd is closed if execv() succeeds
- qt_safe_close(childStartedPipe[0]);
+ qt_safe_close(d->childStartedPipe[0]);
// enter the working directory
- if (workingDir && QT_CHDIR(workingDir) == -1) {
- // failed, stop the process
- strcpy(error.function, "chdir");
- goto report_errno;
+ if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
+ failChildProcess(d, "fchdir", errno);
+
+ bool sigpipeHandled = false;
+ bool sigmaskHandled = false;
+ if (d->unixExtras) {
+ // FIRST we call the user modifier function, before we dropping
+ // privileges or closing non-standard file descriptors
+ callChildProcessModifier(d);
+
+ // then we apply our other user-provided parameters
+ if (const char *what = applyProcessParameters(d->unixExtras->processParameters))
+ failChildProcess(d, what, errno);
+
+ auto flags = d->unixExtras->processParameters.flags;
+ using P = QProcess::UnixProcessFlag;
+ sigpipeHandled = flags.testAnyFlags(P::ResetSignalHandlers | P::IgnoreSigPipe);
+ sigmaskHandled = flags.testFlag(P::ResetSignalHandlers);
+ }
+ if (!sigpipeHandled) {
+ // reset the signal that we ignored
+ QtVforkSafe::change_sigpipe(SIG_DFL); // reset the signal that we ignored
+ }
+ if (!sigmaskHandled) {
+ // restore the signal mask from the parent, if applyProcessParameters()
+ // hasn't completely reset it
+ restoreSignalMask();
}
-
- if (childProcessModifier)
- childProcessModifier();
// execute the process
- if (!envp) {
+ if (!envp.pointers)
qt_safe_execv(argv[0], argv);
- strcpy(error.function, "execvp");
- } else {
-#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
-#endif
+ else
qt_safe_execve(argv[0], argv, envp);
- strcpy(error.function, "execve");
- }
-
- // notify failure
- // don't use strerror or any other routines that may allocate memory, since
- // some buggy libc versions can deadlock on locked mutexes.
-report_errno:
- error.code = errno;
- qt_safe_write(childStartedPipe[1], &error, sizeof(error));
- childStartedPipe[1] = -1;
+ failChildProcess(d, "execve", errno);
}
bool QProcessPrivate::processStarted(QString *errorMessage)
@@ -594,7 +949,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage)
Q_Q(QProcess);
ChildError buf;
- int ret = qt_safe_read(childStartedPipe[0], &buf, sizeof(buf));
+ ssize_t ret = qt_safe_read(childStartedPipe[0], &buf, sizeof(buf));
if (stateNotifier) {
stateNotifier->setEnabled(false);
@@ -624,7 +979,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage)
// did we read an error message?
if (errorMessage)
- *errorMessage = QLatin1String(buf.function) + QLatin1String(": ") + qt_error_string(buf.code);
+ *errorMessage = startFailureErrorMessage(buf, ret);
return false;
}
@@ -742,7 +1097,7 @@ void QProcessPrivate::terminateProcess()
qDebug("QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
#endif
if (pid > 0)
- ::kill(pid_t(pid), SIGTERM);
+ ::kill(pid, SIGTERM);
}
void QProcessPrivate::killProcess()
@@ -751,20 +1106,20 @@ void QProcessPrivate::killProcess()
qDebug("QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
#endif
if (pid > 0)
- ::kill(pid_t(pid), SIGKILL);
+ ::kill(pid, SIGKILL);
}
bool QProcessPrivate::waitForStarted(const QDeadlineTimer &deadline)
{
- const qint64 msecs = deadline.remainingTime();
#if defined (QPROCESS_DEBUG)
+ const qint64 msecs = deadline.remainingTime();
qDebug("QProcessPrivate::waitForStarted(%lld) waiting for child to start (fd = %d)",
msecs, childStartedPipe[0]);
#endif
pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
- if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
+ if (qt_safe_poll(&pfd, 1, deadline) == 0) {
setError(QProcess::Timedout);
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::waitForStarted(%lld) == false (timed out)", msecs);
@@ -913,39 +1268,31 @@ void QProcessPrivate::waitForDeadChild()
Q_ASSERT(forkfd != -1);
// read the process information from our fd
- forkfd_info info;
+ forkfd_info info = {}; // Silence -Wmaybe-uninitialized; Thiago says forkfd_wait cannot fail here
+ // (QTBUG-119081)
int ret;
- EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
+ QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
exitCode = info.status;
- crashed = info.code != CLD_EXITED;
+ exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
delete stateNotifier;
stateNotifier = nullptr;
- EINTR_LOOP(ret, forkfd_close(forkfd));
+ QT_EINTR_LOOP(ret, forkfd_close(forkfd));
forkfd = -1; // Child is dead, don't try to kill it anymore
#if defined QPROCESS_DEBUG
qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
- << exitCode << ", crashed?" << crashed;
+ << exitCode << ", crashed?" << (info.code != CLD_EXITED);
#endif
}
bool QProcessPrivate::startDetached(qint64 *pid)
{
- QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
-
-#ifdef PIPE_BUF
- static_assert(PIPE_BUF >= sizeof(ChildError));
-#else
- static_assert(_POSIX_PIPE_BUF >= sizeof(ChildError));
-#endif
- ChildError childStatus = { 0, {} };
-
AutoPipe startedPipe, pidPipe;
if (!startedPipe || !pidPipe) {
- setErrorAndEmit(QProcess::FailedToStart, QLatin1String("pipe: ") + qt_error_string(errno));
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
}
@@ -955,54 +1302,35 @@ bool QProcessPrivate::startDetached(qint64 *pid)
return false;
}
- const CharPointerList argv(resolveExecutable(program), arguments);
- const CharPointerList envp(environment.d.constData());
+ // see startProcess() for more information
+ QChildProcess childProcess(this);
+ if (!childProcess.ok()) {
+ Q_ASSERT(processError != QProcess::UnknownError);
+ return false;
+ }
- pid_t childPid = fork();
- if (childPid == 0) {
- ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
+ childStartedPipe[1] = startedPipe[1]; // for failChildProcess()
+ pid_t childPid = childProcess.doFork([&] {
::setsid();
qt_safe_close(startedPipe[0]);
qt_safe_close(pidPipe[0]);
- auto reportFailed = [&](const char *function) {
- childStatus.code = errno;
- strcpy(childStatus.function, function);
- qt_safe_write(startedPipe[1], &childStatus, sizeof(childStatus));
- ::_exit(1);
- };
-
- if (!encodedWorkingDirectory.isEmpty()) {
- if (QT_CHDIR(encodedWorkingDirectory.constData()) < 0)
- reportFailed("chdir: ");
- }
-
- pid_t doubleForkPid = fork();
- if (doubleForkPid == 0) {
- // Render channels configuration.
- commitChannels();
-
- if (envp.pointers)
- qt_safe_execve(argv.pointers[0], argv.pointers.get(), envp.pointers.get());
- else
- qt_safe_execv(argv.pointers[0], argv.pointers.get());
-
- reportFailed("execv: ");
- } else if (doubleForkPid == -1) {
- reportFailed("fork: ");
- }
+ pid_t doubleForkPid;
+ if (childProcess.startChild(&doubleForkPid) == -1)
+ failChildProcess(this, "fork", errno);
// success
qt_safe_write(pidPipe[1], &doubleForkPid, sizeof(pid_t));
- ::_exit(1);
- }
+ return 0;
+ });
+ childStartedPipe[1] = -1;
int savedErrno = errno;
closeChannels();
if (childPid == -1) {
- setErrorAndEmit(QProcess::FailedToStart, QLatin1String("fork: ") + qt_error_string(savedErrno));
+ setErrorAndEmit(QProcess::FailedToStart, "fork: "_L1 + qt_error_string(savedErrno));
return false;
}
@@ -1016,6 +1344,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
// successfully execve()'d the target process. If it returns any positive
// result, it means one of the two children wrote an error result. Negative
// values should not happen.
+ ChildError childStatus;
ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus, sizeof(childStatus));
// reap the intermediate child
@@ -1031,10 +1360,8 @@ bool QProcessPrivate::startDetached(qint64 *pid)
} else if (!success) {
if (pid)
*pid = -1;
- QString msg;
- if (startResult == sizeof(childStatus))
- msg = QLatin1String(childStatus.function) + qt_error_string(childStatus.code);
- setErrorAndEmit(QProcess::FailedToStart, msg);
+ setErrorAndEmit(QProcess::FailedToStart,
+ startFailureErrorMessage(childStatus, startResult));
}
return success;
}
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index aaaccf4e0d..e64b133815 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QPROCESS_DEBUG
#include <qdebug.h>
@@ -64,6 +28,10 @@
QT_BEGIN_NAMESPACE
+constexpr UINT KillProcessExitCode = 0xf291;
+
+using namespace Qt::StringLiterals;
+
QProcessEnvironment QProcessEnvironment::systemEnvironment()
{
QProcessEnvironment env;
@@ -172,6 +140,7 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
DWORD dwError = GetLastError();
if (dwError != ERROR_PIPE_BUSY || !--attempts) {
qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.");
+ SetLastError(dwError);
return false;
}
}
@@ -186,8 +155,10 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
FILE_FLAG_OVERLAPPED,
NULL);
if (hClient == INVALID_HANDLE_VALUE) {
+ DWORD dwError = GetLastError();
qErrnoWarning("QProcess: CreateFile failed.");
CloseHandle(hServer);
+ SetLastError(dwError);
return false;
}
@@ -204,10 +175,12 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
WaitForSingleObject(overlapped.hEvent, INFINITE);
break;
default:
+ dwError = GetLastError();
qErrnoWarning(dwError, "QProcess: ConnectNamedPipe failed.");
CloseHandle(overlapped.hEvent);
CloseHandle(hClient);
CloseHandle(hServer);
+ SetLastError(dwError);
return false;
}
}
@@ -233,8 +206,13 @@ bool QProcessPrivate::openChannel(Channel &channel)
switch (channel.type) {
case Channel::Normal: {
// we're piping this channel to our own process
- if (&channel == &stdinChannel)
- return qt_create_pipe(channel.pipe, true, FALSE);
+ if (&channel == &stdinChannel) {
+ if (!qt_create_pipe(channel.pipe, true, FALSE)) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
+ return false;
+ }
+ return true;
+ }
if (&channel == &stdoutChannel) {
if (!stdoutChannel.reader) {
@@ -247,8 +225,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
}
}
- if (!qt_create_pipe(channel.pipe, false, FALSE))
+ if (!qt_create_pipe(channel.pipe, false, FALSE)) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
channel.reader->setHandle(channel.pipe[0]);
channel.reader->startAsyncRead();
@@ -297,7 +277,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
setErrorAndEmit(QProcess::FailedToStart,
QProcess::tr("Could not open output redirection for writing"));
}
- cleanup();
return false;
}
case Channel::PipeSource: {
@@ -314,8 +293,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(source == &stdoutChannel);
Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
- if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) // source is stdout
+ if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) { // source is stdout
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
sink->pipe[0] = source->pipe[0];
source->pipe[0] = INVALID_Q_PIPE;
@@ -334,8 +315,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(sink == &stdinChannel);
Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
- if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) // sink is stdin
+ if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) { // sink is stdin
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
source->pipe[1] = sink->pipe[1];
sink->pipe[1] = INVALID_Q_PIPE;
@@ -391,44 +374,44 @@ static QString qt_create_commandline(const QString &program, const QStringList &
QString args;
if (!program.isEmpty()) {
QString programName = program;
- if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
- programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
- programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ if (!programName.startsWith(u'\"') && !programName.endsWith(u'\"') && programName.contains(u' '))
+ programName = u'\"' + programName + u'\"';
+ programName.replace(u'/', u'\\');
// add the program as the first arg ... it works better
- args = programName + QLatin1Char(' ');
+ args = programName + u' ';
}
- for (int i=0; i<arguments.size(); ++i) {
+ for (qsizetype i = 0; i < arguments.size(); ++i) {
QString tmp = arguments.at(i);
// Quotes are escaped and their preceding backslashes are doubled.
- int index = tmp.indexOf(QLatin1Char('"'));
+ qsizetype index = tmp.indexOf(u'"');
while (index >= 0) {
// Escape quote
- tmp.insert(index++, QLatin1Char('\\'));
+ tmp.insert(index++, u'\\');
// 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('\\'));
+ for (qsizetype i = index - 2 ; i >= 0 && tmp.at(i) == u'\\' ; --i) {
+ tmp.insert(i, u'\\');
index++;
}
- index = tmp.indexOf(QLatin1Char('"'), index + 1);
+ index = tmp.indexOf(u'"', index + 1);
}
- if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
+ if (tmp.isEmpty() || tmp.contains(u' ') || tmp.contains(u'\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.
// rather use "foo"\ than "foo\"
- int i = tmp.length();
- while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\'))
+ qsizetype i = tmp.length();
+ while (i > 0 && tmp.at(i - 1) == u'\\')
--i;
- tmp.insert(i, QLatin1Char('"'));
- tmp.prepend(QLatin1Char('"'));
+ tmp.insert(i, u'"');
+ tmp.prepend(u'"');
}
- args += QLatin1Char(' ') + tmp;
+ args += u' ' + tmp;
}
if (!nativeArguments.isEmpty()) {
if (!args.isEmpty())
- args += QLatin1Char(' ');
+ args += u' ';
args += nativeArguments;
}
@@ -441,7 +424,7 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e
QProcessEnvironmentPrivate::Map copy = environment;
// add PATH if necessary (for DLL loading)
- QProcessEnvironmentPrivate::Key pathKey(QLatin1String("PATH"));
+ QProcessEnvironmentPrivate::Key pathKey("PATH"_L1);
if (!copy.contains(pathKey)) {
QByteArray path = qgetenv("PATH");
if (!path.isEmpty())
@@ -449,7 +432,7 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e
}
// add systemroot if needed
- QProcessEnvironmentPrivate::Key rootKey(QLatin1String("SystemRoot"));
+ QProcessEnvironmentPrivate::Key rootKey("SystemRoot"_L1);
if (!copy.contains(rootKey)) {
QByteArray systemRoot = qgetenv("SystemRoot");
if (!systemRoot.isEmpty())
@@ -555,9 +538,9 @@ void QProcessPrivate::startProcess()
q->setProcessState(QProcess::Starting);
if (!openChannels()) {
- QString errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string());
+ // openChannel sets the error string
+ Q_ASSERT(!errorString.isEmpty());
cleanup();
- setErrorAndEmit(QProcess::FailedToStart, errorString);
return;
}
@@ -666,7 +649,7 @@ void QProcessPrivate::terminateProcess()
void QProcessPrivate::killProcess()
{
if (pid)
- TerminateProcess(pid->hProcess, 0xf291);
+ TerminateProcess(pid->hProcess, KillProcessExitCode);
}
bool QProcessPrivate::waitForStarted(const QDeadlineTimer &)
@@ -816,8 +799,11 @@ void QProcessPrivate::findExitCode()
Q_ASSERT(pid);
if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
exitCode = theExitCode;
- crashed = (exitCode == 0xf291 // our magic number, see killProcess
- || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000));
+ if (exitCode == KillProcessExitCode
+ || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000))
+ exitStatus = QProcess::CrashExit;
+ else
+ exitStatus = QProcess::NormalExit;
}
}
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index af0b9429af..b76d2b6478 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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.
-**
-** $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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qresource.h"
#include "qresource_p.h"
@@ -69,7 +33,7 @@
# include <zstd.h>
#endif
-#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include <sys/mman.h>
#endif
@@ -78,6 +42,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// Symbols used by code generated by RCC.
// They cause compilation errors if the RCC content couldn't
// be interpreted by this QtCore version.
@@ -116,7 +82,7 @@ public:
inline QStringView next()
{
- int start = m_pos;
+ const qsizetype start = m_pos;
while (m_pos < m_len && m_data[m_pos] != m_splitChar)
++m_pos;
return QStringView(m_data + start, m_pos - start);
@@ -125,7 +91,7 @@ public:
const QChar *m_data;
qsizetype m_len;
qsizetype m_pos = 0;
- QChar m_splitChar = QLatin1Char('/');
+ QChar m_splitChar = u'/';
};
// resource glue
@@ -189,7 +155,7 @@ static QString cleanPath(const QString &_path)
QString path = QDir::cleanPath(_path);
// QDir::cleanPath does not remove two trailing slashes under _Windows_
// due to support for UNC paths. Remove those manually.
- if (path.startsWith(QLatin1String("//")))
+ if (path.startsWith("//"_L1))
path.remove(0, 1);
return path;
}
@@ -201,7 +167,6 @@ struct QResourceGlobalData
{
QRecursiveMutex resourceMutex;
ResourceList resourceList;
- QStringList resourceSearchPaths;
};
Q_GLOBAL_STATIC(QResourceGlobalData, resourceGlobalData)
@@ -211,9 +176,6 @@ static inline QRecursiveMutex &resourceMutex()
static inline ResourceList *resourceList()
{ return &resourceGlobalData->resourceList; }
-static inline QStringList *resourceSearchPaths()
-{ return &resourceGlobalData->resourceSearchPaths; }
-
/*!
\class QResource
\inmodule QtCore
@@ -271,6 +233,19 @@ static inline QStringList *resourceSearchPaths()
itself will be unmapped from memory when the last QResource that points
to it is destroyed.
+ \section2 Corruption and Security
+
+ The QResource class performs some checks on the file passed to determine
+ whether it is supported by the current version of Qt. Those tests are only
+ to check the file header does not request features (such as Zstandard
+ decompression) that have not been compiled in or that the file is not of a
+ future version of Qt. They do not confirm the validity of the entire file.
+
+ QResource should not be used on files whose provenance cannot be trusted.
+ Applications should be designed to attempt to load only resource files
+ whose provenance is at least as trustworthy as that of the application
+ itself or its plugins.
+
\sa {The Qt Resource System}, QFile, QDir, QFileInfo
*/
@@ -381,29 +356,23 @@ void QResourcePrivate::ensureInitialized() const
if (!related.isEmpty())
return;
QResourcePrivate *that = const_cast<QResourcePrivate *>(this);
- if (fileName == QLatin1String(":"))
- that->fileName += QLatin1Char('/');
+ if (fileName == ":"_L1)
+ that->fileName += u'/';
that->absoluteFilePath = fileName;
- if (!that->absoluteFilePath.startsWith(QLatin1Char(':')))
- that->absoluteFilePath.prepend(QLatin1Char(':'));
+ if (!that->absoluteFilePath.startsWith(u':'))
+ that->absoluteFilePath.prepend(u':');
QStringView path(fileName);
- if (path.startsWith(QLatin1Char(':')))
+ if (path.startsWith(u':'))
path = path.mid(1);
- if (path.startsWith(QLatin1Char('/'))) {
+ if (path.startsWith(u'/')) {
that->load(path.toString());
} else {
- const auto locker = qt_scoped_lock(resourceMutex());
- QStringList searchPaths = *resourceSearchPaths();
- searchPaths << QLatin1String("");
- for (int i = 0; i < searchPaths.size(); ++i) {
- const QString searchPath(searchPaths.at(i) + QLatin1Char('/') + path);
- if (that->load(searchPath)) {
- that->absoluteFilePath = QLatin1Char(':') + searchPath;
- break;
- }
- }
+ // Should we search QDir::searchPath() before falling back to root ?
+ const QString searchPath(u'/' + path);
+ if (that->load(searchPath))
+ that->absoluteFilePath = u':' + searchPath;
}
}
@@ -414,7 +383,7 @@ void QResourcePrivate::ensureChildren() const
return;
QString path = absoluteFilePath, k;
- if (path.startsWith(QLatin1Char(':')))
+ if (path.startsWith(u':'))
path = path.mid(1);
QDuplicateTracker<QString> kids(related.size());
QString cleaned = cleanPath(path);
@@ -797,7 +766,7 @@ inline QString QResourceRoot::name(int node) const
ret.resize(name_length);
QChar *strData = ret.data();
- qFromBigEndian<ushort>(names + name_offset, name_length, strData);
+ qFromBigEndian<char16_t>(names + name_offset, name_length, strData);
return ret;
}
@@ -808,14 +777,14 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
QString root = mappingRoot();
if (!root.isEmpty()) {
if (root == path) {
- path = QLatin1Char('/');
+ path = u'/';
} else {
- if (!root.endsWith(QLatin1Char('/')))
- root += QLatin1Char('/');
+ if (!root.endsWith(u'/'))
+ root += u'/';
if (path.size() >= root.size() && path.startsWith(root))
- path = path.mid(root.length() - 1);
+ path = path.mid(root.size() - 1);
if (path.isEmpty())
- path = QLatin1Char('/');
+ path = u'/';
}
}
}
@@ -823,7 +792,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
qDebug() << "!!!!" << "START" << path << locale.territory() << locale.language();
#endif
- if (path == QLatin1String("/"))
+ if (path == "/"_L1)
return 0;
// the root node is always first
@@ -1228,7 +1197,7 @@ bool QDynamicFileResourceRoot::registerSelf(const QString &f)
static QString qt_resource_fixResourceRoot(QString r)
{
if (!r.isEmpty()) {
- if (r.startsWith(QLatin1Char(':')))
+ if (r.startsWith(u':'))
r = r.mid(1);
if (!r.isEmpty())
r = QDir::cleanPath(r);
@@ -1249,7 +1218,7 @@ static QString qt_resource_fixResourceRoot(QString r)
bool QResource::registerResource(const QString &rccFilename, const QString &resourceRoot)
{
QString r = qt_resource_fixResourceRoot(resourceRoot);
- if (!r.isEmpty() && r[0] != QLatin1Char('/')) {
+ if (!r.isEmpty() && r[0] != u'/') {
qWarning("QDir::registerResource: Registering a resource [%ls] must be rooted in an "
"absolute path (start with /) [%ls]",
qUtf16Printable(rccFilename), qUtf16Printable(resourceRoot));
@@ -1318,7 +1287,7 @@ bool QResource::unregisterResource(const QString &rccFilename, const QString &re
bool QResource::registerResource(const uchar *rccData, const QString &resourceRoot)
{
QString r = qt_resource_fixResourceRoot(resourceRoot);
- if (!r.isEmpty() && r[0] != QLatin1Char('/')) {
+ if (!r.isEmpty() && r[0] != u'/') {
qWarning("QDir::registerResource: Registering a resource [%p] must be rooted in an "
"absolute path (start with /) [%ls]",
rccData, qUtf16Printable(resourceRoot));
@@ -1512,7 +1481,7 @@ QAbstractFileEngine::FileFlags QResourceFileEngine::fileFlags(QAbstractFileEngin
}
if (type & FlagsMask) {
ret |= ExistsFlag;
- if (d->resource.absoluteFilePath() == QLatin1String(":/"))
+ if (d->resource.absoluteFilePath() == ":/"_L1)
ret |= RootFlag;
}
return ret;
@@ -1522,24 +1491,24 @@ QString QResourceFileEngine::fileName(FileName file) const
{
Q_D(const QResourceFileEngine);
if (file == BaseName) {
- int slash = d->resource.fileName().lastIndexOf(QLatin1Char('/'));
+ const qsizetype slash = d->resource.fileName().lastIndexOf(u'/');
if (slash == -1)
return d->resource.fileName();
return d->resource.fileName().mid(slash + 1);
} else if (file == PathName || file == AbsolutePathName) {
const QString path = (file == AbsolutePathName) ? d->resource.absoluteFilePath()
: d->resource.fileName();
- const int slash = path.lastIndexOf(QLatin1Char('/'));
+ const qsizetype slash = path.lastIndexOf(u'/');
if (slash == -1)
- return QLatin1String(":");
+ return ":"_L1;
else if (slash <= 1)
- return QLatin1String(":/");
+ return ":/"_L1;
return path.left(slash);
} else if (file == CanonicalName || file == CanonicalPathName) {
const QString absoluteFilePath = d->resource.absoluteFilePath();
if (file == CanonicalPathName) {
- const int slash = absoluteFilePath.lastIndexOf(QLatin1Char('/'));
+ const qsizetype slash = absoluteFilePath.lastIndexOf(u'/');
if (slash != -1)
return absoluteFilePath.left(slash);
}
@@ -1554,10 +1523,10 @@ uint QResourceFileEngine::ownerId(FileOwner) const
return nobodyID;
}
-QDateTime QResourceFileEngine::fileTime(FileTime time) const
+QDateTime QResourceFileEngine::fileTime(QFile::FileTime time) const
{
Q_D(const QResourceFileEngine);
- if (time == ModificationTime)
+ if (time == QFile::FileModificationTime)
return d->resource.lastModified();
return QDateTime();
}
@@ -1565,18 +1534,11 @@ QDateTime QResourceFileEngine::fileTime(FileTime time) const
/*!
\internal
*/
-QAbstractFileEngine::Iterator *QResourceFileEngine::beginEntryList(QDir::Filters filters,
- const QStringList &filterNames)
-{
- return new QResourceFileEngineIterator(filters, filterNames);
-}
-
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QResourceFileEngine::endEntryList()
+QAbstractFileEngine::IteratorUniquePtr
+QResourceFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return nullptr;
+ return std::make_unique<QResourceFileEngineIterator>(path, filters, filterNames);
}
bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
@@ -1608,7 +1570,7 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory
qint64 max = resource.uncompressedSize();
qint64 end;
if (offset < 0 || size <= 0 || !resource.isValid() ||
- add_overflow(offset, size, &end) || end > max) {
+ qAddOverflow(offset, size, &end) || end > max) {
q->setError(QFile::UnspecifiedError, QString());
return nullptr;
}
diff --git a/src/corelib/io/qresource.h b/src/corelib/io/qresource.h
index 0361f435b3..ca968b5180 100644
--- a/src/corelib/io/qresource.h
+++ b/src/corelib/io/qresource.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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.
-**
-** $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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2019 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRESOURCE_H
#define QRESOURCE_H
diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp
index 29a9e22294..abb61d3b46 100644
--- a/src/corelib/io/qresource_iterator.cpp
+++ b/src/corelib/io/qresource_iterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qresource.h"
#include "qresource_iterator_p.h"
@@ -44,9 +8,10 @@
QT_BEGIN_NAMESPACE
-QResourceFileEngineIterator::QResourceFileEngineIterator(QDir::Filters filters,
+QResourceFileEngineIterator::QResourceFileEngineIterator(const QString &path, QDir::Filters filters,
const QStringList &filterNames)
- : QAbstractFileEngineIterator(filters, filterNames), index(-1)
+ : QAbstractFileEngineIterator(path, filters, filterNames),
+ index(-1)
{
}
@@ -54,15 +19,7 @@ QResourceFileEngineIterator::~QResourceFileEngineIterator()
{
}
-QString QResourceFileEngineIterator::next()
-{
- if (!hasNext())
- return QString();
- ++index;
- return currentFilePath();
-}
-
-bool QResourceFileEngineIterator::hasNext() const
+bool QResourceFileEngineIterator::advance()
{
if (index == -1) {
// Lazy initialization of the iterator
@@ -70,19 +27,34 @@ bool QResourceFileEngineIterator::hasNext() const
if (!resource.isValid())
return false;
- // Initialize and move to the next entry.
+ // Initialize and move to the first entry.
entries = resource.children();
+ if (entries.isEmpty())
+ return false;
+
index = 0;
+ return true;
}
- return index < entries.size();
+ if (index < entries.size() - 1) {
+ ++index;
+ return true;
+ }
+
+ return false;
}
QString QResourceFileEngineIterator::currentFileName() const
{
- if (index <= 0 || index > entries.size())
+ if (index < 0 || index > entries.size())
return QString();
- return entries.at(index - 1);
+ return entries.at(index);
+}
+
+QFileInfo QResourceFileEngineIterator::currentFileInfo() const
+{
+ m_fileInfo = QFileInfo(currentFilePath());
+ return m_fileInfo;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h
index 207a88b0ba..bcbbc46b51 100644
--- a/src/corelib/io/qresource_iterator_p.h
+++ b/src/corelib/io/qresource_iterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRESOURCE_ITERATOR_P_H
#define QRESOURCE_ITERATOR_P_H
@@ -60,13 +24,14 @@ class QResourceFileEngineIteratorPrivate;
class QResourceFileEngineIterator : public QAbstractFileEngineIterator
{
public:
- QResourceFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
+ QResourceFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames);
~QResourceFileEngineIterator();
- QString next() override;
- bool hasNext() const override;
+ bool advance() override;
QString currentFileName() const override;
+ QFileInfo currentFileInfo() const override;
private:
mutable QStringList entries;
diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h
index 19db6b24cd..37fddd7a41 100644
--- a/src/corelib/io/qresource_p.h
+++ b/src/corelib/io/qresource_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRESOURCE_P_H
#define QRESOURCE_P_H
@@ -83,10 +47,10 @@ public:
uint ownerId(FileOwner) const override;
- QDateTime fileTime(FileTime time) const override;
+ QDateTime fileTime(QFile::FileTime time) const override;
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr) override;
bool supportsExtension(Extension extension) const override;
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index afe39287bd..cc59bb3725 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 David Faure <faure@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsavefile.h"
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "qplatformdefs.h"
#include "private/qsavefile_p.h"
@@ -55,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QSaveFilePrivate::QSaveFilePrivate()
: writeError(QFileDevice::NoError),
useTemporaryFile(true),
@@ -147,10 +113,10 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
QSaveFile::~QSaveFile()
{
Q_D(QSaveFile);
- QFileDevice::close();
- if (d->fileEngine) {
+ if (isOpen()) {
+ QFileDevice::close();
+ Q_ASSERT(d->fileEngine);
d->fileEngine->remove();
- d->fileEngine.reset();
}
}
@@ -186,7 +152,7 @@ void QSaveFile::setFileName(const QString &name)
QIODevice::ReadWrite, QIODevice::Append, QIODevice::NewOnly and
QIODevice::ExistingOnly are not supported at the moment.
- \sa QIODevice::OpenMode, setFileName()
+ \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN
*/
bool QSaveFile::open(OpenMode mode)
{
@@ -234,7 +200,7 @@ bool QSaveFile::open(OpenMode mode)
}
auto openDirectly = [&]() {
- d->fileEngine.reset(QAbstractFileEngine::create(d->finalFileName));
+ d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
d->useTemporaryFile = false;
QFileDevice::open(mode);
@@ -246,10 +212,10 @@ bool QSaveFile::open(OpenMode mode)
bool requiresDirectWrite = false;
#ifdef Q_OS_WIN
// check if it is an Alternate Data Stream
- requiresDirectWrite = d->finalFileName == d->fileName && d->fileName.indexOf(QLatin1Char(':'), 2) > 1;
+ requiresDirectWrite = d->finalFileName == d->fileName && d->fileName.indexOf(u':', 2) > 1;
#elif defined(Q_OS_ANDROID)
// check if it is a content:// URL
- requiresDirectWrite = d->fileName.startsWith(QLatin1String("content://"));
+ requiresDirectWrite = d->fileName.startsWith("content://"_L1);
#endif
if (requiresDirectWrite) {
// yes, we can't rename onto it...
@@ -332,7 +298,7 @@ bool QSaveFile::commit()
}
QFileDevice::close(); // calls flush()
- const auto fe = std::move(d->fileEngine);
+ const auto &fe = d->fileEngine;
// Sync to disk if possible. Ignore errors (e.g. not supported).
fe->syncToDisk();
@@ -446,4 +412,4 @@ QT_END_NAMESPACE
#include "moc_qsavefile.cpp"
#endif
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 200068d30d..4dd712d4b6 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 David Faure <faure@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSAVEFILE_H
#define QSAVEFILE_H
#include <QtCore/qglobal.h>
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include <QtCore/qfiledevice.h>
#include <QtCore/qstring.h>
@@ -75,7 +39,7 @@ public:
QString fileName() const override;
void setFileName(const QString &name);
- bool open(OpenMode flags) override;
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override;
bool commit();
void cancelWriting();
@@ -98,6 +62,6 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
#endif // QSAVEFILE_H
diff --git a/src/corelib/io/qsavefile_p.h b/src/corelib/io/qsavefile_p.h
index 3f81df9ae2..4d0f40fbb0 100644
--- a/src/corelib/io/qsavefile_p.h
+++ b/src/corelib/io/qsavefile_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSAVEFILE_P_H
#define QSAVEFILE_P_H
@@ -53,7 +17,7 @@
#include <QtCore/qglobal.h>
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "private/qfiledevice_p.h"
@@ -78,6 +42,6 @@ protected:
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
#endif // QSAVEFILE_P_H
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index e72b4349c8..6934ca4404 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qdebug.h>
#include "qplatformdefs.h"
@@ -48,11 +12,12 @@
#include "qfileinfo.h"
#include "qmutex.h"
#include "private/qlocking_p.h"
+#include "private/qtools_p.h"
#include "qlibraryinfo.h"
#include "qtemporaryfile.h"
#include "qstandardpaths.h"
#include <qdatastream.h>
-#include <qstringconverter.h>
+#include "private/qstringconverter_p.h"
#ifndef QT_NO_GEOM_VARIANT
#include "qsize.h"
@@ -79,12 +44,13 @@
# include <shlobj.h>
#endif
-#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
#define Q_XDG_PLATFORM
#endif
-#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
-#define QSETTINGS_USE_QSTANDARDPATHS
+#if !defined(QT_NO_STANDARDPATHS) \
+ && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID))
+# define QSETTINGS_USE_QSTANDARDPATHS
#endif
// ************************************************************************
@@ -99,6 +65,9 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+
struct QConfFileCustomFormat
{
QString extension;
@@ -129,9 +98,9 @@ Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
Q_GLOBAL_STATIC(PathHash, pathHashFunc)
Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
-static QBasicMutex settingsGlobalMutex;
+Q_CONSTINIT static QBasicMutex settingsGlobalMutex;
-static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
+Q_CONSTINIT static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
QConfFile::QConfFile(const QString &fileName, bool _userPerms)
: name(fileName), size(0), ref(1), userPerms(_userPerms)
@@ -148,11 +117,10 @@ QConfFile::~QConfFile()
ParsedSettingsMap QConfFile::mergedKeyMap() const
{
ParsedSettingsMap result = originalKeys;
- ParsedSettingsMap::const_iterator i;
- for (i = removedKeys.begin(); i != removedKeys.end(); ++i)
+ for (auto i = removedKeys.begin(); i != removedKeys.end(); ++i)
result.remove(i.key());
- for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
+ for (auto i = addedKeys.begin(); i != addedKeys.end(); ++i)
result.insert(i.key(), i.value());
return result;
}
@@ -161,12 +129,12 @@ bool QConfFile::isWritable() const
{
QFileInfo fileInfo(name);
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
if (fileInfo.exists()) {
#endif
QFile file(name);
return file.open(QFile::ReadWrite);
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
} else {
// Create the directories to the file.
QDir dir(fileInfo.absolutePath());
@@ -229,13 +197,30 @@ QSettingsPrivate::~QSettingsPrivate()
{
}
-QString QSettingsPrivate::actualKey(const QString &key) const
+QString QSettingsPrivate::actualKey(QAnyStringView key) const
{
auto n = normalizedKey(key);
Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
return groupPrefix + n;
}
+namespace {
+ // ### this needs some public API (QStringConverter?)
+ QChar *write(QChar *out, QUtf8StringView v)
+ {
+ return QUtf8::convertToUnicode(out, QByteArrayView(v));
+ }
+ QChar *write(QChar *out, QLatin1StringView v)
+ {
+ return QLatin1::convertToUnicode(out, v);
+ }
+ QChar *write(QChar *out, QStringView v)
+ {
+ memcpy(out, v.data(), v.size() * sizeof(QChar));
+ return out + v.size();
+ }
+}
+
/*
Returns a string that never starts nor ends with a slash (or an
empty string). Examples:
@@ -243,38 +228,49 @@ QString QSettingsPrivate::actualKey(const QString &key) const
"foo" becomes "foo"
"/foo//bar///" becomes "foo/bar"
"///" becomes ""
-
- This function is optimized to avoid a QString deep copy in the
- common case where the key is already normalized.
*/
-QString QSettingsPrivate::normalizedKey(const QString &key)
+QString QSettingsPrivate::normalizedKey(QAnyStringView key)
{
- QString result = key;
+ QString result(key.size(), Qt::Uninitialized);
+ auto out = const_cast<QChar*>(result.constData()); // don't detach
- int i = 0;
- while (i < result.size()) {
- while (result.at(i) == QLatin1Char('/')) {
- result.remove(i, 1);
- if (i == result.size())
- goto after_loop;
- }
- while (result.at(i) != QLatin1Char('/')) {
- ++i;
- if (i == result.size())
- return result;
+ const bool maybeEndsInSlash = key.visit([&out](auto key) {
+ using View = decltype(key);
+
+ auto it = key.begin();
+ const auto end = key.end();
+
+ while (it != end) {
+ while (*it == u'/') {
+ ++it;
+ if (it == end)
+ return true;
+ }
+ auto mark = it;
+ while (*it != u'/') {
+ ++it;
+ if (it == end)
+ break;
+ }
+ out = write(out, View{mark, it});
+ if (it == end)
+ return false;
+ Q_ASSERT(*it == u'/');
+ *out++ = u'/';
+ ++it;
}
- ++i; // leave the slash alone
- }
+ return true;
+ });
-after_loop:
- if (!result.isEmpty())
- result.truncate(i - 1); // remove the trailing slash
+ if (maybeEndsInSlash && out != result.constData())
+ --out; // remove the trailing slash
+ result.truncate(out - result.constData());
return result;
}
// see also qsettings_win.cpp and qsettings_mac.cpp
-#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
+#if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_WASM)
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
{
@@ -292,7 +288,7 @@ QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::F
void QSettingsPrivate::processChild(QStringView key, ChildSpec spec, QStringList &result)
{
if (spec != AllKeys) {
- int slashPos = key.indexOf(QLatin1Char('/'));
+ qsizetype slashPos = key.indexOf(u'/');
if (slashPos == -1) {
if (spec != ChildKeys)
return;
@@ -310,7 +306,7 @@ void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group)
groupStack.push(group);
const QString name = group.name();
if (!name.isEmpty())
- groupPrefix += name + QLatin1Char('/');
+ groupPrefix += name + u'/';
}
/*
@@ -346,30 +342,27 @@ void QSettingsPrivate::requestUpdate()
QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l)
{
QStringList result;
- result.reserve(l.count());
- QVariantList::const_iterator it = l.constBegin();
- for (; it != l.constEnd(); ++it)
- result.append(variantToString(*it));
+ result.reserve(l.size());
+ for (auto v : l)
+ result.append(variantToString(v));
return result;
}
QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l)
{
QStringList outStringList = l;
- for (int i = 0; i < outStringList.count(); ++i) {
+ for (qsizetype i = 0; i < outStringList.size(); ++i) {
const QString &str = outStringList.at(i);
- if (str.startsWith(QLatin1Char('@'))) {
- if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) {
- outStringList[i].remove(0, 1);
- } else {
+ if (str.startsWith(u'@')) {
+ if (str.size() < 2 || str.at(1) != u'@') {
QVariantList variantList;
- const int stringCount = l.count();
- variantList.reserve(stringCount);
- for (int j = 0; j < stringCount; ++j)
- variantList.append(stringToVariant(l.at(j)));
+ variantList.reserve(l.size());
+ for (const auto &s : l)
+ variantList.append(stringToVariant(s));
return variantList;
}
+ outStringList[i].remove(0, 1);
}
}
return outStringList;
@@ -381,14 +374,12 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
switch (v.metaType().id()) {
case QMetaType::UnknownType:
- result = QLatin1String("@Invalid()");
+ result = "@Invalid()"_L1;
break;
case QMetaType::QByteArray: {
QByteArray a = v.toByteArray();
- result = QLatin1String("@ByteArray(")
- + QLatin1String(a.constData(), a.size())
- + QLatin1Char(')');
+ result = "@ByteArray("_L1 + QLatin1StringView(a) + u')';
break;
}
@@ -405,9 +396,9 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
case QMetaType::Double: {
result = v.toString();
if (result.contains(QChar::Null))
- result = QLatin1String("@String(") + result + QLatin1Char(')');
- else if (result.startsWith(QLatin1Char('@')))
- result.prepend(QLatin1Char('@'));
+ result = "@String("_L1 + result + u')';
+ else if (result.startsWith(u'@'))
+ result.prepend(u'@');
break;
}
#ifndef QT_NO_GEOM_VARIANT
@@ -446,9 +437,9 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
s << v;
}
- result = QLatin1String(typeSpec)
- + QLatin1String(a.constData(), a.size())
- + QLatin1Char(')');
+ result = QLatin1StringView(typeSpec)
+ + QLatin1StringView(a.constData(), a.size())
+ + u')';
#else
Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
#endif
@@ -462,25 +453,25 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
QVariant QSettingsPrivate::stringToVariant(const QString &s)
{
- if (s.startsWith(QLatin1Char('@'))) {
- if (s.endsWith(QLatin1Char(')'))) {
- if (s.startsWith(QLatin1String("@ByteArray("))) {
- return QVariant(QStringView{s}.mid(11, s.size() - 12).toLatin1());
- } else if (s.startsWith(QLatin1String("@String("))) {
- return QVariant(QStringView{s}.mid(8, s.size() - 9).toString());
- } else if (s.startsWith(QLatin1String("@Variant("))
- || s.startsWith(QLatin1String("@DateTime("))) {
+ if (s.startsWith(u'@')) {
+ if (s.endsWith(u')')) {
+ if (s.startsWith("@ByteArray("_L1)) {
+ return QVariant(QStringView{s}.sliced(11).chopped(1).toLatin1());
+ } else if (s.startsWith("@String("_L1)) {
+ return QVariant(QStringView{s}.sliced(8).chopped(1).toString());
+ } else if (s.startsWith("@Variant("_L1)
+ || s.startsWith("@DateTime("_L1)) {
#ifndef QT_NO_DATASTREAM
QDataStream::Version version;
int offset;
- if (s.at(1) == QLatin1Char('D')) {
+ if (s.at(1) == u'D') {
version = QDataStream::Qt_5_6;
offset = 10;
} else {
version = QDataStream::Qt_4_0;
offset = 9;
}
- QByteArray a = QStringView{s}.mid(offset).toLatin1();
+ QByteArray a = QStringView{s}.sliced(offset).toLatin1();
QDataStream stream(&a, QIODevice::ReadOnly);
stream.setVersion(version);
QVariant result;
@@ -490,53 +481,50 @@ QVariant QSettingsPrivate::stringToVariant(const QString &s)
Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
#endif
#ifndef QT_NO_GEOM_VARIANT
- } else if (s.startsWith(QLatin1String("@Rect("))) {
+ } else if (s.startsWith("@Rect("_L1)) {
QStringList args = QSettingsPrivate::splitArgs(s, 5);
if (args.size() == 4)
return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
- } else if (s.startsWith(QLatin1String("@Size("))) {
+ } else if (s.startsWith("@Size("_L1)) {
QStringList args = QSettingsPrivate::splitArgs(s, 5);
if (args.size() == 2)
return QVariant(QSize(args[0].toInt(), args[1].toInt()));
- } else if (s.startsWith(QLatin1String("@Point("))) {
+ } else if (s.startsWith("@Point("_L1)) {
QStringList args = QSettingsPrivate::splitArgs(s, 6);
if (args.size() == 2)
return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
#endif
- } else if (s == QLatin1String("@Invalid()")) {
+ } else if (s == "@Invalid()"_L1) {
return QVariant();
}
}
- if (s.startsWith(QLatin1String("@@")))
- return QVariant(s.mid(1));
+ if (s.startsWith("@@"_L1))
+ return QVariant(s.sliced(1));
}
return QVariant(s);
}
-static const char hexDigits[] = "0123456789ABCDEF";
-
void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
{
- result.reserve(result.length() + key.length() * 3 / 2);
- for (int i = 0; i < key.size(); ++i) {
+ result.reserve(result.size() + key.size() * 3 / 2);
+ for (qsizetype i = 0; i < key.size(); ++i) {
uint ch = key.at(i).unicode();
if (ch == '/') {
result += '\\';
- } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
- || ch == '_' || ch == '-' || ch == '.') {
+ } else if (isAsciiLetterOrNumber(ch) || ch == '_' || ch == '-' || ch == '.') {
result += (char)ch;
} else if (ch <= 0xFF) {
result += '%';
- result += hexDigits[ch / 16];
- result += hexDigits[ch % 16];
+ result += QtMiscUtils::toHexUpper(ch / 16);
+ result += QtMiscUtils::toHexUpper(ch % 16);
} else {
result += "%U";
QByteArray hexCode;
- for (int i = 0; i < 4; ++i) {
- hexCode.prepend(hexDigits[ch % 16]);
+ for (int j = 0; j < 4; ++j) {
+ hexCode.prepend(QtMiscUtils::toHexUpper(ch % 16));
ch >>= 4;
}
result += hexCode;
@@ -544,49 +532,50 @@ void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
}
}
-bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
+bool QSettingsPrivate::iniUnescapedKey(QByteArrayView key, QString &result)
{
+ const QString decoded = QString::fromUtf8(key);
+ const qsizetype size = decoded.size();
+ result.reserve(result.size() + size);
+ qsizetype i = 0;
bool lowercaseOnly = true;
- int i = from;
- result.reserve(result.length() + (to - from));
- while (i < to) {
- char16_t ch = (uchar)key.at(i);
+ while (i < size) {
+ char16_t ch = decoded.at(i).unicode();
if (ch == '\\') {
- result += QLatin1Char('/');
+ result += u'/';
++i;
continue;
}
- if (ch != '%' || i == to - 1) {
- if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII
+ if (ch != '%' || i == size - 1) {
+ QChar qch(ch);
+ if (qch.isUpper())
lowercaseOnly = false;
- result += ch;
+ result += qch;
++i;
continue;
}
int numDigits = 2;
- int firstDigitPos = i + 1;
+ qsizetype firstDigitPos = i + 1;
- ch = key.at(i + 1);
+ ch = decoded.at(i + 1).unicode();
if (ch == 'U') {
++firstDigitPos;
numDigits = 4;
}
- if (firstDigitPos + numDigits > to) {
- result += QLatin1Char('%');
- // ### missing U
+ if (firstDigitPos + numDigits > size) {
+ result += u'%';
++i;
continue;
}
bool ok;
- ch = key.mid(firstDigitPos, numDigits).toUShort(&ok, 16);
+ ch = QStringView(decoded).sliced(firstDigitPos, numDigits).toUShort(&ok, 16);
if (!ok) {
- result += QLatin1Char('%');
- // ### missing U
+ result += u'%';
++i;
continue;
}
@@ -604,25 +593,20 @@ void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result)
{
bool needsQuotes = false;
bool escapeNextIfDigit = false;
- bool useCodec = !str.startsWith(QLatin1String("@ByteArray("))
- && !str.startsWith(QLatin1String("@Variant("));
-
- int i;
- int startPos = result.size();
+ const bool useCodec = !(str.startsWith("@ByteArray("_L1)
+ || str.startsWith("@Variant("_L1)
+ || str.startsWith("@DateTime("_L1));
+ const qsizetype startPos = result.size();
QStringEncoder toUtf8(QStringEncoder::Utf8);
result.reserve(startPos + str.size() * 3 / 2);
- const QChar *unicode = str.unicode();
- for (i = 0; i < str.size(); ++i) {
- uint ch = unicode[i].unicode();
+ for (QChar qch : str) {
+ uint ch = qch.unicode();
if (ch == ';' || ch == ',' || ch == '=')
needsQuotes = true;
- if (escapeNextIfDigit
- && ((ch >= '0' && ch <= '9')
- || (ch >= 'a' && ch <= 'f')
- || (ch >= 'A' && ch <= 'F'))) {
+ if (escapeNextIfDigit && isHexDigit(ch)) {
result += "\\x" + QByteArray::number(ch, 16);
continue;
}
@@ -666,7 +650,7 @@ void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result)
escapeNextIfDigit = true;
} else if (useCodec) {
// slow
- result += toUtf8(unicode[i]);
+ result += toUtf8(qch);
} else {
result += (char)ch;
}
@@ -681,11 +665,11 @@ void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result)
}
}
-inline static void iniChopTrailingSpaces(QString &str, int limit)
+inline static void iniChopTrailingSpaces(QString &str, qsizetype limit)
{
- int n = str.size() - 1;
+ qsizetype n = str.size() - 1;
QChar ch;
- while (n >= limit && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
+ while (n >= limit && ((ch = str.at(n)) == u' ' || ch == u'\t'))
str.truncate(n--);
}
@@ -702,7 +686,7 @@ void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray
*/
result += "@Invalid()";
} else {
- for (int i = 0; i < strs.size(); ++i) {
+ for (qsizetype i = 0; i < strs.size(); ++i) {
if (i != 0)
result += ", ";
iniEscapedString(strs.at(i), result);
@@ -710,7 +694,7 @@ void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray
}
}
-bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, int to,
+bool QSettingsPrivate::iniUnescapedStringList(QByteArrayView str,
QString &stringResult, QStringList &stringListResult)
{
static const char escapeCodes[][2] =
@@ -732,22 +716,22 @@ bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, i
bool inQuotedString = false;
bool currentValueIsQuoted = false;
char16_t escapeVal = 0;
- int i = from;
+ qsizetype i = 0;
char ch;
QStringDecoder fromUtf8(QStringDecoder::Utf8);
StSkipSpaces:
- while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
+ while (i < str.size() && ((ch = str.at(i)) == ' ' || ch == '\t'))
++i;
// fallthrough
StNormal:
- int chopLimit = stringResult.length();
- while (i < to) {
+ qsizetype chopLimit = stringResult.size();
+ while (i < str.size()) {
switch (str.at(i)) {
case '\\':
++i;
- if (i >= to)
+ if (i >= str.size())
goto end;
ch = str.at(i++);
@@ -761,17 +745,17 @@ StNormal:
if (ch == 'x') {
escapeVal = 0;
- if (i >= to)
+ if (i >= str.size())
goto end;
ch = str.at(i);
- if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
+ if (isHexDigit(ch))
goto StHexEscape;
- } else if (ch >= '0' && ch <= '7') {
- escapeVal = ch - '0';
+ } else if (const int o = fromOct(ch); o != -1) {
+ escapeVal = o;
goto StOctEscape;
} else if (ch == '\n' || ch == '\r') {
- if (i < to) {
+ if (i < str.size()) {
char ch2 = str.at(i);
// \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
@@ -780,7 +764,7 @@ StNormal:
} else {
// the character is skipped
}
- chopLimit = stringResult.length();
+ chopLimit = stringResult.size();
break;
case '"':
++i;
@@ -806,15 +790,15 @@ StNormal:
}
Q_FALLTHROUGH();
default: {
- int j = i + 1;
- while (j < to) {
+ qsizetype j = i + 1;
+ while (j < str.size()) {
ch = str.at(j);
if (ch == '\\' || ch == '"' || ch == ',')
break;
++j;
}
- stringResult += fromUtf8(QByteArrayView(str).first(j).sliced(i));
+ stringResult += fromUtf8(str.first(j).sliced(i));
i = j;
}
}
@@ -824,17 +808,15 @@ StNormal:
goto end;
StHexEscape:
- if (i >= to) {
+ if (i >= str.size()) {
stringResult += escapeVal;
goto end;
}
ch = str.at(i);
- if (ch >= 'a')
- ch -= 'a' - 'A';
- if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
+ if (const int h = fromHex(ch); h != -1) {
escapeVal <<= 4;
- escapeVal += strchr(hexDigits, ch) - hexDigits;
+ escapeVal += h;
++i;
goto StHexEscape;
} else {
@@ -843,15 +825,15 @@ StHexEscape:
}
StOctEscape:
- if (i >= to) {
+ if (i >= str.size()) {
stringResult += escapeVal;
goto end;
}
ch = str.at(i);
- if (ch >= '0' && ch <= '7') {
+ if (const int o = fromOct(ch); o != -1) {
escapeVal <<= 3;
- escapeVal += ch - '0';
+ escapeVal += o;
++i;
goto StOctEscape;
} else {
@@ -865,22 +847,22 @@ end:
return isStringList;
}
-QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
+QStringList QSettingsPrivate::splitArgs(const QString &s, qsizetype idx)
{
- int l = s.length();
+ qsizetype l = s.size();
Q_ASSERT(l > 0);
- Q_ASSERT(s.at(idx) == QLatin1Char('('));
- Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
+ Q_ASSERT(s.at(idx) == u'(');
+ Q_ASSERT(s.at(l - 1) == u')');
QStringList result;
QString item;
for (++idx; idx < l; ++idx) {
QChar c = s.at(idx);
- if (c == QLatin1Char(')')) {
+ if (c == u')') {
Q_ASSERT(idx == l - 1);
result.append(item);
- } else if (c == QLatin1Char(' ')) {
+ } else if (c == u' ') {
result.append(item);
item.clear();
} else {
@@ -896,20 +878,30 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
void QConfFileSettingsPrivate::initFormat()
{
- extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
+#if defined(Q_OS_WASM)
+ extension = (format == QSettings::NativeFormat || format == QSettings::WebIndexedDBFormat)
+ ? ".conf"_L1
+ : ".ini"_L1;
+#else
+ extension = (format == QSettings::NativeFormat) ? ".conf"_L1 : ".ini"_L1;
+#endif
readFunc = nullptr;
writeFunc = nullptr;
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
#else
caseSensitivity = IniCaseSensitivity;
#endif
+#if defined Q_OS_WASM
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
+#else
if (format > QSettings::IniFormat) {
+#endif
const auto locker = qt_scoped_lock(settingsGlobalMutex);
const CustomFormatVector *customFormatVector = customFormatVectorFunc();
- int i = (int)format - (int)QSettings::CustomFormat1;
+ qsizetype i = qsizetype(format) - qsizetype(QSettings::CustomFormat1);
if (i >= 0 && i < customFormatVector->size()) {
QConfFileCustomFormat info = customFormatVector->at(i);
extension = info.extension;
@@ -923,7 +915,11 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
if (!confFiles.isEmpty()) {
+#if defined Q_OS_WASM
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
+#else
if (format > QSettings::IniFormat) {
+#endif
if (!readFunc)
setStatus(QSettings::AccessError);
}
@@ -945,9 +941,9 @@ static QString windowsConfigPath(const KNOWNFOLDERID &type)
if (result.isEmpty()) {
if (type == FOLDERID_ProgramData) {
- result = QLatin1String("C:\\temp\\qt-common");
+ result = "C:\\temp\\qt-common"_L1;
} else if (type == FOLDERID_RoamingAppData) {
- result = QLatin1String("C:\\temp\\qt-user");
+ result = "C:\\temp\\qt-user"_L1;
}
}
@@ -961,26 +957,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
}
#ifndef Q_OS_WIN
-static QString make_user_path()
+static constexpr QChar sep = u'/';
+
+#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID)
+static QString make_user_path_without_qstandard_paths()
{
- static constexpr QChar sep = QLatin1Char('/');
-#ifndef QSETTINGS_USE_QSTANDARDPATHS
- // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
- // for some time now. Moving away from that would require migrating existing settings.
QByteArray env = qgetenv("XDG_CONFIG_HOME");
if (env.isEmpty()) {
- return QDir::homePath() + QLatin1String("/.config/");
+ return QDir::homePath() + "/.config/"_L1;
} else if (env.startsWith('/')) {
return QFile::decodeName(env) + sep;
- } else {
- return QDir::homePath() + sep + QFile::decodeName(env) + sep;
}
+
+ return QDir::homePath() + sep + QFile::decodeName(env) + sep;
+}
+#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID
+
+static QString make_user_path()
+{
+#ifndef QSETTINGS_USE_QSTANDARDPATHS
+ // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
+ // for some time now. Moving away from that would require migrating existing settings.
+ // The migration has already been done for Android.
+ return make_user_path_without_qstandard_paths();
#else
- // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
- // it makes the use of test mode from unit tests possible.
+
+#ifdef Q_OS_ANDROID
+ // If an old settings path exists, use it instead of creating a new one
+ QString ret = make_user_path_without_qstandard_paths();
+ if (QFile(ret).exists())
+ return ret;
+#endif // Q_OS_ANDROID
+
+ // When using a proper XDG platform or Android platform, use QStandardPaths rather than the
+ // above hand-written code. It makes the use of test mode from unit tests possible.
// Ideally all platforms should use this, but see above for the migration issue.
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
-#endif
+#endif // !QSETTINGS_USE_QSTANDARDPATHS
}
#endif // !Q_OS_WIN
@@ -995,7 +1008,7 @@ static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMut
avoid a dead-lock, we can't hold the global mutex while
calling it.
*/
- QString systemPath = QLibraryInfo::path(QLibraryInfo::SettingsPath) + QLatin1Char('/');
+ QString systemPath = QLibraryInfo::path(QLibraryInfo::SettingsPath) + u'/';
locker.lock();
if (pathHash->isEmpty()) {
@@ -1016,7 +1029,7 @@ static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMut
const QString userPath = make_user_path();
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
-#ifndef Q_OS_MAC
+#ifndef Q_OS_DARWIN
pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
#endif
@@ -1028,8 +1041,8 @@ static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMut
static Path getPath(QSettings::Format format, QSettings::Scope scope)
{
- Q_ASSERT((int)QSettings::NativeFormat == 0);
- Q_ASSERT((int)QSettings::IniFormat == 1);
+ Q_ASSERT(int(QSettings::NativeFormat) == 0);
+ Q_ASSERT(int(QSettings::IniFormat) == 1);
auto locker = qt_unique_lock(settingsGlobalMutex);
PathHash *pathHash = pathHashFunc();
@@ -1065,7 +1078,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QString org = organization;
if (org.isEmpty()) {
setStatus(QSettings::AccessError);
- org = QLatin1String("Unknown Organization");
+ org = "Unknown Organization"_L1;
}
QString appFile = org + QDir::separator() + application + extension;
@@ -1092,16 +1105,16 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QStringList paths;
if (!application.isEmpty()) {
paths.reserve(dirs.size() * 2);
- for (const auto &dir : qAsConst(dirs))
- paths.append(dir + QLatin1Char('/') + appFile);
+ for (const auto &dir : std::as_const(dirs))
+ paths.append(dir + u'/' + appFile);
} else {
paths.reserve(dirs.size());
}
- for (const auto &dir : qAsConst(dirs))
- paths.append(dir + QLatin1Char('/') + orgFile);
+ for (const auto &dir : std::as_const(dirs))
+ paths.append(dir + u'/' + orgFile);
// Note: No check for existence of files is done intentionally.
- for (const auto &path : qAsConst(paths))
+ for (const auto &path : std::as_const(paths))
confFiles.append(QConfFile::fromName(path, false));
} else
#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
@@ -1111,9 +1124,7 @@ 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,
@@ -1134,7 +1145,7 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- for (auto conf_file : qAsConst(confFiles)) {
+ for (auto conf_file : std::as_const(confFiles)) {
if (!conf_file->ref.deref()) {
if (conf_file->size == 0) {
delete conf_file;
@@ -1168,18 +1179,18 @@ void QConfFileSettingsPrivate::remove(const QString &key)
QConfFile *confFile = confFiles.at(0);
QSettingsKey theKey(key, caseSensitivity);
- QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
+ QSettingsKey prefix(key + u'/', caseSensitivity);
const auto locker = qt_scoped_lock(confFile->mutex);
ensureSectionParsed(confFile, theKey);
ensureSectionParsed(confFile, prefix);
- ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix);
+ auto i = confFile->addedKeys.lowerBound(prefix);
while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
i = confFile->addedKeys.erase(i);
confFile->addedKeys.remove(theKey);
- ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
+ auto j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
confFile->removedKeys.insert(j.key(), QVariant());
++j;
@@ -1208,7 +1219,7 @@ std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const
ParsedSettingsMap::const_iterator j;
bool found = false;
- for (auto confFile : qAsConst(confFiles)) {
+ for (auto confFile : std::as_const(confFiles)) {
const auto locker = qt_scoped_lock(confFile->mutex);
if (!confFile->addedKeys.isEmpty()) {
@@ -1233,12 +1244,11 @@ std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const
QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
{
QStringList result;
- ParsedSettingsMap::const_iterator j;
QSettingsKey thePrefix(prefix, caseSensitivity);
- int startPos = prefix.size();
+ qsizetype startPos = prefix.size();
- for (auto confFile : qAsConst(confFiles)) {
+ for (auto confFile : std::as_const(confFiles)) {
const auto locker = qt_scoped_lock(confFile->mutex);
if (thePrefix.isEmpty())
@@ -1246,18 +1256,18 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
else
ensureSectionParsed(confFile, thePrefix);
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->originalKeys)->lowerBound( thePrefix);
- while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
- if (!confFile->removedKeys.contains(j.key()))
- processChild(QStringView{j.key().originalCaseKey()}.mid(startPos), spec, result);
- ++j;
+ const auto &originalKeys = confFile->originalKeys;
+ auto i = originalKeys.lowerBound(thePrefix);
+ while (i != originalKeys.end() && i.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(i.key()))
+ processChild(QStringView{i.key().originalCaseKey()}.sliced(startPos), spec, result);
+ ++i;
}
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
- processChild(QStringView{j.key().originalCaseKey()}.mid(startPos), spec, result);
+ const auto &addedKeys = confFile->addedKeys;
+ auto j = addedKeys.lowerBound(thePrefix);
+ while (j != addedKeys.end() && j.key().startsWith(thePrefix)) {
+ processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
++j;
}
@@ -1289,7 +1299,7 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it
- for (auto confFile : qAsConst(confFiles)) {
+ for (auto confFile : std::as_const(confFiles)) {
const auto locker = qt_scoped_lock(confFile->mutex);
syncConfFile(confFile);
}
@@ -1311,7 +1321,11 @@ QString QConfFileSettingsPrivate::fileName() const
bool QConfFileSettingsPrivate::isWritable() const
{
+#if defined(Q_OS_WASM)
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat && !writeFunc)
+#else
if (format > QSettings::IniFormat && !writeFunc)
+#endif
return false;
if (confFiles.isEmpty())
@@ -1324,13 +1338,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
+ QFileInfo fileInfo(confFile->name);
/*
We can often optimize the read-only case, if the file on disk
hasn't changed.
*/
if (readOnly && confFile->size > 0) {
- QFileInfo fileInfo(confFile->name);
- if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
+ if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified(QTimeZone::UTC))
return;
}
@@ -1340,6 +1354,14 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
}
#ifndef QT_BOOTSTRAPPED
+ QString lockFileName = confFile->name + ".lock"_L1;
+
+# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS)
+ // On android and if it is a content URL put the lock file in a
+ // writable location to prevent permissions issues and invalid paths.
+ if (confFile->name.startsWith("content:"_L1))
+ lockFileName = make_user_path() + QFileInfo(lockFileName).fileName();
+# endif
/*
Use a lockfile in order to protect us against other QSettings instances
trying to write the same settings at the same time.
@@ -1347,7 +1369,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
We only need to lock if we are actually writing as only concurrent writes are a problem.
Concurrent read and write are not a problem because the writing operation is atomic.
*/
- QLockFile lockFile(confFile->name + QLatin1String(".lock"));
+ QLockFile lockFile(lockFileName);
if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
setStatus(QSettings::AccessError);
return;
@@ -1358,13 +1380,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
We hold the lock. Let's reread the file if it has changed
since last time we read it.
*/
- QFileInfo fileInfo(confFile->name);
+ fileInfo.refresh();
bool mustReadFile = true;
bool createFile = !fileInfo.exists();
if (!readOnly)
mustReadFile = (confFile->size != fileInfo.size()
- || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
+ || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified(QTimeZone::UTC)));
if (mustReadFile) {
confFile->unparsedIniSections.clear();
@@ -1382,7 +1404,14 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
*/
if (file.isReadable() && file.size() != 0) {
bool ok = false;
-#ifdef Q_OS_MAC
+
+#ifdef Q_OS_WASM
+ if (format == QSettings::WebIndexedDBFormat) {
+ QByteArray data = file.readAll();
+ ok = readIniFile(data, &confFile->unparsedIniSections);
+ } else
+#endif
+#ifdef Q_OS_DARWIN
if (format == QSettings::NativeFormat) {
QByteArray data = file.readAll();
ok = readPlistFile(data, &confFile->originalKeys);
@@ -1396,7 +1425,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
ok = readFunc(file, tempNewKeys);
if (ok) {
- QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin();
+ auto i = tempNewKeys.constBegin();
while (i != tempNewKeys.constEnd()) {
confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
i.value());
@@ -1410,7 +1439,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
}
confFile->size = fileInfo.size();
- confFile->timeStamp = fileInfo.lastModified();
+ confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
}
/*
@@ -1425,6 +1454,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
QSaveFile sf(confFile->name);
sf.setDirectWriteFallback(!atomicSyncOnly);
+# ifdef Q_OS_ANDROID
+ // QSaveFile requires direct write when using content scheme URL in Android
+ if (confFile->name.startsWith("content:"_L1))
+ sf.setDirectWriteFallback(true);
+# endif
#else
QFile sf(confFile->name);
#endif
@@ -1433,7 +1467,12 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
return;
}
-#ifdef Q_OS_MAC
+#ifdef Q_OS_WASM
+ if (format == QSettings::WebIndexedDBFormat) {
+ ok = writeIniFile(sf, mergedKeys);
+ } else
+#endif
+#ifdef Q_OS_DARWIN
if (format == QSettings::NativeFormat) {
ok = writePlistFile(sf, mergedKeys);
} else
@@ -1443,7 +1482,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
} else if (writeFunc) {
QSettings::SettingsMap tempOriginalKeys;
- ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
+ auto i = mergedKeys.constBegin();
while (i != mergedKeys.constEnd()) {
tempOriginalKeys.insert(i.key(), i.value());
++i;
@@ -1462,9 +1501,9 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
confFile->addedKeys.clear();
confFile->removedKeys.clear();
- QFileInfo fileInfo(confFile->name);
+ fileInfo.refresh();
confFile->size = fileInfo.size();
- confFile->timeStamp = fileInfo.lastModified();
+ confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
// If we have created the file, apply the file perms
if (createFile) {
@@ -1479,6 +1518,8 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
}
}
+namespace SettingsImpl {
+
enum { Space = 0x1, Special = 0x2 };
static const char charTraits[256] =
@@ -1505,10 +1546,16 @@ static const char charTraits[256] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos,
- int &lineStart, int &lineLen, int &equalsPos)
+} // namespace SettingsImpl
+
+using SettingsImpl::charTraits;
+
+bool QConfFileSettingsPrivate::readIniLine(QByteArrayView data, qsizetype &dataPos,
+ qsizetype &lineStart, qsizetype &lineLen,
+ qsizetype &equalsPos)
{
- int dataLen = data.length();
+ using namespace SettingsImpl;
+ qsizetype dataLen = data.size();
bool inQuotes = false;
equalsPos = -1;
@@ -1517,7 +1564,7 @@ bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos,
while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
++lineStart;
- int i = lineStart;
+ qsizetype i = lineStart;
while (i < dataLen) {
char ch = data.at(i);
while (!(charTraits[uchar(ch)] & Special)) {
@@ -1576,7 +1623,7 @@ break_out_of_outer_loop:
possible, so if the user doesn't check the status he will get the
most out of the file anyway.
*/
-bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
+bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data,
UnparsedSettingsMap *unparsedIniSections)
{
#define FLUSH_CURRENT_SECTION() \
@@ -1586,59 +1633,56 @@ bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
sectionPosition)]; \
if (!sectionData.isEmpty()) \
sectionData.append('\n'); \
- sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \
+ sectionData += data.first(lineStart).sliced(currentSectionStart); \
sectionPosition = ++position; \
}
QString currentSection;
- int currentSectionStart = 0;
- int dataPos = 0;
- int lineStart;
- int lineLen;
- int equalsPos;
- int position = 0;
- int sectionPosition = 0;
+ qsizetype currentSectionStart = 0;
+ qsizetype dataPos = 0;
+ qsizetype lineStart;
+ qsizetype lineLen;
+ qsizetype equalsPos;
+ qsizetype position = 0;
+ qsizetype sectionPosition = 0;
bool ok = true;
- // skip potential utf8 BOM
- const uchar *dd = (const uchar *)data.constData();
- if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf)
- dataPos = 3;
+ // Skip possible UTF-8 BOM:
+ if (data.startsWith("\xef\xbb\xbf"))
+ data = data.sliced(3);
while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
- char ch = data.at(lineStart);
- if (ch == '[') {
+ QByteArrayView line = data.sliced(lineStart, lineLen);
+ if (line.startsWith('[')) {
FLUSH_CURRENT_SECTION();
- // this is a section
- QByteArray iniSection;
- int idx = data.indexOf(']', lineStart);
- if (idx == -1 || idx >= lineStart + lineLen) {
+ // This starts a new section.
+ qsizetype idx = line.indexOf(']');
+ Q_ASSERT(idx == -1 || idx > 0); // line[0] is '[', not ']'.
+ Q_ASSERT(idx < lineLen); // (including -1 < lineLen, if no ']' present.)
+ if (idx < 0) {
ok = false;
- iniSection = data.mid(lineStart + 1, lineLen - 1);
- } else {
- iniSection = data.mid(lineStart + 1, idx - lineStart - 1);
+ idx = lineLen; // so line.first(idx) is just line
}
-
- iniSection = iniSection.trimmed();
+ QByteArrayView iniSection = line.first(idx).sliced(1).trimmed();
if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
currentSection.clear();
} else {
if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
- currentSection = QLatin1String(iniSection.constData() + 1);
+ currentSection = QLatin1StringView(iniSection.constData() + 1, iniSection.size() - 1);
} else {
currentSection.clear();
- iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection);
+ iniUnescapedKey(iniSection, currentSection);
}
- currentSection += QLatin1Char('/');
+ currentSection += u'/';
}
currentSectionStart = dataPos;
}
++position;
}
- Q_ASSERT(lineStart == data.length());
+ Q_ASSERT(lineStart == data.size());
FLUSH_CURRENT_SECTION();
return ok;
@@ -1646,57 +1690,53 @@ bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
#undef FLUSH_CURRENT_SECTION
}
-bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, const QByteArray &data,
+bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, QByteArrayView data,
ParsedSettingsMap *settingsMap)
{
QStringList strListValue;
bool sectionIsLowercase = (section == section.originalCaseKey());
- int equalsPos;
+ qsizetype equalsPos;
bool ok = true;
- int dataPos = 0;
- int lineStart;
- int lineLen;
- int position = section.originalKeyPosition();
+ qsizetype dataPos = 0;
+ qsizetype lineStart;
+ qsizetype lineLen;
+ qsizetype position = section.originalKeyPosition();
while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
- char ch = data.at(lineStart);
- Q_ASSERT(ch != '[');
+ QByteArrayView line = data.sliced(lineStart, lineLen);
+ Q_ASSERT(!line.startsWith('['));
if (equalsPos == -1) {
- if (ch != ';')
+ if (!line.startsWith(';'))
ok = false;
continue;
}
+ // Shift equalPos indexing to be within line, rather than data:
+ equalsPos -= lineStart;
+ // Assured by readIniLine:
+ Q_ASSERT(equalsPos >= 0 && equalsPos < lineLen);
- int keyEnd = equalsPos;
- while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t'))
- --keyEnd;
- int valueStart = equalsPos + 1;
+ QByteArrayView key = line.first(equalsPos).trimmed();
+ QByteArrayView value = line.sliced(equalsPos + 1);
- QString key = section.originalCaseKey();
- bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase);
+ QString strKey = section.originalCaseKey();
+ const Qt::CaseSensitivity casing = iniUnescapedKey(key, strKey) && sectionIsLowercase
+ ? Qt::CaseSensitive
+ : IniCaseSensitivity;
QString strValue;
- strValue.reserve(lineLen - (valueStart - lineStart));
- bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen,
- strValue, strListValue);
- QVariant variant;
- if (isStringList) {
- variant = stringListToVariantList(strListValue);
- } else {
- variant = stringToVariant(strValue);
- }
+ strValue.reserve(value.size());
+ QVariant variant = iniUnescapedStringList(value, strValue, strListValue)
+ ? stringListToVariantList(strListValue)
+ : stringToVariant(strValue);
/*
We try to avoid the expensive toLower() call in
QSettingsKey by passing Qt::CaseSensitive when the
key is already in lowercase.
*/
- settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
- : IniCaseSensitivity,
- position),
- variant);
+ settingsMap->insert(QSettingsKey(strKey, casing, position), std::move(variant));
++position;
}
@@ -1707,9 +1747,9 @@ class QSettingsIniKey : public QString
{
public:
inline QSettingsIniKey() : position(-1) {}
- inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
+ inline QSettingsIniKey(const QString &str, qsizetype pos = -1) : QString(str), position(pos) {}
- int position;
+ qsizetype position;
};
Q_DECLARE_TYPEINFO(QSettingsIniKey, Q_RELOCATABLE_TYPE);
@@ -1724,7 +1764,7 @@ typedef QMap<QSettingsIniKey, QVariant> IniKeyMap;
struct QSettingsIniSection
{
- int position;
+ qsizetype position;
IniKeyMap keyMap;
inline QSettingsIniSection() : position(-1) {}
@@ -1741,7 +1781,6 @@ typedef QMap<QString, QSettingsIniSection> IniMap;
bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
{
IniMap iniMap;
- IniMap::const_iterator i;
#ifdef Q_OS_WIN
const char * const eol = "\r\n";
@@ -1749,12 +1788,12 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti
const char eol = '\n';
#endif
- for (ParsedSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) {
+ for (auto j = map.constBegin(); j != map.constEnd(); ++j) {
QString section;
QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
- int slashPos;
+ qsizetype slashPos;
- if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) {
+ if ((slashPos = key.indexOf(u'/')) != -1) {
section = key.left(slashPos);
key.remove(0, slashPos + 1);
}
@@ -1762,21 +1801,21 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti
QSettingsIniSection &iniSection = iniMap[section];
// -1 means infinity
- if (uint(key.position) < uint(iniSection.position))
+ if (size_t(key.position) < size_t(iniSection.position))
iniSection.position = key.position;
iniSection.keyMap[key] = j.value();
}
- const int sectionCount = iniMap.size();
+ const qsizetype sectionCount = iniMap.size();
QList<QSettingsIniKey> sections;
sections.reserve(sectionCount);
- for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
+ for (auto i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
sections.append(QSettingsIniKey(i.key(), i.value().position));
std::sort(sections.begin(), sections.end());
bool writeError = false;
- for (int j = 0; !writeError && j < sectionCount; ++j) {
- i = iniMap.constFind(sections.at(j));
+ for (qsizetype j = 0; !writeError && j < sectionCount; ++j) {
+ auto i = iniMap.constFind(sections.at(j));
Q_ASSERT(i != iniMap.constEnd());
QByteArray realSection;
@@ -1799,7 +1838,7 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti
device.write(realSection);
const IniKeyMap &ents = i.value().keyMap;
- for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) {
+ for (auto j = ents.constBegin(); j != ents.constEnd(); ++j) {
QByteArray block;
iniEscapedKey(j.key(), block);
block += '=';
@@ -1829,8 +1868,8 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti
void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
{
- UnparsedSettingsMap::const_iterator i = confFile->unparsedIniSections.constBegin();
- const UnparsedSettingsMap::const_iterator end = confFile->unparsedIniSections.constEnd();
+ auto i = confFile->unparsedIniSections.constBegin();
+ const auto end = confFile->unparsedIniSections.constEnd();
for (; i != end; ++i) {
if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
@@ -1847,7 +1886,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
UnparsedSettingsMap::iterator i;
- int indexOfSlash = key.indexOf(QLatin1Char('/'));
+ qsizetype indexOfSlash = key.indexOf(u'/');
if (indexOfSlash != -1) {
i = confFile->unparsedIniSections.upperBound(key);
if (i == confFile->unparsedIniSections.begin())
@@ -2084,12 +2123,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\snippet settings/settings.cpp 15
- Note that type information is not preserved when reading settings from INI
- files; all values will be returned as QString.
-
- The \l{tools/settingseditor}{Settings Editor} example lets you
- experiment with different settings location and with fallbacks
- turned on or off.
+ Note that INI files lose the distinction between numeric data and the
+ strings used to encode them, so values written as numbers shall be read back
+ as QString. The numeric value can be recovered using \l QString::toInt(), \l
+ QString::toDouble() and related functions.
\section1 Restoring the State of a GUI Application
@@ -2116,9 +2153,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\codeline
\snippet settings/settings.cpp 21
- See the \l{mainwindows/application}{Application} example for a
- self-contained example that uses QSettings.
-
\section1 Accessing Settings from Multiple Threads or Processes Simultaneously
QSettings is \l{reentrant}. This means that you can use
@@ -2160,8 +2194,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
following files are used by default:
\list 1
- \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
- \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
+ \li \c{$HOME/.config/MySoft/Star Runner.conf}
+ \li \c{$HOME/.config/MySoft.conf}
\li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
\li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
\endlist
@@ -2198,8 +2232,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
used on Unix, \macos, and iOS:
\list 1
- \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
- \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
+ \li \c{$HOME/.config/MySoft/Star Runner.ini}
+ \li \c{$HOME/.config/MySoft.ini}
\li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
\li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
\endlist
@@ -2334,7 +2368,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\endlist
- \sa QVariant, QSessionManager, {Settings Editor Example}, {Qt Widgets - Application Example}
+ \sa QVariant, QSessionManager
*/
/*! \enum QSettings::Status
@@ -2368,9 +2402,20 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
On 32-bit Windows or from a 64-bit application on 64-bit Windows,
this works the same as specifying NativeFormat.
This enum value was added in Qt 5.7.
- \value IniFormat Store the settings in INI files. Note that type information
- is not preserved when reading settings from INI files;
- all values will be returned as QString.
+ \value IniFormat Store the settings in INI files. Note that INI files
+ lose the distinction between numeric data and the
+ strings used to encode them, so values written as
+ numbers shall be read back as QString.
+ \value WebLocalStorageFormat
+ WASM only: Store the settings in window.localStorage for the current
+ origin. If cookies are not allowed, this falls back to the INI format.
+ This provides up to 5MiB storage per origin, but access to it is
+ synchronous and JSPI is not required.
+ \value WebIndexedDBFormat
+ WASM only: Store the settings in an Indexed DB for the current
+ origin. If cookies are not allowed, this falls back to the INI format.
+ This requires JSPI, but provides more storage than
+ WebLocalStorageFormat.
\value InvalidFormat Special value returned by registerFormat().
\omitvalue CustomFormat1
@@ -2428,16 +2473,19 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
such as "General/someKey", the key will be located in the
"%General" section, \e not in the "General" section.
- \li In line with most implementations today, QSettings will
- assume the INI file is utf-8 encoded. This means that keys and values
+ \li In line with most implementations today, QSettings will assume that
+ \e values in the INI file are utf-8 encoded. This means that \e values
will be decoded as utf-8 encoded entries and written back as utf-8.
+ To retain backward compatibility with older Qt versions, \e keys in the
+ INI file are written in %-encoded format, but can be read in both
+ %-encoded and utf-8 formats.
\endlist
\section2 Compatibility with older Qt versions
Please note that this behavior is different to how QSettings behaved
- in versions of Qt prior to Qt 6. INI files written with Qt 5 or earlier aree
+ in versions of Qt prior to Qt 6. INI files written with Qt 5 or earlier are
however fully readable by a Qt 6 based application (unless a ini codec
different from utf8 had been set). But INI files written with Qt 6
will only be readable by older Qt versions if you set the "iniCodec" to
@@ -2686,10 +2734,11 @@ QSettings::~QSettings()
{
Q_D(QSettings);
if (d->pendingChanges) {
+ // Don't cause a failing flush() to std::terminate() the whole
+ // application - dtors are implicitly noexcept!
QT_TRY {
d->flush();
} QT_CATCH(...) {
- ; // ok. then don't flush but at least don't throw in the destructor
}
}
}
@@ -2881,9 +2930,12 @@ void QSettings::setAtomicSyncRequired(bool enable)
Call endGroup() to reset the current group to what it was before
the corresponding beginGroup() call. Groups can be nested.
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa endGroup(), group()
*/
-void QSettings::beginGroup(const QString &prefix)
+void QSettings::beginGroup(QAnyStringView prefix)
{
Q_D(QSettings);
d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
@@ -2908,7 +2960,7 @@ void QSettings::endGroup()
}
QSettingsGroup group = d->groupStack.pop();
- int len = group.toString().size();
+ qsizetype len = group.toString().size();
if (len > 0)
d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
@@ -2937,13 +2989,16 @@ QString QSettings::group() const
Use beginWriteArray() to write the array in the first place.
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa beginWriteArray(), endArray(), setArrayIndex()
*/
-int QSettings::beginReadArray(const QString &prefix)
+int QSettings::beginReadArray(QAnyStringView prefix)
{
Q_D(QSettings);
d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
- return value(QLatin1String("size")).toInt();
+ return value("size"_L1).toInt();
}
/*!
@@ -2973,17 +3028,20 @@ int QSettings::beginReadArray(const QString &prefix)
To read back an array, use beginReadArray().
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa beginReadArray(), endArray(), setArrayIndex()
*/
-void QSettings::beginWriteArray(const QString &prefix, int size)
+void QSettings::beginWriteArray(QAnyStringView prefix, int size)
{
Q_D(QSettings);
d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
if (size < 0)
- remove(QLatin1String("size"));
+ remove("size"_L1);
else
- setValue(QLatin1String("size"), size);
+ setValue("size"_L1, size);
}
/*!
@@ -3001,13 +3059,13 @@ void QSettings::endArray()
}
QSettingsGroup group = d->groupStack.top();
- int len = group.toString().size();
+ qsizetype len = group.toString().size();
d->groupStack.pop();
if (len > 0)
d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
if (group.arraySizeGuess() != -1)
- setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
+ setValue(group.name() + "/size"_L1, group.arraySizeGuess());
if (!group.isArray())
qWarning("QSettings::endArray: Expected endGroup() instead");
@@ -3030,7 +3088,7 @@ void QSettings::setArrayIndex(int i)
}
QSettingsGroup &top = d->groupStack.top();
- int len = top.toString().size();
+ qsizetype len = top.toString().size();
top.setArrayIndex(qMax(i, 0));
d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
}
@@ -3136,9 +3194,12 @@ bool QSettings::isWritable() const
\snippet code/src_corelib_io_qsettings.cpp 23
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa value(), remove(), contains()
*/
-void QSettings::setValue(const QString &key, const QVariant &value)
+void QSettings::setValue(QAnyStringView key, const QVariant &value)
{
Q_D(QSettings);
if (key.isEmpty()) {
@@ -3170,9 +3231,12 @@ void QSettings::setValue(const QString &key, const QVariant &value)
case-sensitive keys. To avoid portability problems, see the
\l{Section and Key Syntax} rules.
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa setValue(), value(), contains()
*/
-void QSettings::remove(const QString &key)
+void QSettings::remove(QAnyStringView key)
{
Q_D(QSettings);
/*
@@ -3205,9 +3269,12 @@ void QSettings::remove(const QString &key)
case-sensitive keys. To avoid portability problems, see the
\l{Section and Key Syntax} rules.
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa value(), setValue()
*/
-bool QSettings::contains(const QString &key) const
+bool QSettings::contains(QAnyStringView key) const
{
Q_D(const QSettings);
return d->get(d->actualKey(key)) != std::nullopt;
@@ -3255,6 +3322,9 @@ bool QSettings::event(QEvent *event)
#endif
/*!
+ \fn QSettings::value(QAnyStringView key) const
+ \fn QSettings::value(QAnyStringView key, const QVariant &defaultValue) const
+
Returns the value for setting \a key. If the setting doesn't
exist, returns \a defaultValue.
@@ -3270,16 +3340,34 @@ bool QSettings::event(QEvent *event)
\snippet code/src_corelib_io_qsettings.cpp 26
+ \note In Qt versions prior to 6.4, this function took QString, not
+ QAnyStringView.
+
\sa setValue(), contains(), remove()
*/
-QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
+QVariant QSettings::value(QAnyStringView key) const
{
Q_D(const QSettings);
+ return d->value(key, nullptr);
+}
+
+QVariant QSettings::value(QAnyStringView key, const QVariant &defaultValue) const
+{
+ Q_D(const QSettings);
+ return d->value(key, &defaultValue);
+}
+
+QVariant QSettingsPrivate::value(QAnyStringView key, const QVariant *defaultValue) const
+{
if (key.isEmpty()) {
qWarning("QSettings::value: Empty key passed");
return QVariant();
}
- return d->get(d->actualKey(key)).value_or(defaultValue);
+ if (std::optional r = get(actualKey(key)))
+ return std::move(*r);
+ if (defaultValue)
+ return *defaultValue;
+ return QVariant();
}
/*!
@@ -3326,8 +3414,6 @@ QSettings::Format QSettings::defaultFormat()
\row \li SystemScope \li \c FOLDERID_ProgramData
\row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config
\row \li SystemScope \li \c /etc/xdg
- \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings
- \row \li SystemScope \li \c /etc/xdg
\row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config
\row \li SystemScope \li \c /etc/xdg
\endtable
@@ -3433,18 +3519,18 @@ QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc r
const auto locker = qt_scoped_lock(settingsGlobalMutex);
CustomFormatVector *customFormatVector = customFormatVectorFunc();
- int index = customFormatVector->size();
+ qsizetype index = customFormatVector->size();
if (index == 16) // the QSettings::Format enum has room for 16 custom formats
return QSettings::InvalidFormat;
QConfFileCustomFormat info;
- info.extension = QLatin1Char('.') + extension;
+ info.extension = u'.' + extension;
info.readFunc = readFunc;
info.writeFunc = writeFunc;
info.caseSensitivity = caseSensitivity;
customFormatVector->append(info);
- return QSettings::Format((int)QSettings::CustomFormat1 + index);
+ return QSettings::Format(int(QSettings::CustomFormat1) + index);
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index 05b30b562b..8bc73eb016 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSETTINGS_H
#define QSETTINGS_H
@@ -82,12 +46,17 @@ public:
#endif
enum Format {
- NativeFormat,
- IniFormat,
+ NativeFormat = 0,
+ IniFormat = 1,
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
- Registry32Format,
- Registry64Format,
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+ Registry32Format = 2,
+ Registry64Format = 3,
+#endif
+
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+ WebLocalStorageFormat = 4,
+ WebIndexedDBFormat = 5,
#endif
InvalidFormat = 16,
@@ -148,12 +117,19 @@ public:
bool isAtomicSyncRequired() const;
void setAtomicSyncRequired(bool enable);
+#if QT_CORE_REMOVED_SINCE(6, 4)
void beginGroup(const QString &prefix);
+#endif
+ void beginGroup(QAnyStringView prefix);
void endGroup();
QString group() const;
+#if QT_CORE_REMOVED_SINCE(6, 4)
int beginReadArray(const QString &prefix);
void beginWriteArray(const QString &prefix, int size = -1);
+#endif
+ int beginReadArray(QAnyStringView prefix);
+ void beginWriteArray(QAnyStringView prefix, int size = -1);
void endArray();
void setArrayIndex(int i);
@@ -162,11 +138,21 @@ public:
QStringList childGroups() const;
bool isWritable() const;
+#if QT_CORE_REMOVED_SINCE(6, 4)
void setValue(const QString &key, const QVariant &value);
- QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+ QVariant value(const QString &key, const QVariant &defaultValue) const;
+ QVariant value(const QString &key) const;
+#endif
+ void setValue(QAnyStringView key, const QVariant &value);
+ QVariant value(QAnyStringView key, const QVariant &defaultValue) const;
+ QVariant value(QAnyStringView key) const;
+#if QT_CORE_REMOVED_SINCE(6, 4)
void remove(const QString &key);
bool contains(const QString &key) const;
+#endif
+ void remove(QAnyStringView key);
+ bool contains(QAnyStringView key) const;
void setFallbacksEnabled(bool b);
bool fallbacksEnabled() const;
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index 59f0015b63..144ed59dc2 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsettings.h"
@@ -50,6 +14,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const CFStringRef hostNames[2] = { kCFPreferencesCurrentHost, kCFPreferencesAnyHost };
static const int numHostNames = 2;
@@ -291,18 +257,16 @@ static QString comify(const QString &organization)
{
for (int i = organization.size() - 1; i >= 0; --i) {
QChar ch = organization.at(i);
- if (ch == QLatin1Char('.') || ch == QChar(0x3002) || ch == QChar(0xff0e)
+ if (ch == u'.' || ch == QChar(0x3002) || ch == QChar(0xff0e)
|| ch == QChar(0xff61)) {
QString suffix = organization.mid(i + 1).toLower();
- if (suffix.size() == 2 || suffix == QLatin1String("com")
- || suffix == QLatin1String("org") || suffix == QLatin1String("net")
- || suffix == QLatin1String("edu") || suffix == QLatin1String("gov")
- || suffix == QLatin1String("mil") || suffix == QLatin1String("biz")
- || suffix == QLatin1String("info") || suffix == QLatin1String("name")
- || suffix == QLatin1String("pro") || suffix == QLatin1String("aero")
- || suffix == QLatin1String("coop") || suffix == QLatin1String("museum")) {
+ if (suffix.size() == 2 || suffix == "com"_L1 || suffix == "org"_L1
+ || suffix == "net"_L1 || suffix == "edu"_L1 || suffix == "gov"_L1
+ || suffix == "mil"_L1 || suffix == "biz"_L1 || suffix == "info"_L1
+ || suffix == "name"_L1 || suffix == "pro"_L1 || suffix == "aero"_L1
+ || suffix == "coop"_L1 || suffix == "museum"_L1) {
QString result = organization;
- result.replace(QLatin1Char('/'), QLatin1Char(' '));
+ result.replace(u'/', u' ');
return result;
}
break;
@@ -321,13 +285,13 @@ static QString comify(const QString &organization)
} else if (uc >= 'A' && uc <= 'Z') {
domain += ch.toLower();
} else {
- domain += QLatin1Char(' ');
+ domain += u' ';
}
}
domain = domain.simplified();
- domain.replace(QLatin1Char(' '), QLatin1Char('-'));
+ domain.replace(u' ', u'-');
if (!domain.isEmpty())
- domain.append(QLatin1String(".com"));
+ domain.append(".com"_L1);
return domain;
}
@@ -380,35 +344,34 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
if (main_bundle_identifier != NULL) {
QString bundle_identifier(qtKey(main_bundle_identifier));
// CFBundleGetIdentifier returns identifier separated by slashes rather than periods.
- QStringList bundle_identifier_components = bundle_identifier.split(QLatin1Char('/'));
+ QStringList bundle_identifier_components = bundle_identifier.split(u'/');
// pre-reverse them so that when they get reversed again below, they are in the com.company.product format.
QStringList bundle_identifier_components_reversed;
for (int i=0; i<bundle_identifier_components.size(); ++i) {
const QString &bundle_identifier_component = bundle_identifier_components.at(i);
bundle_identifier_components_reversed.push_front(bundle_identifier_component);
}
- domainName = bundle_identifier_components_reversed.join(QLatin1Char('.'));
+ domainName = bundle_identifier_components_reversed.join(u'.');
}
}
}
// if no bundle identifier yet. use a hard coded string.
- if (domainName.isEmpty()) {
- domainName = QLatin1String("unknown-organization.trolltech.com");
- }
+ if (domainName.isEmpty())
+ domainName = "unknown-organization.trolltech.com"_L1;
- while ((nextDot = domainName.indexOf(QLatin1Char('.'), curPos)) != -1) {
+ while ((nextDot = domainName.indexOf(u'.', curPos)) != -1) {
javaPackageName.prepend(QStringView{domainName}.mid(curPos, nextDot - curPos));
- javaPackageName.prepend(QLatin1Char('.'));
+ javaPackageName.prepend(u'.');
curPos = nextDot + 1;
}
javaPackageName.prepend(QStringView{domainName}.mid(curPos));
javaPackageName = std::move(javaPackageName).toLower();
if (curPos == 0)
- javaPackageName.prepend(QLatin1String("com."));
+ javaPackageName.prepend("com."_L1);
suiteId = javaPackageName;
if (!application.isEmpty()) {
- javaPackageName += QLatin1Char('.') + application;
+ javaPackageName += u'.' + application;
applicationId = javaPackageName;
}
@@ -436,13 +399,13 @@ QMacSettingsPrivate::~QMacSettingsPrivate()
void QMacSettingsPrivate::remove(const QString &key)
{
- QStringList keys = children(key + QLatin1Char('/'), AllKeys);
+ QStringList keys = children(key + u'/', AllKeys);
// If i == -1, then delete "key" itself.
for (int i = -1; i < keys.size(); ++i) {
QString subKey = key;
if (i >= 0) {
- subKey += QLatin1Char('/');
+ subKey += u'/';
subKey += keys.at(i);
}
CFPreferencesSetValue(macKey(subKey), 0, domains[0].applicationOrSuiteId,
@@ -534,7 +497,7 @@ void QMacSettingsPrivate::flush()
bool QMacSettingsPrivate::isWritable() const
{
QMacSettingsPrivate *that = const_cast<QMacSettingsPrivate *>(this);
- QString impossibleKey(QLatin1String("qt_internal/"));
+ QString impossibleKey("qt_internal/"_L1);
QSettings::Status oldStatus = that->status;
that->status = QSettings::NoError;
@@ -554,9 +517,9 @@ QString QMacSettingsPrivate::fileName() const
QString result;
if (scope == QSettings::UserScope)
result = QDir::homePath();
- result += QLatin1String("/Library/Preferences/");
+ result += "/Library/Preferences/"_L1;
result += QString::fromCFString(domains[0].applicationOrSuiteId);
- result += QLatin1String(".plist");
+ result += ".plist"_L1;
return result;
}
@@ -566,7 +529,7 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format,
const QString &application)
{
#ifndef QT_BOOTSTRAPPED
- if (organization == QLatin1String("Qt"))
+ if (organization == "Qt"_L1)
{
QString organizationDomain = QCoreApplication::organizationDomain();
QString applicationName = QCoreApplication::applicationName();
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index ddcbe0f76c..4229abd874 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSETTINGS_P_H
#define QSETTINGS_P_H
@@ -80,11 +44,11 @@ static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseSensitive;
class QSettingsKey : public QString
{
public:
- inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int /* position */ = -1)
+ inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, qsizetype /* position */ = -1)
: QString(key) { Q_ASSERT(cs == Qt::CaseSensitive); Q_UNUSED(cs); }
inline QString originalCaseKey() const { return *this; }
- inline int originalKeyPosition() const { return -1; }
+ inline qsizetype originalKeyPosition() const { return -1; }
};
#else
static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseInsensitive;
@@ -92,7 +56,7 @@ static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseInsensitive;
class QSettingsKey : public QString
{
public:
- inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int position = -1)
+ inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, qsizetype position = -1)
: QString(key), theOriginalKey(key), theOriginalKeyPosition(position)
{
if (cs == Qt::CaseInsensitive)
@@ -100,11 +64,11 @@ public:
}
inline QString originalCaseKey() const { return theOriginalKey; }
- inline int originalKeyPosition() const { return theOriginalKeyPosition; }
+ inline qsizetype originalKeyPosition() const { return theOriginalKeyPosition; }
private:
QString theOriginalKey;
- int theOriginalKeyPosition;
+ qsizetype theOriginalKeyPosition;
};
#endif
@@ -126,13 +90,13 @@ public:
inline QString name() const { return str; }
inline QString toString() const;
inline bool isArray() const { return num != -1; }
- inline int arraySizeGuess() const { return maxNum; }
- inline void setArrayIndex(int i)
+ inline qsizetype arraySizeGuess() const { return maxNum; }
+ inline void setArrayIndex(qsizetype i)
{ num = i + 1; if (maxNum != -1 && num > maxNum) maxNum = num; }
QString str;
- int num;
- int maxNum;
+ qsizetype num;
+ qsizetype maxNum;
};
Q_DECLARE_TYPEINFO(QSettingsGroup, Q_RELOCATABLE_TYPE);
@@ -141,13 +105,13 @@ inline QString QSettingsGroup::toString() const
QString result;
result = str;
if (num > 0) {
- result += QLatin1Char('/');
+ result += u'/';
result += QString::number(num);
}
return result;
}
-class Q_AUTOTEST_EXPORT QConfFile
+class QConfFile
{
public:
~QConfFile();
@@ -156,6 +120,7 @@ public:
bool isWritable() const;
static QConfFile *fromName(const QString &name, bool _userPerms);
+ Q_AUTOTEST_EXPORT
static void clearCache();
QString name;
@@ -208,13 +173,14 @@ public:
virtual bool isWritable() const = 0;
virtual QString fileName() const = 0;
- QString actualKey(const QString &key) const;
+ QVariant value(QAnyStringView key, const QVariant *defaultValue) const;
+ QString actualKey(QAnyStringView key) const;
void beginGroupOrArray(const QSettingsGroup &group);
void setStatus(QSettings::Status status) const;
void requestUpdate();
void update();
- static QString normalizedKey(const QString &key);
+ static QString normalizedKey(QAnyStringView key);
static QSettingsPrivate *create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application);
static QSettingsPrivate *create(const QString &fileName, QSettings::Format format);
@@ -229,12 +195,12 @@ public:
static QString variantToString(const QVariant &v);
static QVariant stringToVariant(const QString &s);
static void iniEscapedKey(const QString &key, QByteArray &result);
- static bool iniUnescapedKey(const QByteArray &key, int from, int to, QString &result);
+ static bool iniUnescapedKey(QByteArrayView key, QString &result);
static void iniEscapedString(const QString &str, QByteArray &result);
static void iniEscapedStringList(const QStringList &strs, QByteArray &result);
- static bool iniUnescapedStringList(const QByteArray &str, int from, int to,
- QString &stringResult, QStringList &stringListResult);
- static QStringList splitArgs(const QString &s, int idx);
+ static bool iniUnescapedStringList(QByteArrayView str, QString &stringResult,
+ QStringList &stringListResult);
+ static QStringList splitArgs(const QString &s, qsizetype idx);
QSettings::Format format;
QSettings::Scope scope;
@@ -250,10 +216,6 @@ protected:
mutable QSettings::Status status;
};
-#ifdef Q_OS_WASM
-class QWasmSettingsPrivate;
-#endif
-
class QConfFileSettingsPrivate : public QSettingsPrivate
{
public:
@@ -274,18 +236,22 @@ public:
bool isWritable() const override;
QString fileName() const override;
- bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections);
- static bool readIniSection(const QSettingsKey &section, const QByteArray &data,
+ bool readIniFile(QByteArrayView data, UnparsedSettingsMap *unparsedIniSections);
+ static bool readIniSection(const QSettingsKey &section, QByteArrayView data,
ParsedSettingsMap *settingsMap);
- static bool readIniLine(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen,
- int &equalsPos);
+ static bool readIniLine(QByteArrayView data, qsizetype &dataPos,
+ qsizetype &lineStart, qsizetype &lineLen,
+ qsizetype &equalsPos);
+
+protected:
+ const QList<QConfFile *> &getConfFiles() const { return confFiles; }
private:
void initFormat();
virtual void initAccess();
void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
bool writePlistFile(QIODevice &file, const ParsedSettingsMap &map) const;
#endif
@@ -297,9 +263,9 @@ private:
QSettings::WriteFunc writeFunc;
QString extension;
Qt::CaseSensitivity caseSensitivity;
- int nextPosition;
+ qsizetype nextPosition;
#ifdef Q_OS_WASM
- friend class QWasmSettingsPrivate;
+ friend class QWasmIDBSettingsPrivate;
#endif
};
diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp
index 9e016aa4f4..7d80ff82d3 100644
--- a/src/corelib/io/qsettings_wasm.cpp
+++ b/src/corelib/io/qsettings_wasm.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsettings.h"
#ifndef QT_NO_SETTINGS
@@ -46,213 +10,393 @@
#include <QFile>
#endif // QT_NO_QOBJECT
#include <QDebug>
+#include <QtCore/private/qstdweb_p.h>
#include <QFileInfo>
#include <QDir>
+#include <QList>
+#include <QSet>
+
#include <emscripten.h>
+# include <emscripten/proxying.h>
+# include <emscripten/threading.h>
+# include <emscripten/val.h>
QT_BEGIN_NAMESPACE
-static bool isReadReady = false;
+using emscripten::val;
+using namespace Qt::StringLiterals;
-class QWasmSettingsPrivate : public QConfFileSettingsPrivate
+namespace {
+QStringView keyNameFromPrefixedStorageName(QStringView prefix, QStringView prefixedStorageName)
+{
+ // Return the key slice after m_keyPrefix, or an empty string view if no match
+ if (!prefixedStorageName.startsWith(prefix))
+ return QStringView();
+ return prefixedStorageName.sliced(prefix.length());
+}
+} // namespace
+
+//
+// Native settings implementation for WebAssembly using window.localStorage
+// as the storage backend. localStorage is a key-value store with a synchronous
+// API and a 5MB storage limit.
+//
+class QWasmLocalStorageSettingsPrivate final : public QSettingsPrivate
{
public:
- QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
- const QString &application);
- ~QWasmSettingsPrivate();
-
- std::optional<QVariant> get(const QString &key) 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;
+ QWasmLocalStorageSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ ~QWasmLocalStorageSettingsPrivate() final = default;
+
+ void remove(const QString &key) final;
+ void set(const QString &key, const QVariant &value) final;
+ std::optional<QVariant> get(const QString &key) const final;
+ QStringList children(const QString &prefix, ChildSpec spec) const final;
+ void clear() final;
+ void sync() final;
+ void flush() final;
+ bool isWritable() const final;
+ QString fileName() const final;
private:
- QString databaseName;
- QString id;
+ QStringList m_keyPrefixes;
};
-static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
+QWasmLocalStorageSettingsPrivate::QWasmLocalStorageSettingsPrivate(QSettings::Scope scope,
+ const QString &organization,
+ const QString &application)
+ : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
{
- 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 (organization.isEmpty()) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
- if (file.open(QFile::WriteOnly)) {
- file.write(reinterpret_cast<char *>(dataPtr), size);
- file.close();
- wasm->setReady();
+ // The key prefix contians "qt" to separate Qt keys from other keys on localStorage, a
+ // version tag to allow for making changes to the key format in the future, the org
+ // and app names.
+ //
+ // User code could could create separate settings object with different org and app names,
+ // and would expect them to have separate settings. Also, different webassembly instances
+ // on the page could write to the same window.localStorage. Add the org and app name
+ // to the key prefix to differentiate, even if that leads to keys with redundant sections
+ // for the common case of a single org and app name.
+ //
+ // Also, the common Qt mechanism for user/system scope and all-application settings are
+ // implemented, using different prefixes.
+ const QString allAppsSetting = QStringLiteral("all-apps");
+ const QString systemSetting = QStringLiteral("sys-tem");
+
+ const QLatin1String separator("-");
+ const QLatin1String doubleSeparator("--");
+ const QString escapedOrganization = QString(organization).replace(separator, doubleSeparator);
+ const QString escapedApplication = QString(application).replace(separator, doubleSeparator);
+ const QString prefix = "qt-v0-" + escapedOrganization + separator;
+ if (scope == QSettings::Scope::UserScope) {
+ if (!escapedApplication.isEmpty())
+ m_keyPrefixes.push_back(prefix + escapedApplication + separator);
+ m_keyPrefixes.push_back(prefix + allAppsSetting + separator);
+ }
+ if (!escapedApplication.isEmpty()) {
+ m_keyPrefixes.push_back(prefix + escapedApplication + separator + systemSetting
+ + separator);
}
+ m_keyPrefixes.push_back(prefix + allAppsSetting + separator + systemSetting + separator);
}
-static void QWasmSettingsPrivate_onError(void *userData)
+void QWasmLocalStorageSettingsPrivate::remove(const QString &key)
{
- QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
- if (wasm)
- wasm->setStatus(QSettings::AccessError);
+ const std::string removed = QString(m_keyPrefixes.first() + key).toStdString();
+
+ qstdweb::runTaskOnMainThread<void>([this, &removed, &key]() {
+ std::vector<std::string> children = { removed };
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ for (int i = 0; i < length; ++i) {
+ const QString storedKeyWithPrefix = QString::fromStdString(
+ val::global("window")["localStorage"].call<val>("key", i).as<std::string>());
+
+ const QStringView storedKey = keyNameFromPrefixedStorageName(
+ m_keyPrefixes.first(), QStringView(storedKeyWithPrefix));
+ if (storedKey.isEmpty() || !storedKey.startsWith(key))
+ continue;
+
+ children.push_back(storedKeyWithPrefix.toStdString());
+ }
+
+ for (const auto &child : children)
+ val::global("window")["localStorage"].call<val>("removeItem", child);
+ });
}
-static void QWasmSettingsPrivate_onStore(void *userData)
+void QWasmLocalStorageSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
- if (wasm)
- wasm->setStatus(QSettings::NoError);
+ qstdweb::runTaskOnMainThread<void>([this, &key, &value]() {
+ const std::string keyString = QString(m_keyPrefixes.first() + key).toStdString();
+ const std::string valueString = QSettingsPrivate::variantToString(value).toStdString();
+ val::global("window")["localStorage"].call<void>("setItem", keyString, valueString);
+ });
}
-static void QWasmSettingsPrivate_onCheck(void *userData, int exists)
+std::optional<QVariant> QWasmLocalStorageSettingsPrivate::get(const QString &key) const
{
- QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
- if (wasm) {
- if (exists)
- wasm->loadLocal(wasm->fileName().toLocal8Bit());
- else
- wasm->setReady();
- }
+ return qstdweb::runTaskOnMainThread<std::optional<QVariant>>(
+ [this, &key]() -> std::optional<QVariant> {
+ for (const auto &prefix : m_keyPrefixes) {
+ const std::string keyString = QString(prefix + key).toStdString();
+ const emscripten::val value =
+ val::global("window")["localStorage"].call<val>("getItem", keyString);
+ if (!value.isNull()) {
+ return QSettingsPrivate::stringToVariant(
+ QString::fromStdString(value.as<std::string>()));
+ }
+ if (!fallbacks) {
+ return std::nullopt;
+ }
+ }
+ return std::nullopt;
+ });
}
-QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format,
- QSettings::Scope scope,
- const QString &organization,
- const QString &application)
+QStringList QWasmLocalStorageSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
{
- Q_UNUSED(format);
- if (organization == QLatin1String("Qt"))
- {
- QString organizationDomain = QCoreApplication::organizationDomain();
- QString applicationName = QCoreApplication::applicationName();
+ return qstdweb::runTaskOnMainThread<QStringList>([this, &prefix, &spec]() -> QStringList {
+ QSet<QString> nodes;
+ // Loop through all keys on window.localStorage, return Qt keys belonging to
+ // this application, with the correct prefix, and according to ChildSpec.
+ QStringList children;
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ for (int i = 0; i < length; ++i) {
+ for (const auto &storagePrefix : m_keyPrefixes) {
+ const QString keyString =
+ QString::fromStdString(val::global("window")["localStorage"]
+ .call<val>("key", i)
+ .as<std::string>());
+
+ const QStringView key =
+ keyNameFromPrefixedStorageName(storagePrefix, QStringView(keyString));
+ if (!key.isEmpty() && key.startsWith(prefix)) {
+ QStringList children;
+ QSettingsPrivate::processChild(key.sliced(prefix.length()), spec, children);
+ if (!children.isEmpty())
+ nodes.insert(children.first());
+ }
+ if (!fallbacks)
+ break;
+ }
+ }
+
+ return QStringList(nodes.begin(), nodes.end());
+ });
+}
- QSettingsPrivate *newSettings;
- newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName);
+void QWasmLocalStorageSettingsPrivate::clear()
+{
+ qstdweb::runTaskOnMainThread<void>([this]() {
+ // Get all Qt keys from window.localStorage
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ QStringList keys;
+ keys.reserve(length);
+ for (int i = 0; i < length; ++i)
+ keys.append(QString::fromStdString(
+ (val::global("window")["localStorage"].call<val>("key", i).as<std::string>())));
+
+ // Remove all Qt keys. Note that localStorage does not guarantee a stable
+ // iteration order when the storage is mutated, which is why removal is done
+ // in a second step after getting all keys.
+ for (const QString &key : keys) {
+ if (!keyNameFromPrefixedStorageName(m_keyPrefixes.first(), key).isEmpty())
+ val::global("window")["localStorage"].call<val>("removeItem", key.toStdString());
+ }
+ });
+}
- newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization)));
- if (!application.isEmpty())
- newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application)));
+void QWasmLocalStorageSettingsPrivate::sync() { }
- return newSettings;
- }
- return new QWasmSettingsPrivate(scope, organization, application);
-}
+void QWasmLocalStorageSettingsPrivate::flush() { }
-QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
- const QString &application)
- : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+bool QWasmLocalStorageSettingsPrivate::isWritable() const
{
- 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);
+ return true;
}
-QWasmSettingsPrivate::~QWasmSettingsPrivate()
+QString QWasmLocalStorageSettingsPrivate::fileName() const
{
+ return QString();
}
- void QWasmSettingsPrivate::initAccess()
+//
+// Native settings implementation for WebAssembly using the indexed database as
+// the storage backend
+//
+class QWasmIDBSettingsPrivate : public QConfFileSettingsPrivate
{
- if (isReadReady)
- QConfFileSettingsPrivate::initAccess();
-}
+public:
+ QWasmIDBSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ ~QWasmIDBSettingsPrivate();
+
+ void clear() override;
+ void sync() override;
+
+private:
+ bool writeSettingsToTemporaryFile(const QString &fileName, void *dataPtr, int size);
+ void loadIndexedDBFiles();
+
+
+ QString databaseName;
+ QString id;
+};
-std::optional<QVariant> QWasmSettingsPrivate::get(const QString &key) const
+constexpr char DbName[] = "/home/web_user";
+
+QWasmIDBSettingsPrivate::QWasmIDBSettingsPrivate(QSettings::Scope scope,
+ const QString &organization,
+ const QString &application)
+ : QConfFileSettingsPrivate(QSettings::WebIndexedDBFormat, scope, organization, application)
{
- if (isReadReady)
- return QConfFileSettingsPrivate::get(key);
+ Q_ASSERT_X(qstdweb::haveJspi(), Q_FUNC_INFO, "QWasmIDBSettingsPrivate needs JSPI to work");
+
+ if (organization.isEmpty()) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ databaseName = organization;
+ id = application;
- return std::nullopt;
+ loadIndexedDBFiles();
+
+ QConfFileSettingsPrivate::initAccess();
}
-QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
+QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate() = default;
+
+bool QWasmIDBSettingsPrivate::writeSettingsToTemporaryFile(const QString &fileName, void *dataPtr,
+ int size)
{
- return QConfFileSettingsPrivate::children(prefix, spec);
+ QFile file(fileName);
+ QFileInfo fileInfo(fileName);
+ QDir dir(fileInfo.path());
+ if (!dir.exists())
+ dir.mkpath(fileInfo.path());
+
+ if (!file.open(QFile::WriteOnly))
+ return false;
+
+ return size == file.write(reinterpret_cast<char *>(dataPtr), size);
}
-void QWasmSettingsPrivate::clear()
+void QWasmIDBSettingsPrivate::clear()
{
QConfFileSettingsPrivate::clear();
- emscripten_idb_async_delete("/home/web_user",
- fileName().toLocal8Bit(),
- reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onStore,
- QWasmSettingsPrivate_onError);
+
+ int error = 0;
+ emscripten_idb_delete(DbName, fileName().toLocal8Bit(), &error);
+ setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
}
-void QWasmSettingsPrivate::sync()
+void QWasmIDBSettingsPrivate::sync()
{
+ // Reload the files, in case there were any changes in IndexedDB, and flush them to disk.
+ // Thanks to this, QConfFileSettingsPrivate::sync will handle key merging correctly.
+ loadIndexedDBFiles();
+
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);
+ int error = 0;
+ emscripten_idb_store(DbName, fileName().toLocal8Bit(),
+ reinterpret_cast<void *>(dataPointer.data()), dataPointer.length(),
+ &error);
+ setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
}
}
-void QWasmSettingsPrivate::flush()
-{
- sync();
-}
-
-bool QWasmSettingsPrivate::isWritable() const
-{
- return isReadReady && QConfFileSettingsPrivate::isWritable();
-}
-
-void QWasmSettingsPrivate::syncToLocal(const char *data, int size)
+void QWasmIDBSettingsPrivate::loadIndexedDBFiles()
{
- 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();
+ for (const auto *confFile : getConfFiles()) {
+ int exists = 0;
+ int error = 0;
+ emscripten_idb_exists(DbName, confFile->name.toLocal8Bit(), &exists, &error);
+ if (error) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+ if (exists) {
+ void *contents;
+ int size;
+ emscripten_idb_load(DbName, confFile->name.toLocal8Bit(), &contents, &size, &error);
+ if (error || !writeSettingsToTemporaryFile(confFile->name, contents, size)) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+ }
}
}
-void QWasmSettingsPrivate::loadLocal(const QByteArray &filename)
+QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
+ const QString &organization, const QString &application)
{
- emscripten_idb_async_load("/home/web_user",
- filename.data(),
- reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onLoad,
- QWasmSettingsPrivate_onError);
-}
+ // Make WebLocalStorageFormat the default native format
+ if (format == QSettings::NativeFormat)
+ format = QSettings::WebLocalStorageFormat;
+
+ // Check if cookies are enabled (required for using persistent storage)
+
+ const bool cookiesEnabled = qstdweb::runTaskOnMainThread<bool>(
+ []() { return val::global("navigator")["cookieEnabled"].as<bool>(); });
+
+ constexpr QLatin1StringView cookiesWarningMessage(
+ "QSettings::%1 requires cookies, falling back to IniFormat with temporary file");
+ if (!cookiesEnabled) {
+ if (format == QSettings::WebLocalStorageFormat) {
+ qWarning() << cookiesWarningMessage.arg("WebLocalStorageFormat");
+ format = QSettings::IniFormat;
+ } else if (format == QSettings::WebIndexedDBFormat) {
+ qWarning() << cookiesWarningMessage.arg("WebIndexedDBFormat");
+ format = QSettings::IniFormat;
+ }
+ }
+ if (format == QSettings::WebIndexedDBFormat && !qstdweb::haveJspi()) {
+ qWarning() << "QSettings::WebIndexedDBFormat requires JSPI, falling back to IniFormat with "
+ "temporary file";
+ format = QSettings::IniFormat;
+ }
-void QWasmSettingsPrivate::setReady()
-{
- isReadReady = true;
- setStatus(QSettings::NoError);
- QConfFileSettingsPrivate::initAccess();
+ // Create settings backend according to selected format
+ switch (format) {
+ case QSettings::Format::WebLocalStorageFormat:
+ return new QWasmLocalStorageSettingsPrivate(scope, organization, application);
+ case QSettings::Format::WebIndexedDBFormat:
+ return new QWasmIDBSettingsPrivate(scope, organization, application);
+ case QSettings::Format::IniFormat:
+ case QSettings::Format::CustomFormat1:
+ case QSettings::Format::CustomFormat2:
+ case QSettings::Format::CustomFormat3:
+ case QSettings::Format::CustomFormat4:
+ case QSettings::Format::CustomFormat5:
+ case QSettings::Format::CustomFormat6:
+ case QSettings::Format::CustomFormat7:
+ case QSettings::Format::CustomFormat8:
+ case QSettings::Format::CustomFormat9:
+ case QSettings::Format::CustomFormat10:
+ case QSettings::Format::CustomFormat11:
+ case QSettings::Format::CustomFormat12:
+ case QSettings::Format::CustomFormat13:
+ case QSettings::Format::CustomFormat14:
+ case QSettings::Format::CustomFormat15:
+ case QSettings::Format::CustomFormat16:
+ return new QConfFileSettingsPrivate(format, scope, organization, application);
+ case QSettings::Format::InvalidFormat:
+ return nullptr;
+ case QSettings::Format::NativeFormat:
+ Q_UNREACHABLE();
+ break;
+ }
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 5146009c71..e88d738fe4 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsettings.h"
@@ -60,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/* Keys are stored in QStrings. If the variable name starts with 'u', this is a "user"
key, ie. "foo/bar/alpha/beta". If the variable name starts with 'r', this is a "registry"
key, ie. "\foo\bar\alpha\beta". */
@@ -76,7 +42,7 @@ static const REGSAM registryPermissions = KEY_READ | KEY_WRITE;
static QString keyPath(const QString &rKey)
{
- int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+ int idx = rKey.lastIndexOf(u'\\');
if (idx == -1)
return QString();
return rKey.left(idx + 1);
@@ -84,7 +50,7 @@ static QString keyPath(const QString &rKey)
static QString keyName(const QString &rKey)
{
- int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+ int idx = rKey.lastIndexOf(u'\\');
QString res;
if (idx == -1)
@@ -92,8 +58,8 @@ static QString keyName(const QString &rKey)
else
res = rKey.mid(idx + 1);
- if (res == QLatin1String("Default") || res == QLatin1String("."))
- res = QLatin1String("");
+ if (res == "Default"_L1 || res == "."_L1)
+ res = ""_L1;
return res;
}
@@ -248,7 +214,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
continue;
}
if (item.isEmpty())
- item = QLatin1String(".");
+ item = "."_L1;
result.append(item);
}
return result;
@@ -267,7 +233,7 @@ static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result,
for (int i = 0; i < childKeys.size(); ++i) {
QString s = rSubKey;
if (!s.isEmpty())
- s += QLatin1Char('\\');
+ s += u'\\';
s += childKeys.at(i);
result->insert(s, QString());
}
@@ -275,7 +241,7 @@ static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result,
for (int i = 0; i < childGroups.size(); ++i) {
QString s = rSubKey;
if (!s.isEmpty())
- s += QLatin1Char('\\');
+ s += u'\\';
s += childGroups.at(i);
allKeys(parentHandle, s, result, access);
}
@@ -411,9 +377,9 @@ QWinSettingsPrivate::QWinSettingsPrivate(QSettings::Scope scope, const QString &
deleteWriteHandleOnExit = false;
if (!organization.isEmpty()) {
- QString prefix = QLatin1String("Software\\") + organization;
- QString orgPrefix = prefix + QLatin1String("\\OrganizationDefaults");
- QString appPrefix = prefix + QLatin1Char('\\') + application;
+ QString prefix = "Software\\"_L1 + organization;
+ QString orgPrefix = prefix + "\\OrganizationDefaults"_L1;
+ QString appPrefix = prefix + u'\\' + application;
if (scope == QSettings::UserScope) {
if (!application.isEmpty())
@@ -438,34 +404,34 @@ QWinSettingsPrivate::QWinSettingsPrivate(QString rPath, REGSAM access)
{
deleteWriteHandleOnExit = false;
- if (rPath.startsWith(QLatin1Char('\\')))
+ if (rPath.startsWith(u'\\'))
rPath.remove(0, 1);
int keyLength;
HKEY keyName;
- if (rPath.startsWith(QLatin1String("HKEY_CURRENT_USER"))) {
+ if (rPath.startsWith("HKEY_CURRENT_USER"_L1)) {
keyLength = 17;
keyName = HKEY_CURRENT_USER;
- } else if (rPath.startsWith(QLatin1String("HKCU"))) {
+ } else if (rPath.startsWith("HKCU"_L1)) {
keyLength = 4;
keyName = HKEY_CURRENT_USER;
- } else if (rPath.startsWith(QLatin1String("HKEY_LOCAL_MACHINE"))) {
+ } else if (rPath.startsWith("HKEY_LOCAL_MACHINE"_L1)) {
keyLength = 18;
keyName = HKEY_LOCAL_MACHINE;
- } else if (rPath.startsWith(QLatin1String("HKLM"))) {
+ } else if (rPath.startsWith("HKLM"_L1)) {
keyLength = 4;
keyName = HKEY_LOCAL_MACHINE;
- } else if (rPath.startsWith(QLatin1String("HKEY_CLASSES_ROOT"))) {
+ } else if (rPath.startsWith("HKEY_CLASSES_ROOT"_L1)) {
keyLength = 17;
keyName = HKEY_CLASSES_ROOT;
- } else if (rPath.startsWith(QLatin1String("HKCR"))) {
+ } else if (rPath.startsWith("HKCR"_L1)) {
keyLength = 4;
keyName = HKEY_CLASSES_ROOT;
- } else if (rPath.startsWith(QLatin1String("HKEY_USERS"))) {
+ } else if (rPath.startsWith("HKEY_USERS"_L1)) {
keyLength = 10;
keyName = HKEY_USERS;
- } else if (rPath.startsWith(QLatin1String("HKU"))) {
+ } else if (rPath.startsWith("HKU"_L1)) {
keyLength = 3;
keyName = HKEY_USERS;
} else {
@@ -474,7 +440,7 @@ QWinSettingsPrivate::QWinSettingsPrivate(QString rPath, REGSAM access)
if (rPath.length() == keyLength)
regList.append(RegistryKey(keyName, QString(), false, access));
- else if (rPath[keyLength] == QLatin1Char('\\'))
+ else if (rPath[keyLength] == u'\\')
regList.append(RegistryKey(keyName, rPath.mid(keyLength+1), false, access));
}
@@ -773,7 +739,7 @@ QStringList QWinSettingsPrivate::children(const QString &uKey, ChildSpec spec) c
if (spec == AllKeys) {
NameSet keys;
- allKeys(handle, QLatin1String(""), &keys, access);
+ allKeys(handle, ""_L1, &keys, access);
mergeKeySets(&result, keys);
} else { // ChildGroups or ChildKeys
QStringList names = childKeysOrGroups(handle, spec);
@@ -813,9 +779,9 @@ QString QWinSettingsPrivate::fileName() const
const RegistryKey &key = regList.at(0);
QString result;
if (key.parentHandle() == HKEY_CURRENT_USER)
- result = QLatin1String("\\HKEY_CURRENT_USER\\");
+ result = "\\HKEY_CURRENT_USER\\"_L1;
else
- result = QLatin1String("\\HKEY_LOCAL_MACHINE\\");
+ result = "\\HKEY_LOCAL_MACHINE\\"_L1;
return result + regList.at(0).key();
}
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index d207b34510..792721f50d 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -60,6 +24,7 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
/*!
\class QStandardPaths
\inmodule QtCore
@@ -161,6 +126,12 @@ QT_BEGIN_NAMESPACE
template files can be stored. This is a generic value. Note that the returned path may be
empty if the system has no concept of a templates location.
This enum value was added in Qt 6.4.
+ \value [since 6.7] StateLocation Returns a directory location where user-specific application
+ state data files should be written. This is an application-specific directory,
+ and the returned path is never empty.
+ \value [since 6.7] GenericStateLocation Returns a directory location where shared state data files
+ across applications should be written. This value might be generic or application-specific,
+ but the returned path is never empty.
The following table gives examples of paths on different operating systems.
The first path is the writable path (unless noted). Other, additional
@@ -201,6 +172,9 @@ QT_BEGIN_NAMESPACE
\row \li CacheLocation
\li "~/Library/Caches/<APPNAME>", "/Library/Caches/<APPNAME>"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>/cache"
+ \row \li StateLocation
+ \li "~/Library/Preferences/<APPNAME>/State"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>/State", "C:/ProgramData/<APPNAME>/State"
\row \li GenericDataLocation
\li "~/Library/Application Support", "/Library/Application Support"
\li "C:/Users/<USER>/AppData/Local", "C:/ProgramData", "<APPDIR>", "<APPDIR>/data"
@@ -219,6 +193,9 @@ QT_BEGIN_NAMESPACE
\row \li GenericCacheLocation
\li "~/Library/Caches", "/Library/Caches"
\li "C:/Users/<USER>/AppData/Local/cache"
+ \row \li GenericStateLocation
+ \li "~/Library/Preferences/State"
+ \li "C:/Users/<USER>/AppData/Local/State", "C:/ProgramData/State"
\row \li AppDataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
\li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data", "<APPDIR>/data/<APPNAME>"
@@ -257,6 +234,8 @@ QT_BEGIN_NAMESPACE
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\row \li CacheLocation
\li "~/.cache/<APPNAME>"
+ \row \li StateLocation
+ \li "~/.local/state/<APPNAME>"
\row \li GenericDataLocation
\li "~/.local/share", "/usr/local/share", "/usr/share"
\row \li RuntimeLocation
@@ -269,6 +248,8 @@ QT_BEGIN_NAMESPACE
\li "~/Downloads"
\row \li GenericCacheLocation
\li "~/.cache"
+ \row \li GenericStateLocation
+ \li "~/.local/state"
\row \li AppDataLocation
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\row \li AppConfigLocation
@@ -285,7 +266,7 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/files"
\li "<APPROOT>/Documents/Desktop"
\row \li DocumentsLocation
- \li "<USER>/Documents", "<USER>/<APPNAME>/Documents"
+ \li "<USER>/Documents" [*], "<USER>/<APPNAME>/Documents"
\li "<APPROOT>/Documents"
\row \li FontsLocation
\li "/system/fonts" (not writable)
@@ -294,13 +275,13 @@ QT_BEGIN_NAMESPACE
\li not supported (directory not readable)
\li not supported
\row \li MusicLocation
- \li "<USER>/Music", "<USER>/<APPNAME>/Music"
+ \li "<USER>/Music" [*], "<USER>/<APPNAME>/Music"
\li "<APPROOT>/Documents/Music"
\row \li MoviesLocation
- \li "<USER>/Movies", "<USER>/<APPNAME>/Movies"
+ \li "<USER>/Movies" [*], "<USER>/<APPNAME>/Movies"
\li "<APPROOT>/Documents/Movies"
\row \li PicturesLocation
- \li "<USER>/Pictures", "<USER>/<APPNAME>/Pictures"
+ \li "<USER>/Pictures" [*], "<USER>/<APPNAME>/Pictures"
\li "<APPROOT>/Documents/Pictures", "assets-library://"
\row \li TempLocation
\li "<APPROOT>/cache"
@@ -314,9 +295,13 @@ QT_BEGIN_NAMESPACE
\row \li CacheLocation
\li "<APPROOT>/cache", "<USER>/<APPNAME>/cache"
\li "<APPROOT>/Library/Caches"
+ \row \li StateLocation
+ \li "<APPROOT>/files/state"
+ \row \li GenericStateLocation (there is shared state)
+ \li "<APPROOT>/files/state"
\row \li GenericDataLocation
- \li "<USER>"
- \li "<APPROOT>/Documents"
+ \li "<USER>" [*] or "<USER>/<APPNAME>/files"
+ \li "<APPROOT>/Library/Application Support"
\row \li RuntimeLocation
\li "<APPROOT>/cache"
\li not supported
@@ -327,7 +312,7 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/files/settings" (there is no shared settings)
\li "<APPROOT>/Library/Preferences"
\row \li DownloadLocation
- \li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
+ \li "<USER>/Downloads" [*], "<USER>/<APPNAME>/Downloads"
\li "<APPROOT>/Documents/Downloads"
\row \li GenericCacheLocation
\li "<APPROOT>/cache" (there is no shared cache)
@@ -363,6 +348,11 @@ QT_BEGIN_NAMESPACE
\note On Android, reading/writing to GenericDataLocation needs the READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE permission granted.
+ \note [*] On Android 11 and above, public directories are no longer directly accessible
+ in scoped storage mode. Thus, paths of the form \c "<USER>/DirName" are not returned.
+ Instead, you can use \l QFileDialog which uses the Storage Access Framework (SAF)
+ to access such directories.
+
\note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()}
as argument to \l{QFileDialog::setDirectory()},
a native image picker dialog will be used for accessing the user's photo album.
@@ -412,7 +402,7 @@ QString QStandardPaths::locate(StandardLocation type, const QString &fileName, L
{
const QStringList &dirs = standardLocations(type);
for (QStringList::const_iterator dir = dirs.constBegin(); dir != dirs.constEnd(); ++dir) {
- const QString path = *dir + QLatin1Char('/') + fileName;
+ const QString path = *dir + u'/' + fileName;
if (existsAsSpecified(path, options))
return path;
}
@@ -427,7 +417,7 @@ QStringList QStandardPaths::locateAll(StandardLocation type, const QString &file
const QStringList &dirs = standardLocations(type);
QStringList result;
for (QStringList::const_iterator dir = dirs.constBegin(); dir != dirs.constEnd(); ++dir) {
- const QString path = *dir + QLatin1Char('/') + fileName;
+ const QString path = *dir + u'/' + fileName;
if (existsAsSpecified(path, options))
result.append(path);
}
@@ -438,11 +428,9 @@ QStringList QStandardPaths::locateAll(StandardLocation type, const QString &file
static QStringList executableExtensions()
{
// If %PATHEXT% does not contain .exe, it is either empty, malformed, or distorted in ways that we cannot support, anyway.
- const QStringList pathExt = QString::fromLocal8Bit(qgetenv("PATHEXT")).toLower().split(QLatin1Char(';'));
- return pathExt.contains(QLatin1String(".exe"), Qt::CaseInsensitive) ?
- pathExt :
- QStringList() << QLatin1String(".exe") << QLatin1String(".com")
- << QLatin1String(".bat") << QLatin1String(".cmd");
+ const QStringList pathExt = QString::fromLocal8Bit(qgetenv("PATHEXT")).toLower().split(u';');
+ return pathExt.contains(".exe"_L1, Qt::CaseInsensitive) ?
+ pathExt : QStringList{".exe"_L1, ".com"_L1, ".bat"_L1, ".cmd"_L1};
}
#endif
@@ -461,7 +449,7 @@ static inline QString searchExecutable(const QStringList &searchPaths,
{
const QDir currentDir = QDir::current();
for (const QString &searchPath : searchPaths) {
- const QString candidate = currentDir.absoluteFilePath(searchPath + QLatin1Char('/') + executableName);
+ const QString candidate = currentDir.absoluteFilePath(searchPath + u'/' + executableName);
const QString absPath = checkExecutable(candidate);
if (!absPath.isEmpty())
return absPath;
@@ -480,7 +468,7 @@ static inline QString
{
const QDir currentDir = QDir::current();
for (const QString &searchPath : searchPaths) {
- const QString candidateRoot = currentDir.absoluteFilePath(searchPath + QLatin1Char('/') + executableName);
+ const QString candidateRoot = currentDir.absoluteFilePath(searchPath + u'/' + executableName);
for (const QString &suffix : suffixes) {
const QString absPath = checkExecutable(candidateRoot + suffix);
if (!absPath.isEmpty())
@@ -530,7 +518,7 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
searchPaths.reserve(rawPaths.size());
for (const QString &rawPath : rawPaths) {
QString cleanPath = QDir::cleanPath(rawPath);
- if (cleanPath.size() > 1 && cleanPath.endsWith(QLatin1Char('/')))
+ if (cleanPath.size() > 1 && cleanPath.endsWith(u'/'))
cleanPath.truncate(cleanPath.size() - 1);
searchPaths.push_back(cleanPath);
}
@@ -540,9 +528,9 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
// On Windows, if the name does not have a suffix or a suffix not
// in PATHEXT ("xx.foo"), append suffixes from PATHEXT.
static const QStringList executable_extensions = executableExtensions();
- if (executableName.contains(QLatin1Char('.'))) {
+ if (executableName.contains(u'.')) {
const QString suffix = QFileInfo(executableName).suffix();
- if (suffix.isEmpty() || !executable_extensions.contains(QLatin1Char('.') + suffix, Qt::CaseInsensitive))
+ if (suffix.isEmpty() || !executable_extensions.contains(u'.' + suffix, Qt::CaseInsensitive))
return searchExecutableAppendSuffix(searchPaths, executableName, executable_extensions);
} else {
return searchExecutableAppendSuffix(searchPaths, executableName, executable_extensions);
@@ -552,10 +540,12 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
}
/*!
+ \fn QString QStandardPaths::displayName(StandardLocation type)
+
\include standardpath/functiondocs.qdocinc displayName
*/
-#if !defined(Q_OS_MAC) && !defined(QT_BOOTSTRAPPED)
+#if !defined(Q_OS_DARWIN) && !defined(QT_BOOTSTRAPPED)
QString QStandardPaths::displayName(StandardLocation type)
{
switch (type) {
@@ -581,6 +571,8 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Application Data");
case CacheLocation:
return QCoreApplication::translate("QStandardPaths", "Cache");
+ case StateLocation:
+ return QCoreApplication::translate("QStandardPaths", "State");
case GenericDataLocation:
return QCoreApplication::translate("QStandardPaths", "Shared Data");
case RuntimeLocation:
@@ -591,6 +583,8 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Shared Configuration");
case GenericCacheLocation:
return QCoreApplication::translate("QStandardPaths", "Shared Cache");
+ case GenericStateLocation:
+ return QCoreApplication::translate("QStandardPaths", "Shared State");
case DownloadLocation:
return QCoreApplication::translate("QStandardPaths", "Download");
case AppDataLocation:
@@ -612,7 +606,7 @@ QString QStandardPaths::displayName(StandardLocation type)
\include standardpath/functiondocs.qdocinc setTestModeEnabled
*/
-static bool qsp_testMode = false;
+Q_CONSTINIT static bool qsp_testMode = false;
void QStandardPaths::setTestModeEnabled(bool testMode)
{
diff --git a/src/corelib/io/qstandardpaths.h b/src/corelib/io/qstandardpaths.h
index 145591f58d..56aa2b100c 100644
--- a/src/corelib/io/qstandardpaths.h
+++ b/src/corelib/io/qstandardpaths.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTANDARDPATHS_H
#define QSTANDARDPATHS_H
@@ -74,7 +38,9 @@ public:
AppDataLocation,
AppConfigLocation,
PublicShareLocation,
- TemplatesLocation
+ TemplatesLocation,
+ StateLocation,
+ GenericStateLocation,
};
Q_ENUM(StandardLocation)
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index 28993a16dc..f39b6855b6 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -48,21 +12,24 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment");
+Q_DECLARE_JNI_CLASS(File, "java/io/File");
+
using namespace QNativeInterface;
+using namespace Qt::StringLiterals;
typedef QMap<QString, QString> AndroidDirCache;
Q_GLOBAL_STATIC(AndroidDirCache, androidDirCache)
static QString testDir()
{
- return QStandardPaths::isTestModeEnabled() ? QLatin1String("/qttest")
- : QLatin1String("");
+ return QStandardPaths::isTestModeEnabled() ? "/qttest"_L1 : ""_L1;
}
static inline QString getAbsolutePath(const QJniObject &file)
{
- QJniObject path = file.callObjectMethod("getAbsolutePath",
- "()Ljava/lang/String;");
+ QJniObject path = file.callMethod<jstring>("getAbsolutePath");
+
if (!path.isValid())
return QString();
@@ -70,12 +37,54 @@ static inline QString getAbsolutePath(const QJniObject &file)
}
/*
+ * The root of the external storage
+ *
+ */
+static QString getExternalStorageDirectory()
+{
+ QString &path = (*androidDirCache)[QStringLiteral("EXT_ROOT")];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
+ "getExternalStorageDirectory");
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
+ * Locations where applications can place user files shared by all apps (public).
+ * E.g., /storage/Music
+ */
+static QString getExternalStoragePublicDirectory(const char *directoryField)
+{
+ QString &path = (*androidDirCache)[QLatin1String(directoryField)];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject dirField = QJniObject::getStaticField<jstring>("android/os/Environment",
+ directoryField);
+ if (!dirField.isValid())
+ return QString();
+
+ QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
+ "getExternalStoragePublicDirectory",
+ dirField.object<jstring>());
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
* Locations where applications can place persistent files it owns.
* E.g., /storage/org.app/Music
*/
static QString getExternalFilesDir(const char *directoryField = nullptr)
{
- QString &path = (*androidDirCache)[QLatin1String("APPNAME_%1").arg(QLatin1String(directoryField))];
+ QString &path = (*androidDirCache)["APPNAME_%1"_L1.arg(QLatin1StringView(directoryField))];
if (!path.isEmpty())
return path;
@@ -83,18 +92,15 @@ static QString getExternalFilesDir(const char *directoryField = nullptr)
if (!appCtx.isValid())
return QString();
- QJniObject dirField = QJniObject::fromString(QLatin1String(""));
+ QJniObject dirField = QJniObject::fromString(""_L1);
if (directoryField && strlen(directoryField) > 0) {
- dirField = QJniObject::getStaticObjectField("android/os/Environment",
- directoryField,
- "Ljava/lang/String;");
+ dirField = QJniObject::getStaticField<QtJniTypes::Environment, jstring>(directoryField);
if (!dirField.isValid())
return QString();
}
- QJniObject file = appCtx.callObjectMethod("getExternalFilesDir",
- "(Ljava/lang/String;)Ljava/io/File;",
- dirField.object());
+ QJniObject file = appCtx.callMethod<QtJniTypes::File>("getExternalFilesDir",
+ dirField.object<jstring>());
if (!file.isValid())
return QString();
@@ -116,8 +122,7 @@ static QString getExternalCacheDir()
if (!appCtx.isValid())
return QString();
- QJniObject file = appCtx.callObjectMethod("getExternalCacheDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callMethod<QtJniTypes::File>("getExternalCacheDir");
if (!file.isValid())
return QString();
@@ -138,8 +143,7 @@ static QString getCacheDir()
if (!appCtx.isValid())
return QString();
- QJniObject file = appCtx.callObjectMethod("getCacheDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callMethod<QtJniTypes::File>("getCacheDir");
if (!file.isValid())
return QString();
@@ -160,33 +164,45 @@ static QString getFilesDir()
if (!appCtx.isValid())
return QString();
- QJniObject file = appCtx.callObjectMethod("getFilesDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callMethod<QtJniTypes::File>("getFilesDir");
if (!file.isValid())
return QString();
return (path = getAbsolutePath(file));
}
+static QString getSdkBasedExternalDir(const char *directoryField = nullptr)
+{
+ return (QNativeInterface::QAndroidApplication::sdkVersion() >= 30)
+ ? getExternalFilesDir(directoryField)
+ : getExternalStoragePublicDirectory(directoryField);
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
switch (type) {
case QStandardPaths::MusicLocation:
- return getExternalFilesDir("DIRECTORY_MUSIC");
+ return getSdkBasedExternalDir("DIRECTORY_MUSIC");
case QStandardPaths::MoviesLocation:
- return getExternalFilesDir("DIRECTORY_MOVIES");
+ return getSdkBasedExternalDir("DIRECTORY_MOVIES");
case QStandardPaths::PicturesLocation:
- return getExternalFilesDir("DIRECTORY_PICTURES");
+ return getSdkBasedExternalDir("DIRECTORY_PICTURES");
case QStandardPaths::DocumentsLocation:
- return getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ return getSdkBasedExternalDir("DIRECTORY_DOCUMENTS");
case QStandardPaths::DownloadLocation:
- return getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ return getSdkBasedExternalDir("DIRECTORY_DOWNLOADS");
case QStandardPaths::GenericConfigLocation:
case QStandardPaths::ConfigLocation:
case QStandardPaths::AppConfigLocation:
- return getFilesDir() + testDir() + QLatin1String("/settings");
+ return getFilesDir() + testDir() + "/settings"_L1;
+ case QStandardPaths::StateLocation:
+ case QStandardPaths::GenericStateLocation:
+ return getFilesDir() + testDir() + "/state"_L1;
case QStandardPaths::GenericDataLocation:
- return getExternalFilesDir() + testDir();
+ {
+ return QAndroidApplication::sdkVersion() >= 30 ?
+ getExternalFilesDir() + testDir() : getExternalStorageDirectory() + testDir();
+ }
case QStandardPaths::AppDataLocation:
case QStandardPaths::AppLocalDataLocation:
return getFilesDir() + testDir();
@@ -211,59 +227,53 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QStringList QStandardPaths::standardLocations(StandardLocation type)
{
- if (type == MusicLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MUSIC")
- << getExternalFilesDir("DIRECTORY_PODCASTS")
- << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
- << getExternalFilesDir("DIRECTORY_ALARMS");
- }
-
- if (type == MoviesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MOVIES");
- }
-
- if (type == PicturesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_PICTURES");
- }
+ QStringList locations;
- if (type == DocumentsLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOCUMENTS");
- }
-
- if (type == DownloadLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOWNLOADS");
- }
-
- if (type == AppDataLocation || type == AppLocalDataLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir();
- }
-
- if (type == CacheLocation) {
- return QStringList() << writableLocation(type)
- << getExternalCacheDir();
- }
-
- if (type == FontsLocation) {
+ if (type == MusicLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MUSIC");
+ // Place the public dirs before the app own dirs
+ if (QNativeInterface::QAndroidApplication::sdkVersion() < 30) {
+ locations << getExternalStoragePublicDirectory("DIRECTORY_PODCASTS")
+ << getExternalStoragePublicDirectory("DIRECTORY_NOTIFICATIONS")
+ << getExternalStoragePublicDirectory("DIRECTORY_ALARMS");
+ }
+ locations << getExternalFilesDir("DIRECTORY_PODCASTS")
+ << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
+ << getExternalFilesDir("DIRECTORY_ALARMS");
+ } else if (type == MoviesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MOVIES");
+ } else if (type == PicturesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_PICTURES");
+ } else if (type == DocumentsLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ } else if (type == DownloadLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ } else if (type == AppDataLocation || type == AppLocalDataLocation) {
+ locations << getExternalFilesDir();
+ } else if (type == CacheLocation) {
+ locations << getExternalCacheDir();
+ } else if (type == FontsLocation) {
QString &fontLocation = (*androidDirCache)[QStringLiteral("FONT_LOCATION")];
- if (!fontLocation.isEmpty())
- return QStringList(fontLocation);
-
- const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
- if (!ba.isEmpty())
- return QStringList((fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba))));
-
- // Don't cache the fallback, as we might just have been called before
- // QT_ANDROID_FONT_LOCATION has been set.
- return QStringList(QLatin1String("/system/fonts"));
+ if (!fontLocation.isEmpty()) {
+ locations << fontLocation;
+ } else {
+ const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
+ if (!ba.isEmpty()) {
+ locations << (fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)));
+ } else {
+ // Don't cache the fallback, as we might just have been called before
+ // QT_ANDROID_FONT_LOCATION has been set.
+ locations << "/system/fonts"_L1;
+ }
+ }
}
- return QStringList(writableLocation(type));
+ const QString writable = writableLocation(type);
+ if (!writable.isEmpty())
+ locations.prepend(writable);
+
+ locations.removeDuplicates();
+ return locations;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstandardpaths_haiku.cpp b/src/corelib/io/qstandardpaths_haiku.cpp
index cac7767e6b..93eba134f3 100644
--- a/src/corelib/io/qstandardpaths_haiku.cpp
+++ b/src/corelib/io/qstandardpaths_haiku.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -61,10 +25,10 @@ void appendOrganizationAndApp(QString &path)
#ifndef QT_BOOTSTRAPPED
const QString org = QCoreApplication::organizationName();
if (!org.isEmpty())
- path += QLatin1Char('/') + org;
+ path += u'/' + org;
const QString appName = QCoreApplication::applicationName();
if (!appName.isEmpty())
- path += QLatin1Char('/') + appName;
+ path += u'/' + appName;
#else
Q_UNUSED(path);
#endif
@@ -156,8 +120,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return haikuAppStandardPath(B_USER_CACHE_DIRECTORY);
case GenericCacheLocation:
return haikuStandardPath(B_USER_CACHE_DIRECTORY);
- case ConfigLocation: // fall through
+ case ConfigLocation:
case AppConfigLocation:
+ case StateLocation:
+ case GenericStateLocation:
return haikuAppStandardPath(B_USER_SETTINGS_DIRECTORY);
case GenericConfigLocation:
return haikuStandardPath(B_USER_SETTINGS_DIRECTORY);
diff --git a/src/corelib/io/qstandardpaths_mac.mm b/src/corelib/io/qstandardpaths_mac.mm
index 8c102d6928..2acbe92736 100644
--- a/src/corelib/io/qstandardpaths_mac.mm
+++ b/src/corelib/io/qstandardpaths_mac.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -53,6 +17,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QString pathForDirectory(NSSearchPathDirectory directory,
NSSearchPathDomainMask mask)
{
@@ -98,10 +64,10 @@ static void appendOrganizationAndApp(QString &path)
#ifndef QT_BOOTSTRAPPED
const QString org = QCoreApplication::organizationName();
if (!org.isEmpty())
- path += QLatin1Char('/') + org;
+ path += u'/' + org;
const QString appName = QCoreApplication::applicationName();
if (!appName.isEmpty())
- path += QLatin1Char('/') + appName;
+ path += u'/' + appName;
#else
Q_UNUSED(path);
#endif
@@ -123,36 +89,42 @@ static QString baseWritableLocation(QStandardPaths::StandardLocation type,
#if defined(QT_PLATFORM_UIKIT)
// These locations point to non-existing write-protected paths. Use sensible fallbacks.
case QStandardPaths::MusicLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Music");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Music"_L1;
break;
case QStandardPaths::MoviesLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Movies");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Movies"_L1;
break;
case QStandardPaths::PicturesLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Pictures");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Pictures"_L1;
break;
case QStandardPaths::DownloadLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Downloads");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Downloads"_L1;
break;
case QStandardPaths::DesktopLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Desktop");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Desktop"_L1;
break;
case QStandardPaths::ApplicationsLocation:
break;
case QStandardPaths::PublicShareLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Public");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Public"_L1;
break;
case QStandardPaths::TemplatesLocation:
- path = pathForDirectory(NSDocumentDirectory, mask) + QLatin1String("/Templates");
+ path = pathForDirectory(NSDocumentDirectory, mask) + "/Templates"_L1;
break;
#endif
case QStandardPaths::FontsLocation:
- path = pathForDirectory(NSLibraryDirectory, mask) + QLatin1String("/Fonts");
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Fonts"_L1;
break;
case QStandardPaths::ConfigLocation:
case QStandardPaths::GenericConfigLocation:
case QStandardPaths::AppConfigLocation:
- path = pathForDirectory(NSLibraryDirectory, mask) + QLatin1String("/Preferences");
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences"_L1;
+ break;
+ case QStandardPaths::StateLocation:
+ if (appendOrgAndApp) { break; }
+ Q_FALLTHROUGH();
+ case QStandardPaths::GenericStateLocation:
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences/State"_L1;
break;
default:
path = pathForDirectory(dir, mask);
@@ -167,6 +139,11 @@ static QString baseWritableLocation(QStandardPaths::StandardLocation type,
case QStandardPaths::CacheLocation:
appendOrganizationAndApp(path);
break;
+ case QStandardPaths::StateLocation:
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences"_L1;
+ appendOrganizationAndApp(path);
+ path += "/State"_L1;
+ break;
default:
break;
}
@@ -179,7 +156,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
{
QString location = baseWritableLocation(type, NSUserDomainMask, true);
if (isTestModeEnabled())
- location = location.replace(QDir::homePath(), QDir::homePath() + QLatin1String("/.qttest"));
+ location = location.replace(QDir::homePath(), QDir::homePath() + "/.qttest"_L1);
return location;
}
@@ -190,7 +167,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
#if defined(QT_PLATFORM_UIKIT)
if (type == PicturesLocation)
- dirs << writableLocation(PicturesLocation) << QLatin1String("assets-library://");
+ dirs << writableLocation(PicturesLocation) << "assets-library://"_L1;
#endif
if (type == GenericDataLocation || type == FontsLocation || type == ApplicationsLocation
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index 6acec9c034..e38f670895 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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.
-**
-** $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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2020 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
#include <qdir.h>
@@ -58,42 +22,44 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static void appendOrganizationAndApp(QString &path)
{
#ifndef QT_BOOTSTRAPPED
const QString org = QCoreApplication::organizationName();
if (!org.isEmpty())
- path += QLatin1Char('/') + org;
+ path += u'/' + org;
const QString appName = QCoreApplication::applicationName();
if (!appName.isEmpty())
- path += QLatin1Char('/') + appName;
+ path += u'/' + appName;
#else
Q_UNUSED(path);
#endif
}
#if QT_CONFIG(regularexpression)
-static QLatin1String xdg_key_name(QStandardPaths::StandardLocation type)
+static QLatin1StringView xdg_key_name(QStandardPaths::StandardLocation type)
{
switch (type) {
case QStandardPaths::DesktopLocation:
- return QLatin1String("DESKTOP");
+ return "DESKTOP"_L1;
case QStandardPaths::DocumentsLocation:
- return QLatin1String("DOCUMENTS");
+ return "DOCUMENTS"_L1;
case QStandardPaths::PicturesLocation:
- return QLatin1String("PICTURES");
+ return "PICTURES"_L1;
case QStandardPaths::MusicLocation:
- return QLatin1String("MUSIC");
+ return "MUSIC"_L1;
case QStandardPaths::MoviesLocation:
- return QLatin1String("VIDEOS");
+ return "VIDEOS"_L1;
case QStandardPaths::DownloadLocation:
- return QLatin1String("DOWNLOAD");
+ return "DOWNLOAD"_L1;
case QStandardPaths::PublicShareLocation:
- return QLatin1String("PUBLICSHARE");
+ return "PUBLICSHARE"_L1;
case QStandardPaths::TemplatesLocation:
- return QLatin1String("TEMPLATES");
+ return "TEMPLATES"_L1;
default:
- return QLatin1String();
+ return {};
}
}
#endif
@@ -214,25 +180,56 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case CacheLocation:
case GenericCacheLocation:
{
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
- QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
- if (isTestModeEnabled())
- xdgCacheHome = QDir::homePath() + QLatin1String("/.qttest/cache");
- if (xdgCacheHome.isEmpty())
- xdgCacheHome = QDir::homePath() + QLatin1String("/.cache");
+ QString xdgCacheHome;
+ if (isTestModeEnabled()) {
+ xdgCacheHome = QDir::homePath() + "/.qttest/cache"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
+ xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
+ if (!xdgCacheHome.startsWith(u'/'))
+ xdgCacheHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgCacheHome.isEmpty())
+ xdgCacheHome = QDir::homePath() + "/.cache"_L1;
+ }
if (type == QStandardPaths::CacheLocation)
appendOrganizationAndApp(xdgCacheHome);
return xdgCacheHome;
}
+ case StateLocation:
+ case GenericStateLocation:
+ {
+ QString xdgStateHome;
+ if (isTestModeEnabled()) {
+ xdgStateHome = QDir::homePath() + "/.qttest/state"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ xdgStateHome = QFile::decodeName(qgetenv("XDG_STATE_HOME"));
+ if (!xdgStateHome.startsWith(u'/'))
+ xdgStateHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgStateHome.isEmpty())
+ xdgStateHome = QDir::homePath() + "/.local/state"_L1;
+ }
+ if (type == QStandardPaths::StateLocation)
+ appendOrganizationAndApp(xdgStateHome);
+ return xdgStateHome;
+ }
case AppDataLocation:
case AppLocalDataLocation:
case GenericDataLocation:
{
- QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
- if (isTestModeEnabled())
- xdgDataHome = QDir::homePath() + QLatin1String("/.qttest/share");
- if (xdgDataHome.isEmpty())
- xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
+ QString xdgDataHome;
+ if (isTestModeEnabled()) {
+ xdgDataHome = QDir::homePath() + "/.qttest/share"_L1;
+ } else {
+ xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
+ if (!xdgDataHome.startsWith(u'/'))
+ xdgDataHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgDataHome.isEmpty())
+ xdgDataHome = QDir::homePath() + "/.local/share"_L1;
+ }
if (type == AppDataLocation || type == AppLocalDataLocation)
appendOrganizationAndApp(xdgDataHome);
return xdgDataHome;
@@ -241,12 +238,18 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case GenericConfigLocation:
case AppConfigLocation:
{
- // http://standards.freedesktop.org/basedir-spec/latest/
- QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
- if (isTestModeEnabled())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.qttest/config");
- if (xdgConfigHome.isEmpty())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
+ QString xdgConfigHome;
+ if (isTestModeEnabled()) {
+ xdgConfigHome = QDir::homePath() + "/.qttest/config"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgConfigHome.isEmpty())
+ xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ }
if (type == AppConfigLocation)
appendOrganizationAndApp(xdgConfigHome);
return xdgConfigHome;
@@ -254,12 +257,15 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case RuntimeLocation:
{
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
+ if (!xdgRuntimeDir.startsWith(u'/'))
+ xdgRuntimeDir.clear(); // spec says relative paths should be ignored
+
bool fromEnv = !xdgRuntimeDir.isEmpty();
if (xdgRuntimeDir.isEmpty() || !checkXdgRuntimeDir(xdgRuntimeDir)) {
// environment variable not set or is set to something unsuitable
const uint myUid = uint(geteuid());
const QString userName = QFileSystemEngine::resolveUserName(myUid);
- xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
+ xdgRuntimeDir = QDir::tempPath() + "/runtime-"_L1 + userName;
if (!fromEnv) {
#ifndef Q_OS_WASM
@@ -280,30 +286,33 @@ QString QStandardPaths::writableLocation(StandardLocation type)
#if QT_CONFIG(regularexpression)
// http://www.freedesktop.org/wiki/Software/xdg-user-dirs
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
if (xdgConfigHome.isEmpty())
- xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
- QFile file(xdgConfigHome + QLatin1String("/user-dirs.dirs"));
- const QLatin1String key = xdg_key_name(type);
+ xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ QFile file(xdgConfigHome + "/user-dirs.dirs"_L1);
+ const QLatin1StringView key = xdg_key_name(type);
if (!key.isEmpty() && !isTestModeEnabled() && file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
// Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop"
- QRegularExpression exp(QLatin1String("^XDG_(.*)_DIR=(.*)$"));
+ static const QRegularExpression exp(u"^XDG_(.*)_DIR=(.*)$"_s);
QString result;
while (!stream.atEnd()) {
const QString &line = stream.readLine();
QRegularExpressionMatch match = exp.match(line);
if (match.hasMatch() && match.capturedView(1) == key) {
QStringView value = match.capturedView(2);
- if (value.length() > 2
- && value.startsWith(QLatin1Char('\"'))
- && value.endsWith(QLatin1Char('\"')))
- value = value.mid(1, value.length() - 2);
+ if (value.size() > 2
+ && value.startsWith(u'\"')
+ && value.endsWith(u'\"'))
+ value = value.mid(1, value.size() - 2);
// value can start with $HOME
- if (value.startsWith(QLatin1String("$HOME")))
+ if (value.startsWith("$HOME"_L1))
result = QDir::homePath() + value.mid(5);
else
result = value.toString();
- if (result.length() > 1 && result.endsWith(QLatin1Char('/')))
+ if (result.size() > 1 && result.endsWith(u'/'))
result.chop(1);
}
}
@@ -315,39 +324,39 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QString path;
switch (type) {
case DesktopLocation:
- path = QDir::homePath() + QLatin1String("/Desktop");
+ path = QDir::homePath() + "/Desktop"_L1;
break;
case DocumentsLocation:
- path = QDir::homePath() + QLatin1String("/Documents");
+ path = QDir::homePath() + "/Documents"_L1;
break;
case PicturesLocation:
- path = QDir::homePath() + QLatin1String("/Pictures");
+ path = QDir::homePath() + "/Pictures"_L1;
break;
case FontsLocation:
- path = writableLocation(GenericDataLocation) + QLatin1String("/fonts");
+ path = writableLocation(GenericDataLocation) + "/fonts"_L1;
break;
case MusicLocation:
- path = QDir::homePath() + QLatin1String("/Music");
+ path = QDir::homePath() + "/Music"_L1;
break;
case MoviesLocation:
- path = QDir::homePath() + QLatin1String("/Videos");
+ path = QDir::homePath() + "/Videos"_L1;
break;
case DownloadLocation:
- path = QDir::homePath() + QLatin1String("/Downloads");
+ path = QDir::homePath() + "/Downloads"_L1;
break;
case ApplicationsLocation:
- path = writableLocation(GenericDataLocation) + QLatin1String("/applications");
+ path = writableLocation(GenericDataLocation) + "/applications"_L1;
break;
case PublicShareLocation:
- path = QDir::homePath() + QLatin1String("/Public");
+ path = QDir::homePath() + "/Public"_L1;
break;
case TemplatesLocation:
- path = QDir::homePath() + QLatin1String("/Templates");
+ path = QDir::homePath() + "/Templates"_L1;
break;
default:
@@ -357,41 +366,48 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return path;
}
-static QStringList xdgDataDirs()
+static QStringList dirsList(const QString &xdgEnvVar)
{
QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
+ // Normalize paths, skip relative paths (the spec says relative paths
+ // should be ignored)
+ for (const auto dir : qTokenize(xdgEnvVar, u':'))
+ if (dir.startsWith(u'/'))
+ dirs.push_back(QDir::cleanPath(dir.toString()));
+
+ // Remove duplicates from the list, there's no use for duplicated paths
+ // in XDG_* env vars - if whatever is being looked for is not found in
+ // the given directory the first time, it won't be there the second time.
+ // Plus duplicate paths causes problems for example for mimetypes,
+ // where duplicate paths here lead to duplicated mime types returned
+ // for a file, eg "text/plain,text/plain" instead of "text/plain"
+ dirs.removeDuplicates();
+
+ return dirs;
+}
+
+static QStringList xdgDataDirs()
+{
+ // http://standards.freedesktop.org/basedir-spec/latest/
QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
- if (xdgDataDirsEnv.isEmpty()) {
- dirs.append(QString::fromLatin1("/usr/local/share"));
- dirs.append(QString::fromLatin1("/usr/share"));
- } else {
- // Normalize paths, skip relative paths
- for (const auto dir : qTokenize(xdgDataDirsEnv, u':')) {
- if (dir.startsWith(QLatin1Char('/')))
- dirs.push_back(QDir::cleanPath(dir.toString()));
- }
- // Remove duplicates from the list, there's no use for duplicated
- // paths in XDG_DATA_DIRS - if it's not found in the given
- // directory the first time, it won't be there the second time.
- // Plus duplicate paths causes problems for example for mimetypes,
- // where duplicate paths here lead to duplicated mime types returned
- // for a file, eg "text/plain,text/plain" instead of "text/plain"
- dirs.removeDuplicates();
- }
+ QStringList dirs = dirsList(xdgDataDirsEnv);
+ if (dirs.isEmpty())
+ dirs = QStringList{u"/usr/local/share"_s, u"/usr/share"_s};
+
return dirs;
}
static QStringList xdgConfigDirs()
{
- QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
- if (xdgConfigDirs.isEmpty())
- dirs.append(QString::fromLatin1("/etc/xdg"));
- else
- dirs = xdgConfigDirs.split(QLatin1Char(':'));
+
+ QStringList dirs = dirsList(xdgConfigDirs);
+ if (dirs.isEmpty())
+ dirs.push_back(u"/etc/xdg"_s);
+
return dirs;
}
@@ -405,7 +421,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case AppConfigLocation:
dirs = xdgConfigDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case GenericDataLocation:
@@ -413,20 +429,20 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case ApplicationsLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
- dirs[i].append(QLatin1String("/applications"));
+ for (int i = 0; i < dirs.size(); ++i)
+ dirs[i].append("/applications"_L1);
break;
case AppDataLocation:
case AppLocalDataLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case FontsLocation:
- dirs += QDir::homePath() + QLatin1String("/.fonts");
+ dirs += QDir::homePath() + "/.fonts"_L1;
dirs += xdgDataDirs();
- for (int i = 1; i < dirs.count(); ++i)
- dirs[i].append(QLatin1String("/fonts"));
+ for (int i = 1; i < dirs.size(); ++i)
+ dirs[i].append("/fonts"_L1);
break;
default:
break;
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index 2ddf4a5fe1..805ce65a5a 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -55,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QString convertCharArray(const wchar_t *path)
{
return QDir::fromNativeSeparators(QString::fromWCharArray(path));
@@ -77,10 +43,10 @@ static void appendOrganizationAndApp(QString &path) // Courtesy qstandardpaths_u
#ifndef QT_BOOTSTRAPPED
const QString &org = QCoreApplication::organizationName();
if (!org.isEmpty())
- path += QLatin1Char('/') + org;
+ path += u'/' + org;
const QString &appName = QCoreApplication::applicationName();
if (!appName.isEmpty())
- path += QLatin1Char('/') + appName;
+ path += u'/' + appName;
#else // !QT_BOOTSTRAPPED
Q_UNUSED(path);
#endif
@@ -89,11 +55,13 @@ static void appendOrganizationAndApp(QString &path) // Courtesy qstandardpaths_u
static inline void appendTestMode(QString &path)
{
if (QStandardPaths::isTestModeEnabled())
- path += QLatin1String("/qttest");
+ path += "/qttest"_L1;
}
-static bool isProcessLowIntegrity() {
- const HANDLE process_token = GetCurrentProcessToken();
+static bool isProcessLowIntegrity()
+{
+ // same as GetCurrentProcessToken()
+ const auto process_token = HANDLE(quintptr(-4));
QVarLengthArray<char,256> token_info_buf(256);
auto* token_info = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_info_buf.data());
@@ -137,8 +105,10 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppData, // AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation
+ GUID(), // StateLocation
+ GUID(), // GenericStateLocation
};
- static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::TemplatesLocation + 1));
+ static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::GenericStateLocation + 1));
// folders for low integrity processes
static const GUID folderIds_li[] = {
@@ -162,6 +132,8 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation
+ GUID(), // StateLocation
+ GUID(), // GenericStateLocation
};
static_assert(sizeof(folderIds_li) == sizeof(folderIds));
@@ -195,7 +167,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
if (!result.isEmpty()) {
appendTestMode(result);
appendOrganizationAndApp(result);
- result += QLatin1String("/cache");
+ result += "/cache"_L1;
}
break;
@@ -203,7 +175,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
if (!result.isEmpty()) {
appendTestMode(result);
- result += QLatin1String("/cache");
+ result += "/cache"_L1;
}
break;
@@ -216,6 +188,23 @@ QString QStandardPaths::writableLocation(StandardLocation type)
result = QDir::tempPath();
break;
+ case StateLocation:
+ result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));
+ if (!result.isEmpty()) {
+ appendTestMode(result);
+ appendOrganizationAndApp(result);
+ result += "/State"_L1;
+ }
+ break;
+
+ case GenericStateLocation:
+ result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
+ if (!result.isEmpty()) {
+ appendTestMode(result);
+ result += "/State"_L1;
+ }
+ break;
+
default:
result = sHGetKnownFolderPath(writableSpecialFolderId(type));
if (!result.isEmpty() && isConfigLocation(type)) {
@@ -254,7 +243,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
QString applicationDirPath = qApp ? QCoreApplication::applicationDirPath()
: QFileInfo(qAppFileName()).path();
dirs.append(applicationDirPath);
- const QString dataDir = applicationDirPath + QLatin1String("/data");
+ const QString dataDir = applicationDirPath + "/data"_L1;
dirs.append(dataDir);
if (!isGenericConfigLocation(type)) {
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 41abce8d84..b7a17febaf 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2015 Ivan Komissarov <ABBAPOH@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstorageinfo.h"
#include "qstorageinfo_p.h"
@@ -55,6 +20,8 @@ QT_IMPL_METATYPE_EXTERN(QStorageInfo)
\ingroup io
\ingroup shared
+ \compares equality
+
Allows retrieving information about the volume's space, its mount point,
label, and filesystem name.
@@ -72,6 +39,11 @@ QT_IMPL_METATYPE_EXTERN(QStorageInfo)
\snippet code/src_corelib_io_qstorageinfo.cpp 2
*/
+QStorageInfo::QStorageInfo(QStorageInfoPrivate &dd)
+ : d(&dd)
+{
+}
+
/*!
Constructs an empty QStorageInfo object.
@@ -276,9 +248,10 @@ QByteArray QStorageInfo::device() const
Returns the subvolume name for this volume.
Some filesystem types allow multiple subvolumes inside one device, which
- may be mounted in different paths. If the subvolume could be detected, it
- is returned here. The format of the subvolume name is specific to each
- filesystem type.
+ may be mounted in different paths (e.g. 'bind' mounts on Unix, or Btrfs
+ filesystem subvolumes). If the subvolume could be detected, its name is
+ returned by this function. The format of the subvolume name is specific
+ to each filesystem type.
If this volume was not mounted from a subvolume of a larger filesystem or
if the subvolume could not be detected, this function returns an empty byte
@@ -399,7 +372,7 @@ QList<QStorageInfo> QStorageInfo::mountedVolumes()
return QStorageInfoPrivate::mountedVolumes();
}
-Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root()))
+Q_GLOBAL_STATIC(QStorageInfo, getRoot, QStorageInfoPrivate::root())
/*!
Returns a QStorageInfo object that represents the system root volume.
@@ -415,22 +388,29 @@ QStorageInfo QStorageInfo::root()
}
/*!
- \fn bool QStorageInfo::operator==(const QStorageInfo &first, const QStorageInfo &second)
+ \fn bool QStorageInfo::operator==(const QStorageInfo &lhs, const QStorageInfo &rhs)
- Returns true if the \a first QStorageInfo object refers to the same drive or volume
- as the \a second; otherwise it returns false.
+ Returns \c true if the QStorageInfo object \a lhs refers to the same drive or
+ volume as the QStorageInfo object \a rhs; otherwise it returns \c false.
Note that the result of comparing two invalid QStorageInfo objects is always
positive.
*/
/*!
- \fn bool QStorageInfo::operator!=(const QStorageInfo &first, const QStorageInfo &second)
+ \fn bool QStorageInfo::operator!=(const QStorageInfo &lhs, const QStorageInfo &rhs)
- Returns true if the \a first QStorageInfo object refers to a different drive or
- volume than the \a second; otherwise returns false.
+ Returns \c true if the QStorageInfo object \a lhs refers to a different drive or
+ volume than the QStorageInfo object \a rhs; otherwise returns \c false.
*/
+bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs)
+{
+ if (lhs.d == rhs.d)
+ return true;
+ return lhs.device() == rhs.device() && lhs.rootPath() == rhs.rootPath();
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QStorageInfo &s)
{
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index 251635efa6..3784fe8e47 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTORAGEINFO_H
#define QSTORAGEINFO_H
#include <QtCore/qbytearray.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qdir.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
@@ -92,18 +57,10 @@ public:
static QStorageInfo root();
private:
+ explicit QStorageInfo(QStorageInfoPrivate &dd);
friend class QStorageInfoPrivate;
- friend inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
- {
- if (first.d == second.d)
- return true;
- return first.device() == second.device() && first.rootPath() == second.rootPath();
- }
-
- friend inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
- {
- return !(first == second);
- }
+ friend Q_CORE_EXPORT bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QStorageInfo)
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QStorageInfo &);
QExplicitlySharedDataPointer<QStorageInfoPrivate> d;
diff --git a/src/corelib/io/qstorageinfo_linux.cpp b/src/corelib/io/qstorageinfo_linux.cpp
new file mode 100644
index 0000000000..a9d46e7395
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_linux.cpp
@@ -0,0 +1,288 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qstorageinfo_linux_p.h"
+
+#include "qdirlisting.h"
+#include <private/qcore_unix_p.h>
+#include <private/qtools_p.h>
+
+#include <q20memory.h>
+
+#include <sys/ioctl.h>
+#include <sys/statfs.h>
+
+// so we don't have to #include <linux/fs.h>, which is known to cause conflicts
+#ifndef FSLABEL_MAX
+# define FSLABEL_MAX 256
+#endif
+#ifndef FS_IOC_GETFSLABEL
+# define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
+#endif
+
+// or <linux/statfs.h>
+#ifndef ST_RDONLY
+# define ST_RDONLY 0x0001 /* mount read-only */
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+// udev encodes the labels with ID_LABEL_FS_ENC which is done with
+// blkid_encode_string(). Within this function some 1-byte utf-8
+// characters not considered safe (e.g. '\' or ' ') are encoded as hex
+static QString decodeFsEncString(QString &&str)
+{
+ using namespace QtMiscUtils;
+ qsizetype start = str.indexOf(u'\\');
+ if (start < 0)
+ return std::move(str);
+
+ // decode in-place
+ QString decoded = std::move(str);
+ auto ptr = reinterpret_cast<char16_t *>(decoded.begin());
+ qsizetype in = start;
+ qsizetype out = start;
+ qsizetype size = decoded.size();
+
+ while (in < size) {
+ Q_ASSERT(ptr[in] == u'\\');
+ if (size - in >= 4 && ptr[in + 1] == u'x') { // we need four characters: \xAB
+ int c = fromHex(ptr[in + 2]) << 4;
+ c |= fromHex(ptr[in + 3]);
+ if (Q_UNLIKELY(c < 0))
+ c = QChar::ReplacementCharacter; // bad hex sequence
+ ptr[out++] = c;
+ in += 4;
+ }
+
+ for ( ; in < size; ++in) {
+ char16_t c = ptr[in];
+ if (c == u'\\')
+ break;
+ ptr[out++] = c;
+ }
+ }
+ decoded.resize(out);
+ return decoded;
+}
+
+static inline dev_t deviceIdForPath(const QString &device)
+{
+ QT_STATBUF st;
+ if (QT_STAT(QFile::encodeName(device), &st) < 0)
+ return 0;
+ return st.st_dev;
+}
+
+static inline quint64 retrieveDeviceId(const QByteArray &device, quint64 deviceId = 0)
+{
+ // major = 0 implies an anonymous block device, so we need to stat() the
+ // actual device to get its dev_t. This is required for btrfs (and possibly
+ // others), which always uses them for all the subvolumes (including the
+ // root):
+ // https://codebrowser.dev/linux/linux/fs/btrfs/disk-io.c.html#btrfs_init_fs_root
+ // https://codebrowser.dev/linux/linux/fs/super.c.html#get_anon_bdev
+ // For everything else, we trust the parameter.
+ if (major(deviceId) != 0)
+ return deviceId;
+
+ // don't even try to stat() a relative path or "/"
+ if (device.size() < 2 || !device.startsWith('/'))
+ return 0;
+
+ QT_STATBUF st;
+ if (QT_STAT(device, &st) < 0)
+ return 0;
+ if (!S_ISBLK(st.st_mode))
+ return 0;
+ return st.st_rdev;
+}
+
+static QDirListing devicesByLabel()
+{
+ static const char pathDiskByLabel[] = "/dev/disk/by-label";
+ static constexpr auto LabelFileFilter =
+ QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot;
+
+ return QDirListing(QLatin1StringView(pathDiskByLabel), LabelFileFilter);
+}
+
+static inline auto retrieveLabels()
+{
+ struct Entry {
+ QString label;
+ quint64 deviceId;
+ };
+ QList<Entry> result;
+
+ for (const auto &dirEntry : devicesByLabel()) {
+ quint64 deviceId = retrieveDeviceId(QFile::encodeName(dirEntry.filePath()));
+ if (!deviceId)
+ continue;
+ result.emplaceBack(Entry{ decodeFsEncString(dirEntry.fileName()), deviceId });
+ }
+ return result;
+}
+
+static std::optional<QString> retrieveLabelViaIoctl(const QString &path)
+{
+ // FS_IOC_GETFSLABEL was introduced in v4.18; previously it was btrfs-specific.
+ int fd = qt_safe_open(QFile::encodeName(path).constData(), QT_OPEN_RDONLY);
+ if (fd < 0)
+ return std::nullopt;
+
+ // Note: it doesn't append the null terminator (despite what the man page
+ // says) and the return code on success (0) does not indicate the length.
+ char label[FSLABEL_MAX] = {};
+ int r = ioctl(fd, FS_IOC_GETFSLABEL, &label);
+ close(fd);
+ if (r < 0)
+ return std::nullopt;
+ return QString::fromUtf8(label);
+}
+
+static inline QString retrieveLabel(const QStorageInfoPrivate &d, quint64 deviceId)
+{
+ if (auto label = retrieveLabelViaIoctl(d.rootPath))
+ return *label;
+
+ deviceId = retrieveDeviceId(d.device, deviceId);
+ if (!deviceId)
+ return QString();
+
+ for (const auto &dirEntry : devicesByLabel()) {
+ if (retrieveDeviceId(QFile::encodeName(dirEntry.filePath())) == deviceId)
+ return decodeFsEncString(dirEntry.fileName());
+ }
+ return QString();
+}
+
+void QStorageInfoPrivate::retrieveVolumeInfo()
+{
+ struct statfs64 statfs_buf;
+ int result;
+ QT_EINTR_LOOP(result, statfs64(QFile::encodeName(rootPath).constData(), &statfs_buf));
+ if (result == 0) {
+ valid = true;
+ ready = true;
+
+ bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
+ bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
+ bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
+ blockSize = int(statfs_buf.f_bsize);
+ readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
+ }
+}
+
+static std::vector<MountInfo> parseMountInfo(FilterMountInfo filter = FilterMountInfo::All)
+{
+ QFile file(u"/proc/self/mountinfo"_s);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return {};
+
+ QByteArray mountinfo = file.readAll();
+ file.close();
+
+ return doParseMountInfo(mountinfo, filter);
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ retrieveVolumeInfo();
+ if (!ready)
+ return;
+
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+ if (rootPath.isEmpty())
+ return;
+
+ std::vector<MountInfo> infos = parseMountInfo();
+ if (infos.empty()) {
+ rootPath = u'/';
+ return;
+ }
+
+ // We iterate over the /proc/self/mountinfo list backwards because then any
+ // matching isParentOf must be the actual mount point because it's the most
+ // recent mount on that path. Linux does allow mounting over non-empty
+ // directories, such as in:
+ // # mount | tail -2
+ // tmpfs on /tmp/foo/bar type tmpfs (rw,relatime,inode64)
+ // tmpfs on /tmp/foo type tmpfs (rw,relatime,inode64)
+ //
+ // We try to match the device ID in case there's a mount --move.
+ // We can't *rely* on it because some filesystems like btrfs will assign
+ // device IDs to subvolumes that aren't listed in /proc/self/mountinfo.
+
+ const QString oldRootPath = std::exchange(rootPath, QString());
+ const dev_t rootPathDevId = deviceIdForPath(oldRootPath);
+ MountInfo *best = nullptr;
+ for (auto it = infos.rbegin(); it != infos.rend(); ++it) {
+ if (!isParentOf(it->mountPoint, oldRootPath))
+ continue;
+ if (rootPathDevId == it->stDev) {
+ // device ID matches; this is definitely the best option
+ best = q20::to_address(it);
+ break;
+ }
+ if (!best) {
+ // if we can't find a device ID match, this parent path is probably
+ // the correct one
+ best = q20::to_address(it);
+ }
+ }
+ if (best) {
+ auto stDev = best->stDev;
+ setFromMountInfo(std::move(*best));
+ name = retrieveLabel(*this, stDev);
+ }
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ std::vector<MountInfo> infos = parseMountInfo(FilterMountInfo::Filtered);
+ if (infos.empty())
+ return QList{root()};
+
+ std::optional<decltype(retrieveLabels())> labelMap;
+ auto labelForDevice = [&labelMap](const QStorageInfoPrivate &d, quint64 devid) {
+ if (d.fileSystemType == "tmpfs")
+ return QString();
+
+ if (auto label = retrieveLabelViaIoctl(d.rootPath))
+ return *label;
+
+ devid = retrieveDeviceId(d.device, devid);
+ if (!devid)
+ return QString();
+
+ if (!labelMap)
+ labelMap = retrieveLabels();
+ for (auto &[deviceLabel, deviceId] : std::as_const(*labelMap)) {
+ if (devid == deviceId)
+ return deviceLabel;
+ }
+ return QString();
+ };
+
+ QList<QStorageInfo> volumes;
+ for (MountInfo &info : infos) {
+ const auto infoStDev = info.stDev;
+ QStorageInfoPrivate d(std::move(info));
+ d.retrieveVolumeInfo();
+ if (d.bytesTotal <= 0 && d.rootPath != u'/')
+ continue;
+ if (infoStDev != deviceIdForPath(d.rootPath))
+ continue; // probably something mounted over this mountpoint
+ d.name = labelForDevice(d, infoStDev);
+ volumes.emplace_back(QStorageInfo(*new QStorageInfoPrivate(std::move(d))));
+ }
+ return volumes;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_linux_p.h b/src/corelib/io/qstorageinfo_linux_p.h
new file mode 100644
index 0000000000..6f5e107ec6
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_linux_p.h
@@ -0,0 +1,244 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSTORAGEINFO_LINUX_P_H
+#define QSTORAGEINFO_LINUX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API.
+// This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstorageinfo_p.h"
+
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/private/qlocale_tools_p.h>
+
+#include <sys/sysmacros.h> // makedev()
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+using MountInfo = QStorageInfoPrivate::MountInfo;
+
+static const char MountInfoPath[] = "/proc/self/mountinfo";
+
+static std::optional<dev_t> deviceNumber(QByteArrayView devno)
+{
+ // major:minor
+ auto it = devno.cbegin();
+ auto r = qstrntoll(it, devno.size(), 10);
+ if (!r.ok())
+ return std::nullopt;
+ int rdevmajor = int(r.result);
+ it += r.used;
+
+ if (*it != ':')
+ return std::nullopt;
+
+ r = qstrntoll(++it, devno.size() - r.used + 1, 10);
+ if (!r.ok())
+ return std::nullopt;
+
+ return makedev(rdevmajor, r.result);
+}
+
+// Helper function to parse paths that the kernel inserts escape sequences
+// for.
+static QByteArray parseMangledPath(QByteArrayView path)
+{
+ // The kernel escapes with octal the following characters:
+ // space ' ', tab '\t', backslash '\\', and newline '\n'
+ // See:
+ // https://codebrowser.dev/linux/linux/fs/proc_namespace.c.html#show_mountinfo
+ // https://codebrowser.dev/linux/linux/fs/seq_file.c.html#mangle_path
+
+ QByteArray ret(path.size(), '\0');
+ char *dst = ret.data();
+ const char *src = path.data();
+ const char *srcEnd = path.data() + path.size();
+ while (src != srcEnd) {
+ switch (*src) {
+ case ' ': // Shouldn't happen
+ return {};
+
+ case '\\': {
+ // It always uses exactly three octal characters.
+ ++src;
+ char c = (*src++ - '0') << 6;
+ c |= (*src++ - '0') << 3;
+ c |= (*src++ - '0');
+ *dst++ = c;
+ break;
+ }
+
+ default:
+ *dst++ = *src++;
+ break;
+ }
+ }
+ // If "path" contains any of the characters this method is demangling,
+ // "ret" would be oversized with extra '\0' characters at the end.
+ ret.resize(dst - ret.data());
+ return ret;
+}
+
+// Indexes into the "fields" std::array in parseMountInfo()
+// static constexpr short MountId = 0;
+// static constexpr short ParentId = 1;
+static constexpr short DevNo = 2;
+static constexpr short FsRoot = 3;
+static constexpr short MountPoint = 4;
+static constexpr short MountOptions = 5;
+// static constexpr short OptionalFields = 6;
+// static constexpr short Separator = 7;
+static constexpr short FsType = 8;
+static constexpr short MountSource = 9;
+static constexpr short SuperOptions = 10;
+static constexpr short FieldCount = 11;
+
+// Splits a line from /proc/self/mountinfo into fields; fields are separated
+// by a single space.
+static void tokenizeLine(std::array<QByteArrayView, FieldCount> &fields, QByteArrayView line)
+{
+ size_t fieldIndex = 0;
+ qsizetype from = 0;
+ const char *begin = line.data();
+ const qsizetype len = line.size();
+ qsizetype spaceIndex = -1;
+ while ((spaceIndex = line.indexOf(' ', from)) != -1 && fieldIndex < FieldCount) {
+ fields[fieldIndex] = QByteArrayView{begin + from, begin + spaceIndex};
+ from = spaceIndex;
+
+ // Skip "OptionalFields" and Separator fields
+ if (fieldIndex == MountOptions) {
+ static constexpr char separatorField[] = " - ";
+ const qsizetype sepIndex = line.indexOf(separatorField, from);
+ if (sepIndex == -1) {
+ qCWarning(lcStorageInfo,
+ "Malformed line (missing '-' separator field) while parsing '%s':\n%s",
+ MountInfoPath, line.constData());
+ fields.fill({});
+ return;
+ }
+
+ from = sepIndex + strlen(separatorField);
+ // Continue parsing at FsType field
+ fieldIndex = FsType;
+ continue;
+ }
+
+ if (from + 1 < len)
+ ++from; // Skip the space at spaceIndex
+
+ ++fieldIndex;
+ }
+
+ // Currently we don't use the last field, so just check the index
+ if (fieldIndex != SuperOptions) {
+ qCInfo(lcStorageInfo,
+ "Expected %d fields while parsing line from '%s', but found %zu instead:\n%.*s",
+ FieldCount, MountInfoPath, fieldIndex, int(line.size()), line.data());
+ fields.fill({});
+ }
+}
+
+// parseMountInfo() is called from:
+// - QStorageInfoPrivate::initRootPath(), where a list of all mounted volumes is needed
+// - QStorageInfoPrivate::mountedVolumes(), where some filesystem types are ignored
+// (see shouldIncludefs())
+enum class FilterMountInfo {
+ All,
+ Filtered,
+};
+
+[[maybe_unused]] static std::vector<MountInfo>
+doParseMountInfo(const QByteArray &mountinfo, FilterMountInfo filter = FilterMountInfo::All)
+{
+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt:
+ // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+ // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
+
+ auto it = mountinfo.cbegin();
+ const auto end = mountinfo.cend();
+ auto nextLine = [&it, &end]() -> QByteArrayView {
+ auto nIt = std::find(it, end, '\n');
+ if (nIt != end) {
+ QByteArrayView ba(it, nIt);
+ it = ++nIt; // Advance
+ return ba;
+ }
+ return {};
+ };
+
+ std::vector<MountInfo> infos;
+ std::array<QByteArrayView, FieldCount> fields;
+ QByteArrayView line;
+
+ auto checkField = [&line](QByteArrayView field) {
+ if (field.isEmpty()) {
+ qDebug("Failed to parse line from %s:\n%.*s", MountInfoPath, int(line.size()),
+ line.data());
+ return false;
+ }
+ return true;
+ };
+
+ // mountinfo has a stable format, no empty lines
+ while (!(line = nextLine()).isEmpty()) {
+ fields.fill({});
+ tokenizeLine(fields, line);
+
+ MountInfo info;
+ QByteArray mountP = parseMangledPath(fields[MountPoint]);
+ if (!checkField(mountP))
+ continue;
+ info.mountPoint = QFile::decodeName(mountP);
+
+ if (!checkField(fields[FsType]))
+ continue;
+ info.fsType = fields[FsType].toByteArray();
+
+ if (filter == FilterMountInfo::Filtered && !shouldIncludeFs(info.mountPoint, info.fsType))
+ continue;
+
+ std::optional<dev_t> devno = deviceNumber(fields[DevNo]);
+ if (!devno) {
+ checkField({});
+ continue;
+ }
+ info.stDev = *devno;
+
+ QByteArrayView fsRootView = fields[FsRoot];
+ if (!checkField(fsRootView))
+ continue;
+
+ // If the filesystem root is "/" -- it's not a *sub*-volume/bind-mount,
+ // in that case we leave info.fsRoot empty
+ if (fsRootView != "/") {
+ info.fsRoot = parseMangledPath(fsRootView);
+ if (!checkField(info.fsRoot))
+ continue;
+ }
+
+ info.device = parseMangledPath(fields[MountSource]);
+ if (!checkField(info.device))
+ continue;
+
+ infos.push_back(std::move(info));
+ }
+ return infos;
+}
+
+QT_END_NAMESPACE
+
+#endif // QSTORAGEINFO_LINUX_P_H
diff --git a/src/corelib/io/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp
index 8b06543d71..c6c0f501da 100644
--- a/src/corelib/io/qstorageinfo_mac.cpp
+++ b/src/corelib/io/qstorageinfo_mac.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstorageinfo_p.h"
@@ -79,9 +43,9 @@ void QStorageInfoPrivate::retrievePosixInfo()
QT_STATFSBUF statfs_buf;
int result = QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf);
if (result == 0) {
- device = QByteArray(statfs_buf.f_mntfromname);
+ device.assign(statfs_buf.f_mntfromname);
readOnly = (statfs_buf.f_flags & MNT_RDONLY) != 0;
- fileSystemType = QByteArray(statfs_buf.f_fstypename);
+ fileSystemType.assign(statfs_buf.f_fstypename);
blockSize = statfs_buf.f_bsize;
}
}
@@ -196,9 +160,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QStringLiteral("/"));
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index c0f7595c08..3af4b81ca4 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTORAGEINFO_P_H
#define QSTORAGEINFO_P_H
@@ -51,36 +15,77 @@
// We mean it.
//
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qtenvironmentvariables.h>
#include <QtCore/private/qglobal_p.h>
#include "qstorageinfo.h"
+#ifdef Q_OS_UNIX
+#include <sys/types.h> // dev_t
+#endif
+
QT_BEGIN_NAMESPACE
+inline Q_LOGGING_CATEGORY(lcStorageInfo, "qt.core.qstorageinfo", QtWarningMsg)
+
class QStorageInfoPrivate : public QSharedData
{
public:
- inline QStorageInfoPrivate() : QSharedData(),
- bytesTotal(-1), bytesFree(-1), bytesAvailable(-1), blockSize(-1),
- readOnly(false), ready(false), valid(false)
- {}
+ QStorageInfoPrivate() = default;
- void initRootPath();
void doStat();
static QList<QStorageInfo> mountedVolumes();
- static QStorageInfo root();
+
+ static QStorageInfo root()
+ {
+#ifdef Q_OS_WIN
+ return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
+#else
+ return QStorageInfo(QStringLiteral("/"));
+#endif
+ };
protected:
#if defined(Q_OS_WIN)
+ void initRootPath();
void retrieveVolumeInfo();
void retrieveDiskFreeSpace();
bool queryStorageProperty();
void queryFileFsSectorSizeInformation();
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_DARWIN)
+ void initRootPath();
void retrievePosixInfo();
void retrieveUrlProperties(bool initRootPath = false);
void retrieveLabel();
+#elif defined(Q_OS_LINUX)
+ void retrieveVolumeInfo();
+
+public:
+ struct MountInfo {
+ QString mountPoint;
+ QByteArray fsType;
+ QByteArray device;
+ QByteArray fsRoot;
+ dev_t stDev = 0;
+ };
+
+ void setFromMountInfo(MountInfo &&info)
+ {
+ rootPath = std::move(info.mountPoint);
+ fileSystemType = std::move(info.fsType);
+ device = std::move(info.device);
+ subvolume = std::move(info.fsRoot);
+ }
+
+ QStorageInfoPrivate(MountInfo &&info)
+ {
+ setFromMountInfo(std::move(info));
+ }
+
#elif defined(Q_OS_UNIX)
+ void initRootPath();
void retrieveVolumeInfo();
#endif
@@ -91,16 +96,68 @@ public:
QByteArray fileSystemType;
QString name;
- qint64 bytesTotal;
- qint64 bytesFree;
- qint64 bytesAvailable;
- int blockSize;
+ qint64 bytesTotal = -1;
+ qint64 bytesFree = -1;
+ qint64 bytesAvailable = -1;
+ int blockSize = -1;
- bool readOnly;
- bool ready;
- bool valid;
+ bool readOnly = false;
+ bool ready = false;
+ bool valid = false;
};
+// Common helper functions
+template <typename String>
+static bool isParentOf(const String &parent, const QString &dirName)
+{
+ return dirName.startsWith(parent) &&
+ (dirName.size() == parent.size() || dirName.at(parent.size()) == u'/' ||
+ parent.size() == 1);
+}
+
+static inline bool shouldIncludeFs(const QString &mountDir, const QByteArray &fsType)
+{
+#if defined(Q_OS_ANDROID)
+ // "rootfs" is the filesystem type of "/" on Android
+ static constexpr char RootFsStr[] = "";
+#else
+ // "rootfs" is a type of ramfs on Linux, used in the initrd on some distros
+ static constexpr char RootFsStr[] = "rootfs";
+#endif
+
+ using namespace Qt::StringLiterals;
+ /*
+ * This function implements a heuristic algorithm to determine whether a
+ * given mount should be reported to the user. Our objective is to list
+ * only entries that the end-user would find useful.
+ *
+ * We therefore ignore:
+ * - mounted in /dev, /proc, /sys: special mounts
+ * (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts,
+ * some of which are tmpfs on Linux)
+ * - mounted in /var/run or /var/lock: most likely pseudofs
+ * (on earlier systemd versions, /var/run was a bind-mount of /run, so
+ * everything would be unnecessarily duplicated)
+ * - filesystem type is "rootfs": artifact of the root-pivot on some Linux
+ * initrd
+ * - if the filesystem total size is zero, it's a pseudo-fs (not checked here).
+ */
+
+ if (isParentOf("/dev"_L1, mountDir)
+ || isParentOf("/proc"_L1, mountDir)
+ || isParentOf("/sys"_L1, mountDir)
+ || isParentOf("/var/run"_L1, mountDir)
+ || isParentOf("/var/lock"_L1, mountDir)) {
+ return false;
+ }
+
+ if (!fsType.isEmpty() && fsType == RootFsStr)
+ return false;
+
+ // size checking in QStorageInfo::mountedVolumes()
+ return true;
+}
+
QT_END_NAMESPACE
#endif // QSTORAGEINFO_P_H
diff --git a/src/corelib/io/qstorageinfo_stub.cpp b/src/corelib/io/qstorageinfo_stub.cpp
new file mode 100644
index 0000000000..f2f7d2eb65
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_stub.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qstorageinfo_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QStorageInfoPrivate::initRootPath()
+{
+ Q_UNIMPLEMENTED();
+ rootPath = QString();
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ Q_UNIMPLEMENTED();
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ Q_UNIMPLEMENTED();
+ return QList<QStorageInfo>();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 2b635f63bb..9df098a389 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstorageinfo_p.h"
-#include <QtCore/qdiriterator.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qtextstream.h>
@@ -54,11 +17,7 @@
#if defined(Q_OS_BSD4)
# include <sys/mount.h>
# include <sys/statvfs.h>
-#elif defined(Q_OS_ANDROID)
-# include <sys/mount.h>
-# include <sys/vfs.h>
-# include <mntent.h>
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
+#elif defined(Q_OS_HURD)
# include <mntent.h>
# include <sys/statvfs.h>
# include <sys/sysmacros.h>
@@ -91,12 +50,6 @@
# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)
# define _STATFS_F_FLAGS 1
# endif
-#elif defined(Q_OS_ANDROID)
-# define QT_STATFS ::statfs
-# define QT_STATFSBUF struct statfs
-# if !defined(ST_RDONLY)
-# define ST_RDONLY 1 // hack for missing define on Android
-# endif
#elif defined(Q_OS_HAIKU)
# define QT_STATFSBUF struct statvfs
# define QT_STATFS ::statvfs
@@ -119,6 +72,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QStorageIterator
{
public:
@@ -140,43 +95,10 @@ private:
#elif defined(Q_OS_SOLARIS)
FILE *fp;
mnttab mnt;
-#elif defined(Q_OS_ANDROID)
- QFile file;
- QByteArray m_rootPath;
- QByteArray m_fileSystemType;
- QByteArray m_device;
- QByteArray m_options;
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
- struct mountinfoent : public mntent {
- // Details from proc(5) section from /proc/<pid>/mountinfo:
- //(1) mount ID: a unique ID for the mount (may be reused after umount(2)).
- int mount_id;
- //(2) parent ID: the ID of the parent mount (or of self for the top of the mount tree).
-// int parent_id;
- //(3) major:minor: the value of st_dev for files on this filesystem (see stat(2)).
- dev_t rdev;
- //(4) root: the pathname of the directory in the filesystem which forms the root of this mount.
- char *subvolume;
- //(5) mount point: the pathname of the mount point relative to the process's root directory.
-// char *mnt_dir; // in mntent
- //(6) mount options: per-mount options.
-// char *mnt_opts; // in mntent
- //(7) optional fields: zero or more fields of the form "tag[:value]"; see below.
-// int flags;
- //(8) separator: the end of the optional fields is marked by a single hyphen.
-
- //(9) filesystem type: the filesystem type in the form "type[.subtype]".
-// char *mnt_type; // in mntent
- //(10) mount source: filesystem-specific information or "none".
-// char *mnt_fsname; // in mntent
- //(11) super options: per-superblock options.
- char *superopts;
- };
-
+#elif defined(Q_OS_HURD)
FILE *fp;
QByteArray buffer;
mountinfoent mnt;
- bool usingMountinfo;
#elif defined(Q_OS_HAIKU)
BVolumeRoster m_volumeRoster;
@@ -186,51 +108,6 @@ private:
#endif
};
-template <typename String>
-static bool isParentOf(const String &parent, const QString &dirName)
-{
- return dirName.startsWith(parent) &&
- (dirName.size() == parent.size() || dirName.at(parent.size()) == QLatin1Char('/') ||
- parent.size() == 1);
-}
-
-static bool shouldIncludeFs(const QStorageIterator &it)
-{
- /*
- * This function implements a heuristic algorithm to determine whether a
- * given mount should be reported to the user. Our objective is to list
- * only entries that the end-user would find useful.
- *
- * We therefore ignore:
- * - mounted in /dev, /proc, /sys: special mounts
- * (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts,
- * some of which are tmpfs on Linux)
- * - mounted in /var/run or /var/lock: most likely pseudofs
- * (on earlier systemd versions, /var/run was a bind-mount of /run, so
- * everything would be unnecessarily duplicated)
- * - filesystem type is "rootfs": artifact of the root-pivot on some Linux
- * initrd
- * - if the filesystem total size is zero, it's a pseudo-fs (not checked here).
- */
-
- QString mountDir = it.rootPath();
- if (isParentOf(QLatin1String("/dev"), mountDir)
- || isParentOf(QLatin1String("/proc"), mountDir)
- || isParentOf(QLatin1String("/sys"), mountDir)
- || isParentOf(QLatin1String("/var/run"), mountDir)
- || isParentOf(QLatin1String("/var/lock"), mountDir)) {
- return false;
- }
-
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
- if (it.fileSystemType() == "rootfs")
- return false;
-#endif
-
- // size checking in mountedVolumes()
- return true;
-}
-
#if defined(Q_OS_BSD4)
#ifndef MNT_NOWAIT
@@ -324,67 +201,8 @@ inline QByteArray QStorageIterator::subvolume() const
{
return QByteArray();
}
-#elif defined(Q_OS_ANDROID)
-
-inline QStorageIterator::QStorageIterator()
-{
- file.setFileName(QString::fromUtf8(_PATH_MOUNTED));
- file.open(QIODevice::ReadOnly | QIODevice::Text);
-}
-
-inline QStorageIterator::~QStorageIterator()
-{
-}
-
-inline bool QStorageIterator::isValid() const
-{
- return file.isOpen();
-}
-
-inline bool QStorageIterator::next()
-{
- QList<QByteArray> data;
- // If file is virtual, file.readLine() may succeed even when file.atEnd().
- do {
- const QByteArray line = file.readLine();
- if (line.isEmpty() && file.atEnd())
- return false;
- data = line.split(' ');
- } while (data.count() < 4);
-
- m_device = data.at(0);
- m_rootPath = data.at(1);
- m_fileSystemType = data.at(2);
- m_options = data.at(3);
-
- return true;
-}
-
-inline QString QStorageIterator::rootPath() const
-{
- return QFile::decodeName(m_rootPath);
-}
-
-inline QByteArray QStorageIterator::fileSystemType() const
-{
- return m_fileSystemType;
-}
-
-inline QByteArray QStorageIterator::device() const
-{
- return m_device;
-}
-
-inline QByteArray QStorageIterator::options() const
-{
- return m_options;
-}
-inline QByteArray QStorageIterator::subvolume() const
-{
- return QByteArray();
-}
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
+#elif defined(Q_OS_HURD)
static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo;
// should be enough
@@ -392,28 +210,13 @@ static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo
inline QStorageIterator::QStorageIterator() :
buffer(QByteArray(bufferSize, 0))
{
- fp = nullptr;
-
-#ifdef Q_OS_LINUX
- // first, try to open /proc/self/mountinfo, which has more details
- fp = ::fopen("/proc/self/mountinfo", "re");
-#endif
- if (fp) {
- usingMountinfo = true;
- } else {
- usingMountinfo = false;
- fp = ::setmntent(_PATH_MOUNTED, "r");
- }
+ fp = ::setmntent(_PATH_MOUNTED, "r");
}
inline QStorageIterator::~QStorageIterator()
{
- if (fp) {
- if (usingMountinfo)
- ::fclose(fp);
- else
- ::endmntent(fp);
- }
+ if (fp)
+ ::endmntent(fp);
}
inline bool QStorageIterator::isValid() const
@@ -423,137 +226,7 @@ inline bool QStorageIterator::isValid() const
inline bool QStorageIterator::next()
{
- mnt.subvolume = nullptr;
- mnt.superopts = nullptr;
- if (!usingMountinfo)
- return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
-
- // Helper function to parse paths that the kernel inserts escape sequences
- // for. The unescaped string is left at \a src and is properly
- // NUL-terminated. Returns a pointer to the delimiter that terminated the
- // path, or nullptr if it failed.
- auto parseMangledPath = [](char *src) {
- // The kernel escapes with octal the following characters:
- // space ' ', tab '\t', backslask '\\', and newline '\n'
- char *dst = src;
- while (*src) {
- switch (*src) {
- case ' ':
- // Unescaped space: end of the field.
- *dst = '\0';
- return src;
-
- default:
- *dst++ = *src++;
- break;
-
- case '\\':
- // It always uses exactly three octal characters.
- ++src;
- char c = (*src++ - '0') << 6;
- c |= (*src++ - '0') << 3;
- c |= (*src++ - '0');
- *dst++ = c;
- break;
- }
- }
-
- // Found a NUL before the end of the field.
- src = nullptr;
- return src;
- };
-
- char *ptr = buffer.data();
- if (fgets(ptr, buffer.size(), fp) == nullptr)
- return false;
-
- size_t len = strlen(ptr);
- if (len == 0)
- return false;
- while (Q_UNLIKELY(ptr[len - 1] != '\n' && !feof(fp))) {
- // buffer wasn't large enough. Enlarge and try again.
- // (we're readidng from the kernel, so OOM is unlikely)
- buffer.resize((buffer.size() + 4096) & ~4095);
- ptr = buffer.data();
- if (fgets(ptr + len, buffer.size() - len, fp) == nullptr)
- return false;
-
- len += strlen(ptr + len);
- Q_ASSERT(len < size_t(buffer.size()));
- }
- ptr[len - 1] = '\0';
- const char *const stop = ptr + len - 1;
-
- // parse the line
- bool ok;
- mnt.mnt_freq = 0;
- mnt.mnt_passno = 0;
-
- mnt.mount_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
- return false;
-
- int parent_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- Q_UNUSED(parent_id);
- if (!ok)
- return false;
-
- int rdevmajor = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
- return false;
- if (*ptr != ':')
- return false;
- int rdevminor = qstrntoll(ptr + 1, stop - ptr - 1, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
- return false;
- mnt.rdev = makedev(rdevmajor, rdevminor);
-
- if (*ptr != ' ')
- return false;
-
- mnt.subvolume = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- // unset a subvolume of "/" -- it's not a *sub* volume
- if (mnt.subvolume + 1 == ptr)
- *mnt.subvolume = '\0';
-
- mnt.mnt_dir = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- mnt.mnt_opts = ++ptr;
- ptr = strchr(ptr, ' ');
- if (!ptr)
- return false;
-
- // we don't parse the flags, so just find the separator
- if (char *const dashed = strstr(ptr, " - ")) {
- *ptr = '\0';
- ptr = dashed + strlen(" - ") - 1;
- } else {
- return false;
- }
-
- mnt.mnt_type = ++ptr;
- ptr = strchr(ptr, ' ');
- if (!ptr)
- return false;
- *ptr = '\0';
-
- mnt.mnt_fsname = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- mnt.superopts = ++ptr;
- ptr += strcspn(ptr, " \n");
- *ptr = '\0';
-
- return true;
+ return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
}
inline QString QStorageIterator::rootPath() const
@@ -568,49 +241,17 @@ inline QByteArray QStorageIterator::fileSystemType() const
inline QByteArray QStorageIterator::device() const
{
-#ifdef Q_OS_LINUX
- // check that the device exists
- if (mnt.mnt_fsname[0] == '/' && access(mnt.mnt_fsname, F_OK) != 0) {
- // It doesn't, so let's try to resolve the dev_t from /dev/block.
- // Note how strlen("4294967295") == digits10 + 1, so we need to add 1
- // for each number, plus the ':'.
- char buf[sizeof("/dev/block/") + 2 * std::numeric_limits<unsigned>::digits10 + 3];
- QByteArray dev(PATH_MAX, Qt::Uninitialized);
- char *devdata = dev.data();
-
- snprintf(buf, sizeof(buf), "/dev/block/%u:%u", major(mnt.rdev), minor(mnt.rdev));
- if (realpath(buf, devdata)) {
- dev.truncate(strlen(devdata));
- return dev;
- }
- }
-#endif
return QByteArray(mnt.mnt_fsname);
}
inline QByteArray QStorageIterator::options() const
{
- // Merge the two options, starting with the superblock options and letting
- // the per-mount options override.
- const char *superopts = mnt.superopts;
-
- // Both mnt_opts and superopts start with "ro" or "rw", so we can skip the
- // superblock's field (see show_mountinfo() in fs/proc_namespace.c).
- if (superopts && superopts[0] == 'r') {
- if (superopts[2] == '\0') // no other superopts besides "ro" / "rw"?
- superopts = nullptr;
- else if (superopts[2] == ',')
- superopts += 3;
- }
-
- if (superopts)
- return QByteArray(superopts) + ',' + mnt.mnt_opts;
return QByteArray(mnt.mnt_opts);
}
inline QByteArray QStorageIterator::subvolume() const
{
- return QByteArray(mnt.subvolume);
+ return QByteArray();
}
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
@@ -678,6 +319,7 @@ inline QByteArray QStorageIterator::subvolume() const
{
return QByteArray();
}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -724,84 +366,9 @@ inline QByteArray QStorageIterator::subvolume() const
}
#endif
-void QStorageInfoPrivate::initRootPath()
-{
- rootPath = QFileInfo(rootPath).canonicalFilePath();
-
- if (rootPath.isEmpty())
- return;
-
- QStorageIterator it;
- if (!it.isValid()) {
- rootPath = QStringLiteral("/");
- return;
- }
-
- int maxLength = 0;
- const QString oldRootPath = rootPath;
- rootPath.clear();
-
- while (it.next()) {
- const QString mountDir = it.rootPath();
- const QByteArray fsName = it.fileSystemType();
- // we try to find most suitable entry
- if (isParentOf(mountDir, oldRootPath) && maxLength < mountDir.length()) {
- maxLength = mountDir.length();
- rootPath = mountDir;
- device = it.device();
- fileSystemType = fsName;
- subvolume = it.subvolume();
- }
- }
-}
-
-#ifdef Q_OS_LINUX
-// udev encodes the labels with ID_LABEL_FS_ENC which is done with
-// blkid_encode_string(). Within this function some 1-byte utf-8
-// characters not considered safe (e.g. '\' or ' ') are encoded as hex
-static QString decodeFsEncString(const QString &str)
-{
- QString decoded;
- decoded.reserve(str.size());
-
- int i = 0;
- while (i < str.size()) {
- if (i <= str.size() - 4) { // we need at least four characters \xAB
- if (str.at(i) == QLatin1Char('\\') &&
- str.at(i+1) == QLatin1Char('x')) {
- bool bOk;
- const int code = QStringView{str}.mid(i+2, 2).toInt(&bOk, 16);
- // only decode characters between 0x20 and 0x7f but not
- // the backslash to prevent collisions
- if (bOk && code >= 0x20 && code < 0x80 && code != '\\') {
- decoded += QChar(code);
- i += 4;
- continue;
- }
- }
- }
- decoded += str.at(i);
- ++i;
- }
- return decoded;
-}
-#endif
-
static inline QString retrieveLabel(const QByteArray &device)
{
-#ifdef Q_OS_LINUX
- static const char pathDiskByLabel[] = "/dev/disk/by-label";
-
- QFileInfo devinfo(QFile::decodeName(device));
- QString devicePath = devinfo.canonicalFilePath();
-
- QDirIterator it(QLatin1String(pathDiskByLabel), QDir::NoDotAndDotDot);
- while (it.hasNext()) {
- QFileInfo fileInfo = it.nextFileInfo();
- if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
- return decodeFsEncString(fileInfo.fileName());
- }
-#elif defined Q_OS_HAIKU
+#if defined Q_OS_HAIKU
fs_info fsInfo;
memset(&fsInfo, 0, sizeof(fsInfo));
@@ -835,7 +402,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
{
QT_STATFSBUF statfs_buf;
int result;
- EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
+ QT_EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
if (result == 0) {
valid = true;
ready = true;
@@ -849,7 +416,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
#endif
- blockSize = statfs_buf.f_bsize;
+ blockSize = int(statfs_buf.f_bsize);
#if defined(Q_OS_ANDROID) || defined(Q_OS_BSD4) || defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)
#if defined(_STATFS_F_FLAGS)
readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
@@ -860,6 +427,37 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
}
}
+void QStorageInfoPrivate::initRootPath()
+{
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ QStorageIterator it;
+ if (!it.isValid()) {
+ rootPath = QStringLiteral("/");
+ return;
+ }
+
+ int maxLength = 0;
+ const QString oldRootPath = rootPath;
+ rootPath.clear();
+
+ while (it.next()) {
+ const QString mountDir = it.rootPath();
+ const QByteArray fsName = it.fileSystemType();
+ // we try to find most suitable entry
+ if (maxLength < mountDir.size() && isParentOf(mountDir, oldRootPath)) {
+ maxLength = mountDir.size();
+ rootPath = mountDir;
+ device = it.device();
+ fileSystemType = fsName;
+ subvolume = it.subvolume();
+ }
+ }
+}
+
QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
{
QStorageIterator it;
@@ -869,7 +467,7 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
QList<QStorageInfo> volumes;
while (it.next()) {
- if (!shouldIncludeFs(it))
+ if (!shouldIncludeFs(it.rootPath(), it.fileSystemType()))
continue;
const QString mountDir = it.rootPath();
@@ -877,7 +475,7 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
info.d->device = it.device();
info.d->fileSystemType = it.fileSystemType();
info.d->subvolume = it.subvolume();
- if (info.bytesTotal() == 0 && info != root())
+ if (info.bytesTotal() <= 0 && info != root())
continue;
volumes.append(info);
}
@@ -885,9 +483,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QStringLiteral("/"));
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
index d594551425..3ee1df9f3c 100644
--- a/src/corelib/io/qstorageinfo_win.cpp
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstorageinfo_p.h"
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const int defaultBufferSize = MAX_PATH + 1;
static QString canonicalPath(const QString &rootPath)
@@ -59,16 +25,16 @@ static QString canonicalPath(const QString &rootPath)
if (path.isEmpty())
return path;
- if (path.startsWith(QLatin1String("\\\\?\\")))
+ if (path.startsWith("\\\\?\\"_L1))
path.remove(0, 4);
- if (path.length() < 2 || path.at(1) != QLatin1Char(':'))
+ if (path.length() < 2 || path.at(1) != u':')
return QString();
path[0] = path[0].toUpper();
if (!(path.at(0).unicode() >= 'A' && path.at(0).unicode() <= 'Z'))
return QString();
- if (!path.endsWith(QLatin1Char('\\')))
- path.append(QLatin1Char('\\'));
+ if (!path.endsWith(u'\\'))
+ path.append(u'\\');
return path;
}
@@ -204,11 +170,6 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
-}
-
bool QStorageInfoPrivate::queryStorageProperty()
{
QString path = QDir::toNativeSeparators(uR"(\\.\)" + rootPath);
@@ -242,14 +203,14 @@ bool QStorageInfoPrivate::queryStorageProperty()
nullptr);
CloseHandle(handle);
if (result)
- blockSize = saad.BytesPerPhysicalSector;
+ blockSize = int(saad.BytesPerPhysicalSector);
return result;
}
struct Helper
{
QBasicMutex mutex;
- QSystemLibrary ntdll {u"ntdll"_qs};
+ QSystemLibrary ntdll {u"ntdll"_s};
};
Q_GLOBAL_STATIC(Helper, gNtdllHelper)
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index db35256704..8187524067 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -1,50 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtemporarydir.h"
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "qdebug.h"
-#include "qdiriterator.h"
-#include "qpair.h"
#include "qplatformdefs.h"
#include "qrandom.h"
#include "private/qtemporaryfile_p.h"
@@ -57,8 +19,15 @@
#include <errno.h>
#endif
+#include <type_traits>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static_assert(std::is_nothrow_move_constructible_v<QTemporaryDir>);
+static_assert(std::is_nothrow_move_assignable_v<QTemporaryDir>);
+
//************* QTemporaryDirPrivate
class QTemporaryDirPrivate
{
@@ -90,9 +59,9 @@ static QString defaultTemplateName()
baseName = QCoreApplication::applicationName();
if (baseName.isEmpty())
#endif
- baseName = QLatin1String("qt_temp");
+ baseName = "qt_temp"_L1;
- return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX");
+ return QDir::tempPath() + u'/' + baseName + "-XXXXXX"_L1;
}
void QTemporaryDirPrivate::create(const QString &templateName)
@@ -198,6 +167,39 @@ QTemporaryDir::QTemporaryDir(const QString &templatePath)
}
/*!
+ \fn QTemporaryDir::QTemporaryDir(QTemporaryDir &&other)
+
+ Move-constructs a new QTemporaryDir from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.4
+*/
+
+/*!
+ \fn QTemporaryDir &QTemporaryDir::operator=(QTemporaryDir&& other)
+
+ Move-assigns \a other to this QTemporaryDir instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.4
+*/
+
+/*!
+ \fn void QTemporaryDir::swap(QTemporaryDir &other)
+
+ Swaps temporary-dir \a other with this temporary-dir. This operation is
+ very fast and never fails.
+
+ \since 6.4
+*/
+
+/*!
Destroys the temporary directory object.
If auto remove mode was set, it will automatically delete the directory
including all its contents.
@@ -206,8 +208,12 @@ QTemporaryDir::QTemporaryDir(const QString &templatePath)
*/
QTemporaryDir::~QTemporaryDir()
{
- if (d_ptr->autoRemove)
- remove();
+ if (d_ptr) {
+ if (d_ptr->autoRemove)
+ remove();
+
+ delete d_ptr;
+ }
}
/*!
@@ -260,7 +266,7 @@ QString QTemporaryDir::filePath(const QString &fileName) const
QString ret = d_ptr->pathOrError;
if (!fileName.isEmpty()) {
- ret += QLatin1Char('/');
+ ret += u'/';
ret += fileName;
}
return ret;
@@ -305,7 +311,7 @@ bool QTemporaryDir::remove()
if (!d_ptr->success)
return false;
Q_ASSERT(!path().isEmpty());
- Q_ASSERT(path() != QLatin1String("."));
+ Q_ASSERT(path() != "."_L1);
const bool result = QDir(path()).removeRecursively();
if (!result) {
@@ -318,4 +324,4 @@ bool QTemporaryDir::remove()
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 5864ce5cfc..8737bf9e26 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -1,52 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEMPORARYDIR_H
#define QTEMPORARYDIR_H
+#include <QtCore/qglobal.h>
#include <QtCore/qdir.h>
#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryDirPrivate;
@@ -55,8 +20,17 @@ class Q_CORE_EXPORT QTemporaryDir
public:
QTemporaryDir();
explicit QTemporaryDir(const QString &templateName);
+ QTemporaryDir(QTemporaryDir &&other) noexcept
+ : d_ptr{std::exchange(other.d_ptr, nullptr)}
+ { }
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QTemporaryDir)
+
~QTemporaryDir();
+ void swap(QTemporaryDir &other) noexcept
+ { qt_ptr_swap(d_ptr, other.d_ptr); }
+
bool isValid() const;
QString errorString() const;
@@ -68,12 +42,17 @@ public:
QString filePath(const QString &fileName) const;
private:
- QScopedPointer<QTemporaryDirPrivate> d_ptr;
+ QTemporaryDirPrivate *d_ptr;
Q_DISABLE_COPY(QTemporaryDir)
};
-#endif // QT_NO_TEMPORARYFILE
+inline void swap(QTemporaryDir &lhs, QTemporaryDir &rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 4b587857a8..4e48a18d91 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtemporaryfile.h"
@@ -59,6 +23,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#if defined(Q_OS_WIN)
typedef ushort Char;
@@ -79,19 +45,19 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
{
// Ensure there is a placeholder mask
QString qfilename = QDir::fromNativeSeparators(templateName);
- uint phPos = qfilename.length();
- uint phLength = 0;
+ qsizetype phPos = qfilename.size();
+ qsizetype phLength = 0;
while (phPos != 0) {
--phPos;
- if (qfilename[phPos] == QLatin1Char('X')) {
+ if (qfilename[phPos] == u'X') {
++phLength;
continue;
}
if (phLength >= 6
- || qfilename[phPos] == QLatin1Char('/')) {
+ || qfilename[phPos] == u'/') {
++phPos;
break;
}
@@ -101,15 +67,14 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
}
if (phLength < 6)
- qfilename.append(QLatin1String(".XXXXXX"));
+ qfilename.append(".XXXXXX"_L1);
// "Nativify" :-)
- QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName(
- QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()))
- .nativeFilePath();
+ QFileSystemEntry::NativePath filename =
+ QFileSystemEntry(QDir::cleanPath(qfilename)).nativeFilePath();
// Find mask in native path
- phPos = filename.length();
+ phPos = filename.size();
phLength = 0;
while (phPos != 0) {
--phPos;
@@ -143,8 +108,8 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
{
Q_ASSERT(length != 0);
- Q_ASSERT(pos < path.length());
- Q_ASSERT(length <= path.length() - pos);
+ Q_ASSERT(pos < path.size());
+ Q_ASSERT(length <= path.size() - pos);
Char *const placeholderStart = (Char *)path.data() + pos;
Char *const placeholderEnd = placeholderStart + length;
@@ -191,13 +156,13 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
return path;
}
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
/*!
\internal
Generates a unique file path from the template \a templ and creates a new
- file based based on those parameters: the \c templ.length characters in \c
+ file based on those parameters: the \c templ.length characters in \c
templ.path starting at \c templ.pos will be replaced by a random sequence of
characters. \a mode specifies the file mode bits (not used on Windows).
@@ -219,8 +184,9 @@ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &t
const DWORD shareMode = (flags & QTemporaryFileEngine::Win32NonShared)
? 0u : (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ const DWORD extraAccessFlags = (flags & QTemporaryFileEngine::Win32NonShared) ? DELETE : 0;
file = CreateFile((const wchar_t *)path.constData(),
- GENERIC_READ | GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE | extraAccessFlags,
shareMode, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
@@ -425,6 +391,18 @@ bool QTemporaryFileEngine::renameOverwrite(const QString &newName)
QFSFileEngine::close();
return ok;
}
+#ifdef Q_OS_WIN
+ if (flags & Win32NonShared) {
+ QFileSystemEntry newEntry(newName, QFileSystemEntry::FromInternalPath());
+ bool ok = d_func()->nativeRenameOverwrite(newEntry);
+ QFSFileEngine::close();
+ if (ok) {
+ // Match what QFSFileEngine::renameOverwrite() does
+ setFileEntry(std::move(newEntry));
+ }
+ return ok;
+ }
+#endif
QFSFileEngine::close();
return QFSFileEngine::renameOverwrite(newName);
}
@@ -440,7 +418,7 @@ bool QTemporaryFileEngine::close()
QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const
{
if (isUnnamedFile()) {
- if (file == AbsoluteLinkTarget) {
+ if (file == AbsoluteLinkTarget || file == RawLinkPath) {
// we know our file isn't (won't be) a symlink
return QString();
}
@@ -576,9 +554,9 @@ QString QTemporaryFilePrivate::defaultTemplateName()
baseName = QCoreApplication::applicationName();
if (baseName.isEmpty())
#endif
- baseName = QLatin1String("qt_temp");
+ baseName = "qt_temp"_L1;
- return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String(".XXXXXX");
+ return QDir::tempPath() + u'/' + baseName + ".XXXXXX"_L1;
}
//************* QTemporaryFile
@@ -620,6 +598,9 @@ QString QTemporaryFilePrivate::defaultTemplateName()
be placed into the temporary path as returned by QDir::tempPath().
If you specify your own filename, a relative file path will not be placed in the
temporary directory by default, but be relative to the current working directory.
+ It is important to specify the correct directory if the rename() function will be
+ called, as QTemporaryFile can only rename files within the same volume / filesystem
+ as the temporary file itself was created on.
Specified filenames can contain the following template \c XXXXXX
(six upper case "X" characters), which will be replaced by the
@@ -662,6 +643,12 @@ QTemporaryFile::QTemporaryFile()
}
/*!
+ \fn QTemporaryFile::QTemporaryFile(const std::filesystem::path &templateName, QObject *parent)
+ \overload
+ \since 6.7
+*/
+
+/*!
Constructs a QTemporaryFile with a template filename of \a
templateName. Upon opening the temporary file this will be used to create
a unique filename.
@@ -671,7 +658,11 @@ QTemporaryFile::QTemporaryFile()
If \a templateName is a relative path, the path will be relative to the
current working directory. You can use QDir::tempPath() to construct \a
- templateName if you want use the system's temporary directory.
+ templateName if you want use the system's temporary directory. It is
+ important to specify the correct directory if the rename() function will be
+ called, as QTemporaryFile can only rename files within the same volume /
+ filesystem as the temporary file itself was created on.
+
\sa open(), fileTemplate()
*/
@@ -704,7 +695,10 @@ QTemporaryFile::QTemporaryFile(QObject *parent)
If \a templateName is a relative path, the path will be relative to the
current working directory. You can use QDir::tempPath() to construct \a
- templateName if you want use the system's temporary directory.
+ templateName if you want use the system's temporary directory. It is
+ important to specify the correct directory if the rename() function will be
+ called, as QTemporaryFile can only rename files within the same volume /
+ filesystem as the temporary file itself was created on.
\sa open(), fileTemplate()
*/
@@ -737,7 +731,7 @@ QTemporaryFile::~QTemporaryFile()
return true upon success and will set the fileName() to the unique
filename used.
- \sa fileName()
+ \sa fileName(), QT_USE_NODISCARD_FILE_OPEN
*/
/*!
@@ -816,6 +810,12 @@ QString QTemporaryFile::fileTemplate() const
}
/*!
+ \fn void QTemporaryFile::setFileTemplate(const std::filesystem::path &name)
+ \overload
+ \since 6.7
+*/
+
+/*!
Sets the static portion of the file name to \a name. If the file
template contains XXXXXX that will automatically be replaced with
the unique part of the filename, otherwise a filename will be
@@ -823,7 +823,10 @@ QString QTemporaryFile::fileTemplate() const
If \a name contains a relative file path, the path will be relative to the
current working directory. You can use QDir::tempPath() to construct \a
- name if you want use the system's temporary directory.
+ name if you want use the system's temporary directory. It is important to
+ specify the correct directory if the rename() function will be called, as
+ QTemporaryFile can only rename files within the same volume / filesystem as
+ the temporary file itself was created on.
\sa fileTemplate()
*/
@@ -834,11 +837,28 @@ void QTemporaryFile::setFileTemplate(const QString &name)
}
/*!
- \internal
+ \fn bool QTemporaryFile::rename(const std::filesystem::path &newName)
+ \overload
+ \since 6.7
+*/
- This is just a simplified version of QFile::rename() because we know a few
- extra details about what kind of file we have. The documentation is hidden
- from the user because QFile::rename() should be enough.
+/*!
+ Renames the current temporary file to \a newName and returns true if it
+ succeeded.
+
+ This function has an important difference compared to QFile::rename(): it
+ will not perform a copy+delete if the low-level system call to rename the
+ file fails, something that could happen if \a newName specifies a file in a
+ different volume or filesystem than the temporary file was created on. In
+ other words, QTemporaryFile only supports atomic file renaming.
+
+ This functionality is intended to support materializing the destination
+ file with all contents already present, so another process cannot see an
+ incomplete file in the process of being written. The \l QSaveFile class can
+ be used for a similar purpose too, particularly if the destination file is
+ not temporary.
+
+ \sa QSaveFile, QSaveFile::commit(), QFile::rename()
*/
bool QTemporaryFile::rename(const QString &newName)
{
@@ -853,7 +873,6 @@ bool QTemporaryFile::rename(const QString &newName)
if (tef->rename(newName)) {
unsetError();
// engine was able to handle the new name so we just reset it
- tef->setFileName(newName);
d->fileName = newName;
return true;
}
@@ -870,7 +889,11 @@ bool QTemporaryFile::rename(const QString &newName)
Works on the given \a fileName rather than an existing QFile
object.
*/
-
+/*!
+ \fn QTemporaryFile *QTemporaryFile::createNativeFile(const std::filesystem::path &fileName)
+ \overload
+ \since 6.7
+*/
/*!
If \a file is not already a native file, then a QTemporaryFile is created
@@ -958,7 +981,7 @@ bool QTemporaryFile::open(OpenMode flags)
return false;
}
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.h b/src/corelib/io/qtemporaryfile.h
index 93f687bc17..9a4476f9d2 100644
--- a/src/corelib/io/qtemporaryfile.h
+++ b/src/corelib/io/qtemporaryfile.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEMPORARYFILE_H
#define QTEMPORARYFILE_H
@@ -50,7 +14,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryFilePrivate;
class QLockFilePrivate;
@@ -68,26 +32,59 @@ public:
#ifndef QT_NO_QOBJECT
explicit QTemporaryFile(QObject *parent);
QTemporaryFile(const QString &templateName, QObject *parent);
-#endif
+
+# if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ explicit QTemporaryFile(const std::filesystem::path &templateName, QObject *parent = nullptr)
+ : QTemporaryFile(QtPrivate::fromFilesystemPath(templateName), parent)
+ {
+ }
+# endif // QT_CONFIG(cxx17_filesystem)
+#endif // !QT_NO_QOBJECT
+
~QTemporaryFile();
bool autoRemove() const;
void setAutoRemove(bool b);
// ### Hides open(flags)
- bool open() { return open(QIODevice::ReadWrite); }
+ QFILE_MAYBE_NODISCARD bool open() { return open(QIODevice::ReadWrite); }
QString fileName() const override;
QString fileTemplate() const;
void setFileTemplate(const QString &name);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ void setFileTemplate(const std::filesystem::path &name)
+ {
+ return setFileTemplate(QtPrivate::fromFilesystemPath(name));
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
// Hides QFile::rename
bool rename(const QString &newName);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ bool rename(const std::filesystem::path &newName)
+ {
+ return rename(QtPrivate::fromFilesystemPath(newName));
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
+
inline static QTemporaryFile *createNativeFile(const QString &fileName)
{ QFile file(fileName); return createNativeFile(file); }
static QTemporaryFile *createNativeFile(QFile &file);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ static QTemporaryFile *createNativeFile(const std::filesystem::path &fileName)
+ {
+ QFile file(fileName);
+ return createNativeFile(file);
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
+
protected:
bool open(OpenMode flags) override;
@@ -97,7 +94,7 @@ private:
Q_DISABLE_COPY(QTemporaryFile)
};
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index ac9c239d21..d160afe41e 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEMPORARYFILE_P_H
#define QTEMPORARYFILE_P_H
@@ -81,7 +45,7 @@ struct QTemporaryFileName
QFileSystemEntry::NativePath generateNext();
};
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryFilePrivate : public QFilePrivate
{
@@ -124,8 +88,7 @@ public:
if (filePathIsTemplate) {
d->fileEntry.clear();
} else {
- d->fileEntry = QFileSystemEntry(file);
- QFSFileEngine::setFileName(file);
+ QFSFileEngine::setFileEntry(QFileSystemEntry(file));
}
}
~QTemporaryFileEngine();
@@ -152,7 +115,7 @@ public:
bool unnamedFile = false;
};
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index bae31c1b6c..4360b5b076 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QUrl
@@ -50,14 +14,18 @@
\ingroup network
\ingroup shared
+ \compares weak
It can parse and construct URLs in both encoded and unencoded
form. QUrl also has support for internationalized domain names
(IDNs).
- The most common way to use QUrl is to initialize it via the
- constructor by passing a QString. Otherwise, setUrl() can also
- be used.
+ The most common way to use QUrl is to initialize it via the constructor by
+ passing a QString containing a full URL. QUrl objects can also be created
+ from a QByteArray containing a full URL using QUrl::fromEncoded(), or
+ heuristically from incomplete URLs using QUrl::fromUserInput(). The URL
+ representation can be obtained from a QUrl using either QUrl::toString() or
+ QUrl::toEncoded().
URLs can be represented in two forms: encoded or unencoded. The
unencoded representation is suitable for showing to users, but
@@ -436,16 +404,17 @@
#include "private/qipaddress_p.h"
#include "qurlquery.h"
#include "private/qdir_p.h"
+#include <private/qtools_p.h>
QT_BEGIN_NAMESPACE
-// in qstring.cpp:
-void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept;
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
inline static bool isHex(char c)
{
c |= 0x20;
- return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
+ return isAsciiDigit(c) || (c >= 'a' && c <= 'f');
}
static inline QString ftpScheme()
@@ -526,8 +495,8 @@ public:
struct Error {
QString source;
+ qsizetype position;
ErrorCode code;
- int position;
};
QUrlPrivate();
@@ -540,11 +509,11 @@ public:
std::unique_ptr<Error> cloneError() const;
void clearError();
- void setError(ErrorCode errorCode, const QString &source, int supplement = -1);
- ErrorCode validityError(QString *source = nullptr, int *position = nullptr) const;
- bool validateComponent(Section section, const QString &input, int begin, int end);
+ void setError(ErrorCode errorCode, const QString &source, qsizetype supplement = -1);
+ ErrorCode validityError(QString *source = nullptr, qsizetype *position = nullptr) const;
+ bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end);
bool validateComponent(Section section, const QString &input)
- { return validateComponent(section, input, 0, uint(input.length())); }
+ { return validateComponent(section, input, 0, input.size()); }
// no QString scheme() const;
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
@@ -557,15 +526,15 @@ public:
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
// the "end" parameters are like STL iterators: they point to one past the last valid element
- bool setScheme(const QString &value, int len, bool doSetError);
- void setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode);
- void setUserInfo(const QString &userInfo, int from, int end);
- void setUserName(const QString &value, int from, int end);
- void setPassword(const QString &value, int from, int end);
- bool setHost(const QString &value, int from, int end, QUrl::ParsingMode mode);
- void setPath(const QString &value, int from, int end);
- void setQuery(const QString &value, int from, int end);
- void setFragment(const QString &value, int from, int end);
+ bool setScheme(const QString &value, qsizetype len, bool doSetError);
+ void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
+ void setUserInfo(const QString &userInfo, qsizetype from, qsizetype end);
+ void setUserName(const QString &value, qsizetype from, qsizetype end);
+ void setPassword(const QString &value, qsizetype from, qsizetype end);
+ bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
+ void setPath(const QString &value, qsizetype from, qsizetype end);
+ void setQuery(const QString &value, qsizetype from, qsizetype end);
+ void setFragment(const QString &value, qsizetype from, qsizetype end);
inline bool hasScheme() const { return sectionIsPresent & Scheme; }
inline bool hasAuthority() const { return sectionIsPresent & Authority; }
@@ -642,7 +611,7 @@ inline void QUrlPrivate::clearError()
error.reset();
}
-inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, int supplement)
+inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, qsizetype supplement)
{
if (error) {
// don't overwrite an error set in a previous section during parsing
@@ -833,11 +802,11 @@ static const ushort * const fragmentInUrl = userNameInUrl + 6;
static inline void parseDecodedComponent(QString &data)
{
- data.replace(QLatin1Char('%'), QLatin1String("%25"));
+ data.replace(u'%', "%25"_L1);
}
static inline QString
-recodeFromUser(const QString &input, const ushort *actions, int from, int to)
+recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsizetype to)
{
QString output;
const QChar *begin = input.constData() + from;
@@ -853,14 +822,16 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to)
static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
const ushort *actions)
{
- // Test ComponentFormattingOptions, ignore FormattingOptions.
- if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
+ // The stored value is already QUrl::PrettyDecoded, so there's nothing to
+ // do if that's what the user asked for (test only
+ // ComponentFormattingOptions, ignore FormattingOptions).
+ if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
+ !qt_urlRecode(appendTo, value, options, actions))
appendTo += value;
- return;
- }
- if (!qt_urlRecode(appendTo, value, options, actions))
- appendTo += value;
+ // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
+ if (appendTo.isNull() && !value.isNull())
+ appendTo.detach();
}
inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
@@ -870,11 +841,11 @@ inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOpti
// add '@' only if we added anything
if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
- appendTo += QLatin1Char('@');
+ appendTo += u'@';
}
appendHost(appendTo, options);
if (!(options & QUrl::RemovePort) && port != -1)
- appendTo += QLatin1Char(':') + QString::number(port);
+ appendTo += u':' + QString::number(port);
}
inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
@@ -916,7 +887,7 @@ inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptio
if (options & QUrl::RemovePassword || !hasPassword()) {
return;
} else {
- appendTo += QLatin1Char(':');
+ appendTo += u':';
if (!qt_urlRecode(appendTo, password, options, passwordActions))
appendTo += password;
}
@@ -945,14 +916,14 @@ inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions o
QStringView thePathView(thePath);
if (options & QUrl::RemoveFilename) {
- const int slash = path.lastIndexOf(QLatin1Char('/'));
+ const qsizetype slash = path.lastIndexOf(u'/');
if (slash == -1)
return;
thePathView = QStringView{path}.left(slash + 1);
}
// check if we need to remove trailing slashes
if (options & QUrl::StripTrailingSlash) {
- while (thePathView.length() > 1 && thePathView.endsWith(QLatin1Char('/')))
+ while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
thePathView.chop(1);
}
@@ -975,7 +946,7 @@ inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions
// setXXX functions
-inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetError)
+inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doSetError)
{
// schemes are strictly RFC-compliant:
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
@@ -991,17 +962,17 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro
sectionIsPresent |= Scheme;
// validate it:
- int needsLowercasing = -1;
+ qsizetype needsLowercasing = -1;
const ushort *p = reinterpret_cast<const ushort *>(value.data());
- for (int i = 0; i < len; ++i) {
- if (p[i] >= 'a' && p[i] <= 'z')
+ for (qsizetype i = 0; i < len; ++i) {
+ if (isAsciiLower(p[i]))
continue;
- if (p[i] >= 'A' && p[i] <= 'Z') {
+ if (isAsciiUpper(p[i])) {
needsLowercasing = i;
continue;
}
if (i) {
- if (p[i] >= '0' && p[i] <= '9')
+ if (isAsciiDigit(p[i]))
continue;
if (p[i] == '+' || p[i] == '-' || p[i] == '.')
continue;
@@ -1020,9 +991,9 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro
if (needsLowercasing != -1) {
// schemes are ASCII only, so we don't need the full Unicode toLower
QChar *schemeData = scheme.data(); // force detaching here
- for (int i = needsLowercasing; i >= 0; --i) {
+ for (qsizetype i = needsLowercasing; i >= 0; --i) {
ushort c = schemeData[i].unicode();
- if (c >= 'A' && c <= 'Z')
+ if (isAsciiUpper(c))
schemeData[i] = QChar(c + 0x20);
}
}
@@ -1040,7 +1011,7 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro
return true;
}
-inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode)
+inline void QUrlPrivate::setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
{
sectionIsPresent &= ~Authority;
sectionIsPresent |= Host;
@@ -1048,33 +1019,33 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
// we never actually _loop_
while (from != end) {
- int userInfoIndex = auth.indexOf(QLatin1Char('@'), from);
- if (uint(userInfoIndex) < uint(end)) {
+ qsizetype userInfoIndex = auth.indexOf(u'@', from);
+ if (size_t(userInfoIndex) < size_t(end)) {
setUserInfo(auth, from, userInfoIndex);
if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
break;
from = userInfoIndex + 1;
}
- int colonIndex = auth.lastIndexOf(QLatin1Char(':'), end - 1);
+ qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
if (colonIndex < from)
colonIndex = -1;
- if (uint(colonIndex) < uint(end)) {
+ if (size_t(colonIndex) < size_t(end)) {
if (auth.at(from).unicode() == '[') {
// check if colonIndex isn't inside the "[...]" part
- int closingBracket = auth.indexOf(QLatin1Char(']'), from);
- if (uint(closingBracket) > uint(colonIndex))
+ qsizetype closingBracket = auth.indexOf(u']', from);
+ if (size_t(closingBracket) > size_t(colonIndex))
colonIndex = -1;
}
}
- if (uint(colonIndex) < uint(end) - 1) {
+ if (size_t(colonIndex) < size_t(end) - 1) {
// found a colon with digits after it
unsigned long x = 0;
- for (int i = colonIndex + 1; i < end; ++i) {
+ for (qsizetype i = colonIndex + 1; i < end; ++i) {
ushort c = auth.at(i).unicode();
- if (c >= '0' && c <= '9') {
+ if (isAsciiDigit(c)) {
x *= 10;
x += c - '0';
} else {
@@ -1091,8 +1062,8 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
}
}
- setHost(auth, from, qMin<uint>(end, colonIndex), mode);
- if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<uint>(end, colonIndex))) {
+ setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
+ if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
// clear host too
sectionIsPresent &= ~Authority;
break;
@@ -1109,12 +1080,12 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
port = -1;
}
-inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end)
+inline void QUrlPrivate::setUserInfo(const QString &userInfo, qsizetype from, qsizetype end)
{
- int delimIndex = userInfo.indexOf(QLatin1Char(':'), from);
- setUserName(userInfo, from, qMin<uint>(delimIndex, end));
+ qsizetype delimIndex = userInfo.indexOf(u':', from);
+ setUserName(userInfo, from, qMin<size_t>(delimIndex, end));
- if (uint(delimIndex) >= uint(end)) {
+ if (size_t(delimIndex) >= size_t(end)) {
password.clear();
sectionIsPresent &= ~Password;
} else {
@@ -1122,31 +1093,31 @@ inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end)
}
}
-inline void QUrlPrivate::setUserName(const QString &value, int from, int end)
+inline void QUrlPrivate::setUserName(const QString &value, qsizetype from, qsizetype end)
{
sectionIsPresent |= UserName;
userName = recodeFromUser(value, userNameInIsolation, from, end);
}
-inline void QUrlPrivate::setPassword(const QString &value, int from, int end)
+inline void QUrlPrivate::setPassword(const QString &value, qsizetype from, qsizetype end)
{
sectionIsPresent |= Password;
password = recodeFromUser(value, passwordInIsolation, from, end);
}
-inline void QUrlPrivate::setPath(const QString &value, int from, int end)
+inline void QUrlPrivate::setPath(const QString &value, qsizetype from, qsizetype end)
{
// sectionIsPresent |= Path; // not used, save some cycles
path = recodeFromUser(value, pathInIsolation, from, end);
}
-inline void QUrlPrivate::setFragment(const QString &value, int from, int end)
+inline void QUrlPrivate::setFragment(const QString &value, qsizetype from, qsizetype end)
{
sectionIsPresent |= Fragment;
fragment = recodeFromUser(value, fragmentInIsolation, from, end);
}
-inline void QUrlPrivate::setQuery(const QString &value, int from, int iend)
+inline void QUrlPrivate::setQuery(const QString &value, qsizetype from, qsizetype iend)
{
sectionIsPresent |= Query;
query = recodeFromUser(value, queryInIsolation, from, iend);
@@ -1216,16 +1187,14 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar
const QChar *const origBegin = begin;
if (begin[3].unicode() != '.')
return &begin[3];
- if ((begin[2].unicode() >= 'A' && begin[2].unicode() <= 'F') ||
- (begin[2].unicode() >= 'a' && begin[2].unicode() <= 'f') ||
- (begin[2].unicode() >= '0' && begin[2].unicode() <= '9')) {
+ if (isHexDigit(begin[2].unicode())) {
// this is so unlikely that we'll just go down the slow path
// decode the whole string, skipping the "[vH." and "]" which we already know to be there
host += QStringView(begin, 4);
// uppercase the version, if necessary
if (begin[2].unicode() >= 'a')
- host[host.length() - 2] = QChar{begin[2].unicode() - 0x20};
+ host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
begin += 4;
--end;
@@ -1237,18 +1206,14 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar
}
for ( ; begin != end; ++begin) {
- if (begin->unicode() >= 'A' && begin->unicode() <= 'Z')
- host += *begin;
- else if (begin->unicode() >= 'a' && begin->unicode() <= 'z')
- host += *begin;
- else if (begin->unicode() >= '0' && begin->unicode() <= '9')
+ if (isAsciiLetterOrNumber(begin->unicode()))
host += *begin;
else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != nullptr)
host += *begin;
else
return decoded.isEmpty() ? begin : &origBegin[2];
}
- host += QLatin1Char(']');
+ host += u']';
return nullptr;
}
return &origBegin[2];
@@ -1270,7 +1235,7 @@ static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end
QIPAddressUtils::IPv6Address address;
QStringView zoneId;
- int zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
+ qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
decoded.truncate(zoneIdPosition);
@@ -1290,23 +1255,24 @@ static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end
return begin + (ret - decoded.constBegin());
host.reserve(host.size() + (end - begin) + 2); // +2 for the brackets
- host += QLatin1Char('[');
+ host += u'[';
QIPAddressUtils::toString(host, address);
if (!zoneId.isEmpty()) {
host += zoneIdIdentifier;
host += zoneId;
}
- host += QLatin1Char(']');
+ host += u']';
return nullptr;
}
-inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl::ParsingMode mode)
+inline bool
+QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl::ParsingMode mode)
{
const QChar *begin = value.constData() + from;
const QChar *end = value.constData() + iend;
- const int len = end - begin;
+ const qsizetype len = end - begin;
host.clear();
sectionIsPresent |= Host;
if (len == 0)
@@ -1367,14 +1333,14 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl:
if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { }, nullptr)) {
// something was decoded
// anything encoded left?
- int pos = s.indexOf(QChar(0x25)); // '%'
+ qsizetype pos = s.indexOf(QChar(0x25)); // '%'
if (pos != -1) {
setError(InvalidRegNameError, s, pos);
return false;
}
// recurse
- return setHost(s, 0, s.length(), QUrl::StrictMode);
+ return setHost(s, 0, s.size(), QUrl::StrictMode);
}
s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
@@ -1407,15 +1373,15 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
clearError();
// find the important delimiters
- int colon = -1;
- int question = -1;
- int hash = -1;
- const int len = url.length();
+ qsizetype colon = -1;
+ qsizetype question = -1;
+ qsizetype hash = -1;
+ const qsizetype len = url.size();
const QChar *const begin = url.constData();
const ushort *const data = reinterpret_cast<const ushort *>(begin);
- for (int i = 0; i < len; ++i) {
- uint uc = data[i];
+ for (qsizetype i = 0; i < len; ++i) {
+ size_t uc = data[i];
if (uc == '#' && hash == -1) {
hash = i;
@@ -1432,7 +1398,7 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
}
// check if we have a scheme
- int hierStart;
+ qsizetype hierStart;
if (colon != -1 && setScheme(url, colon, /* don't set error */ false)) {
hierStart = colon + 1;
} else {
@@ -1442,12 +1408,12 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
hierStart = 0;
}
- int pathStart;
- int hierEnd = qMin<uint>(qMin<uint>(question, hash), len);
+ qsizetype pathStart;
+ qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') {
// we have an authority, it ends at the first slash after these
- int authorityEnd = hierEnd;
- for (int i = hierStart + 2; i < authorityEnd ; ++i) {
+ qsizetype authorityEnd = hierEnd;
+ for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
if (data[i] == '/') {
authorityEnd = i;
break;
@@ -1472,8 +1438,8 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
path.clear();
}
- if (uint(question) < uint(hash))
- setQuery(url, question + 1, qMin<uint>(hash, len));
+ if (size_t(question) < size_t(hash))
+ setQuery(url, question + 1, qMin<size_t>(hash, len));
if (hash != -1)
setFragment(url, hash + 1, len);
@@ -1489,7 +1455,7 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
if (!validateComponent(Path, url, pathStart, hierEnd))
return;
- if (uint(question) < uint(hash) && !validateComponent(Query, url, question + 1, qMin<uint>(hash, len)))
+ if (size_t(question) < size_t(hash) && !validateComponent(Query, url, question + 1, qMin<size_t>(hash, len)))
return;
if (hash != -1)
validateComponent(Fragment, url, hash + 1, len);
@@ -1503,19 +1469,19 @@ QString QUrlPrivate::toLocalFile(QUrl::FormattingOptions options) const
// magic for shared drive on windows
if (!host.isEmpty()) {
- tmp = QLatin1String("//") + host;
+ tmp = "//"_L1 + host;
#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only.
if (scheme == webDavScheme())
tmp += webDavSslTag();
#endif
- if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/')))
- tmp += QLatin1Char('/');
+ if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
+ tmp += u'/';
tmp += ourPath;
} else {
tmp = ourPath;
#ifdef Q_OS_WIN
// magic for drives on windows
- if (ourPath.length() > 2 && ourPath.at(0) == QLatin1Char('/') && ourPath.at(2) == QLatin1Char(':'))
+ if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
tmp.remove(0, 1);
#endif
}
@@ -1536,7 +1502,7 @@ inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
// path, then return a string consisting of "/" concatenated with
// the reference's path; otherwise,
if (!host.isEmpty() && path.isEmpty())
- return QLatin1Char('/') + relativePath;
+ return u'/' + relativePath;
// Return a string consisting of the reference's path component
// appended to all but the last segment of the base URI's path
@@ -1544,10 +1510,10 @@ inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
// base URI path, or excluding the entire base URI path if it does
// not contain any "/" characters).
QString newPath;
- if (!path.contains(QLatin1Char('/')))
+ if (!path.contains(u'/'))
newPath = relativePath;
else
- newPath = QStringView{path}.left(path.lastIndexOf(QLatin1Char('/')) + 1) + relativePath;
+ newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
return newPath;
}
@@ -1593,7 +1559,7 @@ static void removeDotsFromPath(QString *path)
in += 2;
continue;
} else if (in == end - 2 && in[0].unicode() == '/' && in[1].unicode() == '.') {
- *out++ = QLatin1Char('/');
+ *out++ = u'/';
in += 2;
break;
}
@@ -1634,7 +1600,7 @@ static void removeDotsFromPath(QString *path)
path->truncate(out - path->constData());
}
-inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *position) const
+inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizetype *position) const
{
Q_ASSERT(!source == !position);
if (error) {
@@ -1660,8 +1626,8 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
if (path.isEmpty())
return NoError;
- if (path.at(0) == QLatin1Char('/')) {
- if (hasAuthority() || path.length() == 1 || path.at(1) != QLatin1Char('/'))
+ if (path.at(0) == u'/') {
+ if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
return NoError;
if (source) {
*source = path;
@@ -1681,7 +1647,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
return NoError;
// check for a path of "text:text/"
- for (int i = 0; i < path.length(); ++i) {
+ for (qsizetype i = 0; i < path.size(); ++i) {
ushort c = path.at(i).unicode();
if (c == '/') {
// found the slash before the colon
@@ -1700,7 +1666,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
}
bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString &input,
- int begin, int end)
+ qsizetype begin, qsizetype end)
{
// What we need to look out for, that the regular parser tolerates:
// - percent signs not followed by two hex digits
@@ -1721,13 +1687,13 @@ bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString
Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl);
const ushort *const data = reinterpret_cast<const ushort *>(input.constData());
- for (uint i = uint(begin); i < uint(end); ++i) {
+ for (size_t i = size_t(begin); i < size_t(end); ++i) {
uint uc = data[i];
if (uc >= 0x80)
continue;
bool error = false;
- if ((uc == '%' && (uint(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
+ if ((uc == '%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
|| uc <= 0x20 || strchr(forbidden, uc)) {
// found an error
error = true;
@@ -1745,7 +1711,7 @@ bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString
if (section == UserInfo) {
// is it the user name or the password?
errorCode = InvalidUserNameError;
- for (uint j = uint(begin); j < i; ++j)
+ for (size_t j = size_t(begin); j < i; ++j)
if (data[j] == ':') {
errorCode = InvalidPasswordError;
break;
@@ -1778,7 +1744,7 @@ inline void QUrlPrivate::validate() const
if (!isHostValid)
return;
- if (scheme == QLatin1String("mailto")) {
+ if (scheme == "mailto"_L1) {
if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
that->isValid = false;
that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username,"
@@ -1825,7 +1791,20 @@ inline void QUrlPrivate::validate() const
/*!
- Constructs a URL by parsing \a url. QUrl will automatically percent encode
+ Constructs a URL by parsing \a url. Note this constructor expects a proper
+ URL or URL-Reference and will not attempt to guess intent. For example, the
+ following declaration:
+
+ \snippet code/src_corelib_io_qurl.cpp constructor-url-reference
+
+ Will construct a valid URL but it may not be what one expects, as the
+ scheme() part of the input is missing. For a string like the above,
+ applications may want to use fromUserInput(). For this constructor or
+ setUrl(), the following is probably what was intended:
+
+ \snippet code/src_corelib_io_qurl.cpp constructor-url
+
+ QUrl will automatically percent encode
all characters that are not allowed in a URL and decode the percent-encoded
sequences that represent an unreserved character (letters, digits, hyphens,
underscores, dots and tildes). All other characters are left in their
@@ -1870,7 +1849,7 @@ QUrl::QUrl() : d(nullptr)
/*!
Constructs a copy of \a other.
*/
-QUrl::QUrl(const QUrl &other) : d(other.d)
+QUrl::QUrl(const QUrl &other) noexcept : d(other.d)
{
if (d)
d->ref.ref();
@@ -1989,7 +1968,7 @@ void QUrl::setScheme(const QString &scheme)
d->flags &= ~QUrlPrivate::IsLocalFile;
d->scheme.clear();
} else {
- d->setScheme(scheme, scheme.length(), /* do set error */ true);
+ d->setScheme(scheme, scheme.size(), /* do set error */ true);
}
}
@@ -2049,7 +2028,7 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode)
return;
}
- d->setAuthority(authority, 0, authority.length(), mode);
+ d->setAuthority(authority, 0, authority.size(), mode);
if (authority.isNull()) {
// QUrlPrivate::setAuthority cleared almost everything
// but it leaves the Host bit set
@@ -2120,7 +2099,7 @@ void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode)
return;
}
- d->setUserInfo(trimmed, 0, trimmed.length());
+ d->setUserInfo(trimmed, 0, trimmed.size());
if (userInfo.isNull()) {
// QUrlPrivate::setUserInfo cleared almost everything
// but it leaves the UserName bit set
@@ -2192,7 +2171,7 @@ void QUrl::setUserName(const QString &userName, ParsingMode mode)
mode = TolerantMode;
}
- d->setUserName(data, 0, data.length());
+ d->setUserName(data, 0, data.size());
if (userName.isNull())
d->sectionIsPresent &= ~QUrlPrivate::UserName;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
@@ -2255,7 +2234,7 @@ void QUrl::setPassword(const QString &password, ParsingMode mode)
mode = TolerantMode;
}
- d->setPassword(data, 0, data.length());
+ d->setPassword(data, 0, data.size());
if (password.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Password;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
@@ -2317,18 +2296,18 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
mode = TolerantMode;
}
- if (d->setHost(data, 0, data.length(), mode)) {
+ if (d->setHost(data, 0, data.size(), mode)) {
if (host.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Host;
- } else if (!data.startsWith(QLatin1Char('['))) {
+ } else if (!data.startsWith(u'[')) {
// setHost failed, it might be IPv6 or IPvFuture in need of bracketing
Q_ASSERT(d->error);
- data.prepend(QLatin1Char('['));
- data.append(QLatin1Char(']'));
- if (!d->setHost(data, 0, data.length(), mode)) {
+ data.prepend(u'[');
+ data.append(u']');
+ if (!d->setHost(data, 0, data.size(), mode)) {
// failed again
- if (data.contains(QLatin1Char(':'))) {
+ if (data.contains(u':')) {
// source data contains ':', so it's an IPv6 error
d->error->code = QUrlPrivate::InvalidIPv6AddressError;
}
@@ -2362,8 +2341,8 @@ QString QUrl::host(ComponentFormattingOptions options) const
QString result;
if (d) {
d->appendHost(result, options);
- if (result.startsWith(QLatin1Char('[')))
- result = result.mid(1, result.length() - 2);
+ if (result.startsWith(u'['))
+ result = result.mid(1, result.size() - 2);
}
return result;
}
@@ -2442,7 +2421,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
mode = TolerantMode;
}
- d->setPath(data, 0, data.length());
+ d->setPath(data, 0, data.size());
// optimized out, since there is no path delimiter
// if (path.isNull())
@@ -2517,7 +2496,7 @@ QString QUrl::path(ComponentFormattingOptions options) const
QString QUrl::fileName(ComponentFormattingOptions options) const
{
const QString ourPath = path(options);
- const int slash = ourPath.lastIndexOf(QLatin1Char('/'));
+ const qsizetype slash = ourPath.lastIndexOf(u'/');
if (slash == -1)
return ourPath;
return ourPath.mid(slash + 1);
@@ -2578,7 +2557,7 @@ void QUrl::setQuery(const QString &query, ParsingMode mode)
mode = TolerantMode;
}
- d->setQuery(data, 0, data.length());
+ d->setQuery(data, 0, data.size());
if (query.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Query;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
@@ -2676,7 +2655,7 @@ void QUrl::setFragment(const QString &fragment, ParsingMode mode)
mode = TolerantMode;
}
- d->setFragment(data, 0, data.length());
+ d->setFragment(data, 0, data.size());
if (fragment.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Fragment;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
@@ -2775,7 +2754,7 @@ QUrl QUrl::resolved(const QUrl &relative) const
t.d->sectionIsPresent |= QUrlPrivate::Query;
}
} else {
- t.d->path = relative.d->path.startsWith(QLatin1Char('/'))
+ t.d->path = relative.d->path.startsWith(u'/')
? relative.d->path
: d->mergePaths(relative.d->path);
if (relative.d->hasQuery()) {
@@ -2882,26 +2861,26 @@ QString QUrl::toString(FormattingOptions options) const
options |= EncodeReserved;
if (!(options & QUrl::RemoveScheme) && d->hasScheme())
- url += d->scheme + QLatin1Char(':');
+ url += d->scheme + u':';
- bool pathIsAbsolute = d->path.startsWith(QLatin1Char('/'));
+ bool pathIsAbsolute = d->path.startsWith(u'/');
if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
- url += QLatin1String("//");
+ url += "//"_L1;
d->appendAuthority(url, options, QUrlPrivate::FullUrl);
} else if (isLocalFile() && pathIsAbsolute) {
// Comply with the XDG file URI spec, which requires triple slashes.
- url += QLatin1String("//");
+ url += "//"_L1;
}
if (!(options & QUrl::RemovePath))
d->appendPath(url, options, QUrlPrivate::FullUrl);
if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
- url += QLatin1Char('?');
+ url += u'?';
d->appendQuery(url, options, QUrlPrivate::FullUrl);
}
if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
- url += QLatin1Char('#');
+ url += u'#';
d->appendFragment(url, options, QUrlPrivate::FullUrl);
}
@@ -2970,7 +2949,7 @@ QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
that.detach();
QString path;
d->appendPath(path, options | FullyEncoded, QUrlPrivate::Path);
- that.d->setPath(path, 0, path.length());
+ that.d->setPath(path, 0, path.size());
}
return that;
}
@@ -2991,19 +2970,23 @@ QByteArray QUrl::toEncoded(FormattingOptions options) const
}
/*!
- \fn QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode parsingMode)
-
Parses \a input and returns the corresponding QUrl. \a input is
assumed to be in encoded form, containing only ASCII characters.
- Parses the URL using \a parsingMode. See setUrl() for more information on
+ Parses the URL using \a mode. See setUrl() for more information on
this parameter. QUrl::DecodedMode is not permitted in this context.
+ \note In Qt versions prior to 6.7, this function took a QByteArray, not
+ QByteArrayView. If you experience compile errors, it's because your code
+ is passing objects that are implicitly convertible to QByteArray, but not
+ QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to
+ make the cast explicit. This is backwards-compatible with old Qt versions.
+
\sa toEncoded(), setUrl()
*/
-QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)
+QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
{
- return QUrl(QString::fromUtf8(input.constData(), input.size()), mode);
+ return QUrl(QString::fromUtf8(input), mode);
}
/*!
@@ -3060,17 +3043,6 @@ QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions optio
ForbidLeadingDot /*FIXME: make configurable*/, options);
}
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
-/*!
- \since 4.2
- \overload
-*/
-QString QUrl::fromAce(const QByteArray &domain)
-{
- return fromAce(domain, {});
-}
-#endif
-
/*!
\since 6.3
@@ -3094,102 +3066,104 @@ QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
.toLatin1();
}
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
-/*!
- \since 4.2
- \overload
-*/
-QByteArray QUrl::toAce(const QString &domain)
-{
- return toAce(domain, {});
-}
-#endif
-
/*!
\internal
- Returns \c true if this URL is "less than" the given \a url. This
+ \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if URL \a lhs is "less than" URL \a rhs. This
provides a means of ordering URLs.
*/
-bool QUrl::operator <(const QUrl &url) const
+
+Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
{
- if (!d || !url.d) {
- bool thisIsEmpty = !d || d->isEmpty();
- bool thatIsEmpty = !url.d || url.d->isEmpty();
+ if (!lhs.d || !rhs.d) {
+ bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
+ bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
// sort an empty URL first
- return thisIsEmpty && !thatIsEmpty;
+ if (thisIsEmpty) {
+ if (!thatIsEmpty)
+ return Qt::weak_ordering::less;
+ else
+ return Qt::weak_ordering::equivalent;
+ } else {
+ return Qt::weak_ordering::greater;
+ }
}
int cmp;
- cmp = d->scheme.compare(url.d->scheme);
+ cmp = lhs.d->scheme.compare(rhs.d->scheme);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->userName.compare(url.d->userName);
+ cmp = lhs.d->userName.compare(rhs.d->userName);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->password.compare(url.d->password);
+ cmp = lhs.d->password.compare(rhs.d->password);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->host.compare(url.d->host);
+ cmp = lhs.d->host.compare(rhs.d->host);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->port != url.d->port)
- return d->port < url.d->port;
+ if (lhs.d->port != rhs.d->port)
+ return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
- cmp = d->path.compare(url.d->path);
+ cmp = lhs.d->path.compare(rhs.d->path);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->hasQuery() != url.d->hasQuery())
- return url.d->hasQuery();
+ if (lhs.d->hasQuery() != rhs.d->hasQuery())
+ return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
- cmp = d->query.compare(url.d->query);
+ cmp = lhs.d->query.compare(rhs.d->query);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->hasFragment() != url.d->hasFragment())
- return url.d->hasFragment();
+ if (lhs.d->hasFragment() != rhs.d->hasFragment())
+ return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
- cmp = d->fragment.compare(url.d->fragment);
- return cmp < 0;
+ cmp = lhs.d->fragment.compare(rhs.d->fragment);
+ return Qt::compareThreeWay(cmp, 0);
}
/*!
- Returns \c true if this URL and the given \a url are equal;
+ \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if \a lhs and \a rhs URLs are equivalent;
otherwise returns \c false.
\sa matches()
*/
-bool QUrl::operator ==(const QUrl &url) const
+
+bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
{
- if (!d && !url.d)
+ if (!lhs.d && !rhs.d)
return true;
- if (!d)
- return url.d->isEmpty();
- if (!url.d)
- return d->isEmpty();
+ if (!lhs.d)
+ return rhs.d->isEmpty();
+ if (!rhs.d)
+ return lhs.d->isEmpty();
// First, compare which sections are present, since it speeds up the
// processing considerably. We just have to ignore the host-is-present flag
// for local files (the "file" protocol), due to the requirements of the
// XDG file URI specification.
int mask = QUrlPrivate::FullUrl;
- if (isLocalFile())
+ if (lhs.isLocalFile())
mask &= ~QUrlPrivate::Host;
- return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) &&
- d->scheme == url.d->scheme &&
- d->userName == url.d->userName &&
- d->password == url.d->password &&
- d->host == url.d->host &&
- d->port == url.d->port &&
- d->path == url.d->path &&
- d->query == url.d->query &&
- d->fragment == url.d->fragment;
+ return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) &&
+ lhs.d->scheme == rhs.d->scheme &&
+ lhs.d->userName == rhs.d->userName &&
+ lhs.d->password == rhs.d->password &&
+ lhs.d->host == rhs.d->host &&
+ lhs.d->port == rhs.d->port &&
+ lhs.d->path == rhs.d->path &&
+ lhs.d->query == rhs.d->query &&
+ lhs.d->fragment == rhs.d->fragment;
}
/*!
@@ -3269,20 +3243,18 @@ bool QUrl::matches(const QUrl &url, FormattingOptions options) const
}
/*!
- Returns \c true if this URL and the given \a url are not equal;
+ \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if \a lhs and \a rhs URLs are not equal;
otherwise returns \c false.
\sa matches()
*/
-bool QUrl::operator !=(const QUrl &url) const
-{
- return !(*this == url);
-}
/*!
Assigns the specified \a url to this object.
*/
-QUrl &QUrl::operator =(const QUrl &url)
+QUrl &QUrl::operator =(const QUrl &url) noexcept
{
if (!d) {
if (url.d) {
@@ -3401,11 +3373,11 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
QString deslashified = fromNativeSeparators(localFile);
// magic for drives on windows
- if (deslashified.length() > 1 && deslashified.at(1) == QLatin1Char(':') && deslashified.at(0) != QLatin1Char('/')) {
- deslashified.prepend(QLatin1Char('/'));
- } else if (deslashified.startsWith(QLatin1String("//"))) {
+ if (deslashified.size() > 1 && deslashified.at(1) == u':' && deslashified.at(0) != u'/') {
+ deslashified.prepend(u'/');
+ } else if (deslashified.startsWith("//"_L1)) {
// magic for shared drive on windows
- int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2);
+ qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
// Check for Windows-specific WebDAV specification: "//host@SSL/path".
if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
@@ -3422,7 +3394,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
// Path hostname is not a valid URL host, so set it entirely in the path
// (by leaving deslashified unchanged)
} else if (indexOfPath > 2) {
- deslashified = deslashified.right(deslashified.length() - indexOfPath);
+ deslashified = deslashified.right(deslashified.size() - indexOfPath);
} else {
deslashified.clear();
}
@@ -3486,16 +3458,16 @@ bool QUrl::isParentOf(const QUrl &childUrl) const
if (!d)
return ((childUrl.scheme().isEmpty())
&& (childUrl.authority().isEmpty())
- && childPath.length() > 0 && childPath.at(0) == QLatin1Char('/'));
+ && childPath.size() > 0 && childPath.at(0) == u'/');
QString ourPath = path();
return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
&& (childUrl.authority().isEmpty() || authority() == childUrl.authority())
&& childPath.startsWith(ourPath)
- && ((ourPath.endsWith(QLatin1Char('/')) && childPath.length() > ourPath.length())
- || (!ourPath.endsWith(QLatin1Char('/'))
- && childPath.length() > ourPath.length() && childPath.at(ourPath.length()) == QLatin1Char('/'))));
+ && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
+ || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
+ && childPath.at(ourPath.size()) == u'/')));
}
@@ -3541,34 +3513,31 @@ QDebug operator<<(QDebug d, const QUrl &url)
}
#endif
-static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, int errorPosition)
+static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
{
- QChar c = uint(errorPosition) < uint(errorSource.length()) ?
+ QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
errorSource.at(errorPosition) : QChar(QChar::Null);
switch (errorCode) {
case QUrlPrivate::NoError:
- Q_ASSERT_X(false, "QUrl::errorString",
- "Impossible: QUrl::errorString should have treated this condition");
- Q_UNREACHABLE();
- return QString();
+ Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition
case QUrlPrivate::InvalidSchemeError: {
- auto msg = QLatin1String("Invalid scheme (character '%1' not permitted)");
+ auto msg = "Invalid scheme (character '%1' not permitted)"_L1;
return msg.arg(c);
}
case QUrlPrivate::InvalidUserNameError:
- return QLatin1String("Invalid user name (character '%1' not permitted)")
+ return "Invalid user name (character '%1' not permitted)"_L1
.arg(c);
case QUrlPrivate::InvalidPasswordError:
- return QLatin1String("Invalid password (character '%1' not permitted)")
+ return "Invalid password (character '%1' not permitted)"_L1
.arg(c);
case QUrlPrivate::InvalidRegNameError:
- if (errorPosition != -1)
- return QLatin1String("Invalid hostname (character '%1' not permitted)")
+ if (errorPosition >= 0)
+ return "Invalid hostname (character '%1' not permitted)"_L1
.arg(c);
else
return QStringLiteral("Invalid hostname (contains invalid characters)");
@@ -3577,9 +3546,9 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err
case QUrlPrivate::InvalidIPv6AddressError:
return QStringLiteral("Invalid IPv6 address");
case QUrlPrivate::InvalidCharacterInIPv6Error:
- return QLatin1String("Invalid IPv6 address (character '%1' not permitted)").arg(c);
+ return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
case QUrlPrivate::InvalidIPvFutureError:
- return QLatin1String("Invalid IPvFuture address (character '%1' not permitted)").arg(c);
+ return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
case QUrlPrivate::HostMissingEndBracket:
return QStringLiteral("Expected ']' to match '[' in hostname");
@@ -3589,15 +3558,15 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err
return QStringLiteral("Port field was empty");
case QUrlPrivate::InvalidPathError:
- return QLatin1String("Invalid path (character '%1' not permitted)")
+ return "Invalid path (character '%1' not permitted)"_L1
.arg(c);
case QUrlPrivate::InvalidQueryError:
- return QLatin1String("Invalid query (character '%1' not permitted)")
+ return "Invalid query (character '%1' not permitted)"_L1
.arg(c);
case QUrlPrivate::InvalidFragmentError:
- return QLatin1String("Invalid fragment (character '%1' not permitted)")
+ return "Invalid fragment (character '%1' not permitted)"_L1
.arg(c);
case QUrlPrivate::AuthorityPresentAndPathIsRelative:
@@ -3608,20 +3577,14 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err
return QStringLiteral("Relative URL's path component contains ':' before any '/'");
}
- Q_ASSERT_X(false, "QUrl::errorString", "Cannot happen, unknown error");
- Q_UNREACHABLE();
- return QString();
+ Q_UNREACHABLE_RETURN(QString());
}
static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName,
const QString &component)
{
- if (present) {
- msg += QLatin1String(componentName);
- msg += QLatin1Char('"');
- msg += component;
- msg += QLatin1String("\",");
- }
+ if (present)
+ msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1;
}
/*!
@@ -3644,15 +3607,15 @@ QString QUrl::errorString() const
return msg;
QString errorSource;
- int errorPosition = 0;
+ qsizetype errorPosition = 0;
QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
if (errorCode == QUrlPrivate::NoError)
return msg;
msg += errorMessage(errorCode, errorSource, errorPosition);
- msg += QLatin1String("; source was \"");
+ msg += "; source was \""_L1;
msg += errorSource;
- msg += QLatin1String("\";");
+ msg += "\";"_L1;
appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
" scheme = ", d->scheme);
appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
@@ -3667,7 +3630,7 @@ QString QUrl::errorString() const
" query = ", d->query);
appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
" fragment = ", d->fragment);
- if (msg.endsWith(QLatin1Char(',')))
+ if (msg.endsWith(u','))
msg.chop(1);
return msg;
}
@@ -3738,8 +3701,8 @@ static QUrl adjustFtpPath(QUrl url)
{
if (url.scheme() == ftpScheme()) {
QString path = url.path(QUrl::PrettyDecoded);
- if (path.startsWith(QLatin1String("//")))
- url.setPath(QLatin1String("/%2F") + QStringView{path}.mid(2), QUrl::TolerantMode);
+ if (path.startsWith("//"_L1))
+ url.setPath("/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
}
return url;
}
@@ -3824,7 +3787,7 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto
if (QDir::isAbsolutePath(trimmedString))
return QUrl::fromLocalFile(trimmedString);
- QUrl urlPrepended = QUrl(QLatin1String("http://") + trimmedString, QUrl::TolerantMode);
+ QUrl urlPrepended = QUrl("http://"_L1 + trimmedString, QUrl::TolerantMode);
// Check the most common case of a valid url with a scheme
// We check if the port would be valid by adding the scheme to handle the case host:port
@@ -3836,7 +3799,7 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto
// Else, try the prepended one and adjust the scheme from the host name
if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
- int dotIndex = trimmedString.indexOf(QLatin1Char('.'));
+ qsizetype dotIndex = trimmedString.indexOf(u'.');
const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
urlPrepended.setScheme(ftpScheme());
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index 3001904ef3..d6779cf485 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QURL_H
#define QURL_H
#include <QtCore/qbytearray.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
#include <QtCore/qglobal.h>
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
@@ -179,8 +143,8 @@ public:
#endif
QUrl();
- QUrl(const QUrl &copy);
- QUrl &operator =(const QUrl &copy);
+ QUrl(const QUrl &copy) noexcept;
+ QUrl &operator =(const QUrl &copy) noexcept;
#ifdef QT_NO_URL_CAST_FROM_STRING
explicit QUrl(const QString &url, ParsingMode mode = TolerantMode);
#else
@@ -201,7 +165,10 @@ public:
[[nodiscard]] QUrl adjusted(FormattingOptions options) const;
QByteArray toEncoded(FormattingOptions options = FullyEncoded) const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode);
+#endif
+ static QUrl fromEncoded(QByteArrayView input, ParsingMode mode = TolerantMode);
enum UserInputResolutionOption {
DefaultResolution,
@@ -264,9 +231,11 @@ public:
void detach();
bool isDetached() const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator <(const QUrl &url) const;
bool operator ==(const QUrl &url) const;
bool operator !=(const QUrl &url) const;
+#endif
bool matches(const QUrl &url, FormattingOptions options) const;
@@ -287,15 +256,12 @@ public:
};
Q_DECLARE_FLAGS(AceProcessingOptions, AceProcessingOption)
-#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
- static QString fromAce(const QByteArray &, AceProcessingOptions options = {});
- static QByteArray toAce(const QString &, AceProcessingOptions options = {});
-#else
+#if QT_CORE_REMOVED_SINCE(6, 3)
static QString fromAce(const QByteArray &);
static QByteArray toAce(const QString &);
- static QString fromAce(const QByteArray &, AceProcessingOptions options);
- static QByteArray toAce(const QString &, AceProcessingOptions options);
#endif
+ static QString fromAce(const QByteArray &domain, AceProcessingOptions options = {});
+ static QByteArray toAce(const QString &domain, AceProcessingOptions options = {});
static QStringList idnWhitelist();
static QStringList toStringList(const QList<QUrl> &uris, FormattingOptions options = FormattingOptions(PrettyDecoded));
@@ -305,6 +271,11 @@ public:
friend Q_CORE_EXPORT size_t qHash(const QUrl &url, size_t seed) noexcept;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QUrl &lhs, const QUrl &rhs);
+ friend Q_CORE_EXPORT Qt::weak_ordering
+ compareThreeWay(const QUrl &lhs, const QUrl &rhs);
+ Q_DECLARE_WEAKLY_ORDERED(QUrl)
+
QUrlPrivate *d;
friend class QUrlQuery;
diff --git a/src/corelib/io/qurl_p.h b/src/corelib/io/qurl_p.h
index 9b755cf5df..9562d1993d 100644
--- a/src/corelib/io/qurl_p.h
+++ b/src/corelib/io/qurl_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QURL_P_H
#define QURL_P_H
@@ -65,8 +29,8 @@ extern Q_AUTOTEST_EXPORT qsizetype qt_urlRecode(QString &appendTo, QStringView u
// in qurlidna.cpp
enum AceLeadingDot { AllowLeadingDot, ForbidLeadingDot };
enum AceOperation { ToAceOnly, NormalizeAce };
-extern QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
- QUrl::AceProcessingOptions options);
+QString Q_CORE_EXPORT qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
+ QUrl::AceProcessingOptions options = {});
extern Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output);
extern Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc);
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index b3e67fecf7..a2a81c7605 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qurl_p.h"
#include <QtCore/qstringlist.h>
#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/private/qoffsetstringarray_p.h>
#include <QtCore/private/qstringiterator_p.h>
#include <QtCore/private/qunicodetables_p.h>
@@ -49,6 +14,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// needed by the punycode encoder/decoder
static const uint base = 36;
static const uint tmin = 1;
@@ -106,11 +73,11 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// Do not try to encode strings that certainly will result in output
// that is longer than allowable domain name label length. Note that
// non-BMP codepoints are encoded as two QChars.
- if (in.length() > MaxDomainLabelLength * 2)
+ if (in.size() > MaxDomainLabelLength * 2)
return;
- int outLen = output->length();
- output->resize(outLen + in.length());
+ int outLen = output->size();
+ output->resize(outLen + in.size());
QChar *d = output->data() + outLen;
bool skipped = false;
@@ -136,7 +103,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// if basic code points were copied, add the delimiter character.
if (h > 0)
- *output += QLatin1Char{'-'};
+ *output += u'-';
// compute the input length in Unicode code points.
uint inputLength = 0;
@@ -165,7 +132,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// delta = delta + (m - n) * (h + 1), fail on overflow
uint tmp;
- if (mul_overflow<uint>(m - n, h + 1, &tmp) || add_overflow<uint>(delta, tmp, &delta)) {
+ if (qMulOverflow<uint>(m - n, h + 1, &tmp) || qAddOverflow<uint>(delta, tmp, &delta)) {
output->truncate(outLen);
return; // punycode_overflow
}
@@ -177,7 +144,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// increase delta until we reach the character processed in this iteration;
// fail if delta overflows.
if (c < n) {
- if (add_overflow<uint>(delta, 1, &delta)) {
+ if (qAddOverflow<uint>(delta, 1, &delta)) {
output->truncate(outLen);
return; // punycode_overflow
}
@@ -197,7 +164,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
}
// prepend ACE prefix
- output->insert(outLen, QLatin1String("xn--"));
+ output->insert(outLen, "xn--"_L1);
return;
}
@@ -210,17 +177,17 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
// Do not try to decode strings longer than allowable for a domain label.
// Non-ASCII strings are not allowed here anyway, so there is no need
// to account for surrogates.
- if (pc.length() > MaxDomainLabelLength)
+ if (pc.size() > MaxDomainLabelLength)
return QString();
// strip any ACE prefix
- int start = pc.startsWith(QLatin1String("xn--")) ? 4 : 0;
+ int start = pc.startsWith("xn--"_L1) ? 4 : 0;
if (!start)
return pc;
// find the last delimiter character '-' in the input array. copy
// all data before this delimiter directly to the output array.
- int delimiterPos = pc.lastIndexOf(QLatin1Char{'-'});
+ int delimiterPos = pc.lastIndexOf(u'-');
auto output = delimiterPos < 4 ? std::u32string()
: pc.mid(start, delimiterPos - start).toStdU32String();
@@ -252,7 +219,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
// i = i + digit * w, fail on overflow
uint tmp;
- if (mul_overflow<uint>(digit, w, &tmp) || add_overflow<uint>(i, tmp, &i))
+ if (qMulOverflow<uint>(digit, w, &tmp) || qAddOverflow<uint>(i, tmp, &i))
return QString();
// detect threshold to stop reading delta digits
@@ -264,7 +231,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
if (digit < t) break;
// w = w * (base - t), fail on overflow
- if (mul_overflow<uint>(w, base - t, &w))
+ if (qMulOverflow<uint>(w, base - t, &w))
return QString();
}
@@ -274,7 +241,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
bias = adapt(i - oldi, outputLength + 1, oldi == 0);
// n = n + i div (length(output) + 1), fail on overflow
- if (add_overflow<uint>(n, i / (outputLength + 1), &n))
+ if (qAddOverflow<uint>(n, i / (outputLength + 1), &n))
return QString();
// allow the deltas to wrap around
@@ -310,7 +277,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
return QString::fromStdU32String(output);
}
-static const char * const idn_whitelist[] = {
+static constexpr auto idn_whitelist = qOffsetStringArray(
"ac", "ar", "asia", "at",
"biz", "br",
"cat", "ch", "cl", "cn", "com",
@@ -347,26 +314,25 @@ static const char * const idn_whitelist[] = {
"xn--wgbh1c", // Egypt
"xn--wgbl6a", // Qatar
"xn--xkc2al3hye2a" // Sri Lanka
-};
-static const size_t idn_whitelist_size = sizeof idn_whitelist / sizeof *idn_whitelist;
+);
-static QStringList *user_idn_whitelist = nullptr;
+Q_CONSTINIT static QStringList *user_idn_whitelist = nullptr;
static bool lessThan(const QChar *a, int l, const char *c)
{
- const ushort *uc = (const ushort *)a;
- const ushort *e = uc + l;
+ const auto *uc = reinterpret_cast<const char16_t *>(a);
+ const char16_t *e = uc + l;
if (!c || *c == 0)
return false;
while (*c) {
- if (uc == e || *uc != *c)
+ if (uc == e || *uc != static_cast<unsigned char>(*c))
break;
++uc;
++c;
}
- return (uc == e ? *c : *uc < *c);
+ return uc == e ? *c : (*uc < static_cast<unsigned char>(*c));
}
static bool equal(const QChar *a, int l, const char *b)
@@ -383,7 +349,7 @@ static bool equal(const QChar *a, int l, const char *b)
static bool qt_is_idn_enabled(QStringView aceDomain)
{
- auto idx = aceDomain.lastIndexOf(QLatin1Char('.'));
+ auto idx = aceDomain.lastIndexOf(u'.');
if (idx == -1)
return false;
@@ -396,17 +362,17 @@ static bool qt_is_idn_enabled(QStringView aceDomain)
return user_idn_whitelist->contains(tldString);
int l = 0;
- int r = idn_whitelist_size - 1;
+ int r = idn_whitelist.count() - 1;
int i = (l + r + 1) / 2;
while (r != l) {
- if (lessThan(tld, len, idn_whitelist[i]))
+ if (lessThan(tld, len, idn_whitelist.at(i)))
r = i - 1;
else
l = i;
i = (l + r + 1) / 2;
}
- return equal(tld, len, idn_whitelist[i]);
+ return equal(tld, len, idn_whitelist.at(i));
}
template<typename C>
@@ -457,13 +423,19 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
if (uc >= U'A' && uc <= U'Z')
uc |= 0x20; // lower-case it
- if (!isValidInNormalizedAsciiName(uc))
- return {};
+ if (isValidInNormalizedAsciiName(uc)) {
+ result.append(static_cast<char16_t>(uc));
+ continue;
+ }
+ }
- result.append(static_cast<char16_t>(uc));
+ allAscii = false;
+
+ // Capital sharp S is a special case since UTR #46 revision 31 (Unicode 15.1)
+ if (uc == 0x1E9E && options.testFlag(QUrl::AceTransitionalProcessing)) {
+ result.append(u"ss"_s);
continue;
}
- allAscii = false;
QUnicodeTables::IdnaStatus status = QUnicodeTables::idnaStatus(uc);
@@ -476,14 +448,13 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
case QUnicodeTables::IdnaStatus::Ignored:
continue;
case QUnicodeTables::IdnaStatus::Valid:
+ case QUnicodeTables::IdnaStatus::Disallowed:
for (auto c : QChar::fromUcs4(uc))
result.append(c);
break;
case QUnicodeTables::IdnaStatus::Mapped:
result.append(QUnicodeTables::idnaMapping(uc));
break;
- case QUnicodeTables::IdnaStatus::Disallowed:
- return {};
default:
Q_UNREACHABLE();
}
@@ -502,7 +473,7 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
*/
static bool validateAsciiLabel(QStringView label)
{
- if (label.length() > MaxDomainLabelLength)
+ if (label.size() > MaxDomainLabelLength)
return false;
if (label.first() == u'-' || label.last() == u'-')
@@ -517,12 +488,13 @@ class DomainValidityChecker
{
bool domainNameIsBidi = false;
bool hadBidiErrors = false;
+ bool ignoreBidiErrors;
static constexpr char32_t ZWNJ = U'\u200C';
static constexpr char32_t ZWJ = U'\u200D';
public:
- DomainValidityChecker() { }
+ DomainValidityChecker(bool ignoreBidiErrors = false) : ignoreBidiErrors(ignoreBidiErrors) { }
bool checkLabel(const QString &label, QUrl::AceProcessingOptions options);
private:
@@ -743,18 +715,18 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
if (label != label.normalized(QString::NormalizationForm_C))
return false;
- if (label.length() >= 4) {
+ if (label.size() >= 4) {
// This assumes that the first two characters are in BMP, but that's ok
// because non-BMP characters are unlikely to be used for specifying
// future extensions.
- if (label[2] == QLatin1Char('-') && label[3] == QLatin1Char('-'))
- return false;
+ if (label[2] == u'-' && label[3] == u'-')
+ return ignoreBidiErrors && label.startsWith(u"xn") && validateAsciiLabel(label);
}
- if (label.startsWith(QLatin1Char('-')) || label.endsWith(QLatin1Char('-')))
+ if (label.startsWith(u'-') || label.endsWith(u'-'))
return false;
- if (label.contains(QLatin1Char('.')))
+ if (label.contains(u'.'))
return false;
QStringIterator iter(label);
@@ -770,7 +742,7 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
for (;;) {
hasJoiners = hasJoiners || c == ZWNJ || c == ZWJ;
- if (!domainNameIsBidi) {
+ if (!ignoreBidiErrors && !domainNameIsBidi) {
switch (QChar::direction(c)) {
case QChar::DirR:
case QChar::DirAL:
@@ -811,25 +783,20 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
return true;
}
-static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot)
+static QString convertToAscii(QStringView normalizedDomain, AceLeadingDot dot)
{
qsizetype lastIdx = 0;
QString aceForm; // this variable is here for caching
QString aceResult;
while (true) {
- auto idx = normalizedDomain.indexOf(u'.', lastIdx);
+ qsizetype idx = normalizedDomain.indexOf(u'.', lastIdx);
if (idx == -1)
idx = normalizedDomain.size();
- const auto labelLength = idx - lastIdx;
- if (labelLength == 0) {
- if (idx == normalizedDomain.size())
- break;
- if (dot == ForbidLeadingDot || idx > 0)
- return {}; // two delimiters in a row -- empty label not allowed
- } else {
- const auto label = QStringView(normalizedDomain).sliced(lastIdx, labelLength);
+ const qsizetype labelLength = idx - lastIdx;
+ if (labelLength) {
+ const auto label = normalizedDomain.sliced(lastIdx, labelLength);
aceForm.clear();
qt_punycodeEncoder(label, &aceForm);
if (aceForm.isEmpty())
@@ -841,6 +808,9 @@ static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot
if (idx == normalizedDomain.size())
break;
+ if (labelLength == 0 && (dot == ForbidLeadingDot || idx > 0))
+ return {}; // two delimiters in a row -- empty label not allowed
+
lastIdx = idx + 1;
aceResult += u'.';
}
@@ -848,7 +818,7 @@ static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot
return aceResult;
}
-static bool checkAsciiDomainName(const QString &normalizedDomain, AceLeadingDot dot,
+static bool checkAsciiDomainName(QStringView normalizedDomain, AceLeadingDot dot,
bool *usesPunycode)
{
qsizetype lastIdx = 0;
@@ -867,11 +837,11 @@ static bool checkAsciiDomainName(const QString &normalizedDomain, AceLeadingDot
if (dot == ForbidLeadingDot || idx > 0)
return false; // two delimiters in a row -- empty label not allowed
} else {
- const auto label = QStringView(normalizedDomain).sliced(lastIdx, labelLength);
+ const auto label = normalizedDomain.sliced(lastIdx, labelLength);
if (!validateAsciiLabel(label))
return false;
- hasPunycode = hasPunycode || label.startsWith(QLatin1String("xn--"));
+ hasPunycode = hasPunycode || label.startsWith("xn--"_L1);
}
lastIdx = idx + 1;
@@ -920,6 +890,33 @@ static QString convertToUnicode(const QString &asciiDomain, QUrl::AceProcessingO
return result;
}
+static bool checkUnicodeName(const QString &domainName, QUrl::AceProcessingOptions options)
+{
+ qsizetype lastIdx = 0;
+
+ DomainValidityChecker checker(true);
+
+ while (true) {
+ qsizetype idx = domainName.indexOf(u'.', lastIdx);
+ if (idx == -1)
+ idx = domainName.size();
+
+ const qsizetype labelLength = idx - lastIdx;
+ if (labelLength) {
+ const auto label = domainName.sliced(lastIdx, labelLength);
+
+ if (!checker.checkLabel(label, options))
+ return false;
+ }
+
+ if (idx == domainName.size())
+ break;
+
+ lastIdx = idx + 1;
+ }
+ return true;
+}
+
QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
QUrl::AceProcessingOptions options)
{
@@ -934,12 +931,15 @@ QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
if (normalized.isEmpty())
return {};
- bool needsCoversionToUnicode;
+ if (!mappedToAscii && !checkUnicodeName(normalized, options))
+ return {};
+
+ bool needsConversionToUnicode;
const QString aceResult = mappedToAscii ? normalized : convertToAscii(normalized, dot);
- if (aceResult.isEmpty() || !checkAsciiDomainName(aceResult, dot, &needsCoversionToUnicode))
+ if (aceResult.isEmpty() || !checkAsciiDomainName(aceResult, dot, &needsConversionToUnicode))
return {};
- if (op == ToAceOnly || !needsCoversionToUnicode
+ if (op == ToAceOnly || !needsConversionToUnicode
|| (!options.testFlag(QUrl::IgnoreIDNWhitelist) && !qt_is_idn_enabled(aceResult))) {
return aceResult;
}
@@ -963,10 +963,10 @@ QStringList QUrl::idnWhitelist()
return *user_idn_whitelist;
static const QStringList list = [] {
QStringList list;
- list.reserve(idn_whitelist_size);
- unsigned int i = 0;
- while (i < idn_whitelist_size) {
- list << QLatin1String(idn_whitelist[i]);
+ list.reserve(idn_whitelist.count());
+ int i = 0;
+ while (i < idn_whitelist.count()) {
+ list << QLatin1StringView(idn_whitelist.at(i));
++i;
}
return list;
diff --git a/src/corelib/io/qurlquery.cpp b/src/corelib/io/qurlquery.cpp
index 637e6c3c01..31f3ee1d90 100644
--- a/src/corelib/io/qurlquery.cpp
+++ b/src/corelib/io/qurlquery.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qurlquery.h"
#include "qurl_p.h"
@@ -60,6 +24,8 @@ QT_BEGIN_NAMESPACE
\ingroup network
\ingroup shared
+ \compares equality
+
It is used to parse the query strings found in URLs like the following:
\image qurl-querystring.png
@@ -95,7 +61,7 @@ QT_BEGIN_NAMESPACE
improperly-encoded strings are passed to the setter or query methods,
QUrlQuery will attempt to recover instead of failing. That is to say, all
functions in this class parse their string arguments as if the
- {{QUrl::TolerantMode}} decoding mode was specified.
+ QUrl::TolerantMode decoding mode was specified.
Application code should strive to always ensure proper encoding and not rely
on TolerantMode parsing fixing the strings. Notably, all user input must be
@@ -159,14 +125,14 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QUrlQuery::QUrlQuery(std::initializer_list<QPair<QString, QString>> list)
+ \fn QUrlQuery::QUrlQuery(std::initializer_list<std::pair<QString, QString>> list)
\since 5.13
Constructs a QUrlQuery object from the \a list of key/value pair.
*/
-typedef QList<QPair<QString, QString> > Map;
+typedef QList<std::pair<QString, QString> > Map;
class QUrlQueryPrivate : public QSharedData
{
@@ -182,7 +148,7 @@ public:
void setQuery(const QString &query);
void addQueryItem(const QString &key, const QString &value)
- { itemList.append(qMakePair(recodeFromUser(key), recodeFromUser(value))); }
+ { itemList.append(std::make_pair(recodeFromUser(key), recodeFromUser(value))); }
int findRecodedKey(const QString &key, int from = 0) const
{
for (int i = from; i < itemList.size(); ++i)
@@ -326,17 +292,17 @@ void QUrlQueryPrivate::setQuery(const QString &query)
if (delimiter == pos) {
// the value delimiter wasn't found, store a null value
- itemList.append(qMakePair(key, QString()));
+ itemList.append(std::make_pair(key, QString()));
} else if (delimiter + 1 == pos) {
// if the delimiter was found but the value is empty, store empty-but-not-null
- itemList.append(qMakePair(key, QString(0, Qt::Uninitialized)));
+ itemList.append(std::make_pair(key, QString(0, Qt::Uninitialized)));
} else {
QString value;
if (!qt_urlRecode(value, QStringView{delimiter + 1, pos},
QUrl::DecodeReserved,
prettyDecodedActions))
value = QString(delimiter + 1, pos - delimiter - 1);
- itemList.append(qMakePair(key, value));
+ itemList.append(std::make_pair(key, value));
}
if (pos != end)
@@ -400,6 +366,16 @@ QUrlQuery::QUrlQuery(const QUrlQuery &other)
}
/*!
+ \since 6.5
+ Moves the contents of the \a other QUrlQuery object, including the query
+ delimiters.
+*/
+QUrlQuery::QUrlQuery(QUrlQuery &&other) noexcept
+ : d(std::move(other.d))
+{
+}
+
+/*!
Copies the contents of the \a other QUrlQuery object, including the query
delimiters.
*/
@@ -425,19 +401,26 @@ QUrlQuery::~QUrlQuery()
}
/*!
- Returns \c true if this object and the \a other object contain the same
+ \fn bool QUrlQuery::operator==(const QUrlQuery &lhs, const QUrlQuery &rhs)
+
+ Returns \c true if QUrlQuery objects \a lhs and \a rhs contain the same
contents, in the same order, and use the same query delimiters.
*/
-bool QUrlQuery::operator ==(const QUrlQuery &other) const
+
+bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs)
{
- if (d == other.d)
+ if (lhs.d == rhs.d)
return true;
- if (d && other.d)
+ if (lhs.d && rhs.d)
// keep in sync with qHash(QUrlQuery):
- return d->valueDelimiter == other.d->valueDelimiter &&
- d->pairDelimiter == other.d->pairDelimiter &&
- d->itemList == other.d->itemList;
- return false;
+ return lhs.d->valueDelimiter == rhs.d->valueDelimiter &&
+ lhs.d->pairDelimiter == rhs.d->pairDelimiter &&
+ lhs.d->itemList == rhs.d->itemList;
+
+ const QUrlQueryPrivate *x = lhs.d ? lhs.d.data() : rhs.d.data();
+ return x->valueDelimiter == QUrlQuery::defaultQueryValueDelimiter() &&
+ x->pairDelimiter == QUrlQuery::defaultQueryPairDelimiter() &&
+ x->itemList.isEmpty();
}
/*!
@@ -551,7 +534,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
{
int size = 0;
for ( ; it != end; ++it)
- size += it->first.length() + 1 + it->second.length() + 1;
+ size += it->first.size() + 1 + it->second.size() + 1;
result.reserve(size + size / 4);
}
@@ -580,7 +563,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
representation of the keys and values of the query string are
percent encoded when returned in query().
- If \a valueDelimiter is set to '(' and \a pairDelimiter is ')',
+ If \a valueDelimiter is set to ',' and \a pairDelimiter is ';',
the above query string would instead be represented like this:
\snippet code/src_corelib_io_qurl.cpp 4
@@ -591,7 +574,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
\snippet code/src_corelib_io_qurlquery.cpp 0
Use of other characters is not supported and may result in unexpected
- behaviour. This method does not verify that you passed a valid delimiter.
+ behavior. This method does not verify that you passed a valid delimiter.
\sa queryValueDelimiter(), queryPairDelimiter()
*/
@@ -635,14 +618,14 @@ QChar QUrlQuery::queryPairDelimiter() const
\sa queryItems(), isEmpty()
*/
-void QUrlQuery::setQueryItems(const QList<QPair<QString, QString> > &query)
+void QUrlQuery::setQueryItems(const QList<std::pair<QString, QString> > &query)
{
clear();
if (query.isEmpty())
return;
QUrlQueryPrivate *dd = d;
- QList<QPair<QString, QString> >::const_iterator it = query.constBegin(),
+ QList<std::pair<QString, QString> >::const_iterator it = query.constBegin(),
end = query.constEnd();
for ( ; it != end; ++it)
dd->addQueryItem(it->first, it->second);
@@ -656,20 +639,20 @@ void QUrlQuery::setQueryItems(const QList<QPair<QString, QString> > &query)
\sa setQueryItems(), {encoding}{Encoding}
*/
-QList<QPair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
+QList<std::pair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
{
if (!d)
- return QList<QPair<QString, QString> >();
+ return QList<std::pair<QString, QString> >();
if (idempotentRecodeToUser(encoding))
return d->itemList;
- QList<QPair<QString, QString> > result;
+ QList<std::pair<QString, QString> > result;
Map::const_iterator it = d->itemList.constBegin();
Map::const_iterator end = d->itemList.constEnd();
- result.reserve(d->itemList.count());
+ result.reserve(d->itemList.size());
for ( ; it != end; ++it)
- result << qMakePair(d->recodeToUser(it->first, encoding),
- d->recodeToUser(it->second, encoding));
+ result << std::make_pair(d->recodeToUser(it->first, encoding),
+ d->recodeToUser(it->second, encoding));
return result;
}
@@ -788,7 +771,7 @@ void QUrlQuery::removeAllQueryItems(const QString &key)
if (d.constData()) {
auto *p = d.data();
const QString encodedKey = p->recodeFromUser(key);
- auto firstEqualsEncodedKey = [&encodedKey](const QPair<QString, QString> &item) {
+ auto firstEqualsEncodedKey = [&encodedKey](const std::pair<QString, QString> &item) {
return item.first == encodedKey;
};
p->itemList.removeIf(firstEqualsEncodedKey);
@@ -832,10 +815,15 @@ void QUrlQuery::removeAllQueryItems(const QString &key)
*/
/*!
- \fn bool QUrlQuery::operator!=(const QUrlQuery &other) const
+ \fn bool QUrlQuery::operator!=(const QUrlQuery &lhs, const QUrlQuery &rhs)
- Returns \c true if \a other is not equal to this QUrlQuery. Otherwise, returns \c false.
+ Returns \c true if the QUrlQuery object \a rhs is not equal to \a lhs.
+ Otherwise, returns \c false.
\sa operator==()
*/
QT_END_NAMESPACE
+
+#undef decode
+#undef leave
+#undef encode
diff --git a/src/corelib/io/qurlquery.h b/src/corelib/io/qurlquery.h
index e509f77cd2..061107606e 100644
--- a/src/corelib/io/qurlquery.h
+++ b/src/corelib/io/qurlquery.h
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QURLQUERY_H
#define QURLQUERY_H
-#include <QtCore/qpair.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qurl.h>
@@ -58,21 +22,24 @@ public:
QUrlQuery();
explicit QUrlQuery(const QUrl &url);
explicit QUrlQuery(const QString &queryString);
- QUrlQuery(std::initializer_list<QPair<QString, QString>> list)
+ QUrlQuery(std::initializer_list<std::pair<QString, QString>> list)
: QUrlQuery()
{
- for (const QPair<QString, QString> &item : list)
+ for (const std::pair<QString, QString> &item : list)
addQueryItem(item.first, item.second);
}
QUrlQuery(const QUrlQuery &other);
+ QUrlQuery(QUrlQuery &&other) noexcept;
QUrlQuery &operator=(const QUrlQuery &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QUrlQuery)
~QUrlQuery();
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QUrlQuery &other) const;
bool operator!=(const QUrlQuery &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
+#endif
void swap(QUrlQuery &other) noexcept { d.swap(other.d); }
@@ -89,8 +56,8 @@ public:
QChar queryValueDelimiter() const;
QChar queryPairDelimiter() const;
- void setQueryItems(const QList<QPair<QString, QString> > &query);
- QList<QPair<QString, QString> > queryItems(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const;
+ void setQueryItems(const QList<std::pair<QString, QString> > &query);
+ QList<std::pair<QString, QString> > queryItems(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const;
bool hasQueryItem(const QString &key) const;
void addQueryItem(const QString &key, const QString &value);
@@ -103,6 +70,8 @@ public:
static constexpr char16_t defaultQueryPairDelimiter() noexcept { return u'&'; }
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QUrlQuery)
friend class QUrl;
friend Q_CORE_EXPORT size_t qHash(const QUrlQuery &key, size_t seed) noexcept;
QSharedDataPointer<QUrlQueryPrivate> d;
diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp
index fd5accb108..60dad31a3e 100644
--- a/src/corelib/io/qurlrecode.cpp
+++ b/src/corelib/io/qurlrecode.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qurl.h"
#include "private/qstringconverter_p.h"
@@ -676,7 +640,7 @@ qt_urlRecode(QString &appendTo, QStringView in,
{
uchar actionTable[sizeof defaultActionTable];
if ((encoding & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
- return int(decode(appendTo, in));
+ return decode(appendTo, in);
}
memcpy(actionTable, defaultActionTable, sizeof actionTable);
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index 4435a47cab..31d0dc1417 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowspipereader_p.h"
#include <qcoreapplication.h>
@@ -45,6 +9,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const DWORD minReadBufferSize = 4096;
QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
@@ -493,7 +459,7 @@ bool QWindowsPipeReader::consumePendingAndEmit(bool allowWinActPosting)
if (emitReadyRead)
emit readyRead();
if (alive && dwError != ERROR_BROKEN_PIPE && dwError != ERROR_PIPE_NOT_CONNECTED)
- emit winError(dwError, QLatin1String("QWindowsPipeReader::consumePendingAndEmit"));
+ emit winError(dwError, "QWindowsPipeReader::consumePendingAndEmit"_L1);
if (alive)
emit pipeClosed();
}
@@ -545,3 +511,5 @@ bool QWindowsPipeReader::waitForNotification()
}
QT_END_NAMESPACE
+
+#include "moc_qwindowspipereader_p.cpp"
diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h
index 22a4365f02..14db4f9313 100644
--- a/src/corelib/io/qwindowspipereader_p.h
+++ b/src/corelib/io/qwindowspipereader_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSPIPEREADER_P_H
#define QWINDOWSPIPEREADER_P_H
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index 2d96a3d87d..9d0f6a8a3e 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowspipewriter_p.h"
#include <qcoreapplication.h>
@@ -350,3 +314,5 @@ bool QWindowsPipeWriter::consumePendingAndEmit(bool allowWinActPosting)
}
QT_END_NAMESPACE
+
+#include "moc_qwindowspipewriter_p.cpp"
diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h
index 71e47c9787..c8c82310b8 100644
--- a/src/corelib/io/qwindowspipewriter_p.h
+++ b/src/corelib/io/qwindowspipewriter_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSPIPEWRITER_P_H
#define QWINDOWSPIPEWRITER_P_H
diff --git a/src/corelib/io/qzip.cpp b/src/corelib/io/qzip.cpp
new file mode 100644
index 0000000000..173563ec29
--- /dev/null
+++ b/src/corelib/io/qzip.cpp
@@ -0,0 +1,1347 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qzipreader_p.h"
+#include "qzipwriter_p.h"
+
+#include <qdatetime.h>
+#include <qendian.h>
+#include <qdebug.h>
+#include <qdir.h>
+
+#include <memory>
+
+#include <zlib.h>
+
+// Zip standard version for archives handled by this API
+// (actually, the only basic support of this version is implemented but it is enough for now)
+#define ZIP_VERSION 20
+
+#if 0
+#define ZDEBUG qDebug
+#else
+#define ZDEBUG if (0) qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static inline uint readUInt(const uchar *data)
+{
+ return (data[0]) + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
+}
+
+static inline ushort readUShort(const uchar *data)
+{
+ return (data[0]) + (data[1]<<8);
+}
+
+static inline void writeUInt(uchar *data, uint i)
+{
+ data[0] = i & 0xff;
+ data[1] = (i>>8) & 0xff;
+ data[2] = (i>>16) & 0xff;
+ data[3] = (i>>24) & 0xff;
+}
+
+static inline void writeUShort(uchar *data, ushort i)
+{
+ data[0] = i & 0xff;
+ data[1] = (i>>8) & 0xff;
+}
+
+static inline void copyUInt(uchar *dest, const uchar *src)
+{
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+}
+
+static inline void copyUShort(uchar *dest, const uchar *src)
+{
+ dest[0] = src[0];
+ dest[1] = src[1];
+}
+
+static void writeMSDosDate(uchar *dest, const QDateTime& dt)
+{
+ if (dt.isValid()) {
+ quint16 time =
+ (dt.time().hour() << 11) // 5 bit hour
+ | (dt.time().minute() << 5) // 6 bit minute
+ | (dt.time().second() >> 1); // 5 bit double seconds
+
+ dest[0] = time & 0xff;
+ dest[1] = time >> 8;
+
+ quint16 date =
+ ((dt.date().year() - 1980) << 9) // 7 bit year 1980-based
+ | (dt.date().month() << 5) // 4 bit month
+ | (dt.date().day()); // 5 bit day
+
+ dest[2] = char(date);
+ dest[3] = char(date >> 8);
+ } else {
+ dest[0] = 0;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ }
+}
+
+static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = const_cast<Bytef*>(source);
+ stream.avail_in = (uInt)sourceLen;
+ if ((uLong)stream.avail_in != sourceLen)
+ return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen)
+ return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)nullptr;
+ stream.zfree = (free_func)nullptr;
+
+ err = inflateInit2(&stream, -MAX_WBITS);
+ if (err != Z_OK)
+ return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
+
+static int deflate (Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = const_cast<Bytef*>(source);
+ stream.avail_in = (uInt)sourceLen;
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)nullptr;
+ stream.zfree = (free_func)nullptr;
+ stream.opaque = (voidpf)nullptr;
+
+ err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+
+namespace WindowsFileAttributes {
+enum {
+ Dir = 0x10, // FILE_ATTRIBUTE_DIRECTORY
+ File = 0x80, // FILE_ATTRIBUTE_NORMAL
+ TypeMask = 0x90,
+
+ ReadOnly = 0x01, // FILE_ATTRIBUTE_READONLY
+ PermMask = 0x01
+};
+}
+
+namespace UnixFileAttributes {
+enum {
+ Dir = 0040000, // __S_IFDIR
+ File = 0100000, // __S_IFREG
+ SymLink = 0120000, // __S_IFLNK
+ TypeMask = 0170000, // __S_IFMT
+
+ ReadUser = 0400, // __S_IRUSR
+ WriteUser = 0200, // __S_IWUSR
+ ExeUser = 0100, // __S_IXUSR
+ ReadGroup = 0040, // __S_IRGRP
+ WriteGroup = 0020, // __S_IWGRP
+ ExeGroup = 0010, // __S_IXGRP
+ ReadOther = 0004, // __S_IROTH
+ WriteOther = 0002, // __S_IWOTH
+ ExeOther = 0001, // __S_IXOTH
+ PermMask = 0777
+};
+}
+
+static QFile::Permissions modeToPermissions(quint32 mode)
+{
+ QFile::Permissions ret;
+ if (mode & UnixFileAttributes::ReadUser)
+ ret |= QFile::ReadOwner | QFile::ReadUser;
+ if (mode & UnixFileAttributes::WriteUser)
+ ret |= QFile::WriteOwner | QFile::WriteUser;
+ if (mode & UnixFileAttributes::ExeUser)
+ ret |= QFile::ExeOwner | QFile::ExeUser;
+ if (mode & UnixFileAttributes::ReadGroup)
+ ret |= QFile::ReadGroup;
+ if (mode & UnixFileAttributes::WriteGroup)
+ ret |= QFile::WriteGroup;
+ if (mode & UnixFileAttributes::ExeGroup)
+ ret |= QFile::ExeGroup;
+ if (mode & UnixFileAttributes::ReadOther)
+ ret |= QFile::ReadOther;
+ if (mode & UnixFileAttributes::WriteOther)
+ ret |= QFile::WriteOther;
+ if (mode & UnixFileAttributes::ExeOther)
+ ret |= QFile::ExeOther;
+ return ret;
+}
+
+static quint32 permissionsToMode(QFile::Permissions perms)
+{
+ quint32 mode = 0;
+ if (perms & (QFile::ReadOwner | QFile::ReadUser))
+ mode |= UnixFileAttributes::ReadUser;
+ if (perms & (QFile::WriteOwner | QFile::WriteUser))
+ mode |= UnixFileAttributes::WriteUser;
+ if (perms & (QFile::ExeOwner | QFile::ExeUser))
+ mode |= UnixFileAttributes::WriteUser;
+ if (perms & QFile::ReadGroup)
+ mode |= UnixFileAttributes::ReadGroup;
+ if (perms & QFile::WriteGroup)
+ mode |= UnixFileAttributes::WriteGroup;
+ if (perms & QFile::ExeGroup)
+ mode |= UnixFileAttributes::ExeGroup;
+ if (perms & QFile::ReadOther)
+ mode |= UnixFileAttributes::ReadOther;
+ if (perms & QFile::WriteOther)
+ mode |= UnixFileAttributes::WriteOther;
+ if (perms & QFile::ExeOther)
+ mode |= UnixFileAttributes::ExeOther;
+ return mode;
+}
+
+static QDateTime readMSDosDate(const uchar *src)
+{
+ uint dosDate = readUInt(src);
+ quint64 uDate;
+ uDate = (quint64)(dosDate >> 16);
+ uint tm_mday = (uDate & 0x1f);
+ uint tm_mon = ((uDate & 0x1E0) >> 5);
+ uint tm_year = (((uDate & 0x0FE00) >> 9) + 1980);
+ uint tm_hour = ((dosDate & 0xF800) >> 11);
+ uint tm_min = ((dosDate & 0x7E0) >> 5);
+ uint tm_sec = ((dosDate & 0x1f) << 1);
+
+ return QDateTime(QDate(tm_year, tm_mon, tm_mday), QTime(tm_hour, tm_min, tm_sec));
+}
+
+// for details, see http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+enum HostOS {
+ HostFAT = 0,
+ HostAMIGA = 1,
+ HostVMS = 2, // VAX/VMS
+ HostUnix = 3,
+ HostVM_CMS = 4,
+ HostAtari = 5, // what if it's a minix filesystem? [cjh]
+ HostHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
+ HostMac = 7,
+ HostZ_System = 8,
+ HostCPM = 9,
+ HostTOPS20 = 10, // pkzip 2.50 NTFS
+ HostNTFS = 11, // filesystem used by Windows NT
+ HostQDOS = 12, // SMS/QDOS
+ HostAcorn = 13, // Archimedes Acorn RISC OS
+ HostVFAT = 14, // filesystem used by Windows 95, NT
+ HostMVS = 15,
+ HostBeOS = 16, // hybrid POSIX/database filesystem
+ HostTandem = 17,
+ HostOS400 = 18,
+ HostOSX = 19
+};
+Q_DECLARE_TYPEINFO(HostOS, Q_PRIMITIVE_TYPE);
+
+enum GeneralPurposeFlag {
+ Encrypted = 0x01,
+ AlgTune1 = 0x02,
+ AlgTune2 = 0x04,
+ HasDataDescriptor = 0x08,
+ PatchedData = 0x20,
+ StrongEncrypted = 0x40,
+ Utf8Names = 0x0800,
+ CentralDirectoryEncrypted = 0x2000
+};
+Q_DECLARE_TYPEINFO(GeneralPurposeFlag, Q_PRIMITIVE_TYPE);
+
+enum CompressionMethod {
+ CompressionMethodStored = 0,
+ CompressionMethodShrunk = 1,
+ CompressionMethodReduced1 = 2,
+ CompressionMethodReduced2 = 3,
+ CompressionMethodReduced3 = 4,
+ CompressionMethodReduced4 = 5,
+ CompressionMethodImploded = 6,
+ CompressionMethodReservedTokenizing = 7, // reserved for tokenizing
+ CompressionMethodDeflated = 8,
+ CompressionMethodDeflated64 = 9,
+ CompressionMethodPKImploding = 10,
+
+ CompressionMethodBZip2 = 12,
+
+ CompressionMethodLZMA = 14,
+
+ CompressionMethodTerse = 18,
+ CompressionMethodLz77 = 19,
+
+ CompressionMethodJpeg = 96,
+ CompressionMethodWavPack = 97,
+ CompressionMethodPPMd = 98,
+ CompressionMethodWzAES = 99
+};
+Q_DECLARE_TYPEINFO(CompressionMethod, Q_PRIMITIVE_TYPE);
+
+struct LocalFileHeader
+{
+ uchar signature[4]; // 0x04034b50
+ uchar version_needed[2];
+ uchar general_purpose_bits[2];
+ uchar compression_method[2];
+ uchar last_mod_file[4];
+ uchar crc_32[4];
+ uchar compressed_size[4];
+ uchar uncompressed_size[4];
+ uchar file_name_length[2];
+ uchar extra_field_length[2];
+};
+Q_DECLARE_TYPEINFO(LocalFileHeader, Q_PRIMITIVE_TYPE);
+
+struct DataDescriptor
+{
+ uchar crc_32[4];
+ uchar compressed_size[4];
+ uchar uncompressed_size[4];
+};
+Q_DECLARE_TYPEINFO(DataDescriptor, Q_PRIMITIVE_TYPE);
+
+struct CentralFileHeader
+{
+ uchar signature[4]; // 0x02014b50
+ uchar version_made[2];
+ uchar version_needed[2];
+ uchar general_purpose_bits[2];
+ uchar compression_method[2];
+ uchar last_mod_file[4];
+ uchar crc_32[4];
+ uchar compressed_size[4];
+ uchar uncompressed_size[4];
+ uchar file_name_length[2];
+ uchar extra_field_length[2];
+ uchar file_comment_length[2];
+ uchar disk_start[2];
+ uchar internal_file_attributes[2];
+ uchar external_file_attributes[4];
+ uchar offset_local_header[4];
+};
+Q_DECLARE_TYPEINFO(CentralFileHeader, Q_PRIMITIVE_TYPE);
+
+struct EndOfDirectory
+{
+ uchar signature[4]; // 0x06054b50
+ uchar this_disk[2];
+ uchar start_of_directory_disk[2];
+ uchar num_dir_entries_this_disk[2];
+ uchar num_dir_entries[2];
+ uchar directory_size[4];
+ uchar dir_start_offset[4];
+ uchar comment_length[2];
+};
+Q_DECLARE_TYPEINFO(EndOfDirectory, Q_PRIMITIVE_TYPE);
+
+struct FileHeader
+{
+ CentralFileHeader h;
+ QByteArray file_name;
+ QByteArray extra_field;
+ QByteArray file_comment;
+};
+Q_DECLARE_TYPEINFO(FileHeader, Q_RELOCATABLE_TYPE);
+
+class QZipPrivate
+{
+public:
+ QZipPrivate(QIODevice *device, bool ownDev)
+ : device(device), ownDevice(ownDev), dirtyFileTree(true), start_of_directory(0)
+ {
+ }
+
+ ~QZipPrivate()
+ {
+ if (ownDevice)
+ delete device;
+ }
+
+ QZipReader::FileInfo fillFileInfo(int index) const;
+
+ QIODevice *device;
+ bool ownDevice;
+ bool dirtyFileTree;
+ QList<FileHeader> fileHeaders;
+ QByteArray comment;
+ uint start_of_directory;
+};
+
+QZipReader::FileInfo QZipPrivate::fillFileInfo(int index) const
+{
+ QZipReader::FileInfo fileInfo;
+ FileHeader header = fileHeaders.at(index);
+ quint32 mode = readUInt(header.h.external_file_attributes);
+ const HostOS hostOS = HostOS(readUShort(header.h.version_made) >> 8);
+ switch (hostOS) {
+ case HostUnix:
+ mode = (mode >> 16) & 0xffff;
+ switch (mode & UnixFileAttributes::TypeMask) {
+ case UnixFileAttributes::SymLink:
+ fileInfo.isSymLink = true;
+ break;
+ case UnixFileAttributes::Dir:
+ fileInfo.isDir = true;
+ break;
+ case UnixFileAttributes::File:
+ default: // ### just for the case; should we warn?
+ fileInfo.isFile = true;
+ break;
+ }
+ fileInfo.permissions = modeToPermissions(mode);
+ break;
+ case HostFAT:
+ case HostNTFS:
+ case HostHPFS:
+ case HostVFAT:
+ switch (mode & WindowsFileAttributes::TypeMask) {
+ case WindowsFileAttributes::Dir:
+ fileInfo.isDir = true;
+ break;
+ case WindowsFileAttributes::File:
+ default:
+ fileInfo.isFile = true;
+ break;
+ }
+ fileInfo.permissions |= QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther;
+ if ((mode & WindowsFileAttributes::ReadOnly) == 0)
+ fileInfo.permissions |= QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther;
+ if (fileInfo.isDir)
+ fileInfo.permissions |= QFile::ExeOwner | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther;
+ break;
+ default:
+ qWarning("QZip: Zip entry format at %d is not supported.", index);
+ return fileInfo; // we don't support anything else
+ }
+
+ ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
+ // if bit 11 is set, the filename and comment fields must be encoded using UTF-8
+ const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
+ fileInfo.filePath = inUtf8 ? QString::fromUtf8(header.file_name) : QString::fromLocal8Bit(header.file_name);
+ fileInfo.crc = readUInt(header.h.crc_32);
+ fileInfo.size = readUInt(header.h.uncompressed_size);
+ fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
+
+ // fix the file path, if broken (convert separators, eat leading and trailing ones)
+ fileInfo.filePath = QDir::fromNativeSeparators(fileInfo.filePath);
+ QStringView filePathRef(fileInfo.filePath);
+ while (filePathRef.startsWith(u'.') || filePathRef.startsWith(u'/'))
+ filePathRef = filePathRef.mid(1);
+ while (filePathRef.endsWith(u'/'))
+ filePathRef.chop(1);
+
+ fileInfo.filePath = filePathRef.toString();
+ return fileInfo;
+}
+
+class QZipReaderPrivate : public QZipPrivate
+{
+public:
+ QZipReaderPrivate(QIODevice *device, bool ownDev)
+ : QZipPrivate(device, ownDev), status(QZipReader::NoError)
+ {
+ }
+
+ void scanFiles();
+
+ QZipReader::Status status;
+};
+
+class QZipWriterPrivate : public QZipPrivate
+{
+public:
+ QZipWriterPrivate(QIODevice *device, bool ownDev)
+ : QZipPrivate(device, ownDev),
+ status(QZipWriter::NoError),
+ permissions(QFile::ReadOwner | QFile::WriteOwner),
+ compressionPolicy(QZipWriter::AlwaysCompress)
+ {
+ }
+
+ QZipWriter::Status status;
+ QFile::Permissions permissions;
+ QZipWriter::CompressionPolicy compressionPolicy;
+
+ enum EntryType { Directory, File, Symlink };
+
+ void addEntry(EntryType type, const QString &fileName, const QByteArray &contents);
+};
+
+static LocalFileHeader toLocalHeader(const CentralFileHeader &ch)
+{
+ LocalFileHeader h;
+ writeUInt(h.signature, 0x04034b50);
+ copyUShort(h.version_needed, ch.version_needed);
+ copyUShort(h.general_purpose_bits, ch.general_purpose_bits);
+ copyUShort(h.compression_method, ch.compression_method);
+ copyUInt(h.last_mod_file, ch.last_mod_file);
+ copyUInt(h.crc_32, ch.crc_32);
+ copyUInt(h.compressed_size, ch.compressed_size);
+ copyUInt(h.uncompressed_size, ch.uncompressed_size);
+ copyUShort(h.file_name_length, ch.file_name_length);
+ copyUShort(h.extra_field_length, ch.extra_field_length);
+ return h;
+}
+
+void QZipReaderPrivate::scanFiles()
+{
+ if (!dirtyFileTree)
+ return;
+
+ if (! (device->isOpen() || device->open(QIODevice::ReadOnly))) {
+ status = QZipReader::FileOpenError;
+ return;
+ }
+
+ if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
+ status = QZipReader::FileReadError;
+ return;
+ }
+
+ dirtyFileTree = false;
+ uchar tmp[4];
+ device->read((char *)tmp, 4);
+ if (readUInt(tmp) != 0x04034b50) {
+ qWarning("QZip: not a zip file!");
+ return;
+ }
+
+ // find EndOfDirectory header
+ int i = 0;
+ int start_of_directory = -1;
+ int num_dir_entries = 0;
+ EndOfDirectory eod;
+ while (start_of_directory == -1) {
+ const int pos = device->size() - int(sizeof(EndOfDirectory)) - i;
+ if (pos < 0 || i > 65535) {
+ qWarning("QZip: EndOfDirectory not found");
+ return;
+ }
+
+ device->seek(pos);
+ device->read((char *)&eod, sizeof(EndOfDirectory));
+ if (readUInt(eod.signature) == 0x06054b50)
+ break;
+ ++i;
+ }
+
+ // have the eod
+ start_of_directory = readUInt(eod.dir_start_offset);
+ num_dir_entries = readUShort(eod.num_dir_entries);
+ ZDEBUG("start_of_directory at %d, num_dir_entries=%d", start_of_directory, num_dir_entries);
+ int comment_length = readUShort(eod.comment_length);
+ if (comment_length != i)
+ qWarning("QZip: failed to parse zip file.");
+ comment = device->read(qMin(comment_length, i));
+
+
+ device->seek(start_of_directory);
+ for (i = 0; i < num_dir_entries; ++i) {
+ FileHeader header;
+ int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
+ if (read < (int)sizeof(CentralFileHeader)) {
+ qWarning("QZip: Failed to read complete header, index may be incomplete");
+ break;
+ }
+ if (readUInt(header.h.signature) != 0x02014b50) {
+ qWarning("QZip: invalid header signature, index may be incomplete");
+ break;
+ }
+
+ int l = readUShort(header.h.file_name_length);
+ header.file_name = device->read(l);
+ if (header.file_name.size() != l) {
+ qWarning("QZip: Failed to read filename from zip index, index may be incomplete");
+ break;
+ }
+ l = readUShort(header.h.extra_field_length);
+ header.extra_field = device->read(l);
+ if (header.extra_field.size() != l) {
+ qWarning("QZip: Failed to read extra field in zip file, skipping file, index may be incomplete");
+ break;
+ }
+ l = readUShort(header.h.file_comment_length);
+ header.file_comment = device->read(l);
+ if (header.file_comment.size() != l) {
+ qWarning("QZip: Failed to read read file comment, index may be incomplete");
+ break;
+ }
+
+ ZDEBUG("found file '%s'", header.file_name.data());
+ fileHeaders.append(header);
+ }
+}
+
+void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const QByteArray &contents/*, QFile::Permissions permissions, QZip::Method m*/)
+{
+#ifndef NDEBUG
+ static const char *const entryTypes[] = {
+ "directory",
+ "file ",
+ "symlink " };
+ ZDEBUG() << "adding" << entryTypes[type] <<":" << fileName.toUtf8().data() << (type == 2 ? QByteArray(" -> " + contents).constData() : "");
+#endif
+
+ if (! (device->isOpen() || device->open(QIODevice::WriteOnly))) {
+ status = QZipWriter::FileOpenError;
+ return;
+ }
+ device->seek(start_of_directory);
+
+ // don't compress small files
+ QZipWriter::CompressionPolicy compression = compressionPolicy;
+ if (compressionPolicy == QZipWriter::AutoCompress) {
+ if (contents.size() < 64)
+ compression = QZipWriter::NeverCompress;
+ else
+ compression = QZipWriter::AlwaysCompress;
+ }
+
+ FileHeader header;
+ memset(&header.h, 0, sizeof(CentralFileHeader));
+ writeUInt(header.h.signature, 0x02014b50);
+
+ writeUShort(header.h.version_needed, ZIP_VERSION);
+ writeUInt(header.h.uncompressed_size, contents.size());
+ writeMSDosDate(header.h.last_mod_file, QDateTime::currentDateTime());
+ QByteArray data = contents;
+ if (compression == QZipWriter::AlwaysCompress) {
+ writeUShort(header.h.compression_method, CompressionMethodDeflated);
+
+ ulong len = contents.size();
+ // shamelessly copied form zlib
+ len += (len >> 12) + (len >> 14) + 11;
+ int res;
+ do {
+ data.resize(len);
+ res = deflate((uchar*)data.data(), &len, (const uchar*)contents.constData(), contents.size());
+
+ switch (res) {
+ case Z_OK:
+ data.resize(len);
+ break;
+ case Z_MEM_ERROR:
+ qWarning("QZip: Z_MEM_ERROR: Not enough memory to compress file, skipping");
+ data.resize(0);
+ break;
+ case Z_BUF_ERROR:
+ len *= 2;
+ break;
+ }
+ } while (res == Z_BUF_ERROR);
+ }
+// TODO add a check if data.length() > contents.length(). Then try to store the original and revert the compression method to be uncompressed
+ writeUInt(header.h.compressed_size, data.size());
+ uint crc_32 = ::crc32(0, nullptr, 0);
+ crc_32 = ::crc32(crc_32, (const uchar *)contents.constData(), contents.size());
+ writeUInt(header.h.crc_32, crc_32);
+
+ // if bit 11 is set, the filename and comment fields must be encoded using UTF-8
+ ushort general_purpose_bits = Utf8Names; // always use utf-8
+ writeUShort(header.h.general_purpose_bits, general_purpose_bits);
+
+ const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
+ header.file_name = inUtf8 ? fileName.toUtf8() : fileName.toLocal8Bit();
+ if (header.file_name.size() > 0xffff) {
+ qWarning("QZip: Filename is too long, chopping it to 65535 bytes");
+ header.file_name = header.file_name.left(0xffff); // ### don't break the utf-8 sequence, if any
+ }
+ if (header.file_comment.size() + header.file_name.size() > 0xffff) {
+ qWarning("QZip: File comment is too long, chopping it to 65535 bytes");
+ header.file_comment.truncate(0xffff - header.file_name.size()); // ### don't break the utf-8 sequence, if any
+ }
+ writeUShort(header.h.file_name_length, header.file_name.size());
+ //h.extra_field_length[2];
+
+ writeUShort(header.h.version_made, HostUnix << 8);
+ //uchar internal_file_attributes[2];
+ //uchar external_file_attributes[4];
+ quint32 mode = permissionsToMode(permissions);
+ switch (type) {
+ case Symlink:
+ mode |= UnixFileAttributes::SymLink;
+ break;
+ case Directory:
+ mode |= UnixFileAttributes::Dir;
+ break;
+ case File:
+ mode |= UnixFileAttributes::File;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ writeUInt(header.h.external_file_attributes, mode << 16);
+ writeUInt(header.h.offset_local_header, start_of_directory);
+
+
+ fileHeaders.append(header);
+
+ LocalFileHeader h = toLocalHeader(header.h);
+ device->write((const char *)&h, sizeof(LocalFileHeader));
+ device->write(header.file_name);
+ device->write(data);
+ start_of_directory = device->pos();
+ dirtyFileTree = true;
+}
+
+////////////////////////////// Reader
+
+/*!
+ \class QZipReader::FileInfo
+ \internal
+ Represents one entry in the zip table of contents.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::filePath
+ The full filepath inside the archive.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::isDir
+ A boolean type indicating if the entry is a directory.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::isFile
+ A boolean type, if it is one this entry is a file.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::isSymLink
+ A boolean type, if it is one this entry is symbolic link.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::permissions
+ A list of flags for the permissions of this entry.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::crc
+ The calculated checksum as a crc type.
+*/
+
+/*!
+ \variable QZipReader::FileInfo::size
+ The total size of the unpacked content.
+*/
+
+/*!
+ \class QZipReader
+ \internal
+ \since 4.5
+
+ \brief the QZipReader class provides a way to inspect the contents of a zip
+ archive and extract individual files from it.
+
+ QZipReader can be used to read a zip archive either from a file or from any
+ device. An in-memory QBuffer for instance. The reader can be used to read
+ which files are in the archive using fileInfoList() and entryInfoAt() but
+ also to extract individual files using fileData() or even to extract all
+ files in the archive using extractAll()
+*/
+
+/*!
+ Create a new zip archive that operates on the \a fileName. The file will be
+ opened with the \a mode.
+*/
+QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode)
+{
+ auto f = std::make_unique<QFile>(archive);
+ const bool result = f->open(mode);
+ QZipReader::Status status;
+ const QFileDevice::FileError error = f->error();
+ if (result && error == QFile::NoError) {
+ status = NoError;
+ } else {
+ if (error == QFile::ReadError)
+ status = FileReadError;
+ else if (error == QFile::OpenError)
+ status = FileOpenError;
+ else if (error == QFile::PermissionsError)
+ status = FilePermissionsError;
+ else
+ status = FileError;
+ }
+
+ d = new QZipReaderPrivate(f.get(), /*ownDevice=*/true);
+ Q_UNUSED(f.release());
+ d->status = status;
+}
+
+/*!
+ Create a new zip archive that operates on the archive found in \a device.
+ You have to open the device previous to calling the constructor and only a
+ device that is readable will be scanned for zip filecontent.
+ */
+QZipReader::QZipReader(QIODevice *device)
+ : d(new QZipReaderPrivate(device, /*ownDevice=*/false))
+{
+ Q_ASSERT(device);
+}
+
+/*!
+ Destructor
+*/
+QZipReader::~QZipReader()
+{
+ close();
+ delete d;
+}
+
+/*!
+ Returns device used for reading zip archive.
+*/
+QIODevice* QZipReader::device() const
+{
+ return d->device;
+}
+
+/*!
+ Returns \c true if the user can read the file; otherwise returns \c false.
+*/
+bool QZipReader::isReadable() const
+{
+ return d->device->isReadable();
+}
+
+/*!
+ Returns \c true if the file exists; otherwise returns \c false.
+*/
+bool QZipReader::exists() const
+{
+ QFile *f = qobject_cast<QFile*> (d->device);
+ if (f == nullptr)
+ return true;
+ return f->exists();
+}
+
+/*!
+ Returns the list of files the archive contains.
+*/
+QList<QZipReader::FileInfo> QZipReader::fileInfoList() const
+{
+ d->scanFiles();
+ QList<FileInfo> files;
+ const int numFileHeaders = d->fileHeaders.size();
+ files.reserve(numFileHeaders);
+ for (int i = 0; i < numFileHeaders; ++i)
+ files.append(d->fillFileInfo(i));
+ return files;
+
+}
+
+/*!
+ Return the number of items in the zip archive.
+*/
+int QZipReader::count() const
+{
+ d->scanFiles();
+ return d->fileHeaders.size();
+}
+
+/*!
+ Returns a FileInfo of an entry in the zipfile.
+ The \a index is the index into the directory listing of the zipfile.
+ Returns an invalid FileInfo if \a index is out of boundaries.
+
+ \sa fileInfoList()
+*/
+QZipReader::FileInfo QZipReader::entryInfoAt(int index) const
+{
+ d->scanFiles();
+ if (index >= 0 && index < d->fileHeaders.size())
+ return d->fillFileInfo(index);
+ return QZipReader::FileInfo();
+}
+
+/*!
+ Fetch the file contents from the zip archive and return the uncompressed bytes.
+*/
+QByteArray QZipReader::fileData(const QString &fileName) const
+{
+ d->scanFiles();
+ int i;
+ for (i = 0; i < d->fileHeaders.size(); ++i) {
+ if (QString::fromLocal8Bit(d->fileHeaders.at(i).file_name) == fileName)
+ break;
+ }
+ if (i == d->fileHeaders.size())
+ return QByteArray();
+
+ FileHeader header = d->fileHeaders.at(i);
+
+ ushort version_needed = readUShort(header.h.version_needed);
+ if (version_needed > ZIP_VERSION) {
+ qWarning("QZip: .ZIP specification version %d implementationis needed to extract the data.", version_needed);
+ return QByteArray();
+ }
+
+ ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
+ int compressed_size = readUInt(header.h.compressed_size);
+ int uncompressed_size = readUInt(header.h.uncompressed_size);
+ int start = readUInt(header.h.offset_local_header);
+ //qDebug("uncompressing file %d: local header at %d", i, start);
+
+ d->device->seek(start);
+ LocalFileHeader lh;
+ d->device->read((char *)&lh, sizeof(LocalFileHeader));
+ uint skip = readUShort(lh.file_name_length) + readUShort(lh.extra_field_length);
+ d->device->seek(d->device->pos() + skip);
+
+ int compression_method = readUShort(lh.compression_method);
+ //qDebug("file=%s: compressed_size=%d, uncompressed_size=%d", fileName.toLocal8Bit().data(), compressed_size, uncompressed_size);
+
+ if ((general_purpose_bits & Encrypted) != 0) {
+ qWarning("QZip: Unsupported encryption method is needed to extract the data.");
+ return QByteArray();
+ }
+
+ //qDebug("file at %lld", d->device->pos());
+ QByteArray compressed = d->device->read(compressed_size);
+ if (compression_method == CompressionMethodStored) {
+ // no compression
+ compressed.truncate(uncompressed_size);
+ return compressed;
+ } else if (compression_method == CompressionMethodDeflated) {
+ // Deflate
+ //qDebug("compressed=%d", compressed.size());
+ compressed.truncate(compressed_size);
+ QByteArray baunzip;
+ ulong len = qMax(uncompressed_size, 1);
+ int res;
+ do {
+ baunzip.resize(len);
+ res = inflate((uchar*)baunzip.data(), &len,
+ (const uchar*)compressed.constData(), compressed_size);
+
+ switch (res) {
+ case Z_OK:
+ if ((int)len != baunzip.size())
+ baunzip.resize(len);
+ break;
+ case Z_MEM_ERROR:
+ qWarning("QZip: Z_MEM_ERROR: Not enough memory");
+ break;
+ case Z_BUF_ERROR:
+ len *= 2;
+ break;
+ case Z_DATA_ERROR:
+ qWarning("QZip: Z_DATA_ERROR: Input data is corrupted");
+ break;
+ }
+ } while (res == Z_BUF_ERROR);
+ return baunzip;
+ }
+
+ qWarning("QZip: Unsupported compression method %d is needed to extract the data.", compression_method);
+ return QByteArray();
+}
+
+/*!
+ Extracts the full contents of the zip file into \a destinationDir on
+ the local filesystem.
+ In case writing or linking a file fails, the extraction will be aborted.
+*/
+bool QZipReader::extractAll(const QString &destinationDir) const
+{
+ QDir baseDir(destinationDir);
+
+ // create directories first
+ const QList<FileInfo> allFiles = fileInfoList();
+ bool foundDirs = false;
+ bool hasDirs = false;
+ for (const FileInfo &fi : allFiles) {
+ const QString absPath = destinationDir + QDir::separator() + fi.filePath;
+ if (fi.isDir) {
+ foundDirs = true;
+ if (!baseDir.mkpath(fi.filePath))
+ return false;
+ if (!QFile::setPermissions(absPath, fi.permissions))
+ return false;
+ } else if (!hasDirs && fi.filePath.contains(u"/")) {
+ // filePath does not have leading or trailing '/', so if we find
+ // one, than the file path contains directories.
+ hasDirs = true;
+ }
+ }
+
+ // Some zip archives can be broken in the sense that they do not report
+ // separate entries for directories, only for files. In this case we
+ // need to recreate directory structure based on the file paths.
+ if (hasDirs && !foundDirs) {
+ for (const FileInfo &fi : allFiles) {
+ const auto dirPath = fi.filePath.left(fi.filePath.lastIndexOf(u"/"));
+ if (!baseDir.mkpath(dirPath))
+ return false;
+ // We will leave the directory permissions default in this case,
+ // because setting dir permissions based on file is incorrect
+ }
+ }
+
+ // set up symlinks
+ for (const FileInfo &fi : allFiles) {
+ const QString absPath = destinationDir + QDir::separator() + fi.filePath;
+ if (fi.isSymLink) {
+ QString destination = QFile::decodeName(fileData(fi.filePath));
+ if (destination.isEmpty())
+ return false;
+ QFileInfo linkFi(absPath);
+ if (!QFile::exists(linkFi.absolutePath()))
+ QDir::root().mkpath(linkFi.absolutePath());
+ if (!QFile::link(destination, absPath))
+ return false;
+ /* cannot change permission of links
+ if (!QFile::setPermissions(absPath, fi.permissions))
+ return false;
+ */
+ }
+ }
+
+ for (const FileInfo &fi : allFiles) {
+ const QString absPath = destinationDir + QDir::separator() + fi.filePath;
+ if (fi.isFile) {
+ QFile f(absPath);
+ if (!f.open(QIODevice::WriteOnly))
+ return false;
+ f.write(fileData(fi.filePath));
+ f.setPermissions(fi.permissions);
+ f.close();
+ }
+ }
+
+ return true;
+}
+
+/*!
+ \enum QZipReader::Status
+
+ The following status values are possible:
+
+ \value NoError No error occurred.
+ \value FileReadError An error occurred when reading from the file.
+ \value FileOpenError The file could not be opened.
+ \value FilePermissionsError The file could not be accessed.
+ \value FileError Another file error occurred.
+*/
+
+/*!
+ Returns a status code indicating the first error that was met by QZipReader,
+ or QZipReader::NoError if no error occurred.
+*/
+QZipReader::Status QZipReader::status() const
+{
+ return d->status;
+}
+
+/*!
+ Close the zip file.
+*/
+void QZipReader::close()
+{
+ d->device->close();
+}
+
+////////////////////////////// Writer
+
+/*!
+ \class QZipWriter
+ \internal
+ \since 4.5
+
+ \brief the QZipWriter class provides a way to create a new zip archive.
+
+ QZipWriter can be used to create a zip archive containing any number of files
+ and directories. The files in the archive will be compressed in a way that is
+ compatible with common zip reader applications.
+*/
+
+
+/*!
+ Create a new zip archive that operates on the \a archive filename. The file will
+ be opened with the \a mode.
+ \sa isValid()
+*/
+QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode)
+{
+ auto f = std::make_unique<QFile>(fileName);
+ QZipWriter::Status status;
+ if (f->open(mode) && f->error() == QFile::NoError)
+ status = QZipWriter::NoError;
+ else {
+ if (f->error() == QFile::WriteError)
+ status = QZipWriter::FileWriteError;
+ else if (f->error() == QFile::OpenError)
+ status = QZipWriter::FileOpenError;
+ else if (f->error() == QFile::PermissionsError)
+ status = QZipWriter::FilePermissionsError;
+ else
+ status = QZipWriter::FileError;
+ }
+
+ d = new QZipWriterPrivate(f.get(), /*ownDevice=*/true);
+ Q_UNUSED(f.release());
+ d->status = status;
+}
+
+/*!
+ Create a new zip archive that operates on the archive found in \a device.
+ You have to open the device previous to calling the constructor and
+ only a device that is readable will be scanned for zip filecontent.
+ */
+QZipWriter::QZipWriter(QIODevice *device)
+ : d(new QZipWriterPrivate(device, /*ownDevice=*/false))
+{
+ Q_ASSERT(device);
+}
+
+QZipWriter::~QZipWriter()
+{
+ close();
+ delete d;
+}
+
+/*!
+ Returns device used for writing zip archive.
+*/
+QIODevice* QZipWriter::device() const
+{
+ return d->device;
+}
+
+/*!
+ Returns \c true if the user can write to the archive; otherwise returns \c false.
+*/
+bool QZipWriter::isWritable() const
+{
+ return d->device->isWritable();
+}
+
+/*!
+ Returns \c true if the file exists; otherwise returns \c false.
+*/
+bool QZipWriter::exists() const
+{
+ QFile *f = qobject_cast<QFile*> (d->device);
+ if (f == nullptr)
+ return true;
+ return f->exists();
+}
+
+/*!
+ \enum QZipWriter::Status
+
+ The following status values are possible:
+
+ \value NoError No error occurred.
+ \value FileWriteError An error occurred when writing to the device.
+ \value FileOpenError The file could not be opened.
+ \value FilePermissionsError The file could not be accessed.
+ \value FileError Another file error occurred.
+*/
+
+/*!
+ Returns a status code indicating the first error that was met by QZipWriter,
+ or QZipWriter::NoError if no error occurred.
+*/
+QZipWriter::Status QZipWriter::status() const
+{
+ return d->status;
+}
+
+/*!
+ \enum QZipWriter::CompressionPolicy
+
+ \value AlwaysCompress A file that is added is compressed.
+ \value NeverCompress A file that is added will be stored without changes.
+ \value AutoCompress A file that is added will be compressed only if that will give a smaller file.
+*/
+
+/*!
+ Sets the policy for compressing newly added files to the new \a policy.
+
+ \note the default policy is AlwaysCompress
+
+ \sa compressionPolicy()
+ \sa addFile()
+*/
+void QZipWriter::setCompressionPolicy(CompressionPolicy policy)
+{
+ d->compressionPolicy = policy;
+}
+
+/*!
+ Returns the currently set compression policy.
+ \sa setCompressionPolicy()
+ \sa addFile()
+*/
+QZipWriter::CompressionPolicy QZipWriter::compressionPolicy() const
+{
+ return d->compressionPolicy;
+}
+
+/*!
+ Sets the permissions that will be used for newly added files.
+
+ \note the default permissions are QFile::ReadOwner | QFile::WriteOwner.
+
+ \sa creationPermissions()
+ \sa addFile()
+*/
+void QZipWriter::setCreationPermissions(QFile::Permissions permissions)
+{
+ d->permissions = permissions;
+}
+
+/*!
+ Returns the currently set creation permissions.
+
+ \sa setCreationPermissions()
+ \sa addFile()
+*/
+QFile::Permissions QZipWriter::creationPermissions() const
+{
+ return d->permissions;
+}
+
+/*!
+ Add a file to the archive with \a data as the file contents.
+ The file will be stored in the archive using the \a fileName which
+ includes the full path in the archive.
+
+ The new file will get the file permissions based on the current
+ creationPermissions and it will be compressed using the zip compression
+ based on the current compression policy.
+
+ \sa setCreationPermissions()
+ \sa setCompressionPolicy()
+*/
+void QZipWriter::addFile(const QString &fileName, const QByteArray &data)
+{
+ d->addEntry(QZipWriterPrivate::File, QDir::fromNativeSeparators(fileName), data);
+}
+
+/*!
+ Add a file to the archive with \a device as the source of the contents.
+ The contents returned from QIODevice::readAll() will be used as the
+ filedata.
+ The file will be stored in the archive using the \a fileName which
+ includes the full path in the archive.
+*/
+void QZipWriter::addFile(const QString &fileName, QIODevice *device)
+{
+ Q_ASSERT(device);
+ QIODevice::OpenMode mode = device->openMode();
+ bool opened = false;
+ if ((mode & QIODevice::ReadOnly) == 0) {
+ opened = true;
+ if (! device->open(QIODevice::ReadOnly)) {
+ d->status = FileOpenError;
+ return;
+ }
+ }
+ d->addEntry(QZipWriterPrivate::File, QDir::fromNativeSeparators(fileName), device->readAll());
+ if (opened)
+ device->close();
+}
+
+/*!
+ Create a new directory in the archive with the specified \a dirName and
+ the \a permissions;
+*/
+void QZipWriter::addDirectory(const QString &dirName)
+{
+ QString name(QDir::fromNativeSeparators(dirName));
+ // separator is mandatory
+ if (!name.endsWith(u'/'))
+ name.append(u'/');
+ d->addEntry(QZipWriterPrivate::Directory, name, QByteArray());
+}
+
+/*!
+ Create a new symbolic link in the archive with the specified \a dirName
+ and the \a permissions;
+ A symbolic link contains the destination (relative) path and name.
+*/
+void QZipWriter::addSymLink(const QString &fileName, const QString &destination)
+{
+ d->addEntry(QZipWriterPrivate::Symlink, QDir::fromNativeSeparators(fileName), QFile::encodeName(destination));
+}
+
+/*!
+ Closes the zip file.
+*/
+void QZipWriter::close()
+{
+ if (!(d->device->openMode() & QIODevice::WriteOnly)) {
+ d->device->close();
+ return;
+ }
+
+ //qDebug("QZip::close writing directory, %d entries", d->fileHeaders.size());
+ d->device->seek(d->start_of_directory);
+ // write new directory
+ for (int i = 0; i < d->fileHeaders.size(); ++i) {
+ const FileHeader &header = d->fileHeaders.at(i);
+ d->device->write((const char *)&header.h, sizeof(CentralFileHeader));
+ d->device->write(header.file_name);
+ d->device->write(header.extra_field);
+ d->device->write(header.file_comment);
+ }
+ int dir_size = d->device->pos() - d->start_of_directory;
+ // write end of directory
+ EndOfDirectory eod;
+ memset(&eod, 0, sizeof(EndOfDirectory));
+ writeUInt(eod.signature, 0x06054b50);
+ //uchar this_disk[2];
+ //uchar start_of_directory_disk[2];
+ writeUShort(eod.num_dir_entries_this_disk, d->fileHeaders.size());
+ writeUShort(eod.num_dir_entries, d->fileHeaders.size());
+ writeUInt(eod.directory_size, dir_size);
+ writeUInt(eod.dir_start_offset, d->start_of_directory);
+ writeUShort(eod.comment_length, d->comment.size());
+
+ d->device->write((const char *)&eod, sizeof(EndOfDirectory));
+ d->device->write(d->comment);
+ d->device->close();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qzipreader_p.h b/src/corelib/io/qzipreader_p.h
new file mode 100644
index 0000000000..e6ddd0dc99
--- /dev/null
+++ b/src/corelib/io/qzipreader_p.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QZIPREADER_H
+#define QZIPREADER_H
+
+#include <QtCore/private/qglobal_p.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QZipReader class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QZipReaderPrivate;
+
+class Q_CORE_EXPORT QZipReader
+{
+public:
+ explicit QZipReader(const QString &fileName, QIODevice::OpenMode mode = QIODevice::ReadOnly );
+
+ explicit QZipReader(QIODevice *device);
+ ~QZipReader();
+
+ QIODevice* device() const;
+
+ bool isReadable() const;
+ bool exists() const;
+
+ struct FileInfo
+ {
+ FileInfo() noexcept
+ : isDir(false), isFile(false), isSymLink(false), crc(0), size(0)
+ {}
+
+ bool isValid() const noexcept { return isDir || isFile || isSymLink; }
+
+ QString filePath;
+ uint isDir : 1;
+ uint isFile : 1;
+ uint isSymLink : 1;
+ QFile::Permissions permissions;
+ uint crc;
+ qint64 size;
+ QDateTime lastModified;
+ };
+
+ QList<FileInfo> fileInfoList() const;
+ int count() const;
+
+ FileInfo entryInfoAt(int index) const;
+ QByteArray fileData(const QString &fileName) const;
+ bool extractAll(const QString &destinationDir) const;
+
+ enum Status {
+ NoError,
+ FileReadError,
+ FileOpenError,
+ FilePermissionsError,
+ FileError
+ };
+
+ Status status() const;
+
+ void close();
+
+private:
+ QZipReaderPrivate *d;
+ Q_DISABLE_COPY_MOVE(QZipReader)
+};
+Q_DECLARE_TYPEINFO(QZipReader::FileInfo, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QZipReader::Status, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QZIPREADER_H
diff --git a/src/corelib/io/qzipwriter_p.h b/src/corelib/io/qzipwriter_p.h
new file mode 100644
index 0000000000..770e6118b6
--- /dev/null
+++ b/src/corelib/io/qzipwriter_p.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QZIPWRITER_H
+#define QZIPWRITER_H
+
+#include <QtCore/private/qglobal_p.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QZipWriter class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstring.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+class QZipWriterPrivate;
+
+class Q_CORE_EXPORT QZipWriter
+{
+public:
+ explicit QZipWriter(const QString &fileName, QIODevice::OpenMode mode = (QIODevice::WriteOnly | QIODevice::Truncate) );
+
+ explicit QZipWriter(QIODevice *device);
+ ~QZipWriter();
+
+ QIODevice* device() const;
+
+ bool isWritable() const;
+ bool exists() const;
+
+ enum Status {
+ NoError,
+ FileWriteError,
+ FileOpenError,
+ FilePermissionsError,
+ FileError
+ };
+
+ Status status() const;
+
+ enum CompressionPolicy {
+ AlwaysCompress,
+ NeverCompress,
+ AutoCompress
+ };
+
+ void setCompressionPolicy(CompressionPolicy policy);
+ CompressionPolicy compressionPolicy() const;
+
+ void setCreationPermissions(QFile::Permissions permissions);
+ QFile::Permissions creationPermissions() const;
+
+ void addFile(const QString &fileName, const QByteArray &data);
+
+ void addFile(const QString &fileName, QIODevice *device);
+
+ void addDirectory(const QString &dirName);
+
+ void addSymLink(const QString &fileName, const QString &destination);
+
+ void close();
+private:
+ QZipWriterPrivate *d;
+ Q_DISABLE_COPY_MOVE(QZipWriter)
+};
+
+QT_END_NAMESPACE
+
+#endif // QZIPWRITER_H