diff options
Diffstat (limited to 'src/corelib/io/qdiriterator.cpp')
-rw-r--r-- | src/corelib/io/qdiriterator.cpp | 424 |
1 files changed, 93 insertions, 331 deletions
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 9799c9b075..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 & QDir::NoSymLinks); - const bool includeSystem = (filters & 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 & 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 |