diff options
Diffstat (limited to 'src/corelib/io/qdiriterator.cpp')
-rw-r--r-- | src/corelib/io/qdiriterator.cpp | 348 |
1 files changed, 61 insertions, 287 deletions
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 258bb631da..3604e673e2 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -34,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() */ @@ -56,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> @@ -72,297 +77,74 @@ #include <QtCore/private/qduplicatetracker_p.h> #include <memory> +#include <stack> +#include <vector> QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -template <class Iterator> -class QDirIteratorPrivateIteratorStack : public QStack<Iterator *> -{ -public: - ~QDirIteratorPrivateIteratorStack() - { - qDeleteAll(*this); - } -}; - 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("*"_L1) ? 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 ("."_L1 == fileName || ".."_L1 == 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] == 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 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 @@ -380,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))); } /*! @@ -399,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)) { } @@ -416,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)) { } @@ -440,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)) { } @@ -466,7 +247,7 @@ QDirIterator::~QDirIterator() QString QDirIterator::next() { d->advance(); - return filePath(); + return d->currentFileInfo.filePath(); } /*! @@ -486,7 +267,7 @@ QString QDirIterator::next() QFileInfo QDirIterator::nextFileInfo() { d->advance(); - return fileInfo(); + return d->currentFileInfo; } /*! @@ -497,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(); } /*! @@ -547,7 +321,7 @@ QFileInfo QDirIterator::fileInfo() const */ QString QDirIterator::path() const { - return d->dirEntry.filePath(); + return d->lister.iteratorPath(); } QT_END_NAMESPACE |