QDirIterator: port to QDirListing internally
De-duplicates the code between the two classes. [ChangeLog][Core][QDirIterator] This class has been deprecated and may be removed in a future Qt release. Use QDirListing instead. Change-Id: Iceba5091e72ea462dc9c5145a474bf312ee78043 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
c610cfe328
commit
94dfcaac8a
@ -34,6 +34,9 @@
|
|||||||
you cannot iterate directories in reverse order) and does not allow random
|
you cannot iterate directories in reverse order) and does not allow random
|
||||||
access.
|
access.
|
||||||
|
|
||||||
|
\note This class is deprecated and may be removed in a Qt release. Use
|
||||||
|
QDirListing instead.
|
||||||
|
|
||||||
\sa QDir, QDir::entryList()
|
\sa QDir, QDir::entryList()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -56,6 +59,8 @@
|
|||||||
#include "qdiriterator.h"
|
#include "qdiriterator.h"
|
||||||
#include "qdir_p.h"
|
#include "qdir_p.h"
|
||||||
#include "qabstractfileengine_p.h"
|
#include "qabstractfileengine_p.h"
|
||||||
|
#include "qdirlisting.h"
|
||||||
|
#include "qdirentryinfo_p.h"
|
||||||
|
|
||||||
#include <QtCore/qset.h>
|
#include <QtCore/qset.h>
|
||||||
#include <QtCore/qstack.h>
|
#include <QtCore/qstack.h>
|
||||||
@ -81,292 +86,66 @@ using namespace Qt::StringLiterals;
|
|||||||
|
|
||||||
class QDirIteratorPrivate
|
class QDirIteratorPrivate
|
||||||
{
|
{
|
||||||
|
static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)
|
||||||
|
{
|
||||||
|
using F = QDirListing::IteratorFlag;
|
||||||
|
QDirListing::IteratorFlags listerFlags;
|
||||||
|
|
||||||
|
if (flags & QDirIterator::NoIteratorFlags)
|
||||||
|
listerFlags.setFlag(F::NoFlag);
|
||||||
|
if (flags & QDirIterator::FollowSymlinks)
|
||||||
|
listerFlags.setFlag(F::FollowSymlinks);
|
||||||
|
if (flags & QDirIterator::Subdirectories)
|
||||||
|
listerFlags.setFlag(F::Recursive);
|
||||||
|
|
||||||
|
return listerFlags;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(bool resolveEngine);
|
QDirIteratorPrivate(const QDir &dir, QDirIterator::IteratorFlags flags)
|
||||||
void advance();
|
: lister(dir, toDirListingFlags(flags))
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
QDirIteratorPrivate(const QString &path, QDirIterator::IteratorFlags flags)
|
||||||
|
: lister(path, toDirListingFlags(flags))
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
QDirIteratorPrivate(const QString &path, QDir::Filters filters,
|
||||||
|
QDirIterator::IteratorFlags flags)
|
||||||
|
: lister(path, filters, toDirListingFlags(flags))
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
|
||||||
|
QDirIterator::IteratorFlags flags)
|
||||||
|
: lister(path, nameFilters, filters, toDirListingFlags(flags))
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
|
void init()
|
||||||
void pushDirectory(const QFileInfo &fileInfo);
|
{
|
||||||
void checkAndPushDirectory(const QFileInfo &);
|
it = lister.begin();
|
||||||
bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
|
if (it != lister.end())
|
||||||
|
nextFileInfo = it->fileInfo();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<QAbstractFileEngine> engine;
|
void advance()
|
||||||
|
{
|
||||||
QFileSystemEntry dirEntry;
|
currentFileInfo = nextFileInfo;
|
||||||
QStringList nameFilters;
|
if (++it != lister.end()) {
|
||||||
QDir::Filters filters;
|
nextFileInfo = it->fileInfo();
|
||||||
QDirIterator::IteratorFlags iteratorFlags;
|
}
|
||||||
|
}
|
||||||
#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
|
|
||||||
|
|
||||||
|
QDirListing lister;
|
||||||
|
QDirListing::const_iterator it = {};
|
||||||
QFileInfo currentFileInfo;
|
QFileInfo currentFileInfo;
|
||||||
QFileInfo nextFileInfo;
|
QFileInfo nextFileInfo;
|
||||||
|
|
||||||
// Loop protection
|
|
||||||
QDuplicateTracker<QString> visitedLinks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void QDirIteratorPrivate::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());
|
|
||||||
for (const auto &filter : nameFilters) {
|
|
||||||
auto re = QRegularExpression::fromWildcard(filter, (filters & QDir::CaseSensitive ?
|
|
||||||
Qt::CaseSensitive : Qt::CaseInsensitive));
|
|
||||||
nameRegExps.append(re);
|
|
||||||
}
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine) {
|
|
||||||
engine->setFileName(path);
|
|
||||||
QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
|
|
||||||
if (it) {
|
|
||||||
it->setPath(path);
|
|
||||||
fileEngineIterators.emplace(FEngineIteratorPtr(it));
|
|
||||||
} else {
|
|
||||||
// No iterator; no entry list.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
|
||||||
nativeIterators.emplace(std::make_unique<QFileSystemIterator>(
|
|
||||||
fileInfo.d_ptr->fileEntry, filters));
|
|
||||||
#else
|
|
||||||
qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\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 QDirIteratorPrivate::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->hasNext()) {
|
|
||||||
it->next();
|
|
||||||
if (entryMatches(it->currentFileName(), it->currentFileInfo()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileEngineIterators.pop();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
|
||||||
QFileSystemEntry nextEntry;
|
|
||||||
QFileSystemMetaData nextMetaData;
|
|
||||||
|
|
||||||
while (!nativeIterators.empty()) {
|
|
||||||
// Find the next valid iterator that matches the filters.
|
|
||||||
QFileSystemIterator *it;
|
|
||||||
while (it = nativeIterators.top().get(), it->advance(nextEntry, nextMetaData)) {
|
|
||||||
QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
|
|
||||||
|
|
||||||
if (entryMatches(nextEntry.fileName(), info))
|
|
||||||
return;
|
|
||||||
nextMetaData = QFileSystemMetaData();
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeIterators.pop();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a QDirIterator that can iterate over \a dir's entrylist, using
|
Constructs a QDirIterator that can iterate over \a dir's entrylist, using
|
||||||
\a dir's name filters and regular filters. You can pass options via \a
|
\a dir's name filters and regular filters. You can pass options via \a
|
||||||
@ -383,15 +162,8 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
|
|||||||
\sa hasNext(), next(), IteratorFlags
|
\sa hasNext(), next(), IteratorFlags
|
||||||
*/
|
*/
|
||||||
QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
|
QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
|
||||||
: d(new QDirIteratorPrivate)
|
: d(new QDirIteratorPrivate(dir, flags))
|
||||||
{
|
{
|
||||||
const QDirPrivate *other = dir.d_ptr.constData();
|
|
||||||
d->dirEntry = other->dirEntry;
|
|
||||||
d->nameFilters = other->nameFilters;
|
|
||||||
d->filters = other->filters;
|
|
||||||
d->iteratorFlags = flags;
|
|
||||||
const bool resolveEngine = other->fileEngine ? true : false;
|
|
||||||
d->init(resolveEngine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -408,12 +180,8 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
|
|||||||
\sa hasNext(), next(), IteratorFlags
|
\sa hasNext(), next(), IteratorFlags
|
||||||
*/
|
*/
|
||||||
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
|
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
|
||||||
: d(new QDirIteratorPrivate)
|
: d(new QDirIteratorPrivate(path, filters, flags))
|
||||||
{
|
{
|
||||||
d->dirEntry = QFileSystemEntry(path);
|
|
||||||
d->filters = filters;
|
|
||||||
d->iteratorFlags = flags;
|
|
||||||
d->init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -429,12 +197,8 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF
|
|||||||
\sa hasNext(), next(), IteratorFlags
|
\sa hasNext(), next(), IteratorFlags
|
||||||
*/
|
*/
|
||||||
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
|
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
|
||||||
: d(new QDirIteratorPrivate)
|
: d(new QDirIteratorPrivate(path, flags))
|
||||||
{
|
{
|
||||||
d->dirEntry = QFileSystemEntry(path);
|
|
||||||
d->filters = QDir::NoFilter;
|
|
||||||
d->iteratorFlags = flags;
|
|
||||||
d->init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -457,13 +221,8 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
|
|||||||
*/
|
*/
|
||||||
QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
|
QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
|
||||||
QDir::Filters filters, IteratorFlags flags)
|
QDir::Filters filters, IteratorFlags flags)
|
||||||
: d(new QDirIteratorPrivate)
|
: d(new QDirIteratorPrivate(path, nameFilters, filters, flags))
|
||||||
{
|
{
|
||||||
d->dirEntry = QFileSystemEntry(path);
|
|
||||||
d->nameFilters = nameFilters;
|
|
||||||
d->filters = filters;
|
|
||||||
d->iteratorFlags = flags;
|
|
||||||
d->init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -488,7 +247,7 @@ QDirIterator::~QDirIterator()
|
|||||||
QString QDirIterator::next()
|
QString QDirIterator::next()
|
||||||
{
|
{
|
||||||
d->advance();
|
d->advance();
|
||||||
return filePath();
|
return d->currentFileInfo.filePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -508,7 +267,7 @@ QString QDirIterator::next()
|
|||||||
QFileInfo QDirIterator::nextFileInfo()
|
QFileInfo QDirIterator::nextFileInfo()
|
||||||
{
|
{
|
||||||
d->advance();
|
d->advance();
|
||||||
return fileInfo();
|
return d->currentFileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -519,14 +278,7 @@ QFileInfo QDirIterator::nextFileInfo()
|
|||||||
*/
|
*/
|
||||||
bool QDirIterator::hasNext() const
|
bool QDirIterator::hasNext() const
|
||||||
{
|
{
|
||||||
if (d->engine)
|
return d->it != d->lister.end();
|
||||||
return !d->fileEngineIterators.empty();
|
|
||||||
else
|
|
||||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
|
||||||
return !d->nativeIterators.empty();
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -569,7 +321,7 @@ QFileInfo QDirIterator::fileInfo() const
|
|||||||
*/
|
*/
|
||||||
QString QDirIterator::path() const
|
QString QDirIterator::path() const
|
||||||
{
|
{
|
||||||
return d->dirEntry.filePath();
|
return d->lister.iteratorPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user