1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qplatformdefs.h"
43 #include "qdir.h"
44 #include "qdir_p.h"
45 #include "qabstractfileengine.h"
46 #ifndef QT_NO_DEBUG_STREAM
47 #include "qdebug.h"
48 #endif
49 #include "qdiriterator.h"
50 #include "qfsfileengine.h"
51 #include "qdatetime.h"
52 #include "qstring.h"
53 #include "qregexp.h"
54 #include "qvector.h"
55 #include "qalgorithms.h"
56 #include "qvarlengtharray.h"
57 #include "qfilesystementry_p.h"
58 #include "qfilesystemmetadata_p.h"
59 #include "qfilesystemengine_p.h"
60 #include <qstringbuilder.h>
61 
62 #ifdef QT_BUILD_CORE_LIB
63 #  include "qresource.h"
64 #  include "private/qcoreglobaldata_p.h"
65 #endif
66 
67 #include <stdlib.h>
68 
69 QT_BEGIN_NAMESPACE
70 
driveSpec(const QString & path)71 static QString driveSpec(const QString &path)
72 {
73 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
74     if (path.size() < 2)
75         return QString();
76     char c = path.at(0).toAscii();
77     if (c < 'a' && c > 'z' && c < 'A' && c > 'Z')
78         return QString();
79     if (path.at(1).toAscii() != ':')
80         return QString();
81     return path.mid(0, 2);
82 #else
83     Q_UNUSED(path);
84     return QString();
85 #endif
86 }
87 
88 //************* QDirPrivate
QDirPrivate(const QString & path,const QStringList & nameFilters_,QDir::SortFlags sort_,QDir::Filters filters_)89 QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_)
90     : QSharedData()
91     , nameFilters(nameFilters_)
92     , sort(sort_)
93     , filters(filters_)
94 #ifdef QT3_SUPPORT
95     , filterSepChar(0)
96     , matchAllDirs(false)
97 #endif
98     , fileListsInitialized(false)
99 {
100     setPath(path.isEmpty() ? QString::fromLatin1(".") : path);
101 
102     bool empty = nameFilters.isEmpty();
103     if (!empty) {
104         empty = true;
105         for (int i = 0; i < nameFilters.size(); ++i) {
106             if (!nameFilters.at(i).isEmpty()) {
107                 empty = false;
108                 break;
109             }
110         }
111     }
112     if (empty)
113         nameFilters = QStringList(QString::fromLatin1("*"));
114 }
115 
QDirPrivate(const QDirPrivate & copy)116 QDirPrivate::QDirPrivate(const QDirPrivate &copy)
117     : QSharedData(copy)
118     , nameFilters(copy.nameFilters)
119     , sort(copy.sort)
120     , filters(copy.filters)
121 #ifdef QT3_SUPPORT
122     , filterSepChar(copy.filterSepChar)
123     , matchAllDirs(copy.matchAllDirs)
124 #endif
125     , fileListsInitialized(false)
126     , dirEntry(copy.dirEntry)
127     , metaData(copy.metaData)
128 {
129 }
130 
exists() const131 bool QDirPrivate::exists() const
132 {
133     if (fileEngine.isNull()) {
134         QFileSystemEngine::fillMetaData(dirEntry, metaData,
135                 QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); // always stat
136         return metaData.exists() && metaData.isDirectory();
137     }
138     const QAbstractFileEngine::FileFlags info =
139         fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
140                                        | QAbstractFileEngine::ExistsFlag
141                                        | QAbstractFileEngine::Refresh);
142     if (!(info & QAbstractFileEngine::DirectoryType))
143         return false;
144     return info & QAbstractFileEngine::ExistsFlag;
145 }
146 
147 // static
getFilterSepChar(const QString & nameFilter)148 inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter)
149 {
150     QChar sep(QLatin1Char(';'));
151     int i = nameFilter.indexOf(sep, 0);
152     if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1)
153         sep = QChar(QLatin1Char(' '));
154     return sep;
155 }
156 
157 // static
splitFilters(const QString & nameFilter,QChar sep)158 inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar sep)
159 {
160     if (sep == 0)
161         sep = getFilterSepChar(nameFilter);
162     QStringList ret = nameFilter.split(sep);
163     for (int i = 0; i < ret.count(); ++i)
164         ret[i] = ret[i].trimmed();
165     return ret;
166 }
167 
setPath(const QString & path)168 inline void QDirPrivate::setPath(const QString &path)
169 {
170     QString p = QDir::fromNativeSeparators(path);
171     if (p.endsWith(QLatin1Char('/'))
172             && p.length() > 1
173 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
174         && (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter()))
175 #endif
176     ) {
177             p.truncate(p.length() - 1);
178     }
179 
180     dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
181     metaData.clear();
182     initFileEngine();
183     clearFileLists();
184     absoluteDirEntry = QFileSystemEntry();
185 }
186 
clearFileLists()187 inline void QDirPrivate::clearFileLists()
188 {
189     fileListsInitialized = false;
190     files.clear();
191     fileInfos.clear();
192 }
193 
resolveAbsoluteEntry() const194 inline void QDirPrivate::resolveAbsoluteEntry() const
195 {
196     if (!absoluteDirEntry.isEmpty() || dirEntry.isEmpty())
197         return;
198 
199     QString absoluteName;
200     if (fileEngine.isNull()) {
201         if (!dirEntry.isRelative() && dirEntry.isClean()) {
202             absoluteDirEntry = dirEntry;
203             return;
204         }
205 
206         absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
207     } else {
208         absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
209     }
210 
211     absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
212 }
213 
214 /* For sorting */
215 struct QDirSortItem
216 {
217     mutable QString filename_cache;
218     mutable QString suffix_cache;
219     QFileInfo item;
220 };
221 
222 
223 class QDirSortItemComparator
224 {
225     int qt_cmp_si_sort_flags;
226 public:
QDirSortItemComparator(int flags)227     QDirSortItemComparator(int flags) : qt_cmp_si_sort_flags(flags) {}
228     bool operator()(const QDirSortItem &, const QDirSortItem &);
229 };
230 
operator ()(const QDirSortItem & n1,const QDirSortItem & n2)231 bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2)
232 {
233     const QDirSortItem* f1 = &n1;
234     const QDirSortItem* f2 = &n2;
235 
236     if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
237         return f1->item.isDir();
238     if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
239         return !f1->item.isDir();
240 
241     int r = 0;
242     int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask)
243                  | (qt_cmp_si_sort_flags & QDir::Type);
244 
245     switch (sortBy) {
246       case QDir::Time:
247         r = f1->item.lastModified().secsTo(f2->item.lastModified());
248         break;
249       case QDir::Size:
250           r = int(qBound<qint64>(-1, f2->item.size() - f1->item.size(), 1));
251         break;
252       case QDir::Type:
253       {
254         bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase;
255 
256         if (f1->suffix_cache.isNull())
257             f1->suffix_cache = ic ? f1->item.suffix().toLower()
258                                : f1->item.suffix();
259         if (f2->suffix_cache.isNull())
260             f2->suffix_cache = ic ? f2->item.suffix().toLower()
261                                : f2->item.suffix();
262 
263         r = qt_cmp_si_sort_flags & QDir::LocaleAware
264             ? f1->suffix_cache.localeAwareCompare(f2->suffix_cache)
265             : f1->suffix_cache.compare(f2->suffix_cache);
266       }
267         break;
268       default:
269         ;
270     }
271 
272     if (r == 0 && sortBy != QDir::Unsorted) {
273         // Still not sorted - sort by name
274         bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase;
275 
276         if (f1->filename_cache.isNull())
277             f1->filename_cache = ic ? f1->item.fileName().toLower()
278                                     : f1->item.fileName();
279         if (f2->filename_cache.isNull())
280             f2->filename_cache = ic ? f2->item.fileName().toLower()
281                                     : f2->item.fileName();
282 
283         r = qt_cmp_si_sort_flags & QDir::LocaleAware
284             ? f1->filename_cache.localeAwareCompare(f2->filename_cache)
285             : f1->filename_cache.compare(f2->filename_cache);
286     }
287     if (r == 0) // Enforce an order - the order the items appear in the array
288         r = (&n1) - (&n2);
289     if (qt_cmp_si_sort_flags & QDir::Reversed)
290         return r > 0;
291     return r < 0;
292 }
293 
sortFileList(QDir::SortFlags sort,QFileInfoList & l,QStringList * names,QFileInfoList * infos)294 inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
295                                       QStringList *names, QFileInfoList *infos)
296 {
297     // names and infos are always empty lists or 0 here
298     int n = l.size();
299     if (n > 0) {
300         if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
301             if (infos)
302                 *infos = l;
303             if (names) {
304                 for (int i = 0; i < n; ++i)
305                     names->append(l.at(i).fileName());
306             }
307         } else {
308             QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
309             for (int i = 0; i < n; ++i)
310                 si[i].item = l.at(i);
311             qSort(si.data(), si.data() + n, QDirSortItemComparator(sort));
312             // put them back in the list(s)
313             if (infos) {
314                 for (int i = 0; i < n; ++i)
315                     infos->append(si[i].item);
316             }
317             if (names) {
318                 for (int i = 0; i < n; ++i)
319                     names->append(si[i].item.fileName());
320             }
321         }
322     }
323 }
initFileLists(const QDir & dir) const324 inline void QDirPrivate::initFileLists(const QDir &dir) const
325 {
326     if (!fileListsInitialized) {
327         QFileInfoList l;
328         QDirIterator it(dir);
329         while (it.hasNext()) {
330             it.next();
331             l.append(it.fileInfo());
332         }
333         sortFileList(sort, l, &files, &fileInfos);
334         fileListsInitialized = true;
335     }
336 }
337 
initFileEngine()338 inline void QDirPrivate::initFileEngine()
339 {
340     fileEngine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
341 }
342 
343 /*!
344     \class QDir
345     \brief The QDir class provides access to directory structures and their contents.
346 
347     \ingroup io
348     \ingroup shared
349     \reentrant
350 
351 
352     A QDir is used to manipulate path names, access information
353     regarding paths and files, and manipulate the underlying file
354     system. It can also be used to access Qt's \l{resource system}.
355 
356     Qt uses "/" as a universal directory separator in the same way
357     that "/" is used as a path separator in URLs. If you always use
358     "/" as a directory separator, Qt will translate your paths to
359     conform to the underlying operating system.
360 
361     A QDir can point to a file using either a relative or an absolute
362     path. Absolute paths begin with the directory separator
363     (optionally preceded by a drive specification under Windows).
364     Relative file names begin with a directory name or a file name and
365     specify a path relative to the current directory.
366 
367     Examples of absolute paths:
368 
369     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 0
370 
371     On Windows, the second example above will be translated to
372     \c{C:\Documents and Settings} when used to access files.
373 
374     Examples of relative paths:
375 
376     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 1
377 
378     You can use the isRelative() or isAbsolute() functions to check if
379     a QDir is using a relative or an absolute file path. Call
380     makeAbsolute() to convert a relative QDir to an absolute one.
381 
382     \section1 Navigation and Directory Operations
383 
384     A directory's path can be obtained with the path() function, and
385     a new path set with the setPath() function. The absolute path to
386     a directory is found by calling absolutePath().
387 
388     The name of a directory is found using the dirName() function. This
389     typically returns the last element in the absolute path that specifies
390     the location of the directory. However, it can also return "." if
391     the QDir represents the current directory.
392 
393     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 2
394 
395     The path for a directory can also be changed with the cd() and cdUp()
396     functions, both of which operate like familiar shell commands.
397     When cd() is called with the name of an existing directory, the QDir
398     object changes directory so that it represents that directory instead.
399     The cdUp() function changes the directory of the QDir object so that
400     it refers to its parent directory; i.e. cd("..") is equivalent to
401     cdUp().
402 
403     Directories can be created with mkdir(), renamed with rename(), and
404     removed with rmdir().
405 
406     You can test for the presence of a directory with a given name by
407     using exists(), and the properties of a directory can be tested with
408     isReadable(), isAbsolute(), isRelative(), and isRoot().
409 
410     The refresh() function re-reads the directory's data from disk.
411 
412     \section1 Files and Directory Contents
413 
414     Directories contain a number of entries, representing files,
415     directories, and symbolic links. The number of entries in a
416     directory is returned by count().
417     A string list of the names of all the entries in a directory can be
418     obtained with entryList(). If you need information about each
419     entry, use entryInfoList() to obtain a list of QFileInfo objects.
420 
421     Paths to files and directories within a directory can be
422     constructed using filePath() and absoluteFilePath().
423     The filePath() function returns a path to the specified file
424     or directory relative to the path of the QDir object;
425     absoluteFilePath() returns an absolute path to the specified
426     file or directory. Neither of these functions checks for the
427     existence of files or directory; they only construct paths.
428 
429     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 3
430 
431     Files can be removed by using the remove() function. Directories
432     cannot be removed in the same way as files; use rmdir() to remove
433     them instead.
434 
435     It is possible to reduce the number of entries returned by
436     entryList() and entryInfoList() by applying filters to a QDir object.
437     You can apply a name filter to specify a pattern with wildcards that
438     file names need to match, an attribute filter that selects properties
439     of entries and can distinguish between files and directories, and a
440     sort order.
441 
442     Name filters are lists of strings that are passed to setNameFilters().
443     Attribute filters consist of a bitwise OR combination of Filters, and
444     these are specified when calling setFilter().
445     The sort order is specified using setSorting() with a bitwise OR
446     combination of SortFlags.
447 
448     You can test to see if a filename matches a filter using the match()
449     function.
450 
451     Filter and sort order flags may also be specified when calling
452     entryList() and entryInfoList() in order to override previously defined
453     behavior.
454 
455     \section1 The Current Directory and Other Special Paths
456 
457     Access to some common directories is provided with a number of static
458     functions that return QDir objects. There are also corresponding functions
459     for these that return strings:
460 
461     \table
462     \header \o QDir      \o QString         \o Return Value
463     \row    \o current() \o currentPath()   \o The application's working directory
464     \row    \o home()    \o homePath()      \o The user's home directory
465     \row    \o root()    \o rootPath()      \o The root directory
466     \row    \o temp()    \o tempPath()      \o The system's temporary directory
467     \endtable
468 
469     The setCurrent() static function can also be used to set the application's
470     working directory.
471 
472     If you want to find the directory containing the application's executable,
473     see \l{QCoreApplication::applicationDirPath()}.
474 
475     The drives() static function provides a list of root directories for each
476     device that contains a filing system. On Unix systems this returns a list
477     containing a single root directory "/"; on Windows the list will usually
478     contain \c{C:/}, and possibly other drive letters such as \c{D:/}, depending
479     on the configuration of the user's system.
480 
481     \section1 Path Manipulation and Strings
482 
483     Paths containing "." elements that reference the current directory at that
484     point in the path, ".." elements that reference the parent directory, and
485     symbolic links can be reduced to a canonical form using the canonicalPath()
486     function.
487 
488     Paths can also be simplified by using cleanPath() to remove redundant "/"
489     and ".." elements.
490 
491     It is sometimes necessary to be able to show a path in the native
492     representation for the user's platform. The static toNativeSeparators()
493     function returns a copy of the specified path in which each directory
494     separator is replaced by the appropriate separator for the underlying
495     operating system.
496 
497     \section1 Examples
498 
499     Check if a directory exists:
500 
501     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 4
502 
503     (We could also use the static convenience function
504     QFile::exists().)
505 
506     Traversing directories and reading a file:
507 
508     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 5
509 
510     A program that lists all the files in the current directory
511     (excluding symbolic links), sorted by size, smallest first:
512 
513     \snippet doc/src/snippets/qdir-listfiles/main.cpp 0
514 
515     \sa QFileInfo, QFile, QFileDialog, QApplication::applicationDirPath(), {Find Files Example}
516 */
517 
518 /*!
519     Constructs a QDir pointing to the given directory \a path. If path
520     is empty the program's working directory, ("."), is used.
521 
522     \sa currentPath()
523 */
QDir(const QString & path)524 QDir::QDir(const QString &path) : d_ptr(new QDirPrivate(path))
525 {
526 }
527 
528 /*!
529     Constructs a QDir with path \a path, that filters its entries by
530     name using \a nameFilter and by attributes using \a filters. It
531     also sorts the names using \a sort.
532 
533     The default \a nameFilter is an empty string, which excludes
534     nothing; the default \a filters is \l AllEntries, which also means
535     exclude nothing. The default \a sort is \l Name | \l IgnoreCase,
536     i.e. sort by name case-insensitively.
537 
538     If \a path is an empty string, QDir uses "." (the current
539     directory). If \a nameFilter is an empty string, QDir uses the
540     name filter "*" (all files).
541 
542     Note that \a path need not exist.
543 
544     \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting()
545 */
QDir(const QString & path,const QString & nameFilter,SortFlags sort,Filters filters)546 QDir::QDir(const QString &path, const QString &nameFilter,
547            SortFlags sort, Filters filters)
548     : d_ptr(new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
549 {
550 }
551 
552 /*!
553     Constructs a QDir object that is a copy of the QDir object for
554     directory \a dir.
555 
556     \sa operator=()
557 */
QDir(const QDir & dir)558 QDir::QDir(const QDir &dir)
559     : d_ptr(dir.d_ptr)
560 {
561 }
562 
563 /*!
564     Destroys the QDir object frees up its resources. This has no
565     effect on the underlying directory in the file system.
566 */
~QDir()567 QDir::~QDir()
568 {
569 }
570 
571 /*!
572     Sets the path of the directory to \a path. The path is cleaned of
573     redundant ".", ".." and of multiple separators. No check is made
574     to see whether a directory with this path actually exists; but you
575     can check for yourself using exists().
576 
577     The path can be either absolute or relative. Absolute paths begin
578     with the directory separator "/" (optionally preceded by a drive
579     specification under Windows). Relative file names begin with a
580     directory name or a file name and specify a path relative to the
581     current directory. An example of an absolute path is the string
582     "/tmp/quartz", a relative path might look like "src/fatlib".
583 
584     \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
585       absoluteFilePath(), isRelative(), makeAbsolute()
586 */
setPath(const QString & path)587 void QDir::setPath(const QString &path)
588 {
589     d_ptr->setPath(path);
590 }
591 
592 /*!
593     Returns the path. This may contain symbolic links, but never
594     contains redundant ".", ".." or multiple separators.
595 
596     The returned path can be either absolute or relative (see
597     setPath()).
598 
599     \sa setPath(), absolutePath(), exists(), cleanPath(), dirName(),
600     absoluteFilePath(), toNativeSeparators(), makeAbsolute()
601 */
path() const602 QString QDir::path() const
603 {
604     const QDirPrivate* d = d_ptr.constData();
605     return d->dirEntry.filePath();
606 }
607 
608 /*!
609     Returns the absolute path (a path that starts with "/" or with a
610     drive specification), which may contain symbolic links, but never
611     contains redundant ".", ".." or multiple separators.
612 
613     \sa setPath(), canonicalPath(), exists(), cleanPath(),
614     dirName(), absoluteFilePath()
615 */
absolutePath() const616 QString QDir::absolutePath() const
617 {
618     const QDirPrivate* d = d_ptr.constData();
619     d->resolveAbsoluteEntry();
620     return d->absoluteDirEntry.filePath();
621 }
622 
623 /*!
624     Returns the canonical path, i.e. a path without symbolic links or
625     redundant "." or ".." elements.
626 
627     On systems that do not have symbolic links this function will
628     always return the same string that absolutePath() returns. If the
629     canonical path does not exist (normally due to dangling symbolic
630     links) canonicalPath() returns an empty string.
631 
632     Example:
633 
634     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 6
635 
636     \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
637         absoluteFilePath()
638 */
canonicalPath() const639 QString QDir::canonicalPath() const
640 {
641     const QDirPrivate* d = d_ptr.constData();
642     if (d->fileEngine.isNull()) {
643         QFileSystemEntry answer = QFileSystemEngine::canonicalName(d->dirEntry, d->metaData);
644         return answer.filePath();
645     }
646     return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
647 }
648 
649 /*!
650     Returns the name of the directory; this is \e not the same as the
651     path, e.g. a directory with the name "mail", might have the path
652     "/var/spool/mail". If the directory has no name (e.g. it is the
653     root directory) an empty string is returned.
654 
655     No check is made to ensure that a directory with this name
656     actually exists; but see exists().
657 
658     \sa path(), filePath(), absolutePath(), absoluteFilePath()
659 */
dirName() const660 QString QDir::dirName() const
661 {
662     const QDirPrivate* d = d_ptr.constData();
663     return d->dirEntry.fileName();
664 }
665 
666 /*!
667     Returns the path name of a file in the directory. Does \e not
668     check if the file actually exists in the directory; but see
669     exists(). If the QDir is relative the returned path name will also
670     be relative. Redundant multiple separators or "." and ".."
671     directories in \a fileName are not removed (see cleanPath()).
672 
673     \sa dirName() absoluteFilePath(), isRelative(), canonicalPath()
674 */
filePath(const QString & fileName) const675 QString QDir::filePath(const QString &fileName) const
676 {
677     const QDirPrivate* d = d_ptr.constData();
678     if (isAbsolutePath(fileName))
679         return QString(fileName);
680 
681     QString ret = d->dirEntry.filePath();
682     if (!fileName.isEmpty()) {
683         if (!ret.isEmpty() && ret[(int)ret.length()-1] != QLatin1Char('/') && fileName[0] != QLatin1Char('/'))
684             ret += QLatin1Char('/');
685         ret += fileName;
686     }
687     return ret;
688 }
689 
690 /*!
691     Returns the absolute path name of a file in the directory. Does \e
692     not check if the file actually exists in the directory; but see
693     exists(). Redundant multiple separators or "." and ".."
694     directories in \a fileName are not removed (see cleanPath()).
695 
696     \sa relativeFilePath() filePath() canonicalPath()
697 */
absoluteFilePath(const QString & fileName) const698 QString QDir::absoluteFilePath(const QString &fileName) const
699 {
700     const QDirPrivate* d = d_ptr.constData();
701     if (isAbsolutePath(fileName))
702         return fileName;
703 
704     d->resolveAbsoluteEntry();
705     if (fileName.isEmpty())
706         return d->absoluteDirEntry.filePath();
707     if (!d->absoluteDirEntry.isRoot())
708         return d->absoluteDirEntry.filePath() % QLatin1Char('/') % fileName;
709     return d->absoluteDirEntry.filePath() % fileName;
710 }
711 
712 /*!
713     Returns the path to \a fileName relative to the directory.
714 
715     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 7
716 
717     \sa absoluteFilePath() filePath() canonicalPath()
718 */
relativeFilePath(const QString & fileName) const719 QString QDir::relativeFilePath(const QString &fileName) const
720 {
721     QString dir = cleanPath(absolutePath());
722     QString file = cleanPath(fileName);
723 
724     if (isRelativePath(file) || isRelativePath(dir))
725         return file;
726 
727     QString dirDrive = driveSpec(dir);
728     QString fileDrive = driveSpec(file);
729 
730     bool fileDriveMissing = false;
731     if (fileDrive.isEmpty()) {
732         fileDrive = dirDrive;
733         fileDriveMissing = true;
734     }
735 
736 #ifdef Q_OS_WIN
737     if (fileDrive.toLower() != dirDrive.toLower()
738         || (file.startsWith(QLatin1String("//"))
739         && !dir.startsWith(QLatin1String("//"))))
740 #elif defined(Q_OS_SYMBIAN)
741     if (fileDrive.toLower() != dirDrive.toLower())
742 #else
743     if (fileDrive != dirDrive)
744 #endif
745         return file;
746 
747     dir.remove(0, dirDrive.size());
748     if (!fileDriveMissing)
749         file.remove(0, fileDrive.size());
750 
751     QString result;
752     QStringList dirElts = dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
753     QStringList fileElts = file.split(QLatin1Char('/'), QString::SkipEmptyParts);
754 
755     int i = 0;
756     while (i < dirElts.size() && i < fileElts.size() &&
757 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
758            dirElts.at(i).toLower() == fileElts.at(i).toLower())
759 #else
760            dirElts.at(i) == fileElts.at(i))
761 #endif
762         ++i;
763 
764     for (int j = 0; j < dirElts.size() - i; ++j)
765         result += QLatin1String("../");
766 
767     for (int j = i; j < fileElts.size(); ++j) {
768         result += fileElts.at(j);
769         if (j < fileElts.size() - 1)
770             result += QLatin1Char('/');
771     }
772 
773     return result;
774 }
775 
776 #ifndef QT_NO_DEPRECATED
777 /*!
778     \obsolete
779 
780     Use QDir::toNativeSeparators() instead.
781 */
convertSeparators(const QString & pathName)782 QString QDir::convertSeparators(const QString &pathName)
783 {
784     return toNativeSeparators(pathName);
785 }
786 #endif
787 
788 /*!
789     \since 4.2
790 
791     Returns \a pathName with the '/' separators converted to
792     separators that are appropriate for the underlying operating
793     system.
794 
795     On Windows, toNativeSeparators("c:/winnt/system32") returns
796     "c:\\winnt\\system32".
797 
798     The returned string may be the same as the argument on some
799     operating systems, for example on Unix.
800 
801     \sa fromNativeSeparators(), separator()
802 */
toNativeSeparators(const QString & pathName)803 QString QDir::toNativeSeparators(const QString &pathName)
804 {
805 #if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
806     int i = pathName.indexOf(QLatin1Char('/'));
807     if (i != -1) {
808         QString n(pathName);
809 
810         QChar * const data = n.data();
811         data[i++] = QLatin1Char('\\');
812 
813         for (; i < n.length(); ++i) {
814             if (data[i] == QLatin1Char('/'))
815                 data[i] = QLatin1Char('\\');
816         }
817 
818         return n;
819     }
820 #endif
821     return pathName;
822 }
823 
824 /*!
825     \since 4.2
826 
827     Returns \a pathName using '/' as file separator. On Windows,
828     for instance, fromNativeSeparators("\c{c:\\winnt\\system32}") returns
829     "c:/winnt/system32".
830 
831     The returned string may be the same as the argument on some
832     operating systems, for example on Unix.
833 
834     \sa toNativeSeparators(), separator()
835 */
fromNativeSeparators(const QString & pathName)836 QString QDir::fromNativeSeparators(const QString &pathName)
837 {
838 #if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
839     int i = pathName.indexOf(QLatin1Char('\\'));
840     if (i != -1) {
841         QString n(pathName);
842 
843         QChar * const data = n.data();
844         data[i++] = QLatin1Char('/');
845 
846         for (; i < n.length(); ++i) {
847             if (data[i] == QLatin1Char('\\'))
848                 data[i] = QLatin1Char('/');
849         }
850 
851         return n;
852     }
853 #endif
854     return pathName;
855 }
856 
857 /*!
858     Changes the QDir's directory to \a dirName.
859 
860     Returns true if the new directory exists and is readable;
861     otherwise returns false. Note that the logical cd() operation is
862     not performed if the new directory does not exist.
863 
864     Calling cd("..") is equivalent to calling cdUp().
865 
866     \sa cdUp(), isReadable(), exists(), path()
867 */
cd(const QString & dirName)868 bool QDir::cd(const QString &dirName)
869 {
870     // Don't detach just yet.
871     const QDirPrivate * const d = d_ptr.constData();
872 
873     if (dirName.isEmpty() || dirName == QLatin1String("."))
874         return true;
875     QString newPath;
876     if (isAbsolutePath(dirName)) {
877         newPath = cleanPath(dirName);
878     } else {
879         if (isRoot()) {
880             if (dirName == QLatin1String(".."))
881                 return false;
882             newPath = d->dirEntry.filePath();
883         } else {
884             newPath = d->dirEntry.filePath() % QLatin1Char('/');
885         }
886 
887         newPath += dirName;
888         if (dirName.indexOf(QLatin1Char('/')) >= 0
889             || dirName == QLatin1String("..")
890             || d->dirEntry.filePath() == QLatin1String(".")) {
891             newPath = cleanPath(newPath);
892             /*
893               If newPath starts with .., we convert it to absolute to
894               avoid infinite looping on
895 
896                   QDir dir(".");
897                   while (dir.cdUp())
898                       ;
899             */
900             if (newPath.startsWith(QLatin1String(".."))) {
901                 newPath = QFileInfo(newPath).absoluteFilePath();
902             }
903         }
904     }
905 
906     QScopedPointer<QDirPrivate> dir(new QDirPrivate(*d_ptr.constData()));
907     dir->setPath(newPath);
908     if (!dir->exists())
909         return false;
910 
911     d_ptr = dir.take();
912     return true;
913 }
914 
915 /*!
916     Changes directory by moving one directory up from the QDir's
917     current directory.
918 
919     Returns true if the new directory exists and is readable;
920     otherwise returns false. Note that the logical cdUp() operation is
921     not performed if the new directory does not exist.
922 
923     \sa cd(), isReadable(), exists(), path()
924 */
cdUp()925 bool QDir::cdUp()
926 {
927     return cd(QString::fromLatin1(".."));
928 }
929 
930 /*!
931     Returns the string list set by setNameFilters()
932 */
nameFilters() const933 QStringList QDir::nameFilters() const
934 {
935     const QDirPrivate* d = d_ptr.constData();
936     return d->nameFilters;
937 }
938 
939 /*!
940     Sets the name filters used by entryList() and entryInfoList() to the
941     list of filters specified by \a nameFilters.
942 
943     Each name filter is a wildcard (globbing) filter that understands
944     \c{*} and \c{?} wildcards. (See \l{QRegExp wildcard matching}.)
945 
946     For example, the following code sets three name filters on a QDir
947     to ensure that only files with extensions typically used for C++
948     source files are listed:
949 
950     \snippet doc/src/snippets/qdir-namefilters/main.cpp 0
951 
952     \sa nameFilters(), setFilter()
953 */
setNameFilters(const QStringList & nameFilters)954 void QDir::setNameFilters(const QStringList &nameFilters)
955 {
956     QDirPrivate* d = d_ptr.data();
957     d->initFileEngine();
958     d->clearFileLists();
959 
960     d->nameFilters = nameFilters;
961 }
962 
963 /*!
964     \obsolete
965 
966     Use QDir::addSearchPath() with a prefix instead.
967 
968     Adds \a path to the search paths searched in to find resources
969     that are not specified with an absolute path. The default search
970     path is to search only in the root (\c{:/}).
971 
972     \sa {The Qt Resource System}
973 */
addResourceSearchPath(const QString & path)974 void QDir::addResourceSearchPath(const QString &path)
975 {
976 #ifdef QT_BUILD_CORE_LIB
977     QResource::addSearchPath(path);
978 #else
979     Q_UNUSED(path)
980 #endif
981 }
982 
983 #ifdef QT_BUILD_CORE_LIB
984 /*!
985     \since 4.3
986 
987     Sets or replaces Qt's search paths for file names with the prefix \a prefix
988     to \a searchPaths.
989 
990     To specify a prefix for a file name, prepend the prefix followed by a single
991     colon (e.g., "images:undo.png", "xmldocs:books.xml"). \a prefix can only
992     contain letters or numbers (e.g., it cannot contain a colon, nor a slash).
993 
994     Qt uses this search path to locate files with a known prefix. The search
995     path entries are tested in order, starting with the first entry.
996 
997     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 8
998 
999     File name prefix must be at least 2 characters long to avoid conflicts with
1000     Windows drive letters.
1001 
1002     Search paths may contain paths to \l{The Qt Resource System}.
1003 */
setSearchPaths(const QString & prefix,const QStringList & searchPaths)1004 void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
1005 {
1006     if (prefix.length() < 2) {
1007         qWarning("QDir::setSearchPaths: Prefix must be longer than 1 character");
1008         return;
1009     }
1010 
1011     for (int i = 0; i < prefix.count(); ++i) {
1012         if (!prefix.at(i).isLetterOrNumber()) {
1013             qWarning("QDir::setSearchPaths: Prefix can only contain letters or numbers");
1014             return;
1015         }
1016     }
1017 
1018     QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
1019     QMap<QString, QStringList> &paths = QCoreGlobalData::instance()->dirSearchPaths;
1020     if (searchPaths.isEmpty()) {
1021         paths.remove(prefix);
1022     } else {
1023         paths.insert(prefix, searchPaths);
1024     }
1025 }
1026 
1027 /*!
1028     \since 4.3
1029 
1030     Adds \a path to the search path for \a prefix.
1031 
1032     \sa setSearchPaths()
1033 */
addSearchPath(const QString & prefix,const QString & path)1034 void QDir::addSearchPath(const QString &prefix, const QString &path)
1035 {
1036     if (path.isEmpty())
1037         return;
1038 
1039     QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
1040     QCoreGlobalData::instance()->dirSearchPaths[prefix] += path;
1041 }
1042 
1043 /*!
1044     \since 4.3
1045 
1046     Returns the search paths for \a prefix.
1047 
1048     \sa setSearchPaths(), addSearchPath()
1049 */
searchPaths(const QString & prefix)1050 QStringList QDir::searchPaths(const QString &prefix)
1051 {
1052     QReadLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
1053     return QCoreGlobalData::instance()->dirSearchPaths.value(prefix);
1054 }
1055 
1056 #endif // QT_BUILD_CORE_LIB
1057 
1058 /*!
1059     Returns the value set by setFilter()
1060 */
filter() const1061 QDir::Filters QDir::filter() const
1062 {
1063     const QDirPrivate* d = d_ptr.constData();
1064     return d->filters;
1065 }
1066 
1067 /*!
1068     \enum QDir::Filter
1069 
1070     This enum describes the filtering options available to QDir; e.g.
1071     for entryList() and entryInfoList(). The filter value is specified
1072     by combining values from the following list using the bitwise OR
1073     operator:
1074 
1075     \value Dirs    List directories that match the filters.
1076     \value AllDirs  List all directories; i.e. don't apply the filters
1077                     to directory names.
1078     \value Files   List files.
1079     \value Drives  List disk drives (ignored under Unix).
1080     \value NoSymLinks  Do not list symbolic links (ignored by operating
1081                        systems that don't support symbolic links).
1082     \value NoDotAndDotDot Do not list the special entries "." and "..".
1083     \value NoDot       Do not list the special entry ".".
1084     \value NoDotDot    Do not list the special entry "..".
1085     \value AllEntries  List directories, files, drives and symlinks (this does not list
1086                 broken symlinks unless you specify System).
1087     \value Readable    List files for which the application has read
1088                        access. The Readable value needs to be combined
1089                        with Dirs or Files.
1090     \value Writable    List files for which the application has write
1091                        access. The Writable value needs to be combined
1092                        with Dirs or Files.
1093     \value Executable  List files for which the application has
1094                        execute access. The Executable value needs to be
1095                        combined with Dirs or Files.
1096     \value Modified  Only list files that have been modified (ignored
1097                      on Unix).
1098     \value Hidden  List hidden files (on Unix, files starting with a ".").
1099     \value System  List system files (on Unix, FIFOs, sockets and
1100                    device files are included; on Windows, \c {.lnk}
1101                    files are included)
1102     \value CaseSensitive  The filter should be case sensitive.
1103 
1104     \omitvalue DefaultFilter
1105     \omitvalue TypeMask
1106     \omitvalue All
1107     \omitvalue RWEMask
1108     \omitvalue AccessMask
1109     \omitvalue PermissionMask
1110     \omitvalue NoFilter
1111 
1112     Functions that use Filter enum values to filter lists of files
1113     and directories will include symbolic links to files and directories
1114     unless you set the NoSymLinks value.
1115 
1116     A default constructed QDir will not filter out files based on
1117     their permissions, so entryList() and entryInfoList() will return
1118     all files that are readable, writable, executable, or any
1119     combination of the three.  This makes the default easy to write,
1120     and at the same time useful.
1121 
1122     For example, setting the \c Readable, \c Writable, and \c Files
1123     flags allows all files to be listed for which the application has read
1124     access, write access or both. If the \c Dirs and \c Drives flags are
1125     also included in this combination then all drives, directories, all
1126     files that the application can read, write, or execute, and symlinks
1127     to such files/directories can be listed.
1128 
1129     To retrieve the permissons for a directory, use the
1130     entryInfoList() function to get the associated QFileInfo objects
1131     and then use the QFileInfo::permissons() to obtain the permissions
1132     and ownership for each file.
1133 */
1134 
1135 /*!
1136     Sets the filter used by entryList() and entryInfoList() to \a
1137     filters. The filter is used to specify the kind of files that
1138     should be returned by entryList() and entryInfoList(). See
1139     \l{QDir::Filter}.
1140 
1141     \sa filter(), setNameFilters()
1142 */
setFilter(Filters filters)1143 void QDir::setFilter(Filters filters)
1144 {
1145     QDirPrivate* d = d_ptr.data();
1146     d->initFileEngine();
1147     d->clearFileLists();
1148 
1149     d->filters = filters;
1150 }
1151 
1152 /*!
1153     Returns the value set by setSorting()
1154 
1155     \sa setSorting() SortFlag
1156 */
sorting() const1157 QDir::SortFlags QDir::sorting() const
1158 {
1159     const QDirPrivate* d = d_ptr.constData();
1160     return d->sort;
1161 }
1162 
1163 /*!
1164     \enum QDir::SortFlag
1165 
1166     This enum describes the sort options available to QDir, e.g. for
1167     entryList() and entryInfoList(). The sort value is specified by
1168     OR-ing together values from the following list:
1169 
1170     \value Name  Sort by name.
1171     \value Time  Sort by time (modification time).
1172     \value Size  Sort by file size.
1173     \value Type  Sort by file type (extension).
1174     \value Unsorted  Do not sort.
1175     \value NoSort Not sorted by default.
1176 
1177     \value DirsFirst  Put the directories first, then the files.
1178     \value DirsLast Put the files first, then the directories.
1179     \value Reversed  Reverse the sort order.
1180     \value IgnoreCase  Sort case-insensitively.
1181     \value LocaleAware Sort items appropriately using the current locale settings.
1182 
1183     \omitvalue SortByMask
1184     \omitvalue DefaultSort
1185 
1186     You can only specify one of the first four.
1187 
1188     If you specify both DirsFirst and Reversed, directories are
1189     still put first, but in reverse order; the files will be listed
1190     after the directories, again in reverse order.
1191 */
1192 
1193 /*!
1194     Sets the sort order used by entryList() and entryInfoList().
1195 
1196     The \a sort is specified by OR-ing values from the enum
1197     \l{QDir::SortFlag}.
1198 
1199     \sa sorting() SortFlag
1200 */
setSorting(SortFlags sort)1201 void QDir::setSorting(SortFlags sort)
1202 {
1203     QDirPrivate* d = d_ptr.data();
1204     d->initFileEngine();
1205     d->clearFileLists();
1206 
1207     d->sort = sort;
1208 }
1209 
1210 /*!
1211     Returns the total number of directories and files in the directory.
1212 
1213     Equivalent to entryList().count().
1214 
1215     \sa operator[](), entryList()
1216 */
count() const1217 uint QDir::count() const
1218 {
1219     const QDirPrivate* d = d_ptr.constData();
1220     d->initFileLists(*this);
1221     return d->files.count();
1222 }
1223 
1224 /*!
1225     Returns the file name at position \a pos in the list of file
1226     names. Equivalent to entryList().at(index).
1227     \a pos must be a valid index position in the list (i.e., 0 <= pos < count()).
1228 
1229     \sa count(), entryList()
1230 */
operator [](int pos) const1231 QString QDir::operator[](int pos) const
1232 {
1233     const QDirPrivate* d = d_ptr.constData();
1234     d->initFileLists(*this);
1235     return d->files[pos];
1236 }
1237 
1238 /*!
1239     \overload
1240 
1241     Returns a list of the names of all the files and directories in
1242     the directory, ordered according to the name and attribute filters
1243     previously set with setNameFilters() and setFilter(), and sorted according
1244     to the flags set with setSorting().
1245 
1246     The attribute filter and sorting specifications can be overridden using the
1247     \a filters and \a sort arguments.
1248 
1249     Returns an empty list if the directory is unreadable, does not
1250     exist, or if nothing matches the specification.
1251 
1252     \note To list symlinks that point to non existing files, \l System must be
1253      passed to the filter.
1254 
1255     \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
1256 */
entryList(Filters filters,SortFlags sort) const1257 QStringList QDir::entryList(Filters filters, SortFlags sort) const
1258 {
1259     const QDirPrivate* d = d_ptr.constData();
1260     return entryList(d->nameFilters, filters, sort);
1261 }
1262 
1263 
1264 /*!
1265     \overload
1266 
1267     Returns a list of QFileInfo objects for all the files and directories in
1268     the directory, ordered according to the name and attribute filters
1269     previously set with setNameFilters() and setFilter(), and sorted according
1270     to the flags set with setSorting().
1271 
1272     The attribute filter and sorting specifications can be overridden using the
1273     \a filters and \a sort arguments.
1274 
1275     Returns an empty list if the directory is unreadable, does not
1276     exist, or if nothing matches the specification.
1277 
1278     \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
1279 */
entryInfoList(Filters filters,SortFlags sort) const1280 QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
1281 {
1282     const QDirPrivate* d = d_ptr.constData();
1283     return entryInfoList(d->nameFilters, filters, sort);
1284 }
1285 
1286 /*!
1287     Returns a list of the names of all the files and
1288     directories in the directory, ordered according to the name
1289     and attribute filters previously set with setNameFilters()
1290     and setFilter(), and sorted according to the flags set with
1291     setSorting().
1292 
1293     The name filter, file attribute filter, and sorting specification
1294     can be overridden using the \a nameFilters, \a filters, and \a sort
1295     arguments.
1296 
1297     Returns an empty list if the directory is unreadable, does not
1298     exist, or if nothing matches the specification.
1299 
1300     \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
1301 */
entryList(const QStringList & nameFilters,Filters filters,SortFlags sort) const1302 QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
1303                             SortFlags sort) const
1304 {
1305     const QDirPrivate* d = d_ptr.constData();
1306 
1307     if (filters == NoFilter)
1308         filters = d->filters;
1309 #ifdef QT3_SUPPORT
1310     if (d->matchAllDirs)
1311         filters |= AllDirs;
1312 #endif
1313     if (sort == NoSort)
1314         sort = d->sort;
1315 
1316     if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1317         d->initFileLists(*this);
1318         return d->files;
1319     }
1320 
1321     QFileInfoList l;
1322     QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
1323     while (it.hasNext()) {
1324         it.next();
1325         l.append(it.fileInfo());
1326     }
1327     QStringList ret;
1328     d->sortFileList(sort, l, &ret, 0);
1329     return ret;
1330 }
1331 
1332 /*!
1333     Returns a list of QFileInfo objects for all the files and
1334     directories in the directory, ordered according to the name
1335     and attribute filters previously set with setNameFilters()
1336     and setFilter(), and sorted according to the flags set with
1337     setSorting().
1338 
1339     The name filter, file attribute filter, and sorting specification
1340     can be overridden using the \a nameFilters, \a filters, and \a sort
1341     arguments.
1342 
1343     Returns an empty list if the directory is unreadable, does not
1344     exist, or if nothing matches the specification.
1345 
1346     \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
1347 */
entryInfoList(const QStringList & nameFilters,Filters filters,SortFlags sort) const1348 QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filters,
1349                                   SortFlags sort) const
1350 {
1351     const QDirPrivate* d = d_ptr.constData();
1352 
1353     if (filters == NoFilter)
1354         filters = d->filters;
1355 #ifdef QT3_SUPPORT
1356     if (d->matchAllDirs)
1357         filters |= AllDirs;
1358 #endif
1359     if (sort == NoSort)
1360         sort = d->sort;
1361 
1362     if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
1363         d->initFileLists(*this);
1364         return d->fileInfos;
1365     }
1366 
1367     QFileInfoList l;
1368     QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
1369     while (it.hasNext()) {
1370         it.next();
1371         l.append(it.fileInfo());
1372     }
1373     QFileInfoList ret;
1374     d->sortFileList(sort, l, 0, &ret);
1375     return ret;
1376 }
1377 
1378 /*!
1379     Creates a sub-directory called \a dirName.
1380 
1381     Returns true on success; otherwise returns false.
1382 
1383     If the directory already exists when this function is called, it will return false.
1384 
1385     \sa rmdir()
1386 */
1387 // ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath
mkdir(const QString & dirName) const1388 bool QDir::mkdir(const QString &dirName) const
1389 {
1390     const QDirPrivate* d = d_ptr.constData();
1391 
1392     if (dirName.isEmpty()) {
1393         qWarning("QDir::mkdir: Empty or null file name(s)");
1394         return false;
1395     }
1396 
1397     QString fn = filePath(dirName);
1398     if (d->fileEngine.isNull())
1399         return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), false);
1400     return d->fileEngine->mkdir(fn, false);
1401 }
1402 
1403 /*!
1404     Removes the directory specified by \a dirName.
1405 
1406     The directory must be empty for rmdir() to succeed.
1407 
1408     Returns true if successful; otherwise returns false.
1409 
1410     \sa mkdir()
1411 */
rmdir(const QString & dirName) const1412 bool QDir::rmdir(const QString &dirName) const
1413 {
1414     const QDirPrivate* d = d_ptr.constData();
1415 
1416     if (dirName.isEmpty()) {
1417         qWarning("QDir::rmdir: Empty or null file name(s)");
1418         return false;
1419     }
1420 
1421     QString fn = filePath(dirName);
1422     if (d->fileEngine.isNull())
1423         return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), false);
1424 
1425     return d->fileEngine->rmdir(fn, false);
1426 }
1427 
1428 /*!
1429     Creates the directory path \a dirPath.
1430 
1431     The function will create all parent directories necessary to
1432     create the directory.
1433 
1434     Returns true if successful; otherwise returns false.
1435 
1436     If the path already exists when this function is called, it will return true.
1437 
1438     \sa rmpath()
1439 */
1440 // ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath
mkpath(const QString & dirPath) const1441 bool QDir::mkpath(const QString &dirPath) const
1442 {
1443     const QDirPrivate* d = d_ptr.constData();
1444 
1445     if (dirPath.isEmpty()) {
1446         qWarning("QDir::mkpath: Empty or null file name(s)");
1447         return false;
1448     }
1449 
1450     QString fn = filePath(dirPath);
1451     if (d->fileEngine.isNull())
1452         return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), true);
1453     return d->fileEngine->mkdir(fn, true);
1454 }
1455 
1456 /*!
1457     Removes the directory path \a dirPath.
1458 
1459     The function will remove all parent directories in \a dirPath,
1460     provided that they are empty. This is the opposite of
1461     mkpath(dirPath).
1462 
1463     Returns true if successful; otherwise returns false.
1464 
1465     \sa mkpath()
1466 */
rmpath(const QString & dirPath) const1467 bool QDir::rmpath(const QString &dirPath) const
1468 {
1469     const QDirPrivate* d = d_ptr.constData();
1470 
1471     if (dirPath.isEmpty()) {
1472         qWarning("QDir::rmpath: Empty or null file name(s)");
1473         return false;
1474     }
1475 
1476     QString fn = filePath(dirPath);
1477     if (d->fileEngine.isNull())
1478         return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), true);
1479     return d->fileEngine->rmdir(fn, true);
1480 }
1481 
1482 /*!
1483     Returns true if the directory is readable \e and we can open files
1484     by name; otherwise returns false.
1485 
1486     \warning A false value from this function is not a guarantee that
1487     files in the directory are not accessible.
1488 
1489     \sa QFileInfo::isReadable()
1490 */
isReadable() const1491 bool QDir::isReadable() const
1492 {
1493     const QDirPrivate* d = d_ptr.constData();
1494 
1495     if (d->fileEngine.isNull()) {
1496         if (!d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
1497             QFileSystemEngine::fillMetaData(d->dirEntry, d->metaData, QFileSystemMetaData::UserReadPermission);
1498 
1499         return (d->metaData.permissions() & QFile::ReadUser) != 0;
1500     }
1501 
1502     const QAbstractFileEngine::FileFlags info =
1503         d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
1504                                        | QAbstractFileEngine::PermsMask);
1505     if (!(info & QAbstractFileEngine::DirectoryType))
1506         return false;
1507     return info & QAbstractFileEngine::ReadUserPerm;
1508 }
1509 
1510 /*!
1511     \overload
1512 
1513     Returns true if the directory exists; otherwise returns false.
1514     (If a file with the same name is found this function will return false).
1515 
1516     The overload of this function that accepts an argument is used to test
1517     for the presence of files and directories within a directory.
1518 
1519     \sa QFileInfo::exists(), QFile::exists()
1520 */
exists() const1521 bool QDir::exists() const
1522 {
1523     return d_ptr->exists();
1524 }
1525 
1526 /*!
1527     Returns true if the directory is the root directory; otherwise
1528     returns false.
1529 
1530     Note: If the directory is a symbolic link to the root directory
1531     this function returns false. If you want to test for this use
1532     canonicalPath(), e.g.
1533 
1534     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 9
1535 
1536     \sa root(), rootPath()
1537 */
isRoot() const1538 bool QDir::isRoot() const
1539 {
1540     if (d_ptr->fileEngine.isNull())
1541         return d_ptr->dirEntry.isRoot();
1542     return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::RootFlag;
1543 }
1544 
1545 /*!
1546     \fn bool QDir::isAbsolute() const
1547 
1548     Returns true if the directory's path is absolute; otherwise
1549     returns false. See isAbsolutePath().
1550 
1551     \sa isRelative() makeAbsolute() cleanPath()
1552 */
1553 
1554 /*!
1555    \fn bool QDir::isAbsolutePath(const QString &)
1556 
1557     Returns true if \a path is absolute; returns false if it is
1558     relative.
1559 
1560     \sa isAbsolute() isRelativePath() makeAbsolute() cleanPath()
1561 */
1562 
1563 /*!
1564     Returns true if the directory path is relative; otherwise returns
1565     false. (Under Unix a path is relative if it does not start with a
1566     "/").
1567 
1568     \sa makeAbsolute() isAbsolute() isAbsolutePath() cleanPath()
1569 */
isRelative() const1570 bool QDir::isRelative() const
1571 {
1572     if (d_ptr->fileEngine.isNull())
1573         return d_ptr->dirEntry.isRelative();
1574     return d_ptr->fileEngine->isRelativePath();
1575 }
1576 
1577 
1578 /*!
1579     Converts the directory path to an absolute path. If it is already
1580     absolute nothing happens. Returns true if the conversion
1581     succeeded; otherwise returns false.
1582 
1583     \sa isAbsolute() isAbsolutePath() isRelative() cleanPath()
1584 */
makeAbsolute()1585 bool QDir::makeAbsolute()
1586 {
1587     const QDirPrivate *d = d_ptr.constData();
1588     QScopedPointer<QDirPrivate> dir;
1589     if (!d->fileEngine.isNull()) {
1590         QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
1591         if (QDir::isRelativePath(absolutePath))
1592             return false;
1593 
1594         dir.reset(new QDirPrivate(*d_ptr.constData()));
1595         dir->setPath(absolutePath);
1596     } else { // native FS
1597         d->resolveAbsoluteEntry();
1598         dir.reset(new QDirPrivate(*d_ptr.constData()));
1599         dir->setPath(d->absoluteDirEntry.filePath());
1600     }
1601     d_ptr = dir.take(); // actually detach
1602     return true;
1603 }
1604 
1605 /*!
1606     Returns true if directory \a dir and this directory have the same
1607     path and their sort and filter settings are the same; otherwise
1608     returns false.
1609 
1610     Example:
1611 
1612     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 10
1613 */
operator ==(const QDir & dir) const1614 bool QDir::operator==(const QDir &dir) const
1615 {
1616     const QDirPrivate *d = d_ptr.constData();
1617     const QDirPrivate *other = dir.d_ptr.constData();
1618 
1619     if (d == other)
1620         return true;
1621     Qt::CaseSensitivity sensitive;
1622     if (d->fileEngine.isNull() || other->fileEngine.isNull()) {
1623         if (d->fileEngine.data() != other->fileEngine.data()) // one is native, the other is a custom file-engine
1624             return false;
1625 
1626         sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1627     } else {
1628         if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
1629             return false;
1630         sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
1631     }
1632 
1633     if (d->filters == other->filters
1634        && d->sort == other->sort
1635        && d->nameFilters == other->nameFilters) {
1636 
1637         // Assume directories are the same if path is the same
1638         if (d->dirEntry.filePath() == other->dirEntry.filePath())
1639             return true;
1640 
1641         if (exists()) {
1642             if (!dir.exists())
1643                 return false; //can't be equal if only one exists
1644             // Both exist, fallback to expensive canonical path computation
1645             return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0;
1646         } else {
1647             if (dir.exists())
1648                 return false; //can't be equal if only one exists
1649             // Neither exists, compare absolute paths rather than canonical (which would be empty strings)
1650             d->resolveAbsoluteEntry();
1651             other->resolveAbsoluteEntry();
1652             return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0;
1653         }
1654     }
1655     return false;
1656 }
1657 
1658 /*!
1659     Makes a copy of the \a dir object and assigns it to this QDir
1660     object.
1661 */
operator =(const QDir & dir)1662 QDir &QDir::operator=(const QDir &dir)
1663 {
1664     d_ptr = dir.d_ptr;
1665     return *this;
1666 }
1667 
1668 /*!
1669     \overload
1670     \obsolete
1671 
1672     Sets the directory path to the given \a path.
1673 
1674     Use setPath() instead.
1675 */
operator =(const QString & path)1676 QDir &QDir::operator=(const QString &path)
1677 {
1678     d_ptr->setPath(path);
1679     return *this;
1680 }
1681 
1682 /*!
1683     \fn bool QDir::operator!=(const QDir &dir) const
1684 
1685     Returns true if directory \a dir and this directory have different
1686     paths or different sort or filter settings; otherwise returns
1687     false.
1688 
1689     Example:
1690 
1691     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 11
1692 */
1693 
1694 /*!
1695     Removes the file, \a fileName.
1696 
1697     Returns true if the file is removed successfully; otherwise
1698     returns false.
1699 */
remove(const QString & fileName)1700 bool QDir::remove(const QString &fileName)
1701 {
1702     if (fileName.isEmpty()) {
1703         qWarning("QDir::remove: Empty or null file name");
1704         return false;
1705     }
1706     return QFile::remove(filePath(fileName));
1707 }
1708 
1709 /*!
1710     Renames a file or directory from \a oldName to \a newName, and returns
1711     true if successful; otherwise returns false.
1712 
1713     On most file systems, rename() fails only if \a oldName does not
1714     exist, if \a newName and \a oldName are not on the same
1715     partition or if a file with the new name already exists.
1716     However, there are also other reasons why rename() can
1717     fail. For example, on at least one file system rename() fails if
1718     \a newName points to an open file.
1719 */
rename(const QString & oldName,const QString & newName)1720 bool QDir::rename(const QString &oldName, const QString &newName)
1721 {
1722     if (oldName.isEmpty() || newName.isEmpty()) {
1723         qWarning("QDir::rename: Empty or null file name(s)");
1724         return false;
1725     }
1726 
1727     QFile file(filePath(oldName));
1728     if (!file.exists())
1729         return false;
1730     return file.rename(filePath(newName));
1731 }
1732 
1733 /*!
1734     Returns true if the file called \a name exists; otherwise returns
1735     false.
1736 
1737     Unless \a name contains an absolute file path, the file name is assumed
1738     to be relative to the directory itself, so this function is typically used
1739     to check for the presence of files within a directory.
1740 
1741     \sa QFileInfo::exists(), QFile::exists()
1742 */
exists(const QString & name) const1743 bool QDir::exists(const QString &name) const
1744 {
1745     if (name.isEmpty()) {
1746         qWarning("QDir::exists: Empty or null file name");
1747         return false;
1748     }
1749     return QFile::exists(filePath(name));
1750 }
1751 
1752 /*!
1753     Returns a list of the root directories on this system.
1754 
1755     On Windows this returns a list of QFileInfo objects containing "C:/",
1756     "D:/", etc. On other operating systems, it returns a list containing
1757     just one root directory (i.e. "/").
1758 
1759     \sa root(), rootPath()
1760 */
drives()1761 QFileInfoList QDir::drives()
1762 {
1763 #ifdef QT_NO_FSFILEENGINE
1764     return QFileInfoList();
1765 #else
1766     return QFSFileEngine::drives();
1767 #endif
1768 }
1769 
1770 /*!
1771     Returns the native directory separator: "/" under Unix (including
1772     Mac OS X) and "\\" under Windows.
1773 
1774     You do not need to use this function to build file paths. If you
1775     always use "/", Qt will translate your paths to conform to the
1776     underlying operating system. If you want to display paths to the
1777     user using their operating system's separator use
1778     toNativeSeparators().
1779 */
separator()1780 QChar QDir::separator()
1781 {
1782 #if defined (Q_FS_FAT) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN)
1783     return QLatin1Char('\\');
1784 #elif defined(Q_OS_UNIX)
1785     return QLatin1Char('/');
1786 #elif defined (Q_OS_MAC)
1787     return QLatin1Char(':');
1788 #else
1789     return QLatin1Char('/');
1790 #endif
1791 }
1792 
1793 /*!
1794     Sets the application's current working directory to \a path.
1795     Returns true if the directory was successfully changed; otherwise
1796     returns false.
1797 
1798     \sa current(), currentPath(), home(), root(), temp()
1799 */
setCurrent(const QString & path)1800 bool QDir::setCurrent(const QString &path)
1801 {
1802     return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
1803 }
1804 
1805 /*!
1806     \fn QDir QDir::current()
1807 
1808     Returns the application's current directory.
1809 
1810     The directory is constructed using the absolute path of the current directory,
1811     ensuring that its path() will be the same as its absolutePath().
1812 
1813     \sa currentPath(), setCurrent(), home(), root(), temp()
1814 */
1815 
1816 /*!
1817     Returns the absolute path of the application's current directory.
1818 
1819     \sa current(), setCurrent(), homePath(), rootPath(), tempPath()
1820 */
currentPath()1821 QString QDir::currentPath()
1822 {
1823     return QFileSystemEngine::currentPath().filePath();
1824 }
1825 
1826 /*!
1827   \fn QString QDir::currentDirPath()
1828     Returns the absolute path of the application's current directory.
1829 
1830     Use currentPath() instead.
1831 
1832     \sa currentPath(), setCurrent()
1833 */
1834 
1835 /*!
1836     \fn QDir QDir::home()
1837 
1838     Returns the user's home directory.
1839 
1840     The directory is constructed using the absolute path of the home directory,
1841     ensuring that its path() will be the same as its absolutePath().
1842 
1843     See homePath() for details.
1844 
1845     \sa drives(), current(), root(), temp()
1846 */
1847 
1848 /*!
1849     Returns the absolute path of the user's home directory.
1850 
1851     Under Windows this function will return the directory of the
1852     current user's profile. Typically, this is:
1853 
1854     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 12
1855 
1856     Use the toNativeSeparators() function to convert the separators to
1857     the ones that are appropriate for the underlying operating system.
1858 
1859     If the directory of the current user's profile does not exist or
1860     cannot be retrieved, the following alternatives will be checked (in
1861     the given order) until an existing and available path is found:
1862 
1863     \list 1
1864     \o The path specified by the \c USERPROFILE environment variable.
1865     \o The path formed by concatenating the \c HOMEDRIVE and \c HOMEPATH
1866     environment variables.
1867     \o The path specified by the \c HOME environment variable.
1868     \o The path returned by the rootPath() function (which uses the \c SystemDrive
1869     environment variable)
1870     \o  The \c{C:/} directory.
1871     \endlist
1872 
1873     Under non-Windows operating systems the \c HOME environment
1874     variable is used if it exists, otherwise the path returned by the
1875     rootPath().
1876 
1877     On Symbian this typically returns "c:/data",
1878     i.e. the same as native PathInfo::PhoneMemoryRootPath().
1879 
1880     \sa home(), currentPath(), rootPath(), tempPath()
1881 */
homePath()1882 QString QDir::homePath()
1883 {
1884     return QFileSystemEngine::homePath();
1885 }
1886 
1887 /*!
1888     \fn QString QDir::homeDirPath()
1889 
1890     Returns the absolute path of the user's home directory.
1891 
1892     Use homePath() instead.
1893 
1894     \sa homePath()
1895 */
1896 
1897 /*!
1898     \fn QDir QDir::temp()
1899 
1900     Returns the system's temporary directory.
1901 
1902     The directory is constructed using the absolute path of the temporary directory,
1903     ensuring that its path() will be the same as its absolutePath().
1904 
1905     See tempPath() for details.
1906 
1907     \sa drives(), current(), home(), root()
1908 */
1909 
1910 /*!
1911     Returns the absolute path of the system's temporary directory.
1912 
1913     On Unix/Linux systems this is the path in the \c TMPDIR environment
1914     variable or \c{/tmp} if \c TMPDIR is not defined. On Windows this is
1915     usually the path in the \c TEMP or \c TMP environment
1916     variable. Whether a directory separator is added to the end or
1917     not, depends on the operating system.
1918 
1919     \sa temp(), currentPath(), homePath(), rootPath()
1920 */
tempPath()1921 QString QDir::tempPath()
1922 {
1923     return QFileSystemEngine::tempPath();
1924 }
1925 
1926 /*!
1927     \fn QDir QDir::root()
1928 
1929     Returns the root directory.
1930 
1931     The directory is constructed using the absolute path of the root directory,
1932     ensuring that its path() will be the same as its absolutePath().
1933 
1934     See rootPath() for details.
1935 
1936     \sa drives(), current(), home(), temp()
1937 */
1938 
1939 /*!
1940     Returns the absolute path of the root directory.
1941 
1942     For Unix operating systems this returns "/". For Windows and Symbian file
1943     systems this normally returns "c:/". I.E. the root of the system drive.
1944 
1945     \sa root(), drives(), currentPath(), homePath(), tempPath()
1946 */
rootPath()1947 QString QDir::rootPath()
1948 {
1949     return QFileSystemEngine::rootPath();
1950 }
1951 
1952 /*!
1953     \fn QString QDir::rootDirPath()
1954 
1955     Returns the absolute path of the root directory.
1956 
1957     Use rootPath() instead.
1958 
1959     \sa rootPath()
1960 */
1961 
1962 #ifndef QT_NO_REGEXP
1963 /*!
1964     \overload
1965 
1966     Returns true if the \a fileName matches any of the wildcard (glob)
1967     patterns in the list of \a filters; otherwise returns false. The
1968     matching is case insensitive.
1969 
1970     \sa {QRegExp wildcard matching}, QRegExp::exactMatch() entryList() entryInfoList()
1971 */
match(const QStringList & filters,const QString & fileName)1972 bool QDir::match(const QStringList &filters, const QString &fileName)
1973 {
1974     for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
1975         QRegExp rx(*sit, Qt::CaseInsensitive, QRegExp::Wildcard);
1976         if (rx.exactMatch(fileName))
1977             return true;
1978     }
1979     return false;
1980 }
1981 
1982 /*!
1983     Returns true if the \a fileName matches the wildcard (glob)
1984     pattern \a filter; otherwise returns false. The \a filter may
1985     contain multiple patterns separated by spaces or semicolons.
1986     The matching is case insensitive.
1987 
1988     \sa {QRegExp wildcard matching}, QRegExp::exactMatch() entryList() entryInfoList()
1989 */
match(const QString & filter,const QString & fileName)1990 bool QDir::match(const QString &filter, const QString &fileName)
1991 {
1992     return match(nameFiltersFromString(filter), fileName);
1993 }
1994 #endif // QT_NO_REGEXP
1995 
1996 /*!
1997     Removes all multiple directory separators "/" and resolves any
1998     "."s or ".."s found in the path, \a path.
1999 
2000     Symbolic links are kept. This function does not return the
2001     canonical path, but rather the simplest version of the input.
2002     For example, "./local" becomes "local", "local/../bin" becomes
2003     "bin" and "/local/usr/../bin" becomes "/local/bin".
2004 
2005     \sa absolutePath() canonicalPath()
2006 */
cleanPath(const QString & path)2007 QString QDir::cleanPath(const QString &path)
2008 {
2009     if (path.isEmpty())
2010         return path;
2011     QString name = path;
2012     QChar dir_separator = separator();
2013     if (dir_separator != QLatin1Char('/'))
2014        name.replace(dir_separator, QLatin1Char('/'));
2015 
2016     int used = 0, levels = 0;
2017     const int len = name.length();
2018     QVarLengthArray<QChar> outVector(len);
2019     QChar *out = outVector.data();
2020 
2021     const QChar *p = name.unicode();
2022     for (int i = 0, last = -1, iwrite = 0; i < len; ++i) {
2023         if (p[i] == QLatin1Char('/')) {
2024             while (i+1 < len && p[i+1] == QLatin1Char('/')) {
2025 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //allow unc paths
2026                 if (!i)
2027                     break;
2028 #endif
2029                 i++;
2030             }
2031             bool eaten = false;
2032             if (i+1 < len && p[i+1] == QLatin1Char('.')) {
2033                 int dotcount = 1;
2034                 if (i+2 < len && p[i+2] == QLatin1Char('.'))
2035                     dotcount++;
2036                 if (i == len - dotcount - 1) {
2037                     if (dotcount == 1) {
2038                         break;
2039                     } else if (levels) {
2040                         if (last == -1) {
2041                             for (int i2 = iwrite-1; i2 >= 0; i2--) {
2042                                 if (out[i2] == QLatin1Char('/')) {
2043                                     last = i2;
2044                                     break;
2045                                 }
2046                             }
2047                         }
2048                         used -= iwrite - last - 1;
2049                         break;
2050                     }
2051                 } else if (p[i+dotcount+1] == QLatin1Char('/')) {
2052                     if (dotcount == 2 && levels) {
2053                         if (last == -1 || iwrite - last == 1) {
2054                             for (int i2 = (last == -1) ? (iwrite-1) : (last-1); i2 >= 0; i2--) {
2055                                 if (out[i2] == QLatin1Char('/')) {
2056                                     eaten = true;
2057                                     last = i2;
2058                                     break;
2059                                 }
2060                             }
2061                         } else {
2062                             eaten = true;
2063                         }
2064                         if (eaten) {
2065                             levels--;
2066                             used -= iwrite - last;
2067                             iwrite = last;
2068                             last = -1;
2069                         }
2070                     } else if (dotcount == 2 && i > 0 && p[i - 1] != QLatin1Char('.')) {
2071                         eaten = true;
2072                         used -= iwrite - qMax(0, last);
2073                         iwrite = qMax(0, last);
2074                         last = -1;
2075                         ++i;
2076                     } else if (dotcount == 1) {
2077                         eaten = true;
2078                     }
2079                     if (eaten)
2080                         i += dotcount;
2081                 } else {
2082                     levels++;
2083                 }
2084             } else if (last != -1 && iwrite - last == 1) {
2085 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
2086                 eaten = (iwrite > 2);
2087 #else
2088                 eaten = true;
2089 #endif
2090                 last = -1;
2091             } else if (last != -1 && i == len-1) {
2092                 eaten = true;
2093             } else {
2094                 levels++;
2095             }
2096             if (!eaten)
2097                 last = i - (i - iwrite);
2098             else
2099                 continue;
2100         } else if (!i && p[i] == QLatin1Char('.')) {
2101             int dotcount = 1;
2102             if (len >= 1 && p[1] == QLatin1Char('.'))
2103                 dotcount++;
2104             if (len >= dotcount && p[dotcount] == QLatin1Char('/')) {
2105                 if (dotcount == 1) {
2106                     i++;
2107                     while (i+1 < len-1 && p[i+1] == QLatin1Char('/'))
2108                         i++;
2109                     continue;
2110                 }
2111             }
2112         }
2113         out[iwrite++] = p[i];
2114         used++;
2115     }
2116 
2117     QString ret = (used == len ? name : QString(out, used));
2118     // Strip away last slash except for root directories
2119     if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {
2120 #if defined (Q_OS_WIN) || defined (Q_OS_SYMBIAN)
2121         if (!(ret.length() == 3 && ret.at(1) == QLatin1Char(':')))
2122 #endif
2123             ret.chop(1);
2124     }
2125 
2126     return ret;
2127 }
2128 
2129 /*!
2130     Returns true if \a path is relative; returns false if it is
2131     absolute.
2132 
2133     \sa isRelative() isAbsolutePath() makeAbsolute()
2134 */
isRelativePath(const QString & path)2135 bool QDir::isRelativePath(const QString &path)
2136 {
2137     return QFileInfo(path).isRelative();
2138 }
2139 
2140 /*!
2141     Refreshes the directory information.
2142 */
refresh() const2143 void QDir::refresh() const
2144 {
2145     QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data();
2146     d->metaData.clear();
2147     d->initFileEngine();
2148     d->clearFileLists();
2149 }
2150 
2151 /*!
2152     \internal
2153 
2154     Returns a list of name filters from the given \a nameFilter. (If
2155     there is more than one filter, each pair of filters is separated
2156     by a space or by a semicolon.)
2157 */
nameFiltersFromString(const QString & nameFilter)2158 QStringList QDir::nameFiltersFromString(const QString &nameFilter)
2159 {
2160     return QDirPrivate::splitFilters(nameFilter);
2161 }
2162 
2163 /*!
2164     \macro void Q_INIT_RESOURCE(name)
2165     \relates QDir
2166 
2167     Initializes the resources specified by the \c .qrc file with the
2168     specified base \a name. Normally, Qt resources are loaded
2169     automatically at startup. The Q_INIT_RESOURCE() macro is
2170     necessary on some platforms for resources stored in a static
2171     library.
2172 
2173     For example, if your application's resources are listed in a file
2174     called \c myapp.qrc, you can ensure that the resources are
2175     initialized at startup by adding this line to your \c main()
2176     function:
2177 
2178     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 13
2179 
2180     If the file name contains characters that cannot be part of a valid C++ function name
2181     (such as '-'), they have to be replaced by the underscore character ('_').
2182 
2183     Note: This macro cannot be used in a namespace. It should be called from
2184     main(). If that is not possible, the following workaround can be used
2185     to init the resource \c myapp from the function \c{MyNamespace::myFunction}:
2186 
2187     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 14
2188 
2189     \sa Q_CLEANUP_RESOURCE(), {The Qt Resource System}
2190 */
2191 
2192 /*!
2193     \since 4.1
2194     \macro void Q_CLEANUP_RESOURCE(name)
2195     \relates QDir
2196 
2197     Unloads the resources specified by the \c .qrc file with the base
2198     name \a name.
2199 
2200     Normally, Qt resources are unloaded automatically when the
2201     application terminates, but if the resources are located in a
2202     plugin that is being unloaded, call Q_CLEANUP_RESOURCE() to force
2203     removal of your resources.
2204 
2205     Note: This macro cannot be used in a namespace. Please see the
2206     Q_INIT_RESOURCE documentation for a workaround.
2207 
2208     Example:
2209 
2210     \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 15
2211 
2212     \sa Q_INIT_RESOURCE(), {The Qt Resource System}
2213 */
2214 
2215 #ifdef QT3_SUPPORT
2216 
2217 /*!
2218     \fn bool QDir::matchAllDirs() const
2219 
2220     Use filter() & AllDirs instead.
2221 */
matchAllDirs() const2222 bool QDir::matchAllDirs() const
2223 {
2224     const QDirPrivate* d = d_ptr.constData();
2225     return d->matchAllDirs;
2226 }
2227 
2228 
2229 /*!
2230     \fn void QDir::setMatchAllDirs(bool on)
2231 
2232     Use setFilter() instead.
2233 */
setMatchAllDirs(bool on)2234 void QDir::setMatchAllDirs(bool on)
2235 {
2236     QDirPrivate* d = d_ptr.data();
2237     d->initFileEngine();
2238     d->clearFileLists();
2239 
2240     d->matchAllDirs = on;
2241 }
2242 
2243 /*!
2244     Use nameFilters() instead.
2245 */
nameFilter() const2246 QString QDir::nameFilter() const
2247 {
2248     const QDirPrivate* d = d_ptr.constData();
2249     return nameFilters().join(QString(d->filterSepChar));
2250 }
2251 
2252 /*!
2253     Use setNameFilters() instead.
2254 
2255     The \a nameFilter is a wildcard (globbing) filter that understands
2256     "*" and "?" wildcards. (See \l{QRegExp wildcard matching}.) You may
2257     specify several filter entries, each separated by spaces or by
2258     semicolons.
2259 
2260     For example, if you want entryList() and entryInfoList() to list
2261     all files ending with either ".cpp" or ".h", you would use either
2262     dir.setNameFilters("*.cpp *.h") or dir.setNameFilters("*.cpp;*.h").
2263 
2264     \oldcode
2265         QString filter = "*.cpp *.cxx *.cc";
2266         dir.setNameFilter(filter);
2267     \newcode
2268         QString filter = "*.cpp *.cxx *.cc";
2269         dir.setNameFilters(filter.split(' '));
2270     \endcode
2271 */
setNameFilter(const QString & nameFilter)2272 void QDir::setNameFilter(const QString &nameFilter)
2273 {
2274     QDirPrivate* d = d_ptr.data();
2275     d->initFileEngine();
2276     d->clearFileLists();
2277 
2278     d->filterSepChar = QDirPrivate::getFilterSepChar(nameFilter);
2279     d->nameFilters = QDirPrivate::splitFilters(nameFilter, d->filterSepChar);
2280 }
2281 
2282 /*!
2283     \fn QString QDir::absPath() const
2284 
2285     Use absolutePath() instead.
2286 */
2287 
2288 /*!
2289     \fn QString QDir::absFilePath(const QString &fileName, bool acceptAbsPath) const
2290 
2291     Use absoluteFilePath(\a fileName) instead.
2292 
2293     The \a acceptAbsPath parameter is ignored.
2294 */
2295 
2296 /*!
2297     \fn bool QDir::mkdir(const QString &dirName, bool acceptAbsPath) const
2298 
2299     Use mkdir(\a dirName) instead.
2300 
2301     The \a acceptAbsPath parameter is ignored.
2302 */
2303 
2304 /*!
2305     \fn bool QDir::rmdir(const QString &dirName, bool acceptAbsPath) const
2306 
2307     Use rmdir(\a dirName) instead.
2308 
2309     The \a acceptAbsPath parameter is ignored.
2310 */
2311 
2312 /*!
2313     \fn QStringList QDir::entryList(const QString &nameFilter, Filters filters,
2314                                     SortFlags sort) const
2315     \overload
2316 
2317     Use the overload that takes a name filter string list as first
2318     argument instead of a combination of attribute filter flags.
2319 */
2320 
2321 /*!
2322     \fn QFileInfoList QDir::entryInfoList(const QString &nameFilter, Filters filters,
2323                                           SortFlags sort) const
2324     \overload
2325 
2326     Use the overload that takes a name filter string list as first
2327     argument instead of a combination of attribute filter flags.
2328 */
2329 
2330 /*!
2331     \fn void QDir::convertToAbs()
2332 
2333     Use makeAbsolute() instead.
2334 */
2335 
2336 /*!
2337     \fn QString QDir::cleanDirPath(const QString &name)
2338 
2339     Use cleanPath() instead.
2340 */
2341 
2342 /*!
2343     \typedef QDir::FilterSpec
2344 
2345     Use QDir::Filters instead.
2346 */
2347 
2348 /*!
2349     \typedef QDir::SortSpec
2350 
2351     Use QDir::SortFlags instead.
2352 */
2353 #endif // QT3_SUPPORT
2354 
2355 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug debug,QDir::Filters filters)2356 QDebug operator<<(QDebug debug, QDir::Filters filters)
2357 {
2358     QStringList flags;
2359     if (filters == QDir::NoFilter) {
2360         flags << QLatin1String("NoFilter");
2361     } else {
2362         if (filters & QDir::Dirs) flags << QLatin1String("Dirs");
2363         if (filters & QDir::AllDirs) flags << QLatin1String("AllDirs");
2364         if (filters & QDir::Files) flags << QLatin1String("Files");
2365         if (filters & QDir::Drives) flags << QLatin1String("Drives");
2366         if (filters & QDir::NoSymLinks) flags << QLatin1String("NoSymLinks");
2367         if (filters & QDir::NoDotAndDotDot) flags << QLatin1String("NoDotAndDotDot"); // ### Qt5: remove (because NoDotAndDotDot=NoDot|NoDotDot)
2368         if (filters & QDir::NoDot) flags << QLatin1String("NoDot");
2369         if (filters & QDir::NoDotDot) flags << QLatin1String("NoDotDot");
2370         if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << QLatin1String("AllEntries");
2371         if (filters & QDir::Readable) flags << QLatin1String("Readable");
2372         if (filters & QDir::Writable) flags << QLatin1String("Writable");
2373         if (filters & QDir::Executable) flags << QLatin1String("Executable");
2374         if (filters & QDir::Modified) flags << QLatin1String("Modified");
2375         if (filters & QDir::Hidden) flags << QLatin1String("Hidden");
2376         if (filters & QDir::System) flags << QLatin1String("System");
2377         if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
2378     }
2379     debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ')';
2380     return debug;
2381 }
2382 
operator <<(QDebug debug,QDir::SortFlags sorting)2383 static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
2384 {
2385     if (sorting == QDir::NoSort) {
2386         debug << "QDir::SortFlags(NoSort)";
2387     } else {
2388         QString type;
2389         if ((sorting & 3) == QDir::Name) type = QLatin1String("Name");
2390         if ((sorting & 3) == QDir::Time) type = QLatin1String("Time");
2391         if ((sorting & 3) == QDir::Size) type = QLatin1String("Size");
2392         if ((sorting & 3) == QDir::Unsorted) type = QLatin1String("Unsorted");
2393 
2394         QStringList flags;
2395         if (sorting & QDir::DirsFirst) flags << QLatin1String("DirsFirst");
2396         if (sorting & QDir::DirsLast) flags << QLatin1String("DirsLast");
2397         if (sorting & QDir::IgnoreCase) flags << QLatin1String("IgnoreCase");
2398         if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware");
2399         if (sorting & QDir::Type) flags << QLatin1String("Type");
2400         debug << "QDir::SortFlags(" << qPrintable(type)
2401               << '|'
2402               << qPrintable(flags.join(QLatin1String("|"))) << ')';
2403     }
2404     return debug;
2405 }
2406 
operator <<(QDebug debug,const QDir & dir)2407 QDebug operator<<(QDebug debug, const QDir &dir)
2408 {
2409     debug.maybeSpace() << "QDir(" << dir.path()
2410                        << ", nameFilters = {"
2411                        << qPrintable(dir.nameFilters().join(QLatin1String(",")))
2412                        << "}, "
2413                        << dir.sorting()
2414                        << ','
2415                        << dir.filter()
2416                        << ')';
2417     return debug.space();
2418 }
2419 #endif // QT_NO_DEBUG_STREAM
2420 
2421 QT_END_NAMESPACE
2422