diff options
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/io.pri | 4 | ||||
-rw-r--r-- | src/corelib/io/qabstractfileengine.cpp | 31 | ||||
-rw-r--r-- | src/corelib/io/qabstractfileengine_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.cpp | 3 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qdebug.cpp | 73 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 12 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemengine_unix.cpp | 14 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine.cpp | 16 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_p.h | 3 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 23 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 29 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 4 | ||||
-rw-r--r-- | src/corelib/io/qsavefile.cpp | 316 | ||||
-rw-r--r-- | src/corelib/io/qsavefile.h | 94 | ||||
-rw-r--r-- | src/corelib/io/qsavefile_p.h | 75 | ||||
-rw-r--r-- | src/corelib/io/qtemporaryfile.cpp | 60 | ||||
-rw-r--r-- | src/corelib/io/qtemporaryfile_p.h | 101 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.cpp | 218 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qtextstream_p.h | 185 | ||||
-rw-r--r-- | src/corelib/io/qurl.cpp | 31 | ||||
-rw-r--r-- | src/corelib/io/qurl.h | 3 |
23 files changed, 1076 insertions, 227 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index f57dcebe33..e0364a1460 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -22,10 +22,13 @@ HEADERS += \ io/qprocess.h \ io/qprocess_p.h \ io/qtextstream.h \ + io/qtextstream_p.h \ io/qtemporarydir.h \ io/qtemporaryfile.h \ + io/qtemporaryfile_p.h \ io/qresource_p.h \ io/qresource_iterator_p.h \ + io/qsavefile.h \ io/qstandardpaths.h \ io/qurl.h \ io/qurl_p.h \ @@ -65,6 +68,7 @@ SOURCES += \ io/qtemporaryfile.cpp \ io/qresource.cpp \ io/qresource_iterator.cpp \ + io/qsavefile.cpp \ io/qstandardpaths.cpp \ io/qurl.cpp \ io/qurlidna.cpp \ diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 2d9cb85d9f..9cdbbbbb25 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -400,6 +400,19 @@ bool QAbstractFileEngine::close() } /*! + \since 5.1 + + Flushes and syncs the file to disk. + + Returns true if successful; otherwise returns false. + The default implementation always returns false. +*/ +bool QAbstractFileEngine::syncToDisk() +{ + return false; +} + +/*! Flushes the open file, returning true if successful; otherwise returns false. @@ -496,6 +509,24 @@ bool QAbstractFileEngine::rename(const QString &newName) } /*! + \since 5.1 + + Requests that the file be renamed to \a newName in the file + system. If the new name already exists, it must be overwritten. + If the operation succeeds, returns true; otherwise returns + false. + + This virtual function must be reimplemented by all subclasses. + + \sa setFileName() + */ +bool QAbstractFileEngine::renameOverwrite(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 diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index 868b086b57..bdc4b5c123 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -124,6 +124,7 @@ public: virtual bool open(QIODevice::OpenMode openMode); virtual bool close(); virtual bool flush(); + virtual bool syncToDisk(); virtual qint64 size() const; virtual qint64 pos() const; virtual bool seek(qint64 pos); @@ -131,6 +132,7 @@ public: virtual bool remove(); virtual bool copy(const QString &newName); virtual bool rename(const QString &newName); + virtual bool renameOverwrite(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; diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 544e9e8592..8f788ac355 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -251,7 +251,7 @@ QT_BEGIN_NAMESPACE return retVal; enum { - DefaultStreamVersion = QDataStream::Qt_5_0 + DefaultStreamVersion = QDataStream::Qt_5_1 }; /*! @@ -539,6 +539,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_8 Same as Qt_4_6. \value Qt_4_9 Same as Qt_4_6. \value Qt_5_0 Version 13 (Qt 5.0) + \value Qt_5_1 Same as Qt_5_0. \sa setVersion(), version() */ diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 092f3a15b3..f85dd0fb23 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -87,8 +87,9 @@ public: Qt_4_7 = Qt_4_6, Qt_4_8 = Qt_4_7, Qt_4_9 = Qt_4_8, - Qt_5_0 = 13 -#if QT_VERSION >= 0x050100 + Qt_5_0 = 13, + Qt_5_1 = Qt_5_0 +#if QT_VERSION >= 0x050200 #error Add the datastream version for this Qt version #endif }; diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index bd43963139..9cb5609dac 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -47,6 +47,9 @@ #endif #include "qdebug.h" +#include <private/qtextstream_p.h> + +QT_BEGIN_NAMESPACE // This file is needed to force compilation of QDebug into the kernel library. @@ -170,6 +173,8 @@ between writes. \since 5.0 + + \sa QDebugStateSaver */ /*! @@ -179,6 +184,8 @@ automatic insertion of spaces is disabled. \since 5.0 + + \sa QDebugStateSaver */ /*! @@ -321,3 +328,69 @@ \fn QDebug &QDebug::operator<<(QTextStreamManipulator m) \internal */ + +/*! + \class QDebugStateSaver + + \brief Convenience class for custom QDebug operators + + Saves the settings used by QDebug, and restores them upon destruction. + + The automatic insertion of spaces between writes is one of the settings + that QDebugStateSaver stores for the duration of the current block. + + The settings of the internal QTextStream are also saved and restored, + so that using << hex in a QDebug operator doesn't affect other QDebug + operators. + + \since 5.1 +*/ + +class QDebugStateSaverPrivate +{ +public: + QDebugStateSaverPrivate(QDebug &dbg) + : m_dbg(dbg), + m_spaces(dbg.autoInsertSpaces()), + m_streamParams(dbg.stream->ts.d_ptr->params) + { + } + void restoreState() + { + m_dbg.setAutoInsertSpaces(m_spaces); + m_dbg.stream->ts.d_ptr->params = m_streamParams; + } + + QDebug &m_dbg; + + // QDebug state + const bool m_spaces; + + // QTextStream state + const QTextStreamPrivate::Params m_streamParams; +}; + + +/*! + Creates a QDebugStateSaver instance, which saves the settings + currently used by \a dbg. + + \sa QDebug::setAutoInsertSpaces(), QDebug::autoInsertSpaces() +*/ +QDebugStateSaver::QDebugStateSaver(QDebug &dbg) + : d(new QDebugStateSaverPrivate(dbg)) +{ +} + +/*! + Destroyes a QDebugStateSaver instance, which restores the settings + used by \a dbg when the QDebugStateSaver instance was created. + + \sa QDebug::setAutoInsertSpaces(), QDebug::autoInsertSpaces() +*/ +QDebugStateSaver::~QDebugStateSaver() +{ + d->restoreState(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index be8252fbb2..b39397858e 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QDebug { friend class QMessageLogger; + friend class QDebugStateSaverPrivate; 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) {} @@ -132,6 +133,17 @@ public: Q_DECLARE_SHARED(QDebug) +class QDebugStateSaverPrivate; +class Q_CORE_EXPORT QDebugStateSaver +{ +public: + QDebugStateSaver(QDebug &dbg); + ~QDebugStateSaver(); +private: + Q_DISABLE_COPY(QDebugStateSaver) + QScopedPointer<QDebugStateSaverPrivate> d; +}; + class QNoDebug { public: diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 4af01f6730..1fe1107d95 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -286,7 +286,7 @@ QString QFileSystemEngine::resolveUserName(uint userId) struct passwd *pw = 0; #if !defined(Q_OS_INTEGRITY) -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS) struct passwd entry; getpwuid_r(userId, &entry, buf.data(), buf.size(), &pw); #else @@ -310,7 +310,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId) struct group *gr = 0; #if !defined(Q_OS_INTEGRITY) -#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS) size_max = sysconf(_SC_GETGR_R_SIZE_MAX); if (size_max == -1) size_max = 1024; @@ -685,8 +685,16 @@ QFileSystemEntry QFileSystemEngine::currentPath() } #else char currentName[PATH_MAX+1]; - if (::getcwd(currentName, PATH_MAX)) + if (::getcwd(currentName, PATH_MAX)) { +#if defined(Q_OS_VXWORKS) && defined(VXWORKS_VXSIM) + QByteArray dir(currentName); + if (dir.indexOf(':') < dir.indexOf('/')) + dir.remove(0, dir.indexOf(':')+1); + + qstrncpy(currentName, dir.constData(), PATH_MAX); +#endif result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath()); + } # if defined(QT_DEBUG) if (result.isEmpty()) qWarning("QFileSystemEngine::currentPath: getcwd() failed"); diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index b1d7ca9dd1..1206b992e6 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -419,6 +419,17 @@ bool QFSFileEngine::flush() } /*! + \reimp +*/ +bool QFSFileEngine::syncToDisk() +{ + Q_D(QFSFileEngine); + if ((d->openMode & QIODevice::WriteOnly) == 0) + return true; + return d->nativeSyncToDisk(); +} + +/*! \internal */ bool QFSFileEnginePrivate::flushFh() @@ -908,6 +919,11 @@ bool QFSFileEngine::supportsExtension(Extension extension) const \reimp */ + +/*! \fn bool QFSFileEngine::renameOverwrite(const QString &newName) + \reimp +*/ + /*! \fn bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const \reimp */ diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index d19310b6b6..21f38fea1d 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -81,6 +81,7 @@ public: bool open(QIODevice::OpenMode flags, FILE *fh); bool close(); bool flush(); + bool syncToDisk(); qint64 size() const; qint64 pos() const; bool seek(qint64); @@ -88,6 +89,7 @@ public: bool remove(); bool copy(const QString &newName); bool rename(const QString &newName); + bool renameOverwrite(const QString &newName); bool link(const QString &newName); bool mkdir(const QString &dirName, bool createParentDirectories) const; bool rmdir(const QString &dirName, bool recurseParentDirectories) const; @@ -149,6 +151,7 @@ public: bool nativeClose(); bool closeFdFh(); bool nativeFlush(); + bool nativeSyncToDisk(); bool flushFh(); qint64 nativeSize() const; #ifndef Q_OS_WIN diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 482f65e7f6..a5f077bd0b 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -258,6 +258,23 @@ bool QFSFileEnginePrivate::nativeFlush() /*! \internal + \since 5.1 +*/ +bool QFSFileEnginePrivate::nativeSyncToDisk() +{ + Q_Q(QFSFileEngine); +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 + const int ret = fdatasync(nativeHandle()); +#else + const int ret = fsync(nativeHandle()); +#endif + if (ret != 0) + q->setError(QFile::WriteError, qt_error_string(errno)); + return ret == 0; +} + +/*! + \internal */ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len) { @@ -388,6 +405,12 @@ bool QFSFileEngine::copy(const QString &newName) return ret; } +bool QFSFileEngine::renameOverwrite(const QString &newName) +{ + // On Unix, rename() overwrites. + return rename(newName); +} + bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 1cb3c03c30..fecfa7de2b 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -198,15 +198,25 @@ bool QFSFileEnginePrivate::nativeFlush() return true; } - // Windows native mode; flushing is - // unnecessary. FlushFileBuffers(), the equivalent of sync() or - // fsync() on Unix, does a low-level flush to the disk, and we - // don't expose an API for this. + // Windows native mode; flushing is unnecessary. return true; } /* \internal + \since 5.1 +*/ +bool QFSFileEnginePrivate::nativeSyncToDisk() +{ + if (fh || fd != -1) { + // stdlib / stdio mode. No API available. + return false; + } + return FlushFileBuffers(fileHandle); +} + +/* + \internal */ qint64 QFSFileEnginePrivate::nativeSize() const { @@ -507,6 +517,17 @@ bool QFSFileEngine::rename(const QString &newName) return ret; } +bool QFSFileEngine::renameOverwrite(const QString &newName) +{ + Q_D(QFSFileEngine); + bool ret = ::MoveFileEx((wchar_t*)d->fileEntry.nativeFilePath().utf16(), + (wchar_t*)QFileSystemEntry(newName).nativeFilePath().utf16(), + MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0; + if (!ret) + setError(QFile::RenameError, QSystemError(::GetLastError(), QSystemError::NativeError).toString()); + return ret; +} + bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const { return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index e159bf8f30..3daae8b2f6 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1001,9 +1001,9 @@ static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout) if (timeout < 0) return qt_safe_select(nfds, fdread, fdwrite, 0, 0); - struct timeval tv; + struct timespec tv; tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + tv.tv_nsec = (timeout % 1000) * 1000 * 1000; return qt_safe_select(nfds, fdread, fdwrite, 0, &tv); } diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp new file mode 100644 index 0000000000..fee6a4c4d8 --- /dev/null +++ b/src/corelib/io/qsavefile.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2012 David Faure <faure@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qsavefile.h" +#include "private/qsavefile_p.h" +#include "qfileinfo.h" +#include "qabstractfileengine_p.h" +#include "qdebug.h" +#include "qtemporaryfile.h" +#include "private/qiodevice_p.h" +#include "private/qtemporaryfile_p.h" + +QT_BEGIN_NAMESPACE + +QSaveFilePrivate::QSaveFilePrivate() + : writeError(QFileDevice::NoError) +{ +} + +QSaveFilePrivate::~QSaveFilePrivate() +{ +} + +/*! + \class QSaveFile + \inmodule QtCore + \brief The QSaveFile class provides an interface for safely writing to files. + + \ingroup io + + \reentrant + + \since 5.1 + + QSaveFile is an I/O device for writing text and binary files, without losing + existing data if the writing operation fails. + + While writing, the contents will be written to a temporary file, and if + no error happened, commit() will move it to the final file. This ensures that + no data at the final file is lost in case an error happens while writing, + and no partially-written file is ever present at the final location. Always + use QSaveFile when saving entire documents to disk. + + QSaveFile automatically detects errors while writing, such as the full partition + situation, where write() cannot write all the bytes. It will remember that + an error happened, and will discard the temporary file in commit(). + + Much like with QFile, the file is opened with open(). Data is usually read + and written using QDataStream or QTextStream, but you can also call the + QIODevice-inherited functions read(), readLine(), readAll(), write(). + + Unlike QFile, calling close() is not allowed. commit() replaces it. If commit() + was not called and the QSaveFile instance is destroyed, the temporary file is + discarded. + + To abort saving due to an application error, call cancelWriting(), so that + even a call to commit() later on will not save. + + \sa QTextStream, QDataStream, QFileInfo, QDir, QFile, QTemporaryFile +*/ + +/*! + Constructs a new file object with the given \a parent. +*/ +QSaveFile::QSaveFile(QObject *parent) + : QFileDevice(*new QSaveFilePrivate, parent) +{ +} +/*! + Constructs a new file object to represent the file with the given \a name. +*/ +QSaveFile::QSaveFile(const QString &name) + : QFileDevice(*new QSaveFilePrivate, 0) +{ + Q_D(QSaveFile); + d->fileName = name; +} +/*! + Constructs a new file object with the given \a parent to represent the + file with the specified \a name. +*/ +QSaveFile::QSaveFile(const QString &name, QObject *parent) + : QFileDevice(*new QSaveFilePrivate, parent) +{ + Q_D(QSaveFile); + d->fileName = name; +} + +/*! + Destroys the file object, discarding the saved contents unless commit() was called. +*/ +QSaveFile::~QSaveFile() +{ + Q_D(QSaveFile); + QFileDevice::close(); + if (d->fileEngine) { + d->fileEngine->remove(); + delete d->fileEngine; + d->fileEngine = 0; + } +} + +/*! + Returns the name set by setFileName() or to the QSaveFile + constructor. + + \sa setFileName() +*/ +QString QSaveFile::fileName() const +{ + return d_func()->fileName; +} + +/*! + Sets the \a name of the file. The name can have no path, a + relative path, or an absolute path. + + \sa QFile::setFileName(), fileName() +*/ +void QSaveFile::setFileName(const QString &name) +{ + d_func()->fileName = name; +} + +/*! + Opens the file using OpenMode \a mode, returning true if successful; + otherwise false. + + Important: the \a mode must include QIODevice::WriteOnly. + It may also have additional flags, such as QIODevice::Text and QIODevice::Unbuffered. + + QIODevice::ReadWrite and QIODevice::Append are not supported at the moment. + + \sa QIODevice::OpenMode, setFileName() +*/ +bool QSaveFile::open(OpenMode mode) +{ + Q_D(QSaveFile); + if (isOpen()) { + qWarning("QSaveFile::open: File (%s) already open", qPrintable(fileName())); + return false; + } + unsetError(); + if ((mode & (ReadOnly | WriteOnly)) == 0) { + qWarning("QSaveFile::open: Open mode not specified"); + return false; + } + // In the future we could implement ReadWrite by copying from the existing file to the temp file... + if ((mode & ReadOnly) || (mode & Append)) { + qWarning("QSaveFile::open: Unsupported open mode 0x%x", int(mode)); + return false; + } + + // check if existing file is writable + QFileInfo existingFile(d->fileName); + if (existingFile.exists() && !existingFile.isWritable()) { + d->setError(QFileDevice::WriteError, QSaveFile::tr("Existing file %1 is not writable").arg(d->fileName)); + d->writeError = QFileDevice::WriteError; + return false; + } + d->fileEngine = new QTemporaryFileEngine(d->fileName); + // Same as in QFile: QIODevice provides the buffering, so there's no need to request it from the file engine. + if (!d->fileEngine->open(mode | QIODevice::Unbuffered)) { + QFileDevice::FileError err = d->fileEngine->error(); + if (err == QFileDevice::UnspecifiedError) + err = QFileDevice::OpenError; + d->setError(err, d->fileEngine->errorString()); + delete d->fileEngine; + d->fileEngine = 0; + return false; + } + + QFileDevice::open(mode); + if (existingFile.exists()) + setPermissions(existingFile.permissions()); + return true; +} + +/*! + \reimp + This method has been made private so that it cannot be called, in order to prevent mistakes. + In order to finish writing the file, call commit(). + If instead you want to abort writing, call cancelWriting(). +*/ +void QSaveFile::close() +{ + qFatal("QSaveFile::close called"); +} + +/*! + Commits the changes to disk, if all previous writes were successful. + + It is mandatory to call this at the end of the saving operation, otherwise the file will be + discarded. + + If an error happened during writing, deletes the temporary file and returns false. + Otherwise, renames it to the final fileName and returns true on success. + Finally, closes the device. + + \sa cancelWriting() +*/ +bool QSaveFile::commit() +{ + Q_D(QSaveFile); + if (!d->fileEngine) + return false; + + if (!isOpen()) { + qWarning("QSaveFile::commit: File (%s) is not open", qPrintable(fileName())); + return false; + } + QFileDevice::close(); // calls flush() + + // Sync to disk if possible. Ignore errors (e.g. not supported). + d->fileEngine->syncToDisk(); + + if (d->writeError != QFileDevice::NoError) { + d->fileEngine->remove(); + d->writeError = QFileDevice::NoError; + delete d->fileEngine; + d->fileEngine = 0; + return false; + } + // atomically replace old file with new file + // Can't use QFile::rename for that, must use the file engine directly + Q_ASSERT(d->fileEngine); + if (!d->fileEngine->renameOverwrite(d->fileName)) { + d->setError(d->fileEngine->error(), d->fileEngine->errorString()); + d->fileEngine->remove(); + delete d->fileEngine; + d->fileEngine = 0; + return false; + } + delete d->fileEngine; + d->fileEngine = 0; + return true; +} + +/*! + Cancels writing the new file. + + If the application changes its mind while saving, it can call cancelWriting(), + which sets an error code so that commit() will discard the temporary file. + + Alternatively, it can simply make sure not to call commit(). + + Further write operations are possible after calling this method, but none + of it will have any effect, the written file will be discarded. + + \sa commit() +*/ +void QSaveFile::cancelWriting() +{ + Q_D(QSaveFile); + if (!isOpen()) + return; + d->setError(QFileDevice::WriteError, QSaveFile::tr("Writing canceled by application")); + d->writeError = QFileDevice::WriteError; +} + +/*! + \reimp +*/ +qint64 QSaveFile::writeData(const char *data, qint64 len) +{ + Q_D(QSaveFile); + if (d->writeError != QFileDevice::NoError) + return -1; + + const qint64 ret = QFileDevice::writeData(data, len); + + if (d->error != QFileDevice::NoError) + d->writeError = d->error; + return ret; +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h new file mode 100644 index 0000000000..47a02a0b83 --- /dev/null +++ b/src/corelib/io/qsavefile.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2012 David Faure <faure@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSAVEFILE_H +#define QSAVEFILE_H + +#include <QtCore/qfiledevice.h> +#include <QtCore/qstring.h> + +#ifdef open +#error qsavefile.h must be included before any header file that defines open +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QAbstractFileEngine; +class QSaveFilePrivate; + +class Q_CORE_EXPORT QSaveFile : public QFileDevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSaveFile) + +public: + + explicit QSaveFile(const QString &name); + explicit QSaveFile(QObject *parent = 0); + explicit QSaveFile(const QString &name, QObject *parent); + ~QSaveFile(); + + QString fileName() const Q_DECL_OVERRIDE; + void setFileName(const QString &name); + + bool open(OpenMode flags) Q_DECL_OVERRIDE; + bool commit(); + + void cancelWriting(); + +protected: + qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE; + +private: + void close() Q_DECL_OVERRIDE; + +private: + Q_DISABLE_COPY(QSaveFile) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSAVEFILE_H diff --git a/src/corelib/io/qsavefile_p.h b/src/corelib/io/qsavefile_p.h new file mode 100644 index 0000000000..27e687835b --- /dev/null +++ b/src/corelib/io/qsavefile_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 David Faure <faure@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSAVEFILE_P_H +#define QSAVEFILE_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 "private/qfiledevice_p.h" + +QT_BEGIN_NAMESPACE + +class QSaveFilePrivate : public QFileDevicePrivate +{ + Q_DECLARE_PUBLIC(QSaveFile) + +protected: + QSaveFilePrivate(); + ~QSaveFilePrivate(); + + QString fileName; + + QFileDevice::FileError writeError; +}; + +QT_END_NAMESPACE + +#endif // QSAVEFILE_P_H diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 9408727d25..d3a6e3c238 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -44,10 +44,9 @@ #ifndef QT_NO_TEMPORARYFILE #include "qplatformdefs.h" +#include "private/qtemporaryfile_p.h" #include "private/qfile_p.h" -#include "private/qfsfileengine_p.h" #include "private/qsystemerror_p.h" -#include "private/qfilesystemengine_p.h" #if !defined(Q_OS_WIN) #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -218,36 +217,6 @@ static bool createFileFromTemplate(NativeFileHandle &file, } //************* QTemporaryFileEngine -class QTemporaryFileEngine : public QFSFileEngine -{ - Q_DECLARE_PRIVATE(QFSFileEngine) -public: - QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true) - : QFSFileEngine(), filePathIsTemplate(fileIsTemplate), - filePathWasTemplate(fileIsTemplate) - { - Q_D(QFSFileEngine); - d->fileEntry = QFileSystemEntry(file); - - if (!filePathIsTemplate) - QFSFileEngine::setFileName(file); - } - - ~QTemporaryFileEngine(); - - bool isReallyOpen(); - void setFileName(const QString &file); - void setFileTemplate(const QString &fileTemplate); - - bool open(QIODevice::OpenMode flags); - bool remove(); - bool rename(const QString &newName); - bool close(); - - bool filePathIsTemplate; - bool filePathWasTemplate; -}; - QTemporaryFileEngine::~QTemporaryFileEngine() { QFSFileEngine::close(); @@ -398,6 +367,12 @@ bool QTemporaryFileEngine::rename(const QString &newName) return QFSFileEngine::rename(newName); } +bool QTemporaryFileEngine::renameOverwrite(const QString &newName) +{ + QFSFileEngine::close(); + return QFSFileEngine::renameOverwrite(newName); +} + bool QTemporaryFileEngine::close() { // Don't close the file, just seek to the front. @@ -407,19 +382,6 @@ bool QTemporaryFileEngine::close() } //************* QTemporaryFilePrivate -class QTemporaryFilePrivate : public QFilePrivate -{ - Q_DECLARE_PUBLIC(QTemporaryFile) - -protected: - QTemporaryFilePrivate(); - ~QTemporaryFilePrivate(); - - QAbstractFileEngine *engine() const; - - bool autoRemove; - QString templateName; -}; QTemporaryFilePrivate::QTemporaryFilePrivate() : autoRemove(true) { @@ -440,7 +402,7 @@ QAbstractFileEngine *QTemporaryFilePrivate::engine() const return fileEngine; } -static QString defaultTemplateName() +QString QTemporaryFilePrivate::defaultTemplateName() { QString baseName; #if defined(QT_BUILD_CORE_LIB) @@ -506,7 +468,7 @@ QTemporaryFile::QTemporaryFile() : QFile(*new QTemporaryFilePrivate) { Q_D(QTemporaryFile); - d->templateName = defaultTemplateName(); + d->templateName = QTemporaryFilePrivate::defaultTemplateName(); } QTemporaryFile::QTemporaryFile(const QString &templateName) @@ -529,7 +491,7 @@ QTemporaryFile::QTemporaryFile() : QFile(*new QTemporaryFilePrivate, 0) { Q_D(QTemporaryFile); - d->templateName = defaultTemplateName(); + d->templateName = QTemporaryFilePrivate::defaultTemplateName(); } /*! @@ -565,7 +527,7 @@ QTemporaryFile::QTemporaryFile(QObject *parent) : QFile(*new QTemporaryFilePrivate, parent) { Q_D(QTemporaryFile); - d->templateName = defaultTemplateName(); + d->templateName = QTemporaryFilePrivate::defaultTemplateName(); } /*! diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h new file mode 100644 index 0000000000..dd011f56c1 --- /dev/null +++ b/src/corelib/io/qtemporaryfile_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEMPORARYFILE_P_H +#define QTEMPORARYFILE_P_H + +#include "private/qfsfileengine_p.h" +#include "private/qfilesystemengine_p.h" +#include "private/qfile_p.h" + +QT_BEGIN_NAMESPACE + +class QTemporaryFilePrivate : public QFilePrivate +{ + Q_DECLARE_PUBLIC(QTemporaryFile) + +protected: + QTemporaryFilePrivate(); + ~QTemporaryFilePrivate(); + + QAbstractFileEngine *engine() const; + + bool autoRemove; + QString templateName; + + static QString defaultTemplateName(); +}; + +class QTemporaryFileEngine : public QFSFileEngine +{ + Q_DECLARE_PRIVATE(QFSFileEngine) +public: + QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true) + : QFSFileEngine(), filePathIsTemplate(fileIsTemplate), + filePathWasTemplate(fileIsTemplate) + { + Q_D(QFSFileEngine); + d->fileEntry = QFileSystemEntry(file); + + if (!filePathIsTemplate) + QFSFileEngine::setFileName(file); + } + + ~QTemporaryFileEngine(); + + bool isReallyOpen(); + void setFileName(const QString &file); + void setFileTemplate(const QString &fileTemplate); + + bool open(QIODevice::OpenMode flags); + bool remove(); + bool rename(const QString &newName); + bool renameOverwrite(const QString &newName); + bool close(); + + bool filePathIsTemplate; + bool filePathWasTemplate; +}; + +QT_END_NAMESPACE + +#endif /* QTEMPORARYFILE_P_H */ + diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 70c6eed9da..8459cdd158 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -226,12 +226,10 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384; */ #include "qtextstream.h" +#include "private/qtextstream_p.h" #include "qbuffer.h" #include "qfile.h" #include "qnumeric.h" -#ifndef QT_NO_TEXTCODEC -#include "qtextcodec.h" -#endif #ifndef Q_OS_WINCE #include <locale.h> #endif @@ -315,119 +313,7 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE -#ifndef QT_NO_QOBJECT -class QDeviceClosedNotifier : public QObject -{ - Q_OBJECT -public: - inline QDeviceClosedNotifier() - { } - - inline void setupDevice(QTextStream *stream, QIODevice *device) - { - disconnect(); - if (device) - connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream())); - this->stream = stream; - } - -public Q_SLOTS: - inline void flushStream() { stream->flush(); } - -private: - QTextStream *stream; -}; -#endif - //------------------------------------------------------------------- -class QTextStreamPrivate -{ - Q_DECLARE_PUBLIC(QTextStream) -public: - QTextStreamPrivate(QTextStream *q_ptr); - ~QTextStreamPrivate(); - void reset(); - - // device - QIODevice *device; -#ifndef QT_NO_QOBJECT - QDeviceClosedNotifier deviceClosedNotifier; -#endif - bool deleteDevice; - - // string - QString *string; - int stringOffset; - QIODevice::OpenMode stringOpenMode; - -#ifndef QT_NO_TEXTCODEC - // codec - QTextCodec *codec; - QTextCodec::ConverterState readConverterState; - QTextCodec::ConverterState writeConverterState; - QTextCodec::ConverterState *readConverterSavedState; - bool autoDetectUnicode; -#endif - - // i/o - enum TokenDelimiter { - Space, - NotSpace, - EndOfLine - }; - - QString read(int maxlen); - bool scan(const QChar **ptr, int *tokenLength, - int maxlen, TokenDelimiter delimiter); - inline const QChar *readPtr() const; - inline void consumeLastToken(); - inline void consume(int nchars); - void saveConverterState(qint64 newPos); - void restoreToSavedConverterState(); - int lastTokenSize; - - // Return value type for getNumber() - enum NumberParsingStatus { - npsOk, - npsMissingDigit, - npsInvalidPrefix - }; - - inline bool getChar(QChar *ch); - inline void ungetChar(QChar ch); - NumberParsingStatus getNumber(qulonglong *l); - bool getReal(double *f); - - inline void write(const QString &data); - inline void putString(const QString &ch, bool number = false); - void putNumber(qulonglong number, bool negative); - - // buffers - bool fillReadBuffer(qint64 maxBytes = -1); - void resetReadBuffer(); - void flushWriteBuffer(); - QString writeBuffer; - QString readBuffer; - int readBufferOffset; - int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer - qint64 readBufferStartDevicePos; - - // streaming parameters - int realNumberPrecision; - int integerBase; - int fieldWidth; - QChar padChar; - QTextStream::FieldAlignment fieldAlignment; - QTextStream::RealNumberNotation realNumberNotation; - QTextStream::NumberFlags numberFlags; - - // status - QTextStream::Status status; - - QLocale locale; - - QTextStream *q_ptr; -}; /*! \internal @@ -481,10 +367,7 @@ static void copyConverterStateHelper(QTextCodec::ConverterState *dest, } #endif -/*! - \internal -*/ -void QTextStreamPrivate::reset() +void QTextStreamPrivate::Params::reset() { realNumberPrecision = 6; integerBase = 0; @@ -493,6 +376,14 @@ void QTextStreamPrivate::reset() fieldAlignment = QTextStream::AlignRight; realNumberNotation = QTextStream::SmartNotation; numberFlags = 0; +} + +/*! + \internal +*/ +void QTextStreamPrivate::reset() +{ + params.reset(); device = 0; deleteDevice = false; @@ -985,15 +876,17 @@ inline void QTextStreamPrivate::putString(const QString &s, bool number) QString tmp = s; // handle padding - int padSize = fieldWidth - s.size(); + int padSize = params.fieldWidth - s.size(); if (padSize > 0) { - QString pad(padSize, padChar); - if (fieldAlignment == QTextStream::AlignLeft) { - tmp.append(QString(padSize, padChar)); - } else if (fieldAlignment == QTextStream::AlignRight - || fieldAlignment == QTextStream::AlignAccountingStyle) { - tmp.prepend(QString(padSize, padChar)); - if (fieldAlignment == QTextStream::AlignAccountingStyle && number) { + QString pad(padSize, params.padChar); + switch (params.fieldAlignment) { + case QTextStream::AlignLeft: + tmp.append(pad); + break; + case QTextStream::AlignRight: + case QTextStream::AlignAccountingStyle: + tmp.prepend(pad); + if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) { const QChar sign = s.size() > 0 ? s.at(0) : QChar(); if (sign == locale.negativeSign() || sign == locale.positiveSign()) { QChar *data = tmp.data(); @@ -1001,9 +894,11 @@ inline void QTextStreamPrivate::putString(const QString &s, bool number) data[0] = sign; } } - } else if (fieldAlignment == QTextStream::AlignCenter) { - tmp.prepend(QString(padSize/2, padChar)); - tmp.append(QString(padSize - padSize/2, padChar)); + break; + case QTextStream::AlignCenter: + tmp.prepend(QString(padSize/2, params.padChar)); + tmp.append(QString(padSize - padSize/2, params.padChar)); + break; } } @@ -1175,13 +1070,7 @@ void QTextStream::reset() { Q_D(QTextStream); - d->realNumberPrecision = 6; - d->integerBase = 0; - d->fieldWidth = 0; - d->padChar = QLatin1Char(' '); - d->fieldAlignment = QTextStream::AlignRight; - d->realNumberNotation = QTextStream::SmartNotation; - d->numberFlags = 0; + d->params.reset(); } /*! @@ -1400,7 +1289,7 @@ QString *QTextStream::string() const void QTextStream::setFieldAlignment(FieldAlignment mode) { Q_D(QTextStream); - d->fieldAlignment = mode; + d->params.fieldAlignment = mode; } /*! @@ -1411,7 +1300,7 @@ void QTextStream::setFieldAlignment(FieldAlignment mode) QTextStream::FieldAlignment QTextStream::fieldAlignment() const { Q_D(const QTextStream); - return d->fieldAlignment; + return d->params.fieldAlignment; } /*! @@ -1432,7 +1321,7 @@ QTextStream::FieldAlignment QTextStream::fieldAlignment() const void QTextStream::setPadChar(QChar ch) { Q_D(QTextStream); - d->padChar = ch; + d->params.padChar = ch; } /*! @@ -1443,7 +1332,7 @@ void QTextStream::setPadChar(QChar ch) QChar QTextStream::padChar() const { Q_D(const QTextStream); - return d->padChar; + return d->params.padChar; } /*! @@ -1461,7 +1350,7 @@ QChar QTextStream::padChar() const void QTextStream::setFieldWidth(int width) { Q_D(QTextStream); - d->fieldWidth = width; + d->params.fieldWidth = width; } /*! @@ -1472,7 +1361,7 @@ void QTextStream::setFieldWidth(int width) int QTextStream::fieldWidth() const { Q_D(const QTextStream); - return d->fieldWidth; + return d->params.fieldWidth; } /*! @@ -1486,7 +1375,7 @@ int QTextStream::fieldWidth() const void QTextStream::setNumberFlags(NumberFlags flags) { Q_D(QTextStream); - d->numberFlags = flags; + d->params.numberFlags = flags; } /*! @@ -1497,7 +1386,7 @@ void QTextStream::setNumberFlags(NumberFlags flags) QTextStream::NumberFlags QTextStream::numberFlags() const { Q_D(const QTextStream); - return d->numberFlags; + return d->params.numberFlags; } /*! @@ -1513,7 +1402,7 @@ QTextStream::NumberFlags QTextStream::numberFlags() const void QTextStream::setIntegerBase(int base) { Q_D(QTextStream); - d->integerBase = base; + d->params.integerBase = base; } /*! @@ -1525,7 +1414,7 @@ void QTextStream::setIntegerBase(int base) int QTextStream::integerBase() const { Q_D(const QTextStream); - return d->integerBase; + return d->params.integerBase; } /*! @@ -1539,7 +1428,7 @@ int QTextStream::integerBase() const void QTextStream::setRealNumberNotation(RealNumberNotation notation) { Q_D(QTextStream); - d->realNumberNotation = notation; + d->params.realNumberNotation = notation; } /*! @@ -1550,7 +1439,7 @@ void QTextStream::setRealNumberNotation(RealNumberNotation notation) QTextStream::RealNumberNotation QTextStream::realNumberNotation() const { Q_D(const QTextStream); - return d->realNumberNotation; + return d->params.realNumberNotation; } /*! @@ -1567,10 +1456,10 @@ void QTextStream::setRealNumberPrecision(int precision) Q_D(QTextStream); if (precision < 0) { qWarning("QTextStream::setRealNumberPrecision: Invalid precision (%d)", precision); - d->realNumberPrecision = 6; + d->params.realNumberPrecision = 6; return; } - d->realNumberPrecision = precision; + d->params.realNumberPrecision = precision; } /*! @@ -1582,7 +1471,7 @@ void QTextStream::setRealNumberPrecision(int precision) int QTextStream::realNumberPrecision() const { Q_D(const QTextStream); - return d->realNumberPrecision; + return d->params.realNumberPrecision; } /*! @@ -1722,7 +1611,7 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong consumeLastToken(); // detect int encoding - int base = integerBase; + int base = params.integerBase; if (base == 0) { QChar ch; if (!getChar(&ch)) @@ -2300,6 +2189,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) QString result; unsigned flags = 0; + const QTextStream::NumberFlags numberFlags = params.numberFlags; if (numberFlags & QTextStream::ShowBase) flags |= QLocalePrivate::ShowBase; if (numberFlags & QTextStream::ForceSign) @@ -2315,7 +2205,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) flags |= QLocalePrivate::ThousandsGroup; const QLocalePrivate *dd = locale.d; - int base = integerBase ? integerBase : 10; + int base = params.integerBase ? params.integerBase : 10; if (negative && base == 10) { result = dd->longLongToString(-static_cast<qlonglong>(number), -1, base, -1, flags); @@ -2330,7 +2220,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative) result = dd->unsLongLongToString(number, -1, base, -1, flags); // workaround for backward compatibility - in octal form with // ShowBase flag set zero should be written as '00' - if (number == 0 && base == 8 && numberFlags & QTextStream::ShowBase + if (number == 0 && base == 8 && params.numberFlags & QTextStream::ShowBase && result == QLatin1String("0")) { result.prepend(QLatin1Char('0')); } @@ -2524,7 +2414,7 @@ QTextStream &QTextStream::operator<<(double f) flags |= QLocalePrivate::Alternate; const QLocalePrivate *dd = d->locale.d; - QString num = dd->doubleToString(f, d->realNumberPrecision, form, -1, flags); + QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags); d->putString(num, true); return *this; } @@ -2605,13 +2495,13 @@ QTextStream &QTextStream::operator<<(const void *ptr) { Q_D(QTextStream); CHECK_VALID_STREAM(*this); - int oldBase = d->integerBase; - NumberFlags oldFlags = d->numberFlags; - d->integerBase = 16; - d->numberFlags |= ShowBase; + const int oldBase = d->params.integerBase; + const NumberFlags oldFlags = d->params.numberFlags; + d->params.integerBase = 16; + d->params.numberFlags |= ShowBase; d->putNumber(reinterpret_cast<quintptr>(ptr), false); - d->integerBase = oldBase; - d->numberFlags = oldFlags; + d->params.integerBase = oldBase; + d->params.numberFlags = oldFlags; return *this; } @@ -3130,7 +3020,3 @@ QLocale QTextStream::locale() const QT_END_NAMESPACE -#ifndef QT_NO_QOBJECT -#include "qtextstream.moc" -#endif - diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h index 3c25e0587a..0606b5f9ab 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/io/qtextstream.h @@ -194,6 +194,7 @@ public: private: Q_DISABLE_COPY(QTextStream) + friend class QDebugStateSaverPrivate; QScopedPointer<QTextStreamPrivate> d_ptr; }; diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/io/qtextstream_p.h new file mode 100644 index 0000000000..d5d5288426 --- /dev/null +++ b/src/corelib/io/qtextstream_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTSTREAM_P_H +#define QTEXTSTREAM_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 "qtextstream.h" +#ifndef QT_NO_TEXTCODEC +#include "qtextcodec.h" +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_QOBJECT +class QDeviceClosedNotifier : public QObject +{ + Q_OBJECT +public: + inline QDeviceClosedNotifier() + { } + + inline void setupDevice(QTextStream *stream, QIODevice *device) + { + disconnect(); + if (device) + connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream())); + this->stream = stream; + } + +public Q_SLOTS: + inline void flushStream() { stream->flush(); } + +private: + QTextStream *stream; +}; +#endif + +class QTextStreamPrivate +{ + Q_DECLARE_PUBLIC(QTextStream) +public: + QTextStreamPrivate(QTextStream *q_ptr); + ~QTextStreamPrivate(); + void reset(); + + // device + QIODevice *device; +#ifndef QT_NO_QOBJECT + QDeviceClosedNotifier deviceClosedNotifier; +#endif + bool deleteDevice; + + // string + QString *string; + int stringOffset; + QIODevice::OpenMode stringOpenMode; + +#ifndef QT_NO_TEXTCODEC + // codec + QTextCodec *codec; + QTextCodec::ConverterState readConverterState; + QTextCodec::ConverterState writeConverterState; + QTextCodec::ConverterState *readConverterSavedState; + bool autoDetectUnicode; +#endif + + // i/o + enum TokenDelimiter { + Space, + NotSpace, + EndOfLine + }; + + QString read(int maxlen); + bool scan(const QChar **ptr, int *tokenLength, + int maxlen, TokenDelimiter delimiter); + inline const QChar *readPtr() const; + inline void consumeLastToken(); + inline void consume(int nchars); + void saveConverterState(qint64 newPos); + void restoreToSavedConverterState(); + int lastTokenSize; + + // Return value type for getNumber() + enum NumberParsingStatus { + npsOk, + npsMissingDigit, + npsInvalidPrefix + }; + + inline bool getChar(QChar *ch); + inline void ungetChar(QChar ch); + NumberParsingStatus getNumber(qulonglong *l); + bool getReal(double *f); + + inline void write(const QString &data); + inline void putString(const QString &ch, bool number = false); + void putNumber(qulonglong number, bool negative); + + // buffers + bool fillReadBuffer(qint64 maxBytes = -1); + void resetReadBuffer(); + void flushWriteBuffer(); + QString writeBuffer; + QString readBuffer; + int readBufferOffset; + int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer + qint64 readBufferStartDevicePos; + + // streaming parameters + class Params + { + public: + void reset(); + + int realNumberPrecision; + int integerBase; + int fieldWidth; + QChar padChar; + QTextStream::FieldAlignment fieldAlignment; + QTextStream::RealNumberNotation realNumberNotation; + QTextStream::NumberFlags numberFlags; + }; + Params params; + + // status + QTextStream::Status status; + + QLocale locale; + + QTextStream *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QTEXTSTREAM_P_H diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 79981738f2..4882e3575f 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3765,6 +3765,37 @@ QString QUrl::errorString() const } /*! + \since 5.1 + + Converts a list of \a urls into a list of QStrings, using toString(\a options). +*/ +QStringList QUrl::toStringList(const QList<QUrl> &urls, FormattingOptions options) +{ + QStringList lst; + lst.reserve(urls.size()); + foreach (const QUrl &url, urls) + lst.append(url.toString(options)); + return lst; + +} + +/*! + \since 5.1 + + Converts a list of strings representing \a urls into a list of urls, using QUrl(str, \a mode). + Note that this means all strings must be urls, not for instance local paths. +*/ +QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode) +{ + QList<QUrl> lst; + lst.reserve(urls.size()); + foreach (const QString &str, urls) { + lst.append(QUrl(str, mode)); + } + return lst; +} + +/*! \typedef QUrl::DataPtr \internal */ diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index bd35b44f17..17012d1b3f 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -322,6 +322,9 @@ public: static QString fromAce(const QByteArray &); static QByteArray toAce(const QString &); static QStringList idnWhitelist(); + static QStringList toStringList(const QList<QUrl> &uris, FormattingOptions options = FormattingOptions(PrettyDecoded)); + static QList<QUrl> fromStringList(const QStringList &uris, ParsingMode mode = TolerantMode); + static void setIdnWhitelist(const QStringList &); friend Q_CORE_EXPORT uint qHash(const QUrl &url, uint seed = 0) Q_DECL_NOTHROW; |