| 1 | // Copyright (C) 2016 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 3 |  | 
| 4 | /*! | 
| 5 |     \since 4.3 | 
| 6 |     \class QDirIterator | 
| 7 |     \inmodule QtCore | 
| 8 |     \ingroup io | 
| 9 |     \brief The QDirIterator class provides an iterator for directory entrylists. | 
| 10 |  | 
| 11 |     You can use QDirIterator to navigate entries of a directory one at a time. | 
| 12 |     It is similar to QDir::entryList() and QDir::entryInfoList(), but because | 
| 13 |     it lists entries one at a time instead of all at once, it scales better | 
| 14 |     and is more suitable for large directories. It also supports listing | 
| 15 |     directory contents recursively, and following symbolic links. Unlike | 
| 16 |     QDir::entryList(), QDirIterator does not support sorting. | 
| 17 |  | 
| 18 |     The QDirIterator constructor takes a QDir or a directory as | 
| 19 |     argument. After construction, the iterator is located before the first | 
| 20 |     directory entry. Here's how to iterate over all the entries sequentially: | 
| 21 |  | 
| 22 |     \snippet code/src_corelib_io_qdiriterator.cpp 0 | 
| 23 |  | 
| 24 |     Here's how to find and read all files filtered by name, recursively: | 
| 25 |  | 
| 26 |     \snippet code/src_corelib_io_qdiriterator.cpp 1 | 
| 27 |  | 
| 28 |     The next() and nextFileInfo() functions advance the iterator and return | 
| 29 |     the path or the QFileInfo of the next directory entry. You can also call | 
| 30 |     filePath() or fileInfo() to get the current file path or QFileInfo without | 
| 31 |     first advancing the iterator. The fileName() function returns only the | 
| 32 |     name of the file, similar to how QDir::entryList() works. | 
| 33 |  | 
| 34 |     Unlike Qt's container iterators, QDirIterator is uni-directional (i.e., | 
| 35 |     you cannot iterate directories in reverse order) and does not allow random | 
| 36 |     access. | 
| 37 |  | 
| 38 |     \note This class is deprecated and may be removed in a Qt release. Use | 
| 39 |     QDirListing instead. | 
| 40 |  | 
| 41 |     \sa QDir, QDir::entryList() | 
| 42 | */ | 
| 43 |  | 
| 44 | /*! \enum QDirIterator::IteratorFlag | 
| 45 |  | 
| 46 |     This enum describes flags that you can combine to configure the behavior | 
| 47 |     of QDirIterator. | 
| 48 |  | 
| 49 |     \value NoIteratorFlags The default value, representing no flags. The | 
| 50 |     iterator will return entries for the assigned path. | 
| 51 |  | 
| 52 |     \value Subdirectories List entries inside all subdirectories as well. | 
| 53 |  | 
| 54 |     \value FollowSymlinks When combined with Subdirectories, this flag | 
| 55 |     enables iterating through all subdirectories of the assigned path, | 
| 56 |     following all symbolic links. Symbolic link loops (e.g., "link" => "." or | 
| 57 |     "link" => "..") are automatically detected and ignored. | 
| 58 | */ | 
| 59 |  | 
| 60 | #include "qdiriterator.h" | 
| 61 | #include "qdir_p.h" | 
| 62 | #include "qabstractfileengine_p.h" | 
| 63 | #include "qdirlisting.h" | 
| 64 | #include "qdirentryinfo_p.h" | 
| 65 |  | 
| 66 | #include <QtCore/qset.h> | 
| 67 | #include <QtCore/qstack.h> | 
| 68 | #include <QtCore/qvariant.h> | 
| 69 | #if QT_CONFIG(regularexpression) | 
| 70 | #include <QtCore/qregularexpression.h> | 
| 71 | #endif | 
| 72 |  | 
| 73 | #include <QtCore/private/qfilesystemiterator_p.h> | 
| 74 | #include <QtCore/private/qfilesystementry_p.h> | 
| 75 | #include <QtCore/private/qfilesystemmetadata_p.h> | 
| 76 | #include <QtCore/private/qfilesystemengine_p.h> | 
| 77 | #include <QtCore/private/qfileinfo_p.h> | 
| 78 | #include <QtCore/private/qduplicatetracker_p.h> | 
| 79 |  | 
| 80 | #include <memory> | 
| 81 | #include <stack> | 
| 82 | #include <vector> | 
| 83 |  | 
| 84 | QT_BEGIN_NAMESPACE | 
| 85 |  | 
| 86 | using namespace Qt::StringLiterals; | 
| 87 |  | 
| 88 | class QDirIteratorPrivate | 
| 89 | { | 
| 90 | public: | 
| 91 |     QDirIteratorPrivate(const QString &path, const QStringList &nameFilters = {}, | 
| 92 |                         QDir::Filters filters = QDir::NoFilter, | 
| 93 |                         QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags) | 
| 94 |         : lister(path, nameFilters, filters.toInt(), flags.toInt()) | 
| 95 |     { init(); } | 
| 96 |  | 
| 97 |     void init() | 
| 98 |     { | 
| 99 |         it = lister.begin(); | 
| 100 |         if (it != lister.end()) | 
| 101 |             nextFileInfo = it->fileInfo(); | 
| 102 |     } | 
| 103 |  | 
| 104 |     void advance() | 
| 105 |     { | 
| 106 |         // Match the behavior of advance() from before porting to QDirListing, | 
| 107 |         // that is, even if hasNext() returns false, calling next() returns an | 
| 108 |         // empty string without crashing. QTBUG-130142 | 
| 109 |         if (it == lister.end()) | 
| 110 |             return; | 
| 111 |         currentFileInfo = nextFileInfo; | 
| 112 |         if (++it != lister.end()) { | 
| 113 |             nextFileInfo = it->fileInfo(); | 
| 114 |         } | 
| 115 |     } | 
| 116 |  | 
| 117 |     QDirListing lister; | 
| 118 |     QDirListing::const_iterator it = {}; | 
| 119 |     QFileInfo currentFileInfo; | 
| 120 |     QFileInfo nextFileInfo; | 
| 121 | }; | 
| 122 |  | 
| 123 | /*! | 
| 124 |     Constructs a QDirIterator that can iterate over \a dir's entrylist, using | 
| 125 |     \a dir's name filters and regular filters. You can pass options via \a | 
| 126 |     flags to decide how the directory should be iterated. | 
| 127 |  | 
| 128 |     By default, \a flags is NoIteratorFlags, which provides the same behavior | 
| 129 |     as in QDir::entryList(). | 
| 130 |  | 
| 131 |     The sorting in \a dir is ignored. | 
| 132 |  | 
| 133 |     \note To list symlinks that point to non existing files, QDir::System must be | 
| 134 |      passed to the flags. | 
| 135 |  | 
| 136 |     \sa hasNext(), next(), IteratorFlags | 
| 137 | */ | 
| 138 | QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) | 
| 139 |     : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags)) | 
| 140 | { | 
| 141 | } | 
| 142 |  | 
| 143 | /*! | 
| 144 |     Constructs a QDirIterator that can iterate over \a path, with no name | 
| 145 |     filtering and \a filters for entry filtering. You can pass options via \a | 
| 146 |     flags to decide how the directory should be iterated. | 
| 147 |  | 
| 148 |     By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags, | 
| 149 |     which provides the same behavior as in QDir::entryList(). | 
| 150 |  | 
| 151 |     \note To list symlinks that point to non existing files, QDir::System must be | 
| 152 |      passed to the flags. | 
| 153 |  | 
| 154 |     \sa hasNext(), next(), IteratorFlags | 
| 155 | */ | 
| 156 | QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) | 
| 157 |     : d(new QDirIteratorPrivate(path, {}, filters, flags)) | 
| 158 | { | 
| 159 | } | 
| 160 |  | 
| 161 | /*! | 
| 162 |     Constructs a QDirIterator that can iterate over \a path. You can pass | 
| 163 |     options via \a flags to decide how the directory should be iterated. | 
| 164 |  | 
| 165 |     By default, \a flags is NoIteratorFlags, which provides the same behavior | 
| 166 |     as in QDir::entryList(). | 
| 167 |  | 
| 168 |     \note To list symlinks that point to non existing files, QDir::System must be | 
| 169 |      passed to the flags. | 
| 170 |  | 
| 171 |     \sa hasNext(), next(), IteratorFlags | 
| 172 | */ | 
| 173 | QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) | 
| 174 |     : d(new QDirIteratorPrivate(path, {}, QDir::NoFilter, flags)) | 
| 175 | { | 
| 176 | } | 
| 177 |  | 
| 178 | /*! | 
| 179 |     Constructs a QDirIterator that can iterate over \a path, using \a | 
| 180 |     nameFilters and \a filters. You can pass options via \a flags to decide | 
| 181 |     how the directory should be iterated. | 
| 182 |  | 
| 183 |     By default, \a flags is NoIteratorFlags, which provides the same behavior | 
| 184 |     as QDir::entryList(). | 
| 185 |  | 
| 186 |     For example, the following iterator could be used to iterate over audio | 
| 187 |     files: | 
| 188 |  | 
| 189 |     \snippet code/src_corelib_io_qdiriterator.cpp 2 | 
| 190 |  | 
| 191 |     \note To list symlinks that point to non existing files, QDir::System must be | 
| 192 |      passed to the flags. | 
| 193 |  | 
| 194 |     \sa hasNext(), next(), IteratorFlags, QDir::setNameFilters() | 
| 195 | */ | 
| 196 | QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters, | 
| 197 |                            QDir::Filters filters, IteratorFlags flags) | 
| 198 |     : d(new QDirIteratorPrivate(path, nameFilters, filters, flags)) | 
| 199 | { | 
| 200 | } | 
| 201 |  | 
| 202 | /*! | 
| 203 |     Destroys the QDirIterator. | 
| 204 | */ | 
| 205 | QDirIterator::~QDirIterator() | 
| 206 | { | 
| 207 | } | 
| 208 |  | 
| 209 | /*! | 
| 210 |     Advances the iterator to the next entry, and returns the file path of this | 
| 211 |     new entry. If hasNext() returns \c false, this function does nothing, and | 
| 212 |     returns an empty QString. | 
| 213 |  | 
| 214 |     You can call fileName() or filePath() to get the current entry's file name | 
| 215 |     or path, or fileInfo() to get a QFileInfo for the current entry. | 
| 216 |  | 
| 217 |     Call nextFileInfo() instead of next() if you're interested in the QFileInfo. | 
| 218 |  | 
| 219 |     \sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo() | 
| 220 | */ | 
| 221 | QString QDirIterator::next() | 
| 222 | { | 
| 223 |     d->advance(); | 
| 224 |     return d->currentFileInfo.filePath(); | 
| 225 | } | 
| 226 |  | 
| 227 | /*! | 
| 228 |     \since 6.3 | 
| 229 |  | 
| 230 |     Advances the iterator to the next entry, and returns the file info of this | 
| 231 |     new entry. If hasNext() returns \c false, this function does nothing, and | 
| 232 |     returns an empty QFileInfo. | 
| 233 |  | 
| 234 |     You can call fileName() or filePath() to get the current entry's file name | 
| 235 |     or path, or fileInfo() to get a QFileInfo for the current entry. | 
| 236 |  | 
| 237 |     Call next() instead of nextFileInfo() when all you need is the filePath(). | 
| 238 |  | 
| 239 |     \sa hasNext(), fileName(), filePath(), fileInfo() | 
| 240 | */ | 
| 241 | QFileInfo QDirIterator::nextFileInfo() | 
| 242 | { | 
| 243 |     d->advance(); | 
| 244 |     return d->currentFileInfo; | 
| 245 | } | 
| 246 |  | 
| 247 | /*! | 
| 248 |     Returns \c true if there is at least one more entry in the directory; | 
| 249 |     otherwise, false is returned. | 
| 250 |  | 
| 251 |     \sa next(), nextFileInfo(), fileName(), filePath(), fileInfo() | 
| 252 | */ | 
| 253 | bool QDirIterator::hasNext() const | 
| 254 | { | 
| 255 |     return d->it != d->lister.end(); | 
| 256 | } | 
| 257 |  | 
| 258 | /*! | 
| 259 |     Returns the file name for the current directory entry, without the path | 
| 260 |     prepended. | 
| 261 |  | 
| 262 |     This function is convenient when iterating a single directory. When using | 
| 263 |     the QDirIterator::Subdirectories flag, you can use filePath() to get the | 
| 264 |     full path. | 
| 265 |  | 
| 266 |     \sa filePath(), fileInfo() | 
| 267 | */ | 
| 268 | QString QDirIterator::fileName() const | 
| 269 | { | 
| 270 |     return d->currentFileInfo.fileName(); | 
| 271 | } | 
| 272 |  | 
| 273 | /*! | 
| 274 |     Returns the full file path for the current directory entry. | 
| 275 |  | 
| 276 |     \sa fileInfo(), fileName() | 
| 277 | */ | 
| 278 | QString QDirIterator::filePath() const | 
| 279 | { | 
| 280 |     return d->currentFileInfo.filePath(); | 
| 281 | } | 
| 282 |  | 
| 283 | /*! | 
| 284 |     Returns a QFileInfo for the current directory entry. | 
| 285 |  | 
| 286 |     \sa filePath(), fileName() | 
| 287 | */ | 
| 288 | QFileInfo QDirIterator::fileInfo() const | 
| 289 | { | 
| 290 |     return d->currentFileInfo; | 
| 291 | } | 
| 292 |  | 
| 293 | /*! | 
| 294 |     Returns the base directory of the iterator. | 
| 295 | */ | 
| 296 | QString QDirIterator::path() const | 
| 297 | { | 
| 298 |     return d->lister.iteratorPath(); | 
| 299 | } | 
| 300 |  | 
| 301 | QT_END_NAMESPACE | 
| 302 |  |