summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qdiriterator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qdiriterator.cpp')
-rw-r--r--src/corelib/io/qdiriterator.cpp424
1 files changed, 93 insertions, 331 deletions
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 792f2a863d..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
@@ -60,16 +24,19 @@
\snippet code/src_corelib_io_qdiriterator.cpp 1
- The next() function returns the path to the next directory entry and
- advances the iterator. You can also call filePath() to get the current
- file path without advancing the iterator. The fileName() function returns
- only the name of the file, similar to how QDir::entryList() works. You can
- also call fileInfo() to get a QFileInfo for the current entry.
+ The next() and nextFileInfo() functions advance the iterator and return
+ the path or the QFileInfo of the next directory entry. You can also call
+ filePath() or fileInfo() to get the current file path or QFileInfo without
+ first advancing the iterator. The fileName() function returns only the
+ name of the file, similar to how QDir::entryList() works.
Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
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
+ static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)
+ {
+ using F = QDirListing::IteratorFlag;
+ QDirListing::IteratorFlags listerFlags;
- QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators;
-#ifndef QT_NO_FILESYSTEMITERATOR
- QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators;
-#endif
+ if (flags & QDirIterator::NoIteratorFlags)
+ listerFlags.setFlag(F::NoFlag);
+ if (flags & QDirIterator::FollowSymlinks)
+ listerFlags.setFlag(F::FollowSymlinks);
+ if (flags & QDirIterator::Subdirectories)
+ listerFlags.setFlag(F::Recursive);
- QFileInfo currentFileInfo;
- QFileInfo nextFileInfo;
-
- // Loop protection
- QDuplicateTracker<QString> visitedLinks;
-};
-
-/*!
- \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))
{
}
@@ -490,33 +237,48 @@ QDirIterator::~QDirIterator()
new entry. If hasNext() returns \c false, this function does nothing, and
returns an empty QString.
- You can call fileName() or filePath() to get the current entry file name
+ You can call fileName() or filePath() to get the current entry's file name
or path, or fileInfo() to get a QFileInfo for the current entry.
- \sa hasNext(), fileName(), filePath(), fileInfo()
+ Call nextFileInfo() instead of next() if you're interested in the QFileInfo.
+
+ \sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo()
*/
QString QDirIterator::next()
{
d->advance();
- return filePath();
+ return d->currentFileInfo.filePath();
+}
+
+/*!
+ \since 6.3
+
+ Advances the iterator to the next entry, and returns the file info of this
+ new entry. If hasNext() returns \c false, this function does nothing, and
+ returns an empty QFileInfo.
+
+ You can call fileName() or filePath() to get the current entry's file name
+ or path, or fileInfo() to get a QFileInfo for the current entry.
+
+ Call next() instead of nextFileInfo() when all you need is the filePath().
+
+ \sa hasNext(), fileName(), filePath(), fileInfo()
+*/
+QFileInfo QDirIterator::nextFileInfo()
+{
+ d->advance();
+ return d->currentFileInfo;
}
/*!
Returns \c true if there is at least one more entry in the directory;
otherwise, false is returned.
- \sa next(), fileName(), filePath(), fileInfo()
+ \sa next(), nextFileInfo(), fileName(), filePath(), fileInfo()
*/
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();
}
/*!
@@ -559,7 +321,7 @@ QFileInfo QDirIterator::fileInfo() const
*/
QString QDirIterator::path() const
{
- return d->dirEntry.filePath();
+ return d->lister.iteratorPath();
}
QT_END_NAMESPACE