summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/corelib/io
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri119
-rw-r--r--src/corelib/io/qabstractfileengine.cpp1233
-rw-r--r--src/corelib/io/qabstractfileengine.h248
-rw-r--r--src/corelib/io/qabstractfileengine_p.h81
-rw-r--r--src/corelib/io/qbuffer.cpp493
-rw-r--r--src/corelib/io/qbuffer.h112
-rw-r--r--src/corelib/io/qdatastream.cpp1325
-rw-r--r--src/corelib/io/qdatastream.h440
-rw-r--r--src/corelib/io/qdatastream_p.h72
-rw-r--r--src/corelib/io/qdataurl.cpp101
-rw-r--r--src/corelib/io/qdataurl_p.h67
-rw-r--r--src/corelib/io/qdebug.cpp307
-rw-r--r--src/corelib/io/qdebug.h300
-rw-r--r--src/corelib/io/qdir.cpp2386
-rw-r--r--src/corelib/io/qdir.h271
-rw-r--r--src/corelib/io/qdir_p.h98
-rw-r--r--src/corelib/io/qdiriterator.cpp561
-rw-r--r--src/corelib/io/qdiriterator.h97
-rw-r--r--src/corelib/io/qfile.cpp1884
-rw-r--r--src/corelib/io/qfile.h218
-rw-r--r--src/corelib/io/qfile_p.h99
-rw-r--r--src/corelib/io/qfileinfo.cpp1399
-rw-r--r--src/corelib/io/qfileinfo.h206
-rw-r--r--src/corelib/io/qfileinfo_p.h160
-rw-r--r--src/corelib/io/qfilesystemengine.cpp391
-rw-r--r--src/corelib/io/qfilesystemengine_mac.cpp48
-rw-r--r--src/corelib/io/qfilesystemengine_p.h133
-rw-r--r--src/corelib/io/qfilesystemengine_symbian.cpp408
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp660
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp1218
-rw-r--r--src/corelib/io/qfilesystementry.cpp383
-rw-r--r--src/corelib/io/qfilesystementry_p.h126
-rw-r--r--src/corelib/io/qfilesystemiterator_p.h120
-rw-r--r--src/corelib/io/qfilesystemiterator_symbian.cpp127
-rw-r--r--src/corelib/io/qfilesystemiterator_unix.cpp117
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp148
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h400
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp640
-rw-r--r--src/corelib/io/qfilesystemwatcher.h89
-rw-r--r--src/corelib/io/qfilesystemwatcher_dnotify.cpp461
-rw-r--r--src/corelib/io/qfilesystemwatcher_dnotify_p.h131
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.cpp492
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h132
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp410
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify_p.h95
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp334
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue_p.h97
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h121
-rw-r--r--src/corelib/io/qfilesystemwatcher_symbian.cpp273
-rw-r--r--src/corelib/io/qfilesystemwatcher_symbian_p.h130
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp425
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h166
-rw-r--r--src/corelib/io/qfsfileengine.cpp965
-rw-r--r--src/corelib/io/qfsfileengine.h129
-rw-r--r--src/corelib/io/qfsfileengine_iterator.cpp106
-rw-r--r--src/corelib/io/qfsfileengine_iterator_p.h91
-rw-r--r--src/corelib/io/qfsfileengine_p.h202
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp1108
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp1008
-rw-r--r--src/corelib/io/qiodevice.cpp1846
-rw-r--r--src/corelib/io/qiodevice.h254
-rw-r--r--src/corelib/io/qiodevice_p.h245
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp545
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h190
-rw-r--r--src/corelib/io/qprocess.cpp2371
-rw-r--r--src/corelib/io/qprocess.h245
-rw-r--r--src/corelib/io/qprocess_p.h260
-rw-r--r--src/corelib/io/qprocess_symbian.cpp1067
-rw-r--r--src/corelib/io/qprocess_unix.cpp1297
-rw-r--r--src/corelib/io/qprocess_win.cpp855
-rw-r--r--src/corelib/io/qresource.cpp1496
-rw-r--r--src/corelib/io/qresource.h104
-rw-r--r--src/corelib/io/qresource_iterator.cpp90
-rw-r--r--src/corelib/io/qresource_iterator_p.h80
-rw-r--r--src/corelib/io/qresource_p.h119
-rw-r--r--src/corelib/io/qsettings.cpp3843
-rw-r--r--src/corelib/io/qsettings.h313
-rw-r--r--src/corelib/io/qsettings_mac.cpp654
-rw-r--r--src/corelib/io/qsettings_p.h316
-rw-r--r--src/corelib/io/qsettings_win.cpp847
-rw-r--r--src/corelib/io/qtemporaryfile.cpp713
-rw-r--r--src/corelib/io/qtemporaryfile.h108
-rw-r--r--src/corelib/io/qtextstream.cpp3413
-rw-r--r--src/corelib/io/qtextstream.h377
-rw-r--r--src/corelib/io/qurl.cpp6544
-rw-r--r--src/corelib/io/qurl.h302
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp171
-rw-r--r--src/corelib/io/qwindowspipewriter_p.h162
88 files changed, 52988 insertions, 0 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
new file mode 100644
index 0000000000..f67600d750
--- /dev/null
+++ b/src/corelib/io/io.pri
@@ -0,0 +1,119 @@
+# Qt core io module
+
+HEADERS += \
+ io/qabstractfileengine.h \
+ io/qabstractfileengine_p.h \
+ io/qbuffer.h \
+ io/qdatastream.h \
+ io/qdatastream_p.h \
+ io/qdataurl_p.h \
+ io/qdebug.h \
+ io/qdir.h \
+ io/qdir_p.h \
+ io/qdiriterator.h \
+ io/qfile.h \
+ io/qfileinfo.h \
+ io/qfileinfo_p.h \
+ io/qiodevice.h \
+ io/qiodevice_p.h \
+ io/qnoncontiguousbytedevice_p.h \
+ io/qprocess.h \
+ io/qprocess_p.h \
+ io/qtextstream.h \
+ io/qtemporaryfile.h \
+ io/qresource_p.h \
+ io/qresource_iterator_p.h \
+ io/qurl.h \
+ io/qsettings.h \
+ io/qsettings_p.h \
+ io/qfsfileengine.h \
+ io/qfsfileengine_p.h \
+ io/qfsfileengine_iterator_p.h \
+ io/qfilesystemwatcher.h \
+ io/qfilesystemwatcher_p.h \
+ io/qfilesystementry_p.h \
+ io/qfilesystemengine_p.h \
+ io/qfilesystemmetadata_p.h \
+ io/qfilesystemiterator_p.h
+
+SOURCES += \
+ io/qabstractfileengine.cpp \
+ io/qbuffer.cpp \
+ io/qdatastream.cpp \
+ io/qdataurl.cpp \
+ io/qdebug.cpp \
+ io/qdir.cpp \
+ io/qdiriterator.cpp \
+ io/qfile.cpp \
+ io/qfileinfo.cpp \
+ io/qiodevice.cpp \
+ io/qnoncontiguousbytedevice.cpp \
+ io/qprocess.cpp \
+ io/qtextstream.cpp \
+ io/qtemporaryfile.cpp \
+ io/qresource.cpp \
+ io/qresource_iterator.cpp \
+ io/qurl.cpp \
+ io/qsettings.cpp \
+ io/qfsfileengine.cpp \
+ io/qfsfileengine_iterator.cpp \
+ io/qfilesystemwatcher.cpp \
+ io/qfilesystementry.cpp \
+ io/qfilesystemengine.cpp
+
+win32 {
+ SOURCES += io/qsettings_win.cpp
+ SOURCES += io/qprocess_win.cpp
+ SOURCES += io/qfsfileengine_win.cpp
+
+ SOURCES += io/qfilesystemwatcher_win.cpp
+ HEADERS += io/qfilesystemwatcher_win_p.h
+ HEADERS += io/qwindowspipewriter_p.h
+ SOURCES += io/qwindowspipewriter.cpp
+ SOURCES += io/qfilesystemengine_win.cpp
+ SOURCES += io/qfilesystemiterator_win.cpp
+} else:unix {
+ SOURCES += io/qfsfileengine_unix.cpp
+ symbian {
+ SOURCES += io/qfilesystemengine_symbian.cpp
+ SOURCES += io/qprocess_symbian.cpp
+ SOURCES += io/qfilesystemiterator_symbian.cpp
+ } else {
+ SOURCES += io/qfilesystemengine_unix.cpp
+ SOURCES += io/qprocess_unix.cpp
+ SOURCES += io/qfilesystemiterator_unix.cpp
+ }
+ !nacl:macx-*: {
+ HEADERS += io/qfilesystemwatcher_fsevents_p.h
+ SOURCES += io/qfilesystemengine_mac.cpp
+ SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp
+ }
+
+ linux-*:!symbian {
+ SOURCES += \
+ io/qfilesystemwatcher_inotify.cpp \
+ io/qfilesystemwatcher_dnotify.cpp
+
+ HEADERS += \
+ io/qfilesystemwatcher_inotify_p.h \
+ io/qfilesystemwatcher_dnotify_p.h
+ }
+
+ !nacl {
+ freebsd-*|macx-*|darwin-*|openbsd-*:{
+ SOURCES += io/qfilesystemwatcher_kqueue.cpp
+ HEADERS += io/qfilesystemwatcher_kqueue_p.h
+ }
+ }
+
+ symbian {
+ SOURCES += io/qfilesystemwatcher_symbian.cpp
+ HEADERS += io/qfilesystemwatcher_symbian_p.h
+ INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE
+ LIBS += -lplatformenv -lesock
+ }
+}
+integrity {
+ SOURCES += io/qfsfileengine_unix.cpp \
+ io/qfsfileengine_iterator_unix.cpp
+}
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
new file mode 100644
index 0000000000..0a423c0879
--- /dev/null
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -0,0 +1,1233 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractfileengine.h"
+#include "private/qabstractfileengine_p.h"
+#ifdef QT_BUILD_CORE_LIB
+#include "private/qresource_p.h"
+#endif
+#include "qdatetime.h"
+#include "qreadwritelock.h"
+#include "qvariant.h"
+// built-in handlers
+#include "qfsfileengine.h"
+#include "qdiriterator.h"
+#include "qstringbuilder.h"
+
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+#include <QtCore/private/qfilesystemengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractFileEngineHandler
+ \reentrant
+
+ \brief The QAbstractFileEngineHandler class provides a way to register
+ custom file engines with your application.
+
+ \ingroup io
+ \since 4.1
+
+ QAbstractFileEngineHandler is a factory for creating QAbstractFileEngine
+ objects (file engines), which are used internally by QFile, QFileInfo, and
+ QDir when working with files and directories.
+
+ When you open a file, Qt chooses a suitable file engine by passing the
+ file name from QFile or QDir through an internal list of registered file
+ engine handlers. The first handler to recognize the file name is used to
+ create the engine. Qt provides internal file engines for working with
+ regular files and resources, but you can also register your own
+ QAbstractFileEngine subclasses.
+
+ To install an application-specific file engine, you subclass
+ QAbstractFileEngineHandler and reimplement create(). When you instantiate
+ the handler (e.g. by creating an instance on the stack or on the heap), it
+ will automatically register with Qt. (The latest registered handler takes
+ precedence over existing handlers.)
+
+ For example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qabstractfileengine.cpp 0
+
+ When the handler is destroyed, it is automatically removed from Qt.
+
+ The most common approach to registering a handler is to create an instance
+ as part of the start-up phase of your application. It is also possible to
+ limit the scope of the file engine handler to a particular area of
+ interest (e.g. a special file dialog that needs a custom file engine). By
+ creating the handler inside a local scope, you can precisely control the
+ area in which your engine will be applied without disturbing file
+ operations in other parts of your application.
+
+ \sa QAbstractFileEngine, QAbstractFileEngine::create()
+*/
+
+static bool qt_file_engine_handlers_in_use = false;
+
+/*
+ All application-wide handlers are stored in this list. The mutex must be
+ acquired to ensure thread safety.
+ */
+Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive))
+static bool qt_abstractfileenginehandlerlist_shutDown = false;
+class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
+{
+public:
+ ~QAbstractFileEngineHandlerList()
+ {
+ QWriteLocker locker(fileEngineHandlerMutex());
+ qt_abstractfileenginehandlerlist_shutDown = true;
+ }
+};
+Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers)
+
+/*!
+ Constructs a file handler and registers it with Qt. Once created this
+ handler's create() function will be called (along with all the other
+ handlers) for any paths used. The most recently created handler that
+ recognizes the given path (i.e. that returns a QAbstractFileEngine) is
+ used for the new path.
+
+ \sa create()
+ */
+QAbstractFileEngineHandler::QAbstractFileEngineHandler()
+{
+ QWriteLocker locker(fileEngineHandlerMutex());
+ qt_file_engine_handlers_in_use = true;
+ fileEngineHandlers()->prepend(this);
+}
+
+/*!
+ Destroys the file handler. This will automatically unregister the handler
+ from Qt.
+ */
+QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
+{
+ QWriteLocker locker(fileEngineHandlerMutex());
+ // Remove this handler from the handler list only if the list is valid.
+ if (!qt_abstractfileenginehandlerlist_shutDown) {
+ QAbstractFileEngineHandlerList *handlers = fileEngineHandlers();
+ handlers->removeOne(this);
+ if (handlers->isEmpty())
+ qt_file_engine_handlers_in_use = false;
+ }
+}
+
+/*
+ \├Čnternal
+
+ Handles calls to custom file engine handlers.
+*/
+QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
+{
+ QAbstractFileEngine *engine = 0;
+
+ if (qt_file_engine_handlers_in_use) {
+ QReadLocker locker(fileEngineHandlerMutex());
+
+ // check for registered handlers that can load the file
+ QAbstractFileEngineHandlerList *handlers = fileEngineHandlers();
+ for (int i = 0; i < handlers->size(); i++) {
+ if ((engine = handlers->at(i)->create(path)))
+ break;
+ }
+ }
+
+ return engine;
+}
+
+/*!
+ \fn QAbstractFileEngine *QAbstractFileEngineHandler::create(const QString &fileName) const
+
+ Creates a file engine for file \a fileName. Returns 0 if this
+ file handler cannot handle \a fileName.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qabstractfileengine.cpp 1
+
+ \sa QAbstractFileEngine::create()
+*/
+
+/*!
+ Creates and returns a QAbstractFileEngine suitable for processing \a
+ fileName.
+
+ You should not need to call this function; use QFile, QFileInfo or
+ QDir directly instead.
+
+ If you reimplemnt this function, it should only return file
+ engines that knows how to handle \a fileName; otherwise, it should
+ return 0.
+
+ \sa QAbstractFileEngineHandler
+*/
+QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
+{
+ QFileSystemEntry entry(fileName);
+ QFileSystemMetaData metaData;
+ QAbstractFileEngine *engine = QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, metaData);
+
+#ifndef QT_NO_FSFILEENGINE
+ if (!engine)
+ // fall back to regular file engine
+ return new QFSFileEngine(entry.filePath());
+#endif
+
+ return engine;
+}
+
+/*!
+ \class QAbstractFileEngine
+ \reentrant
+
+ \brief The QAbstractFileEngine class provides an abstraction for accessing
+ the filesystem.
+
+ \ingroup io
+ \since 4.1
+
+ The QDir, QFile, and QFileInfo classes all make use of a
+ QAbstractFileEngine internally. If you create your own QAbstractFileEngine
+ subclass (and register it with Qt by creating a QAbstractFileEngineHandler
+ subclass), your file engine will be used when the path is one that your
+ file engine handles.
+
+ A QAbstractFileEngine refers to one file or one directory. If the referent
+ is a file, the setFileName(), rename(), and remove() functions are
+ applicable. If the referent is a directory the mkdir(), rmdir(), and
+ entryList() functions are applicable. In all cases the caseSensitive(),
+ isRelativePath(), fileFlags(), ownerId(), owner(), and fileTime()
+ functions are applicable.
+
+ A QAbstractFileEngine subclass can be created to do synchronous network I/O
+ based file system operations, local file system operations, or to operate
+ as a resource system to access file based resources.
+
+ \sa QAbstractFileEngineHandler
+*/
+
+/*!
+ \enum QAbstractFileEngine::FileName
+
+ These values are used to request a file name in a particular
+ format.
+
+ \value DefaultName The same filename that was passed to the
+ QAbstractFileEngine.
+ \value BaseName The name of the file excluding the path.
+ \value PathName The path to the file excluding the base name.
+ \value AbsoluteName The absolute path to the file (including
+ the base name).
+ \value AbsolutePathName The absolute path to the file (excluding
+ the base name).
+ \value LinkName The full file name of the file that this file is a
+ link to. (This will be empty if this file is not a link.)
+ \value CanonicalName Often very similar to LinkName. Will return the true path to the file.
+ \value CanonicalPathName Same as CanonicalName, excluding the base name.
+ \value BundleName Returns the name of the bundle implies BundleType is set.
+
+ \omitvalue NFileNames
+
+ \sa fileName(), setFileName()
+*/
+
+/*!
+ \enum QAbstractFileEngine::FileFlag
+
+ The permissions and types of a file, suitable for OR'ing together.
+
+ \value ReadOwnerPerm The owner of the file has permission to read
+ it.
+ \value WriteOwnerPerm The owner of the file has permission to
+ write to it.
+ \value ExeOwnerPerm The owner of the file has permission to
+ execute it.
+ \value ReadUserPerm The current user has permission to read the
+ file.
+ \value WriteUserPerm The current user has permission to write to
+ the file.
+ \value ExeUserPerm The current user has permission to execute the
+ file.
+ \value ReadGroupPerm Members of the current user's group have
+ permission to read the file.
+ \value WriteGroupPerm Members of the current user's group have
+ permission to write to the file.
+ \value ExeGroupPerm Members of the current user's group have
+ permission to execute the file.
+ \value ReadOtherPerm All users have permission to read the file.
+ \value WriteOtherPerm All users have permission to write to the
+ file.
+ \value ExeOtherPerm All users have permission to execute the file.
+
+ \value LinkType The file is a link to another file (or link) in
+ the file system (i.e. not a file or directory).
+ \value FileType The file is a regular file to the file system
+ (i.e. not a link or directory)
+ \value BundleType The file is a Mac OS X bundle implies DirectoryType
+ \value DirectoryType The file is a directory in the file system
+ (i.e. not a link or file).
+
+ \value HiddenFlag The file is hidden.
+ \value ExistsFlag The file actually exists in the file system.
+ \value RootFlag The file or the file pointed to is the root of the filesystem.
+ \value LocalDiskFlag The file resides on the local disk and can be passed to standard file functions.
+ \value Refresh Passing this flag will force the file engine to refresh all flags.
+
+ \omitvalue PermsMask
+ \omitvalue TypesMask
+ \omitvalue FlagsMask
+ \omitvalue FileInfoAll
+
+ \sa fileFlags(), setFileName()
+*/
+
+/*!
+ \enum QAbstractFileEngine::FileTime
+
+ These are used by the fileTime() function.
+
+ \value CreationTime When the file was created.
+ \value ModificationTime When the file was most recently modified.
+ \value AccessTime When the file was most recently accessed (e.g.
+ read or written to).
+
+ \sa setFileName()
+*/
+
+/*!
+ \enum QAbstractFileEngine::FileOwner
+
+ \value OwnerUser The user who owns the file.
+ \value OwnerGroup The group who owns the file.
+
+ \sa owner(), ownerId(), setFileName()
+*/
+
+/*!
+ Constructs a new QAbstractFileEngine that does not refer to any file or directory.
+
+ \sa setFileName()
+ */
+QAbstractFileEngine::QAbstractFileEngine() : d_ptr(new QAbstractFileEnginePrivate)
+{
+ d_ptr->q_ptr = this;
+}
+
+/*!
+ \internal
+
+ Constructs a QAbstractFileEngine.
+ */
+QAbstractFileEngine::QAbstractFileEngine(QAbstractFileEnginePrivate &dd) : d_ptr(&dd)
+{
+ d_ptr->q_ptr = this;
+}
+
+/*!
+ Destroys the QAbstractFileEngine.
+ */
+QAbstractFileEngine::~QAbstractFileEngine()
+{
+}
+
+/*!
+ \fn bool QAbstractFileEngine::open(QIODevice::OpenMode mode)
+
+ Opens the file in the specified \a mode. Returns true if the file
+ was successfully opened; otherwise returns false.
+
+ The \a mode is an OR combination of QIODevice::OpenMode and
+ QIODevice::HandlingMode values.
+*/
+bool QAbstractFileEngine::open(QIODevice::OpenMode openMode)
+{
+ Q_UNUSED(openMode);
+ return false;
+}
+
+/*!
+ Closes the file, returning true if successful; otherwise returns false.
+
+ The default implementation always returns false.
+*/
+bool QAbstractFileEngine::close()
+{
+ return false;
+}
+
+/*!
+ Flushes the open file, returning true if successful; otherwise returns
+ false.
+
+ The default implementation always returns false.
+*/
+bool QAbstractFileEngine::flush()
+{
+ return false;
+}
+
+/*!
+ Returns the size of the file.
+*/
+qint64 QAbstractFileEngine::size() const
+{
+ return 0;
+}
+
+/*!
+ Returns the current file position.
+
+ This is the position of the data read/write head of the file.
+*/
+qint64 QAbstractFileEngine::pos() const
+{
+ return 0;
+}
+
+/*!
+ \fn bool QAbstractFileEngine::seek(qint64 offset)
+
+ Sets the file position to the given \a offset. Returns true if
+ the position was successfully set; otherwise returns false.
+
+ The offset is from the beginning of the file, unless the
+ file is sequential.
+
+ \sa isSequential()
+*/
+bool QAbstractFileEngine::seek(qint64 pos)
+{
+ Q_UNUSED(pos);
+ return false;
+}
+
+/*!
+ Returns true if the file is a sequential access device; returns
+ false if the file is a direct access device.
+
+ Operations involving size() and seek(int) are not valid on
+ sequential devices.
+*/
+bool QAbstractFileEngine::isSequential() const
+{
+ return false;
+}
+
+/*!
+ Requests that the file is deleted from the file system. If the
+ operation succeeds return true; otherwise return false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName() rmdir()
+ */
+bool QAbstractFileEngine::remove()
+{
+ return false;
+}
+
+/*!
+ Copies the contents of this file to a file with the name \a newName.
+ Returns true on success; otherwise, false is returned.
+*/
+bool QAbstractFileEngine::copy(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+/*!
+ Requests that the file be renamed to \a newName in the file
+ system. If the operation succeeds return true; otherwise return
+ false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName()
+ */
+bool QAbstractFileEngine::rename(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+/*!
+ Creates a link from the file currently specified by fileName() to
+ \a newName. What a link is depends on the underlying filesystem
+ (be it a shortcut on Windows or a symbolic link on Unix). Returns
+ true if successful; otherwise returns false.
+*/
+bool QAbstractFileEngine::link(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+/*!
+ Requests that the directory \a dirName be created. If
+ \a createParentDirectories is true, then any sub-directories in \a dirName
+ that don't exist must be created. If \a createParentDirectories is false then
+ any sub-directories in \a dirName must already exist for the function to
+ succeed. If the operation succeeds return true; otherwise return
+ false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName() rmdir() isRelativePath()
+ */
+bool QAbstractFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
+{
+ Q_UNUSED(dirName);
+ Q_UNUSED(createParentDirectories);
+ return false;
+}
+
+/*!
+ Requests that the directory \a dirName is deleted from the file
+ system. When \a recurseParentDirectories is true, then any empty
+ parent-directories in \a dirName must also be deleted. If
+ \a recurseParentDirectories is false, only the \a dirName leaf-node
+ should be deleted. In most file systems a directory cannot be deleted
+ using this function if it is non-empty. If the operation succeeds
+ return true; otherwise return false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName() remove() mkdir() isRelativePath()
+ */
+bool QAbstractFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+ Q_UNUSED(dirName);
+ Q_UNUSED(recurseParentDirectories);
+ return false;
+}
+
+/*!
+ Requests that the file be set to size \a size. If \a size is larger
+ than the current file then it is filled with 0's, if smaller it is
+ simply truncated. If the operations succceeds return true; otherwise
+ return false;
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa size()
+*/
+bool QAbstractFileEngine::setSize(qint64 size)
+{
+ Q_UNUSED(size);
+ return false;
+}
+
+/*!
+ Should return true if the underlying file system is case-sensitive;
+ otherwise return false.
+
+ This virtual function must be reimplemented by all subclasses.
+ */
+bool QAbstractFileEngine::caseSensitive() const
+{
+ return false;
+}
+
+/*!
+ Return true if the file referred to by this file engine has a
+ relative path; otherwise return false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName()
+ */
+bool QAbstractFileEngine::isRelativePath() const
+{
+ return false;
+}
+
+/*!
+ Requests that a list of all the files matching the \a filters
+ list based on the \a filterNames in the file engine's directory
+ are returned.
+
+ Should return an empty list if the file engine refers to a file
+ rather than a directory, or if the directory is unreadable or does
+ not exist or if nothing matches the specifications.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName()
+ */
+QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
+{
+ QStringList ret;
+ QDirIterator it(fileName(), filterNames, filters);
+ while (it.hasNext()) {
+ it.next();
+ ret << it.fileName();
+ }
+ return ret;
+}
+
+/*!
+ This function should return the set of OR'd flags that are true
+ for the file engine's file, and that are in the \a type's OR'd
+ members.
+
+ In your reimplementation you can use the \a type argument as an
+ optimization hint and only return the OR'd set of members that are
+ true and that match those in \a type; in other words you can
+ ignore any members not mentioned in \a type, thus avoiding some
+ potentially expensive lookups or system calls.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName()
+*/
+QAbstractFileEngine::FileFlags QAbstractFileEngine::fileFlags(FileFlags type) const
+{
+ Q_UNUSED(type);
+ return 0;
+}
+
+/*!
+ Requests that the file's permissions be set to \a perms. The argument
+ perms will be set to the OR-ed together combination of
+ QAbstractFileEngine::FileInfo, with only the QAbstractFileEngine::PermsMask being
+ honored. If the operations succceeds return true; otherwise return
+ false;
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa size()
+*/
+bool QAbstractFileEngine::setPermissions(uint perms)
+{
+ Q_UNUSED(perms);
+ return false;
+}
+
+/*!
+ Return the file engine's current file name in the format
+ specified by \a file.
+
+ If you don't handle some \c FileName possibilities, return the
+ file name set in setFileName() when an unhandled format is
+ requested.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName(), FileName
+ */
+QString QAbstractFileEngine::fileName(FileName file) const
+{
+ Q_UNUSED(file);
+ return QString();
+}
+
+/*!
+ If \a owner is \c OwnerUser return the ID of the user who owns
+ the file. If \a owner is \c OwnerGroup return the ID of the group
+ that own the file. If you can't determine the owner return -2.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa owner() setFileName(), FileOwner
+ */
+uint QAbstractFileEngine::ownerId(FileOwner owner) const
+{
+ Q_UNUSED(owner);
+ return 0;
+}
+
+/*!
+ If \a owner is \c OwnerUser return the name of the user who owns
+ the file. If \a owner is \c OwnerGroup return the name of the group
+ that own the file. If you can't determine the owner return
+ QString().
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa ownerId() setFileName(), FileOwner
+ */
+QString QAbstractFileEngine::owner(FileOwner owner) const
+{
+ Q_UNUSED(owner);
+ return QString();
+}
+
+/*!
+ If \a time is \c CreationTime, return when the file was created.
+ If \a time is \c ModificationTime, return when the file was most
+ recently modified. If \a time is \c AccessTime, return when the
+ file was most recently accessed (e.g. read or written).
+ If the time cannot be determined return QDateTime() (an invalid
+ date time).
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa setFileName(), QDateTime, QDateTime::isValid(), FileTime
+ */
+QDateTime QAbstractFileEngine::fileTime(FileTime time) const
+{
+ Q_UNUSED(time);
+ return QDateTime();
+}
+
+/*!
+ Sets the file engine's file name to \a file. This file name is the
+ file that the rest of the virtual functions will operate on.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa rename()
+ */
+void QAbstractFileEngine::setFileName(const QString &file)
+{
+ Q_UNUSED(file);
+}
+
+/*!
+ Returns the native file handle for this file engine. This handle must be
+ used with care; its value and type are platform specific, and using it
+ will most likely lead to non-portable code.
+*/
+int QAbstractFileEngine::handle() const
+{
+ return -1;
+}
+
+/*!
+ \since 4.3
+
+ Returns true if the current position is at the end of the file; otherwise,
+ returns false.
+
+ This function bases its behavior on calling extension() with
+ AtEndExtension. If the engine does not support this extension, false is
+ returned.
+
+ \sa extension(), supportsExtension(), QFile::atEnd()
+*/
+bool QAbstractFileEngine::atEnd() const
+{
+ return const_cast<QAbstractFileEngine *>(this)->extension(AtEndExtension);
+}
+
+/*!
+ \since 4.4
+
+ Maps \a size bytes of the file into memory starting at \a offset.
+ Returns a pointer to the memory if successful; otherwise returns false
+ if, for example, an error occurs.
+
+ This function bases its behavior on calling extension() with
+ MapExtensionOption. If the engine does not support this extension, 0 is
+ returned.
+
+ \a flags is currently not used, but could be used in the future.
+
+ \sa unmap(), supportsExtension()
+ */
+
+uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
+{
+ MapExtensionOption option;
+ option.offset = offset;
+ option.size = size;
+ option.flags = flags;
+ MapExtensionReturn r;
+ if (!extension(MapExtension, &option, &r))
+ return 0;
+ return r.address;
+}
+
+/*!
+ \since 4.4
+
+ Unmaps the memory \a address. Returns true if the unmap succeeds; otherwise
+ returns false.
+
+ This function bases its behavior on calling extension() with
+ UnMapExtensionOption. If the engine does not support this extension, false is
+ returned.
+
+ \sa map(), supportsExtension()
+ */
+bool QAbstractFileEngine::unmap(uchar *address)
+{
+ UnMapExtensionOption options;
+ options.address = address;
+ return extension(UnMapExtension, &options);
+}
+
+/*!
+ \since 4.3
+ \class QAbstractFileEngineIterator
+ \brief The QAbstractFileEngineIterator class provides an iterator
+ interface for custom file engines.
+
+ If all you want is to iterate over entries in a directory, see
+ QDirIterator instead. This class is only for custom file engine authors.
+
+ QAbstractFileEngineIterator is a unidirectional single-use virtual
+ iterator that plugs into QDirIterator, providing transparent proxy
+ iteration for custom file engines.
+
+ You can subclass QAbstractFileEngineIterator to provide an iterator when
+ writing your own file engine. To plug the iterator into your file system,
+ you simply return an instance of this subclass from a reimplementation of
+ QAbstractFileEngine::beginEntryList().
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qabstractfileengine.cpp 2
+
+ QAbstractFileEngineIterator is associated with a path, name filters, and
+ entry filters. The path is the directory that the iterator lists entries
+ in. The name filters and entry filters are provided for file engines that
+ can optimize directory listing at the iterator level (e.g., network file
+ systems that need to minimize network traffic), but they can also be
+ ignored by the iterator subclass; QAbstractFileEngineIterator already
+ provides the required filtering logics in the matchesFilters() function.
+ You can call dirName() to get the directory name, nameFilters() to get a
+ stringlist of name filters, and filters() to get the entry filters.
+
+ The pure virtual function hasNext() returns true if the current directory
+ has at least one more entry (i.e., the directory name is valid and
+ accessible, and we have not reached the end of the entry list), and false
+ otherwise. Reimplement next() to seek to the next entry.
+
+ The pure virtual function currentFileName() returns the name of the
+ current entry without advancing the iterator. The currentFilePath()
+ function is provided for convenience; it returns the full path of the
+ current entry.
+
+ Here is an example of how to implement an iterator that returns each of
+ three fixed entries in sequence.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qabstractfileengine.cpp 3
+
+ Note: QAbstractFileEngineIterator does not deal with QDir::IteratorFlags;
+ it simply returns entries for a single directory.
+
+ \sa QDirIterator
+*/
+
+/*!
+ \enum QAbstractFileEngineIterator::EntryInfoType
+ \internal
+
+ This enum describes the different types of information that can be
+ requested through the QAbstractFileEngineIterator::entryInfo() function.
+*/
+
+/*!
+ \typedef QAbstractFileEngine::Iterator
+ \since 4.3
+ \relates QAbstractFileEngine
+
+ Synonym for QAbstractFileEngineIterator.
+*/
+
+class QAbstractFileEngineIteratorPrivate
+{
+public:
+ QString path;
+ QDir::Filters filters;
+ QStringList nameFilters;
+ QFileInfo fileInfo;
+};
+
+/*!
+ Constructs a QAbstractFileEngineIterator, using the entry filters \a
+ filters, and wildcard name filters \a nameFilters.
+*/
+QAbstractFileEngineIterator::QAbstractFileEngineIterator(QDir::Filters filters,
+ const QStringList &nameFilters)
+ : d(new QAbstractFileEngineIteratorPrivate)
+{
+ d->nameFilters = nameFilters;
+ d->filters = filters;
+}
+
+/*!
+ Destroys the QAbstractFileEngineIterator.
+
+ \sa QDirIterator
+*/
+QAbstractFileEngineIterator::~QAbstractFileEngineIterator()
+{
+}
+
+/*!
+ Returns the path for this iterator. QDirIterator is responsible for
+ assigning this path; it cannot change during the iterator's lifetime.
+
+ \sa nameFilters(), filters()
+*/
+QString QAbstractFileEngineIterator::path() const
+{
+ return d->path;
+}
+
+/*!
+ \internal
+
+ Sets the iterator path to \a path. This function is called from within
+ QDirIterator.
+*/
+void QAbstractFileEngineIterator::setPath(const QString &path)
+{
+ d->path = path;
+}
+
+/*!
+ Returns the name filters for this iterator.
+
+ \sa QDir::nameFilters(), filters(), path()
+*/
+QStringList QAbstractFileEngineIterator::nameFilters() const
+{
+ return d->nameFilters;
+}
+
+/*!
+ Returns the entry filters for this iterator.
+
+ \sa QDir::filter(), nameFilters(), path()
+*/
+QDir::Filters QAbstractFileEngineIterator::filters() const
+{
+ return d->filters;
+}
+
+/*!
+ \fn QString QAbstractFileEngineIterator::currentFileName() const = 0
+
+ This pure virtual function returns the name of the current directory
+ entry, excluding the path.
+
+ \sa currentFilePath()
+*/
+
+/*!
+ Returns the path to the current directory entry. It's the same as
+ prepending path() to the return value of currentFileName().
+
+ \sa currentFileName()
+*/
+QString QAbstractFileEngineIterator::currentFilePath() const
+{
+ QString name = currentFileName();
+ if (!name.isNull()) {
+ QString tmp = path();
+ if (!tmp.isEmpty()) {
+ if (!tmp.endsWith(QLatin1Char('/')))
+ tmp.append(QLatin1Char('/'));
+ name.prepend(tmp);
+ }
+ }
+ return name;
+}
+
+/*!
+ The virtual function returns a QFileInfo for the current directory
+ entry. This function is provided for convenience. It can also be slightly
+ faster than creating a QFileInfo object yourself, as the object returned
+ by this function might contain cached information that QFileInfo otherwise
+ would have to access through the file engine.
+
+ \sa currentFileName()
+*/
+QFileInfo QAbstractFileEngineIterator::currentFileInfo() const
+{
+ QString path = currentFilePath();
+ if (d->fileInfo.filePath() != path)
+ d->fileInfo.setFile(path);
+
+ // return a shallow copy
+ return d->fileInfo;
+}
+
+/*!
+ \internal
+
+ Returns the entry info \a type for this iterator's current directory entry
+ as a QVariant. If \a type is undefined for this entry, a null QVariant is
+ returned.
+
+ \sa QAbstractFileEngine::beginEntryList(), QDir::beginEntryList()
+*/
+QVariant QAbstractFileEngineIterator::entryInfo(EntryInfoType type) const
+{
+ Q_UNUSED(type)
+ return QVariant();
+}
+
+/*!
+ \fn virtual QString QAbstractFileEngineIterator::next() = 0
+
+ This pure virtual function advances the iterator to the next directory
+ entry, and returns the file path to the current entry.
+
+ This function can optionally make use of nameFilters() and filters() to
+ optimize its performance.
+
+ Reimplement this function in a subclass to advance the iterator.
+
+ \sa QDirIterator::next()
+*/
+
+/*!
+ \fn virtual bool QAbstractFileEngineIterator::hasNext() const = 0
+
+ This pure virtual function returns true if there is at least one more
+ entry in the current directory (i.e., the iterator path is valid and
+ accessible, and the iterator has not reached the end of the entry list).
+
+ \sa QDirIterator::hasNext()
+*/
+
+/*!
+ Returns an instance of a QAbstractFileEngineIterator using \a filters for
+ entry filtering and \a filterNames for name filtering. This function is
+ called by QDirIterator to initiate directory iteration.
+
+ QDirIterator takes ownership of the returned instance, and deletes it when
+ it's done.
+
+ \sa QDirIterator
+*/
+QAbstractFileEngine::Iterator *QAbstractFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+{
+ Q_UNUSED(filters);
+ Q_UNUSED(filterNames);
+ return 0;
+}
+
+/*!
+ \internal
+*/
+QAbstractFileEngine::Iterator *QAbstractFileEngine::endEntryList()
+{
+ return 0;
+}
+
+/*!
+ Reads a number of characters from the file into \a data. At most
+ \a maxlen characters will be read.
+
+ Returns -1 if a fatal error occurs, or 0 if there are no bytes to
+ read.
+*/
+qint64 QAbstractFileEngine::read(char *data, qint64 maxlen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ return -1;
+}
+
+/*!
+ Writes \a len bytes from \a data to the file. Returns the number
+ of characters written on success; otherwise returns -1.
+*/
+qint64 QAbstractFileEngine::write(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return -1;
+}
+
+/*!
+ This function reads one line, terminated by a '\n' character, from the
+ file info \a data. At most \a maxlen characters will be read. The
+ end-of-line character is included.
+*/
+qint64 QAbstractFileEngine::readLine(char *data, qint64 maxlen)
+{
+ qint64 readSoFar = 0;
+ while (readSoFar < maxlen) {
+ char c;
+ qint64 readResult = read(&c, 1);
+ if (readResult <= 0)
+ return (readSoFar > 0) ? readSoFar : -1;
+ ++readSoFar;
+ *data++ = c;
+ if (c == '\n')
+ return readSoFar;
+ }
+ return readSoFar;
+}
+
+/*!
+ \enum QAbstractFileEngine::Extension
+ \since 4.3
+
+ This enum describes the types of extensions that the file engine can
+ support. Before using these extensions, you must verify that the extension
+ is supported (i.e., call supportsExtension()).
+
+ \value AtEndExtension Whether the current file position is at the end of
+ the file or not. This extension allows file engines that implement local
+ buffering to report end-of-file status without having to check the size of
+ the file. It is also useful for sequential files, where the size of the
+ file cannot be used to determine whether or not you have reached the end.
+ This extension returns true if the file is at the end; otherwise it returns
+ false. The input and output arguments to extension() are ignored.
+
+ \value FastReadLineExtension Whether the file engine provides a
+ fast implementation for readLine() or not. If readLine() remains
+ unimplemented in the file engine, QAbstractFileEngine will provide
+ an implementation based on calling read() repeatedly. If
+ supportsExtension() returns false for this extension, however,
+ QIODevice can provide a faster implementation by making use of its
+ internal buffer. For engines that already provide a fast readLine()
+ implementation, returning false for this extension can avoid
+ unnnecessary double-buffering in QIODevice.
+
+ \value MapExtension Whether the file engine provides the ability to map
+ a file to memory.
+
+ \value UnMapExtension Whether the file engine provides the ability to
+ unmap memory that was previously mapped.
+*/
+
+/*!
+ \class QAbstractFileEngine::ExtensionOption
+ \since 4.3
+ \brief provides an extended input argument to QAbstractFileEngine's
+ extension support.
+
+ \sa QAbstractFileEngine::extension()
+*/
+
+/*!
+ \class QAbstractFileEngine::ExtensionReturn
+ \since 4.3
+ \brief provides an extended output argument to QAbstractFileEngine's
+ extension support.
+
+ \sa QAbstractFileEngine::extension()
+*/
+
+/*!
+ \since 4.3
+
+ This virtual function can be reimplemented in a QAbstractFileEngine
+ subclass to provide support for extensions. The \a option argument is
+ provided as input to the extension, and this function can store output
+ results in \a output.
+
+ The behavior of this function is determined by \a extension; see the
+ Extension documentation for details.
+
+ You can call supportsExtension() to check if an extension is supported by
+ the file engine.
+
+ By default, no extensions are supported, and this function returns false.
+
+ \sa supportsExtension(), Extension
+*/
+bool QAbstractFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(option);
+ Q_UNUSED(output);
+ return false;
+}
+
+/*!
+ \since 4.3
+
+ This virtual function returns true if the file engine supports \a
+ extension; otherwise, false is returned. By default, no extensions are
+ supported.
+
+ \sa extension()
+*/
+bool QAbstractFileEngine::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+/*!
+ Returns the QFile::FileError that resulted from the last failed
+ operation. If QFile::UnspecifiedError is returned, QFile will
+ use its own idea of the error status.
+
+ \sa QFile::FileError, errorString()
+ */
+QFile::FileError QAbstractFileEngine::error() const
+{
+ Q_D(const QAbstractFileEngine);
+ return d->fileError;
+}
+
+/*!
+ Returns the human-readable message appropriate to the current error
+ reported by error(). If no suitable string is available, an
+ empty string is returned.
+
+ \sa error()
+ */
+QString QAbstractFileEngine::errorString() const
+{
+ Q_D(const QAbstractFileEngine);
+ return d->errorString;
+}
+
+/*!
+ Sets the error type to \a error, and the error string to \a errorString.
+ Call this function to set the error values returned by the higher-level
+ classes.
+
+ \sa QFile::error(), QIODevice::errorString(), QIODevice::setErrorString()
+*/
+void QAbstractFileEngine::setError(QFile::FileError error, const QString &errorString)
+{
+ Q_D(QAbstractFileEngine);
+ d->fileError = error;
+ d->errorString = errorString;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qabstractfileengine.h b/src/corelib/io/qabstractfileengine.h
new file mode 100644
index 0000000000..91d3a5ef7e
--- /dev/null
+++ b/src/corelib/io/qabstractfileengine.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTFILEENGINE_H
+#define QABSTRACTFILEENGINE_H
+
+#include <QtCore/qdir.h>
+
+#ifdef open
+#error qabstractfileengine.h must be included before any header file that defines open
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QFileExtension;
+class QFileExtensionResult;
+class QVariant;
+class QAbstractFileEngineIterator;
+class QAbstractFileEnginePrivate;
+
+class Q_CORE_EXPORT QAbstractFileEngine
+{
+public:
+ enum FileFlag {
+ //perms (overlaps the QFile::Permission)
+ ReadOwnerPerm = 0x4000, WriteOwnerPerm = 0x2000, ExeOwnerPerm = 0x1000,
+ ReadUserPerm = 0x0400, WriteUserPerm = 0x0200, ExeUserPerm = 0x0100,
+ ReadGroupPerm = 0x0040, WriteGroupPerm = 0x0020, ExeGroupPerm = 0x0010,
+ ReadOtherPerm = 0x0004, WriteOtherPerm = 0x0002, ExeOtherPerm = 0x0001,
+
+ //types
+ LinkType = 0x10000,
+ FileType = 0x20000,
+ DirectoryType = 0x40000,
+ BundleType = 0x80000,
+
+ //flags
+ HiddenFlag = 0x0100000,
+ LocalDiskFlag = 0x0200000,
+ ExistsFlag = 0x0400000,
+ RootFlag = 0x0800000,
+ Refresh = 0x1000000,
+
+ //masks
+ PermsMask = 0x0000FFFF,
+ TypesMask = 0x000F0000,
+ FlagsMask = 0x0FF00000,
+ FileInfoAll = FlagsMask | PermsMask | TypesMask
+ };
+ Q_DECLARE_FLAGS(FileFlags, FileFlag)
+
+ enum FileName {
+ DefaultName,
+ BaseName,
+ PathName,
+ AbsoluteName,
+ AbsolutePathName,
+ LinkName,
+ CanonicalName,
+ CanonicalPathName,
+ BundleName,
+ NFileNames = 9
+ };
+ enum FileOwner {
+ OwnerUser,
+ OwnerGroup
+ };
+ enum FileTime {
+ CreationTime,
+ ModificationTime,
+ AccessTime
+ };
+
+ virtual ~QAbstractFileEngine();
+
+ virtual bool open(QIODevice::OpenMode openMode);
+ virtual bool close();
+ virtual bool flush();
+ virtual qint64 size() const;
+ virtual qint64 pos() const;
+ virtual bool seek(qint64 pos);
+ virtual bool isSequential() const;
+ virtual bool remove();
+ virtual bool copy(const QString &newName);
+ virtual bool rename(const QString &newName);
+ virtual bool link(const QString &newName);
+ virtual bool mkdir(const QString &dirName, bool createParentDirectories) const;
+ virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
+ virtual bool setSize(qint64 size);
+ virtual bool caseSensitive() const;
+ virtual bool isRelativePath() const;
+ virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
+ virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const;
+ virtual bool setPermissions(uint perms);
+ virtual QString fileName(FileName file=DefaultName) const;
+ virtual uint ownerId(FileOwner) const;
+ virtual QString owner(FileOwner) const;
+ virtual QDateTime fileTime(FileTime time) const;
+ virtual void setFileName(const QString &file);
+ virtual int handle() const;
+ bool atEnd() const;
+ uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
+ bool unmap(uchar *ptr);
+
+ typedef QAbstractFileEngineIterator Iterator;
+ virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
+ virtual Iterator *endEntryList();
+
+ virtual qint64 read(char *data, qint64 maxlen);
+ virtual qint64 readLine(char *data, qint64 maxlen);
+ virtual qint64 write(const char *data, qint64 len);
+
+ QFile::FileError error() const;
+ QString errorString() const;
+
+ enum Extension {
+ AtEndExtension,
+ FastReadLineExtension,
+ MapExtension,
+ UnMapExtension
+ };
+ class ExtensionOption
+ {};
+ class ExtensionReturn
+ {};
+
+ class MapExtensionOption : public ExtensionOption {
+ public:
+ qint64 offset;
+ qint64 size;
+ QFile::MemoryMapFlags flags;
+ };
+ class MapExtensionReturn : public ExtensionReturn {
+ public:
+ uchar *address;
+ };
+
+ class UnMapExtensionOption : public ExtensionOption {
+ public:
+ uchar *address;
+ };
+
+ virtual bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0);
+ virtual bool supportsExtension(Extension extension) const;
+
+ // Factory
+ static QAbstractFileEngine *create(const QString &fileName);
+
+protected:
+ void setError(QFile::FileError error, const QString &str);
+
+ QAbstractFileEngine();
+ QAbstractFileEngine(QAbstractFileEnginePrivate &);
+
+ QScopedPointer<QAbstractFileEnginePrivate> d_ptr;
+private:
+ Q_DECLARE_PRIVATE(QAbstractFileEngine)
+ Q_DISABLE_COPY(QAbstractFileEngine)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFileEngine::FileFlags)
+
+class Q_CORE_EXPORT QAbstractFileEngineHandler
+{
+public:
+ QAbstractFileEngineHandler();
+ virtual ~QAbstractFileEngineHandler();
+ virtual QAbstractFileEngine *create(const QString &fileName) const = 0;
+};
+
+class QAbstractFileEngineIteratorPrivate;
+class Q_CORE_EXPORT QAbstractFileEngineIterator
+{
+public:
+ QAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters);
+ virtual ~QAbstractFileEngineIterator();
+
+ virtual QString next() = 0;
+ virtual bool hasNext() const = 0;
+
+ QString path() const;
+ QStringList nameFilters() const;
+ QDir::Filters filters() const;
+
+ virtual QString currentFileName() const = 0;
+ virtual QFileInfo currentFileInfo() const;
+ QString currentFilePath() const;
+
+protected:
+ enum EntryInfoType {
+ };
+ virtual QVariant entryInfo(EntryInfoType type) const;
+
+private:
+ Q_DISABLE_COPY(QAbstractFileEngineIterator)
+ friend class QDirIterator;
+ friend class QDirIteratorPrivate;
+ void setPath(const QString &path);
+ QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTFILEENGINE_H
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
new file mode 100644
index 0000000000..d64eaa56c0
--- /dev/null
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTFILEENGINE_P_H
+#define QABSTRACTFILEENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qabstractfileengine.h"
+#include "QtCore/qfile.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractFileEnginePrivate
+{
+public:
+ inline QAbstractFileEnginePrivate()
+ : fileError(QFile::UnspecifiedError)
+ {
+ }
+ inline virtual ~QAbstractFileEnginePrivate() { }
+
+ QFile::FileError fileError;
+ QString errorString;
+
+ QAbstractFileEngine *q_ptr;
+ Q_DECLARE_PUBLIC(QAbstractFileEngine)
+};
+
+QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path);
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTFILEENGINE_P_H
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
new file mode 100644
index 0000000000..c5c21659b9
--- /dev/null
+++ b/src/corelib/io/qbuffer.cpp
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbuffer.h"
+#include "private/qiodevice_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/** QBufferPrivate **/
+class QBufferPrivate : public QIODevicePrivate
+{
+ Q_DECLARE_PUBLIC(QBuffer)
+
+public:
+ QBufferPrivate()
+ : buf(0)
+#ifndef QT_NO_QOBJECT
+ , writtenSinceLastEmit(0), signalConnectionCount(0), signalsEmitted(false)
+#endif
+ { }
+ ~QBufferPrivate() { }
+
+ QByteArray *buf;
+ QByteArray defaultBuf;
+ int ioIndex;
+
+ virtual qint64 peek(char *data, qint64 maxSize);
+ virtual QByteArray peek(qint64 maxSize);
+
+#ifndef QT_NO_QOBJECT
+ // private slots
+ void _q_emitSignals();
+
+ qint64 writtenSinceLastEmit;
+ int signalConnectionCount;
+ bool signalsEmitted;
+#endif
+};
+
+#ifndef QT_NO_QOBJECT
+void QBufferPrivate::_q_emitSignals()
+{
+ Q_Q(QBuffer);
+ emit q->bytesWritten(writtenSinceLastEmit);
+ writtenSinceLastEmit = 0;
+ emit q->readyRead();
+ signalsEmitted = false;
+}
+#endif
+
+qint64 QBufferPrivate::peek(char *data, qint64 maxSize)
+{
+ qint64 readBytes = qMin(maxSize, static_cast<qint64>(buf->size()) - pos);
+ memcpy(data, buf->constData() + pos, readBytes);
+ return readBytes;
+}
+
+QByteArray QBufferPrivate::peek(qint64 maxSize)
+{
+ qint64 readBytes = qMin(maxSize, static_cast<qint64>(buf->size()) - pos);
+ if (pos == 0 && maxSize >= buf->size())
+ return *buf;
+ return QByteArray(buf->constData() + pos, readBytes);
+}
+
+/*!
+ \class QBuffer
+ \reentrant
+ \brief The QBuffer class provides a QIODevice interface for a QByteArray.
+
+ \ingroup io
+
+ QBuffer allows you to access a QByteArray using the QIODevice
+ interface. The QByteArray is treated just as a standard random-accessed
+ file. Example:
+
+ \snippet doc/src/snippets/buffer/buffer.cpp 0
+
+ By default, an internal QByteArray buffer is created for you when
+ you create a QBuffer. You can access this buffer directly by
+ calling buffer(). You can also use QBuffer with an existing
+ QByteArray by calling setBuffer(), or by passing your array to
+ QBuffer's constructor.
+
+ Call open() to open the buffer. Then call write() or
+ putChar() to write to the buffer, and read(), readLine(),
+ readAll(), or getChar() to read from it. size() returns the
+ current size of the buffer, and you can seek to arbitrary
+ positions in the buffer by calling seek(). When you are done with
+ accessing the buffer, call close().
+
+ The following code snippet shows how to write data to a
+ QByteArray using QDataStream and QBuffer:
+
+ \snippet doc/src/snippets/buffer/buffer.cpp 1
+
+ Effectively, we convert the application's QPalette into a byte
+ array. Here's how to read the data from the QByteArray:
+
+ \snippet doc/src/snippets/buffer/buffer.cpp 2
+
+ QTextStream and QDataStream also provide convenience constructors
+ that take a QByteArray and that create a QBuffer behind the
+ scenes.
+
+ QBuffer emits readyRead() when new data has arrived in the
+ buffer. By connecting to this signal, you can use QBuffer to
+ store temporary data before processing it. For example, you can
+ pass the buffer to QFtp when downloading a file from an FTP
+ server. Whenever a new payload of data has been downloaded,
+ readyRead() is emitted, and you can process the data that just
+ arrived. QBuffer also emits bytesWritten() every time new data
+ has been written to the buffer.
+
+ \sa QFile, QDataStream, QTextStream, QByteArray
+*/
+
+#ifdef QT_NO_QOBJECT
+QBuffer::QBuffer()
+ : QIODevice(*new QBufferPrivate)
+{
+ Q_D(QBuffer);
+ d->buf = &d->defaultBuf;
+ d->ioIndex = 0;
+}
+QBuffer::QBuffer(QByteArray *buf)
+ : QIODevice(*new QBufferPrivate)
+{
+ Q_D(QBuffer);
+ d->buf = buf ? buf : &d->defaultBuf;
+ d->ioIndex = 0;
+ d->defaultBuf.clear();
+}
+#else
+/*!
+ Constructs an empty buffer with the given \a parent. You can call
+ setData() to fill the buffer with data, or you can open it in
+ write mode and use write().
+
+ \sa open()
+*/
+QBuffer::QBuffer(QObject *parent)
+ : QIODevice(*new QBufferPrivate, parent)
+{
+ Q_D(QBuffer);
+ d->buf = &d->defaultBuf;
+ d->ioIndex = 0;
+}
+
+/*!
+ Constructs a QBuffer that uses the QByteArray pointed to by \a
+ byteArray as its internal buffer, and with the given \a parent.
+ The caller is responsible for ensuring that \a byteArray remains
+ valid until the QBuffer is destroyed, or until setBuffer() is
+ called to change the buffer. QBuffer doesn't take ownership of
+ the QByteArray.
+
+ If you open the buffer in write-only mode or read-write mode and
+ write something into the QBuffer, \a byteArray will be modified.
+
+ Example:
+
+ \snippet doc/src/snippets/buffer/buffer.cpp 3
+
+ \sa open(), setBuffer(), setData()
+*/
+QBuffer::QBuffer(QByteArray *byteArray, QObject *parent)
+ : QIODevice(*new QBufferPrivate, parent)
+{
+ Q_D(QBuffer);
+ d->buf = byteArray ? byteArray : &d->defaultBuf;
+ d->defaultBuf.clear();
+ d->ioIndex = 0;
+}
+#endif
+
+/*!
+ Destroys the buffer.
+*/
+
+QBuffer::~QBuffer()
+{
+}
+
+/*!
+ Makes QBuffer uses the QByteArray pointed to by \a
+ byteArray as its internal buffer. The caller is responsible for
+ ensuring that \a byteArray remains valid until the QBuffer is
+ destroyed, or until setBuffer() is called to change the buffer.
+ QBuffer doesn't take ownership of the QByteArray.
+
+ Does nothing if isOpen() is true.
+
+ If you open the buffer in write-only mode or read-write mode and
+ write something into the QBuffer, \a byteArray will be modified.
+
+ Example:
+
+ \snippet doc/src/snippets/buffer/buffer.cpp 4
+
+ If \a byteArray is 0, the buffer creates its own internal
+ QByteArray to work on. This byte array is initially empty.
+
+ \sa buffer(), setData(), open()
+*/
+
+void QBuffer::setBuffer(QByteArray *byteArray)
+{
+ Q_D(QBuffer);
+ if (isOpen()) {
+ qWarning("QBuffer::setBuffer: Buffer is open");
+ return;
+ }
+ if (byteArray) {
+ d->buf = byteArray;
+ } else {
+ d->buf = &d->defaultBuf;
+ }
+ d->defaultBuf.clear();
+ d->ioIndex = 0;
+}
+
+/*!
+ Returns a reference to the QBuffer's internal buffer. You can use
+ it to modify the QByteArray behind the QBuffer's back.
+
+ \sa setBuffer(), data()
+*/
+
+QByteArray &QBuffer::buffer()
+{
+ Q_D(QBuffer);
+ return *d->buf;
+}
+
+/*!
+ \overload
+
+ This is the same as data().
+*/
+
+const QByteArray &QBuffer::buffer() const
+{
+ Q_D(const QBuffer);
+ return *d->buf;
+}
+
+
+/*!
+ Returns the data contained in the buffer.
+
+ This is the same as buffer().
+
+ \sa setData(), setBuffer()
+*/
+
+const QByteArray &QBuffer::data() const
+{
+ Q_D(const QBuffer);
+ return *d->buf;
+}
+
+/*!
+ Sets the contents of the internal buffer to be \a data. This is
+ the same as assigning \a data to buffer().
+
+ Does nothing if isOpen() is true.
+
+ \sa setBuffer()
+*/
+void QBuffer::setData(const QByteArray &data)
+{
+ Q_D(QBuffer);
+ if (isOpen()) {
+ qWarning("QBuffer::setData: Buffer is open");
+ return;
+ }
+ *d->buf = data;
+ d->ioIndex = 0;
+}
+
+/*!
+ \fn void QBuffer::setData(const char *data, int size)
+
+ \overload
+
+ Sets the contents of the internal buffer to be the first \a size
+ bytes of \a data.
+*/
+
+/*!
+ \reimp
+*/
+bool QBuffer::open(OpenMode flags)
+{
+ Q_D(QBuffer);
+
+ if ((flags & Append) == Append)
+ flags |= WriteOnly;
+ setOpenMode(flags);
+ if (!(isReadable() || isWritable())) {
+ qWarning("QFile::open: File access not specified");
+ return false;
+ }
+
+ if ((flags & QIODevice::Truncate) == QIODevice::Truncate) {
+ d->buf->resize(0);
+ }
+ if ((flags & QIODevice::Append) == QIODevice::Append) // append to end of buffer
+ seek(d->buf->size());
+ else
+ seek(0);
+
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QBuffer::close()
+{
+ QIODevice::close();
+}
+
+/*!
+ \reimp
+*/
+qint64 QBuffer::pos() const
+{
+ return QIODevice::pos();
+}
+
+/*!
+ \reimp
+*/
+qint64 QBuffer::size() const
+{
+ Q_D(const QBuffer);
+ return qint64(d->buf->size());
+}
+
+/*!
+ \reimp
+*/
+bool QBuffer::seek(qint64 pos)
+{
+ Q_D(QBuffer);
+ if (pos > d->buf->size() && isWritable()) {
+ if (seek(d->buf->size())) {
+ const qint64 gapSize = pos - d->buf->size();
+ if (write(QByteArray(gapSize, 0)) != gapSize) {
+ qWarning("QBuffer::seek: Unable to fill gap");
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else if (pos > d->buf->size() || pos < 0) {
+ qWarning("QBuffer::seek: Invalid pos: %d", int(pos));
+ return false;
+ }
+ d->ioIndex = int(pos);
+ return QIODevice::seek(pos);
+}
+
+/*!
+ \reimp
+*/
+bool QBuffer::atEnd() const
+{
+ return QIODevice::atEnd();
+}
+
+/*!
+ \reimp
+*/
+bool QBuffer::canReadLine() const
+{
+ Q_D(const QBuffer);
+ if (!isOpen())
+ return false;
+
+ return d->buf->indexOf('\n', int(pos())) != -1 || QIODevice::canReadLine();
+}
+
+/*!
+ \reimp
+*/
+qint64 QBuffer::readData(char *data, qint64 len)
+{
+ Q_D(QBuffer);
+ if ((len = qMin(len, qint64(d->buf->size()) - d->ioIndex)) <= 0)
+ return qint64(0);
+ memcpy(data, d->buf->constData() + d->ioIndex, len);
+ d->ioIndex += int(len);
+ return len;
+}
+
+/*!
+ \reimp
+*/
+qint64 QBuffer::writeData(const char *data, qint64 len)
+{
+ Q_D(QBuffer);
+ int extraBytes = d->ioIndex + len - d->buf->size();
+ if (extraBytes > 0) { // overflow
+ int newSize = d->buf->size() + extraBytes;
+ d->buf->resize(newSize);
+ if (d->buf->size() != newSize) { // could not resize
+ qWarning("QBuffer::writeData: Memory allocation error");
+ return -1;
+ }
+ }
+
+ memcpy(d->buf->data() + d->ioIndex, (uchar *)data, int(len));
+ d->ioIndex += int(len);
+
+#ifndef QT_NO_QOBJECT
+ d->writtenSinceLastEmit += len;
+ if (d->signalConnectionCount && !d->signalsEmitted && !signalsBlocked()) {
+ d->signalsEmitted = true;
+ QMetaObject::invokeMethod(this, "_q_emitSignals", Qt::QueuedConnection);
+ }
+#endif
+ return len;
+}
+
+#ifndef QT_NO_QOBJECT
+/*!
+ \reimp
+ \internal
+*/
+void QBuffer::connectNotify(const char *signal)
+{
+ if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0)
+ d_func()->signalConnectionCount++;
+}
+
+/*!
+ \reimp
+ \internal
+*/
+void QBuffer::disconnectNotify(const char *signal)
+{
+ if (!signal || strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0)
+ d_func()->signalConnectionCount--;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#ifndef QT_NO_QOBJECT
+# include "moc_qbuffer.cpp"
+#endif
+
diff --git a/src/corelib/io/qbuffer.h b/src/corelib/io/qbuffer.h
new file mode 100644
index 0000000000..a6cb87bc3f
--- /dev/null
+++ b/src/corelib/io/qbuffer.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBUFFER_H
+#define QBUFFER_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QObject;
+class QBufferPrivate;
+
+class Q_CORE_EXPORT QBuffer : public QIODevice
+{
+#ifndef QT_NO_QOBJECT
+ Q_OBJECT
+#endif
+
+public:
+#ifndef QT_NO_QOBJECT
+ explicit QBuffer(QObject *parent = 0);
+ QBuffer(QByteArray *buf, QObject *parent = 0);
+#else
+ QBuffer();
+ explicit QBuffer(QByteArray *buf);
+#endif
+ ~QBuffer();
+
+ QByteArray &buffer();
+ const QByteArray &buffer() const;
+ void setBuffer(QByteArray *a);
+
+ void setData(const QByteArray &data);
+ inline void setData(const char *data, int len);
+ const QByteArray &data() const;
+
+ bool open(OpenMode openMode);
+
+ void close();
+ qint64 size() const;
+ qint64 pos() const;
+ bool seek(qint64 off);
+ bool atEnd() const;
+ bool canReadLine() const;
+
+protected:
+#ifndef QT_NO_QOBJECT
+ void connectNotify(const char*);
+ void disconnectNotify(const char*);
+#endif
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+private:
+ Q_DECLARE_PRIVATE(QBuffer)
+ Q_DISABLE_COPY(QBuffer)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_emitSignals())
+};
+
+inline void QBuffer::setData(const char *adata, int alen)
+{ setData(QByteArray(adata, alen)); }
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBUFFER_H
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
new file mode 100644
index 0000000000..0361d180b2
--- /dev/null
+++ b/src/corelib/io/qdatastream.cpp
@@ -0,0 +1,1325 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdatastream.h"
+#include "qdatastream_p.h"
+
+#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#include "qbuffer.h"
+#include "qstring.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "qendian.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDataStream
+ \reentrant
+ \brief The QDataStream class provides serialization of binary data
+ to a QIODevice.
+
+ \ingroup io
+
+
+ A data stream is a binary stream of encoded information which is
+ 100% independent of the host computer's operating system, CPU or
+ byte order. For example, a data stream that is written by a PC
+ under Windows can be read by a Sun SPARC running Solaris.
+
+ You can also use a data stream to read/write \l{raw}{raw
+ unencoded binary data}. If you want a "parsing" input stream, see
+ QTextStream.
+
+ The QDataStream class implements the serialization of C++'s basic
+ data types, like \c char, \c short, \c int, \c{char *}, etc.
+ Serialization of more complex data is accomplished by breaking up
+ the data into primitive units.
+
+ A data stream cooperates closely with a QIODevice. A QIODevice
+ represents an input/output medium one can read data from and write
+ data to. The QFile class is an example of an I/O device.
+
+ Example (write binary data to a stream):
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 0
+
+ Example (read binary data from a stream):
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 1
+
+ Each item written to the stream is written in a predefined binary
+ format that varies depending on the item's type. Supported Qt
+ types include QBrush, QColor, QDateTime, QFont, QPixmap, QString,
+ QVariant and many others. For the complete list of all Qt types
+ supporting data streaming see \l{Serializing Qt Data Types}.
+
+ For integers it is best to always cast to a Qt integer type for
+ writing, and to read back into the same Qt integer type. This
+ ensures that you get integers of the size you want and insulates
+ you from compiler and platform differences.
+
+ To take one example, a \c{char *} string is written as a 32-bit
+ integer equal to the length of the string including the '\\0' byte,
+ followed by all the characters of the string including the
+ '\\0' byte. When reading a \c{char *} string, 4 bytes are read to
+ create the 32-bit length value, then that many characters for the
+ \c {char *} string including the '\\0' terminator are read.
+
+ The initial I/O device is usually set in the constructor, but can be
+ changed with setDevice(). If you've reached the end of the data
+ (or if there is no I/O device set) atEnd() will return true.
+
+ \section1 Versioning
+
+ QDataStream's binary format has evolved since Qt 1.0, and is
+ likely to continue evolving to reflect changes done in Qt. When
+ inputting or outputting complex types, it's very important to
+ make sure that the same version of the stream (version()) is used
+ for reading and writing. If you need both forward and backward
+ compatibility, you can hardcode the version number in the
+ application:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 2
+
+ If you are producing a new binary data format, such as a file
+ format for documents created by your application, you could use a
+ QDataStream to write the data in a portable format. Typically, you
+ would write a brief header containing a magic string and a version
+ number to give yourself room for future expansion. For example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 3
+
+ Then read it in with:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 4
+
+ You can select which byte order to use when serializing data. The
+ default setting is big endian (MSB first). Changing it to little
+ endian breaks the portability (unless the reader also changes to
+ little endian). We recommend keeping this setting unless you have
+ special requirements.
+
+ \target raw
+ \section1 Reading and writing raw binary data
+
+ You may wish to read/write your own raw binary data to/from the
+ data stream directly. Data may be read from the stream into a
+ preallocated \c{char *} using readRawData(). Similarly data can be
+ written to the stream using writeRawData(). Note that any
+ encoding/decoding of the data must be done by you.
+
+ A similar pair of functions is readBytes() and writeBytes(). These
+ differ from their \e raw counterparts as follows: readBytes()
+ reads a quint32 which is taken to be the length of the data to be
+ read, then that number of bytes is read into the preallocated
+ \c{char *}; writeBytes() writes a quint32 containing the length of the
+ data, followed by the data. Note that any encoding/decoding of
+ the data (apart from the length quint32) must be done by you.
+
+ \section1 Reading and writing Qt collection classes
+
+ The Qt container classes can also be serialized to a QDataStream.
+ These include QList, QLinkedList, QVector, QSet, QHash, and QMap.
+ The stream operators are declared as non-members of the classes.
+
+ \target Serializing Qt Classes
+ \section1 Reading and writing other Qt classes.
+
+ In addition to the overloaded stream operators documented here,
+ any Qt classes that you might want to serialize to a QDataStream
+ will have appropriate stream operators declared as non-member of
+ the class:
+
+ \code
+ QDataStream &operator<<(QDataStream &, const QXxx &);
+ QDataStream &operator>>(QDataStream &, QXxx &);
+ \endcode
+
+ For example, here are the stream operators declared as non-members
+ of the QImage class:
+
+ \code
+ QDataStream & operator<< (QDataStream& stream, const QImage& image);
+ QDataStream & operator>> (QDataStream& stream, QImage& image);
+ \endcode
+
+ To see if your favorite Qt class has similar stream operators
+ defined, check the \bold {Related Non-Members} section of the
+ class's documentation page.
+
+ \sa QTextStream QVariant
+*/
+
+/*!
+ \enum QDataStream::ByteOrder
+
+ The byte order used for reading/writing the data.
+
+ \value BigEndian Most significant byte first (the default)
+ \value LittleEndian Least significant byte first
+*/
+
+/*!
+ \enum QDataStream::FloatingPointPrecision
+
+ The precision of floating point numbers used for reading/writing the data. This will only have
+ an effect if the version of the data stream is Qt_4_6 or higher.
+
+ \warning The floating point precision must be set to the same value on the object that writes
+ and the object that reads the data stream.
+
+ \value SinglePrecision All floating point numbers in the data stream have 32-bit precision.
+ \value DoublePrecision All floating point numbers in the data stream have 64-bit precision.
+
+ \sa setFloatingPointPrecision(), floatingPointPrecision()
+*/
+
+/*!
+ \enum QDataStream::Status
+
+ This enum describes the current status of the data stream.
+
+ \value Ok The data stream is operating normally.
+ \value ReadPastEnd The data stream has read past the end of the
+ data in the underlying device.
+ \value ReadCorruptData The data stream has read corrupt data.
+ \value WriteFailed The data stream cannot write to the underlying device.
+*/
+
+/*****************************************************************************
+ QDataStream member functions
+ *****************************************************************************/
+
+#undef CHECK_STREAM_PRECOND
+#ifndef QT_NO_DEBUG
+#define CHECK_STREAM_PRECOND(retVal) \
+ if (!dev) { \
+ qWarning("QDataStream: No device"); \
+ return retVal; \
+ }
+#else
+#define CHECK_STREAM_PRECOND(retVal) \
+ if (!dev) { \
+ return retVal; \
+ }
+#endif
+
+#define CHECK_STREAM_WRITE_PRECOND(retVal) \
+ CHECK_STREAM_PRECOND(retVal) \
+ if (q_status != Ok) \
+ return retVal;
+
+enum {
+ DefaultStreamVersion = QDataStream::Qt_4_6
+};
+
+// ### 5.0: when streaming invalid QVariants, just the type should
+// be written, no "data" after it
+
+/*!
+ Constructs a data stream that has no I/O device.
+
+ \sa setDevice()
+*/
+
+QDataStream::QDataStream()
+{
+ dev = 0;
+ owndev = false;
+ byteorder = BigEndian;
+ ver = DefaultStreamVersion;
+ noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ q_status = Ok;
+}
+
+/*!
+ Constructs a data stream that uses the I/O device \a d.
+
+ \warning If you use QSocket or QSocketDevice as the I/O device \a d
+ for reading data, you must make sure that enough data is available
+ on the socket for the operation to successfully proceed;
+ QDataStream does not have any means to handle or recover from
+ short-reads.
+
+ \sa setDevice(), device()
+*/
+
+QDataStream::QDataStream(QIODevice *d)
+{
+ dev = d; // set device
+ owndev = false;
+ byteorder = BigEndian; // default byte order
+ ver = DefaultStreamVersion;
+ noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ q_status = Ok;
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QDataStream::QDataStream(QByteArray *array, int mode)
+ \compat
+
+ Constructs a data stream that operates on the given \a array. The
+ \a mode specifies how the byte array is to be used, and is
+ usually either QIODevice::ReadOnly or QIODevice::WriteOnly.
+*/
+QDataStream::QDataStream(QByteArray *a, int mode)
+{
+ QBuffer *buf = new QBuffer(a);
+#ifndef QT_NO_QOBJECT
+ buf->blockSignals(true);
+#endif
+ buf->open(QIODevice::OpenMode(mode));
+ dev = buf;
+ owndev = true;
+ byteorder = BigEndian;
+ ver = DefaultStreamVersion;
+ noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ q_status = Ok;
+}
+#endif
+
+/*!
+ \fn QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode mode)
+
+ Constructs a data stream that operates on a byte array, \a a. The
+ \a mode describes how the device is to be used.
+
+ Alternatively, you can use QDataStream(const QByteArray &) if you
+ just want to read from a byte array.
+
+ Since QByteArray is not a QIODevice subclass, internally a QBuffer
+ is created to wrap the byte array.
+*/
+
+QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode flags)
+{
+ QBuffer *buf = new QBuffer(a);
+#ifndef QT_NO_QOBJECT
+ buf->blockSignals(true);
+#endif
+ buf->open(flags);
+ dev = buf;
+ owndev = true;
+ byteorder = BigEndian;
+ ver = DefaultStreamVersion;
+ noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ q_status = Ok;
+}
+
+/*!
+ Constructs a read-only data stream that operates on byte array \a a.
+ Use QDataStream(QByteArray*, int) if you want to write to a byte
+ array.
+
+ Since QByteArray is not a QIODevice subclass, internally a QBuffer
+ is created to wrap the byte array.
+*/
+QDataStream::QDataStream(const QByteArray &a)
+{
+ QBuffer *buf = new QBuffer;
+#ifndef QT_NO_QOBJECT
+ buf->blockSignals(true);
+#endif
+ buf->setData(a);
+ buf->open(QIODevice::ReadOnly);
+ dev = buf;
+ owndev = true;
+ byteorder = BigEndian;
+ ver = DefaultStreamVersion;
+ noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ q_status = Ok;
+}
+
+/*!
+ Destroys the data stream.
+
+ The destructor will not affect the current I/O device, unless it is
+ an internal I/O device (e.g. a QBuffer) processing a QByteArray
+ passed in the \e constructor, in which case the internal I/O device
+ is destroyed.
+*/
+
+QDataStream::~QDataStream()
+{
+ if (owndev)
+ delete dev;
+}
+
+
+/*!
+ \fn QIODevice *QDataStream::device() const
+
+ Returns the I/O device currently set, or 0 if no
+ device is currently set.
+
+ \sa setDevice()
+*/
+
+/*!
+ void QDataStream::setDevice(QIODevice *d)
+
+ Sets the I/O device to \a d, which can be 0
+ to unset to current I/O device.
+
+ \sa device()
+*/
+
+void QDataStream::setDevice(QIODevice *d)
+{
+ if (owndev) {
+ delete dev;
+ owndev = false;
+ }
+ dev = d;
+}
+
+/*!
+ \obsolete
+ Unsets the I/O device.
+ Use setDevice(0) instead.
+*/
+
+void QDataStream::unsetDevice()
+{
+ setDevice(0);
+}
+
+
+/*!
+ \fn bool QDataStream::atEnd() const
+
+ Returns true if the I/O device has reached the end position (end of
+ the stream or file) or if there is no I/O device set; otherwise
+ returns false.
+
+ \sa QIODevice::atEnd()
+*/
+
+bool QDataStream::atEnd() const
+{
+ return dev ? dev->atEnd() : true;
+}
+
+/*!
+ Returns the floating point precision of the data stream.
+
+ \since 4.6
+
+ \sa FloatingPointPrecision setFloatingPointPrecision()
+*/
+QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+{
+ return d == 0 ? QDataStream::DoublePrecision : d->floatingPointPrecision;
+}
+
+/*!
+ Sets the floating point precision of the data stream to \a precision. If the floating point precision is
+ DoublePrecision and the version of the data stream is Qt_4_6 or higher, all floating point
+ numbers will be written and read with 64-bit precision. If the floating point precision is
+ SinglePrecision and the version is Qt_4_6 or higher, all floating point numbers will be written
+ and read with 32-bit precision.
+
+ For versions prior to Qt_4_6, the precision of floating point numbers in the data stream depends
+ on the stream operator called.
+
+ The default is DoublePrecision.
+
+ \warning This property must be set to the same value on the object that writes and the object
+ that reads the data stream.
+
+ \since 4.6
+*/
+void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision)
+{
+ if (d == 0)
+ d.reset(new QDataStreamPrivate());
+ d->floatingPointPrecision = precision;
+}
+
+/*!
+ Returns the status of the data stream.
+
+ \sa Status setStatus() resetStatus()
+*/
+
+QDataStream::Status QDataStream::status() const
+{
+ return q_status;
+}
+
+/*!
+ Resets the status of the data stream.
+
+ \sa Status status() setStatus()
+*/
+void QDataStream::resetStatus()
+{
+ q_status = Ok;
+}
+
+/*!
+ Sets the status of the data stream to the \a status given.
+
+ Subsequent calls to setStatus() are ignored until resetStatus()
+ is called.
+
+ \sa Status status() resetStatus()
+*/
+void QDataStream::setStatus(Status status)
+{
+ if (q_status == Ok)
+ q_status = status;
+}
+
+/*!\fn bool QDataStream::eof() const
+
+ Use atEnd() instead.
+*/
+
+/*!
+ \fn int QDataStream::byteOrder() const
+
+ Returns the current byte order setting -- either BigEndian or
+ LittleEndian.
+
+ \sa setByteOrder()
+*/
+
+/*!
+ Sets the serialization byte order to \a bo.
+
+ The \a bo parameter can be QDataStream::BigEndian or
+ QDataStream::LittleEndian.
+
+ The default setting is big endian. We recommend leaving this
+ setting unless you have special requirements.
+
+ \sa byteOrder()
+*/
+
+void QDataStream::setByteOrder(ByteOrder bo)
+{
+ byteorder = bo;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ noswap = (byteorder == BigEndian);
+ else
+ noswap = (byteorder == LittleEndian);
+}
+
+
+/*!
+ \fn bool QDataStream::isPrintableData() const
+
+ In Qt 4, this function always returns false.
+
+ \sa setPrintableData()
+*/
+
+/*!
+ \fn void QDataStream::setPrintableData(bool enable)
+
+ In Qt 3, this function enabled output in a human-readable
+ format if \a enable was false.
+
+ In Qt 4, QDataStream no longer provides a human-readable output.
+ This function does nothing.
+*/
+
+/*!
+ \enum QDataStream::Version
+
+ This enum provides symbolic synonyms for the data serialization
+ format version numbers.
+
+ \value Qt_1_0 Version 1 (Qt 1.x)
+ \value Qt_2_0 Version 2 (Qt 2.0)
+ \value Qt_2_1 Version 3 (Qt 2.1, 2.2, 2.3)
+ \value Qt_3_0 Version 4 (Qt 3.0)
+ \value Qt_3_1 Version 5 (Qt 3.1, 3.2)
+ \value Qt_3_3 Version 6 (Qt 3.3)
+ \value Qt_4_0 Version 7 (Qt 4.0, Qt 4.1)
+ \value Qt_4_1 Version 7 (Qt 4.0, Qt 4.1)
+ \value Qt_4_2 Version 8 (Qt 4.2)
+ \value Qt_4_3 Version 9 (Qt 4.3)
+ \value Qt_4_4 Version 10 (Qt 4.4)
+ \value Qt_4_5 Version 11 (Qt 4.5)
+ \value Qt_4_6 Version 12 (Qt 4.6)
+ \value Qt_4_7 Same as Qt_4_6.
+
+ \sa setVersion(), version()
+*/
+
+/*!
+ \fn int QDataStream::version() const
+
+ Returns the version number of the data serialization format.
+
+ \sa setVersion(), Version
+*/
+
+/*!
+ \fn void QDataStream::setVersion(int v)
+
+ Sets the version number of the data serialization format to \a v.
+
+ You don't \e have to set a version if you are using the current
+ version of Qt, but for your own custom binary formats we
+ recommend that you do; see \l{Versioning} in the Detailed
+ Description.
+
+ To accommodate new functionality, the datastream serialization
+ format of some Qt classes has changed in some versions of Qt. If
+ you want to read data that was created by an earlier version of
+ Qt, or write data that can be read by a program that was compiled
+ with an earlier version of Qt, use this function to modify the
+ serialization format used by QDataStream.
+
+ \table
+ \header \i Qt Version \i QDataStream Version
+ \row \i Qt 4.6 \i 12
+ \row \i Qt 4.5 \i 11
+ \row \i Qt 4.4 \i 10
+ \row \i Qt 4.3 \i 9
+ \row \i Qt 4.2 \i 8
+ \row \i Qt 4.0, 4.1 \i 7
+ \row \i Qt 3.3 \i 6
+ \row \i Qt 3.1, 3.2 \i 5
+ \row \i Qt 3.0 \i 4
+ \row \i Qt 2.1, 2.2, 2.3 \i 3
+ \row \i Qt 2.0 \i 2
+ \row \i Qt 1.x \i 1
+ \endtable
+
+ The \l Version enum provides symbolic constants for the different
+ versions of Qt. For example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdatastream.cpp 5
+
+ \sa version(), Version
+*/
+
+/*****************************************************************************
+ QDataStream read functions
+ *****************************************************************************/
+
+/*!
+ \fn QDataStream &QDataStream::operator>>(quint8 &i)
+ \overload
+
+ Reads an unsigned byte from the stream into \a i, and returns a
+ reference to the stream.
+*/
+
+/*!
+ Reads a signed byte from the stream into \a i, and returns a
+ reference to the stream.
+*/
+
+QDataStream &QDataStream::operator>>(qint8 &i)
+{
+ i = 0;
+ CHECK_STREAM_PRECOND(*this)
+ char c;
+ if (!dev->getChar(&c))
+ setStatus(ReadPastEnd);
+ else
+ i = qint8(c);
+ return *this;
+}
+
+
+/*!
+ \fn QDataStream &QDataStream::operator>>(quint16 &i)
+ \overload
+
+ Reads an unsigned 16-bit integer from the stream into \a i, and
+ returns a reference to the stream.
+*/
+
+/*!
+ \overload
+
+ Reads a signed 16-bit integer from the stream into \a i, and
+ returns a reference to the stream.
+*/
+
+QDataStream &QDataStream::operator>>(qint16 &i)
+{
+ i = 0;
+ CHECK_STREAM_PRECOND(*this)
+ if (dev->read((char *)&i, 2) != 2) {
+ i = 0;
+ setStatus(ReadPastEnd);
+ } else {
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ }
+ return *this;
+}
+
+
+/*!
+ \fn QDataStream &QDataStream::operator>>(quint32 &i)
+ \overload
+
+ Reads an unsigned 32-bit integer from the stream into \a i, and
+ returns a reference to the stream.
+*/
+
+/*!
+ \overload
+
+ Reads a signed 32-bit integer from the stream into \a i, and
+ returns a reference to the stream.
+*/
+
+QDataStream &QDataStream::operator>>(qint32 &i)
+{
+ i = 0;
+ CHECK_STREAM_PRECOND(*this)
+ if (dev->read((char *)&i, 4) != 4) {
+ i = 0;
+ setStatus(ReadPastEnd);
+ } else {
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ }
+ return *this;
+}
+
+/*!
+ \fn QDataStream &QDataStream::operator>>(quint64 &i)
+ \overload
+
+ Reads an unsigned 64-bit integer from the stream, into \a i, and
+ returns a reference to the stream.
+*/
+
+/*!
+ \overload
+
+ Reads a signed 64-bit integer from the stream into \a i, and
+ returns a reference to the stream.
+*/
+
+QDataStream &QDataStream::operator>>(qint64 &i)
+{
+ i = qint64(0);
+ CHECK_STREAM_PRECOND(*this)
+ if (version() < 6) {
+ quint32 i1, i2;
+ *this >> i2 >> i1;
+ i = ((quint64)i1 << 32) + i2;
+ } else {
+ if (dev->read((char *)&i, 8) != 8) {
+ i = qint64(0);
+ setStatus(ReadPastEnd);
+ } else {
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ }
+ }
+ return *this;
+}
+
+/*!
+ Reads a boolean value from the stream into \a i. Returns a
+ reference to the stream.
+*/
+QDataStream &QDataStream::operator>>(bool &i)
+{
+ qint8 v;
+ *this >> v;
+ i = !!v;
+ return *this;
+}
+
+/*!
+ \overload
+
+ Reads a floating point number from the stream into \a f,
+ using the standard IEEE 754 format. Returns a reference to the
+ stream.
+
+ \sa setFloatingPointPrecision()
+*/
+
+QDataStream &QDataStream::operator>>(float &f)
+{
+ if (version() >= QDataStream::Qt_4_6
+ && floatingPointPrecision() == QDataStream::DoublePrecision) {
+ double d;
+ *this >> d;
+ f = d;
+ return *this;
+ }
+
+ f = 0.0f;
+ CHECK_STREAM_PRECOND(*this)
+ if (dev->read((char *)&f, 4) != 4) {
+ f = 0.0f;
+ setStatus(ReadPastEnd);
+ } else {
+ if (!noswap) {
+ union {
+ float val1;
+ quint32 val2;
+ } x;
+ x.val2 = qbswap(*reinterpret_cast<quint32 *>(&f));
+ f = x.val1;
+ }
+ }
+ return *this;
+}
+
+#if defined(Q_DOUBLE_FORMAT)
+#define Q_DF(x) Q_DOUBLE_FORMAT[(x)] - '0'
+#endif
+
+/*!
+ \overload
+
+ Reads a floating point number from the stream into \a f,
+ using the standard IEEE 754 format. Returns a reference to the
+ stream.
+
+ \sa setFloatingPointPrecision()
+*/
+
+QDataStream &QDataStream::operator>>(double &f)
+{
+ if (version() >= QDataStream::Qt_4_6
+ && floatingPointPrecision() == QDataStream::SinglePrecision) {
+ float d;
+ *this >> d;
+ f = d;
+ return *this;
+ }
+
+ f = 0.0;
+ CHECK_STREAM_PRECOND(*this)
+#ifndef Q_DOUBLE_FORMAT
+ if (dev->read((char *)&f, 8) != 8) {
+ f = 0.0;
+ setStatus(ReadPastEnd);
+ } else {
+ if (!noswap) {
+ union {
+ double val1;
+ quint64 val2;
+ } x;
+ x.val2 = qbswap(*reinterpret_cast<quint64 *>(&f));
+ f = x.val1;
+ }
+ }
+#else
+ //non-standard floating point format
+ union {
+ double val1;
+ char val2[8];
+ } x;
+ char *p = x.val2;
+ char b[8];
+ if (dev->read(b, 8) == 8) {
+ if (noswap) {
+ *p++ = b[Q_DF(0)];
+ *p++ = b[Q_DF(1)];
+ *p++ = b[Q_DF(2)];
+ *p++ = b[Q_DF(3)];
+ *p++ = b[Q_DF(4)];
+ *p++ = b[Q_DF(5)];
+ *p++ = b[Q_DF(6)];
+ *p = b[Q_DF(7)];
+ } else {
+ *p++ = b[Q_DF(7)];
+ *p++ = b[Q_DF(6)];
+ *p++ = b[Q_DF(5)];
+ *p++ = b[Q_DF(4)];
+ *p++ = b[Q_DF(3)];
+ *p++ = b[Q_DF(2)];
+ *p++ = b[Q_DF(1)];
+ *p = b[Q_DF(0)];
+ }
+ f = x.val1;
+ } else {
+ setStatus(ReadPastEnd);
+ }
+#endif
+ return *this;
+}
+
+
+/*!
+ \overload
+
+ Reads the '\0'-terminated string \a s from the stream and returns
+ a reference to the stream.
+
+ Space for the string is allocated using \c new -- the caller must
+ destroy it with \c{delete[]}.
+*/
+
+QDataStream &QDataStream::operator>>(char *&s)
+{
+ uint len = 0;
+ return readBytes(s, len);
+}
+
+
+/*!
+ Reads the buffer \a s from the stream and returns a reference to
+ the stream.
+
+ The buffer \a s is allocated using \c new. Destroy it with the \c
+ delete[] operator.
+
+ The \a l parameter is set to the length of the buffer. If the
+ string read is empty, \a l is set to 0 and \a s is set to
+ a null pointer.
+
+ The serialization format is a quint32 length specifier first,
+ then \a l bytes of data.
+
+ \sa readRawData(), writeBytes()
+*/
+
+QDataStream &QDataStream::readBytes(char *&s, uint &l)
+{
+ s = 0;
+ l = 0;
+ CHECK_STREAM_PRECOND(*this)
+
+ quint32 len;
+ *this >> len;
+ if (len == 0)
+ return *this;
+
+ const quint32 Step = 1024 * 1024;
+ quint32 allocated = 0;
+ char *prevBuf = 0;
+ char *curBuf = 0;
+
+ do {
+ int blockSize = qMin(Step, len - allocated);
+ prevBuf = curBuf;
+ curBuf = new char[allocated + blockSize + 1];
+ if (prevBuf) {
+ memcpy(curBuf, prevBuf, allocated);
+ delete [] prevBuf;
+ }
+ if (dev->read(curBuf + allocated, blockSize) != blockSize) {
+ delete [] curBuf;
+ setStatus(ReadPastEnd);
+ return *this;
+ }
+ allocated += blockSize;
+ } while (allocated < len);
+
+ s = curBuf;
+ s[len] = '\0';
+ l = (uint)len;
+ return *this;
+}
+
+/*!
+ Reads at most \a len bytes from the stream into \a s and returns the number of
+ bytes read. If an error occurs, this function returns -1.
+
+ The buffer \a s must be preallocated. The data is \e not encoded.
+
+ \sa readBytes(), QIODevice::read(), writeRawData()
+*/
+
+int QDataStream::readRawData(char *s, int len)
+{
+ CHECK_STREAM_PRECOND(-1)
+ return dev->read(s, len);
+}
+
+
+/*****************************************************************************
+ QDataStream write functions
+ *****************************************************************************/
+
+
+/*!
+ \fn QDataStream &QDataStream::operator<<(quint8 i)
+ \overload
+
+ Writes an unsigned byte, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ Writes a signed byte, \a i, to the stream and returns a reference
+ to the stream.
+*/
+
+QDataStream &QDataStream::operator<<(qint8 i)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ if (!dev->putChar(i))
+ q_status = WriteFailed;
+ return *this;
+}
+
+
+/*!
+ \fn QDataStream &QDataStream::operator<<(quint16 i)
+ \overload
+
+ Writes an unsigned 16-bit integer, \a i, to the stream and returns
+ a reference to the stream.
+*/
+
+/*!
+ \overload
+
+ Writes a signed 16-bit integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &QDataStream::operator<<(qint16 i)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ if (dev->write((char *)&i, sizeof(qint16)) != sizeof(qint16))
+ q_status = WriteFailed;
+ return *this;
+}
+
+/*!
+ \overload
+
+ Writes a signed 32-bit integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &QDataStream::operator<<(qint32 i)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ if (dev->write((char *)&i, sizeof(qint32)) != sizeof(qint32))
+ q_status = WriteFailed;
+ return *this;
+}
+
+/*!
+ \fn QDataStream &QDataStream::operator<<(quint64 i)
+ \overload
+
+ Writes an unsigned 64-bit integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \overload
+
+ Writes a signed 64-bit integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &QDataStream::operator<<(qint64 i)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ if (version() < 6) {
+ quint32 i1 = i & 0xffffffff;
+ quint32 i2 = i >> 32;
+ *this << i2 << i1;
+ } else {
+ if (!noswap) {
+ i = qbswap(i);
+ }
+ if (dev->write((char *)&i, sizeof(qint64)) != sizeof(qint64))
+ q_status = WriteFailed;
+ }
+ return *this;
+}
+
+/*!
+ \fn QDataStream &QDataStream::operator<<(quint32 i)
+ \overload
+
+ Writes an unsigned integer, \a i, to the stream as a 32-bit
+ unsigned integer (quint32). Returns a reference to the stream.
+*/
+
+/*!
+ Writes a boolean value, \a i, to the stream. Returns a reference
+ to the stream.
+*/
+
+QDataStream &QDataStream::operator<<(bool i)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ if (!dev->putChar(qint8(i)))
+ q_status = WriteFailed;
+ return *this;
+}
+
+/*!
+ \overload
+
+ Writes a floating point number, \a f, to the stream using
+ the standard IEEE 754 format. Returns a reference to the stream.
+
+ \sa setFloatingPointPrecision()
+*/
+
+QDataStream &QDataStream::operator<<(float f)
+{
+ if (version() >= QDataStream::Qt_4_6
+ && floatingPointPrecision() == QDataStream::DoublePrecision) {
+ *this << double(f);
+ return *this;
+ }
+
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ float g = f; // fixes float-on-stack problem
+ if (!noswap) {
+ union {
+ float val1;
+ quint32 val2;
+ } x;
+ x.val1 = g;
+ x.val2 = qbswap(x.val2);
+ g = x.val1;
+ }
+ if (dev->write((char *)&g, sizeof(float)) != sizeof(float))
+ q_status = WriteFailed;
+ return *this;
+}
+
+
+/*!
+ \overload
+
+ Writes a floating point number, \a f, to the stream using
+ the standard IEEE 754 format. Returns a reference to the stream.
+
+ \sa setFloatingPointPrecision()
+*/
+
+QDataStream &QDataStream::operator<<(double f)
+{
+ if (version() >= QDataStream::Qt_4_6
+ && floatingPointPrecision() == QDataStream::SinglePrecision) {
+ *this << float(f);
+ return *this;
+ }
+
+ CHECK_STREAM_WRITE_PRECOND(*this)
+#ifndef Q_DOUBLE_FORMAT
+ if (noswap) {
+ if (dev->write((char *)&f, sizeof(double)) != sizeof(double))
+ q_status = WriteFailed;
+ } else {
+ union {
+ double val1;
+ quint64 val2;
+ } x;
+ x.val1 = f;
+ x.val2 = qbswap(x.val2);
+ if (dev->write((char *)&x.val2, sizeof(double)) != sizeof(double))
+ q_status = WriteFailed;
+ }
+#else
+ union {
+ double val1;
+ char val2[8];
+ } x;
+ x.val1 = f;
+ char *p = x.val2;
+ char b[8];
+ if (noswap) {
+ b[Q_DF(0)] = *p++;
+ b[Q_DF(1)] = *p++;
+ b[Q_DF(2)] = *p++;
+ b[Q_DF(3)] = *p++;
+ b[Q_DF(4)] = *p++;
+ b[Q_DF(5)] = *p++;
+ b[Q_DF(6)] = *p++;
+ b[Q_DF(7)] = *p;
+ } else {
+ b[Q_DF(7)] = *p++;
+ b[Q_DF(6)] = *p++;
+ b[Q_DF(5)] = *p++;
+ b[Q_DF(4)] = *p++;
+ b[Q_DF(3)] = *p++;
+ b[Q_DF(2)] = *p++;
+ b[Q_DF(1)] = *p++;
+ b[Q_DF(0)] = *p;
+ }
+ if (dev->write(b, 8) != 8)
+ q_status = WriteFailed;
+#endif
+ return *this;
+}
+
+
+/*!
+ \overload
+
+ Writes the '\0'-terminated string \a s to the stream and returns a
+ reference to the stream.
+
+ The string is serialized using writeBytes().
+*/
+
+QDataStream &QDataStream::operator<<(const char *s)
+{
+ if (!s) {
+ *this << (quint32)0;
+ return *this;
+ }
+ uint len = qstrlen(s) + 1; // also write null terminator
+ *this << (quint32)len; // write length specifier
+ writeRawData(s, len);
+ return *this;
+}
+
+
+/*!
+ Writes the length specifier \a len and the buffer \a s to the
+ stream and returns a reference to the stream.
+
+ The \a len is serialized as a quint32, followed by \a len bytes
+ from \a s. Note that the data is \e not encoded.
+
+ \sa writeRawData(), readBytes()
+*/
+
+QDataStream &QDataStream::writeBytes(const char *s, uint len)
+{
+ CHECK_STREAM_WRITE_PRECOND(*this)
+ *this << (quint32)len; // write length specifier
+ if (len)
+ writeRawData(s, len);
+ return *this;
+}
+
+
+/*!
+ Writes \a len bytes from \a s to the stream. Returns the
+ number of bytes actually written, or -1 on error.
+ The data is \e not encoded.
+
+ \sa writeBytes(), QIODevice::write(), readRawData()
+*/
+
+int QDataStream::writeRawData(const char *s, int len)
+{
+ CHECK_STREAM_WRITE_PRECOND(-1)
+ int ret = dev->write(s, len);
+ if (ret != len)
+ q_status = WriteFailed;
+ return ret;
+}
+
+/*!
+ \since 4.1
+
+ Skips \a len bytes from the device. Returns the number of bytes
+ actually skipped, or -1 on error.
+
+ This is equivalent to calling readRawData() on a buffer of length
+ \a len and ignoring the buffer.
+
+ \sa QIODevice::seek()
+*/
+int QDataStream::skipRawData(int len)
+{
+ CHECK_STREAM_PRECOND(-1)
+
+ if (dev->isSequential()) {
+ char buf[4096];
+ int sumRead = 0;
+
+ while (len > 0) {
+ int blockSize = qMin(len, (int)sizeof(buf));
+ int n = dev->read(buf, blockSize);
+ if (n == -1)
+ return -1;
+ if (n == 0)
+ return sumRead;
+
+ sumRead += n;
+ len -= blockSize;
+ }
+ return sumRead;
+ } else {
+ qint64 pos = dev->pos();
+ qint64 size = dev->size();
+ if (pos + len > size)
+ len = size - pos;
+ if (!dev->seek(pos + len))
+ return -1;
+ return len;
+ }
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QDataStream &QDataStream::readRawBytes(char *str, uint len)
+
+ Use readRawData() instead.
+*/
+
+/*!
+ \fn QDataStream &QDataStream::writeRawBytes(const char *str, uint len)
+
+ Use writeRawData() instead.
+*/
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DATASTREAM
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
new file mode 100644
index 0000000000..d19fcc5377
--- /dev/null
+++ b/src/corelib/io/qdatastream.h
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATASTREAM_H
+#define QDATASTREAM_H
+
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+
+#ifdef Status
+#error qdatastream.h must be included before any header file that defines Status
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QByteArray;
+class QIODevice;
+
+template <typename T> class QList;
+template <typename T> class QLinkedList;
+template <typename T> class QVector;
+template <typename T> class QSet;
+template <class Key, class T> class QHash;
+template <class Key, class T> class QMap;
+
+#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+class QDataStreamPrivate;
+class Q_CORE_EXPORT QDataStream
+{
+public:
+ enum Version {
+ Qt_1_0 = 1,
+ Qt_2_0 = 2,
+ Qt_2_1 = 3,
+ Qt_3_0 = 4,
+ Qt_3_1 = 5,
+ Qt_3_3 = 6,
+ Qt_4_0 = 7,
+ Qt_4_1 = Qt_4_0,
+ Qt_4_2 = 8,
+ Qt_4_3 = 9,
+ Qt_4_4 = 10,
+ Qt_4_5 = 11,
+ Qt_4_6 = 12,
+ Qt_4_7 = Qt_4_6,
+ Qt_4_8 = Qt_4_7
+#if QT_VERSION >= 0x040900
+#error Add the datastream version for this Qt version
+ Qt_4_9 = Qt_4_8
+#endif
+ };
+
+ enum ByteOrder {
+ BigEndian = QSysInfo::BigEndian,
+ LittleEndian = QSysInfo::LittleEndian
+ };
+
+ enum Status {
+ Ok,
+ ReadPastEnd,
+ ReadCorruptData,
+ WriteFailed
+ };
+
+ enum FloatingPointPrecision {
+ SinglePrecision,
+ DoublePrecision
+ };
+
+ QDataStream();
+ explicit QDataStream(QIODevice *);
+#ifdef QT3_SUPPORT
+ QDataStream(QByteArray *, int mode);
+#endif
+ QDataStream(QByteArray *, QIODevice::OpenMode flags);
+ QDataStream(const QByteArray &);
+ virtual ~QDataStream();
+
+ QIODevice *device() const;
+ void setDevice(QIODevice *);
+ void unsetDevice();
+
+ bool atEnd() const;
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT bool eof() const { return atEnd(); }
+#endif
+
+ Status status() const;
+ void setStatus(Status status);
+ void resetStatus();
+
+ FloatingPointPrecision floatingPointPrecision() const;
+ void setFloatingPointPrecision(FloatingPointPrecision precision);
+
+ ByteOrder byteOrder() const;
+ void setByteOrder(ByteOrder);
+
+ int version() const;
+ void setVersion(int);
+
+ QDataStream &operator>>(qint8 &i);
+ QDataStream &operator>>(quint8 &i);
+ QDataStream &operator>>(qint16 &i);
+ QDataStream &operator>>(quint16 &i);
+ QDataStream &operator>>(qint32 &i);
+ QDataStream &operator>>(quint32 &i);
+ QDataStream &operator>>(qint64 &i);
+ QDataStream &operator>>(quint64 &i);
+
+ QDataStream &operator>>(bool &i);
+ QDataStream &operator>>(float &f);
+ QDataStream &operator>>(double &f);
+ QDataStream &operator>>(char *&str);
+
+ QDataStream &operator<<(qint8 i);
+ QDataStream &operator<<(quint8 i);
+ QDataStream &operator<<(qint16 i);
+ QDataStream &operator<<(quint16 i);
+ QDataStream &operator<<(qint32 i);
+ QDataStream &operator<<(quint32 i);
+ QDataStream &operator<<(qint64 i);
+ QDataStream &operator<<(quint64 i);
+ QDataStream &operator<<(bool i);
+ QDataStream &operator<<(float f);
+ QDataStream &operator<<(double f);
+ QDataStream &operator<<(const char *str);
+
+ QDataStream &readBytes(char *&, uint &len);
+ int readRawData(char *, int len);
+
+ QDataStream &writeBytes(const char *, uint len);
+ int writeRawData(const char *, int len);
+
+ int skipRawData(int len);
+
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT QDataStream &readRawBytes(char *str, uint len)
+ { readRawData(str, static_cast<int>(len)); return *this; }
+ inline QT3_SUPPORT QDataStream &writeRawBytes(const char *str, uint len)
+ { writeRawData(str, static_cast<int>(len)); return *this; }
+ inline QT3_SUPPORT bool isPrintableData() const { return false; }
+ inline QT3_SUPPORT void setPrintableData(bool) {}
+#endif
+
+private:
+ Q_DISABLE_COPY(QDataStream)
+
+ QScopedPointer<QDataStreamPrivate> d;
+
+ QIODevice *dev;
+ bool owndev;
+ bool noswap;
+ ByteOrder byteorder;
+ int ver;
+ Status q_status;
+};
+
+
+/*****************************************************************************
+ QDataStream inline functions
+ *****************************************************************************/
+
+inline QIODevice *QDataStream::device() const
+{ return dev; }
+
+inline QDataStream::ByteOrder QDataStream::byteOrder() const
+{ return byteorder; }
+
+inline int QDataStream::version() const
+{ return ver; }
+
+inline void QDataStream::setVersion(int v)
+{ ver = v; }
+
+inline QDataStream &QDataStream::operator>>(quint8 &i)
+{ return *this >> reinterpret_cast<qint8&>(i); }
+
+inline QDataStream &QDataStream::operator>>(quint16 &i)
+{ return *this >> reinterpret_cast<qint16&>(i); }
+
+inline QDataStream &QDataStream::operator>>(quint32 &i)
+{ return *this >> reinterpret_cast<qint32&>(i); }
+
+inline QDataStream &QDataStream::operator>>(quint64 &i)
+{ return *this >> reinterpret_cast<qint64&>(i); }
+
+inline QDataStream &QDataStream::operator<<(quint8 i)
+{ return *this << qint8(i); }
+
+inline QDataStream &QDataStream::operator<<(quint16 i)
+{ return *this << qint16(i); }
+
+inline QDataStream &QDataStream::operator<<(quint32 i)
+{ return *this << qint32(i); }
+
+inline QDataStream &QDataStream::operator<<(quint64 i)
+{ return *this << qint64(i); }
+
+template <typename T>
+QDataStream& operator>>(QDataStream& s, QList<T>& l)
+{
+ l.clear();
+ quint32 c;
+ s >> c;
+ l.reserve(c);
+ for(quint32 i = 0; i < c; ++i)
+ {
+ T t;
+ s >> t;
+ l.append(t);
+ if (s.atEnd())
+ break;
+ }
+ return s;
+}
+
+template <typename T>
+QDataStream& operator<<(QDataStream& s, const QList<T>& l)
+{
+ s << quint32(l.size());
+ for (int i = 0; i < l.size(); ++i)
+ s << l.at(i);
+ return s;
+}
+
+template <typename T>
+QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l)
+{
+ l.clear();
+ quint32 c;
+ s >> c;
+ for(quint32 i = 0; i < c; ++i)
+ {
+ T t;
+ s >> t;
+ l.append(t);
+ if (s.atEnd())
+ break;
+ }
+ return s;
+}
+
+template <typename T>
+QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l)
+{
+ s << quint32(l.size());
+ typename QLinkedList<T>::ConstIterator it = l.constBegin();
+ for(; it != l.constEnd(); ++it)
+ s << *it;
+ return s;
+}
+
+template<typename T>
+QDataStream& operator>>(QDataStream& s, QVector<T>& v)
+{
+ v.clear();
+ quint32 c;
+ s >> c;
+ v.resize(c);
+ for(quint32 i = 0; i < c; ++i) {
+ T t;
+ s >> t;
+ v[i] = t;
+ }
+ return s;
+}
+
+template<typename T>
+QDataStream& operator<<(QDataStream& s, const QVector<T>& v)
+{
+ s << quint32(v.size());
+ for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
+ s << *it;
+ return s;
+}
+
+template <typename T>
+QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+{
+ set.clear();
+ quint32 c;
+ in >> c;
+ for (quint32 i = 0; i < c; ++i) {
+ T t;
+ in >> t;
+ set << t;
+ if (in.atEnd())
+ break;
+ }
+ return in;
+}
+
+template <typename T>
+QDataStream& operator<<(QDataStream &out, const QSet<T> &set)
+{
+ out << quint32(set.size());
+ typename QSet<T>::const_iterator i = set.constBegin();
+ while (i != set.constEnd()) {
+ out << *i;
+ ++i;
+ }
+ return out;
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash)
+{
+ QDataStream::Status oldStatus = in.status();
+ in.resetStatus();
+ hash.clear();
+
+ quint32 n;
+ in >> n;
+
+ for (quint32 i = 0; i < n; ++i) {
+ if (in.status() != QDataStream::Ok)
+ break;
+
+ Key k;
+ T t;
+ in >> k >> t;
+ hash.insertMulti(k, t);
+ }
+
+ if (in.status() != QDataStream::Ok)
+ hash.clear();
+ if (oldStatus != QDataStream::Ok)
+ in.setStatus(oldStatus);
+ return in;
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
+{
+ out << quint32(hash.size());
+ typename QHash<Key, T>::ConstIterator it = hash.end();
+ typename QHash<Key, T>::ConstIterator begin = hash.begin();
+ while (it != begin) {
+ --it;
+ out << it.key() << it.value();
+ }
+ return out;
+}
+#ifdef qdoc
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map)
+#else
+template <class aKey, class aT>
+Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map)
+#endif
+{
+ QDataStream::Status oldStatus = in.status();
+ in.resetStatus();
+ map.clear();
+
+ quint32 n;
+ in >> n;
+
+ map.detach();
+ map.setInsertInOrder(true);
+ for (quint32 i = 0; i < n; ++i) {
+ if (in.status() != QDataStream::Ok)
+ break;
+
+ aKey key;
+ aT value;
+ in >> key >> value;
+ map.insertMulti(key, value);
+ }
+ map.setInsertInOrder(false);
+ if (in.status() != QDataStream::Ok)
+ map.clear();
+ if (oldStatus != QDataStream::Ok)
+ in.setStatus(oldStatus);
+ return in;
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
+{
+ out << quint32(map.size());
+ typename QMap<Key, T>::ConstIterator it = map.end();
+ typename QMap<Key, T>::ConstIterator begin = map.begin();
+ while (it != begin) {
+ --it;
+ out << it.key() << it.value();
+ }
+ return out;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDATASTREAM_H
diff --git a/src/corelib/io/qdatastream_p.h b/src/corelib/io/qdatastream_p.h
new file mode 100644
index 0000000000..ec270d2296
--- /dev/null
+++ b/src/corelib/io/qdatastream_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATASTREAM_P_H
+#define QDATASTREAM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+class QDataStreamPrivate
+{
+public:
+ QDataStreamPrivate() : floatingPointPrecision(QDataStream::DoublePrecision) { }
+
+ QDataStream::FloatingPointPrecision floatingPointPrecision;
+};
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QDATASTREAM_P_H
diff --git a/src/corelib/io/qdataurl.cpp b/src/corelib/io/qdataurl.cpp
new file mode 100644
index 0000000000..2e6f635886
--- /dev/null
+++ b/src/corelib/io/qdataurl.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qurl.h"
+#include "private/qdataurl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ Decode a data: URL into its mimetype and payload. Returns a null string if
+ the URL could not be decoded.
+*/
+Q_CORE_EXPORT QPair<QString, QByteArray> qDecodeDataUrl(const QUrl &uri)
+{
+ QString mimeType;
+ QByteArray payload;
+
+ if (uri.scheme() == QLatin1String("data") && uri.host().isEmpty()) {
+ mimeType = QLatin1String("text/plain;charset=US-ASCII");
+
+ // the following would have been the correct thing, but
+ // reality often differs from the specification. People have
+ // data: URIs with ? and #
+ //QByteArray data = QByteArray::fromPercentEncoding(uri.encodedPath());
+ QByteArray data = QByteArray::fromPercentEncoding(uri.toEncoded());
+
+ // remove the data: scheme
+ data.remove(0, 5);
+
+ // parse it:
+ int pos = data.indexOf(',');
+ if (pos != -1) {
+ payload = data.mid(pos + 1);
+ data.truncate(pos);
+ data = data.trimmed();
+
+ // find out if the payload is encoded in Base64
+ if (data.endsWith(";base64")) {
+ payload = QByteArray::fromBase64(payload);
+ data.chop(7);
+ }
+
+ if (data.toLower().startsWith("charset")) {
+ int i = 7; // strlen("charset")
+ while (data.at(i) == ' ')
+ ++i;
+ if (data.at(i) == '=')
+ data.prepend("text/plain;");
+ }
+
+ if (!data.isEmpty())
+ mimeType = QLatin1String(data.trimmed());
+
+ }
+ }
+
+ return QPair<QString,QByteArray>(mimeType,payload);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qdataurl_p.h b/src/corelib/io/qdataurl_p.h
new file mode 100644
index 0000000000..0cde476a5f
--- /dev/null
+++ b/src/corelib/io/qdataurl_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATAURL_P_H
+#define QDATAURL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qDecodeDataUrl. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qurl.h"
+#include "QtCore/qbytearray.h"
+#include "QtCore/qstring.h"
+#include "QtCore/qpair.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT QPair<QString, QByteArray> qDecodeDataUrl(const QUrl &url);
+
+QT_END_NAMESPACE
+
+#endif // QDATAURL_P_H
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
new file mode 100644
index 0000000000..aac0d982aa
--- /dev/null
+++ b/src/corelib/io/qdebug.cpp
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QT_NO_DEBUG
+#undef QT_NO_DEBUG
+#endif
+#ifdef qDebug
+#undef qDebug
+#endif
+
+#include "qdebug.h"
+
+// This file is needed to force compilation of QDebug into the kernel library.
+
+/*!
+ \class QDebug
+
+ \brief The QDebug class provides an output stream for debugging information.
+
+ QDebug is used whenever the developer needs to write out debugging or tracing
+ information to a device, file, string or console.
+
+ \section1 Basic Use
+
+ In the common case, it is useful to call the qDebug() function to obtain a
+ default QDebug object to use for writing debugging information.
+
+ \snippet doc/src/snippets/qdebug/qdebugsnippet.cpp 1
+
+ This constructs a QDebug object using the constructor that accepts a QtMsgType
+ value of QtDebugMsg. Similarly, the qWarning(), qCritical() and qFatal()
+ functions also return QDebug objects for the corresponding message types.
+
+ The class also provides several constructors for other situations, including
+ a constructor that accepts a QFile or any other QIODevice subclass that is
+ used to write debugging information to files and other devices. The constructor
+ that accepts a QString is used to write to a string for display or serialization.
+
+ \section1 Writing Custom Types to a Stream
+
+ Many standard types can be written to QDebug objects, and Qt provides support for
+ most Qt value types. To add support for custom types, you need to implement a
+ streaming operator, as in the following example:
+
+ \snippet doc/src/snippets/qdebug/qdebugsnippet.cpp 0
+
+ This is described in the \l{Debugging Techniques} and
+ \l{Creating Custom Qt Types#Making the Type Printable}{Creating Custom Qt Types}
+ documents.
+*/
+
+/*!
+ \fn QDebug::QDebug(QIODevice *device)
+
+ Constructs a debug stream that writes to the given \a device.
+*/
+
+/*!
+ \fn QDebug::QDebug(QString *string)
+
+ Constructs a debug stream that writes to the given \a string.
+*/
+
+/*!
+ \fn QDebug::QDebug(QtMsgType type)
+
+ Constructs a debug stream that writes to the handler for the message type specified by \a type.
+*/
+
+/*!
+ \fn QDebug::QDebug(const QDebug &other)
+
+ Constructs a copy of the \a other debug stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator=(const QDebug &other)
+
+ Assigns the \a other debug stream to this stream and returns a reference to
+ this stream.
+*/
+
+/*!
+ \fn QDebug::~QDebug()
+
+ Flushes any pending data to be written and destroys the debug stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::space()
+
+ Writes a space character to the debug stream and returns a reference to
+ the stream.
+
+ The stream will record that the last character sent to the stream was a
+ space.
+
+ \sa nospace(), maybeSpace()
+*/
+
+/*!
+ \fn QDebug &QDebug::nospace()
+
+ Clears the stream's internal flag that records whether the last character
+ was a space and returns a reference to the stream.
+
+ \sa space(), maybeSpace()
+*/
+
+/*!
+ \fn QDebug &QDebug::maybeSpace()
+
+ Writes a space character to the debug stream, depending on the last
+ character sent to the stream, and returns a reference to the stream.
+
+ If the last character was a space character, this function writes a space
+ character to the stream; otherwise, no characters are written to the stream.
+
+ \sa space(), nospace()
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(QChar t)
+
+ Writes the character, \a t, to the stream and returns a reference to the
+ stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(QBool t)
+ \internal
+
+ Writes the boolean value, \a t, to the stream and returns a reference to the
+ stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(bool t)
+
+ Writes the boolean value, \a t, to the stream and returns a reference to the
+ stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(char t)
+
+ Writes the character, \a t, to the stream and returns a reference to the
+ stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(signed short i)
+
+ Writes the signed short integer, \a i, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(unsigned short i)
+
+ Writes then unsigned short integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(signed int i)
+
+ Writes the signed integer, \a i, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(unsigned int i)
+
+ Writes then unsigned integer, \a i, to the stream and returns a reference to
+ the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(signed long l)
+
+ Writes the signed long integer, \a l, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(unsigned long l)
+
+ Writes then unsigned long integer, \a l, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(qint64 i)
+
+ Writes the signed 64-bit integer, \a i, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(quint64 i)
+
+ Writes then unsigned 64-bit integer, \a i, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(float f)
+
+ Writes the 32-bit floating point number, \a f, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(double f)
+
+ Writes the 64-bit floating point number, \a f, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const char *s)
+
+ Writes the '\0'-terminated string, \a s, to the stream and returns a
+ reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const QString &s)
+
+ Writes the string, \a s, to the stream and returns a reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const QStringRef &s)
+
+ Writes the string reference, \a s, to the stream and returns a reference to
+ the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const QLatin1String &s)
+
+ Writes the Latin1-encoded string, \a s, to the stream and returns a reference
+ to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const QByteArray &b)
+
+ Writes the byte array, \a b, to the stream and returns a reference to the
+ stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(const void *p)
+
+ Writes a pointer, \a p, to the stream and returns a reference to the stream.
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(QTextStreamFunction f)
+ \internal
+*/
+
+/*!
+ \fn QDebug &QDebug::operator<<(QTextStreamManipulator m)
+ \internal
+*/
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
new file mode 100644
index 0000000000..f463b753fb
--- /dev/null
+++ b/src/corelib/io/qdebug.h
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDEBUG_H
+#define QDEBUG_H
+
+#include <QtCore/qalgorithms.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qset.h>
+#include <QtCore/qcontiguouscache.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class Q_CORE_EXPORT QDebug
+{
+ struct Stream {
+ Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
+ Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
+ Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true) {}
+ QTextStream ts;
+ QString buffer;
+ int ref;
+ QtMsgType type;
+ bool space;
+ bool message_output;
+ } *stream;
+public:
+ inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
+ inline QDebug(QString *string) : stream(new Stream(string)) {}
+ inline QDebug(QtMsgType t) : stream(new Stream(t)) {}
+ inline QDebug(const QDebug &o):stream(o.stream) { ++stream->ref; }
+ inline QDebug &operator=(const QDebug &other);
+ inline ~QDebug() {
+ if (!--stream->ref) {
+ if(stream->message_output) {
+ QT_TRY {
+ qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
+ } QT_CATCH(std::bad_alloc&) { /* We're out of memory - give up. */ }
+ }
+ delete stream;
+ }
+ }
+ inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
+ inline QDebug &nospace() { stream->space = false; return *this; }
+ inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
+
+ inline QDebug &operator<<(QChar t) { stream->ts << '\'' << t << '\''; return maybeSpace(); }
+ inline QDebug &operator<<(QBool t) { stream->ts << (bool(t != 0) ? "true" : "false"); return maybeSpace(); }
+ inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); }
+ inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(unsigned short t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(signed int t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(unsigned int t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(signed long t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(unsigned long t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(qint64 t)
+ { stream->ts << QString::number(t); return maybeSpace(); }
+ inline QDebug &operator<<(quint64 t)
+ { stream->ts << QString::number(t); return maybeSpace(); }
+ inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(const char* t) { stream->ts << QString::fromAscii(t); return maybeSpace(); }
+ inline QDebug &operator<<(const QString & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QDebug &operator<<(const QLatin1String &t) { stream->ts << '\"' << t.latin1() << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(const QByteArray & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
+ inline QDebug &operator<<(QTextStreamFunction f) {
+ stream->ts << f;
+ return *this;
+ }
+
+ inline QDebug &operator<<(QTextStreamManipulator m)
+ { stream->ts << m; return *this; }
+};
+
+class QNoDebug
+{
+public:
+ inline QNoDebug(){}
+ inline QNoDebug(const QDebug &){}
+ inline ~QNoDebug(){}
+#if !defined( QT_NO_TEXTSTREAM )
+ inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
+ inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
+#endif
+ inline QNoDebug &space() { return *this; }
+ inline QNoDebug &nospace() { return *this; }
+ inline QNoDebug &maybeSpace() { return *this; }
+
+ template<typename T>
+ inline QNoDebug &operator<<(const T &) { return *this; }
+};
+
+Q_CORE_EXPORT_INLINE QDebug qCritical() { return QDebug(QtCriticalMsg); }
+
+inline QDebug &QDebug::operator=(const QDebug &other)
+{
+ if (this != &other) {
+ QDebug copy(other);
+ qSwap(stream, copy.stream);
+ }
+ return *this;
+}
+
+#if defined(FORCE_UREF)
+template <class T>
+inline QDebug &operator<<(QDebug debug, const QList<T> &list)
+#else
+template <class T>
+inline QDebug operator<<(QDebug debug, const QList<T> &list)
+#endif
+{
+ debug.nospace() << '(';
+ for (Q_TYPENAME QList<T>::size_type i = 0; i < list.count(); ++i) {
+ if (i)
+ debug << ", ";
+ debug << list.at(i);
+ }
+ debug << ')';
+ return debug.space();
+}
+
+#if defined(FORCE_UREF)
+template <typename T>
+inline QDebug &operator<<(QDebug debug, const QVector<T> &vec)
+#else
+template <typename T>
+inline QDebug operator<<(QDebug debug, const QVector<T> &vec)
+#endif
+{
+ debug.nospace() << "QVector";
+ return operator<<(debug, vec.toList());
+}
+
+#if defined(FORCE_UREF)
+template <class aKey, class aT>
+inline QDebug &operator<<(QDebug debug, const QMap<aKey, aT> &map)
+#else
+template <class aKey, class aT>
+inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map)
+#endif
+{
+ debug.nospace() << "QMap(";
+ for (typename QMap<aKey, aT>::const_iterator it = map.constBegin();
+ it != map.constEnd(); ++it) {
+ debug << '(' << it.key() << ", " << it.value() << ')';
+ }
+ debug << ')';
+ return debug.space();
+}
+
+#if defined(FORCE_UREF)
+template <class aKey, class aT>
+inline QDebug &operator<<(QDebug debug, const QHash<aKey, aT> &hash)
+#else
+template <class aKey, class aT>
+inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash)
+#endif
+{
+ debug.nospace() << "QHash(";
+ for (typename QHash<aKey, aT>::const_iterator it = hash.constBegin();
+ it != hash.constEnd(); ++it)
+ debug << '(' << it.key() << ", " << it.value() << ')';
+ debug << ')';
+ return debug.space();
+}
+
+#if defined(FORCE_UREF)
+template <class T1, class T2>
+inline QDebug &operator<<(QDebug debug, const QPair<T1, T2> &pair)
+#else
+template <class T1, class T2>
+inline QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
+#endif
+{
+ debug.nospace() << "QPair(" << pair.first << ',' << pair.second << ')';
+ return debug.space();
+}
+
+template <typename T>
+inline QDebug operator<<(QDebug debug, const QSet<T> &set)
+{
+ debug.nospace() << "QSet";
+ return operator<<(debug, set.toList());
+}
+
+#if defined(FORCE_UREF)
+template <class T>
+inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache)
+#else
+template <class T>
+inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
+#endif
+{
+ debug.nospace() << "QContiguousCache(";
+ for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
+ debug << cache[i];
+ if (i != cache.lastIndex())
+ debug << ", ";
+ }
+ debug << ')';
+ return debug.space();
+}
+
+#if defined(FORCE_UREF)
+template <class T>
+inline QDebug &operator<<(QDebug debug, const QFlags<T> &flags)
+#else
+template <class T>
+inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
+#endif
+{
+ debug.nospace() << "QFlags(";
+ bool needSeparator = false;
+ for (uint i = 0; i < sizeof(T) * 8; ++i) {
+ if (flags.testFlag(T(1 << i))) {
+ if (needSeparator)
+ debug.nospace() << '|';
+ else
+ needSeparator = true;
+ debug.nospace() << "0x" << QByteArray::number(T(1 << i), 16).constData();
+ }
+ }
+ debug << ')';
+ return debug.space();
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }
+
+#else // QT_NO_DEBUG_STREAM
+#undef qDebug
+inline QNoDebug qDebug() { return QNoDebug(); }
+#define qDebug QT_NO_QDEBUG_MACRO
+
+#endif
+
+#if !defined(QT_NO_WARNING_OUTPUT)
+Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); }
+#else
+#undef qWarning
+inline QNoDebug qWarning() { return QNoDebug(); }
+#define qWarning QT_NO_QWARNING_MACRO
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDEBUG_H
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
new file mode 100644
index 0000000000..166513a6ff
--- /dev/null
+++ b/src/corelib/io/qdir.cpp
@@ -0,0 +1,2386 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qdir.h"
+#include "qdir_p.h"
+#include "qabstractfileengine.h"
+#ifndef QT_NO_DEBUG_STREAM
+#include "qdebug.h"
+#endif
+#include "qdiriterator.h"
+#include "qfsfileengine.h"
+#include "qdatetime.h"
+#include "qstring.h"
+#include "qregexp.h"
+#include "qvector.h"
+#include "qalgorithms.h"
+#include "qvarlengtharray.h"
+#include "qfilesystementry_p.h"
+#include "qfilesystemmetadata_p.h"
+#include "qfilesystemengine_p.h"
+#include <qstringbuilder.h>
+
+#ifdef QT_BUILD_CORE_LIB
+# include "qresource.h"
+# include "private/qcoreglobaldata_p.h"
+#endif
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString driveSpec(const QString &path)
+{
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (path.size() < 2)
+ return QString();
+ char c = path.at(0).toAscii();
+ if (c < 'a' && c > 'z' && c < 'A' && c > 'Z')
+ return QString();
+ if (path.at(1).toAscii() != ':')
+ return QString();
+ return path.mid(0, 2);
+#else
+ Q_UNUSED(path);
+ return QString();
+#endif
+}
+
+//************* QDirPrivate
+QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_)
+ : QSharedData()
+ , nameFilters(nameFilters_)
+ , sort(sort_)
+ , filters(filters_)
+#ifdef QT3_SUPPORT
+ , filterSepChar(0)
+ , matchAllDirs(false)
+#endif
+ , fileListsInitialized(false)
+{
+ setPath(path.isEmpty() ? QString::fromLatin1(".") : path);
+
+ bool empty = nameFilters.isEmpty();
+ if (!empty) {
+ empty = true;
+ for (int i = 0; i < nameFilters.size(); ++i) {
+ if (!nameFilters.at(i).isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ }
+ if (empty)
+ nameFilters = QStringList(QString::fromLatin1("*"));
+}
+
+QDirPrivate::QDirPrivate(const QDirPrivate &copy)
+ : QSharedData(copy)
+ , nameFilters(copy.nameFilters)
+ , sort(copy.sort)
+ , filters(copy.filters)
+#ifdef QT3_SUPPORT
+ , filterSepChar(copy.filterSepChar)
+ , matchAllDirs(copy.matchAllDirs)
+#endif
+ , fileListsInitialized(false)
+ , dirEntry(copy.dirEntry)
+ , metaData(copy.metaData)
+{
+}
+
+bool QDirPrivate::exists() const
+{
+ if (fileEngine.isNull()) {
+ QFileSystemEngine::fillMetaData(dirEntry, metaData,
+ QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType); // always stat
+ return metaData.exists() && metaData.isDirectory();
+ }
+ const QAbstractFileEngine::FileFlags info =
+ fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
+ | QAbstractFileEngine::ExistsFlag
+ | QAbstractFileEngine::Refresh);
+ if (!(info & QAbstractFileEngine::DirectoryType))
+ return false;
+ return info & QAbstractFileEngine::ExistsFlag;
+}
+
+// static
+inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter)
+{
+ QChar sep(QLatin1Char(';'));
+ int i = nameFilter.indexOf(sep, 0);
+ if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1)
+ sep = QChar(QLatin1Char(' '));
+ return sep;
+}
+
+// static
+inline QStringList QDirPrivate::splitFilters(const QString &nameFilter, QChar sep)
+{
+ if (sep == 0)
+ sep = getFilterSepChar(nameFilter);
+ QStringList ret = nameFilter.split(sep);
+ for (int i = 0; i < ret.count(); ++i)
+ ret[i] = ret[i].trimmed();
+ return ret;
+}
+
+inline void QDirPrivate::setPath(const QString &path)
+{
+ QString p = QDir::fromNativeSeparators(path);
+ if (p.endsWith(QLatin1Char('/'))
+ && p.length() > 1
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ && (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter()))
+#endif
+ ) {
+ p.truncate(p.length() - 1);
+ }
+
+ dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
+ metaData.clear();
+ initFileEngine();
+ clearFileLists();
+ absoluteDirEntry = QFileSystemEntry();
+}
+
+inline void QDirPrivate::clearFileLists()
+{
+ fileListsInitialized = false;
+ files.clear();
+ fileInfos.clear();
+}
+
+inline void QDirPrivate::resolveAbsoluteEntry() const
+{
+ if (!absoluteDirEntry.isEmpty() || dirEntry.isEmpty())
+ return;
+
+ QString absoluteName;
+ if (fileEngine.isNull()) {
+ if (!dirEntry.isRelative()) {
+ absoluteDirEntry = dirEntry;
+ return;
+ }
+
+ absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath();
+ } else {
+ absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
+ }
+
+ absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath());
+}
+
+/* For sorting */
+struct QDirSortItem
+{
+ mutable QString filename_cache;
+ mutable QString suffix_cache;
+ QFileInfo item;
+};
+
+
+class QDirSortItemComparator
+{
+ int qt_cmp_si_sort_flags;
+public:
+ QDirSortItemComparator(int flags) : qt_cmp_si_sort_flags(flags) {}
+ bool operator()(const QDirSortItem &, const QDirSortItem &);
+};
+
+bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2)
+{
+ const QDirSortItem* f1 = &n1;
+ const QDirSortItem* f2 = &n2;
+
+ if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir()))
+ return f1->item.isDir();
+ if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
+ return !f1->item.isDir();
+
+ int r = 0;
+ int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask)
+ | (qt_cmp_si_sort_flags & QDir::Type);
+
+ switch (sortBy) {
+ case QDir::Time:
+ r = f1->item.lastModified().secsTo(f2->item.lastModified());
+ break;
+ case QDir::Size:
+ r = int(qBound<qint64>(-1, f2->item.size() - f1->item.size(), 1));
+ break;
+ case QDir::Type:
+ {
+ bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase;
+
+ if (f1->suffix_cache.isNull())
+ f1->suffix_cache = ic ? f1->item.suffix().toLower()
+ : f1->item.suffix();
+ if (f2->suffix_cache.isNull())
+ f2->suffix_cache = ic ? f2->item.suffix().toLower()
+ : f2->item.suffix();
+
+ r = qt_cmp_si_sort_flags & QDir::LocaleAware
+ ? f1->suffix_cache.localeAwareCompare(f2->suffix_cache)
+ : f1->suffix_cache.compare(f2->suffix_cache);
+ }
+ break;
+ default:
+ ;
+ }
+
+ if (r == 0 && sortBy != QDir::Unsorted) {
+ // Still not sorted - sort by name
+ bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase;
+
+ if (f1->filename_cache.isNull())
+ f1->filename_cache = ic ? f1->item.fileName().toLower()
+ : f1->item.fileName();
+ if (f2->filename_cache.isNull())
+ f2->filename_cache = ic ? f2->item.fileName().toLower()
+ : f2->item.fileName();
+
+ r = qt_cmp_si_sort_flags & QDir::LocaleAware
+ ? f1->filename_cache.localeAwareCompare(f2->filename_cache)
+ : f1->filename_cache.compare(f2->filename_cache);
+ }
+ if (r == 0) // Enforce an order - the order the items appear in the array
+ r = (&n1) - (&n2);
+ if (qt_cmp_si_sort_flags & QDir::Reversed)
+ return r > 0;
+ return r < 0;
+}
+
+inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
+ QStringList *names, QFileInfoList *infos)
+{
+ // names and infos are always empty lists or 0 here
+ int n = l.size();
+ if (n > 0) {
+ if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
+ if (infos)
+ *infos = l;
+ if (names) {
+ for (int i = 0; i < n; ++i)
+ names->append(l.at(i).fileName());
+ }
+ } else {
+ QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
+ for (int i = 0; i < n; ++i)
+ si[i].item = l.at(i);
+ qSort(si.data(), si.data() + n, QDirSortItemComparator(sort));
+ // put them back in the list(s)
+ if (infos) {
+ for (int i = 0; i < n; ++i)
+ infos->append(si[i].item);
+ }
+ if (names) {
+ for (int i = 0; i < n; ++i)
+ names->append(si[i].item.fileName());
+ }
+ }
+ }
+}
+inline void QDirPrivate::initFileLists(const QDir &dir) const
+{
+ if (!fileListsInitialized) {
+ QFileInfoList l;
+ QDirIterator it(dir);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
+ sortFileList(sort, l, &files, &fileInfos);
+ fileListsInitialized = true;
+ }
+}
+
+inline void QDirPrivate::initFileEngine()
+{
+ fileEngine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
+}
+
+/*!
+ \class QDir
+ \brief The QDir class provides access to directory structures and their contents.
+
+ \ingroup io
+ \ingroup shared
+ \reentrant
+
+
+ A QDir is used to manipulate path names, access information
+ regarding paths and files, and manipulate the underlying file
+ system. It can also be used to access Qt's \l{resource system}.
+
+ Qt uses "/" as a universal directory separator in the same way
+ that "/" is used as a path separator in URLs. If you always use
+ "/" as a directory separator, Qt will translate your paths to
+ conform to the underlying operating system.
+
+ A QDir can point to a file using either a relative or an absolute
+ path. Absolute paths begin with the directory separator
+ (optionally preceded by a drive specification under Windows).
+ Relative file names begin with a directory name or a file name and
+ specify a path relative to the current directory.
+
+ Examples of absolute paths:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 0
+
+ On Windows, the second example above will be translated to
+ \c{C:\Documents and Settings} when used to access files.
+
+ Examples of relative paths:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 1
+
+ You can use the isRelative() or isAbsolute() functions to check if
+ a QDir is using a relative or an absolute file path. Call
+ makeAbsolute() to convert a relative QDir to an absolute one.
+
+ \section1 Navigation and Directory Operations
+
+ A directory's path can be obtained with the path() function, and
+ a new path set with the setPath() function. The absolute path to
+ a directory is found by calling absolutePath().
+
+ The name of a directory is found using the dirName() function. This
+ typically returns the last element in the absolute path that specifies
+ the location of the directory. However, it can also return "." if
+ the QDir represents the current directory.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 2
+
+ The path for a directory can also be changed with the cd() and cdUp()
+ functions, both of which operate like familiar shell commands.
+ When cd() is called with the name of an existing directory, the QDir
+ object changes directory so that it represents that directory instead.
+ The cdUp() function changes the directory of the QDir object so that
+ it refers to its parent directory; i.e. cd("..") is equivalent to
+ cdUp().
+
+ Directories can be created with mkdir(), renamed with rename(), and
+ removed with rmdir().
+
+ You can test for the presence of a directory with a given name by
+ using exists(), and the properties of a directory can be tested with
+ isReadable(), isAbsolute(), isRelative(), and isRoot().
+
+ The refresh() function re-reads the directory's data from disk.
+
+ \section1 Files and Directory Contents
+
+ Directories contain a number of entries, representing files,
+ directories, and symbolic links. The number of entries in a
+ directory is returned by count().
+ A string list of the names of all the entries in a directory can be
+ obtained with entryList(). If you need information about each
+ entry, use entryInfoList() to obtain a list of QFileInfo objects.
+
+ Paths to files and directories within a directory can be
+ constructed using filePath() and absoluteFilePath().
+ The filePath() function returns a path to the specified file
+ or directory relative to the path of the QDir object;
+ absoluteFilePath() returns an absolute path to the specified
+ file or directory. Neither of these functions checks for the
+ existence of files or directory; they only construct paths.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 3
+
+ Files can be removed by using the remove() function. Directories
+ cannot be removed in the same way as files; use rmdir() to remove
+ them instead.
+
+ It is possible to reduce the number of entries returned by
+ entryList() and entryInfoList() by applying filters to a QDir object.
+ You can apply a name filter to specify a pattern with wildcards that
+ file names need to match, an attribute filter that selects properties
+ of entries and can distinguish between files and directories, and a
+ sort order.
+
+ Name filters are lists of strings that are passed to setNameFilters().
+ Attribute filters consist of a bitwise OR combination of Filters, and
+ these are specified when calling setFilter().
+ The sort order is specified using setSorting() with a bitwise OR
+ combination of SortFlags.
+
+ You can test to see if a filename matches a filter using the match()
+ function.
+
+ Filter and sort order flags may also be specified when calling
+ entryList() and entryInfoList() in order to override previously defined
+ behavior.
+
+ \section1 The Current Directory and Other Special Paths
+
+ Access to some common directories is provided with a number of static
+ functions that return QDir objects. There are also corresponding functions
+ for these that return strings:
+
+ \table
+ \header \o QDir \o QString \o Return Value
+ \row \o current() \o currentPath() \o The application's working directory
+ \row \o home() \o homePath() \o The user's home directory
+ \row \o root() \o rootPath() \o The root directory
+ \row \o temp() \o tempPath() \o The system's temporary directory
+ \endtable
+
+ The setCurrent() static function can also be used to set the application's
+ working directory.
+
+ If you want to find the directory containing the application's executable,
+ see \l{QCoreApplication::applicationDirPath()}.
+
+ The drives() static function provides a list of root directories for each
+ device that contains a filing system. On Unix systems this returns a list
+ containing a single root directory "/"; on Windows the list will usually
+ contain \c{C:/}, and possibly other drive letters such as \c{D:/}, depending
+ on the configuration of the user's system.
+
+ \section1 Path Manipulation and Strings
+
+ Paths containing "." elements that reference the current directory at that
+ point in the path, ".." elements that reference the parent directory, and
+ symbolic links can be reduced to a canonical form using the canonicalPath()
+ function.
+
+ Paths can also be simplified by using cleanPath() to remove redundant "/"
+ and ".." elements.
+
+ It is sometimes necessary to be able to show a path in the native
+ representation for the user's platform. The static toNativeSeparators()
+ function returns a copy of the specified path in which each directory
+ separator is replaced by the appropriate separator for the underlying
+ operating system.
+
+ \section1 Examples
+
+ Check if a directory exists:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 4
+
+ (We could also use the static convenience function
+ QFile::exists().)
+
+ Traversing directories and reading a file:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 5
+
+ A program that lists all the files in the current directory
+ (excluding symbolic links), sorted by size, smallest first:
+
+ \snippet doc/src/snippets/qdir-listfiles/main.cpp 0
+
+ \sa QFileInfo, QFile, QFileDialog, QApplication::applicationDirPath(), {Find Files Example}
+*/
+
+/*!
+ Constructs a QDir pointing to the given directory \a path. If path
+ is empty the program's working directory, ("."), is used.
+
+ \sa currentPath()
+*/
+QDir::QDir(const QString &path) : d_ptr(new QDirPrivate(path))
+{
+}
+
+/*!
+ Constructs a QDir with path \a path, that filters its entries by
+ name using \a nameFilter and by attributes using \a filters. It
+ also sorts the names using \a sort.
+
+ The default \a nameFilter is an empty string, which excludes
+ nothing; the default \a filters is \l AllEntries, which also means
+ exclude nothing. The default \a sort is \l Name | \l IgnoreCase,
+ i.e. sort by name case-insensitively.
+
+ If \a path is an empty string, QDir uses "." (the current
+ directory). If \a nameFilter is an empty string, QDir uses the
+ name filter "*" (all files).
+
+ Note that \a path need not exist.
+
+ \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting()
+*/
+QDir::QDir(const QString &path, const QString &nameFilter,
+ SortFlags sort, Filters filters)
+ : d_ptr(new QDirPrivate(path, QDir::nameFiltersFromString(nameFilter), sort, filters))
+{
+}
+
+/*!
+ Constructs a QDir object that is a copy of the QDir object for
+ directory \a dir.
+
+ \sa operator=()
+*/
+QDir::QDir(const QDir &dir)
+ : d_ptr(dir.d_ptr)
+{
+}
+
+/*!
+ Destroys the QDir object frees up its resources. This has no
+ effect on the underlying directory in the file system.
+*/
+QDir::~QDir()
+{
+}
+
+/*!
+ Sets the path of the directory to \a path. The path is cleaned of
+ redundant ".", ".." and of multiple separators. No check is made
+ to see whether a directory with this path actually exists; but you
+ can check for yourself using exists().
+
+ The path can be either absolute or relative. Absolute paths begin
+ with the directory separator "/" (optionally preceded by a drive
+ specification under Windows). Relative file names begin with a
+ directory name or a file name and specify a path relative to the
+ current directory. An example of an absolute path is the string
+ "/tmp/quartz", a relative path might look like "src/fatlib".
+
+ \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
+ absoluteFilePath(), isRelative(), makeAbsolute()
+*/
+void QDir::setPath(const QString &path)
+{
+ d_ptr->setPath(path);
+}
+
+/*!
+ Returns the path. This may contain symbolic links, but never
+ contains redundant ".", ".." or multiple separators.
+
+ The returned path can be either absolute or relative (see
+ setPath()).
+
+ \sa setPath(), absolutePath(), exists(), cleanPath(), dirName(),
+ absoluteFilePath(), toNativeSeparators(), makeAbsolute()
+*/
+QString QDir::path() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->dirEntry.filePath();
+}
+
+/*!
+ Returns the absolute path (a path that starts with "/" or with a
+ drive specification), which may contain symbolic links, but never
+ contains redundant ".", ".." or multiple separators.
+
+ \sa setPath(), canonicalPath(), exists(), cleanPath(),
+ dirName(), absoluteFilePath()
+*/
+QString QDir::absolutePath() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ d->resolveAbsoluteEntry();
+ return d->absoluteDirEntry.filePath();
+}
+
+/*!
+ Returns the canonical path, i.e. a path without symbolic links or
+ redundant "." or ".." elements.
+
+ On systems that do not have symbolic links this function will
+ always return the same string that absolutePath() returns. If the
+ canonical path does not exist (normally due to dangling symbolic
+ links) canonicalPath() returns an empty string.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 6
+
+ \sa path(), absolutePath(), exists(), cleanPath(), dirName(),
+ absoluteFilePath()
+*/
+QString QDir::canonicalPath() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ if (d->fileEngine.isNull()) {
+ QFileSystemEntry answer = QFileSystemEngine::canonicalName(d->dirEntry, d->metaData);
+ return answer.filePath();
+ }
+ return d->fileEngine->fileName(QAbstractFileEngine::CanonicalName);
+}
+
+/*!
+ Returns the name of the directory; this is \e not the same as the
+ path, e.g. a directory with the name "mail", might have the path
+ "/var/spool/mail". If the directory has no name (e.g. it is the
+ root directory) an empty string is returned.
+
+ No check is made to ensure that a directory with this name
+ actually exists; but see exists().
+
+ \sa path(), filePath(), absolutePath(), absoluteFilePath()
+*/
+QString QDir::dirName() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->dirEntry.fileName();
+}
+
+/*!
+ Returns the path name of a file in the directory. Does \e not
+ check if the file actually exists in the directory; but see
+ exists(). If the QDir is relative the returned path name will also
+ be relative. Redundant multiple separators or "." and ".."
+ directories in \a fileName are not removed (see cleanPath()).
+
+ \sa dirName() absoluteFilePath(), isRelative(), canonicalPath()
+*/
+QString QDir::filePath(const QString &fileName) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ if (isAbsolutePath(fileName))
+ return QString(fileName);
+
+ QString ret = d->dirEntry.filePath();
+ if (!fileName.isEmpty()) {
+ if (!ret.isEmpty() && ret[(int)ret.length()-1] != QLatin1Char('/') && fileName[0] != QLatin1Char('/'))
+ ret += QLatin1Char('/');
+ ret += fileName;
+ }
+ return ret;
+}
+
+/*!
+ Returns the absolute path name of a file in the directory. Does \e
+ not check if the file actually exists in the directory; but see
+ exists(). Redundant multiple separators or "." and ".."
+ directories in \a fileName are not removed (see cleanPath()).
+
+ \sa relativeFilePath() filePath() canonicalPath()
+*/
+QString QDir::absoluteFilePath(const QString &fileName) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ if (isAbsolutePath(fileName))
+ return fileName;
+
+ d->resolveAbsoluteEntry();
+ if (fileName.isEmpty())
+ return d->absoluteDirEntry.filePath();
+ if (!d->absoluteDirEntry.isRoot())
+ return d->absoluteDirEntry.filePath() % QLatin1Char('/') % fileName;
+ return d->absoluteDirEntry.filePath() % fileName;
+}
+
+/*!
+ Returns the path to \a fileName relative to the directory.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 7
+
+ \sa absoluteFilePath() filePath() canonicalPath()
+*/
+QString QDir::relativeFilePath(const QString &fileName) const
+{
+ QString dir = cleanPath(absolutePath());
+ QString file = cleanPath(fileName);
+
+ if (isRelativePath(file) || isRelativePath(dir))
+ return file;
+
+ QString dirDrive = driveSpec(dir);
+ QString fileDrive = driveSpec(file);
+
+ bool fileDriveMissing = false;
+ if (fileDrive.isEmpty()) {
+ fileDrive = dirDrive;
+ fileDriveMissing = true;
+ }
+
+#ifdef Q_OS_WIN
+ if (fileDrive.toLower() != dirDrive.toLower()
+ || (file.startsWith(QLatin1String("//"))
+ && !dir.startsWith(QLatin1String("//"))))
+#elif defined(Q_OS_SYMBIAN)
+ if (fileDrive.toLower() != dirDrive.toLower())
+#else
+ if (fileDrive != dirDrive)
+#endif
+ return file;
+
+ dir.remove(0, dirDrive.size());
+ if (!fileDriveMissing)
+ file.remove(0, fileDrive.size());
+
+ QString result;
+ QStringList dirElts = dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
+ QStringList fileElts = file.split(QLatin1Char('/'), QString::SkipEmptyParts);
+
+ int i = 0;
+ while (i < dirElts.size() && i < fileElts.size() &&
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ dirElts.at(i).toLower() == fileElts.at(i).toLower())
+#else
+ dirElts.at(i) == fileElts.at(i))
+#endif
+ ++i;
+
+ for (int j = 0; j < dirElts.size() - i; ++j)
+ result += QLatin1String("../");
+
+ for (int j = i; j < fileElts.size(); ++j) {
+ result += fileElts.at(j);
+ if (j < fileElts.size() - 1)
+ result += QLatin1Char('/');
+ }
+
+ return result;
+}
+
+#ifndef QT_NO_DEPRECATED
+/*!
+ \obsolete
+
+ Use QDir::toNativeSeparators() instead.
+*/
+QString QDir::convertSeparators(const QString &pathName)
+{
+ return toNativeSeparators(pathName);
+}
+#endif
+
+/*!
+ \since 4.2
+
+ Returns \a pathName with the '/' separators converted to
+ separators that are appropriate for the underlying operating
+ system.
+
+ On Windows, toNativeSeparators("c:/winnt/system32") returns
+ "c:\\winnt\\system32".
+
+ The returned string may be the same as the argument on some
+ operating systems, for example on Unix.
+
+ \sa fromNativeSeparators(), separator()
+*/
+QString QDir::toNativeSeparators(const QString &pathName)
+{
+ QString n(pathName);
+#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
+ for (int i = 0; i < (int)n.length(); ++i) {
+ if (n[i] == QLatin1Char('/'))
+ n[i] = QLatin1Char('\\');
+ }
+#endif
+ return n;
+}
+
+/*!
+ \since 4.2
+
+ Returns \a pathName using '/' as file separator. On Windows,
+ for instance, fromNativeSeparators("\c{c:\\winnt\\system32}") returns
+ "c:/winnt/system32".
+
+ The returned string may be the same as the argument on some
+ operating systems, for example on Unix.
+
+ \sa toNativeSeparators(), separator()
+*/
+QString QDir::fromNativeSeparators(const QString &pathName)
+{
+ QString n(pathName);
+#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
+ for (int i = 0; i < (int)n.length(); ++i) {
+ if (n[i] == QLatin1Char('\\'))
+ n[i] = QLatin1Char('/');
+ }
+#endif
+ return n;
+}
+
+/*!
+ Changes the QDir's directory to \a dirName.
+
+ Returns true if the new directory exists and is readable;
+ otherwise returns false. Note that the logical cd() operation is
+ not performed if the new directory does not exist.
+
+ Calling cd("..") is equivalent to calling cdUp().
+
+ \sa cdUp(), isReadable(), exists(), path()
+*/
+bool QDir::cd(const QString &dirName)
+{
+ // Don't detach just yet.
+ const QDirPrivate * const d = d_ptr.constData();
+
+ if (dirName.isEmpty() || dirName == QLatin1String("."))
+ return true;
+ QString newPath;
+ if (isAbsolutePath(dirName)) {
+ newPath = cleanPath(dirName);
+ } else {
+ if (isRoot()) {
+ if (dirName == QLatin1String(".."))
+ return false;
+ newPath = d->dirEntry.filePath();
+ } else {
+ newPath = d->dirEntry.filePath() % QLatin1Char('/');
+ }
+
+ newPath += dirName;
+ if (dirName.indexOf(QLatin1Char('/')) >= 0
+ || dirName == QLatin1String("..")
+ || d->dirEntry.filePath() == QLatin1String(".")) {
+ newPath = cleanPath(newPath);
+ /*
+ If newPath starts with .., we convert it to absolute to
+ avoid infinite looping on
+
+ QDir dir(".");
+ while (dir.cdUp())
+ ;
+ */
+ if (newPath.startsWith(QLatin1String(".."))) {
+ newPath = QFileInfo(newPath).absoluteFilePath();
+ }
+ }
+ }
+
+ QScopedPointer<QDirPrivate> dir(new QDirPrivate(*d_ptr.constData()));
+ dir->setPath(newPath);
+ if (!dir->exists())
+ return false;
+
+ d_ptr = dir.take();
+ return true;
+}
+
+/*!
+ Changes directory by moving one directory up from the QDir's
+ current directory.
+
+ Returns true if the new directory exists and is readable;
+ otherwise returns false. Note that the logical cdUp() operation is
+ not performed if the new directory does not exist.
+
+ \sa cd(), isReadable(), exists(), path()
+*/
+bool QDir::cdUp()
+{
+ return cd(QString::fromLatin1(".."));
+}
+
+/*!
+ Returns the string list set by setNameFilters()
+*/
+QStringList QDir::nameFilters() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->nameFilters;
+}
+
+/*!
+ Sets the name filters used by entryList() and entryInfoList() to the
+ list of filters specified by \a nameFilters.
+
+ Each name filter is a wildcard (globbing) filter that understands
+ \c{*} and \c{?} wildcards. (See \l{QRegExp wildcard matching}.)
+
+ For example, the following code sets three name filters on a QDir
+ to ensure that only files with extensions typically used for C++
+ source files are listed:
+
+ \snippet doc/src/snippets/qdir-namefilters/main.cpp 0
+
+ \sa nameFilters(), setFilter()
+*/
+void QDir::setNameFilters(const QStringList &nameFilters)
+{
+ QDirPrivate* d = d_ptr.data();
+ d->initFileEngine();
+ d->clearFileLists();
+
+ d->nameFilters = nameFilters;
+}
+
+/*!
+ \obsolete
+
+ Use QDir::addSearchPath() with a prefix instead.
+
+ Adds \a path to the search paths searched in to find resources
+ that are not specified with an absolute path. The default search
+ path is to search only in the root (\c{:/}).
+
+ \sa {The Qt Resource System}
+*/
+void QDir::addResourceSearchPath(const QString &path)
+{
+#ifdef QT_BUILD_CORE_LIB
+ QResource::addSearchPath(path);
+#else
+ Q_UNUSED(path)
+#endif
+}
+
+#ifdef QT_BUILD_CORE_LIB
+/*!
+ \since 4.3
+
+ Sets or replaces Qt's search paths for file names with the prefix \a prefix
+ to \a searchPaths.
+
+ To specify a prefix for a file name, prepend the prefix followed by a single
+ colon (e.g., "images:undo.png", "xmldocs:books.xml"). \a prefix can only
+ contain letters or numbers (e.g., it cannot contain a colon, nor a slash).
+
+ Qt uses this search path to locate files with a known prefix. The search
+ path entries are tested in order, starting with the first entry.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 8
+
+ File name prefix must be at least 2 characters long to avoid conflicts with
+ Windows drive letters.
+
+ Search paths may contain paths to \l{The Qt Resource System}.
+*/
+void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
+{
+ if (prefix.length() < 2) {
+ qWarning("QDir::setSearchPaths: Prefix must be longer than 1 character");
+ return;
+ }
+
+ for (int i = 0; i < prefix.count(); ++i) {
+ if (!prefix.at(i).isLetterOrNumber()) {
+ qWarning("QDir::setSearchPaths: Prefix can only contain letters or numbers");
+ return;
+ }
+ }
+
+ QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
+ QMap<QString, QStringList> &paths = QCoreGlobalData::instance()->dirSearchPaths;
+ if (searchPaths.isEmpty()) {
+ paths.remove(prefix);
+ } else {
+ paths.insert(prefix, searchPaths);
+ }
+}
+
+/*!
+ \since 4.3
+
+ Adds \a path to the search path for \a prefix.
+
+ \sa setSearchPaths()
+*/
+void QDir::addSearchPath(const QString &prefix, const QString &path)
+{
+ if (path.isEmpty())
+ return;
+
+ QWriteLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
+ QCoreGlobalData::instance()->dirSearchPaths[prefix] += path;
+}
+
+/*!
+ \since 4.3
+
+ Returns the search paths for \a prefix.
+
+ \sa setSearchPaths(), addSearchPath()
+*/
+QStringList QDir::searchPaths(const QString &prefix)
+{
+ QReadLocker lock(&QCoreGlobalData::instance()->dirSearchPathsLock);
+ return QCoreGlobalData::instance()->dirSearchPaths.value(prefix);
+}
+
+#endif // QT_BUILD_CORE_LIB
+
+/*!
+ Returns the value set by setFilter()
+*/
+QDir::Filters QDir::filter() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->filters;
+}
+
+/*!
+ \enum QDir::Filter
+
+ This enum describes the filtering options available to QDir; e.g.
+ for entryList() and entryInfoList(). The filter value is specified
+ by combining values from the following list using the bitwise OR
+ operator:
+
+ \value Dirs List directories that match the filters.
+ \value AllDirs List all directories; i.e. don't apply the filters
+ to directory names.
+ \value Files List files.
+ \value Drives List disk drives (ignored under Unix).
+ \value NoSymLinks Do not list symbolic links (ignored by operating
+ systems that don't support symbolic links).
+ \value NoDotAndDotDot Do not list the special entries "." and "..".
+ \value NoDot Do not list the special entry ".".
+ \value NoDotDot Do not list the special entry "..".
+ \value AllEntries List directories, files, drives and symlinks (this does not list
+ broken symlinks unless you specify System).
+ \value Readable List files for which the application has read
+ access. The Readable value needs to be combined
+ with Dirs or Files.
+ \value Writable List files for which the application has write
+ access. The Writable value needs to be combined
+ with Dirs or Files.
+ \value Executable List files for which the application has
+ execute access. The Executable value needs to be
+ combined with Dirs or Files.
+ \value Modified Only list files that have been modified (ignored
+ on Unix).
+ \value Hidden List hidden files (on Unix, files starting with a ".").
+ \value System List system files (on Unix, FIFOs, sockets and
+ device files are included; on Windows, \c {.lnk}
+ files are included)
+ \value CaseSensitive The filter should be case sensitive.
+
+ \omitvalue DefaultFilter
+ \omitvalue TypeMask
+ \omitvalue All
+ \omitvalue RWEMask
+ \omitvalue AccessMask
+ \omitvalue PermissionMask
+ \omitvalue NoFilter
+
+ Functions that use Filter enum values to filter lists of files
+ and directories will include symbolic links to files and directories
+ unless you set the NoSymLinks value.
+
+ A default constructed QDir will not filter out files based on
+ their permissions, so entryList() and entryInfoList() will return
+ all files that are readable, writable, executable, or any
+ combination of the three. This makes the default easy to write,
+ and at the same time useful.
+
+ For example, setting the \c Readable, \c Writable, and \c Files
+ flags allows all files to be listed for which the application has read
+ access, write access or both. If the \c Dirs and \c Drives flags are
+ also included in this combination then all drives, directories, all
+ files that the application can read, write, or execute, and symlinks
+ to such files/directories can be listed.
+
+ To retrieve the permissons for a directory, use the
+ entryInfoList() function to get the associated QFileInfo objects
+ and then use the QFileInfo::permissons() to obtain the permissions
+ and ownership for each file.
+*/
+
+/*!
+ Sets the filter used by entryList() and entryInfoList() to \a
+ filters. The filter is used to specify the kind of files that
+ should be returned by entryList() and entryInfoList(). See
+ \l{QDir::Filter}.
+
+ \sa filter(), setNameFilters()
+*/
+void QDir::setFilter(Filters filters)
+{
+ QDirPrivate* d = d_ptr.data();
+ d->initFileEngine();
+ d->clearFileLists();
+
+ d->filters = filters;
+}
+
+/*!
+ Returns the value set by setSorting()
+
+ \sa setSorting() SortFlag
+*/
+QDir::SortFlags QDir::sorting() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->sort;
+}
+
+/*!
+ \enum QDir::SortFlag
+
+ This enum describes the sort options available to QDir, e.g. for
+ entryList() and entryInfoList(). The sort value is specified by
+ OR-ing together values from the following list:
+
+ \value Name Sort by name.
+ \value Time Sort by time (modification time).
+ \value Size Sort by file size.
+ \value Type Sort by file type (extension).
+ \value Unsorted Do not sort.
+ \value NoSort Not sorted by default.
+
+ \value DirsFirst Put the directories first, then the files.
+ \value DirsLast Put the files first, then the directories.
+ \value Reversed Reverse the sort order.
+ \value IgnoreCase Sort case-insensitively.
+ \value LocaleAware Sort items appropriately using the current locale settings.
+
+ \omitvalue SortByMask
+ \omitvalue DefaultSort
+
+ You can only specify one of the first four.
+
+ If you specify both DirsFirst and Reversed, directories are
+ still put first, but in reverse order; the files will be listed
+ after the directories, again in reverse order.
+*/
+
+/*!
+ Sets the sort order used by entryList() and entryInfoList().
+
+ The \a sort is specified by OR-ing values from the enum
+ \l{QDir::SortFlag}.
+
+ \sa sorting() SortFlag
+*/
+void QDir::setSorting(SortFlags sort)
+{
+ QDirPrivate* d = d_ptr.data();
+ d->initFileEngine();
+ d->clearFileLists();
+
+ d->sort = sort;
+}
+
+/*!
+ Returns the total number of directories and files in the directory.
+
+ Equivalent to entryList().count().
+
+ \sa operator[](), entryList()
+*/
+uint QDir::count() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ d->initFileLists(*this);
+ return d->files.count();
+}
+
+/*!
+ Returns the file name at position \a pos in the list of file
+ names. Equivalent to entryList().at(index).
+ \a pos must be a valid index position in the list (i.e., 0 <= pos < count()).
+
+ \sa count(), entryList()
+*/
+QString QDir::operator[](int pos) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ d->initFileLists(*this);
+ return d->files[pos];
+}
+
+/*!
+ \overload
+
+ Returns a list of the names of all the files and directories in
+ the directory, ordered according to the name and attribute filters
+ previously set with setNameFilters() and setFilter(), and sorted according
+ to the flags set with setSorting().
+
+ The attribute filter and sorting specifications can be overridden using the
+ \a filters and \a sort arguments.
+
+ Returns an empty list if the directory is unreadable, does not
+ exist, or if nothing matches the specification.
+
+ \note To list symlinks that point to non existing files, \l System must be
+ passed to the filter.
+
+ \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
+*/
+QStringList QDir::entryList(Filters filters, SortFlags sort) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return entryList(d->nameFilters, filters, sort);
+}
+
+
+/*!
+ \overload
+
+ Returns a list of QFileInfo objects for all the files and directories in
+ the directory, ordered according to the name and attribute filters
+ previously set with setNameFilters() and setFilter(), and sorted according
+ to the flags set with setSorting().
+
+ The attribute filter and sorting specifications can be overridden using the
+ \a filters and \a sort arguments.
+
+ Returns an empty list if the directory is unreadable, does not
+ exist, or if nothing matches the specification.
+
+ \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
+*/
+QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return entryInfoList(d->nameFilters, filters, sort);
+}
+
+/*!
+ Returns a list of the names of all the files and
+ directories in the directory, ordered according to the name
+ and attribute filters previously set with setNameFilters()
+ and setFilter(), and sorted according to the flags set with
+ setSorting().
+
+ The name filter, file attribute filter, and sorting specification
+ can be overridden using the \a nameFilters, \a filters, and \a sort
+ arguments.
+
+ Returns an empty list if the directory is unreadable, does not
+ exist, or if nothing matches the specification.
+
+ \sa entryInfoList(), setNameFilters(), setSorting(), setFilter()
+*/
+QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
+ SortFlags sort) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (filters == NoFilter)
+ filters = d->filters;
+#ifdef QT3_SUPPORT
+ if (d->matchAllDirs)
+ filters |= AllDirs;
+#endif
+ if (sort == NoSort)
+ sort = d->sort;
+
+ if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
+ d->initFileLists(*this);
+ return d->files;
+ }
+
+ QFileInfoList l;
+ QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
+ QStringList ret;
+ d->sortFileList(sort, l, &ret, 0);
+ return ret;
+}
+
+/*!
+ Returns a list of QFileInfo objects for all the files and
+ directories in the directory, ordered according to the name
+ and attribute filters previously set with setNameFilters()
+ and setFilter(), and sorted according to the flags set with
+ setSorting().
+
+ The name filter, file attribute filter, and sorting specification
+ can be overridden using the \a nameFilters, \a filters, and \a sort
+ arguments.
+
+ Returns an empty list if the directory is unreadable, does not
+ exist, or if nothing matches the specification.
+
+ \sa entryList(), setNameFilters(), setSorting(), setFilter(), isReadable(), exists()
+*/
+QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filters,
+ SortFlags sort) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (filters == NoFilter)
+ filters = d->filters;
+#ifdef QT3_SUPPORT
+ if (d->matchAllDirs)
+ filters |= AllDirs;
+#endif
+ if (sort == NoSort)
+ sort = d->sort;
+
+ if (filters == d->filters && sort == d->sort && nameFilters == d->nameFilters) {
+ d->initFileLists(*this);
+ return d->fileInfos;
+ }
+
+ QFileInfoList l;
+ QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
+ while (it.hasNext()) {
+ it.next();
+ l.append(it.fileInfo());
+ }
+ QFileInfoList ret;
+ d->sortFileList(sort, l, 0, &ret);
+ return ret;
+}
+
+/*!
+ Creates a sub-directory called \a dirName.
+
+ Returns true on success; otherwise returns false.
+
+ If the directory already exists when this function is called, it will return false.
+
+ \sa rmdir()
+*/
+// ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath
+bool QDir::mkdir(const QString &dirName) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (dirName.isEmpty()) {
+ qWarning("QDir::mkdir: Empty or null file name(s)");
+ return false;
+ }
+
+ QString fn = filePath(dirName);
+ if (d->fileEngine.isNull())
+ return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), false);
+ return d->fileEngine->mkdir(fn, false);
+}
+
+/*!
+ Removes the directory specified by \a dirName.
+
+ The directory must be empty for rmdir() to succeed.
+
+ Returns true if successful; otherwise returns false.
+
+ \sa mkdir()
+*/
+bool QDir::rmdir(const QString &dirName) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (dirName.isEmpty()) {
+ qWarning("QDir::rmdir: Empty or null file name(s)");
+ return false;
+ }
+
+ QString fn = filePath(dirName);
+ if (d->fileEngine.isNull())
+ return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), false);
+
+ return d->fileEngine->rmdir(fn, false);
+}
+
+/*!
+ Creates the directory path \a dirPath.
+
+ The function will create all parent directories necessary to
+ create the directory.
+
+ Returns true if successful; otherwise returns false.
+
+ If the path already exists when this function is called, it will return true.
+
+ \sa rmpath()
+*/
+// ### Qt5: behaviour when directory already exists should be made consistent for mkdir and mkpath
+bool QDir::mkpath(const QString &dirPath) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (dirPath.isEmpty()) {
+ qWarning("QDir::mkpath: Empty or null file name(s)");
+ return false;
+ }
+
+ QString fn = filePath(dirPath);
+ if (d->fileEngine.isNull())
+ return QFileSystemEngine::createDirectory(QFileSystemEntry(fn), true);
+ return d->fileEngine->mkdir(fn, true);
+}
+
+/*!
+ Removes the directory path \a dirPath.
+
+ The function will remove all parent directories in \a dirPath,
+ provided that they are empty. This is the opposite of
+ mkpath(dirPath).
+
+ Returns true if successful; otherwise returns false.
+
+ \sa mkpath()
+*/
+bool QDir::rmpath(const QString &dirPath) const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (dirPath.isEmpty()) {
+ qWarning("QDir::rmpath: Empty or null file name(s)");
+ return false;
+ }
+
+ QString fn = filePath(dirPath);
+ if (d->fileEngine.isNull())
+ return QFileSystemEngine::removeDirectory(QFileSystemEntry(fn), true);
+ return d->fileEngine->rmdir(fn, true);
+}
+
+/*!
+ Returns true if the directory is readable \e and we can open files
+ by name; otherwise returns false.
+
+ \warning A false value from this function is not a guarantee that
+ files in the directory are not accessible.
+
+ \sa QFileInfo::isReadable()
+*/
+bool QDir::isReadable() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+
+ if (d->fileEngine.isNull()) {
+ if (!d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
+ QFileSystemEngine::fillMetaData(d->dirEntry, d->metaData, QFileSystemMetaData::UserReadPermission);
+
+ return (d->metaData.permissions() & QFile::ReadUser) != 0;
+ }
+
+ const QAbstractFileEngine::FileFlags info =
+ d->fileEngine->fileFlags(QAbstractFileEngine::DirectoryType
+ | QAbstractFileEngine::PermsMask);
+ if (!(info & QAbstractFileEngine::DirectoryType))
+ return false;
+ return info & QAbstractFileEngine::ReadUserPerm;
+}
+
+/*!
+ \overload
+
+ Returns true if the directory exists; otherwise returns false.
+ (If a file with the same name is found this function will return false).
+
+ The overload of this function that accepts an argument is used to test
+ for the presence of files and directories within a directory.
+
+ \sa QFileInfo::exists(), QFile::exists()
+*/
+bool QDir::exists() const
+{
+ return d_ptr->exists();
+}
+
+/*!
+ Returns true if the directory is the root directory; otherwise
+ returns false.
+
+ Note: If the directory is a symbolic link to the root directory
+ this function returns false. If you want to test for this use
+ canonicalPath(), e.g.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 9
+
+ \sa root(), rootPath()
+*/
+bool QDir::isRoot() const
+{
+ if (d_ptr->fileEngine.isNull())
+ return d_ptr->dirEntry.isRoot();
+ return d_ptr->fileEngine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::RootFlag;
+}
+
+/*!
+ \fn bool QDir::isAbsolute() const
+
+ Returns true if the directory's path is absolute; otherwise
+ returns false. See isAbsolutePath().
+
+ \sa isRelative() makeAbsolute() cleanPath()
+*/
+
+/*!
+ \fn bool QDir::isAbsolutePath(const QString &)
+
+ Returns true if \a path is absolute; returns false if it is
+ relative.
+
+ \sa isAbsolute() isRelativePath() makeAbsolute() cleanPath()
+*/
+
+/*!
+ Returns true if the directory path is relative; otherwise returns
+ false. (Under Unix a path is relative if it does not start with a
+ "/").
+
+ \sa makeAbsolute() isAbsolute() isAbsolutePath() cleanPath()
+*/
+bool QDir::isRelative() const
+{
+ if (d_ptr->fileEngine.isNull())
+ return d_ptr->dirEntry.isRelative();
+ return d_ptr->fileEngine->isRelativePath();
+}
+
+
+/*!
+ Converts the directory path to an absolute path. If it is already
+ absolute nothing happens. Returns true if the conversion
+ succeeded; otherwise returns false.
+
+ \sa isAbsolute() isAbsolutePath() isRelative() cleanPath()
+*/
+bool QDir::makeAbsolute()
+{
+ const QDirPrivate *d = d_ptr.constData();
+ QScopedPointer<QDirPrivate> dir;
+ if (!d->fileEngine.isNull()) {
+ QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
+ if (QDir::isRelativePath(absolutePath))
+ return false;
+
+ dir.reset(new QDirPrivate(*d_ptr.constData()));
+ dir->setPath(absolutePath);
+ } else { // native FS
+ d->resolveAbsoluteEntry();
+ dir.reset(new QDirPrivate(*d_ptr.constData()));
+ dir->setPath(d->absoluteDirEntry.filePath());
+ }
+ d_ptr = dir.take(); // actually detach
+ return true;
+}
+
+/*!
+ Returns true if directory \a dir and this directory have the same
+ path and their sort and filter settings are the same; otherwise
+ returns false.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 10
+*/
+bool QDir::operator==(const QDir &dir) const
+{
+ const QDirPrivate *d = d_ptr.constData();
+ const QDirPrivate *other = dir.d_ptr.constData();
+
+ if (d == other)
+ return true;
+ Qt::CaseSensitivity sensitive;
+ if (d->fileEngine.isNull() || other->fileEngine.isNull()) {
+ if (d->fileEngine.data() != other->fileEngine.data()) // one is native, the other is a custom file-engine
+ return false;
+
+ sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ } else {
+ if (d->fileEngine->caseSensitive() != other->fileEngine->caseSensitive())
+ return false;
+ sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ }
+
+ if (d->filters == other->filters
+ && d->sort == other->sort
+ && d->nameFilters == other->nameFilters) {
+ d->resolveAbsoluteEntry();
+ other->resolveAbsoluteEntry();
+ return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0;
+ }
+ return false;
+}
+
+/*!
+ Makes a copy of the \a dir object and assigns it to this QDir
+ object.
+*/
+QDir &QDir::operator=(const QDir &dir)
+{
+ d_ptr = dir.d_ptr;
+ return *this;
+}
+
+/*!
+ \overload
+ \obsolete
+
+ Sets the directory path to the given \a path.
+
+ Use setPath() instead.
+*/
+QDir &QDir::operator=(const QString &path)
+{
+ d_ptr->setPath(path);
+ return *this;
+}
+
+/*!
+ \fn bool QDir::operator!=(const QDir &dir) const
+
+ Returns true if directory \a dir and this directory have different
+ paths or different sort or filter settings; otherwise returns
+ false.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 11
+*/
+
+/*!
+ Removes the file, \a fileName.
+
+ Returns true if the file is removed successfully; otherwise
+ returns false.
+*/
+bool QDir::remove(const QString &fileName)
+{
+ if (fileName.isEmpty()) {
+ qWarning("QDir::remove: Empty or null file name");
+ return false;
+ }
+ return QFile::remove(filePath(fileName));
+}
+
+/*!
+ Renames a file or directory from \a oldName to \a newName, and returns
+ true if successful; otherwise returns false.
+
+ On most file systems, rename() fails only if \a oldName does not
+ exist, if \a newName and \a oldName are not on the same
+ partition or if a file with the new name already exists.
+ However, there are also other reasons why rename() can
+ fail. For example, on at least one file system rename() fails if
+ \a newName points to an open file.
+*/
+bool QDir::rename(const QString &oldName, const QString &newName)
+{
+ if (oldName.isEmpty() || newName.isEmpty()) {
+ qWarning("QDir::rename: Empty or null file name(s)");
+ return false;
+ }
+
+ QFile file(filePath(oldName));
+ if (!file.exists())
+ return false;
+ return file.rename(filePath(newName));
+}
+
+/*!
+ Returns true if the file called \a name exists; otherwise returns
+ false.
+
+ Unless \a name contains an absolute file path, the file name is assumed
+ to be relative to the directory itself, so this function is typically used
+ to check for the presence of files within a directory.
+
+ \sa QFileInfo::exists(), QFile::exists()
+*/
+bool QDir::exists(const QString &name) const
+{
+ if (name.isEmpty()) {
+ qWarning("QDir::exists: Empty or null file name");
+ return false;
+ }
+ return QFile::exists(filePath(name));
+}
+
+/*!
+ Returns a list of the root directories on this system.
+
+ On Windows this returns a list of QFileInfo objects containing "C:/",
+ "D:/", etc. On other operating systems, it returns a list containing
+ just one root directory (i.e. "/").
+
+ \sa root(), rootPath()
+*/
+QFileInfoList QDir::drives()
+{
+#ifdef QT_NO_FSFILEENGINE
+ return QFileInfoList();
+#else
+ return QFSFileEngine::drives();
+#endif
+}
+
+/*!
+ Returns the native directory separator: "/" under Unix (including
+ Mac OS X) and "\\" under Windows.
+
+ You do not need to use this function to build file paths. If you
+ always use "/", Qt will translate your paths to conform to the
+ underlying operating system. If you want to display paths to the
+ user using their operating system's separator use
+ toNativeSeparators().
+*/
+QChar QDir::separator()
+{
+#if defined (Q_FS_FAT) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN)
+ return QLatin1Char('\\');
+#elif defined(Q_OS_UNIX)
+ return QLatin1Char('/');
+#elif defined (Q_OS_MAC)
+ return QLatin1Char(':');
+#else
+ return QLatin1Char('/');
+#endif
+}
+
+/*!
+ Sets the application's current working directory to \a path.
+ Returns true if the directory was successfully changed; otherwise
+ returns false.
+
+ \sa current(), currentPath(), home(), root(), temp()
+*/
+bool QDir::setCurrent(const QString &path)
+{
+ return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
+}
+
+/*!
+ \fn QDir QDir::current()
+
+ Returns the application's current directory.
+
+ The directory is constructed using the absolute path of the current directory,
+ ensuring that its path() will be the same as its absolutePath().
+
+ \sa currentPath(), setCurrent(), home(), root(), temp()
+*/
+
+/*!
+ Returns the absolute path of the application's current directory.
+
+ \sa current(), setCurrent(), homePath(), rootPath(), tempPath()
+*/
+QString QDir::currentPath()
+{
+ return QFileSystemEngine::currentPath().filePath();
+}
+
+/*!
+ \fn QString QDir::currentDirPath()
+ Returns the absolute path of the application's current directory.
+
+ Use currentPath() instead.
+
+ \sa currentPath(), setCurrent()
+*/
+
+/*!
+ \fn QDir QDir::home()
+
+ Returns the user's home directory.
+
+ The directory is constructed using the absolute path of the home directory,
+ ensuring that its path() will be the same as its absolutePath().
+
+ See homePath() for details.
+
+ \sa drives(), current(), root(), temp()
+*/
+
+/*!
+ Returns the absolute path of the user's home directory.
+
+ Under Windows this function will return the directory of the
+ current user's profile. Typically, this is:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 12
+
+ Use the toNativeSeparators() function to convert the separators to
+ the ones that are appropriate for the underlying operating system.
+
+ If the directory of the current user's profile does not exist or
+ cannot be retrieved, the following alternatives will be checked (in
+ the given order) until an existing and available path is found:
+
+ \list 1
+ \o The path specified by the \c USERPROFILE environment variable.
+ \o The path formed by concatenating the \c HOMEDRIVE and \c HOMEPATH
+ environment variables.
+ \o The path specified by the \c HOME environment variable.
+ \o The path returned by the rootPath() function (which uses the \c SystemDrive
+ environment variable)
+ \o The \c{C:/} directory.
+ \endlist
+
+ Under non-Windows operating systems the \c HOME environment
+ variable is used if it exists, otherwise the path returned by the
+ rootPath(). On Symbian always the same as the path returned by the rootPath().
+
+ \sa home(), currentPath(), rootPath(), tempPath()
+*/
+QString QDir::homePath()
+{
+ return QFileSystemEngine::homePath();
+}
+
+/*!
+ \fn QString QDir::homeDirPath()
+
+ Returns the absolute path of the user's home directory.
+
+ Use homePath() instead.
+
+ \sa homePath()
+*/
+
+/*!
+ \fn QDir QDir::temp()
+
+ Returns the system's temporary directory.
+
+ The directory is constructed using the absolute path of the temporary directory,
+ ensuring that its path() will be the same as its absolutePath().
+
+ See tempPath() for details.
+
+ \sa drives(), current(), home(), root()
+*/
+
+/*!
+ Returns the absolute path of the system's temporary directory.
+
+ On Unix/Linux systems this is the path in the \c TMPDIR environment
+ variable or \c{/tmp} if \c TMPDIR is not defined. On Windows this is
+ usually the path in the \c TEMP or \c TMP environment
+ variable. Whether a directory separator is added to the end or
+ not, depends on the operating system.
+
+ \sa temp(), currentPath(), homePath(), rootPath()
+*/
+QString QDir::tempPath()
+{
+ return QFileSystemEngine::tempPath();
+}
+
+/*!
+ \fn QDir QDir::root()
+
+ Returns the root directory.
+
+ The directory is constructed using the absolute path of the root directory,
+ ensuring that its path() will be the same as its absolutePath().
+
+ See rootPath() for details.
+
+ \sa drives(), current(), home(), temp()
+*/
+
+/*!
+ Returns the absolute path of the root directory.
+
+ For Unix operating systems this returns "/". For Windows file
+ systems this normally returns "c:/". On Symbian this typically returns
+ "c:/data", i.e. the same as native PathInfo::PhoneMemoryRootPath().
+
+ \sa root(), drives(), currentPath(), homePath(), tempPath()
+*/
+QString QDir::rootPath()
+{
+ return QFileSystemEngine::rootPath();
+}
+
+/*!
+ \fn QString QDir::rootDirPath()
+
+ Returns the absolute path of the root directory.
+
+ Use rootPath() instead.
+
+ \sa rootPath()
+*/
+
+#ifndef QT_NO_REGEXP
+/*!
+ \overload
+
+ Returns true if the \a fileName matches any of the wildcard (glob)
+ patterns in the list of \a filters; otherwise returns false. The
+ matching is case insensitive.
+
+ \sa {QRegExp wildcard matching}, QRegExp::exactMatch() entryList() entryInfoList()
+*/
+bool QDir::match(const QStringList &filters, const QString &fileName)
+{
+ for (QStringList::ConstIterator sit = filters.constBegin(); sit != filters.constEnd(); ++sit) {
+ QRegExp rx(*sit, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (rx.exactMatch(fileName))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns true if the \a fileName matches the wildcard (glob)
+ pattern \a filter; otherwise returns false. The \a filter may
+ contain multiple patterns separated by spaces or semicolons.
+ The matching is case insensitive.
+
+ \sa {QRegExp wildcard matching}, QRegExp::exactMatch() entryList() entryInfoList()
+*/
+bool QDir::match(const QString &filter, const QString &fileName)
+{
+ return match(nameFiltersFromString(filter), fileName);
+}
+#endif // QT_NO_REGEXP
+
+/*!
+ Removes all multiple directory separators "/" and resolves any
+ "."s or ".."s found in the path, \a path.
+
+ Symbolic links are kept. This function does not return the
+ canonical path, but rather the simplest version of the input.
+ For example, "./local" becomes "local", "local/../bin" becomes
+ "bin" and "/local/usr/../bin" becomes "/local/bin".
+
+ \sa absolutePath() canonicalPath()
+*/
+QString QDir::cleanPath(const QString &path)
+{
+ if (path.isEmpty())
+ return path;
+ QString name = path;
+ QChar dir_separator = separator();
+ if (dir_separator != QLatin1Char('/'))
+ name.replace(dir_separator, QLatin1Char('/'));
+
+ int used = 0, levels = 0;
+ const int len = name.length();
+ QVarLengthArray<QChar> outVector(len);
+ QChar *out = outVector.data();
+
+ const QChar *p = name.unicode();
+ for (int i = 0, last = -1, iwrite = 0; i < len; ++i) {
+ if (p[i] == QLatin1Char('/')) {
+ while (i < len-1 && p[i+1] == QLatin1Char('/')) {
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //allow unc paths
+ if (!i)
+ break;
+#endif
+ i++;
+ }
+ bool eaten = false;
+ if (i < len - 1 && p[i+1] == QLatin1Char('.')) {
+ int dotcount = 1;
+ if (i < len - 2 && p[i+2] == QLatin1Char('.'))
+ dotcount++;
+ if (i == len - dotcount - 1) {
+ if (dotcount == 1) {
+ break;
+ } else if (levels) {
+ if (last == -1) {
+ for (int i2 = iwrite-1; i2 >= 0; i2--) {
+ if (out[i2] == QLatin1Char('/')) {
+ last = i2;
+ break;
+ }
+ }
+ }
+ used -= iwrite - last - 1;
+ break;
+ }
+ } else if (p[i+dotcount+1] == QLatin1Char('/')) {
+ if (dotcount == 2 && levels) {
+ if (last == -1 || iwrite - last == 1) {
+ for (int i2 = (last == -1) ? (iwrite-1) : (last-1); i2 >= 0; i2--) {
+ if (out[i2] == QLatin1Char('/')) {
+ eaten = true;
+ last = i2;
+ break;
+ }
+ }
+ } else {
+ eaten = true;
+ }
+ if (eaten) {
+ levels--;
+ used -= iwrite - last;
+ iwrite = last;
+ last = -1;
+ }
+ } else if (dotcount == 2 && i > 0 && p[i - 1] != QLatin1Char('.')) {
+ eaten = true;
+ used -= iwrite - qMax(0, last);
+ iwrite = qMax(0, last);
+ last = -1;
+ ++i;
+ } else if (dotcount == 1) {
+ eaten = true;
+ }
+ if (eaten)
+ i += dotcount;
+ } else {
+ levels++;
+ }
+ } else if (last != -1 && iwrite - last == 1) {
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ eaten = (iwrite > 2);
+#else
+ eaten = true;
+#endif
+ last = -1;
+ } else if (last != -1 && i == len-1) {
+ eaten = true;
+ } else {
+ levels++;
+ }
+ if (!eaten)
+ last = i - (i - iwrite);
+ else
+ continue;
+ } else if (!i && p[i] == QLatin1Char('.')) {
+ int dotcount = 1;
+ if (len >= 1 && p[1] == QLatin1Char('.'))
+ dotcount++;
+ if (len >= dotcount && p[dotcount] == QLatin1Char('/')) {
+ if (dotcount == 1) {
+ i++;
+ while (i+1 < len-1 && p[i+1] == QLatin1Char('/'))
+ i++;
+ continue;
+ }
+ }
+ }
+ out[iwrite++] = p[i];
+ used++;
+ }
+
+ QString ret = (used == len ? name : QString(out, used));
+ // Strip away last slash except for root directories
+ if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {
+#if defined (Q_OS_WIN) || defined (Q_OS_SYMBIAN)
+ if (!(ret.length() == 3 && ret.at(1) == QLatin1Char(':')))
+#endif
+ ret.chop(1);
+ }
+
+ return ret;
+}
+
+/*!
+ Returns true if \a path is relative; returns false if it is
+ absolute.
+
+ \sa isRelative() isAbsolutePath() makeAbsolute()
+*/
+bool QDir::isRelativePath(const QString &path)
+{
+ return QFileInfo(path).isRelative();
+}
+
+/*!
+ Refreshes the directory information.
+*/
+void QDir::refresh() const
+{
+ QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data();
+ d->metaData.clear();
+ d->initFileEngine();
+ d->clearFileLists();
+}
+
+/*!
+ \internal
+
+ Returns a list of name filters from the given \a nameFilter. (If
+ there is more than one filter, each pair of filters is separated
+ by a space or by a semicolon.)
+*/
+QStringList QDir::nameFiltersFromString(const QString &nameFilter)
+{
+ return QDirPrivate::splitFilters(nameFilter);
+}
+
+/*!
+ \macro void Q_INIT_RESOURCE(name)
+ \relates QDir
+
+ Initializes the resources specified by the \c .qrc file with the
+ specified base \a name. Normally, Qt resources are loaded
+ automatically at startup. The Q_INIT_RESOURCE() macro is
+ necessary on some platforms for resources stored in a static
+ library.
+
+ For example, if your application's resources are listed in a file
+ called \c myapp.qrc, you can ensure that the resources are
+ initialized at startup by adding this line to your \c main()
+ function:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 13
+
+ If the file name contains characters that cannot be part of a valid C++ function name
+ (such as '-'), they have to be replaced by the underscore character ('_').
+
+ Note: This macro cannot be used in a namespace. It should be called from
+ main(). If that is not possible, the following workaround can be used
+ to init the resource \c myapp from the function \c{MyNamespace::myFunction}:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 14
+
+ \sa Q_CLEANUP_RESOURCE(), {The Qt Resource System}
+*/
+
+/*!
+ \since 4.1
+ \macro void Q_CLEANUP_RESOURCE(name)
+ \relates QDir
+
+ Unloads the resources specified by the \c .qrc file with the base
+ name \a name.
+
+ Normally, Qt resources are unloaded automatically when the
+ application terminates, but if the resources are located in a
+ plugin that is being unloaded, call Q_CLEANUP_RESOURCE() to force
+ removal of your resources.
+
+ Note: This macro cannot be used in a namespace. Please see the
+ Q_INIT_RESOURCE documentation for a workaround.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdir.cpp 15
+
+ \sa Q_INIT_RESOURCE(), {The Qt Resource System}
+*/
+
+#ifdef QT3_SUPPORT
+
+/*!
+ \fn bool QDir::matchAllDirs() const
+
+ Use filter() & AllDirs instead.
+*/
+bool QDir::matchAllDirs() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return d->matchAllDirs;
+}
+
+
+/*!
+ \fn void QDir::setMatchAllDirs(bool on)
+
+ Use setFilter() instead.
+*/
+void QDir::setMatchAllDirs(bool on)
+{
+ QDirPrivate* d = d_ptr.data();
+ d->initFileEngine();
+ d->clearFileLists();
+
+ d->matchAllDirs = on;
+}
+
+/*!
+ Use nameFilters() instead.
+*/
+QString QDir::nameFilter() const
+{
+ const QDirPrivate* d = d_ptr.constData();
+ return nameFilters().join(QString(d->filterSepChar));
+}
+
+/*!
+ Use setNameFilters() instead.
+
+ The \a nameFilter is a wildcard (globbing) filter that understands
+ "*" and "?" wildcards. (See \l{QRegExp wildcard matching}.) You may
+ specify several filter entries, each separated by spaces or by
+ semicolons.
+
+ For example, if you want entryList() and entryInfoList() to list
+ all files ending with either ".cpp" or ".h", you would use either
+ dir.setNameFilters("*.cpp *.h") or dir.setNameFilters("*.cpp;*.h").
+
+ \oldcode
+ QString filter = "*.cpp *.cxx *.cc";
+ dir.setNameFilter(filter);
+ \newcode
+ QString filter = "*.cpp *.cxx *.cc";
+ dir.setNameFilters(filter.split(' '));
+ \endcode
+*/
+void QDir::setNameFilter(const QString &nameFilter)
+{
+ QDirPrivate* d = d_ptr.data();
+ d->initFileEngine();
+ d->clearFileLists();
+
+ d->filterSepChar = QDirPrivate::getFilterSepChar(nameFilter);
+ d->nameFilters = QDirPrivate::splitFilters(nameFilter, d->filterSepChar);
+}
+
+/*!
+ \fn QString QDir::absPath() const
+
+ Use absolutePath() instead.
+*/
+
+/*!
+ \fn QString QDir::absFilePath(const QString &fileName, bool acceptAbsPath) const
+
+ Use absoluteFilePath(\a fileName) instead.
+
+ The \a acceptAbsPath parameter is ignored.
+*/
+
+/*!
+ \fn bool QDir::mkdir(const QString &dirName, bool acceptAbsPath) const
+
+ Use mkdir(\a dirName) instead.
+
+ The \a acceptAbsPath parameter is ignored.
+*/
+
+/*!
+ \fn bool QDir::rmdir(const QString &dirName, bool acceptAbsPath) const
+
+ Use rmdir(\a dirName) instead.
+
+ The \a acceptAbsPath parameter is ignored.
+*/
+
+/*!
+ \fn QStringList QDir::entryList(const QString &nameFilter, Filters filters,
+ SortFlags sort) const
+ \overload
+
+ Use the overload that takes a name filter string list as first
+ argument instead of a combination of attribute filter flags.
+*/
+
+/*!
+ \fn QFileInfoList QDir::entryInfoList(const QString &nameFilter, Filters filters,
+ SortFlags sort) const
+ \overload
+
+ Use the overload that takes a name filter string list as first
+ argument instead of a combination of attribute filter flags.
+*/
+
+/*!
+ \fn void QDir::convertToAbs()
+
+ Use makeAbsolute() instead.
+*/
+
+/*!
+ \fn QString QDir::cleanDirPath(const QString &name)
+
+ Use cleanPath() instead.
+*/
+
+/*!
+ \typedef QDir::FilterSpec
+
+ Use QDir::Filters instead.
+*/
+
+/*!
+ \typedef QDir::SortSpec
+
+ Use QDir::SortFlags instead.
+*/
+#endif // QT3_SUPPORT
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QDir::Filters filters)
+{
+ QStringList flags;
+ if (filters == QDir::NoFilter) {
+ flags << QLatin1String("NoFilter");
+ } else {
+ if (filters & QDir::Dirs) flags << QLatin1String("Dirs");
+ if (filters & QDir::AllDirs) flags << QLatin1String("AllDirs");
+ if (filters & QDir::Files) flags << QLatin1String("Files");
+ if (filters & QDir::Drives) flags << QLatin1String("Drives");
+ if (filters & QDir::NoSymLinks) flags << QLatin1String("NoSymLinks");
+ if (filters & QDir::NoDotAndDotDot) flags << QLatin1String("NoDotAndDotDot"); // ### Qt5: remove (because NoDotAndDotDot=NoDot|NoDotDot)
+ if (filters & QDir::NoDot) flags << QLatin1String("NoDot");
+ if (filters & QDir::NoDotDot) flags << QLatin1String("NoDotDot");
+ if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << QLatin1String("AllEntries");
+ if (filters & QDir::Readable) flags << QLatin1String("Readable");
+ if (filters & QDir::Writable) flags << QLatin1String("Writable");
+ if (filters & QDir::Executable) flags << QLatin1String("Executable");
+ if (filters & QDir::Modified) flags << QLatin1String("Modified");
+ if (filters & QDir::Hidden) flags << QLatin1String("Hidden");
+ if (filters & QDir::System) flags << QLatin1String("System");
+ if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
+ }
+ debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ')';
+ return debug;
+}
+
+static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
+{
+ if (sorting == QDir::NoSort) {
+ debug << "QDir::SortFlags(NoSort)";
+ } else {
+ QString type;
+ if ((sorting & 3) == QDir::Name) type = QLatin1String("Name");
+ if ((sorting & 3) == QDir::Time) type = QLatin1String("Time");
+ if ((sorting & 3) == QDir::Size) type = QLatin1String("Size");
+ if ((sorting & 3) == QDir::Unsorted) type = QLatin1String("Unsorted");
+
+ QStringList flags;
+ if (sorting & QDir::DirsFirst) flags << QLatin1String("DirsFirst");
+ if (sorting & QDir::DirsLast) flags << QLatin1String("DirsLast");
+ if (sorting & QDir::IgnoreCase) flags << QLatin1String("IgnoreCase");
+ if (sorting & QDir::LocaleAware) flags << QLatin1String("LocaleAware");
+ if (sorting & QDir::Type) flags << QLatin1String("Type");
+ debug << "QDir::SortFlags(" << qPrintable(type)
+ << '|'
+ << qPrintable(flags.join(QLatin1String("|"))) << ')';
+ }
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QDir &dir)
+{
+ debug.maybeSpace() << "QDir(" << dir.path()
+ << ", nameFilters = {"
+ << qPrintable(dir.nameFilters().join(QLatin1String(",")))
+ << "}, "
+ << dir.sorting()
+ << ','
+ << dir.filter()
+ << ')';
+ return debug.space();
+}
+#endif // QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
new file mode 100644
index 0000000000..18049403a8
--- /dev/null
+++ b/src/corelib/io/qdir.h
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIR_H
+#define QDIR_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QDirPrivate;
+
+class Q_CORE_EXPORT QDir
+{
+protected:
+ QSharedDataPointer<QDirPrivate> d_ptr;
+
+public:
+ enum Filter { Dirs = 0x001,
+ Files = 0x002,
+ Drives = 0x004,
+ NoSymLinks = 0x008,
+ AllEntries = Dirs | Files | Drives,
+ TypeMask = 0x00f,
+#ifdef QT3_SUPPORT
+ All = AllEntries,
+#endif
+
+ Readable = 0x010,
+ Writable = 0x020,
+ Executable = 0x040,
+ PermissionMask = 0x070,
+#ifdef QT3_SUPPORT
+ RWEMask = 0x070,
+#endif
+
+ Modified = 0x080,
+ Hidden = 0x100,
+ System = 0x200,
+
+ AccessMask = 0x3F0,
+
+ AllDirs = 0x400,
+ CaseSensitive = 0x800,
+ NoDotAndDotDot = 0x1000, // ### Qt5 NoDotAndDotDot = NoDot|NoDotDot
+ NoDot = 0x2000,
+ NoDotDot = 0x4000,
+
+ NoFilter = -1
+#ifdef QT3_SUPPORT
+ ,DefaultFilter = NoFilter
+#endif
+ };
+ Q_DECLARE_FLAGS(Filters, Filter)
+#ifdef QT3_SUPPORT
+ typedef Filters FilterSpec;
+#endif
+
+ enum SortFlag { Name = 0x00,
+ Time = 0x01,
+ Size = 0x02,
+ Unsorted = 0x03,
+ SortByMask = 0x03,
+
+ DirsFirst = 0x04,
+ Reversed = 0x08,
+ IgnoreCase = 0x10,
+ DirsLast = 0x20,
+ LocaleAware = 0x40,
+ Type = 0x80,
+ NoSort = -1
+#ifdef QT3_SUPPORT
+ ,DefaultSort = NoSort
+#endif
+ };
+ Q_DECLARE_FLAGS(SortFlags, SortFlag)
+
+ QDir(const QDir &);
+ QDir(const QString &path = QString());
+ QDir(const QString &path, const QString &nameFilter,
+ SortFlags sort = SortFlags(Name | IgnoreCase), Filters filter = AllEntries);
+ ~QDir();
+
+ QDir &operator=(const QDir &);
+ QDir &operator=(const QString &path);
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QDir &operator=(QDir &&other)
+ { qSwap(d_ptr, other.d_ptr); return *this; }
+#endif
+
+ void setPath(const QString &path);
+ QString path() const;
+ QString absolutePath() const;
+ QString canonicalPath() const;
+
+ static void addResourceSearchPath(const QString &path);
+
+ static void setSearchPaths(const QString &prefix, const QStringList &searchPaths);
+ static void addSearchPath(const QString &prefix, const QString &path);
+ static QStringList searchPaths(const QString &prefix);
+
+ QString dirName() const;
+ QString filePath(const QString &fileName) const;
+ QString absoluteFilePath(const QString &fileName) const;
+ QString relativeFilePath(const QString &fileName) const;
+
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED static QString convertSeparators(const QString &pathName);
+#endif
+ static QString toNativeSeparators(const QString &pathName);
+ static QString fromNativeSeparators(const QString &pathName);
+
+ bool cd(const QString &dirName);
+ bool cdUp();
+
+ QStringList nameFilters() const;
+ void setNameFilters(const QStringList &nameFilters);
+
+ Filters filter() const;
+ void setFilter(Filters filter);
+ SortFlags sorting() const;
+ void setSorting(SortFlags sort);
+
+ uint count() const;
+ QString operator[](int) const;
+
+ static QStringList nameFiltersFromString(const QString &nameFilter);
+
+ QStringList entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const;
+ QStringList entryList(const QStringList &nameFilters, Filters filters = NoFilter,
+ SortFlags sort = NoSort) const;
+
+ QFileInfoList entryInfoList(Filters filters = NoFilter, SortFlags sort = NoSort) const;
+ QFileInfoList entryInfoList(const QStringList &nameFilters, Filters filters = NoFilter,
+ SortFlags sort = NoSort) const;
+
+ bool mkdir(const QString &dirName) const;
+ bool rmdir(const QString &dirName) const;
+ bool mkpath(const QString &dirPath) const;
+ bool rmpath(const QString &dirPath) const;
+
+ bool isReadable() const;
+ bool exists() const;
+ bool isRoot() const;
+
+ static bool isRelativePath(const QString &path);
+ inline static bool isAbsolutePath(const QString &path) { return !isRelativePath(path); }
+ bool isRelative() const;
+ inline bool isAbsolute() const { return !isRelative(); }
+ bool makeAbsolute();
+
+ bool operator==(const QDir &dir) const;
+ inline bool operator!=(const QDir &dir) const { return !operator==(dir); }
+
+ bool remove(const QString &fileName);
+ bool rename(const QString &oldName, const QString &newName);
+ bool exists(const QString &name) const;
+
+ static QFileInfoList drives();
+
+ static QChar separator();
+
+ static bool setCurrent(const QString &path);
+ static inline QDir current() { return QDir(currentPath()); }
+ static QString currentPath();
+
+ static inline QDir home() { return QDir(homePath()); }
+ static QString homePath();
+ static inline QDir root() { return QDir(rootPath()); }
+ static QString rootPath();
+ static inline QDir temp() { return QDir(tempPath()); }
+ static QString tempPath();
+
+#ifndef QT_NO_REGEXP
+ static bool match(const QStringList &filters, const QString &fileName);
+ static bool match(const QString &filter, const QString &fileName);
+#endif
+
+ static QString cleanPath(const QString &path);
+ void refresh() const;
+
+#ifdef QT3_SUPPORT
+ typedef SortFlags SortSpec;
+ inline QT3_SUPPORT QString absPath() const { return absolutePath(); }
+ inline QT3_SUPPORT QString absFilePath(const QString &fileName, bool acceptAbsPath = true) const
+ { Q_UNUSED(acceptAbsPath); return absoluteFilePath(fileName); }
+ QT3_SUPPORT bool matchAllDirs() const;
+ QT3_SUPPORT void setMatchAllDirs(bool on);
+ inline QT3_SUPPORT QStringList entryList(const QString &nameFilter, Filters filters = NoFilter,
+ SortFlags sort = NoSort) const
+ { return entryList(nameFiltersFromString(nameFilter), filters, sort); }
+ inline QT3_SUPPORT QFileInfoList entryInfoList(const QString &nameFilter,
+ Filters filters = NoFilter,
+ SortFlags sort = NoSort) const
+ { return entryInfoList(nameFiltersFromString(nameFilter), filters, sort); }
+
+ QT3_SUPPORT QString nameFilter() const;
+ QT3_SUPPORT void setNameFilter(const QString &nameFilter);
+
+ inline QT3_SUPPORT bool mkdir(const QString &dirName, bool acceptAbsPath) const
+ { Q_UNUSED(acceptAbsPath); return mkdir(dirName); }
+ inline QT3_SUPPORT bool rmdir(const QString &dirName, bool acceptAbsPath) const
+ { Q_UNUSED(acceptAbsPath); return rmdir(dirName); }
+
+ inline QT3_SUPPORT void convertToAbs() { makeAbsolute(); }
+ inline QT3_SUPPORT static QString currentDirPath() { return currentPath(); }
+ inline QT3_SUPPORT static QString homeDirPath() { return homePath(); }
+ inline QT3_SUPPORT static QString rootDirPath() { return rootPath(); }
+ inline QT3_SUPPORT static QString cleanDirPath(const QString &name) { return cleanPath(name); }
+#endif // QT3_SUPPORT
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDir::Filters)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDir::SortFlags)
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters);
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QDir &dir);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDIR_H
diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h
new file mode 100644
index 0000000000..7f77a84866
--- /dev/null
+++ b/src/corelib/io/qdir_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIR_PRIVATE_H
+#define QDIR_PRIVATE_H
+
+#include "qfilesystementry_p.h"
+#include "qfilesystemmetadata_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDirPrivate : public QSharedData
+{
+public:
+ QDirPrivate(const QString &path, const QStringList &nameFilters_ = QStringList(),
+ QDir::SortFlags sort_ = QDir::SortFlags(QDir::Name | QDir::IgnoreCase),
+ QDir::Filters filters_ = QDir::AllEntries);
+
+ QDirPrivate(const QDirPrivate &copy);
+
+ bool exists() const;
+
+ void initFileEngine();
+ void initFileLists(const QDir &dir) const;
+
+ static void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *);
+
+ static inline QChar getFilterSepChar(const QString &nameFilter);
+
+ static inline QStringList splitFilters(const QString &nameFilter, QChar sep = 0);
+
+ inline void setPath(const QString &path);
+
+ inline void clearFileLists();
+
+ inline void resolveAbsoluteEntry() const;
+
+ QStringList nameFilters;
+ QDir::SortFlags sort;
+ QDir::Filters filters;
+
+#ifdef QT3_SUPPORT
+ QChar filterSepChar;
+ bool matchAllDirs;
+#endif
+
+ QScopedPointer<QAbstractFileEngine> fileEngine;
+
+ mutable bool fileListsInitialized;
+ mutable QStringList files;
+ mutable QFileInfoList fileInfos;
+
+ QFileSystemEntry dirEntry;
+ mutable QFileSystemEntry absoluteDirEntry;
+ mutable QFileSystemMetaData metaData;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
new file mode 100644
index 0000000000..4a538f33db
--- /dev/null
+++ b/src/corelib/io/qdiriterator.cpp
@@ -0,0 +1,561 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \since 4.3
+ \class QDirIterator
+ \brief The QDirIterator class provides an iterator for directory entrylists.
+
+ You can use QDirIterator to navigate entries of a directory one at a time.
+ It is similar to QDir::entryList() and QDir::entryInfoList(), but because
+ it lists entries one at a time instead of all at once, it scales better
+ and is more suitable for large directories. It also supports listing
+ directory contents recursively, and following symbolic links. Unlike
+ QDir::entryList(), QDirIterator does not support sorting.
+
+ The QDirIterator constructor takes a QDir or a directory as
+ argument. After construction, the iterator is located before the first
+ directory entry. Here's how to iterate over all the entries sequentially:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qdiriterator.cpp 0
+
+ The next() function returns the path to the next directory entry and
+ advances the iterator. You can also call filePath() to get the current
+ file path without advancing the iterator. The fileName() function returns
+ only the name of the file, similar to how QDir::entryList() works. You can
+ also call fileInfo() to get a QFileInfo for the current entry.
+
+ Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
+ you cannot iterate directories in reverse order) and does not allow random
+ access.
+
+ QDirIterator works with all supported file engines, and is implemented
+ using QAbstractFileEngineIterator.
+
+ \sa QDir, QDir::entryList(), QAbstractFileEngineIterator
+*/
+
+/*! \enum QDirIterator::IteratorFlag
+
+ This enum describes flags that you can combine to configure the behavior
+ of QDirIterator.
+
+ \value NoIteratorFlags The default value, representing no flags. The
+ iterator will return entries for the assigned path.
+
+ \value Subdirectories List entries inside all subdirectories as well.
+
+ \value FollowSymlinks When combined with Subdirectories, this flag
+ enables iterating through all subdirectories of the assigned path,
+ following all symbolic links. Symbolic link loops (e.g., "link" => "." or
+ "link" => "..") are automatically detected and ignored.
+*/
+
+#include "qdiriterator.h"
+#include "qdir_p.h"
+
+#include "qabstractfileengine.h"
+
+#include <QtCore/qset.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qvariant.h>
+
+#include <QtCore/private/qfilesystemiterator_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+#include <QtCore/private/qfilesystemengine_p.h>
+#include <QtCore/qfsfileengine.h>
+#include <QtCore/private/qfileinfo_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template <class Iterator>
+class QDirIteratorPrivateIteratorStack : public QStack<Iterator *>
+{
+public:
+ ~QDirIteratorPrivateIteratorStack()
+ {
+ qDeleteAll(*this);
+ }
+};
+
+class QDirIteratorPrivate
+{
+public:
+ QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
+ QDir::Filters filters, QDirIterator::IteratorFlags flags, bool resolveEngine = true);
+
+ void advance();
+
+ bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
+ void pushDirectory(const QFileInfo &fileInfo);
+ void checkAndPushDirectory(const QFileInfo &);
+ bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
+
+ QScopedPointer<QAbstractFileEngine> engine;
+
+ QFileSystemEntry dirEntry;
+ const QStringList nameFilters;
+ const QDir::Filters filters;
+ const QDirIterator::IteratorFlags iteratorFlags;
+
+#ifndef QT_NO_REGEXP
+ QVector<QRegExp> nameRegExps;
+#endif
+
+ QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators;
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators;
+#endif
+
+ QFileInfo currentFileInfo;
+ QFileInfo nextFileInfo;
+
+ // Loop protection
+ QSet<QString> visitedLinks;
+};
+
+/*!
+ \internal
+*/
+QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
+ QDir::Filters filters, QDirIterator::IteratorFlags flags, bool resolveEngine)
+ : dirEntry(entry)
+ , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters)
+ , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters)
+ , iteratorFlags(flags)
+{
+#ifndef QT_NO_REGEXP
+ nameRegExps.reserve(nameFilters.size());
+ for (int i = 0; i < nameFilters.size(); ++i)
+ nameRegExps.append(
+ QRegExp(nameFilters.at(i),
+ (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
+ QRegExp::Wildcard));
+#endif
+ QFileSystemMetaData metaData;
+ if (resolveEngine)
+ engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
+ QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData));
+
+ // Populate fields for hasNext() and next()
+ pushDirectory(fileInfo);
+ advance();
+}
+
+/*!
+ \internal
+*/
+void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
+{
+ QString path = fileInfo.filePath();
+
+#ifdef Q_OS_WIN
+ if (fileInfo.isSymLink())
+ path = fileInfo.canonicalFilePath();
+#endif
+
+ if (iteratorFlags & QDirIterator::FollowSymlinks)
+ visitedLinks << fileInfo.canonicalFilePath();
+
+ if (engine) {
+ engine->setFileName(path);
+ QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
+ if (it) {
+ it->setPath(path);
+ fileEngineIterators << it;
+ } else {
+ // No iterator; no entry list.
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QFileSystemIterator *it = new QFileSystemIterator(fileInfo.d_ptr->fileEntry,
+ filters, nameFilters, iteratorFlags);
+ nativeIterators << it;
+#endif
+ }
+}
+
+inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo)
+{
+ checkAndPushDirectory(fileInfo);
+
+ if (matchesFilters(fileName, fileInfo)) {
+ currentFileInfo = nextFileInfo;
+ nextFileInfo = fileInfo;
+
+ //We found a matching entry.
+ return true;
+ }
+
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QDirIteratorPrivate::advance()
+{
+ if (engine) {
+ while (!fileEngineIterators.isEmpty()) {
+ // Find the next valid iterator that matches the filters.
+ QAbstractFileEngineIterator *it;
+ while (it = fileEngineIterators.top(), it->hasNext()) {
+ it->next();
+ if (entryMatches(it->currentFileName(), it->currentFileInfo()))
+ return;
+ }
+
+ fileEngineIterators.pop();
+ delete it;
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QFileSystemEntry nextEntry;
+ QFileSystemMetaData nextMetaData;
+
+ while (!nativeIterators.isEmpty()) {
+ // Find the next valid iterator that matches the filters.
+ QFileSystemIterator *it;
+ while (it = nativeIterators.top(), it->advance(nextEntry, nextMetaData)) {
+ QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
+
+ if (entryMatches(nextEntry.fileName(), info))
+ return;
+ }
+
+ nativeIterators.pop();
+ delete it;
+ }
+#endif
+ }
+
+ currentFileInfo = nextFileInfo;
+ nextFileInfo = QFileInfo();
+}
+
+/*!
+ \internal
+ */
+void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
+{
+ // If we're doing flat iteration, we're done.
+ if (!(iteratorFlags & QDirIterator::Subdirectories))
+ return;
+
+ // Never follow non-directory entries
+ if (!fileInfo.isDir())
+ return;
+
+ // Follow symlinks only when asked
+ if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
+ return;
+
+ // Never follow . and ..
+ QString fileName = fileInfo.fileName();
+ if (QLatin1String(".") == fileName || QLatin1String("..") == fileName)
+ return;
+
+ // No hidden directories unless requested
+ if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
+ return;
+
+ // Stop link loops
+ if (!visitedLinks.isEmpty() &&
+ visitedLinks.contains(fileInfo.canonicalFilePath()))
+ return;
+
+ pushDirectory(fileInfo);
+}
+
+/*!
+ \internal
+
+ This convenience function implements the iterator's filtering logics and
+ applies then to the current directory entry.
+
+ It returns true if the current entry matches the filters (i.e., the
+ current entry will be returned as part of the directory iteration);
+ otherwise, false is returned.
+*/
+
+bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
+{
+ Q_ASSERT(!fileName.isEmpty());
+
+ // filter . and ..?
+ const int fileNameSize = fileName.size();
+ const bool dotOrDotDot = fileName[0] == QLatin1Char('.')
+ && ((fileNameSize == 1)
+ ||(fileNameSize == 2 && fileName[1] == QLatin1Char('.')));
+ if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
+ return false;
+ if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
+ return false;
+ if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot) // ### Qt5 remove (NoDotAndDotDot == NoDot|NoDotDot)
+ return false;
+
+ // name filter
+#ifndef QT_NO_REGEXP
+ // Pass all entries through name filters, except dirs if the AllDirs
+ if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
+ bool matched = false;
+ for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(),
+ end = nameRegExps.constEnd();
+ iter != end; ++iter) {
+
+ if (iter->exactMatch(fileName)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched)
+ return false;
+ }
+#endif
+ // skip symlinks
+ const bool skipSymlinks = (filters & QDir::NoSymLinks);
+ const bool includeSystem = (filters & QDir::System);
+ if(skipSymlinks && fi.isSymLink()) {
+ // The only reason to save this file is if it is a broken link and we are requesting system files.
+ if(!includeSystem || fi.exists())
+ return false;
+ }
+
+ // filter hidden
+ const bool includeHidden = (filters & QDir::Hidden);
+ if (!includeHidden && !dotOrDotDot && fi.isHidden())
+ return false;
+
+ // filter system files
+ if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink())
+ || (!fi.exists() && fi.isSymLink())))
+ return false;
+
+ // skip directories
+ const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
+ if (skipDirs && fi.isDir())
+ return false;
+
+ // skip files
+ const bool skipFiles = !(filters & QDir::Files);
+ if (skipFiles && fi.isFile())
+ // Basically we need a reason not to exclude this file otherwise we just eliminate it.
+ return false;
+
+ // filter permissions
+ const bool filterPermissions = ((filters & QDir::PermissionMask)
+ && (filters & QDir::PermissionMask) != QDir::PermissionMask);
+ const bool doWritable = !filterPermissions || (filters & QDir::Writable);
+ const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
+ const bool doReadable = !filterPermissions || (filters & QDir::Readable);
+ if (filterPermissions
+ && ((doReadable && !fi.isReadable())
+ || (doWritable && !fi.isWritable())
+ || (doExecutable && !fi.isExecutable()))) {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ Constructs a QDirIterator that can iterate over \a dir's entrylist, using
+ \a dir's name filters and regular filters. You can pass options via \a
+ flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ The sorting in \a dir is ignored.
+
+ \note To list symlinks that point to non existing files, QDir::System must be
+ passed to the flags.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
+{
+ // little trick to get hold of the QDirPrivate while there is no API on QDir to give it to us
+ class MyQDir : public QDir { public: const QDirPrivate *priv() const { return d_ptr.constData(); } };
+ const QDirPrivate *other = static_cast<const MyQDir*>(&dir)->priv();
+ d.reset(new QDirIteratorPrivate(other->dirEntry, other->nameFilters, other->filters, flags, !other->fileEngine.isNull()));
+}
+
+/*!
+ Constructs a QDirIterator that can iterate over \a path, with no name
+ filtering and \a filters for entry filtering. You can pass options via \a
+ flags to decide how the directory should be iterated.
+
+ By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
+ which provides the same behavior as in QDir::entryList().
+
+ \note To list symlinks that point to non existing files, QDir::System must be
+ passed to the flags.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
+ : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), filters, flags))
+{
+}
+
+/*!
+ Constructs a QDirIterator that can iterate over \a path. You can pass
+ options via \a flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ \note To list symlinks that point to non existing files, QDir::System must be
+ passed to the flags.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
+ : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), QDir::NoFilter, flags))
+{
+}
+
+/*!
+ Constructs a QDirIterator that can iterate over \a path, using \a
+ nameFilters and \a filters. You can pass options via \a flags to decide
+ how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as QDir::entryList().
+
+ \note To list symlinks that point to non existing files, QDir::System must be
+ passed to the flags.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
+ QDir::Filters filters, IteratorFlags flags)
+ : d(new QDirIteratorPrivate(QFileSystemEntry(path), nameFilters, filters, flags))
+{
+}
+
+/*!
+ Destroys the QDirIterator.
+*/
+QDirIterator::~QDirIterator()
+{
+}
+
+/*!
+ Advances the iterator to the next entry, and returns the file path of this
+ new entry. If hasNext() returns false, this function does nothing, and
+ returns a null QString.
+
+ You can call fileName() or filePath() to get the current entry file name
+ or path, or fileInfo() to get a QFileInfo for the current entry.
+
+ \sa hasNext(), fileName(), filePath(), fileInfo()
+*/
+QString QDirIterator::next()
+{
+ d->advance();
+ return filePath();
+}
+
+/*!
+ Returns true if there is at least one more entry in the directory;
+ otherwise, false is returned.
+
+ \sa next(), fileName(), filePath(), fileInfo()
+*/
+bool QDirIterator::hasNext() const
+{
+ if (d->engine)
+ return !d->fileEngineIterators.isEmpty();
+ else
+#ifndef QT_NO_FILESYSTEMITERATOR
+ return !d->nativeIterators.isEmpty();
+#else
+ return false;
+#endif
+}
+
+/*!
+ Returns the file name for the current directory entry, without the path
+ prepended.
+
+ This function is convenient when iterating a single directory. When using
+ the QDirIterator::Subdirectories flag, you can use filePath() to get the
+ full path.
+
+ \sa filePath(), fileInfo()
+*/
+QString QDirIterator::fileName() const
+{
+ return d->currentFileInfo.fileName();
+}
+
+/*!
+ Returns the full file path for the current directory entry.
+
+ \sa fileInfo(), fileName()
+*/
+QString QDirIterator::filePath() const
+{
+ return d->currentFileInfo.filePath();
+}
+
+/*!
+ Returns a QFileInfo for the current directory entry.
+
+ \sa filePath(), fileName()
+*/
+QFileInfo QDirIterator::fileInfo() const
+{
+ return d->currentFileInfo;
+}
+
+/*!
+ Returns the base directory of the iterator.
+*/
+QString QDirIterator::path() const
+{
+ return d->dirEntry.filePath();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qdiriterator.h b/src/corelib/io/qdiriterator.h
new file mode 100644
index 0000000000..df2213f120
--- /dev/null
+++ b/src/corelib/io/qdiriterator.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRITERATOR_H
+#define QDIRITERATOR_H
+
+#include <QtCore/qdir.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QDirIteratorPrivate;
+class Q_CORE_EXPORT QDirIterator {
+public:
+ enum IteratorFlag {
+ NoIteratorFlags = 0x0,
+ FollowSymlinks = 0x1,
+ Subdirectories = 0x2
+ };
+ Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
+
+ QDirIterator(const QDir &dir, IteratorFlags flags = NoIteratorFlags);
+ QDirIterator(const QString &path,
+ IteratorFlags flags = NoIteratorFlags);
+ QDirIterator(const QString &path,
+ QDir::Filters filter,
+ IteratorFlags flags = NoIteratorFlags);
+ QDirIterator(const QString &path,
+ const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ IteratorFlags flags = NoIteratorFlags);
+
+ virtual ~QDirIterator();
+
+ QString next();
+ bool hasNext() const;
+
+ QString fileName() const;
+ QString filePath() const;
+ QFileInfo fileInfo() const;
+ QString path() const;
+
+private:
+ Q_DISABLE_COPY(QDirIterator)
+
+ QScopedPointer<QDirIteratorPrivate> d;
+ friend class QDir;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirIterator::IteratorFlags)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
new file mode 100644
index 0000000000..0ade573ea4
--- /dev/null
+++ b/src/corelib/io/qfile.cpp
@@ -0,0 +1,1884 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qdebug.h"
+#include "qfile.h"
+#include "qfsfileengine.h"
+#include "qtemporaryfile.h"
+#include "qlist.h"
+#include "qfileinfo.h"
+#include "private/qiodevice_p.h"
+#include "private/qfile_p.h"
+#include "private/qsystemerror_p.h"
+#if defined(QT_BUILD_CORE_LIB)
+# include "qcoreapplication.h"
+#endif
+
+#ifdef QT_NO_QOBJECT
+#define tr(X) QString::fromLatin1(X)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static const int QFILE_WRITEBUFFER_SIZE = 16384;
+
+static QByteArray locale_encode(const QString &f)
+{
+#if defined(Q_OS_DARWIN)
+ // Mac always expects UTF-8... and decomposed...
+ return f.normalized(QString::NormalizationForm_D).toUtf8();
+#elif defined(Q_OS_SYMBIAN)
+ return f.toUtf8();
+#else
+ return f.toLocal8Bit();
+#endif
+}
+
+static QString locale_decode(const QByteArray &f)
+{
+#if defined(Q_OS_DARWIN)
+ // Mac always gives us UTF-8 and decomposed, we want that composed...
+ return QString::fromUtf8(f).normalized(QString::NormalizationForm_C);
+#elif defined(Q_OS_SYMBIAN)
+ return QString::fromUtf8(f);
+#else
+ return QString::fromLocal8Bit(f);
+#endif
+}
+
+//************* QFilePrivate
+QFile::EncoderFn QFilePrivate::encoder = locale_encode;
+QFile::DecoderFn QFilePrivate::decoder = locale_decode;
+
+QFilePrivate::QFilePrivate()
+ : fileEngine(0), lastWasWrite(false),
+ writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError),
+ cachedSize(0)
+{
+}
+
+QFilePrivate::~QFilePrivate()
+{
+ delete fileEngine;
+ fileEngine = 0;
+}
+
+bool
+QFilePrivate::openExternalFile(int flags, int fd, QFile::FileHandleFlags handleFlags)
+{
+#ifdef QT_NO_FSFILEENGINE
+ Q_UNUSED(flags);
+ Q_UNUSED(fd);
+ return false;
+#else
+ delete fileEngine;
+ fileEngine = 0;
+ QFSFileEngine *fe = new QFSFileEngine;
+ fileEngine = fe;
+ return fe->open(QIODevice::OpenMode(flags), fd, handleFlags);
+#endif
+}
+
+bool
+QFilePrivate::openExternalFile(int flags, FILE *fh, QFile::FileHandleFlags handleFlags)
+{
+#ifdef QT_NO_FSFILEENGINE
+ Q_UNUSED(flags);
+ Q_UNUSED(fh);
+ return false;
+#else
+ delete fileEngine;
+ fileEngine = 0;
+ QFSFileEngine *fe = new QFSFileEngine;
+ fileEngine = fe;
+ return fe->open(QIODevice::OpenMode(flags), fh, handleFlags);
+#endif
+}
+
+#ifdef Q_OS_SYMBIAN
+bool QFilePrivate::openExternalFile(int flags, const RFile &f, QFile::FileHandleFlags handleFlags)
+{
+#ifdef QT_NO_FSFILEENGINE
+ Q_UNUSED(flags);
+ Q_UNUSED(fh);
+ return false;
+#else
+ delete fileEngine;
+ fileEngine = 0;
+ QFSFileEngine *fe = new QFSFileEngine;
+ fileEngine = fe;
+ return fe->open(QIODevice::OpenMode(flags), f, handleFlags);
+#endif
+}
+#endif
+
+inline bool QFilePrivate::ensureFlushed() const
+{
+ // This function ensures that the write buffer has been flushed (const
+ // because certain const functions need to call it.
+ if (lastWasWrite) {
+ const_cast<QFilePrivate *>(this)->lastWasWrite = false;
+ if (!const_cast<QFile *>(q_func())->flush())
+ return false;
+ }
+ return true;
+}
+
+void
+QFilePrivate::setError(QFile::FileError err)
+{
+ error = err;
+ errorString.clear();
+}
+
+void
+QFilePrivate::setError(QFile::FileError err, const QString &errStr)
+{
+ error = err;
+ errorString = errStr;
+}
+
+void
+QFilePrivate::setError(QFile::FileError err, int errNum)
+{
+ error = err;
+ errorString = qt_error_string(errNum);
+}
+
+//************* QFile
+
+/*!
+ \class QFile
+ \brief The QFile class provides an interface for reading from and writing to files.
+
+ \ingroup io
+
+ \reentrant
+
+ QFile is an I/O device for reading and writing text and binary
+ files and \l{The Qt Resource System}{resources}. A QFile may be
+ used by itself or, more conveniently, with a QTextStream or
+ QDataStream.
+
+ The file name is usually passed in the constructor, but it can be
+ set at any time using setFileName(). QFile expects the file
+ separator to be '/' regardless of operating system. The use of
+ other separators (e.g., '\\') is not supported.
+
+ You can check for a file's existence using exists(), and remove a
+ file using remove(). (More advanced file system related operations
+ are provided by QFileInfo and QDir.)
+
+ The file is opened with open(), closed with close(), and flushed
+ with flush(). Data is usually read and written using QDataStream
+ or QTextStream, but you can also call the QIODevice-inherited
+ functions read(), readLine(), readAll(), write(). QFile also
+ inherits getChar(), putChar(), and ungetChar(), which work one
+ character at a time.
+
+ The size of the file is returned by size(). You can get the
+ current file position using pos(), or move to a new file position
+ using seek(). If you've reached the end of the file, atEnd()
+ returns true.
+
+ \section1 Reading Files Directly
+
+ The following example reads a text file line by line:
+
+ \snippet doc/src/snippets/file/file.cpp 0
+
+ The QIODevice::Text flag passed to open() tells Qt to convert
+ Windows-style line terminators ("\\r\\n") into C++-style
+ terminators ("\\n"). By default, QFile assumes binary, i.e. it
+ doesn't perform any conversion on the bytes stored in the file.
+
+ \section1 Using Streams to Read Files
+
+ The next example uses QTextStream to read a text file
+ line by line:
+
+ \snippet doc/src/snippets/file/file.cpp 1
+
+ QTextStream takes care of converting the 8-bit data stored on
+ disk into a 16-bit Unicode QString. By default, it assumes that
+ the user system's local 8-bit encoding is used (e.g., ISO 8859-1
+ for most of Europe; see QTextCodec::codecForLocale() for
+ details). This can be changed using setCodec().
+
+ To write text, we can use operator<<(), which is overloaded to
+ take a QTextStream on the left and various data types (including
+ QString) on the right:
+
+ \snippet doc/src/snippets/file/file.cpp 2
+
+ QDataStream is similar, in that you can use operator<<() to write
+ data and operator>>() to read it back. See the class
+ documentation for details.
+
+ When you use QFile, QFileInfo, and QDir to access the file system
+ with Qt, you can use Unicode file names. On Unix, these file
+ names are converted to an 8-bit encoding. If you want to use
+ standard C++ APIs (\c <cstdio> or \c <iostream>) or
+ platform-specific APIs to access files instead of QFile, you can
+ use the encodeName() and decodeName() functions to convert
+ between Unicode file names and 8-bit file names.
+
+ On Unix, there are some special system files (e.g. in \c /proc) for which
+ size() will always return 0, yet you may still be able to read more data
+ from such a file; the data is generated in direct response to you calling
+ read(). In this case, however, you cannot use atEnd() to determine if
+ there is more data to read (since atEnd() will return true for a file that
+ claims to have size 0). Instead, you should either call readAll(), or call
+ read() or readLine() repeatedly until no more data can be read. The next
+ example uses QTextStream to read \c /proc/modules line by line:
+
+ \snippet doc/src/snippets/file/file.cpp 3
+
+ \section1 Signals
+
+ Unlike other QIODevice implementations, such as QTcpSocket, QFile does not
+ emit the aboutToClose(), bytesWritten(), or readyRead() signals. This
+ implementation detail means that QFile is not suitable for reading and
+ writing certain types of files, such as device files on Unix platforms.
+
+ \section1 Platform Specific Issues
+
+ File permissions are handled differently on Linux/Mac OS X and
+ Windows. In a non \l{QIODevice::isWritable()}{writable}
+ directory on Linux, files cannot be created. This is not always
+ the case on Windows, where, for instance, the 'My Documents'
+ directory usually is not writable, but it is still possible to
+ create files in it.
+
+ \sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
+*/
+
+/*!
+ \enum QFile::FileError
+
+ This enum describes the errors that may be returned by the error()
+ function.
+
+ \value NoError No error occurred.
+ \value ReadError An error occurred when reading from the file.
+ \value WriteError An error occurred when writing to the file.
+ \value FatalError A fatal error occurred.
+ \value ResourceError
+ \value OpenError The file could not be opened.
+ \value AbortError The operation was aborted.
+ \value TimeOutError A timeout occurred.
+ \value UnspecifiedError An unspecified error occurred.
+ \value RemoveError The file could not be removed.
+ \value RenameError The file could not be renamed.
+ \value PositionError The position in the file could not be changed.
+ \value ResizeError The file could not be resized.
+ \value PermissionsError The file could not be accessed.
+ \value CopyError The file could not be copied.
+
+ \omitvalue ConnectError
+*/
+
+/*!
+ \enum QFile::Permission
+
+ This enum is used by the permission() function to report the
+ permissions and ownership of a file. The values may be OR-ed
+ together to test multiple permissions and ownership values.
+
+ \value ReadOwner The file is readable by the owner of the file.
+ \value WriteOwner The file is writable by the owner of the file.
+ \value ExeOwner The file is executable by the owner of the file.
+ \value ReadUser The file is readable by the user.
+ \value WriteUser The file is writable by the user.
+ \value ExeUser The file is executable by the user.
+ \value ReadGroup The file is readable by the group.
+ \value WriteGroup The file is writable by the group.
+ \value ExeGroup The file is executable by the group.
+ \value ReadOther The file is readable by anyone.
+ \value WriteOther The file is writable by anyone.
+ \value ExeOther The file is executable by anyone.
+
+ \warning Because of differences in the platforms supported by Qt,
+ the semantics of ReadUser, WriteUser and ExeUser are
+ platform-dependent: On Unix, the rights of the owner of the file
+ are returned and on Windows the rights of the current user are
+ returned. This behavior might change in a future Qt version.
+
+ Note that Qt does not by default check for permissions on NTFS
+ file systems, as this may decrease the performance of file
+ handling considerably. It is possible to force permission checking
+ on NTFS by including the following code in your source:
+
+ \snippet doc/src/snippets/ntfsp.cpp 0
+
+ Permission checking is then turned on and off by incrementing and
+ decrementing \c qt_ntfs_permission_lookup by 1.
+
+ \snippet doc/src/snippets/ntfsp.cpp 1
+*/
+
+/*!
+ \enum QFile::FileHandleFlag
+
+ This enum is used when opening a file to specify additional
+ options which only apply to files and not to a generic
+ QIODevice.
+
+ \value AutoCloseHandle The file handle passed into open() should be
+ closed by close(), the default behaviour is that close just flushes
+ the file and the app is responsible for closing the file handle. When
+ opening a file by name, this flag is ignored as Qt always "owns" the
+ file handle and must close it.
+ */
+
+#ifdef QT3_SUPPORT
+/*!
+ \typedef QFile::PermissionSpec
+
+ Use QFile::Permission instead.
+*/
+#endif
+
+#ifdef QT_NO_QOBJECT
+QFile::QFile()
+ : QIODevice(*new QFilePrivate)
+{
+}
+QFile::QFile(const QString &name)
+ : QIODevice(*new QFilePrivate)
+{
+ d_func()->fileName = name;
+}
+QFile::QFile(QFilePrivate &dd)
+ : QIODevice(dd)
+{
+}
+#else
+/*!
+ \internal
+*/
+QFile::QFile()
+ : QIODevice(*new QFilePrivate, 0)
+{
+}
+/*!
+ Constructs a new file object with the given \a parent.
+*/
+QFile::QFile(QObject *parent)
+ : QIODevice(*new QFilePrivate, parent)
+{
+}
+/*!
+ Constructs a new file object to represent the file with the given \a name.
+*/
+QFile::QFile(const QString &name)
+ : QIODevice(*new QFilePrivate, 0)
+{
+ Q_D(QFile);
+ d->fileName = name;
+}
+/*!
+ Constructs a new file object with the given \a parent to represent the
+ file with the specified \a name.
+*/
+QFile::QFile(const QString &name, QObject *parent)
+ : QIODevice(*new QFilePrivate, parent)
+{
+ Q_D(QFile);
+ d->fileName = name;
+}
+/*!
+ \internal
+*/
+QFile::QFile(QFilePrivate &dd, QObject *parent)
+ : QIODevice(dd, parent)
+{
+}
+#endif
+
+/*!
+ Destroys the file object, closing it if necessary.
+*/
+QFile::~QFile()
+{
+ close();
+}
+
+/*!
+ Returns the name set by setFileName() or to the QFile
+ constructors.
+
+ \sa setFileName(), QFileInfo::fileName()
+*/
+QString QFile::fileName() const
+{
+ return fileEngine()->fileName(QAbstractFileEngine::DefaultName);
+}
+
+/*!
+ Sets the \a name of the file. The name can have no path, a
+ relative path, or an absolute path.
+
+ Do not call this function if the file has already been opened.
+
+ If the file name has no path or a relative path, the path used
+ will be the application's current directory path
+ \e{at the time of the open()} call.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 0
+
+ Note that the directory separator "/" works for all operating
+ systems supported by Qt.
+
+ \sa fileName(), QFileInfo, QDir
+*/
+void
+QFile::setFileName(const QString &name)
+{
+ Q_D(QFile);
+ if (isOpen()) {
+ qWarning("QFile::setFileName: File (%s) is already opened",
+ qPrintable(fileName()));
+ close();
+ }
+ if(d->fileEngine) { //get a new file engine later
+ delete d->fileEngine;
+ d->fileEngine = 0;
+ }
+ d->fileName = name;
+}
+
+/*!
+ \fn QString QFile::decodeName(const char *localFileName)
+
+ \overload
+
+ Returns the Unicode version of the given \a localFileName. See
+ encodeName() for details.
+*/
+
+/*!
+ By default, this function converts \a fileName to the local 8-bit
+ encoding determined by the user's locale. This is sufficient for
+ file names that the user chooses. File names hard-coded into the
+ application should only use 7-bit ASCII filename characters.
+
+ \sa decodeName() setEncodingFunction()
+*/
+
+QByteArray
+QFile::encodeName(const QString &fileName)
+{
+ return (*QFilePrivate::encoder)(fileName);
+}
+
+/*!
+ \typedef QFile::EncoderFn
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 1
+
+ \sa setEncodingFunction(), encodeName()
+*/
+
+/*!
+ This does the reverse of QFile::encodeName() using \a localFileName.
+
+ \sa setDecodingFunction(), encodeName()
+*/
+
+QString
+QFile::decodeName(const QByteArray &localFileName)
+{
+ return (*QFilePrivate::decoder)(localFileName);
+}
+
+/*!
+ \fn void QFile::setEncodingFunction(EncoderFn function)
+
+ \nonreentrant
+
+ Sets the \a function for encoding Unicode file names. The
+ default encodes in the locale-specific 8-bit encoding.
+
+ \sa encodeName(), setDecodingFunction()
+*/
+
+void
+QFile::setEncodingFunction(EncoderFn f)
+{
+ if (!f)
+ f = locale_encode;
+ QFilePrivate::encoder = f;
+}
+
+/*!
+ \typedef QFile::DecoderFn
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 2
+
+ \sa setDecodingFunction()
+*/
+
+/*!
+ \fn void QFile::setDecodingFunction(DecoderFn function)
+
+ \nonreentrant
+
+ Sets the \a function for decoding 8-bit file names. The
+ default uses the locale-specific 8-bit encoding.
+
+ \sa setEncodingFunction(), decodeName()
+*/
+
+void
+QFile::setDecodingFunction(DecoderFn f)
+{
+ if (!f)
+ f = locale_decode;
+ QFilePrivate::decoder = f;
+}
+
+/*!
+ \overload
+
+ Returns true if the file specified by fileName() exists; otherwise
+ returns false.
+
+ \sa fileName(), setFileName()
+*/
+
+bool
+QFile::exists() const
+{
+ // 0x1000000 = QAbstractFileEngine::Refresh, forcing an update
+ return (fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask
+ | QAbstractFileEngine::FileFlag(0x1000000)) & QAbstractFileEngine::ExistsFlag);
+}
+
+/*!
+ Returns true if the file specified by \a fileName exists; otherwise
+ returns false.
+*/
+
+bool
+QFile::exists(const QString &fileName)
+{
+ return QFileInfo(fileName).exists();
+}
+
+/*!
+ \fn QString QFile::symLinkTarget() const
+ \since 4.2
+ \overload
+
+ Returns the absolute path of the file or directory a symlink (or shortcut
+ on Windows) points to, or a an empty string if the object isn't a symbolic
+ link.
+
+ This name may not represent an existing file; it is only a string.
+ QFile::exists() returns true if the symlink points to an existing file.
+
+ \sa fileName() setFileName()
+*/
+
+/*!
+ \obsolete
+
+ Use symLinkTarget() instead.
+*/
+QString
+QFile::readLink() const
+{
+ return fileEngine()->fileName(QAbstractFileEngine::LinkName);
+}
+
+/*!
+ \fn static QString QFile::symLinkTarget(const QString &fileName)
+ \since 4.2
+
+ Returns the absolute path of the file or directory referred to by the
+ symlink (or shortcut on Windows) specified by \a fileName, or returns an
+ empty string if the \a fileName does not correspond to a symbolic link.
+
+ This name may not represent an existing file; it is only a string.
+ QFile::exists() returns true if the symlink points to an existing file.
+*/
+
+/*!
+ \obsolete
+
+ Use symLinkTarget() instead.
+*/
+QString
+QFile::readLink(const QString &fileName)
+{
+ return QFileInfo(fileName).readLink();
+}
+
+/*!
+ Removes the file specified by fileName(). Returns true if successful;
+ otherwise returns false.
+
+ The file is closed before it is removed.
+
+ \sa setFileName()
+*/
+
+bool
+QFile::remove()
+{
+ Q_D(QFile);
+ if (d->fileName.isEmpty()) {
+ qWarning("QFile::remove: Empty or null file name");
+ return false;
+ }
+ unsetError();
+ close();
+ if(error() == QFile::NoError) {
+ if(fileEngine()->remove()) {
+ unsetError();
+ return true;
+ }
+ d->setError(QFile::RemoveError, d->fileEngine->errorString());
+ }
+ return false;
+}
+
+/*!
+ \overload
+
+ Removes the file specified by the \a fileName given.
+
+ Returns true if successful; otherwise returns false.
+
+ \sa remove()
+*/
+
+bool
+QFile::remove(const QString &fileName)
+{
+ return QFile(fileName).remove();
+}
+
+/*!
+ Renames the file currently specified by fileName() to \a newName.
+ Returns true if successful; otherwise returns false.
+
+ If a file with the name \a newName already exists, rename() returns false
+ (i.e., QFile will not overwrite it).
+
+ The file is closed before it is renamed.
+
+ \sa setFileName()
+*/
+
+bool
+QFile::rename(const QString &newName)
+{
+ Q_D(QFile);
+ if (d->fileName.isEmpty()) {
+ qWarning("QFile::rename: Empty or null file name");
+ return false;
+ }
+ if (QFile(newName).exists()) {
+ // ### Race condition. If a file is moved in after this, it /will/ be
+ // overwritten. On Unix, the proper solution is to use hardlinks:
+ // return ::link(old, new) && ::remove(old);
+ d->setError(QFile::RenameError, tr("Destination file exists"));
+ return false;
+ }
+ unsetError();
+ close();
+ if(error() == QFile::NoError) {
+ if (fileEngine()->rename(newName)) {
+ unsetError();
+ // engine was able to handle the new name so we just reset it
+ d->fileEngine->setFileName(newName);
+ d->fileName = newName;
+ return true;
+ }
+
+ if (isSequential()) {
+ d->setError(QFile::RenameError, tr("Will not rename sequential file using block copy"));
+ return false;
+ }
+
+ QFile out(newName);
+ if (open(QIODevice::ReadOnly)) {
+ if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ bool error = false;
+ char block[4096];
+ qint64 bytes;
+ while ((bytes = read(block, sizeof(block))) > 0) {
+ if (bytes != out.write(block, bytes)) {
+ d->setError(QFile::RenameError, out.errorString());
+ error = true;
+ break;
+ }
+ }
+ if (bytes == -1) {
+ d->setError(QFile::RenameError, errorString());
+ error = true;
+ }
+ if(!error) {
+ if (!remove()) {
+ d->setError(QFile::RenameError, tr("Cannot remove source file"));
+ error = true;
+ }
+ }
+ if (error) {
+ out.remove();
+ } else {
+ d->fileEngine->setFileName(newName);
+ setPermissions(permissions());
+ unsetError();
+ setFileName(newName);
+ }
+ close();
+ return !error;
+ }
+ close();
+ }
+ d->setError(QFile::RenameError, out.isOpen() ? errorString() : out.errorString());
+ }
+ return false;
+}
+
+/*!
+ \overload
+
+ Renames the file \a oldName to \a newName. Returns true if
+ successful; otherwise returns false.
+
+ If a file with the name \a newName already exists, rename() returns false
+ (i.e., QFile will not overwrite it).
+
+ \sa rename()
+*/
+
+bool
+QFile::rename(const QString &oldName, const QString &newName)
+{
+ return QFile(oldName).rename(newName);
+}
+
+/*!
+
+ Creates a link named \a linkName that points to the file currently specified by
+ fileName(). What a link is depends on the underlying filesystem (be it a
+ shortcut on Windows or a symbolic link on Unix). Returns true if successful;
+ otherwise returns false.
+
+ This function will not overwrite an already existing entity in the file system;
+ in this case, \c link() will return false and set \l{QFile::}{error()} to
+ return \l{QFile::}{RenameError}.
+
+ \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension.
+
+ \note On Symbian, no link is created and false is returned if fileName()
+ currently specifies a directory.
+
+ \sa setFileName()
+*/
+
+bool
+QFile::link(const QString &linkName)
+{
+ Q_D(QFile);
+ if (d->fileName.isEmpty()) {
+ qWarning("QFile::link: Empty or null file name");
+ return false;
+ }
+ QFileInfo fi(linkName);
+ if(fileEngine()->link(fi.absoluteFilePath())) {
+ unsetError();
+ return true;
+ }
+ d->setError(QFile::RenameError, d->fileEngine->errorString());
+ return false;
+}
+
+/*!
+ \overload
+
+ Creates a link named \a linkName that points to the file \a fileName. What a link is
+ depends on the underlying filesystem (be it a shortcut on Windows
+ or a symbolic link on Unix). Returns true if successful; otherwise
+ returns false.
+
+ \sa link()
+*/
+
+bool
+QFile::link(const QString &fileName, const QString &linkName)
+{
+ return QFile(fileName).link(linkName);
+}
+
+/*!
+ Copies the file currently specified by fileName() to a file called
+ \a newName. Returns true if successful; otherwise returns false.
+
+ Note that if a file with the name \a newName already exists,
+ copy() returns false (i.e. QFile will not overwrite it).
+
+ The source file is closed before it is copied.
+
+ \sa setFileName()
+*/
+
+bool
+QFile::copy(const QString &newName)
+{
+ Q_D(QFile);
+ if (d->fileName.isEmpty()) {
+ qWarning("QFile::copy: Empty or null file name");
+ return false;
+ }
+ if (QFile(newName).exists()) {
+ // ### Race condition. If a file is moved in after this, it /will/ be
+ // overwritten. On Unix, the proper solution is to use hardlinks:
+ // return ::link(old, new) && ::remove(old); See also rename().
+ d->setError(QFile::CopyError, tr("Destination file exists"));
+ return false;
+ }
+ unsetError();
+ close();
+ if(error() == QFile::NoError) {
+ if(fileEngine()->copy(newName)) {
+ unsetError();
+ return true;
+ } else {
+ bool error = false;
+ if(!open(QFile::ReadOnly)) {
+ error = true;
+ d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
+ } else {
+ QString fileTemplate = QLatin1String("%1/qt_temp.XXXXXX");
+#ifdef QT_NO_TEMPORARYFILE
+ QFile out(fileTemplate.arg(QFileInfo(newName).path()));
+ if (!out.open(QIODevice::ReadWrite))
+ error = true;
+#else
+ QTemporaryFile out(fileTemplate.arg(QFileInfo(newName).path()));
+ if (!out.open()) {
+ out.setFileTemplate(fileTemplate.arg(QDir::tempPath()));
+ if (!out.open())
+ error = true;
+ }
+#endif
+ if (error) {
+ out.close();
+ d->setError(QFile::CopyError, tr("Cannot open for output"));
+ } else {
+ char block[4096];
+ qint64 totalRead = 0;
+ while(!atEnd()) {
+ qint64 in = read(block, sizeof(block));
+ if (in <= 0)
+ break;
+ totalRead += in;
+ if(in != out.write(block, in)) {
+ d->setError(QFile::CopyError, tr("Failure to write block"));
+ error = true;
+ break;
+ }
+ }
+
+ if (totalRead != size()) {
+ // Unable to read from the source. The error string is
+ // already set from read().
+ error = true;
+ }
+ if (!error && !out.rename(newName)) {
+ error = true;
+ d->setError(QFile::CopyError, tr("Cannot create %1 for output").arg(newName));
+ }
+#ifdef QT_NO_TEMPORARYFILE
+ if (error)
+ out.remove();
+#else
+ if (!error)
+ out.setAutoRemove(false);
+#endif
+ }
+ close();
+ }
+ if(!error) {
+ QFile::setPermissions(newName, permissions());
+ unsetError();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*!
+ \overload
+
+ Copies the file \a fileName to \a newName. Returns true if successful;
+ otherwise returns false.
+
+ If a file with the name \a newName already exists, copy() returns false
+ (i.e., QFile will not overwrite it).
+
+ \sa rename()
+*/
+
+bool
+QFile::copy(const QString &fileName, const QString &newName)
+{
+ return QFile(fileName).copy(newName);
+}
+
+/*!
+ Returns true if the file can only be manipulated sequentially;
+ otherwise returns false.
+
+ Most files support random-access, but some special files may not.
+
+ \sa QIODevice::isSequential()
+*/
+bool QFile::isSequential() const
+{
+ Q_D(const QFile);
+ return d->fileEngine && d->fileEngine->isSequential();
+}
+
+/*!
+ Opens the file using OpenMode \a mode, returning true if successful;
+ otherwise false.
+
+ The \a mode must be QIODevice::ReadOnly, QIODevice::WriteOnly, or
+ QIODevice::ReadWrite. It may also have additional flags, such as
+ QIODevice::Text and QIODevice::Unbuffered.
+
+ \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
+ mode, if the relevant file does not already exist, this function
+ will try to create a new file before opening it.
+
+ \sa QIODevice::OpenMode, setFileName()
+*/
+bool QFile::open(OpenMode mode)
+{
+ Q_D(QFile);
+ if (isOpen()) {
+ qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+ return false;
+ }
+ if (mode & Append)
+ mode |= WriteOnly;
+
+ unsetError();
+ if ((mode & (ReadOnly | WriteOnly)) == 0) {
+ qWarning("QIODevice::open: File access not specified");
+ return false;
+ }
+
+#ifdef Q_OS_SYMBIAN
+ // For symbian, the unbuffered flag is used to control write-behind cache behaviour
+ if (fileEngine()->open(mode))
+#else
+ // QIODevice provides the buffering, so there's no need to request it from the file engine.
+ if (fileEngine()->open(mode | QIODevice::Unbuffered))
+#endif
+ {
+ QIODevice::open(mode);
+ if (mode & Append)
+ seek(size());
+ return true;
+ }
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::OpenError;
+ d->setError(err, d->fileEngine->errorString());
+ return false;
+}
+
+/*! \fn QFile::open(OpenMode, FILE*)
+
+ Use open(FILE *, OpenMode) instead.
+*/
+
+/*!
+ \overload
+
+ Opens the existing file handle \a fh in the given \a mode.
+ Returns true if successful; otherwise returns false.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 3
+
+ When a QFile is opened using this function, close() does not actually
+ close the file, but only flushes it.
+
+ \bold{Warning:}
+ \list 1
+ \o If \a fh does not refer to a regular file, e.g., it is \c stdin,
+ \c stdout, or \c stderr, you may not be able to seek(). size()
+ returns \c 0 in those cases. See QIODevice::isSequential() for
+ more information.
+ \o Since this function opens the file without specifying the file name,
+ you cannot use this QFile with a QFileInfo.
+ \endlist
+
+ \note For Windows CE you may not be able to call resize().
+
+ \sa close(), {qmake Variable Reference#CONFIG}{qmake Variable Reference}
+
+ \bold{Note for the Windows Platform}
+
+ \a fh must be opened in binary mode (i.e., the mode string must contain
+ 'b', as in "rb" or "wb") when accessing files and other random-access
+ devices. Qt will translate the end-of-line characters if you pass
+ QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout,
+ are unaffected by this limitation.
+
+ You need to enable support for console applications in order to use the
+ stdin, stdout and stderr streams at the console. To do this, add the
+ following declaration to your application's project file:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 4
+*/
+// ### Qt5: merge this into new overload with a default parameter
+bool QFile::open(FILE *fh, OpenMode mode)
+{
+ return open(fh, mode, DontCloseHandle);
+}
+
+/*!
+ \overload
+
+ Opens the existing file handle \a fh in the given \a mode.
+ Returns true if successful; otherwise returns false.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 3
+
+ When a QFile is opened using this function, behaviour of close() is
+ controlled by the AutoCloseHandle flag.
+ If AutoCloseHandle is specified, and this function succeeds,
+ then calling close() closes the adopted handle.
+ Otherwise, close() does not actually close the file, but only flushes it.
+
+ \bold{Warning:}
+ \list 1
+ \o If \a fh does not refer to a regular file, e.g., it is \c stdin,
+ \c stdout, or \c stderr, you may not be able to seek(). size()
+ returns \c 0 in those cases. See QIODevice::isSequential() for
+ more information.
+ \o Since this function opens the file without specifying the file name,
+ you cannot use this QFile with a QFileInfo.
+ \endlist
+
+ \note For Windows CE you may not be able to call resize().
+
+ \sa close(), {qmake Variable Reference#CONFIG}{qmake Variable Reference}
+
+ \bold{Note for the Windows Platform}
+
+ \a fh must be opened in binary mode (i.e., the mode string must contain
+ 'b', as in "rb" or "wb") when accessing files and other random-access
+ devices. Qt will translate the end-of-line characters if you pass
+ QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout,
+ are unaffected by this limitation.
+
+ You need to enable support for console applications in order to use the
+ stdin, stdout and stderr streams at the console. To do this, add the
+ following declaration to your application's project file:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfile.cpp 4
+*/
+bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
+{
+ Q_D(QFile);
+ if (isOpen()) {
+ qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+ return false;
+ }
+ if (mode & Append)
+ mode |= WriteOnly;
+ unsetError();
+ if ((mode & (ReadOnly | WriteOnly)) == 0) {
+ qWarning("QFile::open: File access not specified");
+ return false;
+ }
+ if (d->openExternalFile(mode, fh, handleFlags)) {
+ QIODevice::open(mode);
+ if (mode & Append) {
+ seek(size());
+ } else {
+ qint64 pos = (qint64)QT_FTELL(fh);
+ if (pos != -1)
+ seek(pos);
+ }
+ return true;
+ }
+ return false;
+}
+
+/*! \fn QFile::open(OpenMode, int)
+
+ Use open(int, OpenMode) instead.
+*/
+
+/*!
+ \overload
+
+ Opens the existing file descriptor \a fd in the given \a mode.
+ Returns true if successful; otherwise returns false.
+
+ When a QFile is opened using this function, close() does not
+ actually close the file.
+
+ The QFile that is opened using this function is automatically set
+ to be in raw mode; this means that the file input/output functions
+ are slow. If you run into performance issues, you should try to
+ use one of the other open functions.
+
+ \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin),
+ 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
+ those cases, size() returns \c 0. See QIODevice::isSequential()
+ for more information.
+
+ \warning For Windows CE you may not be able to call seek(), setSize(),
+ fileTime(). size() returns \c 0.
+
+ \warning Since this function opens the file without specifying the file name,
+ you cannot use this QFile with a QFileInfo.
+
+ \sa close()
+*/
+// ### Qt5: merge this into new overload with a default parameter
+bool QFile::open(int fd, OpenMode mode)
+{
+ return open(fd, mode, DontCloseHandle);
+}
+
+/*!
+ \overload
+
+ Opens the existing file descriptor \a fd in the given \a mode.
+ Returns true if successful; otherwise returns false.
+
+ When a QFile is opened using this function, behaviour of close() is
+ controlled by the AutoCloseHandle flag.
+ If AutoCloseHandle is specified, and this function succeeds,
+ then calling close() closes the adopted handle.
+ Otherwise, close() does not actually close the file, but only flushes it.
+
+ The QFile that is opened using this function is automatically set
+ to be in raw mode; this means that the file input/output functions
+ are slow. If you run into performance issues, you should try to
+ use one of the other open functions.
+
+ \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin),
+ 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
+ those cases, size() returns \c 0. See QIODevice::isSequential()
+ for more information.
+
+ \warning For Windows CE you may not be able to call seek(), setSize(),
+ fileTime(). size() returns \c 0.
+
+ \warning Since this function opens the file without specifying the file name,
+ you cannot use this QFile with a QFileInfo.
+
+ \sa close()
+*/
+bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
+{
+ Q_D(QFile);
+ if (isOpen()) {
+ qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+ return false;
+ }
+ if (mode & Append)
+ mode |= WriteOnly;
+ unsetError();
+ if ((mode & (ReadOnly | WriteOnly)) == 0) {
+ qWarning("QFile::open: File access not specified");
+ return false;
+ }
+ if (d->openExternalFile(mode, fd, handleFlags)) {
+ QIODevice::open(mode);
+ if (mode & Append) {
+ seek(size());
+ } else {
+ qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
+ if (pos != -1)
+ seek(pos);
+ }
+ return true;
+ }
+ return false;
+}
+
+#ifdef Q_OS_SYMBIAN
+/*!
+ \overload
+
+ Opens the existing file object \a f in the given \a mode.
+ Returns true if successful; otherwise returns false.
+
+ When a QFile is opened using this function, behaviour of close() is
+ controlled by the AutoCloseHandle flag.
+ If AutoCloseHandle is specified, and this function succeeds,
+ then calling close() closes the adopted handle.
+ Otherwise, close() does not actually close the file, but only flushes it.
+
+ \warning If the file handle is adopted from another process,
+ you may not be able to use this QFile with a QFileInfo.
+
+ \sa close()
+*/
+bool QFile::open(const RFile &f, OpenMode mode, FileHandleFlags handleFlags)
+{
+ Q_D(QFile);
+ if (isOpen()) {
+ qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
+ return false;
+ }
+ if (mode & Append)
+ mode |= WriteOnly;
+ unsetError();
+ if ((mode & (ReadOnly | WriteOnly)) == 0) {
+ qWarning("QFile::open: File access not specified");
+ return false;
+ }
+ if (d->openExternalFile(mode, f, handleFlags)) {
+ bool ok = QIODevice::open(mode);
+ if (ok) {
+ if (mode & Append) {
+ ok = seek(size());
+ } else {
+ qint64 pos = 0;
+ TInt err;
+#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
+ err = static_cast<const RFile64&>(f).Seek(ESeekCurrent, pos);
+#else
+ TInt pos32 = 0;
+ err = f.Seek(ESeekCurrent, pos32);
+ pos = pos32;
+#endif
+ ok = ok && (err == KErrNone);
+ ok = ok && seek(pos);
+ }
+ }
+ return ok;
+ }
+ return false;
+}
+#endif
+
+/*!
+ Returns the file handle of the file.
+
+ This is a small positive integer, suitable for use with C library
+ functions such as fdopen() and fcntl(). On systems that use file
+ descriptors for sockets (i.e. Unix systems, but not Windows) the handle
+ can be used with QSocketNotifier as well.
+
+ If the file is not open, or there is an error, handle() returns -1.
+
+ This function is not supported on Windows CE.
+
+ \sa QSocketNotifier
+*/
+
+int
+QFile::handle() const
+{
+ Q_D(const QFile);
+ if (!isOpen() || !d->fileEngine)
+ return -1;
+
+ return d->fileEngine->handle();
+}
+
+/*!
+ \enum QFile::MemoryMapFlags
+ \since 4.4
+
+ This enum describes special options that may be used by the map()
+ function.
+
+ \value NoOptions No options.
+*/
+
+/*!
+ \since 4.4
+ Maps \a size bytes of the file into memory starting at \a offset. A file
+ should be open for a map to succeed but the file does not need to stay
+ open after the memory has been mapped. When the QFile is destroyed
+ or a new file is opened with this object, any maps that have not been
+ unmapped will automatically be unmapped.
+
+ Any mapping options can be passed through \a flags.
+
+ Returns a pointer to the memory or 0 if there is an error.
+
+ \note On Windows CE 5.0 the file will be closed before mapping occurs.
+
+ \sa unmap(), QAbstractFileEngine::supportsExtension()
+ */
+uchar *QFile::map(qint64 offset, qint64 size, MemoryMapFlags flags)
+{
+ Q_D(QFile);
+ if (fileEngine()
+ && d->fileEngine->supportsExtension(QAbstractFileEngine::MapExtension)) {
+ unsetError();
+ uchar *address = d->fileEngine->map(offset, size, flags);
+ if (address == 0)
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ return address;
+ }
+ return 0;
+}
+
+/*!
+ \since 4.4
+ Unmaps the memory \a address.
+
+ Returns true if the unmap succeeds; false otherwise.
+
+ \sa map(), QAbstractFileEngine::supportsExtension()
+ */
+bool QFile::unmap(uchar *address)
+{
+ Q_D(QFile);
+ if (fileEngine()
+ && d->fileEngine->supportsExtension(QAbstractFileEngine::UnMapExtension)) {
+ unsetError();
+ bool success = d->fileEngine->unmap(address);
+ if (!success)
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ return success;
+ }
+ d->setError(PermissionsError, tr("No file engine available or engine does not support UnMapExtension"));
+ return false;
+}
+
+/*!
+ \fn QString QFile::name() const
+
+ Use fileName() instead.
+*/
+
+/*!
+ \fn void QFile::setName(const QString &name)
+
+ Use setFileName() instead.
+*/
+
+/*!
+ Sets the file size (in bytes) \a sz. Returns true if the file if the
+ resize succeeds; false otherwise. If \a sz is larger than the file
+ currently is the new bytes will be set to 0, if \a sz is smaller the
+ file is simply truncated.
+
+ \sa size(), setFileName()
+*/
+
+bool
+QFile::resize(qint64 sz)
+{
+ Q_D(QFile);
+ if (!d->ensureFlushed())
+ return false;
+ fileEngine();
+ if (isOpen() && d->fileEngine->pos() > sz)
+ seek(sz);
+ if(d->fileEngine->setSize(sz)) {
+ unsetError();
+ d->cachedSize = sz;
+ return true;
+ }
+ d->cachedSize = 0;
+ d->setError(QFile::ResizeError, d->fileEngine->errorString());
+ return false;
+}
+
+/*!
+ \overload
+
+ Sets \a fileName to size (in bytes) \a sz. Returns true if the file if
+ the resize succeeds; false otherwise. If \a sz is larger than \a
+ fileName currently is the new bytes will be set to 0, if \a sz is
+ smaller the file is simply truncated.
+
+ \sa resize()
+*/
+
+bool
+QFile::resize(const QString &fileName, qint64 sz)
+{
+ return QFile(fileName).resize(sz);
+}
+
+/*!
+ Returns the complete OR-ed together combination of
+ QFile::Permission for the file.
+
+ \sa setPermissions(), setFileName()
+*/
+
+QFile::Permissions
+QFile::permissions() const
+{
+ QAbstractFileEngine::FileFlags perms = fileEngine()->fileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask;
+ return QFile::Permissions((int)perms); //ewww
+}
+
+/*!
+ \overload
+
+ Returns the complete OR-ed together combination of
+ QFile::Permission for \a fileName.
+*/
+
+QFile::Permissions
+QFile::permissions(const QString &fileName)
+{
+ return QFile(fileName).permissions();
+}
+
+/*!
+ Sets the permissions for the file to the \a permissions specified.
+ Returns true if successful, or false if the permissions cannot be
+ modified.
+
+ \sa permissions(), setFileName()
+*/
+
+bool
+QFile::setPermissions(Permissions permissions)
+{
+ Q_D(QFile);
+ if(fileEngine()->setPermissions(permissions)) {
+ unsetError();
+ return true;
+ }
+ d->setError(QFile::PermissionsError, d->fileEngine->errorString());
+ return false;
+}
+
+/*!
+ \overload
+
+ Sets the permissions for \a fileName file to \a permissions.
+*/
+
+bool
+QFile::setPermissions(const QString &fileName, Permissions permissions)
+{
+ return QFile(fileName).setPermissions(permissions);
+}
+
+static inline qint64 _qfile_writeData(QAbstractFileEngine *engine, QRingBuffer *buffer)
+{
+ qint64 ret = engine->write(buffer->readPointer(), buffer->nextDataBlockSize());
+ if (ret > 0)
+ buffer->free(ret);
+ return ret;
+}
+
+/*!
+ Flushes any buffered data to the file. Returns true if successful;
+ otherwise returns false.
+*/
+
+bool
+QFile::flush()
+{
+ Q_D(QFile);
+ if (!d->fileEngine) {
+ qWarning("QFile::flush: No file engine. Is IODevice open?");
+ return false;
+ }
+
+ if (!d->writeBuffer.isEmpty()) {
+ qint64 size = d->writeBuffer.size();
+ if (_qfile_writeData(d->fileEngine, &d->writeBuffer) != size) {
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::WriteError;
+ d->setError(err, d->fileEngine->errorString());
+ return false;
+ }
+ }
+
+ if (!d->fileEngine->flush()) {
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::WriteError;
+ d->setError(err, d->fileEngine->errorString());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Calls QFile::flush() and closes the file. Errors from flush are ignored.
+
+ \sa QIODevice::close()
+*/
+void
+QFile::close()
+{
+ Q_D(QFile);
+ if(!isOpen())
+ return;
+ bool flushed = flush();
+ QIODevice::close();
+
+ // reset write buffer
+ d->lastWasWrite = false;
+ d->writeBuffer.clear();
+
+ // keep earlier error from flush
+ if (d->fileEngine->close() && flushed)
+ unsetError();
+ else if (flushed)
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+}
+
+/*!
+ Returns the size of the file.
+
+ For regular empty files on Unix (e.g. those in \c /proc), this function
+ returns 0; the contents of such a file are generated on demand in response
+ to you calling read().
+*/
+
+qint64 QFile::size() const
+{
+ Q_D(const QFile);
+ if (!d->ensureFlushed())
+ return 0;
+ d->cachedSize = fileEngine()->size();
+ return d->cachedSize;
+}
+
+/*!
+ \reimp
+*/
+
+qint64 QFile::pos() const
+{
+ return QIODevice::pos();
+}
+
+/*!
+ Returns true if the end of the file has been reached; otherwise returns
+ false.
+
+ For regular empty files on Unix (e.g. those in \c /proc), this function
+ returns true, since the file system reports that the size of such a file is
+ 0. Therefore, you should not depend on atEnd() when reading data from such a
+ file, but rather call read() until no more data can be read.
+*/
+
+bool QFile::atEnd() const
+{
+ Q_D(const QFile);
+
+ // If there's buffered data left, we're not at the end.
+ if (!d->buffer.isEmpty())
+ return false;
+
+ if (!isOpen())
+ return true;
+
+ if (!d->ensureFlushed())
+ return false;
+
+ // If the file engine knows best, say what it says.
+ if (d->fileEngine->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
+ // Check if the file engine supports AtEndExtension, and if it does,
+ // check if the file engine claims to be at the end.
+ return d->fileEngine->atEnd();
+ }
+
+ // if it looks like we are at the end, or if size is not cached,
+ // fall through to bytesAvailable() to make sure.
+ if (pos() < d->cachedSize)
+ return false;
+
+ // Fall back to checking how much is available (will stat files).
+ return bytesAvailable() == 0;
+}
+
+/*!
+ For random-access devices, this function sets the current position
+ to \a pos, returning true on success, or false if an error occurred.
+ For sequential devices, the default behavior is to do nothing and
+ return false.
+
+ Seeking beyond the end of a file:
+ If the position is beyond the end of a file, then seek() shall not
+ immediately extend the file. If a write is performed at this position,
+ then the file shall be extended. The content of the file between the
+ previous end of file and the newly written data is UNDEFINED and
+ varies between platforms and file systems.
+*/
+
+bool QFile::seek(qint64 off)
+{
+ Q_D(QFile);
+ if (!isOpen()) {
+ qWarning("QFile::seek: IODevice is not open");
+ return false;
+ }
+
+ if (!d->ensureFlushed())
+ return false;
+
+ if (!d->fileEngine->seek(off) || !QIODevice::seek(off)) {
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::PositionError;
+ d->setError(err, d->fileEngine->errorString());
+ return false;
+ }
+ unsetError();
+ return true;
+}
+
+/*!
+ \reimp
+*/
+qint64 QFile::readLineData(char *data, qint64 maxlen)
+{
+ Q_D(QFile);
+ if (!d->ensureFlushed())
+ return -1;
+
+ qint64 read;
+ if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) {
+ read = d->fileEngine->readLine(data, maxlen);
+ } else {
+ // Fall back to QIODevice's readLine implementation if the engine
+ // cannot do it faster.
+ read = QIODevice::readLineData(data, maxlen);
+ }
+
+ if (read < maxlen) {
+ // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
+ d->cachedSize = 0;
+ }
+
+ return read;
+}
+
+/*!
+ \reimp
+*/
+
+qint64 QFile::readData(char *data, qint64 len)
+{
+ Q_D(QFile);
+ unsetError();
+ if (!d->ensureFlushed())
+ return -1;
+
+ qint64 read = d->fileEngine->read(data, len);
+ if(read < 0) {
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::ReadError;
+ d->setError(err, d->fileEngine->errorString());
+ }
+
+ if (read < len) {
+ // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
+ d->cachedSize = 0;
+ }
+
+ return read;
+}
+
+/*!
+ \internal
+*/
+bool QFilePrivate::putCharHelper(char c)
+{
+#ifdef QT_NO_QOBJECT
+ return QIODevicePrivate::putCharHelper(c);
+#else
+
+ // Cutoff for code that doesn't only touch the buffer.
+ int writeBufferSize = writeBuffer.size();
+ if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= QFILE_WRITEBUFFER_SIZE
+#ifdef Q_OS_WIN
+ || ((openMode & QIODevice::Text) && c == '\n' && writeBufferSize + 2 >= QFILE_WRITEBUFFER_SIZE)
+#endif
+ ) {
+ return QIODevicePrivate::putCharHelper(c);
+ }
+
+ if (!(openMode & QIODevice::WriteOnly)) {
+ if (openMode == QIODevice::NotOpen)
+ qWarning("QIODevice::putChar: Closed device");
+ else
+ qWarning("QIODevice::putChar: ReadOnly device");
+ return false;
+ }
+
+ // Make sure the device is positioned correctly.
+ const bool sequential = isSequential();
+ if (pos != devicePos && !sequential && !q_func()->seek(pos))
+ return false;
+
+ lastWasWrite = true;
+
+ int len = 1;
+#ifdef Q_OS_WIN
+ if ((openMode & QIODevice::Text) && c == '\n') {
+ ++len;
+ *writeBuffer.reserve(1) = '\r';
+ }
+#endif
+
+ // Write to buffer.
+ *writeBuffer.reserve(1) = c;
+
+ if (!sequential) {
+ pos += len;
+ devicePos += len;
+ if (!buffer.isEmpty())
+ buffer.skip(len);
+ }
+
+ return true;
+#endif
+}
+
+/*!
+ \reimp
+*/
+
+qint64
+QFile::writeData(const char *data, qint64 len)
+{
+ Q_D(QFile);
+ unsetError();
+ d->lastWasWrite = true;
+ bool buffered = !(d->openMode & Unbuffered);
+
+ // Flush buffered data if this read will overflow.
+ if (buffered && (d->writeBuffer.size() + len) > QFILE_WRITEBUFFER_SIZE) {
+ if (!flush())
+ return -1;
+ }
+
+ // Write directly to the engine if the block size is larger than
+ // the write buffer size.
+ if (!buffered || len > QFILE_WRITEBUFFER_SIZE) {
+ qint64 ret = d->fileEngine->write(data, len);
+ if(ret < 0) {
+ QFile::FileError err = d->fileEngine->error();
+ if(err == QFile::UnspecifiedError)
+ err = QFile::WriteError;
+ d->setError(err, d->fileEngine->errorString());
+ }
+ return ret;
+ }
+
+ // Write to the buffer.
+ char *writePointer = d->writeBuffer.reserve(len);
+ if (len == 1)
+ *writePointer = *data;
+ else
+ ::memcpy(writePointer, data, len);
+ return len;
+}
+
+/*!
+ \internal
+ Returns the QIOEngine for this QFile object.
+*/
+QAbstractFileEngine *QFile::fileEngine() const
+{
+ Q_D(const QFile);
+ if(!d->fileEngine)
+ d->fileEngine = QAbstractFileEngine::create(d->fileName);
+ return d->fileEngine;
+}
+
+/*!
+ Returns the file error status.
+
+ The I/O device status returns an error code. For example, if open()
+ returns false, or a read/write operation returns -1, this function can
+ be called to find out the reason why the operation failed.
+
+ \sa unsetError()
+*/
+
+QFile::FileError
+QFile::error() const
+{
+ Q_D(const QFile);
+ return d->error;
+}
+
+/*!
+ Sets the file's error to QFile::NoError.
+
+ \sa error()
+*/
+void
+QFile::unsetError()
+{
+ Q_D(QFile);
+ d->setError(QFile::NoError);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h
new file mode 100644
index 0000000000..41835342f4
--- /dev/null
+++ b/src/corelib/io/qfile.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILE_H
+#define QFILE_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qstring.h>
+#include <stdio.h>
+#ifdef Q_OS_SYMBIAN
+#include <f32file.h>
+#endif
+
+#ifdef open
+#error qfile.h must be included before any header file that defines open
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QAbstractFileEngine;
+class QFilePrivate;
+
+class Q_CORE_EXPORT QFile : public QIODevice
+{
+#ifndef QT_NO_QOBJECT
+ Q_OBJECT
+#endif
+ Q_DECLARE_PRIVATE(QFile)
+
+public:
+
+ enum FileError {
+ NoError = 0,
+ ReadError = 1,
+ WriteError = 2,
+ FatalError = 3,
+ ResourceError = 4,
+ OpenError = 5,
+ AbortError = 6,
+ TimeOutError = 7,
+ UnspecifiedError = 8,
+ RemoveError = 9,
+ RenameError = 10,
+ PositionError = 11,
+ ResizeError = 12,
+ PermissionsError = 13,
+ CopyError = 14
+#ifdef QT3_SUPPORT
+ , ConnectError = 30
+#endif
+ };
+
+ enum Permission {
+ ReadOwner = 0x4000, WriteOwner = 0x2000, ExeOwner = 0x1000,
+ ReadUser = 0x0400, WriteUser = 0x0200, ExeUser = 0x0100,
+ ReadGroup = 0x0040, WriteGroup = 0x0020, ExeGroup = 0x0010,
+ ReadOther = 0x0004, WriteOther = 0x0002, ExeOther = 0x0001
+ };
+ Q_DECLARE_FLAGS(Permissions, Permission)
+
+ enum FileHandleFlag {
+ AutoCloseHandle = 0x0001,
+ DontCloseHandle = 0
+ };
+ Q_DECLARE_FLAGS(FileHandleFlags, FileHandleFlag)
+
+ QFile();
+ QFile(const QString &name);
+#ifndef QT_NO_QOBJECT
+ explicit QFile(QObject *parent);
+ QFile(const QString &name, QObject *parent);
+#endif
+ ~QFile();
+
+ FileError error() const;
+ void unsetError();
+
+ QString fileName() const;
+ void setFileName(const QString &name);
+
+ typedef QByteArray (*EncoderFn)(const QString &fileName);
+ typedef QString (*DecoderFn)(const QByteArray &localfileName);
+ static QByteArray encodeName(const QString &fileName);
+ static QString decodeName(const QByteArray &localFileName);
+ inline static QString decodeName(const char *localFileName)
+ { return decodeName(QByteArray(localFileName)); }
+ static void setEncodingFunction(EncoderFn);
+ static void setDecodingFunction(DecoderFn);
+
+ bool exists() const;
+ static bool exists(const QString &fileName);
+
+ QString readLink() const;
+ static QString readLink(const QString &fileName);
+ inline QString symLinkTarget() const { return readLink(); }
+ inline static QString symLinkTarget(const QString &fileName) { return readLink(fileName); }
+
+ bool remove();
+ static bool remove(const QString &fileName);
+
+ bool rename(const QString &newName);
+ static bool rename(const QString &oldName, const QString &newName);
+
+ bool link(const QString &newName);
+ static bool link(const QString &oldname, const QString &newName);
+
+ bool copy(const QString &newName);
+ static bool copy(const QString &fileName, const QString &newName);
+
+ bool isSequential() const;
+
+ bool open(OpenMode flags);
+ bool open(FILE *f, OpenMode flags);
+ bool open(int fd, OpenMode flags);
+#ifdef Q_OS_SYMBIAN
+ bool open(const RFile &f, OpenMode flags, FileHandleFlags handleFlags = DontCloseHandle);
+#endif
+ bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags);
+ bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags);
+ virtual void close();
+
+ qint64 size() const;
+ qint64 pos() const;
+ bool seek(qint64 offset);
+ bool atEnd() const;
+ bool flush();
+
+ bool resize(qint64 sz);
+ static bool resize(const QString &filename, qint64 sz);
+
+ Permissions permissions() const;
+ static Permissions permissions(const QString &filename);
+ bool setPermissions(Permissions permissionSpec);
+ static bool setPermissions(const QString &filename, Permissions permissionSpec);
+
+ int handle() const;
+
+ enum MemoryMapFlags {
+ NoOptions = 0
+ };
+
+ uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
+ bool unmap(uchar *address);
+
+ virtual QAbstractFileEngine *fileEngine() const;
+
+#ifdef QT3_SUPPORT
+ typedef Permission PermissionSpec;
+ inline QT3_SUPPORT QString name() const { return fileName(); }
+ inline QT3_SUPPORT void setName(const QString &aName) { setFileName(aName); }
+ inline QT3_SUPPORT bool open(OpenMode aFlags, FILE *f) { return open(f, aFlags); }
+ inline QT3_SUPPORT bool open(OpenMode aFlags, int fd) { return open(fd, aFlags); }
+#endif
+
+protected:
+#ifdef QT_NO_QOBJECT
+ QFile(QFilePrivate &dd);
+#else
+ QFile(QFilePrivate &dd, QObject *parent = 0);
+#endif
+
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+ qint64 readLineData(char *data, qint64 maxlen);
+
+private:
+ Q_DISABLE_COPY(QFile)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFile::Permissions)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFILE_H
diff --git a/src/corelib/io/qfile_p.h b/src/corelib/io/qfile_p.h
new file mode 100644
index 0000000000..d647c958d7
--- /dev/null
+++ b/src/corelib/io/qfile_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILE_P_H
+#define QFILE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qabstractfileengine.h"
+#include "private/qiodevice_p.h"
+#include "private/qringbuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QFilePrivate : public QIODevicePrivate
+{
+ Q_DECLARE_PUBLIC(QFile)
+
+protected:
+ QFilePrivate();
+ ~QFilePrivate();
+
+ bool openExternalFile(int flags, int fd, QFile::FileHandleFlags handleFlags);
+ bool openExternalFile(int flags, FILE *fh, QFile::FileHandleFlags handleFlags);
+#ifdef Q_OS_SYMBIAN
+ bool openExternalFile(int flags, const RFile& f, QFile::FileHandleFlags handleFlags);
+#endif
+
+ QString fileName;
+ mutable QAbstractFileEngine *fileEngine;
+
+ bool lastWasWrite;
+ QRingBuffer writeBuffer;
+ inline bool ensureFlushed() const;
+
+ bool putCharHelper(char c);
+
+ QFile::FileError error;
+ void setError(QFile::FileError err);
+ void setError(QFile::FileError err, const QString &errorString);
+ void setError(QFile::FileError err, int errNum);
+
+ mutable qint64 cachedSize;
+
+private:
+ static QFile::EncoderFn encoder;
+ static QFile::DecoderFn decoder;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFILE_P_H
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
new file mode 100644
index 0000000000..6b9c82c41b
--- /dev/null
+++ b/src/corelib/io/qfileinfo.cpp
@@ -0,0 +1,1399 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qfileinfo.h"
+#include "qglobal.h"
+#include "qdir.h"
+#include "qfileinfo_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const
+{
+ if (cache_enabled && !fileNames[(int)name].isNull())
+ return fileNames[(int)name];
+
+ QString ret;
+ if (fileEngine == 0) { // local file; use the QFileSystemEngine directly
+ switch (name) {
+ case QAbstractFileEngine::CanonicalName:
+ case QAbstractFileEngine::CanonicalPathName: {
+ QFileSystemEntry entry = QFileSystemEngine::canonicalName(fileEntry, metaData);
+ if (cache_enabled) { // be smart and store both
+ fileNames[QAbstractFileEngine::CanonicalName] = entry.filePath();
+ fileNames[QAbstractFileEngine::CanonicalPathName] = entry.path();
+ }
+ if (name == QAbstractFileEngine::CanonicalName)
+ ret = entry.filePath();
+ else
+ ret = entry.path();
+ break;
+ }
+ case QAbstractFileEngine::LinkName:
+ ret = QFileSystemEngine::getLinkTarget(fileEntry, metaData).filePath();
+ break;
+ case QAbstractFileEngine::BundleName:
+ ret = QFileSystemEngine::bundleName(fileEntry);
+ break;
+ case QAbstractFileEngine::AbsoluteName:
+ case QAbstractFileEngine::AbsolutePathName: {
+ QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry);
+ if (cache_enabled) { // be smart and store both
+ fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath();
+ fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path();
+ }
+ if (name == QAbstractFileEngine::AbsoluteName)
+ ret = entry.filePath();
+ else
+ ret = entry.path();
+ break;
+ }
+ default: break;
+ }
+ } else {
+ ret = fileEngine->fileName(name);
+ }
+ if (ret.isNull())
+ ret = QLatin1String("");
+ if (cache_enabled)
+ fileNames[(int)name] = ret;
+ return ret;
+}
+
+QString QFileInfoPrivate::getFileOwner(QAbstractFileEngine::FileOwner own) const
+{
+ if (cache_enabled && !fileOwners[(int)own].isNull())
+ return fileOwners[(int)own];
+ QString ret;
+ if (fileEngine == 0) {
+ switch (own) {
+ case QAbstractFileEngine::OwnerUser:
+ ret = QFileSystemEngine::resolveUserName(fileEntry, metaData);
+ break;
+ case QAbstractFileEngine::OwnerGroup:
+ ret = QFileSystemEngine::resolveGroupName(fileEntry, metaData);
+ break;
+ }
+ } else {
+ ret = fileEngine->owner(own);
+ }
+ if (ret.isNull())
+ ret = QLatin1String("");
+ if (cache_enabled)
+ fileOwners[(int)own] = ret;
+ return ret;
+}
+
+uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) const
+{
+ Q_ASSERT(fileEngine); // should never be called when using the native FS
+ // We split the testing into tests for for LinkType, BundleType, PermsMask
+ // and the rest.
+ // Tests for file permissions on Windows can be slow, expecially on network
+ // paths and NTFS drives.
+ // In order to determine if a file is a symlink or not, we have to lstat().
+ // If we're not interested in that information, we might as well avoid one
+ // extra syscall. Bundle detecton on Mac can be slow, expecially on network
+ // paths, so we separate out that as well.
+
+ QAbstractFileEngine::FileFlags req = 0;
+ uint cachedFlags = 0;
+
+ if (request & (QAbstractFileEngine::FlagsMask | QAbstractFileEngine::TypesMask)) {
+ if (!getCachedFlag(CachedFileFlags)) {
+ req |= QAbstractFileEngine::FlagsMask;
+ req |= QAbstractFileEngine::TypesMask;
+ req &= (~QAbstractFileEngine::LinkType);
+ req &= (~QAbstractFileEngine::BundleType);
+
+ cachedFlags |= CachedFileFlags;
+ }
+
+ if (request & QAbstractFileEngine::LinkType) {
+ if (!getCachedFlag(CachedLinkTypeFlag)) {
+ req |= QAbstractFileEngine::LinkType;
+ cachedFlags |= CachedLinkTypeFlag;
+ }
+ }
+
+ if (request & QAbstractFileEngine::BundleType) {
+ if (!getCachedFlag(CachedBundleTypeFlag)) {
+ req |= QAbstractFileEngine::BundleType;
+ cachedFlags |= CachedBundleTypeFlag;
+ }
+ }
+ }
+
+ if (request & QAbstractFileEngine::PermsMask) {
+ if (!getCachedFlag(CachedPerms)) {
+ req |= QAbstractFileEngine::PermsMask;
+ cachedFlags |= CachedPerms;
+ }
+ }
+
+ if (req) {
+ if (cache_enabled)
+ req &= (~QAbstractFileEngine::Refresh);
+ else
+ req |= QAbstractFileEngine::Refresh;
+
+ QAbstractFileEngine::FileFlags flags = fileEngine->fileFlags(req);
+ fileFlags |= uint(flags);
+ setCachedFlag(cachedFlags);
+ }
+
+ return fileFlags & request;
+}
+
+QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const
+{
+ Q_ASSERT(fileEngine); // should never be called when using the native FS
+ if (!cache_enabled)
+ clearFlags();
+ uint cf;
+ if (request == QAbstractFileEngine::CreationTime)
+ cf = CachedCTime;
+ else if (request == QAbstractFileEngine::ModificationTime)
+ cf = CachedMTime;
+ else
+ cf = CachedATime;
+ if (!getCachedFlag(cf)) {
+ fileTimes[request] = fileEngine->fileTime(request);
+ setCachedFlag(cf);
+ }
+ return fileTimes[request];
+}
+
+//************* QFileInfo
+
+/*!
+ \class QFileInfo
+ \reentrant
+ \brief The QFileInfo class provides system-independent file information.
+
+ \ingroup io
+ \ingroup shared
+
+ QFileInfo provides information about a file's name and position
+ (path) in the file system, its access rights and whether it is a
+ directory or symbolic link, etc. The file's size and last
+ modified/read times are also available. QFileInfo can also be
+ used to obtain information about a Qt \l{resource
+ system}{resource}.
+
+ A QFileInfo can point to a file with either a relative or an
+ absolute file path. Absolute file paths begin with the directory
+ separator "/" (or with a drive specification on Windows). Relative
+ file names begin with a directory name or a file name and specify
+ a path relative to the current working directory. An example of an
+ absolute path is the string "/tmp/quartz". A relative path might
+ look like "src/fatlib". You can use the function isRelative() to
+ check whether a QFileInfo is using a relative or an absolute file
+ path. You can call the function makeAbsolute() to convert a
+ relative QFileInfo's path to an absolute path.
+
+ The file that the QFileInfo works on is set in the constructor or
+ later with setFile(). Use exists() to see if the file exists and
+ size() to get its size.
+
+ The file's type is obtained with isFile(), isDir() and
+ isSymLink(). The symLinkTarget() function provides the name of the file
+ the symlink points to.
+
+ On Unix (including Mac OS X), the symlink has the same size() has
+ the file it points to, because Unix handles symlinks
+ transparently; similarly, opening a symlink using QFile
+ effectively opens the link's target. For example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 0
+
+ On Windows, symlinks (shortcuts) are \c .lnk files. The reported
+ size() is that of the symlink (not the link's target), and
+ opening a symlink using QFile opens the \c .lnk file. For
+ example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 1
+
+ Elements of the file's name can be extracted with path() and
+ fileName(). The fileName()'s parts can be extracted with
+ baseName(), suffix() or completeSuffix(). QFileInfo objects to
+ directories created by Qt classes will not have a trailing file
+ separator. If you wish to use trailing separators in your own file
+ info objects, just append one to the file name given to the constructors
+ or setFile().
+
+ The file's dates are returned by created(), lastModified() and
+ lastRead(). Information about the file's access permissions is
+ obtained with isReadable(), isWritable() and isExecutable(). The
+ file's ownership is available from owner(), ownerId(), group() and
+ groupId(). You can examine a file's permissions and ownership in a
+ single statement using the permission() function.
+
+ \section1 Performance Issues
+
+ Some of QFileInfo's functions query the file system, but for
+ performance reasons, some functions only operate on the
+ file name itself. For example: To return the absolute path of
+ a relative file name, absolutePath() has to query the file system.
+ The path() function, however, can work on the file name directly,
+ and so it is faster.
+
+ \note To speed up performance, QFileInfo caches information about
+ the file.
+
+ To speed up performance, QFileInfo caches information about the
+ file. Because files can be changed by other users or programs, or
+ even by other parts of the same program, there is a function that
+ refreshes the file information: refresh(). If you want to switch
+ off a QFileInfo's caching and force it to access the file system
+ every time you request information from it call setCaching(false).
+
+ \sa QDir, QFile
+*/
+
+/*!
+ \internal
+*/
+QFileInfo::QFileInfo(QFileInfoPrivate *p) : d_ptr(p)
+{
+}
+
+/*!
+ Constructs an empty QFileInfo object.
+
+ Note that an empty QFileInfo object contain no file reference.
+
+ \sa setFile()
+*/
+QFileInfo::QFileInfo() : d_ptr(new QFileInfoPrivate())
+{
+}
+
+/*!
+ Constructs a new QFileInfo that gives information about the given
+ file. The \a file can also include an absolute or relative path.
+
+ \sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
+*/
+QFileInfo::QFileInfo(const QString &file) : d_ptr(new QFileInfoPrivate(file))
+{
+}
+
+/*!
+ Constructs a new QFileInfo that gives information about file \a
+ file.
+
+ If the \a file has a relative path, the QFileInfo will also have a
+ relative path.
+
+ \sa isRelative()
+*/
+QFileInfo::QFileInfo(const QFile &file) : d_ptr(new QFileInfoPrivate(file.fileName()))
+{
+}
+
+/*!
+ Constructs a new QFileInfo that gives information about the given
+ \a file in the directory \a dir.
+
+ If \a dir has a relative path, the QFileInfo will also have a
+ relative path.
+
+ If \a file is an absolute path, then the directory specified
+ by \a dir will be disregarded.
+
+ \sa isRelative()
+*/
+QFileInfo::QFileInfo(const QDir &dir, const QString &file)
+ : d_ptr(new QFileInfoPrivate(dir.filePath(file)))
+{
+}
+
+/*!
+ Constructs a new QFileInfo that is a copy of the given \a fileinfo.
+*/
+QFileInfo::QFileInfo(const QFileInfo &fileinfo)
+ : d_ptr(fileinfo.d_ptr)
+{
+
+}
+
+/*!
+ Destroys the QFileInfo and frees its resources.
+*/
+
+QFileInfo::~QFileInfo()
+{
+}
+
+/*!
+ \fn bool QFileInfo::operator!=(const QFileInfo &fileinfo)
+
+ Returns true if this QFileInfo object refers to a different file
+ than the one specified by \a fileinfo; otherwise returns false.
+
+ \sa operator==()
+*/
+
+/*!
+ \overload
+ \fn bool QFileInfo::operator!=(const QFileInfo &fileinfo) const
+*/
+
+/*!
+ \overload
+*/
+bool QFileInfo::operator==(const QFileInfo &fileinfo) const
+{
+ Q_D(const QFileInfo);
+ // ### Qt 5: understand long and short file names on Windows
+ // ### (GetFullPathName()).
+ if (fileinfo.d_ptr == d_ptr)
+ return true;
+ if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed)
+ return false;
+ Qt::CaseSensitivity sensitive;
+ if (d->fileEngine == 0 || fileinfo.d_ptr->fileEngine == 0) {
+ if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine
+ return false;
+
+ sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ } else {
+ if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive())
+ return false;
+ sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ }
+
+ if (fileinfo.size() != size()) //if the size isn't the same...
+ return false;
+
+ return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0;
+}
+
+/*!
+ Returns true if this QFileInfo object refers to a file in the same
+ location as \a fileinfo; otherwise returns false.
+
+ Note that the result of comparing two empty QFileInfo objects,
+ containing no file references, is undefined.
+
+ \warning This will not compare two different symbolic links
+ pointing to the same file.
+
+ \warning Long and short file names that refer to the same file on Windows
+ are treated as if they referred to different files.
+
+ \sa operator!=()
+*/
+bool QFileInfo::operator==(const QFileInfo &fileinfo)
+{
+ return const_cast<const QFileInfo *>(this)->operator==(fileinfo);
+}
+
+/*!
+ Makes a copy of the given \a fileinfo and assigns it to this QFileInfo.
+*/
+QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo)
+{
+ d_ptr = fileinfo.d_ptr;
+ return *this;
+}
+
+/*!
+ Sets the file that the QFileInfo provides information about to \a
+ file.
+
+ The \a file can also include an absolute or relative file path.
+ Absolute paths begin with the directory separator (e.g. "/" under
+ Unix) or a drive specification (under Windows). Relative file
+ names begin with a directory name or a file name and specify a
+ path relative to the current directory.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 2
+
+ \sa isRelative(), QDir::setCurrent(), QDir::isRelativePath()
+*/
+void QFileInfo::setFile(const QString &file)
+{
+ bool caching = d_ptr.constData()->cache_enabled;
+ *this = QFileInfo(file);
+ d_ptr->cache_enabled = caching;
+}
+
+/*!
+ \overload
+
+ Sets the file that the QFileInfo provides information about to \a
+ file.
+
+ If \a file includes a relative path, the QFileInfo will also have
+ a relative path.
+
+ \sa isRelative()
+*/
+void QFileInfo::setFile(const QFile &file)
+{
+ setFile(file.fileName());
+}
+
+/*!
+ \overload
+
+ Sets the file that the QFileInfo provides information about to \a
+ file in directory \a dir.
+
+ If \a file includes a relative path, the QFileInfo will also
+ have a relative path.
+
+ \sa isRelative()
+*/
+void QFileInfo::setFile(const QDir &dir, const QString &file)
+{
+ setFile(dir.filePath(file));
+}
+
+/*!
+ Returns an absolute path including the file name.
+
+ The absolute path name consists of the full path and the file
+ name. On Unix this will always begin with the root, '/',
+ directory. On Windows this will always begin 'D:/' where D is a
+ drive letter, except for network shares that are not mapped to a
+ drive letter, in which case the path will begin '//sharename/'.
+ QFileInfo will uppercase drive letters. Note that QDir does not do
+ this. The code snippet below shows this.
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp newstuff
+
+ This function returns the same as filePath(), unless isRelative()
+ is true. In contrast to canonicalFilePath(), symbolic links or
+ redundant "." or ".." elements are not necessarily removed.
+
+ If the QFileInfo is empty it returns QDir::currentPath().
+
+ \sa filePath(), canonicalFilePath(), isRelative()
+*/
+QString QFileInfo::absoluteFilePath() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileName(QAbstractFileEngine::AbsoluteName);
+}
+
+/*!
+ Returns the canonical path including the file name, i.e. an absolute
+ path without symbolic links or redundant "." or ".." elements.
+
+ If the file does not exist, canonicalFilePath() returns an empty
+ string.
+
+ \sa filePath(), absoluteFilePath(), dir()
+*/
+QString QFileInfo::canonicalFilePath() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileName(QAbstractFileEngine::CanonicalName);
+}
+
+
+/*!
+ Returns a file's path absolute path. This doesn't include the
+ file name.
+
+ On Unix the absolute path will always begin with the root, '/',
+ directory. On Windows this will always begin 'D:/' where D is a
+ drive letter, except for network shares that are not mapped to a
+ drive letter, in which case the path will begin '//sharename/'.
+
+ In contrast to canonicalPath() symbolic links or redundant "." or
+ ".." elements are not necessarily removed.
+
+ \warning If the QFileInfo object was created with an empty QString,
+ the behavior of this function is undefined.
+
+ \sa absoluteFilePath(), path(), canonicalPath(), fileName(), isRelative()
+*/
+QString QFileInfo::absolutePath() const
+{
+ Q_D(const QFileInfo);
+
+ if (d->isDefaultConstructed) {
+ return QLatin1String("");
+ } else if (d->fileEntry.isEmpty()) {
+ qWarning("QFileInfo::absolutePath: Constructed with empty filename");
+ return QLatin1String("");
+ }
+ return d->getFileName(QAbstractFileEngine::AbsolutePathName);
+}
+
+/*!
+ Returns the file's path canonical path (excluding the file name),
+ i.e. an absolute path without symbolic links or redundant "." or ".." elements.
+
+ If the file does not exist, canonicalPath() returns an empty string.
+
+ \sa path(), absolutePath()
+*/
+QString QFileInfo::canonicalPath() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileName(QAbstractFileEngine::CanonicalPathName);
+}
+
+/*!
+ Returns the file's path. This doesn't include the file name.
+
+ Note that, if this QFileInfo object is given a path ending in a
+ slash, the name of the file is considered empty and this function
+ will return the entire path.
+
+ \sa filePath(), absolutePath(), canonicalPath(), dir(), fileName(), isRelative()
+*/
+QString QFileInfo::path() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.path();
+}
+
+/*!
+ \fn bool QFileInfo::isAbsolute() const
+
+ Returns true if the file path name is absolute, otherwise returns
+ false if the path is relative.
+
+ \sa isRelative()
+*/
+
+/*!
+ Returns true if the file path name is relative, otherwise returns
+ false if the path is absolute (e.g. under Unix a path is absolute
+ if it begins with a "/").
+
+ \sa isAbsolute()
+*/
+bool QFileInfo::isRelative() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return true;
+ if (d->fileEngine == 0)
+ return d->fileEntry.isRelative();
+ return d->fileEngine->isRelativePath();
+}
+
+/*!
+ Converts the file's path to an absolute path if it is not already in that form.
+ Returns true to indicate that the path was converted; otherwise returns false
+ to indicate that the path was already absolute.
+
+ \sa filePath(), isRelative()
+*/
+bool QFileInfo::makeAbsolute()
+{
+ if (d_ptr.constData()->isDefaultConstructed
+ || !d_ptr.constData()->fileEntry.isRelative())
+ return false;
+
+ setFile(absoluteFilePath());
+ return true;
+}
+
+/*!
+ Returns true if the file exists; otherwise returns false.
+
+ \note If the file is a symlink that points to a non existing
+ file, false is returned.
+*/
+bool QFileInfo::exists() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute);
+ return d->metaData.exists();
+ }
+ return d->getFileFlags(QAbstractFileEngine::ExistsFlag);
+}
+
+/*!
+ Refreshes the information about the file, i.e. reads in information
+ from the file system the next time a cached property is fetched.
+
+ \note On Windows CE, there might be a delay for the file system driver
+ to detect changes on the file.
+*/
+void QFileInfo::refresh()
+{
+ Q_D(QFileInfo);
+ d->clear();
+}
+
+/*!
+ Returns the file name, including the path (which may be absolute
+ or relative).
+
+ \sa absoluteFilePath(), canonicalFilePath(), isRelative()
+*/
+QString QFileInfo::filePath() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.filePath();
+}
+
+/*!
+ Returns the name of the file, excluding the path.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 3
+
+ Note that, if this QFileInfo object is given a path ending in a
+ slash, the name of the file is considered empty.
+
+ \sa isRelative(), filePath(), baseName(), extension()
+*/
+QString QFileInfo::fileName() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.fileName();
+}
+
+/*!
+ \since 4.3
+ Returns the name of the bundle.
+
+ On Mac OS X this returns the proper localized name for a bundle if the
+ path isBundle(). On all other platforms an empty QString is returned.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 4
+
+ \sa isBundle(), filePath(), baseName(), extension()
+*/
+QString QFileInfo::bundleName() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileName(QAbstractFileEngine::BundleName);
+}
+
+/*!
+ Returns the base name of the file without the path.
+
+ The base name consists of all characters in the file up to (but
+ not including) the \e first '.' character.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 5
+
+
+ The base name of a file is computed equally on all platforms, independent
+ of file naming conventions (e.g., ".bashrc" on Unix has an empty base
+ name, and the suffix is "bashrc").
+
+ \sa fileName(), suffix(), completeSuffix(), completeBaseName()
+*/
+QString QFileInfo::baseName() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.baseName();
+}
+
+/*!
+ Returns the complete base name of the file without the path.
+
+ The complete base name consists of all characters in the file up
+ to (but not including) the \e last '.' character.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 6
+
+ \sa fileName(), suffix(), completeSuffix(), baseName()
+*/
+QString QFileInfo::completeBaseName() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.completeBaseName();
+}
+
+/*!
+ Returns the complete suffix of the file.
+
+ The complete suffix consists of all characters in the file after
+ (but not including) the first '.'.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 7
+
+ \sa fileName(), suffix(), baseName(), completeBaseName()
+*/
+QString QFileInfo::completeSuffix() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.completeSuffix();
+}
+
+/*!
+ Returns the suffix of the file.
+
+ The suffix consists of all characters in the file after (but not
+ including) the last '.'.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 8
+
+ The suffix of a file is computed equally on all platforms, independent of
+ file naming conventions (e.g., ".bashrc" on Unix has an empty base name,
+ and the suffix is "bashrc").
+
+ \sa fileName(), completeSuffix(), baseName(), completeBaseName()
+*/
+QString QFileInfo::suffix() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->fileEntry.suffix();
+}
+
+
+/*!
+ Returns the path of the object's parent directory as a QDir object.
+
+ \bold{Note:} The QDir returned always corresponds to the object's
+ parent directory, even if the QFileInfo represents a directory.
+
+ For each of the following, dir() returns a QDir for
+ \c{"~/examples/191697"}.
+
+ \snippet doc/src/snippets/fileinfo/main.cpp 0
+
+ For each of the following, dir() returns a QDir for
+ \c{"."}.
+
+ \snippet doc/src/snippets/fileinfo/main.cpp 1
+
+ \sa absolutePath(), filePath(), fileName(), isRelative(), absoluteDir()
+*/
+QDir QFileInfo::dir() const
+{
+ Q_D(const QFileInfo);
+ // ### Qt5: Maybe rename this to parentDirectory(), considering what it actually do?
+ return QDir(d->fileEntry.path());
+}
+
+/*!
+ Returns the file's absolute path as a QDir object.
+
+ \sa dir(), filePath(), fileName(), isRelative()
+*/
+QDir QFileInfo::absoluteDir() const
+{
+ return QDir(absolutePath());
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use absoluteDir() or the dir() overload that takes no parameters
+ instead.
+*/
+QDir QFileInfo::dir(bool absPath) const
+{
+ if (absPath)
+ return absoluteDir();
+ return dir();
+}
+#endif //QT3_SUPPORT
+
+/*!
+ Returns true if the user can read the file; otherwise returns false.
+
+ \sa isWritable(), isExecutable(), permission()
+*/
+bool QFileInfo::isReadable() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserReadPermission);
+ return (d->metaData.permissions() & QFile::ReadUser) != 0;
+ }
+ return d->getFileFlags(QAbstractFileEngine::ReadUserPerm);
+}
+
+/*!
+ Returns true if the user can write to the file; otherwise returns false.
+
+ \sa isReadable(), isExecutable(), permission()
+*/
+bool QFileInfo::isWritable() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserWritePermission))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserWritePermission);
+ return (d->metaData.permissions() & QFile::WriteUser) != 0;
+ }
+ return d->getFileFlags(QAbstractFileEngine::WriteUserPerm);
+}
+
+/*!
+ Returns true if the file is executable; otherwise returns false.
+
+ \sa isReadable(), isWritable(), permission()
+*/
+bool QFileInfo::isExecutable() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserExecutePermission))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserExecutePermission);
+ return (d->metaData.permissions() & QFile::ExeUser) != 0;
+ }
+ return d->getFileFlags(QAbstractFileEngine::ExeUserPerm);
+}
+
+/*!
+ Returns true if this is a `hidden' file; otherwise returns false.
+
+ \bold{Note:} This function returns true for the special entries
+ "." and ".." on Unix, even though QDir::entryList threats them as shown.
+*/
+bool QFileInfo::isHidden() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::HiddenAttribute))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::HiddenAttribute);
+ return d->metaData.isHidden();
+ }
+ return d->getFileFlags(QAbstractFileEngine::HiddenFlag);
+}
+
+/*!
+ Returns true if this object points to a file or to a symbolic
+ link to a file. Returns false if the
+ object points to something which isn't a file, such as a directory.
+
+ \sa isDir(), isSymLink(), isBundle()
+*/
+bool QFileInfo::isFile() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::FileType))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::FileType);
+ return d->metaData.isFile();
+ }
+ return d->getFileFlags(QAbstractFileEngine::FileType);
+}
+
+/*!
+ Returns true if this object points to a directory or to a symbolic
+ link to a directory; otherwise returns false.
+
+ \sa isFile(), isSymLink(), isBundle()
+*/
+bool QFileInfo::isDir() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::DirectoryType))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::DirectoryType);
+ return d->metaData.isDirectory();
+ }
+ return d->getFileFlags(QAbstractFileEngine::DirectoryType);
+}
+
+
+/*!
+ \since 4.3
+ Returns true if this object points to a bundle or to a symbolic
+ link to a bundle on Mac OS X; otherwise returns false.
+
+ \sa isDir(), isSymLink(), isFile()
+*/
+bool QFileInfo::isBundle() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::BundleType))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::BundleType);
+ return d->metaData.isBundle();
+ }
+ return d->getFileFlags(QAbstractFileEngine::BundleType);
+}
+
+/*!
+ Returns true if this object points to a symbolic link (or to a
+ shortcut on Windows); otherwise returns false.
+
+ On Unix (including Mac OS X), opening a symlink effectively opens
+ the \l{symLinkTarget()}{link's target}. On Windows, it opens the \c
+ .lnk file itself.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 9
+
+ \note If the symlink points to a non existing file, exists() returns
+ false.
+
+ \sa isFile(), isDir(), symLinkTarget()
+*/
+bool QFileInfo::isSymLink() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::LegacyLinkType))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::LegacyLinkType);
+ return d->metaData.isLegacyLink();
+ }
+ return d->getFileFlags(QAbstractFileEngine::LinkType);
+}
+
+/*!
+ Returns true if the object points to a directory or to a symbolic
+ link to a directory, and that directory is the root directory; otherwise
+ returns false.
+*/
+bool QFileInfo::isRoot() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return true;
+ if (d->fileEngine == 0) {
+ if (d->fileEntry.isRoot()) {
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ //the path is a drive root, but the drive may not exist
+ //for backward compatibility, return true only if the drive exists
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ExistsAttribute))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ExistsAttribute);
+ return d->metaData.exists();
+#else
+ return true;
+#endif
+ }
+ return false;
+ }
+ return d->getFileFlags(QAbstractFileEngine::RootFlag);
+}
+
+/*!
+ \fn QString QFileInfo::symLinkTarget() const
+ \since 4.2
+
+ Returns the absolute path to the file or directory a symlink (or shortcut
+ on Windows) points to, or a an empty string if the object isn't a symbolic
+ link.
+
+ This name may not represent an existing file; it is only a string.
+ QFileInfo::exists() returns true if the symlink points to an
+ existing file.
+
+ \sa exists(), isSymLink(), isDir(), isFile()
+*/
+
+/*!
+ \obsolete
+
+ Use symLinkTarget() instead.
+*/
+QString QFileInfo::readLink() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileName(QAbstractFileEngine::LinkName);
+}
+
+/*!
+ Returns the owner of the file. On systems where files
+ do not have owners, or if an error occurs, an empty string is
+ returned.
+
+ This function can be time consuming under Unix (in the order of
+ milliseconds).
+
+ \sa ownerId(), group(), groupId()
+*/
+QString QFileInfo::owner() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileOwner(QAbstractFileEngine::OwnerUser);
+}
+
+/*!
+ Returns the id of the owner of the file.
+
+ On Windows and on systems where files do not have owners this
+ function returns ((uint) -2).
+
+ \sa owner(), group(), groupId()
+*/
+uint QFileInfo::ownerId() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return 0;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserId))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserId);
+ return d->metaData.userId();
+ }
+ return d->fileEngine->ownerId(QAbstractFileEngine::OwnerUser);
+}
+
+/*!
+ Returns the group of the file. On Windows, on systems where files
+ do not have groups, or if an error occurs, an empty string is
+ returned.
+
+ This function can be time consuming under Unix (in the order of
+ milliseconds).
+
+ \sa groupId(), owner(), ownerId()
+*/
+QString QFileInfo::group() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QLatin1String("");
+ return d->getFileOwner(QAbstractFileEngine::OwnerGroup);
+}
+
+/*!
+ Returns the id of the group the file belongs to.
+
+ On Windows and on systems where files do not have groups this
+ function always returns (uint) -2.
+
+ \sa group(), owner(), ownerId()
+*/
+uint QFileInfo::groupId() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return 0;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::GroupId))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::GroupId);
+ return d->metaData.groupId();
+ }
+ return d->fileEngine->ownerId(QAbstractFileEngine::OwnerGroup);
+}
+
+/*!
+ Tests for file permissions. The \a permissions argument can be
+ several flags of type QFile::Permissions OR-ed together to check
+ for permission combinations.
+
+ On systems where files do not have permissions this function
+ always returns true.
+
+ Example:
+ \snippet doc/src/snippets/code/src_corelib_io_qfileinfo.cpp 10
+
+ \sa isReadable(), isWritable(), isExecutable()
+*/
+bool QFileInfo::permission(QFile::Permissions permissions) const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return false;
+ if (d->fileEngine == 0) {
+ // the QFileSystemMetaData::MetaDataFlag and QFile::Permissions overlap, so just static cast.
+ QFileSystemMetaData::MetaDataFlag permissionFlags = static_cast<QFileSystemMetaData::MetaDataFlag>((int)permissions);
+ if (!d->cache_enabled || !d->metaData.hasFlags(permissionFlags))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, permissionFlags);
+ return (d->metaData.permissions() & permissions) == permissions;
+ }
+ return d->getFileFlags(QAbstractFileEngine::FileFlags((int)permissions)) == (uint)permissions;
+}
+
+/*!
+ Returns the complete OR-ed together combination of
+ QFile::Permissions for the file.
+*/
+QFile::Permissions QFileInfo::permissions() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return 0;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::Permissions))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::Permissions);
+ return d->metaData.permissions();
+ }
+ return QFile::Permissions(d->getFileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask);
+}
+
+
+/*!
+ Returns the file size in bytes. If the file does not exist or cannot be
+ fetched, 0 is returned.
+
+ \sa exists()
+*/
+qint64 QFileInfo::size() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return 0;
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::SizeAttribute))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::SizeAttribute);
+ return d->metaData.size();
+ }
+ if (!d->getCachedFlag(QFileInfoPrivate::CachedSize)) {
+ d->setCachedFlag(QFileInfoPrivate::CachedSize);
+ d->fileSize = d->fileEngine->size();
+ }
+ return d->fileSize;
+}
+
+/*!
+ Returns the date and time when the file was created.
+
+ On most Unix systems, this function returns the time of the last
+ status change. A status change occurs when the file is created,
+ but it also occurs whenever the user writes or sets inode
+ information (for example, changing the file permissions).
+
+ If neither creation time nor "last status change" time are not
+ available, returns the same as lastModified().
+
+ \sa lastModified() lastRead()
+*/
+QDateTime QFileInfo::created() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QDateTime();
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime);
+ return d->metaData.creationTime();
+ }
+ return d->getFileTime(QAbstractFileEngine::CreationTime);
+}
+
+/*!
+ Returns the date and time when the file was last modified.
+
+ \sa created() lastRead()
+*/
+QDateTime QFileInfo::lastModified() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QDateTime();
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime);
+ return d->metaData.modificationTime();
+ }
+ return d->getFileTime(QAbstractFileEngine::ModificationTime);
+}
+
+/*!
+ Returns the date and time when the file was last read (accessed).
+
+ On platforms where this information is not available, returns the
+ same as lastModified().
+
+ \sa created() lastModified()
+*/
+QDateTime QFileInfo::lastRead() const
+{
+ Q_D(const QFileInfo);
+ if (d->isDefaultConstructed)
+ return QDateTime();
+ if (d->fileEngine == 0) {
+ if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime))
+ QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime);
+ return d->metaData.accessTime();
+ }
+ return d->getFileTime(QAbstractFileEngine::AccessTime);
+}
+
+/*! \internal
+ Detaches all internal data.
+*/
+void QFileInfo::detach()
+{
+ d_ptr.detach();
+}
+
+/*!
+ Returns true if caching is enabled; otherwise returns false.
+
+ \sa setCaching(), refresh()
+*/
+bool QFileInfo::caching() const
+{
+ Q_D(const QFileInfo);
+ return d->cache_enabled;
+}
+
+/*!
+ If \a enable is true, enables caching of file information. If \a
+ enable is false caching is disabled.
+
+ When caching is enabled, QFileInfo reads the file information from
+ the file system the first time it's needed, but generally not
+ later.
+
+ Caching is enabled by default.
+
+ \sa refresh(), caching()
+*/
+void QFileInfo::setCaching(bool enable)
+{
+ Q_D(QFileInfo);
+ d->cache_enabled = enable;
+}
+
+/*!
+ \fn QString QFileInfo::baseName(bool complete)
+
+ Use completeBaseName() or the baseName() overload that takes no
+ parameters instead.
+*/
+
+/*!
+ \fn QString QFileInfo::extension(bool complete = true) const
+
+ Use completeSuffix() or suffix() instead.
+*/
+
+/*!
+ \fn QString QFileInfo::absFilePath() const
+
+ Use absoluteFilePath() instead.
+*/
+
+/*!
+ \fn QString QFileInfo::dirPath(bool absPath) const
+
+ Use absolutePath() if the absolute path is wanted (\a absPath
+ is true) or path() if it's not necessary (\a absPath is false).
+*/
+
+/*!
+ \fn bool QFileInfo::convertToAbs()
+
+ Use makeAbsolute() instead.
+*/
+
+/*!
+ \enum QFileInfo::Permission
+
+ \compat
+
+ \value ReadOwner
+ \value WriteOwner
+ \value ExeOwner
+ \value ReadUser
+ \value WriteUser
+ \value ExeUser
+ \value ReadGroup
+ \value WriteGroup
+ \value ExeGroup
+ \value ReadOther
+ \value WriteOther
+ \value ExeOther
+*/
+
+/*!
+ \fn bool QFileInfo::permission(PermissionSpec permissions) const
+ \compat
+
+ Use permission() instead.
+*/
+
+/*!
+ \typedef QFileInfoList
+ \relates QFileInfo
+
+ Synonym for QList<QFileInfo>.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
new file mode 100644
index 0000000000..5cfefb3a95
--- /dev/null
+++ b/src/corelib/io/qfileinfo.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEINFO_H
+#define QFILEINFO_H
+
+#include <QtCore/qfile.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QDir;
+class QDirIteratorPrivate;
+class QDateTime;
+class QFileInfoPrivate;
+
+class Q_CORE_EXPORT QFileInfo
+{
+ friend class QDirIteratorPrivate;
+public:
+ explicit QFileInfo(QFileInfoPrivate *d);
+
+ QFileInfo();
+ QFileInfo(const QString &file);
+ QFileInfo(const QFile &file);
+ QFileInfo(const QDir &dir, const QString &file);
+ QFileInfo(const QFileInfo &fileinfo);
+ ~QFileInfo();
+
+ QFileInfo &operator=(const QFileInfo &fileinfo);
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QFileInfo&operator=(QFileInfo &&other)
+ { qSwap(d_ptr, other.d_ptr); return *this; }
+#endif
+ bool operator==(const QFileInfo &fileinfo); // 5.0 - remove me
+ bool operator==(const QFileInfo &fileinfo) const;
+ inline bool operator!=(const QFileInfo &fileinfo) { return !(operator==(fileinfo)); } // 5.0 - remove me
+ inline bool operator!=(const QFileInfo &fileinfo) const { return !(operator==(fileinfo)); }
+
+ void setFile(const QString &file);
+ void setFile(const QFile &file);
+ void setFile(const QDir &dir, const QString &file);
+ bool exists() const;
+ void refresh();
+
+ QString filePath() const;
+ QString absoluteFilePath() const;
+ QString canonicalFilePath() const;
+ QString fileName() const;
+ QString baseName() const;
+ QString completeBaseName() const;
+ QString suffix() const;
+ QString bundleName() const;
+ QString completeSuffix() const;
+
+ QString path() const;
+ QString absolutePath() const;
+ QString canonicalPath() const;
+ QDir dir() const;
+ QDir absoluteDir() const;
+
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isExecutable() const;
+ bool isHidden() const;
+
+ bool isRelative() const;
+ inline bool isAbsolute() const { return !isRelative(); }
+ bool makeAbsolute();
+
+ bool isFile() const;
+ bool isDir() const;
+ bool isSymLink() const;
+ bool isRoot() const;
+ bool isBundle() const;
+
+ QString readLink() const;
+ inline QString symLinkTarget() const { return readLink(); }
+
+ QString owner() const;
+ uint ownerId() const;
+ QString group() const;
+ uint groupId() const;
+
+ bool permission(QFile::Permissions permissions) const;
+ QFile::Permissions permissions() const;
+
+ qint64 size() const;
+
+ QDateTime created() const;
+ QDateTime lastModified() const;
+ QDateTime lastRead() const;
+
+ void detach();
+
+ bool caching() const;
+ void setCaching(bool on);
+
+#ifdef QT3_SUPPORT
+ enum Permission {
+ ReadOwner = QFile::ReadOwner, WriteOwner = QFile::WriteOwner, ExeOwner = QFile::ExeOwner,
+ ReadUser = QFile::ReadUser, WriteUser = QFile::WriteUser, ExeUser = QFile::ExeUser,
+ ReadGroup = QFile::ReadGroup, WriteGroup = QFile::WriteGroup, ExeGroup = QFile::ExeGroup,
+ ReadOther = QFile::ReadOther, WriteOther = QFile::WriteOther, ExeOther = QFile::ExeOther
+ };
+ Q_DECLARE_FLAGS(PermissionSpec, Permission)
+
+ inline QT3_SUPPORT QString baseName(bool complete) {
+ if(complete)
+ return completeBaseName();
+ return baseName();
+ }
+ inline QT3_SUPPORT QString extension(bool complete = true) const {
+ if(complete)
+ return completeSuffix();
+ return suffix();
+ }
+ inline QT3_SUPPORT QString absFilePath() const { return absoluteFilePath(); }
+
+ inline QT3_SUPPORT QString dirPath(bool absPath = false) const {
+ if(absPath)
+ return absolutePath();
+ return path();
+ }
+ QT3_SUPPORT QDir dir(bool absPath) const;
+ inline QT3_SUPPORT bool convertToAbs() { return makeAbsolute(); }
+#if !defined(Q_NO_TYPESAFE_FLAGS)
+ inline QT3_SUPPORT bool permission(PermissionSpec permissions) const
+ { return permission(QFile::Permissions(static_cast<int>(permissions))); }
+#endif
+#endif
+
+protected:
+ QSharedDataPointer<QFileInfoPrivate> d_ptr;
+private:
+ inline QFileInfoPrivate* d_func()
+ {
+ detach();
+ return const_cast<QFileInfoPrivate *>(d_ptr.constData());
+ }
+
+ inline const QFileInfoPrivate* d_func() const
+ {
+ return d_ptr.constData();
+ }
+};
+
+Q_DECLARE_TYPEINFO(QFileInfo, Q_MOVABLE_TYPE);
+
+#ifdef QT3_SUPPORT
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFileInfo::PermissionSpec)
+#endif
+
+typedef QList<QFileInfo> QFileInfoList;
+#ifdef QT3_SUPPORT
+typedef QList<QFileInfo>::Iterator QFileInfoListIterator;
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFILEINFO_H
diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h
new file mode 100644
index 0000000000..db904c76bb
--- /dev/null
+++ b/src/corelib/io/qfileinfo_p.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEINFO_P_H
+#define QFILEINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfileinfo.h"
+#include "qabstractfileengine.h"
+#include "qdatetime.h"
+#include "qatomic.h"
+#include "qshareddata.h"
+#include "qfilesystemengine_p.h"
+
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFileInfoPrivate : public QSharedData
+{
+public:
+ enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
+ CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
+ CachedSize =0x08, CachedPerms=0x80 };
+
+ inline QFileInfoPrivate()
+ : QSharedData(), fileEngine(0),
+ cachedFlags(0),
+ isDefaultConstructed(true),
+ cache_enabled(true), fileFlags(0), fileSize(0)
+ {}
+ inline QFileInfoPrivate(const QFileInfoPrivate &copy)
+ : QSharedData(copy),
+ fileEntry(copy.fileEntry),
+ metaData(copy.metaData),
+ fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ cachedFlags(0),
+#ifndef QT_NO_FSFILEENGINE
+ isDefaultConstructed(false),
+#else
+ isDefaultConstructed(!fileEngine),
+#endif
+ cache_enabled(copy.cache_enabled), fileFlags(0), fileSize(0)
+ {}
+ inline QFileInfoPrivate(const QString &file)
+ : fileEntry(QDir::fromNativeSeparators(file)),
+ fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ cachedFlags(0),
+#ifndef QT_NO_FSFILEENGINE
+ isDefaultConstructed(false),
+#else
+ isDefaultConstructed(!fileEngine),
+#endif
+ cache_enabled(true), fileFlags(0), fileSize(0)
+ {
+ }
+
+ inline QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data)
+ : QSharedData(),
+ fileEntry(file),
+ metaData(data),
+ cachedFlags(0),
+ isDefaultConstructed(false),
+ cache_enabled(true), fileFlags(0), fileSize(0)
+ {
+ }
+
+ inline void clearFlags() const {
+ fileFlags = 0;
+ cachedFlags = 0;
+ if (fileEngine)
+ (void)fileEngine->fileFlags(QAbstractFileEngine::Refresh);
+ }
+ inline void clear() {
+ metaData.clear();
+ clearFlags();
+ for (int i = QAbstractFileEngine::NFileNames - 1 ; i >= 0 ; --i)
+ fileNames[i].clear();
+ fileOwners[1].clear();
+ fileOwners[0].clear();
+ }
+
+ uint getFileFlags(QAbstractFileEngine::FileFlags) const;
+ QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
+ QString getFileName(QAbstractFileEngine::FileName) const;
+ QString getFileOwner(QAbstractFileEngine::FileOwner own) const;
+
+ QFileSystemEntry fileEntry;
+ mutable QFileSystemMetaData metaData;
+
+ QScopedPointer<QAbstractFileEngine> const fileEngine;
+
+ mutable QString fileNames[QAbstractFileEngine::NFileNames];
+ mutable QString fileOwners[2];
+
+ mutable uint cachedFlags : 30;
+ bool const isDefaultConstructed : 1; // QFileInfo is a default constructed instance
+ bool cache_enabled : 1;
+ mutable uint fileFlags;
+ mutable qint64 fileSize;
+ mutable QDateTime fileTimes[3];
+ inline bool getCachedFlag(uint c) const
+ { return cache_enabled ? (cachedFlags & c) : 0; }
+ inline void setCachedFlag(uint c) const
+ { if (cache_enabled) cachedFlags |= c; }
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QFILEINFO_P_H
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
new file mode 100644
index 0000000000..00c33bd797
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -0,0 +1,391 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemengine_p.h"
+#include <QtCore/qdir.h>
+#include <QtCore/qset.h>
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/private/qabstractfileengine_p.h>
+#ifdef QT_BUILD_CORE_LIB
+#include <QtCore/private/qresource_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ Returns the canonicalized form of \a path (i.e., with all symlinks
+ resolved, and all redundant path elements removed.
+*/
+QString QFileSystemEngine::slowCanonicalized(const QString &path)
+{
+ if (path.isEmpty())
+ return path;
+
+ QFileInfo fi;
+ const QChar slash(QLatin1Char('/'));
+ QString tmpPath = path;
+ int separatorPos = 0;
+ QSet<QString> nonSymlinks;
+ QSet<QString> known;
+
+ known.insert(path);
+ do {
+#ifdef Q_OS_WIN
+ if (separatorPos == 0) {
+ if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
+ // UNC, skip past the first two elements
+ separatorPos = tmpPath.indexOf(slash, 2);
+ } else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
+ // volume root, skip since it can not be a symlink
+ separatorPos = 2;
+ }
+ }
+ if (separatorPos != -1)
+#endif
+ separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
+ QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
+ if (
+#ifdef Q_OS_SYMBIAN
+ // Symbian doesn't support directory symlinks, so do not check for link unless we
+ // are handling the last path element. This not only slightly improves performance,
+ // but also saves us from lot of unnecessary platform security check failures
+ // when dealing with files under *:/private directories.
+ separatorPos == -1 &&
+#endif
+ !nonSymlinks.contains(prefix)) {
+ fi.setFile(prefix);
+ if (fi.isSymLink()) {
+ QString target = fi.symLinkTarget();
+ if(QFileInfo(target).isRelative())
+ target = fi.absolutePath() + slash + target;
+ if (separatorPos != -1) {
+ if (fi.isDir() && !target.endsWith(slash))
+ target.append(slash);
+ target.append(tmpPath.mid(separatorPos));
+ }
+ tmpPath = QDir::cleanPath(target);
+ separatorPos = 0;
+
+ if (known.contains(tmpPath))
+ return QString();
+ known.insert(tmpPath);
+ } else {
+ nonSymlinks.insert(prefix);
+ }
+ }
+ } while (separatorPos != -1);
+
+ return QDir::cleanPath(tmpPath);
+}
+
+static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
+{
+ if (resolvingEntry) {
+ if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
+ || !data.exists()) {
+ data.clear();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
+{
+ if (resolvingEntry) {
+ if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
+ delete engine;
+ engine = 0;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QAbstractFileEngine *&engine, bool resolvingEntry = false)
+{
+ QString const &filePath = entry.filePath();
+ if ((engine = qt_custom_file_engine_handler_create(filePath)))
+ return _q_checkEntry(engine, resolvingEntry);
+
+#if defined(QT_BUILD_CORE_LIB)
+ for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
+ QChar const ch = filePath[prefixSeparator];
+ if (ch == QLatin1Char('/'))
+ break;
+
+ if (ch == QLatin1Char(':')) {
+ if (prefixSeparator == 0) {
+ engine = new QResourceFileEngine(filePath);
+ return _q_checkEntry(engine, resolvingEntry);
+ }
+
+ if (prefixSeparator == 1)
+ break;
+
+ const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
+ for (int i = 0; i < paths.count(); i++) {
+ entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)));
+ // Recurse!
+ if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
+ return true;
+ }
+
+ // entry may have been clobbered at this point.
+ return false;
+ }
+
+ // There's no need to fully validate the prefix here. Consulting the
+ // unicode tables could be expensive and validation is already
+ // performed in QDir::setSearchPaths.
+ //
+ // if (!ch.isLetterOrNumber())
+ // break;
+ }
+#endif // defined(QT_BUILD_CORE_LIB)
+
+ return _q_checkEntry(entry, data, resolvingEntry);
+}
+
+/*!
+ \internal
+
+ Resolves the \a entry (see QDir::searchPaths) and returns an engine for
+ it, but never a QFSFileEngine.
+
+ \returns a file engine that can be used to access the entry. Returns 0 if
+ QFileSystemEngine API should be used to query and interact with the file
+ system object.
+*/
+QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
+ QFileSystemEntry &entry, QFileSystemMetaData &data) {
+ QFileSystemEntry copy = entry;
+ QAbstractFileEngine *engine = 0;
+
+ if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
+ // Reset entry to resolved copy.
+ entry = copy;
+ else
+ data.clear();
+
+ return engine;
+}
+
+//these unix functions are in this file, because they are shared by symbian port
+//for open C file handles.
+#ifdef Q_OS_UNIX
+//static
+bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
+{
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
+
+ QT_STATBUF statBuffer;
+ if (QT_FSTAT(fd, &statBuffer) == 0) {
+ data.fillFromStatBuf(statBuffer);
+ return true;
+ }
+
+ return false;
+}
+
+void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
+{
+ // Permissions
+ if (statBuffer.st_mode & S_IRUSR)
+ entryFlags |= QFileSystemMetaData::OwnerReadPermission;
+ if (statBuffer.st_mode & S_IWUSR)
+ entryFlags |= QFileSystemMetaData::OwnerWritePermission;
+ if (statBuffer.st_mode & S_IXUSR)
+ entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
+
+ if (statBuffer.st_mode & S_IRGRP)
+ entryFlags |= QFileSystemMetaData::GroupReadPermission;
+ if (statBuffer.st_mode & S_IWGRP)
+ entryFlags |= QFileSystemMetaData::GroupWritePermission;
+ if (statBuffer.st_mode & S_IXGRP)
+ entryFlags |= QFileSystemMetaData::GroupExecutePermission;
+
+ if (statBuffer.st_mode & S_IROTH)
+ entryFlags |= QFileSystemMetaData::OtherReadPermission;
+ if (statBuffer.st_mode & S_IWOTH)
+ entryFlags |= QFileSystemMetaData::OtherWritePermission;
+ if (statBuffer.st_mode & S_IXOTH)
+ entryFlags |= QFileSystemMetaData::OtherExecutePermission;
+
+ // Type
+ if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
+ entryFlags |= QFileSystemMetaData::FileType;
+ else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
+ entryFlags |= QFileSystemMetaData::DirectoryType;
+ else
+ entryFlags |= QFileSystemMetaData::SequentialType;
+
+ // Attributes
+ entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ size_ = statBuffer.st_size;
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) \
+ && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (statBuffer.st_flags & UF_HIDDEN) {
+ entryFlags |= QFileSystemMetaData::HiddenAttribute;
+ knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
+ }
+#endif
+
+ // Times
+#ifdef Q_OS_SYMBIAN
+ modificationTime_ = qt_symbian_time_t_To_TTime(statBuffer.st_mtime);
+#else
+ creationTime_ = statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime;
+ modificationTime_ = statBuffer.st_mtime;
+ accessTime_ = statBuffer.st_atime;
+ userId_ = statBuffer.st_uid;
+ groupId_ = statBuffer.st_gid;
+#endif
+}
+
+void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
+{
+#if defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) || defined(Q_OS_SYMBIAN)
+ // BSD4 includes Mac OS X
+
+ // ### This will clear all entry flags and knownFlagsMask
+ switch (entry.d_type)
+ {
+ case DT_DIR:
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_BLK:
+ case DT_CHR:
+ case DT_FIFO:
+ case DT_SOCK:
+ // ### System attribute
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::AliasType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_LNK:
+ knownFlagsMask = QFileSystemMetaData::LinkType;
+ entryFlags = QFileSystemMetaData::LinkType;
+ break;
+
+ case DT_REG:
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::FileType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_UNKNOWN:
+ default:
+ clear();
+ }
+#else
+ Q_UNUSED(entry)
+#endif
+}
+
+#endif
+
+//static
+QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
+{
+#if defined (Q_OS_SYMBIAN)
+ Q_UNUSED(entry);
+ Q_UNUSED(metaData);
+ return QString();
+#elif defined(Q_OS_WIN)
+ Q_UNUSED(metaData);
+ return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
+#else //(Q_OS_UNIX)
+ if (!metaData.hasFlags(QFileSystemMetaData::UserId))
+ QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
+ return resolveUserName(metaData.userId());
+#endif
+}
+
+//static
+QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
+{
+#if defined (Q_OS_SYMBIAN)
+ Q_UNUSED(entry);
+ Q_UNUSED(metaData);
+ return QString();
+#elif defined(Q_OS_WIN)
+ Q_UNUSED(metaData);
+ return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
+#else //(Q_OS_UNIX)
+ if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
+ QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
+ return resolveGroupName(metaData.groupId());
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemengine_mac.cpp b/src/corelib/io/qfilesystemengine_mac.cpp
new file mode 100644
index 0000000000..1c0056bff4
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_mac.cpp
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// Mac-specific implementations only!
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
new file mode 100644
index 0000000000..d6033e66e7
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMENGINE_P_H_INCLUDED
+#define QFILESYSTEMENGINE_P_H_INCLUDED
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfile.h"
+#include "qfilesystementry_p.h"
+#include "qfilesystemmetadata_p.h"
+#include <QtCore/private/qsystemerror_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFileSystemEngine
+{
+public:
+ static bool isCaseSensitive();
+
+ static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
+ static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
+ static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
+ static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
+ static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ static QString resolveUserName(uint userId);
+ static QString resolveGroupName(uint groupId);
+#endif
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ static QString bundleName(const QFileSystemEntry &entry);
+#else
+ static QString bundleName(const QFileSystemEntry &entry) { Q_UNUSED(entry) return QString(); }
+#endif
+
+ static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what);
+#if defined(Q_OS_UNIX)
+ static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
+#endif
+#if defined(Q_OS_WIN)
+
+ static bool uncListSharesOnServer(const QString &server, QStringList *list); //Used also by QFSFileEngineIterator::hasNext()
+ static bool fillMetaData(int fd, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what);
+ static bool fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what);
+ static bool fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what);
+ static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
+ static QString nativeAbsoluteFilePath(const QString &path);
+#endif
+ //homePath, rootPath and tempPath shall return clean paths
+ static QString homePath();
+ static QString rootPath();
+ static QString tempPath();
+
+ static bool createDirectory(const QFileSystemEntry &entry, bool createParents);
+ static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents);
+
+ static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
+
+ static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
+ static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
+ static bool removeFile(const QFileSystemEntry &entry, QSystemError &error);
+
+ static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
+ QFileSystemMetaData *data = 0);
+
+ static bool setCurrentPath(const QFileSystemEntry &entry);
+ static QFileSystemEntry currentPath();
+
+ static QAbstractFileEngine *resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry,
+ QFileSystemMetaData &data);
+private:
+ static QString slowCanonicalized(const QString &path);
+#if defined(Q_OS_WIN)
+ static void clearWinStatData(QFileSystemMetaData &data);
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // include guard
diff --git a/src/corelib/io/qfilesystemengine_symbian.cpp b/src/corelib/io/qfilesystemengine_symbian.cpp
new file mode 100644
index 0000000000..41a550aa1f
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_symbian.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemengine_p.h"
+#include "qfsfileengine.h"
+#include <QtCore/private/qcore_symbian_p.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <f32file.h>
+#include <pathinfo.h>
+#include <wchar.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QFileSystemEngine::isCaseSensitive()
+{
+ return false;
+}
+
+//TODO: resolve this with QDir::cleanPath, without breaking the behaviour of that
+//function which is documented only by autotest
+//input: a dirty absolute path, e.g. c:/../../foo/./
+//output: a clean absolute path, e.g. c:/foo/
+static QString symbianCleanAbsolutePath(const QString& path)
+{
+ bool isDir = path.endsWith(QLatin1Char('/'));
+ //using SkipEmptyParts flag to eliminate duplicated slashes
+ QStringList components = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
+ int cdups = 0;
+ for(int i=components.count() - 1; i>=0; --i) {
+ if(components.at(i) == QLatin1String("..")) {
+ components.removeAt(i);
+ cdups++;
+ }
+ else if(components.at(i) == QLatin1String(".")) {
+ components.removeAt(i);
+ }
+ else if(cdups && i > 0) {
+ --cdups;
+ components.removeAt(i);
+ }
+ }
+ QString result = components.join(QLatin1String("/"));
+ if ((isDir&& !result.endsWith(QLatin1Char('/')))
+ || (result.length() == 2 && result.at(1).unicode() == ':'))
+ result.append(QLatin1Char('/'));
+ return result;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
+{
+ Q_UNUSED(data);
+ return link;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
+{
+ if (entry.isEmpty() || entry.isRoot())
+ return entry;
+
+ QFileSystemEntry result = absoluteName(entry);
+ if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
+ fillMetaData(result, data, QFileSystemMetaData::ExistsAttribute);
+ if (!data.exists()) {
+ // file doesn't exist
+ return QFileSystemEntry();
+ } else {
+ return result;
+ }
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
+{
+ QString orig = entry.filePath();
+ const bool isAbsolute = entry.isAbsolute();
+ const bool isDirty = (orig.contains(QLatin1String("/../")) || orig.contains(QLatin1String("/./")) ||
+ orig.contains(QLatin1String("//")) ||
+ orig.endsWith(QLatin1String("/..")) || orig.endsWith(QLatin1String("/.")));
+ if (isAbsolute && !isDirty)
+ return entry;
+
+ const bool isRelative = entry.isRelative();
+ const bool needsDrive = (!orig.isEmpty() && orig.at(0).unicode() == '/');
+ const bool isDriveLetter = !needsDrive && !isAbsolute && !isRelative && orig.length() == 2;
+ const bool isDriveRelative = !needsDrive && !isAbsolute && !isRelative && orig.length() > 2;
+
+ QString result;
+ if (needsDrive || isDriveLetter || isDriveRelative || !isAbsolute || orig.isEmpty()) {
+ QFileSystemEntry cur(currentPath());
+ if(needsDrive)
+ result = cur.filePath().left(2);
+ else if(isDriveRelative && cur.filePath().at(0) != orig.at(0))
+ result = orig.left(2); // for BC, see tst_QFileInfo::absolutePath(<not current drive>:my.dll)
+ else
+ result = cur.filePath();
+ if(isDriveLetter) {
+ result[0] = orig.at(0); //copy drive letter
+ orig.clear();
+ }
+ if(isDriveRelative) {
+ orig = orig.mid(2); //discard the drive specifier from orig
+ }
+ }
+ if (!orig.isEmpty() && !(orig.length() == 1 && orig.at(0).unicode() == '.')) {
+ if (!result.isEmpty() && !result.endsWith(QLatin1Char('/')))
+ result.append(QLatin1Char('/'));
+ result.append(orig);
+ }
+
+ return QFileSystemEntry(symbianCleanAbsolutePath(result), QFileSystemEntry::FromInternalPath());
+}
+
+void QFileSystemMetaData::fillFromTEntry(const TEntry& entry)
+{
+ entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags);
+ knownFlagsMask |= QFileSystemMetaData::SymbianTEntryFlags;
+ //Symbian doesn't have unix type file permissions
+ entryFlags |= QFileSystemMetaData::ReadPermissions;
+ if(!entry.IsReadOnly()) {
+ entryFlags |= QFileSystemMetaData::WritePermissions;
+ }
+ //set the type
+ if(entry.IsDir())
+ entryFlags |= (QFileSystemMetaData::DirectoryType | QFileSystemMetaData::ExecutePermissions);
+ else
+ entryFlags |= QFileSystemMetaData::FileType;
+
+ //set the attributes
+ entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ if(entry.IsHidden())
+ entryFlags |= QFileSystemMetaData::HiddenAttribute;
+
+#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
+ size_ = entry.FileSize();
+#else
+ size_ = (TUint)(entry.iSize);
+#endif
+
+ modificationTime_ = entry.iModified;
+}
+
+void QFileSystemMetaData::fillFromVolumeInfo(const TVolumeInfo& info)
+{
+ entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags);
+ knownFlagsMask |= QFileSystemMetaData::SymbianTEntryFlags;
+ entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ entryFlags |= QFileSystemMetaData::Permissions;
+ if(info.iDrive.iDriveAtt & KDriveAttRom) {
+ entryFlags &= ~(QFileSystemMetaData::WritePermissions);
+ }
+ entryFlags |= QFileSystemMetaData::DirectoryType;
+ size_ = info.iSize;
+ modificationTime_ = qt_symbian_time_t_To_TTime(0);
+}
+
+//static
+bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what)
+{
+ if (what & QFileSystemMetaData::SymbianTEntryFlags) {
+ RFs& fs(qt_s60GetRFs());
+ TInt err;
+ QFileSystemEntry absentry(absoluteName(entry));
+ if (entry.isEmpty()) {
+ err = KErrNotFound;
+ } else if (absentry.isRoot()) {
+ //Root directories don't have an entry, and Entry() returns KErrBadName.
+ //Therefore get information about the volume instead.
+ TInt drive;
+ err = RFs::CharToDrive(TChar(absentry.nativeFilePath().at(0).unicode()), drive);
+ if (!err) {
+ TVolumeInfo info;
+ err = fs.Volume(info, drive);
+ if (!err)
+ data.fillFromVolumeInfo(info);
+ }
+ } else {
+ TEntry ent;
+ err = fs.Entry(qt_QString2TPtrC(absentry.nativeFilePath()), ent);
+ if (!err)
+ data.fillFromTEntry(ent);
+ }
+ if (err) {
+ data.size_ = 0;
+ data.modificationTime_ = TTime(0);
+ data.entryFlags &= ~(QFileSystemMetaData::SymbianTEntryFlags);
+ }
+ //files in /sys/bin on any drive are executable, even though we don't normally have permission to check whether they exist or not
+ if(absentry.filePath().midRef(1,10).compare(QLatin1String(":/sys/bin/"), Qt::CaseInsensitive) == 0)
+ data.entryFlags |= QFileSystemMetaData::ExecutePermissions;
+ }
+ return data.hasFlags(what);
+}
+
+//static
+bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
+{
+ QString abspath = absoluteName(entry).nativeFilePath();
+ if (!abspath.endsWith(QLatin1Char('\\')))
+ abspath.append(QLatin1Char('\\'));
+ TInt r;
+ if (createParents)
+ r = qt_s60GetRFs().MkDirAll(qt_QString2TPtrC(abspath));
+ else
+ r = qt_s60GetRFs().MkDir(qt_QString2TPtrC(abspath));
+ if (createParents && r == KErrAlreadyExists)
+ return true; //# Qt5 - QDir::mkdir returns false for existing dir, QDir::mkpath returns true (should be made consistent in Qt 5)
+ return (r == KErrNone);
+}
+
+//static
+bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
+{
+ QString abspath = absoluteName(entry).nativeFilePath();
+ if (!abspath.endsWith(QLatin1Char('\\')))
+ abspath.append(QLatin1Char('\\'));
+ TPtrC dir(qt_QString2TPtrC(abspath));
+ RFs& fs = qt_s60GetRFs();
+ bool ok = false;
+ //behaviour of FS file engine:
+ //returns true if the directory could be removed
+ //success/failure of removing parent directories does not matter
+ while (KErrNone == fs.RmDir(dir)) {
+ ok = true;
+ if (!removeEmptyParents)
+ break;
+ //RFs::RmDir treats "c:\foo\bar" and "c:\foo\" the same, so it is sufficient to remove the last \ to the end
+ dir.Set(dir.Left(dir.LocateReverse(TChar('\\'))));
+ }
+ return ok;
+}
+
+//static
+bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ Q_UNUSED(source)
+ Q_UNUSED(target)
+ error = QSystemError(KErrNotSupported, QSystemError::NativeError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ //CFileMan is allocated each time because it is not thread-safe
+ CFileMan *fm = 0;
+ TRAPD(err, fm = CFileMan::NewL(qt_s60GetRFs()));
+ if (err == KErrNone) {
+ err = fm->Copy(qt_QString2TPtrC(absoluteName(source).nativeFilePath()), qt_QString2TPtrC(absoluteName(target).nativeFilePath()), 0);
+ delete fm;
+ }
+ if (err == KErrNone)
+ return true;
+ error = QSystemError(err, QSystemError::NativeError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ QString sourcepath = absoluteName(source).nativeFilePath();
+ QString targetpath = absoluteName(target).nativeFilePath();
+ RFs& fs(qt_s60GetRFs());
+ TInt err = fs.Rename(qt_QString2TPtrC(sourcepath), qt_QString2TPtrC(targetpath));
+ if (err == KErrNone)
+ return true;
+ error = QSystemError(err, QSystemError::NativeError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
+{
+ QString targetpath = absoluteName(entry).nativeFilePath();
+ RFs& fs(qt_s60GetRFs());
+ TInt err = fs.Delete(qt_QString2TPtrC(targetpath));
+ if (err == KErrNone)
+ return true;
+ error = QSystemError(err, QSystemError::NativeError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
+{
+ QString targetpath = absoluteName(entry).nativeFilePath();
+ TUint setmask = 0;
+ TUint clearmask = 0;
+ RFs& fs(qt_s60GetRFs());
+ if (permissions & (QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther))
+ clearmask = KEntryAttReadOnly; //if anyone can write, it's not read-only
+ else
+ setmask = KEntryAttReadOnly;
+ TInt err = fs.SetAtt(qt_QString2TPtrC(targetpath), setmask, clearmask);
+ if (data && !err) {
+ data->entryFlags &= ~QFileSystemMetaData::Permissions;
+ data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions));
+ data->knownFlagsMask |= QFileSystemMetaData::Permissions;
+ }
+ if (err == KErrNone)
+ return true;
+ error = QSystemError(err, QSystemError::NativeError);
+ return false;
+}
+
+QString QFileSystemEngine::homePath()
+{
+ QString home = QDir::fromNativeSeparators(qt_TDesC2QString(PathInfo::PhoneMemoryRootPath()));
+ if(home.endsWith(QLatin1Char('/')))
+ home.chop(1);
+ return home;
+}
+
+QString QFileSystemEngine::rootPath()
+{
+ TChar drive;
+ TInt err = RFs::DriveToChar(RFs::GetSystemDrive(), drive); //RFs::GetSystemDriveChar not supported on S60 3.1
+ Q_ASSERT(err == KErrNone); //RFs::GetSystemDrive() shall always return a convertible drive number on a valid OS configuration
+ return QString(QChar(drive)).append(QLatin1String(":/"));
+}
+
+QString QFileSystemEngine::tempPath()
+{
+ return rootPath().append(QLatin1String("system/temp"));
+}
+
+//static
+bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
+{
+ QFileSystemMetaData meta;
+ QFileSystemEntry absname = absoluteName(entry);
+ fillMetaData(absname, meta, QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType);
+ if(!(meta.exists() && meta.isDirectory()))
+ return false;
+
+ RFs& fs = qt_s60GetRFs();
+ QString abspath = absname.nativeFilePath();
+ if(!abspath.endsWith(QLatin1Char('\\')))
+ abspath.append(QLatin1Char('\\'));
+ TInt r = fs.SetSessionPath(qt_QString2TPtrC(abspath));
+ //SetSessionPath succeeds for non existent directory, which is why it's checked above
+ if (r == KErrNone) {
+ __ASSERT_COMPILE(sizeof(wchar_t) == sizeof(unsigned short));
+ //attempt to set open C to the same path
+ r = ::wchdir(reinterpret_cast<const wchar_t *>(absname.filePath().utf16()));
+ if (r < 0)
+ qWarning("failed to sync path to open C");
+ return true;
+ }
+ return false;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::currentPath()
+{
+ TFileName fn;
+ QFileSystemEntry ret;
+ TInt r = qt_s60GetRFs().SessionPath(fn);
+ if(r == KErrNone) {
+ //remove terminating slash from non root paths (session path is clean, absolute and always ends in a \)
+ if(fn.Length() > 3 && fn[fn.Length() - 1] == '\\')
+ fn.SetLength(fn.Length() - 1);
+ ret = QFileSystemEntry(qt_TDesC2QString(fn), QFileSystemEntry::FromNativePath());
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
new file mode 100644
index 0000000000..c9ebaa48bc
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -0,0 +1,660 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qfilesystemengine_p.h"
+#include "qplatformdefs.h"
+#include "qfsfileengine.h"
+#include "qfile.h"
+
+#include <QtCore/qvarlengtharray.h>
+
+#include <stdlib.h> // for realpath()
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+#if defined(Q_OS_MAC)
+# include <QtCore/private/qcore_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+static inline bool _q_isMacHidden(const char *nativePath)
+{
+ OSErr err;
+
+ FSRef fsRef;
+ err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(nativePath),
+ kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
+ if (err != noErr)
+ return false;
+
+ FSCatalogInfo catInfo;
+ err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL);
+ if (err != noErr)
+ return false;
+
+ FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo);
+ return (fileInfo->finderFlags & kIsInvisible);
+}
+#else
+static inline bool _q_isMacHidden(const char *nativePath)
+{
+ Q_UNUSED(nativePath);
+ // no-op
+ return false;
+}
+#endif
+
+bool QFileSystemEngine::isCaseSensitive()
+{
+ return true;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
+{
+#if defined(__GLIBC__) && !defined(PATH_MAX)
+#define PATH_CHUNK_SIZE 256
+ char *s = 0;
+ int len = -1;
+ int size = PATH_CHUNK_SIZE;
+
+ while (1) {
+ s = (char *) ::realloc(s, size);
+ Q_CHECK_PTR(s);
+ len = ::readlink(link.nativeFilePath().constData(), s, size);
+ if (len < 0) {
+ ::free(s);
+ break;
+ }
+ if (len < size) {
+ break;
+ }
+ size *= 2;
+ }
+#else
+ char s[PATH_MAX+1];
+ int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX);
+#endif
+ if (len > 0) {
+ QString ret;
+ if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
+ fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
+ if (data.isDirectory() && s[0] != '/') {
+ QDir parent(link.filePath());
+ parent.cdUp();
+ ret = parent.path();
+ if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
+ ret += QLatin1Char('/');
+ }
+ s[len] = '\0';
+ ret += QFile::decodeName(QByteArray(s));
+#if defined(__GLIBC__) && !defined(PATH_MAX)
+ ::free(s);
+#endif
+
+ if (!ret.startsWith(QLatin1Char('/'))) {
+ if (link.filePath().startsWith(QLatin1Char('/'))) {
+ ret.prepend(link.filePath().left(link.filePath().lastIndexOf(QLatin1Char('/')))
+ + QLatin1Char('/'));
+ } else {
+ ret.prepend(QDir::currentPath() + QLatin1Char('/'));
+ }
+ }
+ ret = QDir::cleanPath(ret);
+ if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
+ ret.chop(1);
+ return QFileSystemEntry(ret);
+ }
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ {
+ FSRef fref;
+ if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(link.filePath())).data(), &fref, 0) == noErr) {
+ // TODO get the meta data info from the QFileSystemMetaData object
+ Boolean isAlias, isFolder;
+ if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) {
+ AliasHandle alias;
+ if (FSNewAlias(0, &fref, &alias) == noErr && alias) {
+ QCFString cfstr;
+ if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr)
+ return QFileSystemEntry(QCFString::toQString(cfstr));
+ }
+ }
+ }
+ }
+#endif
+ return QFileSystemEntry();
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
+{
+ if (entry.isEmpty() || entry.isRoot())
+ return entry;
+
+#if !defined(Q_OS_MAC) && _POSIX_VERSION < 200809L
+ // realpath(X,0) is not supported
+ Q_UNUSED(data);
+ return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
+#else
+ char *ret = 0;
+# if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES)
+ // Mac OS X 10.5.x doesn't support the realpath(X,0) extension we use here.
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) {
+ ret = realpath(entry.nativeFilePath().constData(), (char*)0);
+ } else {
+ // on 10.5 we can use FSRef to resolve the file path.
+ QString path = QDir::cleanPath(entry.filePath());
+ FSRef fsref;
+ if (FSPathMakeRef((const UInt8 *)path.toUtf8().data(), &fsref, 0) == noErr) {
+ CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref);
+ CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle);
+ QString ret = QCFString::toQString(canonicalPath);
+ CFRelease(canonicalPath);
+ CFRelease(urlref);
+ return QFileSystemEntry(ret);
+ }
+ }
+# else
+ ret = realpath(entry.nativeFilePath().constData(), (char*)0);
+# endif
+ if (ret) {
+ data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
+ data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret));
+ free(ret);
+ return QFileSystemEntry(canonicalPath);
+ } else if (errno == ENOENT) { // file doesn't exist
+ data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
+ data.entryFlags &= ~(QFileSystemMetaData::ExistsAttribute);
+ return QFileSystemEntry();
+ }
+ return entry;
+#endif
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
+{
+ if (entry.isAbsolute())
+ return entry;
+
+ QByteArray orig = entry.nativeFilePath();
+ QByteArray result;
+ if (orig.isEmpty() || !orig.startsWith('/')) {
+ QFileSystemEntry cur(currentPath());
+ result = cur.nativeFilePath();
+ }
+ if (!orig.isEmpty() && !(orig.length() == 1 && orig[0] == '.')) {
+ if (!result.isEmpty() && !result.endsWith('/'))
+ result.append('/');
+ result.append(orig);
+ }
+
+ if (result.length() == 1 && result[0] == '/')
+ return QFileSystemEntry(result, QFileSystemEntry::FromNativePath());
+ const bool isDir = result.endsWith('/');
+
+ /* as long as QDir::cleanPath() operates on a QString we have to convert to a string here.
+ * ideally we never convert to a string since that loses information. Please fix after
+ * we get a QByteArray version of QDir::cleanPath()
+ */
+ QFileSystemEntry resultingEntry(result, QFileSystemEntry::FromNativePath());
+ QString stringVersion = QDir::cleanPath(resultingEntry.filePath());
+ if (isDir)
+ stringVersion.append(QLatin1Char('/'));
+ return QFileSystemEntry(stringVersion);
+}
+
+//static
+QString QFileSystemEngine::resolveUserName(uint userId)
+{
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+ int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (size_max == -1)
+ size_max = 1024;
+ QVarLengthArray<char, 1024> buf(size_max);
+#endif
+
+ struct passwd *pw = 0;
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+ struct passwd entry;
+ getpwuid_r(userId, &entry, buf.data(), buf.size(), &pw);
+#else
+ pw = getpwuid(userId);
+#endif
+ if (pw)
+ return QFile::decodeName(QByteArray(pw->pw_name));
+ return QString();
+}
+
+//static
+QString QFileSystemEngine::resolveGroupName(uint groupId)
+{
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+ int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (size_max == -1)
+ size_max = 1024;
+ QVarLengthArray<char, 1024> buf(size_max);
+#endif
+
+ struct group *gr = 0;
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+ size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (size_max == -1)
+ size_max = 1024;
+ buf.resize(size_max);
+ struct group entry;
+ // Some large systems have more members than the POSIX max size
+ // Loop over by doubling the buffer size (upper limit 250k)
+ for (unsigned size = size_max; size < 256000; size += size)
+ {
+ buf.resize(size);
+ // ERANGE indicates that the buffer was too small
+ if (!getgrgid_r(groupId, &entry, buf.data(), buf.size(), &gr)
+ || errno != ERANGE)
+ break;
+ }
+#else
+ gr = getgrgid(groupId);
+#endif
+ if (gr)
+ return QFile::decodeName(QByteArray(gr->gr_name));
+ return QString();
+}
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+//static
+QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
+{
+ QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(entry.filePath()),
+ kCFURLPOSIXPathStyle, true);
+ if (QCFType<CFDictionaryRef> dict = CFBundleCopyInfoDictionaryForURL(url)) {
+ if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
+ if (CFGetTypeID(name) == CFStringGetTypeID())
+ return QCFString::toQString((CFStringRef)name);
+ }
+ }
+ return QString();
+}
+#endif
+
+//static
+bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::BundleType) {
+ if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
+ what |= QFileSystemMetaData::DirectoryType;
+ }
+#endif
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC) \
+ && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (what & QFileSystemMetaData::HiddenAttribute) {
+ // Mac OS >= 10.5: st_flags & UF_HIDDEN
+ what |= QFileSystemMetaData::PosixStatFlags;
+ }
+#endif
+
+ if (what & QFileSystemMetaData::PosixStatFlags)
+ what |= QFileSystemMetaData::PosixStatFlags;
+
+ if (what & QFileSystemMetaData::ExistsAttribute) {
+ // FIXME: Would other queries being performed provide this bit?
+ what |= QFileSystemMetaData::PosixStatFlags;
+ }
+
+ data.entryFlags &= ~what;
+
+ const char * nativeFilePath;
+ int nativeFilePathLength;
+ {
+ const QByteArray &path = entry.nativeFilePath();
+ nativeFilePath = path.constData();
+ nativeFilePathLength = path.size();
+ }
+
+ bool entryExists = true; // innocent until proven otherwise
+
+ QT_STATBUF statBuffer;
+ bool statBufferValid = false;
+ if (what & QFileSystemMetaData::LinkType) {
+ if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) {
+ if (S_ISLNK(statBuffer.st_mode)) {
+ data.entryFlags |= QFileSystemMetaData::LinkType;
+ } else {
+ statBufferValid = true;
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ }
+ } else {
+ entryExists = false;
+ }
+
+ data.knownFlagsMask |= QFileSystemMetaData::LinkType;
+ }
+
+ if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) {
+ if (entryExists && !statBufferValid)
+ statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0);
+
+ if (statBufferValid)
+ data.fillFromStatBuf(statBuffer);
+ else {
+ entryExists = false;
+ data.creationTime_ = 0;
+ data.modificationTime_ = 0;
+ data.accessTime_ = 0;
+ data.size_ = 0;
+ data.userId_ = (uint) -2;
+ data.groupId_ = (uint) -2;
+ }
+
+ // reset the mask
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::ExistsAttribute;
+ }
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::AliasType)
+ {
+ if (entryExists) {
+ FSRef fref;
+ if (FSPathMakeRef((const UInt8 *)nativeFilePath, &fref, NULL) == noErr) {
+ Boolean isAlias, isFolder;
+ if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr) {
+ if (isAlias)
+ data.entryFlags |= QFileSystemMetaData::AliasType;
+ }
+ }
+ }
+ data.knownFlagsMask |= QFileSystemMetaData::AliasType;
+ }
+#endif
+
+ if (what & QFileSystemMetaData::UserPermissions) {
+ // calculate user permissions
+
+ if (entryExists) {
+ if (what & QFileSystemMetaData::UserReadPermission) {
+ if (QT_ACCESS(nativeFilePath, R_OK) == 0)
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ }
+ if (what & QFileSystemMetaData::UserWritePermission) {
+ if (QT_ACCESS(nativeFilePath, W_OK) == 0)
+ data.entryFlags |= QFileSystemMetaData::UserWritePermission;
+ }
+ if (what & QFileSystemMetaData::UserExecutePermission) {
+ if (QT_ACCESS(nativeFilePath, X_OK) == 0)
+ data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
+ }
+ }
+ data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions);
+ }
+
+ if (what & QFileSystemMetaData::HiddenAttribute
+ && !data.isHidden()) {
+ QString fileName = entry.fileName();
+ if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
+ || (entryExists && _q_isMacHidden(nativeFilePath)))
+ data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
+ data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
+ }
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::BundleType) {
+ if (entryExists && data.isDirectory()) {
+ QCFType<CFStringRef> path = CFStringCreateWithBytes(0,
+ (const UInt8*)nativeFilePath, nativeFilePathLength,
+ kCFStringEncodingUTF8, false);
+ QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path,
+ kCFURLPOSIXPathStyle, true);
+
+ UInt32 type, creator;
+ if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
+ data.entryFlags |= QFileSystemMetaData::BundleType;
+ }
+
+ data.knownFlagsMask |= QFileSystemMetaData::BundleType;
+ }
+#endif
+
+ return data.hasFlags(what);
+}
+
+//static
+bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
+{
+ QString dirName = entry.filePath();
+ if (createParents) {
+ dirName = QDir::cleanPath(dirName);
+ for (int oldslash = -1, slash=0; slash != -1; oldslash = slash) {
+ slash = dirName.indexOf(QDir::separator(), oldslash+1);
+ if (slash == -1) {
+ if (oldslash == dirName.length())
+ break;
+ slash = dirName.length();
+ }
+ if (slash) {
+ QByteArray chunk = QFile::encodeName(dirName.left(slash));
+ QT_STATBUF st;
+ if (QT_STAT(chunk, &st) != -1) {
+ if ((st.st_mode & S_IFMT) != S_IFDIR)
+ return false;
+ } else if (QT_MKDIR(chunk, 0777) != 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s
+ if (dirName.endsWith(QLatin1Char('/')))
+ dirName.chop(1);
+#endif
+ return (QT_MKDIR(QFile::encodeName(dirName), 0777) == 0);
+}
+
+//static
+bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
+{
+ if (removeEmptyParents) {
+ QString dirName = QDir::cleanPath(entry.filePath());
+ for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
+ QByteArray chunk = QFile::encodeName(dirName.left(slash));
+ QT_STATBUF st;
+ if (QT_STAT(chunk, &st) != -1) {
+ if ((st.st_mode & S_IFMT) != S_IFDIR)
+ return false;
+ if (::rmdir(chunk) != 0)
+ return oldslash != 0;
+ } else {
+ return false;
+ }
+ slash = dirName.lastIndexOf(QDir::separator(), oldslash-1);
+ }
+ return true;
+ }
+ return rmdir(QFile::encodeName(entry.filePath())) == 0;
+}
+
+//static
+bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
+ return true;
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ Q_UNUSED(source);
+ Q_UNUSED(target);
+ error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented
+ return false;
+}
+
+//static
+bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
+ return true;
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
+{
+ if (unlink(entry.nativeFilePath().constData()) == 0)
+ return true;
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+
+}
+
+//static
+bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
+{
+ mode_t mode = 0;
+ if (permissions & QFile::ReadOwner)
+ mode |= S_IRUSR;
+ if (permissions & QFile::WriteOwner)
+ mode |= S_IWUSR;
+ if (permissions & QFile::ExeOwner)
+ mode |= S_IXUSR;
+ if (permissions & QFile::ReadUser)
+ mode |= S_IRUSR;
+ if (permissions & QFile::WriteUser)
+ mode |= S_IWUSR;
+ if (permissions & QFile::ExeUser)
+ mode |= S_IXUSR;
+ if (permissions & QFile::ReadGroup)
+ mode |= S_IRGRP;
+ if (permissions & QFile::WriteGroup)
+ mode |= S_IWGRP;
+ if (permissions & QFile::ExeGroup)
+ mode |= S_IXGRP;
+ if (permissions & QFile::ReadOther)
+ mode |= S_IROTH;
+ if (permissions & QFile::WriteOther)
+ mode |= S_IWOTH;
+ if (permissions & QFile::ExeOther)
+ mode |= S_IXOTH;
+
+ bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
+ if (success && data) {
+ data->entryFlags &= ~QFileSystemMetaData::Permissions;
+ data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions));
+ data->knownFlagsMask |= QFileSystemMetaData::Permissions;
+ }
+ if (!success)
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return success;
+}
+
+QString QFileSystemEngine::homePath()
+{
+ QString home = QFile::decodeName(qgetenv("HOME"));
+ if (home.isNull())
+ home = rootPath();
+ return QDir::cleanPath(home);
+}
+
+QString QFileSystemEngine::rootPath()
+{
+ return QLatin1String("/");
+}
+
+QString QFileSystemEngine::tempPath()
+{
+#ifdef QT_UNIX_TEMP_PATH_OVERRIDE
+ return QLatin1String(QT_UNIX_TEMP_PATH_OVERRIDE);
+#else
+ QString temp = QFile::decodeName(qgetenv("TMPDIR"));
+ if (temp.isEmpty())
+ temp = QLatin1String("/tmp/");
+ return QDir::cleanPath(temp);
+#endif
+}
+
+bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &path)
+{
+ int r;
+ r = QT_CHDIR(path.nativeFilePath());
+ return r >= 0;
+}
+
+QFileSystemEntry QFileSystemEngine::currentPath()
+{
+ QFileSystemEntry result;
+ QT_STATBUF st;
+ if (QT_STAT(".", &st) == 0) {
+#if defined(__GLIBC__) && !defined(PATH_MAX)
+ char *currentName = ::get_current_dir_name();
+ if (currentName) {
+ result = QFile::decodeName(QByteArray(currentName));
+ ::free(currentName);
+ }
+#else
+ char currentName[PATH_MAX+1];
+ if (::getcwd(currentName, PATH_MAX))
+ result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
+# if defined(QT_DEBUG)
+ if (result.isEmpty())
+ qWarning("QFSFileEngine::currentPath: getcwd() failed");
+# endif
+#endif
+ } else {
+# if defined(QT_DEBUG)
+ qWarning("QFSFileEngine::currentPath: stat(\".\") failed");
+# endif
+ }
+ return result;
+}
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
new file mode 100644
index 0000000000..82c6ebad05
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -0,0 +1,1218 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemengine_p.h"
+
+#define _POSIX_
+#include "qplatformdefs.h"
+#include "qabstractfileengine.h"
+#include "private/qfsfileengine_p.h"
+#include <private/qsystemlibrary_p.h>
+#include <qdebug.h>
+
+#include "qfile.h"
+#include "qdir.h"
+#include "private/qmutexpool_p.h"
+#include "qvarlengtharray.h"
+#include "qdatetime.h"
+#include "qt_windows.h"
+
+#if !defined(Q_OS_WINCE)
+# include <sys/types.h>
+# include <direct.h>
+# include <winioctl.h>
+#else
+# include <types.h>
+#endif
+#include <objbase.h>
+#include <shlobj.h>
+#include <initguid.h>
+#include <accctrl.h>
+#include <ctype.h>
+#include <limits.h>
+#define SECURITY_WIN32
+#include <security.h>
+
+#ifndef SPI_GETPLATFORMTYPE
+#define SPI_GETPLATFORMTYPE 257
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX FILENAME_MAX
+#endif
+
+#ifndef _INTPTR_T_DEFINED
+#ifdef _WIN64
+typedef __int64 intptr_t;
+#else
+#ifdef _W64
+typedef _W64 int intptr_t;
+#else
+typedef INT_PTR intptr_t;
+#endif
+#endif
+#define _INTPTR_T_DEFINED
+#endif
+
+#ifndef INVALID_FILE_ATTRIBUTES
+# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
+#endif
+
+#if !defined(Q_OS_WINCE)
+# if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
+# endif // !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
+
+# ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+# define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384
+# endif
+# ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+# endif
+# ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+# endif
+#endif // !defined(Q_OS_WINCE)
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
+
+#if defined(Q_OS_WINCE)
+static QString qfsPrivateCurrentDir = QLatin1String("");
+// As none of the functions we try to resolve do exist on Windows CE
+// we use QT_NO_LIBRARY to shorten everything up a little bit.
+#define QT_NO_LIBRARY 1
+#endif
+
+#if !defined(QT_NO_LIBRARY)
+QT_BEGIN_INCLUDE_NAMESPACE
+typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*);
+static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0;
+typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE);
+static PtrLookupAccountSidW ptrLookupAccountSidW = 0;
+typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID);
+static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0;
+typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK);
+static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0;
+static TRUSTEE_W currentUserTrusteeW;
+static TRUSTEE_W worldTrusteeW;
+
+typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
+static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0;
+typedef BOOL (WINAPI *PtrGetVolumePathNamesForVolumeNameW)(LPCWSTR,LPWSTR,DWORD,PDWORD);
+static PtrGetVolumePathNamesForVolumeNameW ptrGetVolumePathNamesForVolumeNameW = 0;
+QT_END_INCLUDE_NAMESPACE
+
+
+static void resolveLibs()
+{
+ static bool triedResolve = false;
+ if (!triedResolve) {
+ // need to resolve the security info functions
+
+ // protect initialization
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
+ // check triedResolve again, since another thread may have already
+ // done the initialization
+ if (triedResolve) {
+ // another thread did initialize the security function pointers,
+ // so we shouldn't do it again.
+ return;
+ }
+#endif
+
+ triedResolve = true;
+#if !defined(Q_OS_WINCE)
+ HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32");
+ if (advapiHnd) {
+ ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW");
+ ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW");
+ ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW");
+ ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW");
+ }
+ if (ptrBuildTrusteeWithSidW) {
+ // Create TRUSTEE for current user
+ HANDLE hnd = ::GetCurrentProcess();
+ HANDLE token = 0;
+ if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) {
+ TOKEN_USER tu;
+ DWORD retsize;
+ if (::GetTokenInformation(token, TokenUser, &tu, sizeof(tu), &retsize))
+ ptrBuildTrusteeWithSidW(&currentUserTrusteeW, tu.User.Sid);
+ ::CloseHandle(token);
+ }
+
+ typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*);
+ PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid");
+ typedef PVOID (WINAPI *PtrFreeSid)(PSID);
+ PtrFreeSid ptrFreeSid = (PtrFreeSid)GetProcAddress(advapiHnd, "FreeSid");
+ if (ptrAllocateAndInitializeSid && ptrFreeSid) {
+ // Create TRUSTEE for Everyone (World)
+ SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
+ PSID pWorld = 0;
+ if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorld))
+ ptrBuildTrusteeWithSidW(&worldTrusteeW, pWorld);
+ ptrFreeSid(pWorld);
+ }
+ }
+ HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv");
+ if (userenvHnd)
+ ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW");
+ HINSTANCE kernel32 = LoadLibrary(L"kernel32");
+ if(kernel32)
+ ptrGetVolumePathNamesForVolumeNameW = (PtrGetVolumePathNamesForVolumeNameW)GetProcAddress(kernel32, "GetVolumePathNamesForVolumeNameW");
+#endif
+ }
+}
+#endif // QT_NO_LIBRARY
+
+typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD);
+static PtrNetShareEnum ptrNetShareEnum = 0;
+typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID);
+static PtrNetApiBufferFree ptrNetApiBufferFree = 0;
+typedef struct _SHARE_INFO_1 {
+ LPWSTR shi1_netname;
+ DWORD shi1_type;
+ LPWSTR shi1_remark;
+} SHARE_INFO_1;
+
+
+static bool resolveUNCLibs()
+{
+ static bool triedResolve = false;
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
+ if (triedResolve) {
+ return ptrNetShareEnum && ptrNetApiBufferFree;
+ }
+#endif
+ triedResolve = true;
+#if !defined(Q_OS_WINCE)
+ HINSTANCE hLib = QSystemLibrary::load(L"Netapi32");
+ if (hLib) {
+ ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum");
+ if (ptrNetShareEnum)
+ ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree");
+ }
+#endif
+ }
+ return ptrNetShareEnum && ptrNetApiBufferFree;
+}
+
+static QString readSymLink(const QFileSystemEntry &link)
+{
+ QString result;
+#if !defined(Q_OS_WINCE)
+ HANDLE handle = CreateFile((wchar_t*)link.nativeFilePath().utf16(),
+ FILE_READ_EA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ 0,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ 0);
+ if (handle != INVALID_HANDLE_VALUE) {
+ DWORD bufsize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+ REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)qMalloc(bufsize);
+ DWORD retsize = 0;
+ if (::DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, 0, 0, rdb, bufsize, &retsize, 0)) {
+ if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ int length = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
+ int offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t);
+ const wchar_t* PathBuffer = &rdb->MountPointReparseBuffer.PathBuffer[offset];
+ result = QString::fromWCharArray(PathBuffer, length);
+ } else if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ int length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
+ int offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t);
+ const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset];
+ result = QString::fromWCharArray(PathBuffer, length);
+ }
+ // cut-off "//?/" and "/??/"
+ if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\'))
+ result = result.mid(4);
+ }
+ qFree(rdb);
+ CloseHandle(handle);
+
+#if !defined(QT_NO_LIBRARY)
+ resolveLibs();
+ if (ptrGetVolumePathNamesForVolumeNameW) {
+ QRegExp matchVolName(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"), Qt::CaseInsensitive);
+ if(matchVolName.indexIn(result) == 0) {
+ DWORD len;
+ wchar_t buffer[MAX_PATH];
+ QString volumeName = result.mid(0, matchVolName.matchedLength()).prepend(QLatin1String("\\\\?\\"));
+ if(ptrGetVolumePathNamesForVolumeNameW((wchar_t*)volumeName.utf16(), buffer, MAX_PATH, &len) != 0)
+ result.replace(0,matchVolName.matchedLength(), QString::fromWCharArray(buffer));
+ }
+ }
+#endif
+ }
+#else
+ Q_UNUSED(link);
+#endif // Q_OS_WINCE
+ return result;
+}
+
+static QString readLink(const QFileSystemEntry &link)
+{
+#if !defined(Q_OS_WINCE)
+#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS)
+ QString ret;
+
+ bool neededCoInit = false;
+ IShellLink *psl; // pointer to IShellLink i/f
+ WIN32_FIND_DATA wfd;
+ wchar_t szGotPath[MAX_PATH];
+
+ // Get pointer to the IShellLink interface.
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
+
+ if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
+ neededCoInit = true;
+ CoInitialize(NULL);
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLink, (LPVOID *)&psl);
+ }
+ if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
+ if (SUCCEEDED(hres)) {
+ hres = ppf->Load((LPOLESTR)link.nativeFilePath().utf16(), STGM_READ);
+ //The original path of the link is retrieved. If the file/folder
+ //was moved, the return value still have the old path.
+ if (SUCCEEDED(hres)) {
+ if (psl->GetPath(szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY) == NOERROR)
+ ret = QString::fromWCharArray(szGotPath);
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ if (neededCoInit)
+ CoUninitialize();
+
+ return ret;
+#else
+ Q_UNUSED(link);
+ return QString();
+#endif // QT_NO_LIBRARY
+#else
+ wchar_t target[MAX_PATH];
+ QString result;
+ if (SHGetShortcutTarget((wchar_t*)QFileInfo(link.filePath()).absoluteFilePath().replace(QLatin1Char('/'),QLatin1Char('\\')).utf16(), target, MAX_PATH)) {
+ result = QString::fromWCharArray(target);
+ if (result.startsWith(QLatin1Char('"')))
+ result.remove(0,1);
+ if (result.endsWith(QLatin1Char('"')))
+ result.remove(result.size()-1,1);
+ }
+ return result;
+#endif // Q_OS_WINCE
+}
+
+static bool uncShareExists(const QString &server)
+{
+ // This code assumes the UNC path is always like \\?\UNC\server...
+ QStringList parts = server.split(QLatin1Char('\\'), QString::SkipEmptyParts);
+ if (parts.count() >= 3) {
+ QStringList shares;
+ if (QFileSystemEngine::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(2), &shares))
+ return parts.count() >= 4 ? shares.contains(parts.at(3), Qt::CaseInsensitive) : true;
+ }
+ return false;
+}
+
+static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
+{
+ // path should not end with a trailing slash
+ while (path.endsWith(QLatin1Char('\\')))
+ path.chop(1);
+
+ // can't handle drives
+ if (!path.endsWith(QLatin1Char(':'))) {
+ HANDLE hFind = ::FindFirstFile((wchar_t*)path.utf16(), &findData);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ ::FindClose(hFind);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list)
+{
+ if (resolveUNCLibs()) {
+ SHARE_INFO_1 *BufPtr, *p;
+ DWORD res;
+ DWORD er = 0, tr = 0, resume = 0, i;
+ do {
+ res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume);
+ if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) {
+ p = BufPtr;
+ for (i = 1; i <= er; ++i) {
+ if (list && p->shi1_type == 0)
+ list->append(QString::fromWCharArray(p->shi1_netname));
+ p++;
+ }
+ }
+ ptrNetApiBufferFree(BufPtr);
+ } while (res == ERROR_MORE_DATA);
+ return res == ERROR_SUCCESS;
+ }
+ return false;
+}
+
+void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
+{
+ data.size_ = 0;
+ data.fileAttribute_ = 0;
+ data.creationTime_ = FILETIME();
+ data.lastAccessTime_ = FILETIME();
+ data.lastWriteTime_ = FILETIME();
+}
+
+bool QFileSystemEngine::isCaseSensitive()
+{
+ return false;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
+ QFileSystemMetaData &data)
+{
+ if (data.missingFlags(QFileSystemMetaData::LinkType))
+ QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
+
+ QString ret;
+ if (data.isLnkFile())
+ ret = readLink(link);
+ else if (data.isLink())
+ ret = readSymLink(link);
+ return QFileSystemEntry(ret);
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
+{
+ if (data.missingFlags(QFileSystemMetaData::ExistsAttribute))
+ QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
+
+ if (data.exists())
+ return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
+ else
+ return QFileSystemEntry();
+}
+
+//static
+QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
+{
+ // can be //server or //server/share
+ QString absPath;
+#if !defined(Q_OS_WINCE)
+ QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
+ wchar_t *fileName = 0;
+ DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
+ if (retLen > (DWORD)buf.size()) {
+ buf.resize(retLen);
+ retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
+ }
+ if (retLen != 0)
+ absPath = QString::fromWCharArray(buf.data(), retLen);
+#else
+ if (path.startsWith(QLatin1Char('/')) || path.startsWith(QLatin1Char('\\')))
+ absPath = QDir::toNativeSeparators(path);
+ else
+ absPath = QDir::toNativeSeparators(QDir::cleanPath(qfsPrivateCurrentDir + QLatin1Char('/') + path));
+#endif
+ // This is really ugly, but GetFullPathName strips off whitespace at the end.
+ // If you for instance write ". " in the lineedit of QFileDialog,
+ // (which is an invalid filename) this function will strip the space off and viola,
+ // the file is later reported as existing. Therefore, we re-add the whitespace that
+ // was at the end of path in order to keep the filename invalid.
+ if (!path.isEmpty() && path.at(path.size() - 1) == QLatin1Char(' '))
+ absPath.append(QLatin1Char(' '));
+ return absPath;
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
+{
+ QString ret;
+
+ if (!entry.isRelative()) {
+#if !defined(Q_OS_WINCE)
+ if (entry.isAbsolute()
+ && !entry.filePath().contains(QLatin1String("/../"))
+ && !entry.filePath().contains(QLatin1String("/./"))
+ && !entry.filePath().endsWith(QLatin1String("/.."))
+ && !entry.filePath().endsWith(QLatin1String("/."))) {
+ ret = entry.filePath();
+ } else {
+ ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
+ }
+#else
+ ret = entry.filePath();
+#endif
+ } else {
+ ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
+ }
+
+ // The path should be absolute at this point.
+ // From the docs :
+ // Absolute paths begin with the directory separator "/"
+ // (optionally preceded by a drive specification under Windows).
+ if (ret.at(0) != QLatin1Char('/')) {
+ Q_ASSERT(ret.length() >= 2);
+ Q_ASSERT(ret.at(0).isLetter());
+ Q_ASSERT(ret.at(1) == QLatin1Char(':'));
+
+ // Force uppercase drive letters.
+ ret[0] = ret.at(0).toUpper();
+ }
+ return QFileSystemEntry(ret);
+}
+
+//static
+QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
+{
+ QString name;
+#if !defined(QT_NO_LIBRARY)
+ extern int qt_ntfs_permission_lookup;
+ if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
+ resolveLibs();
+ if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) {
+ PSID pOwner = 0;
+ PSECURITY_DESCRIPTOR pSD;
+ if (ptrGetNamedSecurityInfoW((wchar_t*)entry.nativeFilePath().utf16(), SE_FILE_OBJECT,
+ own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION,
+ own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0,
+ 0, 0, &pSD) == ERROR_SUCCESS) {
+ DWORD lowner = 64;
+ DWORD ldomain = 64;
+ QVarLengthArray<wchar_t, 64> owner(lowner);
+ QVarLengthArray<wchar_t, 64> domain(ldomain);
+ SID_NAME_USE use = SidTypeUnknown;
+ // First call, to determine size of the strings (with '\0').
+ if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner,
+ (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ if (lowner > (DWORD)owner.size())
+ owner.resize(lowner);
+ if (ldomain > (DWORD)domain.size())
+ domain.resize(ldomain);
+ // Second call, try on resized buf-s
+ if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner,
+ (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) {
+ lowner = 0;
+ }
+ } else {
+ lowner = 0;
+ }
+ }
+ if (lowner != 0)
+ name = QString::fromWCharArray(owner.data());
+ LocalFree(pSD);
+ }
+ }
+ }
+#else
+ Q_UNUSED(own);
+#endif
+ return name;
+}
+
+//static
+bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+ QAbstractFileEngine::FileFlags ret = 0;
+
+#if !defined(QT_NO_LIBRARY)
+ if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
+ resolveLibs();
+ if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) {
+ enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 };
+
+ QString fname = entry.filePath();
+ PSID pOwner = 0;
+ PSID pGroup = 0;
+ PACL pDacl;
+ PSECURITY_DESCRIPTOR pSD;
+ DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+ &pOwner, &pGroup, &pDacl, 0, &pSD);
+ if(res == ERROR_SUCCESS) {
+ ACCESS_MASK access_mask;
+ TRUSTEE_W trustee;
+ if (what & QFileSystemMetaData::UserPermissions) { // user
+ data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
+ if(ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
+ access_mask = (ACCESS_MASK)-1;
+ if(access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ if(access_mask & WriteMask)
+ data.entryFlags|= QFileSystemMetaData::UserWritePermission;
+ if(access_mask & ExecMask)
+ data.entryFlags|= QFileSystemMetaData::UserExecutePermission;
+ }
+ if (what & QFileSystemMetaData::OwnerPermissions) { // owner
+ data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
+ ptrBuildTrusteeWithSidW(&trustee, pOwner);
+ if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
+ access_mask = (ACCESS_MASK)-1;
+ if(access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::OwnerReadPermission;
+ if(access_mask & WriteMask)
+ data.entryFlags |= QFileSystemMetaData::OwnerWritePermission;
+ if(access_mask & ExecMask)
+ data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
+ }
+ if (what & QFileSystemMetaData::GroupPermissions) { // group
+ data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions;
+ ptrBuildTrusteeWithSidW(&trustee, pGroup);
+ if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
+ access_mask = (ACCESS_MASK)-1;
+ if(access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::GroupReadPermission;
+ if(access_mask & WriteMask)
+ data.entryFlags |= QFileSystemMetaData::GroupWritePermission;
+ if(access_mask & ExecMask)
+ data.entryFlags |= QFileSystemMetaData::GroupExecutePermission;
+ }
+ if (what & QFileSystemMetaData::OtherPermissions) { // other (world)
+ data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions;
+ if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS)
+ access_mask = (ACCESS_MASK)-1; // ###
+ if(access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::OtherReadPermission;
+ if(access_mask & WriteMask)
+ data.entryFlags |= QFileSystemMetaData::OtherWritePermission;
+ if(access_mask & ExecMask)
+ data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
+ }
+ LocalFree(pSD);
+ }
+ }
+ } else
+#endif
+ {
+ //### what to do with permissions if we don't use NTFS
+ // for now just add all permissions and what about exe missions ??
+ // also qt_ntfs_permission_lookup is now not set by default ... should it ?
+ data.entryFlags |= QFileSystemMetaData::OwnerReadPermission
+ | QFileSystemMetaData::GroupReadPermission
+ | QFileSystemMetaData::OtherReadPermission;
+
+ if (!(data.fileAttribute_ & FILE_ATTRIBUTE_READONLY)) {
+ data.entryFlags |= QFileSystemMetaData::OwnerWritePermission
+ | QFileSystemMetaData::GroupWritePermission
+ | QFileSystemMetaData::OtherWritePermission;
+ }
+
+ QString fname = entry.filePath();
+ QString ext = fname.right(4).toLower();
+ if (data.isDirectory() ||
+ ext == QLatin1String(".exe") || ext == QLatin1String(".com") || ext == QLatin1String(".bat") ||
+ ext == QLatin1String(".pif") || ext == QLatin1String(".cmd")) {
+ data.entryFlags |= QFileSystemMetaData::OwnerExecutePermission | QFileSystemMetaData::GroupExecutePermission
+ | QFileSystemMetaData::OtherExecutePermission | QFileSystemMetaData::UserExecutePermission;
+ }
+ data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions | QFileSystemMetaData::GroupPermissions
+ | QFileSystemMetaData::OtherPermissions | QFileSystemMetaData::UserExecutePermission;
+ // calculate user permissions
+ if (what & QFileSystemMetaData::UserReadPermission) {
+ if (::_waccess((wchar_t*)entry.nativeFilePath().utf16(), R_OK) == 0)
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission;
+ }
+ if (what & QFileSystemMetaData::UserWritePermission) {
+ if (::_waccess((wchar_t*)entry.nativeFilePath().utf16(), W_OK) == 0)
+ data.entryFlags |= QFileSystemMetaData::UserWritePermission;
+ data.knownFlagsMask |= QFileSystemMetaData::UserReadPermission;
+ }
+ }
+
+ return data.hasFlags(what);
+}
+
+static bool tryDriveUNCFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data)
+{
+ bool entryExists = false;
+ DWORD fileAttrib = 0;
+#if !defined(Q_OS_WINCE)
+ if (fname.isDriveRoot()) {
+ // a valid drive ??
+ DWORD drivesBitmask = ::GetLogicalDrives();
+ int drivebit = 1 << (fname.filePath().at(0).toUpper().unicode() - QLatin1Char('A').unicode());
+ if (drivesBitmask & drivebit) {
+ fileAttrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM;
+ entryExists = true;
+ }
+ } else {
+#endif
+ const QString &path = fname.nativeFilePath();
+ bool is_dir = false;
+ if (path.startsWith(QLatin1String("\\\\?\\UNC"))) {
+ // UNC - stat doesn't work for all cases (Windows bug)
+ int s = path.indexOf(path.at(0),7);
+ if (s > 0) {
+ // "\\?\UNC\server\..."
+ s = path.indexOf(path.at(0),s+1);
+ if (s > 0) {
+ // "\\?\UNC\server\share\..."
+ if (s == path.size() - 1) {
+ // "\\?\UNC\server\share\"
+ is_dir = true;
+ } else {
+ // "\\?\UNC\server\share\notfound"
+ }
+ } else {
+ // "\\?\UNC\server\share"
+ is_dir = true;
+ }
+ } else {
+ // "\\?\UNC\server"
+ is_dir = true;
+ }
+ }
+ if (is_dir && uncShareExists(path)) {
+ // looks like a UNC dir, is a dir.
+ fileAttrib = FILE_ATTRIBUTE_DIRECTORY;
+ entryExists = true;
+ }
+#if !defined(Q_OS_WINCE)
+ }
+#endif
+ if (entryExists)
+ data.fillFromFileAttribute(fileAttrib);
+ return entryExists;
+}
+
+static bool tryFindFallback(const QFileSystemEntry &fname, QFileSystemMetaData &data)
+{
+ bool filledData = false;
+ // This assumes the last call to a Windows API failed.
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ WIN32_FIND_DATA findData;
+ if (getFindData(fname.nativeFilePath(), findData)
+ && findData.dwFileAttributes != INVALID_FILE_ATTRIBUTES) {
+ data.fillFromFindData(findData, true, fname.isDriveRoot());
+ filledData = true;
+ }
+ }
+ return filledData;
+}
+
+#if !defined(Q_OS_WINCE)
+//static
+bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+ HANDLE fHandle = (HANDLE)_get_osfhandle(fd);
+ if (fHandle != INVALID_HANDLE_VALUE) {
+ return fillMetaData(fHandle, data, what);
+ }
+ return false;
+}
+#endif
+
+//static
+bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+ data.entryFlags &= ~what;
+ clearWinStatData(data);
+ BY_HANDLE_FILE_INFORMATION fileInfo;
+ UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ if (GetFileInformationByHandle(fHandle , &fileInfo)) {
+ data.fillFromFindInfo(fileInfo);
+ }
+ SetErrorMode(oldmode);
+ return data.hasFlags(what);
+}
+
+//static
+bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+ what |= QFileSystemMetaData::WinLnkType | QFileSystemMetaData::WinStatFlags;
+ data.entryFlags &= ~what;
+
+ QFileSystemEntry fname;
+ data.knownFlagsMask |= QFileSystemMetaData::WinLnkType;
+ if(entry.filePath().endsWith(QLatin1String(".lnk"))) {
+ data.entryFlags |= QFileSystemMetaData::WinLnkType;
+ fname = QFileSystemEntry(readLink(entry));
+ } else {
+ fname = entry;
+ }
+
+ if (fname.isEmpty()) {
+ data.knownFlagsMask |= what;
+ clearWinStatData(data);
+ return false;
+ }
+
+ if (what & QFileSystemMetaData::WinStatFlags) {
+ UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ clearWinStatData(data);
+ WIN32_FIND_DATA findData;
+ // The memory structure for WIN32_FIND_DATA is same as WIN32_FILE_ATTRIBUTE_DATA
+ // for all members used by fillFindData().
+ bool ok = ::GetFileAttributesEx((wchar_t*)fname.nativeFilePath().utf16(), GetFileExInfoStandard,
+ reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *>(&findData));
+ if (ok) {
+ data.fillFromFindData(findData, false, fname.isDriveRoot());
+ } else {
+ if (!tryFindFallback(fname, data))
+ tryDriveUNCFallback(fname, data);
+ }
+ SetErrorMode(oldmode);
+ }
+
+ if (what & QFileSystemMetaData::Permissions)
+ fillPermissions(fname, data, what);
+ if ((what & QFileSystemMetaData::LinkType)
+ && data.missingFlags(QFileSystemMetaData::LinkType)) {
+ data.knownFlagsMask |= QFileSystemMetaData::LinkType;
+ if (data.fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
+ WIN32_FIND_DATA findData;
+ if (getFindData(fname.nativeFilePath(), findData))
+ data.fillFromFindData(findData, true);
+ }
+ }
+ data.knownFlagsMask |= what;
+ return data.hasFlags(what);
+}
+
+static inline bool mkDir(const QString &path)
+{
+#if defined(Q_OS_WINCE)
+ // Unfortunately CreateDirectory returns true for paths longer than
+ // 256, but does not create a directory. It starts to fail, when
+ // path length > MAX_PATH, which is 260 usually on CE.
+ // This only happens on a Windows Mobile device. Windows CE seems
+ // not to be affected by this.
+ static int platformId = 0;
+ if (platformId == 0) {
+ wchar_t platformString[64];
+ if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformString)/sizeof(*platformString),platformString,0)) {
+ if (0 == wcscmp(platformString, L"PocketPC") || 0 == wcscmp(platformString, L"Smartphone"))
+ platformId = 1;
+ else
+ platformId = 2;
+ }
+ }
+ if (platformId == 1 && QFSFileEnginePrivate::longFileName(path).size() > 256)
+ return false;
+#endif
+ return ::CreateDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), 0);
+}
+
+static inline bool rmDir(const QString &path)
+{
+ return ::RemoveDirectory((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
+}
+
+static bool isDirPath(const QString &dirPath, bool *existed)
+{
+ QString path = dirPath;
+ if (path.length() == 2 && path.at(1) == QLatin1Char(':'))
+ path += QLatin1Char('\\');
+
+ DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
+ if (fileAttrib == INVALID_FILE_ATTRIBUTES) {
+ int errorCode = GetLastError();
+ if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
+ WIN32_FIND_DATA findData;
+ if (getFindData(QFSFileEnginePrivate::longFileName(path), findData))
+ fileAttrib = findData.dwFileAttributes;
+ }
+ }
+
+ if (existed)
+ *existed = fileAttrib != INVALID_FILE_ATTRIBUTES;
+
+ if (fileAttrib == INVALID_FILE_ATTRIBUTES)
+ return false;
+
+ return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+//static
+bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
+{
+ QString dirName = entry.filePath();
+ if (createParents) {
+ dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
+ // We spefically search for / so \ would break it..
+ int oldslash = -1;
+ if (dirName.startsWith(QLatin1String("\\\\"))) {
+ // Don't try to create the root path of a UNC path;
+ // CreateDirectory() will just return ERROR_INVALID_NAME.
+ for (int i = 0; i < dirName.size(); ++i) {
+ if (dirName.at(i) != QDir::separator()) {
+ oldslash = i;
+ break;
+ }
+ }
+ if (oldslash != -1)
+ oldslash = dirName.indexOf(QDir::separator(), oldslash);
+ }
+ for (int slash=0; slash != -1; oldslash = slash) {
+ slash = dirName.indexOf(QDir::separator(), oldslash+1);
+ if (slash == -1) {
+ if (oldslash == dirName.length())
+ break;
+ slash = dirName.length();
+ }
+ if (slash) {
+ QString chunk = dirName.left(slash);
+ bool existed = false;
+ if (!isDirPath(chunk, &existed)) {
+ if (!existed) {
+ if (!mkDir(chunk))
+ return false;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+ return mkDir(entry.filePath());
+}
+
+//static
+bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
+{
+ QString dirName = entry.filePath();
+ if (removeEmptyParents) {
+ dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
+ for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
+ QString chunk = dirName.left(slash);
+ if (chunk.length() == 2 && chunk.at(0).isLetter() && chunk.at(1) == QLatin1Char(':'))
+ break;
+ if (!isDirPath(chunk, 0))
+ return false;
+ if (!rmDir(chunk))
+ return oldslash != 0;
+ slash = dirName.lastIndexOf(QDir::separator(), oldslash-1);
+ }
+ return true;
+ }
+ return rmDir(entry.filePath());
+}
+
+//static
+QString QFileSystemEngine::rootPath()
+{
+#if defined(Q_OS_WINCE)
+ QString ret = QLatin1String("/");
+#elif defined(Q_FS_FAT)
+ QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData());
+ if (ret.isEmpty())
+ ret = QLatin1String("c:");
+ ret.append(QLatin1Char('/'));
+#elif defined(Q_OS_OS2EMX)
+ char dir[4];
+ _abspath(dir, QLatin1String("/"), _MAX_PATH);
+ QString ret(dir);
+#endif
+ return ret;
+}
+
+//static
+QString QFileSystemEngine::homePath()
+{
+ QString ret;
+#if !defined(QT_NO_LIBRARY)
+ resolveLibs();
+ if (ptrGetUserProfileDirectoryW) {
+ HANDLE hnd = ::GetCurrentProcess();
+ HANDLE token = 0;
+ BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token);
+ if (ok) {
+ DWORD dwBufferSize = 0;
+ // First call, to determine size of the strings (with '\0').
+ ok = ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize);
+ if (!ok && dwBufferSize != 0) { // We got the required buffer size
+ wchar_t *userDirectory = new wchar_t[dwBufferSize];
+ // Second call, now we can fill the allocated buffer.
+ ok = ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize);
+ if (ok)
+ ret = QString::fromWCharArray(userDirectory);
+ delete [] userDirectory;
+ }
+ ::CloseHandle(token);
+ }
+ }
+#endif
+ if (ret.isEmpty() || !QFile::exists(ret)) {
+ ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData());
+ if (ret.isEmpty() || !QFile::exists(ret)) {
+ ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData())
+ + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData());
+ if (ret.isEmpty() || !QFile::exists(ret)) {
+ ret = QString::fromLocal8Bit(qgetenv("HOME").constData());
+ if (ret.isEmpty() || !QFile::exists(ret)) {
+#if defined(Q_OS_WINCE)
+ ret = QLatin1String("\\My Documents");
+ if (!QFile::exists(ret))
+#endif
+ ret = rootPath();
+ }
+ }
+ }
+ }
+ return QDir::fromNativeSeparators(ret);
+}
+
+QString QFileSystemEngine::tempPath()
+{
+ QString ret;
+ wchar_t tempPath[MAX_PATH];
+ DWORD len = GetTempPath(MAX_PATH, tempPath);
+ if (len)
+ ret = QString::fromWCharArray(tempPath, len);
+ if (!ret.isEmpty()) {
+ while (ret.endsWith(QLatin1Char('\\')))
+ ret.chop(1);
+ ret = QDir::fromNativeSeparators(ret);
+ }
+ if (ret.isEmpty()) {
+#if !defined(Q_OS_WINCE)
+ ret = QLatin1String("c:/tmp");
+#else
+ ret = QLatin1String("/Temp");
+#endif
+ }
+ return ret;
+}
+
+bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
+{
+ QFileSystemMetaData meta;
+ fillMetaData(entry, meta, QFileSystemMetaData::ExistsAttribute | QFileSystemMetaData::DirectoryType);
+ if(!(meta.exists() && meta.isDirectory()))
+ return false;
+
+#if !defined(Q_OS_WINCE)
+ //TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo
+ //which causes many problems later on when it's returned through currentPath()
+ return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0;
+#else
+ qfsPrivateCurrentDir = entry.filePath();
+ return true;
+#endif
+}
+
+QFileSystemEntry QFileSystemEngine::currentPath()
+{
+ QString ret;
+#if !defined(Q_OS_WINCE)
+ DWORD size = 0;
+ wchar_t currentName[PATH_MAX];
+ size = ::GetCurrentDirectory(PATH_MAX, currentName);
+ if (size != 0) {
+ if (size > PATH_MAX) {
+ wchar_t *newCurrentName = new wchar_t[size];
+ if (::GetCurrentDirectory(PATH_MAX, newCurrentName) != 0)
+ ret = QString::fromWCharArray(newCurrentName, size);
+ delete [] newCurrentName;
+ } else {
+ ret = QString::fromWCharArray(currentName, size);
+ }
+ }
+ if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
+ ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
+#else
+ Q_UNUSED(fileName);
+ //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads
+ if (qfsPrivateCurrentDir.isEmpty())
+ qfsPrivateCurrentDir = QCoreApplication::applicationDirPath();
+
+ ret = qfsPrivateCurrentDir;
+#endif
+ return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
+}
+
+//static
+bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ Q_ASSERT(false);
+ Q_UNUSED(source)
+ Q_UNUSED(target)
+ Q_UNUSED(error)
+
+ return false; // TODO implement; - code needs to be moved from qfsfileengine_win.cpp
+}
+
+//static
+bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ bool ret = ::CopyFile((wchar_t*)source.nativeFilePath().utf16(),
+ (wchar_t*)target.nativeFilePath().utf16(), true) != 0;
+ if(!ret)
+ error = QSystemError(::GetLastError(), QSystemError::NativeError);
+ return ret;
+}
+
+//static
+bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ bool ret = ::MoveFile((wchar_t*)source.nativeFilePath().utf16(),
+ (wchar_t*)target.nativeFilePath().utf16()) != 0;
+ if(!ret)
+ error = QSystemError(::GetLastError(), QSystemError::NativeError);
+ return ret;
+}
+
+//static
+bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
+{
+ bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0;
+ if(!ret)
+ error = QSystemError(::GetLastError(), QSystemError::NativeError);
+ return ret;
+}
+
+//static
+bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
+ QFileSystemMetaData *data)
+{
+ Q_UNUSED(data);
+ int mode = 0;
+
+ if (permissions & QFile::ReadOwner || permissions & QFile::ReadUser
+ || permissions & QFile::ReadGroup || permissions & QFile::ReadOther)
+ mode |= _S_IREAD;
+ if (permissions & QFile::WriteOwner || permissions & QFile::WriteUser
+ || permissions & QFile::WriteGroup || permissions & QFile::WriteOther)
+ mode |= _S_IWRITE;
+
+ if (mode == 0) // not supported
+ return false;
+
+ bool ret = (::_wchmod((wchar_t*)entry.nativeFilePath().utf16(), mode) == 0);
+ if(!ret)
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return ret;
+}
+
+static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
+{
+ QDateTime ret;
+
+#if defined(Q_OS_WINCE)
+ SYSTEMTIME systime;
+ FILETIME ftime;
+ systime.wYear = 1970;
+ systime.wMonth = 1;
+ systime.wDay = 1;
+ systime.wHour = 0;
+ systime.wMinute = 0;
+ systime.wSecond = 0;
+ systime.wMilliseconds = 0;
+ systime.wDayOfWeek = 4;
+ SystemTimeToFileTime(&systime, &ftime);
+ unsigned __int64 acttime = (unsigned __int64)time->dwHighDateTime << 32 | time->dwLowDateTime;
+ FileTimeToSystemTime(time, &systime);
+ unsigned __int64 time1970 = (unsigned __int64)ftime.dwHighDateTime << 32 | ftime.dwLowDateTime;
+ unsigned __int64 difftime = acttime - time1970;
+ difftime /= 10000000;
+ ret.setTime_t((unsigned int)difftime);
+#else
+ SYSTEMTIME sTime, lTime;
+ FileTimeToSystemTime(time, &sTime);
+ SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
+ ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
+ ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
+#endif
+
+ return ret;
+}
+
+QDateTime QFileSystemMetaData::creationTime() const
+{
+ return fileTimeToQDateTime(&creationTime_);
+}
+QDateTime QFileSystemMetaData::modificationTime() const
+{
+ return fileTimeToQDateTime(&lastWriteTime_);
+}
+QDateTime QFileSystemMetaData::accessTime() const
+{
+ return fileTimeToQDateTime(&lastAccessTime_);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
new file mode 100644
index 0000000000..ccbb10d82c
--- /dev/null
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystementry_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/private/qfsfileengine_p.h>
+#ifdef Q_OS_WIN
+#include <QtCore/qstringbuilder.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+static bool isUncRoot(const QString &server)
+{
+ QString localPath = QDir::toNativeSeparators(server);
+ if (!localPath.startsWith(QLatin1String("\\\\")))
+ return false;
+
+ int idx = localPath.indexOf(QLatin1Char('\\'), 2);
+ if (idx == -1 || idx + 1 == localPath.length())
+ return true;
+
+ localPath = localPath.right(localPath.length() - idx - 1).trimmed();
+ return localPath.isEmpty();
+}
+
+static inline QString fixIfRelativeUncPath(const QString &path)
+{
+ QString currentPath = QDir::currentPath();
+ if (currentPath.startsWith(QLatin1String("//")))
+ return currentPath % QChar(QLatin1Char('/')) % path;
+ return path;
+}
+#endif
+
+QFileSystemEntry::QFileSystemEntry()
+ : m_lastSeparator(0),
+ m_firstDotInFileName(0),
+ m_lastDotInFileName(0)
+{
+}
+
+/*!
+ \internal
+ Use this constructor when the path is supplied by user code, as it may contain a mix
+ of '/' and the native separator.
+ */
+QFileSystemEntry::QFileSystemEntry(const QString &filePath)
+ : m_filePath(QDir::fromNativeSeparators(filePath)),
+ m_lastSeparator(-2),
+ m_firstDotInFileName(-2),
+ m_lastDotInFileName(0)
+{
+}
+
+/*!
+ \internal
+ Use this constructor when the path is guaranteed to be in internal format, i.e. all
+ directory separators are '/' and not the native separator.
+ */
+QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /* dummy */)
+ : m_filePath(filePath),
+ m_lastSeparator(-2),
+ m_firstDotInFileName(-2),
+ m_lastDotInFileName(0)
+{
+}
+
+/*!
+ \internal
+ Use this constructor when the path comes from a native API
+ */
+QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath /* dummy */)
+ : m_nativeFilePath(nativeFilePath),
+ m_lastSeparator(-2),
+ m_firstDotInFileName(-2),
+ m_lastDotInFileName(0)
+{
+}
+
+QFileSystemEntry::QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath)
+ : m_filePath(QDir::fromNativeSeparators(filePath)),
+ m_nativeFilePath(nativeFilePath),
+ m_lastSeparator(-2),
+ m_firstDotInFileName(-2),
+ m_lastDotInFileName(0)
+{
+}
+
+QString QFileSystemEntry::filePath() const
+{
+ resolveFilePath();
+ return m_filePath;
+}
+
+QFileSystemEntry::NativePath QFileSystemEntry::nativeFilePath() const
+{
+ resolveNativeFilePath();
+ return m_nativeFilePath;
+}
+
+void QFileSystemEntry::resolveFilePath() const
+{
+ if (m_filePath.isEmpty() && !m_nativeFilePath.isEmpty()) {
+#if defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16)
+ m_filePath = QDir::fromNativeSeparators(m_nativeFilePath);
+#ifdef Q_OS_WIN
+ if (m_filePath.startsWith(QLatin1String("//?/UNC/")))
+ m_filePath = m_filePath.remove(2,6);
+ if (m_filePath.startsWith(QLatin1String("//?/")))
+ m_filePath = m_filePath.remove(0,4);
+#endif
+#else
+ m_filePath = QDir::fromNativeSeparators(QFile::decodeName(m_nativeFilePath));
+#endif
+ }
+}
+
+void QFileSystemEntry::resolveNativeFilePath() const
+{
+ if (!m_filePath.isEmpty() && m_nativeFilePath.isEmpty()) {
+#ifdef Q_OS_WIN
+ QString filePath = m_filePath;
+ if (isRelative())
+ filePath = fixIfRelativeUncPath(m_filePath);
+ m_nativeFilePath = QFSFileEnginePrivate::longFileName(QDir::toNativeSeparators(filePath));
+#elif defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16)
+ m_nativeFilePath = QDir::toNativeSeparators(m_filePath);
+#else
+ m_nativeFilePath = QFile::encodeName(QDir::toNativeSeparators(m_filePath));
+#endif
+ }
+}
+
+QString QFileSystemEntry::fileName() const
+{
+ findLastSeparator();
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ return m_filePath.mid(2);
+#endif
+ return m_filePath.mid(m_lastSeparator + 1);
+}
+
+QString QFileSystemEntry::path() const
+{
+ findLastSeparator();
+ if (m_lastSeparator == -1) {
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ return m_filePath.left(2);
+#endif
+ return QString(QLatin1Char('.'));
+ }
+ if (m_lastSeparator == 0)
+ return QString(QLatin1Char('/'));
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (m_lastSeparator == 2 && m_filePath.at(1) == QLatin1Char(':'))
+ return m_filePath.left(m_lastSeparator + 1);
+#endif
+ return m_filePath.left(m_lastSeparator);
+}
+
+QString QFileSystemEntry::baseName() const
+{
+ findFileNameSeparators();
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ return m_filePath.mid(2);
+#endif
+ int length = -1;
+ if (m_firstDotInFileName >= 0) {
+ length = m_firstDotInFileName;
+ if (m_lastSeparator != -1) // avoid off by one
+ length--;
+ }
+ return m_filePath.mid(m_lastSeparator + 1, length);
+}
+
+QString QFileSystemEntry::completeBaseName() const
+{
+ findFileNameSeparators();
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
+ return m_filePath.mid(2);
+#endif
+ int length = -1;
+ if (m_firstDotInFileName >= 0) {
+ length = m_firstDotInFileName + m_lastDotInFileName;
+ if (m_lastSeparator != -1) // avoid off by one
+ length--;
+ }
+ return m_filePath.mid(m_lastSeparator + 1, length);
+}
+
+QString QFileSystemEntry::suffix() const
+{
+ findFileNameSeparators();
+
+ if (m_lastDotInFileName == -1)
+ return QString();
+
+ return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + m_lastDotInFileName + 1);
+}
+
+QString QFileSystemEntry::completeSuffix() const
+{
+ findFileNameSeparators();
+ if (m_firstDotInFileName == -1)
+ return QString();
+
+ return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + 1);
+}
+
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+bool QFileSystemEntry::isRelative() const
+{
+ resolveFilePath();
+ return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath[0].unicode() != '/')
+ && (!(m_filePath.length() >= 2 && m_filePath[1].unicode() == ':'))));
+}
+
+bool QFileSystemEntry::isAbsolute() const
+{
+ resolveFilePath();
+ return (!m_filePath.isEmpty() && ((m_filePath.length() >= 3
+ && (m_filePath[0].isLetter() && m_filePath[1].unicode() == ':' && m_filePath[2].unicode() == '/'))
+#ifdef Q_OS_WIN
+ || (m_filePath.length() >= 2 && (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/')))
+#endif
+ ));
+}
+#else
+bool QFileSystemEntry::isRelative() const
+{
+ return !isAbsolute();
+}
+
+bool QFileSystemEntry::isAbsolute() const
+{
+ resolveFilePath();
+ return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/'));
+}
+#endif
+
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+bool QFileSystemEntry::isDriveRoot() const
+{
+ resolveFilePath();
+ return (m_filePath.length() == 3
+ && m_filePath.at(0).isLetter() && m_filePath.at(1) == QLatin1Char(':')
+ && m_filePath.at(2) == QLatin1Char('/'));
+}
+#endif
+
+bool QFileSystemEntry::isRoot() const
+{
+ resolveFilePath();
+ if (m_filePath == QLatin1String("/")
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ || isDriveRoot()
+#if defined(Q_OS_WIN)
+ || isUncRoot(m_filePath)
+#endif
+#endif
+ )
+ return true;
+
+ return false;
+}
+
+bool QFileSystemEntry::isEmpty() const
+{
+ resolveNativeFilePath();
+ return m_nativeFilePath.isEmpty();
+}
+
+// private methods
+
+void QFileSystemEntry::findLastSeparator() const
+{
+ if (m_lastSeparator == -2) {
+ resolveFilePath();
+ m_lastSeparator = -1;
+ for (int i = m_filePath.size() - 1; i >= 0; --i) {
+ if (m_filePath[i].unicode() == '/') {
+ m_lastSeparator = i;
+ break;
+ }
+ }
+ }
+}
+
+void QFileSystemEntry::findFileNameSeparators() const
+{
+ if (m_firstDotInFileName == -2) {
+ resolveFilePath();
+ int firstDotInFileName = -1;
+ int lastDotInFileName = -1;
+ int lastSeparator = m_lastSeparator;
+
+ int stop;
+ if (lastSeparator < 0) {
+ lastSeparator = -1;
+ stop = 0;
+ } else {
+ stop = lastSeparator;
+ }
+
+ int i = m_filePath.size() - 1;
+ for (; i >= stop; --i) {
+ if (m_filePath[i].unicode() == '.') {
+ firstDotInFileName = lastDotInFileName = i;
+ break;
+ } else if (m_filePath[i].unicode() == '/') {
+ lastSeparator = i;
+ break;
+ }
+ }
+
+ if (lastSeparator != i) {
+ for (--i; i >= stop; --i) {
+ if (m_filePath[i].unicode() == '.')
+ firstDotInFileName = i;
+ else if (m_filePath[i].unicode() == '/') {
+ lastSeparator = i;
+ break;
+ }
+ }
+ }
+ m_lastSeparator = lastSeparator;
+ m_firstDotInFileName = firstDotInFileName == -1 ? -1 : firstDotInFileName - qMax(0, lastSeparator);
+ if (lastDotInFileName == -1)
+ m_lastDotInFileName = -1;
+ else if (firstDotInFileName == lastDotInFileName)
+ m_lastDotInFileName = 0;
+ else
+ m_lastDotInFileName = lastDotInFileName - firstDotInFileName;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h
new file mode 100644
index 0000000000..d4d16d0de6
--- /dev/null
+++ b/src/corelib/io/qfilesystementry_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMENTRY_P_H_INCLUDED
+#define QFILESYSTEMENTRY_P_H_INCLUDED
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+#define QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFileSystemEntry
+{
+public:
+
+#ifndef QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16
+ typedef QByteArray NativePath;
+#else
+ typedef QString NativePath;
+#endif
+ struct FromNativePath{};
+ struct FromInternalPath{};
+
+ QFileSystemEntry();
+ explicit QFileSystemEntry(const QString &filePath);
+
+ QFileSystemEntry(const QString &filePath, FromInternalPath dummy);
+ QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath dummy);
+ QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath);
+
+ QString filePath() const;
+ QString fileName() const;
+ QString path() const;
+ NativePath nativeFilePath() const;
+ QString baseName() const;
+ QString completeBaseName() const;
+ QString suffix() const;
+ QString completeSuffix() const;
+ bool isAbsolute() const;
+ bool isRelative() const;
+
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ bool isDriveRoot() const;
+#endif
+ bool isRoot() const;
+
+ bool isEmpty() const;
+ void clear()
+ {
+ *this = QFileSystemEntry();
+ }
+
+private:
+ // creates the QString version out of the bytearray version
+ void resolveFilePath() const;
+ // creates the bytearray version out of the QString version
+ void resolveNativeFilePath() const;
+ // resolves the separator
+ void findLastSeparator() const;
+ // resolves the dots and the separator
+ void findFileNameSeparators() const;
+
+ mutable QString m_filePath; // always has slashes as separator
+ mutable NativePath m_nativeFilePath; // native encoding and separators
+
+ mutable qint16 m_lastSeparator; // index in m_filePath of last separator
+ mutable qint16 m_firstDotInFileName; // index after m_filePath for first dot (.)
+ mutable qint16 m_lastDotInFileName; // index after m_firstDotInFileName for last dot (.)
+};
+
+QT_END_NAMESPACE
+
+#endif // include guard
diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h
new file mode 100644
index 0000000000..fb8bfe69e9
--- /dev/null
+++ b/src/corelib/io/qfilesystemiterator_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMITERATOR_P_H_INCLUDED
+#define QFILESYSTEMITERATOR_P_H_INCLUDED
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_FILESYSTEMITERATOR
+
+#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qstringlist.h>
+
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+
+// Platform-specific headers
+#if defined(Q_OS_WIN)
+#elif defined (Q_OS_SYMBIAN)
+#include <f32file.h>
+#else
+#include <QtCore/qscopedpointer.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFileSystemIterator
+{
+public:
+ QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
+ const QStringList &nameFilters, QDirIterator::IteratorFlags flags
+ = QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
+ ~QFileSystemIterator();
+
+ bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData);
+
+private:
+ QFileSystemEntry::NativePath nativePath;
+
+ // Platform-specific data
+#if defined(Q_OS_WIN)
+ QFileSystemEntry::NativePath dirPath;
+ HANDLE findFileHandle;
+ QStringList uncShares;
+ bool uncFallback;
+ int uncShareIndex;
+ bool onlyDirs;
+#elif defined (Q_OS_SYMBIAN)
+ RDir dirHandle;
+ TEntryArray entries;
+ TInt lastError;
+ TInt entryIndex;
+#else
+ QT_DIR *dir;
+ QT_DIRENT *dirEntry;
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+ // for readdir_r
+ QScopedPointer<QT_DIRENT, QScopedPointerPodDeleter> mt_file;
+#endif
+ int lastError;
+#endif
+
+ Q_DISABLE_COPY(QFileSystemIterator)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILESYSTEMITERATOR
+
+#endif // include guard
diff --git a/src/corelib/io/qfilesystemiterator_symbian.cpp b/src/corelib/io/qfilesystemiterator_symbian.cpp
new file mode 100644
index 0000000000..a39f9c3096
--- /dev/null
+++ b/src/corelib/io/qfilesystemiterator_symbian.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemiterator_p.h"
+#include "qfilesystemengine_p.h"
+#include <QtCore/private/qcore_symbian_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &path, QDir::Filters filters,
+ const QStringList &nameFilters, QDirIterator::IteratorFlags iteratorFlags)
+ : lastError(KErrNone), entryIndex(-1)
+{
+ RFs& fs = qt_s60GetRFs();
+
+ nativePath = path.nativeFilePath();
+ if (!nativePath.endsWith(QLatin1Char('\\')))
+ nativePath.append(QLatin1Char('\\'));
+
+ QString absPath = QFileSystemEngine::absoluteName(path).nativeFilePath();
+
+ if (!absPath.endsWith(QLatin1Char('\\')))
+ absPath.append(QLatin1Char('\\'));
+
+ int pathLen = absPath.length();
+ if (pathLen > KMaxFileName) {
+ lastError = KErrBadName;
+ return;
+ }
+
+ //set up server side filtering to reduce IPCs
+ //RDir won't accept all valid name filters e.g. "*. bar"
+ if (nameFilters.count() == 1 && !(filters & QDir::AllDirs) && iteratorFlags
+ == QDirIterator::NoIteratorFlags && pathLen + nameFilters[0].length()
+ <= KMaxFileName) {
+ //server side supports one mask - skip this for recursive mode or if only files should be filtered
+ absPath.append(nameFilters[0]);
+ }
+
+ TUint symbianMask = 0;
+ if ((filters & QDir::Dirs) || (filters & QDir::AllDirs) || (iteratorFlags
+ & QDirIterator::Subdirectories))
+ symbianMask |= KEntryAttDir; //include directories
+ if (filters & QDir::Hidden)
+ symbianMask |= KEntryAttHidden;
+ if (filters & QDir::System)
+ symbianMask |= KEntryAttSystem;
+ if (((filters & QDir::Files) == 0) && symbianMask == KEntryAttDir)
+ symbianMask |= KEntryAttMatchExclusive; //exclude non-directories
+ else if (symbianMask == 0) {
+ if ((filters & QDir::PermissionMask) == QDir::Writable)
+ symbianMask = KEntryAttMatchExclude | KEntryAttReadOnly;
+ }
+
+ lastError = dirHandle.Open(fs, qt_QString2TPtrC(absPath), symbianMask);
+}
+
+QFileSystemIterator::~QFileSystemIterator()
+{
+ dirHandle.Close();
+}
+
+bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
+{
+ //1st time, lastError is result of dirHandle.Open(), entries.Count() is 0 and entryIndex is -1 so initial read is triggered
+ //subsequent times, read is triggered each time we reach the end of the entry list
+ //final time, lastError is KErrEof so we don't need to read anymore.
+ ++entryIndex;
+ if (lastError == KErrNone && entryIndex >= entries.Count()) {
+ lastError = dirHandle.Read(entries);
+ entryIndex = 0;
+ }
+
+ //each call to advance() gets the next entry from the entry list.
+ //from the final (or only) read call, KErrEof is returned together with a full buffer so we still need to go through the list
+ if ((lastError == KErrNone || lastError == KErrEof) && entryIndex < entries.Count()) {
+ Q_ASSERT(entryIndex >= 0);
+ const TEntry &entry(entries[entryIndex]);
+ fileEntry = QFileSystemEntry(nativePath + qt_TDesC2QString(entry.iName), QFileSystemEntry::FromNativePath());
+ metaData.fillFromTEntry(entry);
+ return true;
+ }
+
+ //TODO: error reporting, to allow user to distinguish empty directory from error condition.
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
new file mode 100644
index 0000000000..3d6012b47c
--- /dev/null
+++ b/src/corelib/io/qfilesystemiterator_unix.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qfilesystemiterator_p.h"
+
+#ifndef QT_NO_FILESYSTEMITERATOR
+
+#include <stdlib.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
+ const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
+ : nativePath(entry.nativeFilePath())
+ , dir(0)
+ , dirEntry(0)
+ , lastError(0)
+{
+ Q_UNUSED(filters)
+ Q_UNUSED(nameFilters)
+ Q_UNUSED(flags)
+
+ if ((dir = QT_OPENDIR(nativePath.constData())) == 0) {
+ lastError = errno;
+ } else {
+
+ if (!nativePath.endsWith('/'))
+ nativePath.append('/');
+
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+ // ### Race condition; we should use fpathconf and dirfd().
+ size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
+ if (maxPathName == size_t(-1))
+ maxPathName = FILENAME_MAX;
+ maxPathName += sizeof(QT_DIRENT) + 1;
+
+ QT_DIRENT *p = reinterpret_cast<QT_DIRENT*>(::malloc(maxPathName));
+ Q_CHECK_PTR(p);
+
+ mt_file.reset(p);
+#endif
+ }
+}
+
+QFileSystemIterator::~QFileSystemIterator()
+{
+ if (dir)
+ QT_CLOSEDIR(dir);
+}
+
+bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
+{
+ if (!dir)
+ return false;
+
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
+ lastError = QT_READDIR_R(dir, mt_file.data(), &dirEntry);
+ if (lastError)
+ return false;
+#else
+ // ### add local lock to prevent breaking reentrancy
+ dirEntry = QT_READDIR(dir);
+#endif // _POSIX_THREAD_SAFE_FUNCTIONS
+
+ if (dirEntry) {
+ fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath());
+ metaData.fillFromDirEnt(*dirEntry);
+ return true;
+ }
+
+ lastError = errno;
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILESYSTEMITERATOR
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
new file mode 100644
index 0000000000..0e94130049
--- /dev/null
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include "qfilesystemiterator_p.h"
+#include "qfilesystemengine_p.h"
+#include "qplatformdefs.h"
+
+#include <QtCore/qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+bool done = true;
+
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
+ const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
+ : nativePath(entry.nativeFilePath())
+ , dirPath(entry.filePath())
+ , findFileHandle(INVALID_HANDLE_VALUE)
+ , uncFallback(false)
+ , uncShareIndex(0)
+ , onlyDirs(false)
+{
+ Q_UNUSED(nameFilters)
+ Q_UNUSED(flags)
+ if (nativePath.endsWith(QLatin1String(".lnk"))) {
+ QFileSystemMetaData metaData;
+ QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData);
+ nativePath = link.nativeFilePath();
+ }
+ if (!nativePath.endsWith(QLatin1Char('\\')))
+ nativePath.append(QLatin1Char('\\'));
+ nativePath.append(QLatin1Char('*'));
+ if (!dirPath.endsWith(QLatin1Char('/')))
+ dirPath.append(QLatin1Char('/'));
+ if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
+ onlyDirs = true;
+}
+
+QFileSystemIterator::~QFileSystemIterator()
+{
+ if (findFileHandle != INVALID_HANDLE_VALUE)
+ FindClose(findFileHandle);
+}
+
+bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
+{
+ bool haveData = false;
+ WIN32_FIND_DATA findData;
+
+ if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback) {
+ haveData = true;
+ int infoLevel = 0 ; // FindExInfoStandard;
+ DWORD dwAdditionalFlags = 0;
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
+ infoLevel = 1 ; // FindExInfoBasic;
+ }
+ int searchOps = 0; // FindExSearchNameMatch
+ if (onlyDirs)
+ searchOps = 1 ; // FindExSearchLimitToDirectories
+ findFileHandle = FindFirstFileEx((const wchar_t *)nativePath.utf16(), FINDEX_INFO_LEVELS(infoLevel), &findData,
+ FINDEX_SEARCH_OPS(searchOps), 0, dwAdditionalFlags);
+ if (findFileHandle == INVALID_HANDLE_VALUE) {
+ if (nativePath.startsWith(QLatin1String("\\\\?\\UNC\\"))) {
+ QStringList parts = nativePath.split(QLatin1Char('\\'), QString::SkipEmptyParts);
+ if (parts.count() == 4 && QFileSystemEngine::uncListSharesOnServer(
+ QLatin1String("\\\\") + parts.at(2), &uncShares)) {
+ if (uncShares.isEmpty())
+ return false; // No shares found in the server
+ else
+ uncFallback = true;
+ }
+ }
+ }
+ }
+ if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback)
+ return false;
+ // Retrieve the new file information.
+ if (!haveData) {
+ if (uncFallback) {
+ if (++uncShareIndex >= uncShares.count())
+ return false;
+ } else {
+ if (!FindNextFile(findFileHandle, &findData))
+ return false;
+ }
+ }
+ // Create the new file system entry & meta data.
+ if (uncFallback) {
+ fileEntry = QFileSystemEntry(dirPath + uncShares.at(uncShareIndex));
+ metaData.fillFromFileAttribute(FILE_ATTRIBUTE_DIRECTORY);
+ return true;
+ } else {
+ QString fileName = QString::fromWCharArray(findData.cFileName);
+ fileEntry = QFileSystemEntry(dirPath + fileName);
+ metaData = QFileSystemMetaData();
+ if (!fileName.endsWith(QLatin1String(".lnk"))) {
+ metaData.fillFromFindData(findData, true);
+ }
+ return true;
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
new file mode 100644
index 0000000000..f7f1fa1b8d
--- /dev/null
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -0,0 +1,400 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMMETADATA_P_H_INCLUDED
+#define QFILESYSTEMMETADATA_P_H_INCLUDED
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qplatformdefs.h"
+#include <QtCore/qglobal.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qabstractfileengine.h>
+
+// Platform-specific includes
+#if defined(Q_OS_WIN)
+#ifndef IO_REPARSE_TAG_SYMLINK
+#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+#elif defined(Q_OS_SYMBIAN)
+#include <f32file.h>
+#include <QtCore/private/qdatetime_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFileSystemEngine;
+
+class QFileSystemMetaData
+{
+public:
+ QFileSystemMetaData()
+ : knownFlagsMask(0)
+ {
+ }
+
+ enum MetaDataFlag {
+ // Permissions, overlaps with QFile::Permissions
+ OtherReadPermission = 0x00000004, OtherWritePermission = 0x00000002, OtherExecutePermission = 0x00000001,
+ GroupReadPermission = 0x00000040, GroupWritePermission = 0x00000020, GroupExecutePermission = 0x00000010,
+ UserReadPermission = 0x00000400, UserWritePermission = 0x00000200, UserExecutePermission = 0x00000100,
+ OwnerReadPermission = 0x00004000, OwnerWritePermission = 0x00002000, OwnerExecutePermission = 0x00001000,
+
+ OtherPermissions = OtherReadPermission | OtherWritePermission | OtherExecutePermission,
+ GroupPermissions = GroupReadPermission | GroupWritePermission | GroupExecutePermission,
+ UserPermissions = UserReadPermission | UserWritePermission | UserExecutePermission,
+ OwnerPermissions = OwnerReadPermission | OwnerWritePermission | OwnerExecutePermission,
+
+ ReadPermissions = OtherReadPermission | GroupReadPermission | UserReadPermission | OwnerReadPermission,
+ WritePermissions = OtherWritePermission | GroupWritePermission | UserWritePermission | OwnerWritePermission,
+ ExecutePermissions = OtherExecutePermission | GroupExecutePermission | UserExecutePermission | OwnerExecutePermission,
+
+ Permissions = OtherPermissions | GroupPermissions | UserPermissions | OwnerPermissions,
+
+ // Type
+#ifdef Q_OS_SYMBIAN
+ LinkType = 0,
+#else
+ LinkType = 0x00010000,
+#endif
+ FileType = 0x00020000,
+ DirectoryType = 0x00040000,
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+ BundleType = 0x00080000,
+ AliasType = 0x08000000,
+#else
+ BundleType = 0x0,
+ AliasType = 0x0,
+#endif
+#if defined(Q_OS_WIN)
+ WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac
+#else
+ WinLnkType = 0x0,
+#endif
+ SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag
+
+ LegacyLinkType = LinkType | AliasType | WinLnkType,
+
+ Type = LinkType | FileType | DirectoryType | BundleType | SequentialType | AliasType,
+
+ // Attributes
+ HiddenAttribute = 0x00100000,
+ SizeAttribute = 0x00200000, // Note: overlaps with QAbstractFileEngine::LocalDiskFlag
+ ExistsAttribute = 0x00400000,
+
+ Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute,
+
+ // Times
+ CreationTime = 0x01000000, // Note: overlaps with QAbstractFileEngine::Refresh
+ ModificationTime = 0x02000000,
+ AccessTime = 0x04000000,
+
+ Times = CreationTime | ModificationTime | AccessTime,
+
+ // Owner IDs
+ UserId = 0x10000000,
+ GroupId = 0x20000000,
+
+ OwnerIds = UserId | GroupId,
+
+ PosixStatFlags = QFileSystemMetaData::OtherPermissions
+ | QFileSystemMetaData::GroupPermissions
+ | QFileSystemMetaData::OwnerPermissions
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::SizeAttribute
+ | QFileSystemMetaData::Times
+ | QFileSystemMetaData::OwnerIds,
+
+ SymbianTEntryFlags = QFileSystemMetaData::Permissions
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::Attributes
+ | QFileSystemMetaData::Times,
+#if defined(Q_OS_WIN)
+ WinStatFlags = QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::HiddenAttribute
+ | QFileSystemMetaData::ExistsAttribute
+ | QFileSystemMetaData::SizeAttribute
+ | QFileSystemMetaData::Times,
+#endif
+
+ AllMetaDataFlags = 0xFFFFFFFF
+
+ };
+ Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag)
+
+ bool hasFlags(MetaDataFlags flags) const
+ {
+ return ((knownFlagsMask & flags) == flags);
+ }
+
+ MetaDataFlags missingFlags(MetaDataFlags flags)
+ {
+ return flags & ~knownFlagsMask;
+ }
+
+ void clear()
+ {
+ knownFlagsMask = 0;
+ }
+
+ void clearFlags(MetaDataFlags flags = AllMetaDataFlags)
+ {
+ knownFlagsMask &= ~flags;
+ }
+
+ bool exists() const { return (entryFlags & ExistsAttribute); }
+
+ bool isLink() const { return (entryFlags & LinkType); }
+ bool isFile() const { return (entryFlags & FileType); }
+ bool isDirectory() const { return (entryFlags & DirectoryType); }
+ bool isBundle() const;
+ bool isAlias() const;
+ bool isLegacyLink() const { return (entryFlags & LegacyLinkType); }
+ bool isSequential() const { return (entryFlags & SequentialType); }
+ bool isHidden() const { return (entryFlags & HiddenAttribute); }
+#if defined(Q_OS_WIN)
+ bool isLnkFile() const { return (entryFlags & WinLnkType); }
+#else
+ bool isLnkFile() const { return false; }
+#endif
+
+ qint64 size() const { return size_; }
+
+ QFile::Permissions permissions() const { return QFile::Permissions(Permissions & entryFlags); }
+
+ QDateTime creationTime() const;
+ QDateTime modificationTime() const;
+ QDateTime accessTime() const;
+
+ QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
+ uint userId() const;
+ uint groupId() const;
+ uint ownerId(QAbstractFileEngine::FileOwner owner) const;
+
+#ifdef Q_OS_UNIX
+ void fillFromStatBuf(const QT_STATBUF &statBuffer);
+ void fillFromDirEnt(const QT_DIRENT &statBuffer);
+#endif
+#ifdef Q_OS_SYMBIAN
+ void fillFromTEntry(const TEntry& entry);
+ void fillFromVolumeInfo(const TVolumeInfo& info);
+#endif
+
+#if defined(Q_OS_WIN)
+ inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false);
+ inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false);
+ inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo);
+#endif
+private:
+ friend class QFileSystemEngine;
+
+ MetaDataFlags knownFlagsMask;
+ MetaDataFlags entryFlags;
+
+ qint64 size_;
+
+ // Platform-specific data goes here:
+#if defined(Q_OS_WIN)
+ DWORD fileAttribute_;
+ FILETIME creationTime_;
+ FILETIME lastAccessTime_;
+ FILETIME lastWriteTime_;
+#elif defined(Q_OS_SYMBIAN)
+ TTime modificationTime_;
+#else
+ time_t creationTime_;
+ time_t modificationTime_;
+ time_t accessTime_;
+
+ uint userId_;
+ uint groupId_;
+#endif
+
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags)
+
+#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
+inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); }
+inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); }
+#else
+inline bool QFileSystemMetaData::isBundle() const { return false; }
+inline bool QFileSystemMetaData::isAlias() const { return false; }
+#endif
+
+#if (defined(Q_OS_UNIX) && !defined (Q_OS_SYMBIAN)) || defined (Q_OS_WIN)
+inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
+{
+ switch (time) {
+ case QAbstractFileEngine::ModificationTime:
+ return modificationTime();
+
+ case QAbstractFileEngine::AccessTime:
+ return accessTime();
+
+ case QAbstractFileEngine::CreationTime:
+ return creationTime();
+ }
+
+ return QDateTime();
+}
+#endif
+
+#if defined(Q_OS_UNIX) && !defined (Q_OS_SYMBIAN)
+inline QDateTime QFileSystemMetaData::creationTime() const { return QDateTime::fromTime_t(creationTime_); }
+inline QDateTime QFileSystemMetaData::modificationTime() const { return QDateTime::fromTime_t(modificationTime_); }
+inline QDateTime QFileSystemMetaData::accessTime() const { return QDateTime::fromTime_t(accessTime_); }
+
+inline uint QFileSystemMetaData::userId() const { return userId_; }
+inline uint QFileSystemMetaData::groupId() const { return groupId_; }
+
+inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
+{
+ if (owner == QAbstractFileEngine::OwnerUser)
+ return userId();
+ else
+ return groupId();
+}
+#endif
+
+#ifdef Q_OS_SYMBIAN
+inline QDateTime QFileSystemMetaData::creationTime() const { return modificationTime(); }
+inline QDateTime QFileSystemMetaData::modificationTime() const { return qt_symbian_TTime_To_QDateTime(modificationTime_); }
+inline QDateTime QFileSystemMetaData::accessTime() const { return modificationTime(); }
+
+inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
+{
+ Q_UNUSED(time);
+ return modificationTime();
+}
+inline uint QFileSystemMetaData::userId() const { return (uint) -2; }
+inline uint QFileSystemMetaData::groupId() const { return (uint) -2; }
+inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
+{
+ Q_UNUSED(owner);
+ return (uint) -2;
+}
+#endif
+
+#if defined(Q_OS_WIN)
+inline uint QFileSystemMetaData::userId() const { return (uint) -2; }
+inline uint QFileSystemMetaData::groupId() const { return (uint) -2; }
+inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
+{
+ if (owner == QAbstractFileEngine::OwnerUser)
+ return userId();
+ else
+ return groupId();
+}
+
+inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot)
+{
+ fileAttribute_ = fileAttribute;
+ // Ignore the hidden attribute for drives.
+ if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN))
+ entryFlags |= HiddenAttribute;
+ entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType);
+ entryFlags |= ExistsAttribute;
+ knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute;
+}
+
+inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot)
+{
+ fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot);
+ creationTime_ = findData.ftCreationTime;
+ lastAccessTime_ = findData.ftLastAccessTime;
+ lastWriteTime_ = findData.ftLastWriteTime;
+ if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
+ size_ = 0;
+ } else {
+ size_ = findData.nFileSizeHigh;
+ size_ <<= 32;
+ size_ += findData.nFileSizeLow;
+ }
+ knownFlagsMask |= Times | SizeAttribute;
+ if (setLinkType) {
+ knownFlagsMask |= LinkType;
+ entryFlags &= ~LinkType;
+#if !defined(Q_OS_WINCE)
+ if ((fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK
+ || findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) {
+ entryFlags |= LinkType;
+ }
+#endif
+
+ }
+}
+
+inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
+{
+ fillFromFileAttribute(fileInfo.dwFileAttributes);
+ creationTime_ = fileInfo.ftCreationTime;
+ lastAccessTime_ = fileInfo.ftLastAccessTime;
+ lastWriteTime_ = fileInfo.ftLastWriteTime;
+ if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
+ size_ = 0;
+ } else {
+ size_ = fileInfo.nFileSizeHigh;
+ size_ <<= 32;
+ size_ += fileInfo.nFileSizeLow;
+ }
+ knownFlagsMask |= Times | SizeAttribute;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // include guard
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
new file mode 100644
index 0000000000..e0f2f44913
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -0,0 +1,640 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include <qdatetime.h>
+#include <qdebug.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qmutex.h>
+#include <qset.h>
+#include <qtimer.h>
+
+#if defined(Q_OS_WIN)
+# include "qfilesystemwatcher_win_p.h"
+#elif defined(Q_OS_LINUX)
+# include "qfilesystemwatcher_inotify_p.h"
+# include "qfilesystemwatcher_dnotify_p.h"
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+# if (defined Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+# include "qfilesystemwatcher_fsevents_p.h"
+# endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+# include "qfilesystemwatcher_kqueue_p.h"
+#elif defined(Q_OS_SYMBIAN)
+# include "qfilesystemwatcher_symbian_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+enum { PollingInterval = 1000 };
+
+class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+
+ class FileInfo
+ {
+ uint ownerId;
+ uint groupId;
+ QFile::Permissions permissions;
+ QDateTime lastModified;
+ QStringList entries;
+
+ public:
+ FileInfo(const QFileInfo &fileInfo)
+ : ownerId(fileInfo.ownerId()),
+ groupId(fileInfo.groupId()),
+ permissions(fileInfo.permissions()),
+ lastModified(fileInfo.lastModified())
+ {
+ if (fileInfo.isDir()) {
+ entries = fileInfo.absoluteDir().entryList(QDir::AllEntries);
+ }
+ }
+ FileInfo &operator=(const QFileInfo &fileInfo)
+ {
+ *this = FileInfo(fileInfo);
+ return *this;
+ }
+
+ bool operator!=(const QFileInfo &fileInfo) const
+ {
+ if (fileInfo.isDir() && entries != fileInfo.absoluteDir().entryList(QDir::AllEntries))
+ return true;
+ return (ownerId != fileInfo.ownerId()
+ || groupId != fileInfo.groupId()
+ || permissions != fileInfo.permissions()
+ || lastModified != fileInfo.lastModified());
+ }
+ };
+
+ mutable QMutex mutex;
+ QHash<QString, FileInfo> files, directories;
+
+public:
+ QPollingFileSystemWatcherEngine();
+
+ void run();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ void stop();
+
+private Q_SLOTS:
+ void timeout();
+};
+
+QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine()
+{
+#ifndef QT_NO_THREAD
+ moveToThread(this);
+#endif
+}
+
+void QPollingFileSystemWatcherEngine::run()
+{
+ QTimer timer;
+ connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
+ timer.start(PollingInterval);
+ (void) exec();
+}
+
+QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ QFileInfo fi(path);
+ if (!fi.exists())
+ continue;
+ if (fi.isDir()) {
+ if (!directories->contains(path))
+ directories->append(path);
+ if (!path.endsWith(QLatin1Char('/')))
+ fi = QFileInfo(path + QLatin1Char('/'));
+ this->directories.insert(path, fi);
+ } else {
+ if (!files->contains(path))
+ files->append(path);
+ this->files.insert(path, fi);
+ }
+ it.remove();
+ }
+ start();
+ return p;
+}
+
+QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ if (this->directories.remove(path)) {
+ directories->removeAll(path);
+ it.remove();
+ } else if (this->files.remove(path)) {
+ files->removeAll(path);
+ it.remove();
+ }
+ }
+ if (this->files.isEmpty() && this->directories.isEmpty()) {
+ locker.unlock();
+ stop();
+ wait();
+ }
+ return p;
+}
+
+void QPollingFileSystemWatcherEngine::stop()
+{
+ quit();
+}
+
+void QPollingFileSystemWatcherEngine::timeout()
+{
+ QMutexLocker locker(&mutex);
+ QMutableHashIterator<QString, FileInfo> fit(files);
+ while (fit.hasNext()) {
+ QHash<QString, FileInfo>::iterator x = fit.next();
+ QString path = x.key();
+ QFileInfo fi(path);
+ if (!fi.exists()) {
+ fit.remove();
+ emit fileChanged(path, true);
+ } else if (x.value() != fi) {
+ x.value() = fi;
+ emit fileChanged(path, false);
+ }
+ }
+ QMutableHashIterator<QString, FileInfo> dit(directories);
+ while (dit.hasNext()) {
+ QHash<QString, FileInfo>::iterator x = dit.next();
+ QString path = x.key();
+ QFileInfo fi(path);
+ if (!path.endsWith(QLatin1Char('/')))
+ fi = QFileInfo(path + QLatin1Char('/'));
+ if (!fi.exists()) {
+ dit.remove();
+ emit directoryChanged(path, true);
+ } else if (x.value() != fi) {
+ fi.refresh();
+ if (!fi.exists()) {
+ dit.remove();
+ emit directoryChanged(path, true);
+ } else {
+ x.value() = fi;
+ emit directoryChanged(path, false);
+ }
+ }
+
+ }
+}
+
+
+
+
+QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine()
+{
+#if defined(Q_OS_WIN)
+ return new QWindowsFileSystemWatcherEngine;
+#elif defined(Q_OS_LINUX)
+ QFileSystemWatcherEngine *eng = QInotifyFileSystemWatcherEngine::create();
+ if(!eng)
+ eng = QDnotifyFileSystemWatcherEngine::create();
+ return eng;
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+# if 0 && defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
+ return QFSEventsFileSystemWatcherEngine::create();
+ else
+# endif
+ return QKqueueFileSystemWatcherEngine::create();
+#elif defined(Q_OS_SYMBIAN)
+ return new QSymbianFileSystemWatcherEngine;
+#else
+ return 0;
+#endif
+}
+
+QFileSystemWatcherPrivate::QFileSystemWatcherPrivate()
+ : native(0), poller(0), forced(0)
+{
+}
+
+void QFileSystemWatcherPrivate::init()
+{
+ Q_Q(QFileSystemWatcher);
+ native = createNativeEngine();
+ if (native) {
+ QObject::connect(native,
+ SIGNAL(fileChanged(QString,bool)),
+ q,
+ SLOT(_q_fileChanged(QString,bool)));
+ QObject::connect(native,
+ SIGNAL(directoryChanged(QString,bool)),
+ q,
+ SLOT(_q_directoryChanged(QString,bool)));
+ }
+}
+
+void QFileSystemWatcherPrivate::initForcedEngine(const QString &forceName)
+{
+ if(forced)
+ return;
+
+ Q_Q(QFileSystemWatcher);
+
+#if defined(Q_OS_LINUX)
+ if(forceName == QLatin1String("inotify")) {
+ forced = QInotifyFileSystemWatcherEngine::create();
+ } else if(forceName == QLatin1String("dnotify")) {
+ forced = QDnotifyFileSystemWatcherEngine::create();
+ }
+#else
+ Q_UNUSED(forceName);
+#endif
+
+ if(forced) {
+ QObject::connect(forced,
+ SIGNAL(fileChanged(QString,bool)),
+ q,
+ SLOT(_q_fileChanged(QString,bool)));
+ QObject::connect(forced,
+ SIGNAL(directoryChanged(QString,bool)),
+ q,
+ SLOT(_q_directoryChanged(QString,bool)));
+ }
+}
+
+void QFileSystemWatcherPrivate::initPollerEngine()
+{
+ if(poller)
+ return;
+
+ Q_Q(QFileSystemWatcher);
+ poller = new QPollingFileSystemWatcherEngine; // that was a mouthful
+ QObject::connect(poller,
+ SIGNAL(fileChanged(QString,bool)),
+ q,
+ SLOT(_q_fileChanged(QString,bool)));
+ QObject::connect(poller,
+ SIGNAL(directoryChanged(QString,bool)),
+ q,
+ SLOT(_q_directoryChanged(QString,bool)));
+}
+
+void QFileSystemWatcherPrivate::_q_fileChanged(const QString &path, bool removed)
+{
+ Q_Q(QFileSystemWatcher);
+ if (!files.contains(path)) {
+ // the path was removed after a change was detected, but before we delivered the signal
+ return;
+ }
+ if (removed)
+ files.removeAll(path);
+ emit q->fileChanged(path);
+}
+
+void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool removed)
+{
+ Q_Q(QFileSystemWatcher);
+ if (!directories.contains(path)) {
+ // perhaps the path was removed after a change was detected, but before we delivered the signal
+ return;
+ }
+ if (removed)
+ directories.removeAll(path);
+ emit q->directoryChanged(path);
+}
+
+
+
+/*!
+ \class QFileSystemWatcher
+ \brief The QFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
+ \ingroup io
+ \since 4.2
+ \reentrant
+
+ QFileSystemWatcher monitors the file system for changes to files
+ and directories by watching a list of specified paths.
+
+ Call addPath() to watch a particular file or directory. Multiple
+ paths can be added using the addPaths() function. Existing paths can
+ be removed by using the removePath() and removePaths() functions.
+
+ QFileSystemWatcher examines each path added to it. Files that have
+ been added to the QFileSystemWatcher can be accessed using the
+ files() function, and directories using the directories() function.
+
+ The fileChanged() signal is emitted when a file has been modified,
+ renamed or removed from disk. Similarly, the directoryChanged()
+ signal is emitted when a directory or its contents is modified or
+ removed. Note that QFileSystemWatcher stops monitoring files once
+ they have been renamed or removed from disk, and directories once
+ they have been removed from disk.
+
+ \note On systems running a Linux kernel without inotify support,
+ file systems that contain watched paths cannot be unmounted.
+
+ \note Windows CE does not support directory monitoring by
+ default as this depends on the file system driver installed.
+
+ \note The act of monitoring files and directories for
+ modifications consumes system resources. This implies there is a
+ limit to the number of files and directories your process can
+ monitor simultaneously. On Mac OS X 10.4 and all BSD variants, for
+ example, an open file descriptor is required for each monitored
+ file. Some system limits the number of open file descriptors to 256
+ by default. This means that addPath() and addPaths() will fail if
+ your process tries to add more than 256 files or directories to
+ the file system monitor. Also note that your process may have
+ other file descriptors open in addition to the ones for files
+ being monitored, and these other open descriptors also count in
+ the total. Mac OS X 10.5 and up use a different backend and do not
+ suffer from this issue.
+
+
+ \sa QFile, QDir
+*/
+
+
+/*!
+ Constructs a new file system watcher object with the given \a parent.
+*/
+QFileSystemWatcher::QFileSystemWatcher(QObject *parent)
+ : QObject(*new QFileSystemWatcherPrivate, parent)
+{
+ d_func()->init();
+}
+
+/*!
+ Constructs a new file system watcher object with the given \a parent
+ which monitors the specified \a paths list.
+*/
+QFileSystemWatcher::QFileSystemWatcher(const QStringList &paths, QObject *parent)
+ : QObject(*new QFileSystemWatcherPrivate, parent)
+{
+ d_func()->init();
+ addPaths(paths);
+}
+
+/*!
+ Destroys the file system watcher.
+*/
+QFileSystemWatcher::~QFileSystemWatcher()
+{
+ Q_D(QFileSystemWatcher);
+ if (d->native) {
+ d->native->stop();
+ d->native->wait();
+ delete d->native;
+ d->native = 0;
+ }
+ if (d->poller) {
+ d->poller->stop();
+ d->poller->wait();
+ delete d->poller;
+ d->poller = 0;
+ }
+ if (d->forced) {
+ d->forced->stop();
+ d->forced->wait();
+ delete d->forced;
+ d->forced = 0;
+ }
+}
+
+/*!
+ Adds \a path to the file system watcher if \a path exists. The
+ path is not added if it does not exist, or if it is already being
+ monitored by the file system watcher.
+
+ If \a path specifies a directory, the directoryChanged() signal
+ will be emitted when \a path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when \a path is
+ modified, renamed or removed.
+
+ \note There is a system dependent limit to the number of files and
+ directories that can be monitored simultaneously. If this limit
+ has been reached, \a path will not be added to the file system
+ watcher, and a warning message will be printed to \e{stderr}.
+
+ \sa addPaths(), removePath()
+*/
+void QFileSystemWatcher::addPath(const QString &path)
+{
+ if (path.isEmpty()) {
+ qWarning("QFileSystemWatcher::addPath: path is empty");
+ return;
+ }
+ addPaths(QStringList(path));
+}
+
+/*!
+ Adds each path in \a paths to the file system watcher. Paths are
+ not added if they not exist, or if they are already being
+ monitored by the file system watcher.
+
+ If a path specifies a directory, the directoryChanged() signal
+ will be emitted when the path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when the path is
+ modified, renamed, or removed.
+
+ \note There is a system dependent limit to the number of files and
+ directories that can be monitored simultaneously. If this limit
+ has been reached, the excess \a paths will not be added to the
+ file system watcher, and a warning message will be printed to
+ \e{stderr} for each path that could not be added.
+
+ \sa addPath(), removePaths()
+*/
+void QFileSystemWatcher::addPaths(const QStringList &paths)
+{
+ Q_D(QFileSystemWatcher);
+ if (paths.isEmpty()) {
+ qWarning("QFileSystemWatcher::addPaths: list is empty");
+ return;
+ }
+
+ QStringList p = paths;
+ QFileSystemWatcherEngine *engine = 0;
+
+ if(!objectName().startsWith(QLatin1String("_qt_autotest_force_engine_"))) {
+ // Normal runtime case - search intelligently for best engine
+ if(d->native) {
+ engine = d->native;
+ } else {
+ d_func()->initPollerEngine();
+ engine = d->poller;
+ }
+
+ } else {
+ // Autotest override case - use the explicitly selected engine only
+ QString forceName = objectName().mid(26);
+ if(forceName == QLatin1String("poller")) {
+ qDebug() << "QFileSystemWatcher: skipping native engine, using only polling engine";
+ d_func()->initPollerEngine();
+ engine = d->poller;
+ } else if(forceName == QLatin1String("native")) {
+ qDebug() << "QFileSystemWatcher: skipping polling engine, using only native engine";
+ engine = d->native;
+ } else {
+ qDebug() << "QFileSystemWatcher: skipping polling and native engine, using only explicit" << forceName << "engine";
+ d_func()->initForcedEngine(forceName);
+ engine = d->forced;
+ }
+ }
+
+ if(engine)
+ p = engine->addPaths(p, &d->files, &d->directories);
+
+ if (!p.isEmpty())
+ qWarning("QFileSystemWatcher: failed to add paths: %s",
+ qPrintable(p.join(QLatin1String(", "))));
+}
+
+/*!
+ Removes the specified \a path from the file system watcher.
+
+ \sa removePaths(), addPath()
+*/
+void QFileSystemWatcher::removePath(const QString &path)
+{
+ if (path.isEmpty()) {
+ qWarning("QFileSystemWatcher::removePath: path is empty");
+ return;
+ }
+ removePaths(QStringList(path));
+}
+
+/*!
+ Removes the specified \a paths from the file system watcher.
+
+ \sa removePath(), addPaths()
+*/
+void QFileSystemWatcher::removePaths(const QStringList &paths)
+{
+ if (paths.isEmpty()) {
+ qWarning("QFileSystemWatcher::removePaths: list is empty");
+ return;
+ }
+ Q_D(QFileSystemWatcher);
+ QStringList p = paths;
+ if (d->native)
+ p = d->native->removePaths(p, &d->files, &d->directories);
+ if (d->poller)
+ p = d->poller->removePaths(p, &d->files, &d->directories);
+ if (d->forced)
+ p = d->forced->removePaths(p, &d->files, &d->directories);
+}
+
+/*!
+ \fn void QFileSystemWatcher::fileChanged(const QString &path)
+
+ This signal is emitted when the file at the specified \a path is
+ modified, renamed or removed from disk.
+
+ \sa directoryChanged()
+*/
+
+/*!
+ \fn void QFileSystemWatcher::directoryChanged(const QString &path)
+
+ This signal is emitted when the directory at a specified \a path,
+ is modified (e.g., when a file is added, modified or deleted) or
+ removed from disk. Note that if there are several changes during a
+ short period of time, some of the changes might not emit this
+ signal. However, the last change in the sequence of changes will
+ always generate this signal.
+
+ \sa fileChanged()
+*/
+
+/*!
+ \fn QStringList QFileSystemWatcher::directories() const
+
+ Returns a list of paths to directories that are being watched.
+
+ \sa files()
+*/
+
+/*!
+ \fn QStringList QFileSystemWatcher::files() const
+
+ Returns a list of paths to files that are being watched.
+
+ \sa directories()
+*/
+
+QStringList QFileSystemWatcher::directories() const
+{
+ Q_D(const QFileSystemWatcher);
+ return d->directories;
+}
+
+QStringList QFileSystemWatcher::files() const
+{
+ Q_D(const QFileSystemWatcher);
+ return d->files;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qfilesystemwatcher.cpp"
+
+#include "qfilesystemwatcher.moc"
+
+#endif // QT_NO_FILESYSTEMWATCHER
+
diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h
new file mode 100644
index 0000000000..26b3dec90f
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMWATCHER_H
+#define QFILESYSTEMWATCHER_H
+
+#include <QtCore/qobject.h>
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QFileSystemWatcherPrivate;
+
+class Q_CORE_EXPORT QFileSystemWatcher : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QFileSystemWatcher)
+
+public:
+ QFileSystemWatcher(QObject *parent = 0);
+ QFileSystemWatcher(const QStringList &paths, QObject *parent = 0);
+ ~QFileSystemWatcher();
+
+ void addPath(const QString &file);
+ void addPaths(const QStringList &files);
+ void removePath(const QString &file);
+ void removePaths(const QStringList &files);
+
+ QStringList files() const;
+ QStringList directories() const;
+
+Q_SIGNALS:
+ void fileChanged(const QString &path);
+ void directoryChanged(const QString &path);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_fileChanged(const QString &path, bool removed))
+ Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &path, bool removed))
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_FILESYSTEMWATCHER
+#endif // QFILESYSTEMWATCHER_H
diff --git a/src/corelib/io/qfilesystemwatcher_dnotify.cpp b/src/corelib/io/qfilesystemwatcher_dnotify.cpp
new file mode 100644
index 0000000000..2fcadf1488
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_dnotify.cpp
@@ -0,0 +1,461 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_dnotify_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include <qsocketnotifier.h>
+#include <qcoreapplication.h>
+#include <qfileinfo.h>
+#include <qtimer.h>
+#include <qwaitcondition.h>
+#include <qmutex.h>
+#include <dirent.h>
+#include <qdir.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "private/qcore_unix_p.h"
+
+#ifdef QT_LINUXBASE
+
+/* LSB doesn't standardize these */
+#define F_NOTIFY 1026
+#define DN_ACCESS 0x00000001
+#define DN_MODIFY 0x00000002
+#define DN_CREATE 0x00000004
+#define DN_DELETE 0x00000008
+#define DN_RENAME 0x00000010
+#define DN_ATTRIB 0x00000020
+#define DN_MULTISHOT 0x80000000
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static int qfswd_fileChanged_pipe[2];
+static void (*qfswd_old_sigio_handler)(int) = 0;
+static void (*qfswd_old_sigio_action)(int, siginfo_t *, void *) = 0;
+static void qfswd_sigio_monitor(int signum, siginfo_t *i, void *v)
+{
+ qt_safe_write(qfswd_fileChanged_pipe[1], reinterpret_cast<char*>(&i->si_fd), sizeof(int));
+
+ if (qfswd_old_sigio_handler && qfswd_old_sigio_handler != SIG_IGN)
+ qfswd_old_sigio_handler(signum);
+ if (qfswd_old_sigio_action)
+ qfswd_old_sigio_action(signum, i, v);
+}
+
+class QDnotifySignalThread : public QThread
+{
+Q_OBJECT
+public:
+ QDnotifySignalThread();
+ virtual ~QDnotifySignalThread();
+
+ void startNotify();
+
+ virtual void run();
+
+signals:
+ void fdChanged(int);
+
+protected:
+ virtual bool event(QEvent *);
+
+private slots:
+ void readFromDnotify();
+
+private:
+ QMutex mutex;
+ QWaitCondition wait;
+ bool isExecing;
+};
+
+Q_GLOBAL_STATIC(QDnotifySignalThread, dnotifySignal)
+
+QDnotifySignalThread::QDnotifySignalThread()
+: isExecing(false)
+{
+ moveToThread(this);
+
+ qt_safe_pipe(qfswd_fileChanged_pipe, O_NONBLOCK);
+
+ struct sigaction oldAction;
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_sigaction = qfswd_sigio_monitor;
+ action.sa_flags = SA_SIGINFO;
+ ::sigaction(SIGIO, &action, &oldAction);
+ if (!(oldAction.sa_flags & SA_SIGINFO))
+ qfswd_old_sigio_handler = oldAction.sa_handler;
+ else
+ qfswd_old_sigio_action = oldAction.sa_sigaction;
+}
+
+QDnotifySignalThread::~QDnotifySignalThread()
+{
+ if(isRunning()) {
+ quit();
+ QThread::wait();
+ }
+}
+
+bool QDnotifySignalThread::event(QEvent *e)
+{
+ if(e->type() == QEvent::User) {
+ QMutexLocker locker(&mutex);
+ isExecing = true;
+ wait.wakeAll();
+ return true;
+ } else {
+ return QThread::event(e);
+ }
+}
+
+void QDnotifySignalThread::startNotify()
+{
+ // Note: All this fancy waiting for the thread to enter its event
+ // loop is to avoid nasty messages at app shutdown when the
+ // QDnotifySignalThread singleton is deleted
+ start();
+ mutex.lock();
+ while(!isExecing)
+ wait.wait(&mutex);
+ mutex.unlock();
+}
+
+void QDnotifySignalThread::run()
+{
+ QSocketNotifier sn(qfswd_fileChanged_pipe[0], QSocketNotifier::Read, this);
+ connect(&sn, SIGNAL(activated(int)), SLOT(readFromDnotify()));
+
+ QCoreApplication::instance()->postEvent(this, new QEvent(QEvent::User));
+ (void) exec();
+}
+
+void QDnotifySignalThread::readFromDnotify()
+{
+ int fd;
+ int readrv = qt_safe_read(qfswd_fileChanged_pipe[0], reinterpret_cast<char*>(&fd), sizeof(int));
+ // Only expect EAGAIN or EINTR. Other errors are assumed to be impossible.
+ if(readrv != -1) {
+ Q_ASSERT(readrv == sizeof(int));
+ Q_UNUSED(readrv);
+
+ if(0 == fd)
+ quit();
+ else
+ emit fdChanged(fd);
+ }
+}
+
+QDnotifyFileSystemWatcherEngine::QDnotifyFileSystemWatcherEngine()
+{
+ QObject::connect(dnotifySignal(), SIGNAL(fdChanged(int)),
+ this, SLOT(refresh(int)), Qt::DirectConnection);
+}
+
+QDnotifyFileSystemWatcherEngine::~QDnotifyFileSystemWatcherEngine()
+{
+ QMutexLocker locker(&mutex);
+
+ for(QHash<int, Directory>::ConstIterator iter = fdToDirectory.constBegin();
+ iter != fdToDirectory.constEnd();
+ ++iter) {
+ qt_safe_close(iter->fd);
+ if(iter->parentFd)
+ qt_safe_close(iter->parentFd);
+ }
+}
+
+QDnotifyFileSystemWatcherEngine *QDnotifyFileSystemWatcherEngine::create()
+{
+ return new QDnotifyFileSystemWatcherEngine();
+}
+
+void QDnotifyFileSystemWatcherEngine::run()
+{
+ qFatal("QDnotifyFileSystemWatcherEngine thread should not be run");
+}
+
+QStringList QDnotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+
+ while (it.hasNext()) {
+ QString path = it.next();
+
+ QFileInfo fi(path);
+
+ if(!fi.exists()) {
+ continue;
+ }
+
+ bool isDir = fi.isDir();
+
+ if (isDir && directories->contains(path)) {
+ continue; // Skip monitored directories
+ } else if(!isDir && files->contains(path)) {
+ continue; // Skip monitored files
+ }
+
+ if(!isDir)
+ path = fi.canonicalPath();
+
+ // Locate the directory entry (creating if needed)
+ int fd = pathToFD[path];
+
+ if(fd == 0) {
+
+ QT_DIR *d = QT_OPENDIR(path.toUtf8().constData());
+ if(!d) continue; // Could not open directory
+ QT_DIR *parent = 0;
+
+ QDir parentDir(path);
+ if(!parentDir.isRoot()) {
+ parentDir.cdUp();
+ parent = QT_OPENDIR(parentDir.path().toUtf8().constData());
+ if(!parent) {
+ QT_CLOSEDIR(d);
+ continue;
+ }
+ }
+
+ fd = qt_safe_dup(::dirfd(d));
+ int parentFd = parent ? qt_safe_dup(::dirfd(parent)) : 0;
+
+ QT_CLOSEDIR(d);
+ if(parent) QT_CLOSEDIR(parent);
+
+ Q_ASSERT(fd);
+ if(::fcntl(fd, F_SETSIG, SIGIO) ||
+ ::fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_DELETE |
+ DN_RENAME | DN_ATTRIB | DN_MULTISHOT) ||
+ (parent && ::fcntl(parentFd, F_SETSIG, SIGIO)) ||
+ (parent && ::fcntl(parentFd, F_NOTIFY, DN_DELETE | DN_RENAME |
+ DN_MULTISHOT))) {
+ continue; // Could not set appropriate flags
+ }
+
+ Directory dir;
+ dir.path = path;
+ dir.fd = fd;
+ dir.parentFd = parentFd;
+
+ fdToDirectory.insert(fd, dir);
+ pathToFD.insert(path, fd);
+ if(parentFd)
+ parentToFD.insert(parentFd, fd);
+ }
+
+ Directory &directory = fdToDirectory[fd];
+
+ if(isDir) {
+ directory.isMonitored = true;
+ } else {
+ Directory::File file;
+ file.path = fi.filePath();
+ file.lastWrite = fi.lastModified();
+ directory.files.append(file);
+ pathToFD.insert(fi.filePath(), fd);
+ }
+
+ it.remove();
+
+ if(isDir) {
+ directories->append(path);
+ } else {
+ files->append(fi.filePath());
+ }
+ }
+
+ dnotifySignal()->startNotify();
+
+ return p;
+}
+
+QStringList QDnotifyFileSystemWatcherEngine::removePaths(const QStringList &paths, QStringList *files, QStringList *directories)
+{
+ QMutexLocker locker(&mutex);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+
+ QString path = it.next();
+ int fd = pathToFD.take(path);
+
+ if(!fd)
+ continue;
+
+ Directory &directory = fdToDirectory[fd];
+ bool isDir = false;
+ if(directory.path == path) {
+ isDir = true;
+ directory.isMonitored = false;
+ } else {
+ for(int ii = 0; ii < directory.files.count(); ++ii) {
+ if(directory.files.at(ii).path == path) {
+ directory.files.removeAt(ii);
+ break;
+ }
+ }
+ }
+
+ if(!directory.isMonitored && directory.files.isEmpty()) {
+ // No longer needed
+ qt_safe_close(directory.fd);
+ pathToFD.remove(directory.path);
+ fdToDirectory.remove(fd);
+ }
+
+ if(isDir) {
+ directories->removeAll(path);
+ } else {
+ files->removeAll(path);
+ }
+
+ it.remove();
+ }
+
+ return p;
+}
+
+void QDnotifyFileSystemWatcherEngine::refresh(int fd)
+{
+ QMutexLocker locker(&mutex);
+
+ bool wasParent = false;
+ QHash<int, Directory>::Iterator iter = fdToDirectory.find(fd);
+ if(iter == fdToDirectory.end()) {
+ QHash<int, int>::Iterator pIter = parentToFD.find(fd);
+ if(pIter == parentToFD.end())
+ return;
+
+ iter = fdToDirectory.find(*pIter);
+ if (iter == fdToDirectory.end())
+ return;
+ wasParent = true;
+ }
+
+ Directory &directory = *iter;
+
+ if(!wasParent) {
+ for(int ii = 0; ii < directory.files.count(); ++ii) {
+ Directory::File &file = directory.files[ii];
+ if(file.updateInfo()) {
+ // Emit signal
+ QString filePath = file.path;
+ bool removed = !QFileInfo(filePath).exists();
+
+ if(removed) {
+ directory.files.removeAt(ii);
+ --ii;
+ }
+
+ emit fileChanged(filePath, removed);
+ }
+ }
+ }
+
+ if(directory.isMonitored) {
+ // Emit signal
+ bool removed = !QFileInfo(directory.path).exists();
+ QString path = directory.path;
+
+ if(removed)
+ directory.isMonitored = false;
+
+ emit directoryChanged(path, removed);
+ }
+
+ if(!directory.isMonitored && directory.files.isEmpty()) {
+ qt_safe_close(directory.fd);
+ if(directory.parentFd) {
+ qt_safe_close(directory.parentFd);
+ parentToFD.remove(directory.parentFd);
+ }
+ fdToDirectory.erase(iter);
+ }
+}
+
+void QDnotifyFileSystemWatcherEngine::stop()
+{
+}
+
+bool QDnotifyFileSystemWatcherEngine::Directory::File::updateInfo()
+{
+ QFileInfo fi(path);
+ QDateTime nLastWrite = fi.lastModified();
+ uint nOwnerId = fi.ownerId();
+ uint nGroupId = fi.groupId();
+ QFile::Permissions nPermissions = fi.permissions();
+
+ if(nLastWrite != lastWrite ||
+ nOwnerId != ownerId ||
+ nGroupId != groupId ||
+ nPermissions != permissions) {
+ ownerId = nOwnerId;
+ groupId = nGroupId;
+ permissions = nPermissions;
+ lastWrite = nLastWrite;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qfilesystemwatcher_dnotify.moc"
+
+#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_dnotify_p.h b/src/corelib/io/qfilesystemwatcher_dnotify_p.h
new file mode 100644
index 0000000000..9531a3e81b
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_dnotify_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMWATCHER_DNOTIFY_P_H
+#define QFILESYSTEMWATCHER_DNOTIFY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfilesystemwatcher_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include <qmutex.h>
+#include <qhash.h>
+#include <qdatetime.h>
+#include <qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDnotifyFileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+ Q_OBJECT
+
+public:
+ virtual ~QDnotifyFileSystemWatcherEngine();
+
+ static QDnotifyFileSystemWatcherEngine *create();
+
+ void run();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ void stop();
+
+private Q_SLOTS:
+ void refresh(int);
+
+private:
+ struct Directory {
+ Directory() : fd(0), parentFd(0), isMonitored(false) {}
+ Directory(const Directory &o) : path(o.path),
+ fd(o.fd),
+ parentFd(o.parentFd),
+ isMonitored(o.isMonitored),
+ files(o.files) {}
+ QString path;
+ int fd;
+ int parentFd;
+ bool isMonitored;
+
+ struct File {
+ File() : ownerId(0u), groupId(0u), permissions(0u) { }
+ File(const File &o) : path(o.path),
+ ownerId(o.ownerId),
+ groupId(o.groupId),
+ permissions(o.permissions),
+ lastWrite(o.lastWrite) {}
+ QString path;
+
+ bool updateInfo();
+
+ uint ownerId;
+ uint groupId;
+ QFile::Permissions permissions;
+ QDateTime lastWrite;
+ };
+
+ QList<File> files;
+ };
+
+ QDnotifyFileSystemWatcherEngine();
+
+ QMutex mutex;
+ QHash<QString, int> pathToFD;
+ QHash<int, Directory> fdToDirectory;
+ QHash<int, int> parentToFD;
+};
+
+
+
+QT_END_NAMESPACE
+#endif // QT_NO_FILESYSTEMWATCHER
+#endif // QFILESYSTEMWATCHER_DNOTIFY_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
new file mode 100644
index 0000000000..19b720c8b3
--- /dev/null
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
@@ -0,0 +1,492 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qplatformdefs.h>
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_fsevents_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include <qdebug.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qvarlengtharray.h>
+
+#include <mach/mach.h>
+#include <sys/types.h>
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CFUUID.h>
+#include <CoreServices/CoreServices.h>
+#include <AvailabilityMacros.h>
+#include <private/qcore_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// Static operator overloading so for the sake of some convieniece.
+// They only live in this compilation unit to avoid polluting Qt in general.
+static bool operator==(const struct ::timespec &left, const struct ::timespec &right)
+{
+ return left.tv_sec == right.tv_sec
+ && left.tv_nsec == right.tv_nsec;
+}
+
+static bool operator==(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return left.st_dev == right.st_dev
+ && left.st_mode == right.st_mode
+ && left.st_size == right.st_size
+ && left.st_ino == right.st_ino
+ && left.st_uid == right.st_uid
+ && left.st_gid == right.st_gid
+ && left.st_mtimespec == right.st_mtimespec
+ && left.st_ctimespec == right.st_ctimespec
+ && left.st_flags == right.st_flags;
+}
+
+static bool operator!=(const struct ::stat64 &left, const struct ::stat64 &right)
+{
+ return !(operator==(left, right));
+}
+
+
+static void addPathToHash(PathHash &pathHash, const QString &key, const QFileInfo &fileInfo,
+ const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ list.push_back(PathInfo(path,
+ fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_D).toUtf8()));
+ pathHash.insert(key, list);
+}
+
+static void removePathFromHash(PathHash &pathHash, const QString &key, const QString &path)
+{
+ PathInfoList &list = pathHash[key];
+ // We make the assumption that the list contains unique paths
+ PathInfoList::iterator End = list.end();
+ PathInfoList::iterator it = list.begin();
+ while (it != End) {
+ if (it->originalPath == path) {
+ list.erase(it);
+ break;
+ }
+ ++it;
+ }
+ if (list.isEmpty())
+ pathHash.remove(key);
+}
+
+static void stopFSStream(FSEventStreamRef stream)
+{
+ if (stream) {
+ FSEventStreamStop(stream);
+ FSEventStreamInvalidate(stream);
+ }
+}
+
+static QString createFSStreamPath(const QString &absolutePath)
+{
+ // The path returned has a trailing slash, so ensure that here.
+ QString string = absolutePath;
+ string.reserve(string.size() + 1);
+ string.append(QLatin1Char('/'));
+ return string;
+}
+
+static void cleanupFSStream(FSEventStreamRef stream)
+{
+ if (stream)
+ FSEventStreamRelease(stream);
+}
+
+const FSEventStreamCreateFlags QtFSEventFlags = (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer /* | kFSEventStreamCreateFlagWatchRoot*/);
+
+const CFTimeInterval Latency = 0.033; // This will do updates 30 times a second which is probably more than you need.
+#endif
+
+QFSEventsFileSystemWatcherEngine::QFSEventsFileSystemWatcherEngine()
+ : fsStream(0), pathsToWatch(0), threadsRunLoop(0)
+{
+}
+
+QFSEventsFileSystemWatcherEngine::~QFSEventsFileSystemWatcherEngine()
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ // I assume that at this point, QFileSystemWatcher has already called stop
+ // on me, so I don't need to invalidate or stop my stream, simply
+ // release it.
+ cleanupFSStream(fsStream);
+ if (pathsToWatch)
+ CFRelease(pathsToWatch);
+#endif
+}
+
+QFSEventsFileSystemWatcherEngine *QFSEventsFileSystemWatcherEngine::create()
+{
+ return new QFSEventsFileSystemWatcherEngine();
+}
+
+QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
+ QStringList *files,
+ QStringList *directories)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ stop();
+ wait();
+ QMutexLocker locker(&mutex);
+ QStringList failedToAdd;
+ // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon.
+ FSEventStreamEventId idToCheck;
+ if (fsStream) {
+ idToCheck = FSEventStreamGetLatestEventId(fsStream);
+ cleanupFSStream(fsStream);
+ } else {
+ idToCheck = kFSEventStreamEventIdSinceNow;
+ }
+
+ // Brain-dead approach, but works. FSEvents actually can already read sub-trees, but since it's
+ // work to figure out if we are doing a double register, we just register it twice as FSEvents
+ // seems smart enough to only deliver one event. We also duplicate directory entries in here
+ // (e.g., if you watch five files in the same directory, you get that directory included in the
+ // array 5 times). This stupidity also makes remove work correctly though. I'll freely admit
+ // that we could make this a bit smarter. If you do, check the auto-tests, they should catch at
+ // least a couple of the issues.
+ QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ for (int i = 0; i < paths.size(); ++i) {
+ const QString &path = paths.at(i);
+
+ QFileInfo fileInfo(path);