diff options
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/io.pri | 3 | ||||
-rw-r--r-- | src/corelib/io/qdatastream.h | 7 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 19 | ||||
-rw-r--r-- | src/corelib/io/qdir.cpp | 12 | ||||
-rw-r--r-- | src/corelib/io/qdiriterator.cpp | 4 | ||||
-rw-r--r-- | src/corelib/io/qfile.cpp | 3 | ||||
-rw-r--r-- | src/corelib/io/qfileinfo.cpp | 11 | ||||
-rw-r--r-- | src/corelib/io/qfileinfo_p.h | 145 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_unix.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qfsfileengine_win.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qiodevice.cpp | 15 | ||||
-rw-r--r-- | src/corelib/io/qnoncontiguousbytedevice.cpp | 542 | ||||
-rw-r--r-- | src/corelib/io/qnoncontiguousbytedevice_p.h | 189 | ||||
-rw-r--r-- | src/corelib/io/qprocess.cpp | 107 | ||||
-rw-r--r-- | src/corelib/io/qprocess.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qprocess_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 48 | ||||
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 75 | ||||
-rw-r--r-- | src/corelib/io/qresource.cpp | 80 | ||||
-rw-r--r-- | src/corelib/io/qsettings.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qsettings_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.cpp | 18 | ||||
-rw-r--r-- | src/corelib/io/qurl.cpp | 6 |
23 files changed, 1047 insertions, 252 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 3690d4b..8f37e25 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -10,9 +10,9 @@ HEADERS += \ 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 \ @@ -38,6 +38,7 @@ SOURCES += \ io/qfile.cpp \ io/qfileinfo.cpp \ io/qiodevice.cpp \ + io/qnoncontiguousbytedevice.cpp \ io/qprocess.cpp \ io/qtextstream.cpp \ io/qtemporaryfile.cpp \ diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 4c8295e..ec5780c 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -83,10 +83,11 @@ public: Qt_4_2 = 8, Qt_4_3 = 9, Qt_4_4 = 10, - Qt_4_5 = 11 -#if QT_VERSION >= 0x040600 + Qt_4_5 = 11, + Qt_4_6 = Qt_4_5 +#if QT_VERSION >= 0x040700 #error Add the datastream version for this Qt version - , Qt_4_6 = Qt_4_5 + Qt_4_7 = Qt_4_6 #endif }; diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 8334146..9b0fbe5 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -51,6 +51,7 @@ #include <QtCore/qstring.h> #include <QtCore/qvector.h> #include <QtCore/qset.h> +#include <QtCore/qcontiguouscache.h> QT_BEGIN_HEADER @@ -232,6 +233,24 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set) 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(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); } diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index b7861ba..0dc8a63 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -55,6 +55,8 @@ # include "qresource.h" #endif +#include "qvarlengtharray.h" + #include "../kernel/qcoreglobaldata_p.h" #include <stdlib.h> @@ -2054,11 +2056,13 @@ QString QDir::cleanPath(const QString &path) QString name = path; QChar dir_separator = separator(); if(dir_separator != QLatin1Char('/')) - name.replace(dir_separator, QLatin1Char('/')); + name.replace(dir_separator, QLatin1Char('/')); int used = 0, levels = 0; const int len = name.length(); - QVector<QChar> out(len); + 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('/')) { @@ -2158,7 +2162,7 @@ QString QDir::cleanPath(const QString &path) if(used == len) ret = name; else - ret = QString(out.data(), used); + ret = QString(out, used); // Strip away last slash except for root directories if (ret.endsWith(QLatin1Char('/')) @@ -2221,7 +2225,7 @@ QStringList QDir::nameFiltersFromString(const QString &nameFilter) \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 + 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 diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index b14f436..81bfb27 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -201,8 +201,8 @@ void QDirIteratorPrivate::advance() QString subDir = it->currentFilePath(); #ifdef Q_OS_WIN - if (currentFileInfo.isSymLink()) - subDir = currentFileInfo.canonicalFilePath(); + if (nextFileInfo.isSymLink()) + subDir = nextFileInfo.canonicalFilePath(); #endif pushSubDirectory(subDir, it->nameFilters(), it->filters()); } diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index d7da800..04750b0 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -708,6 +708,7 @@ QFile::rename(const QString &newName) d->setError(QFile::RenameError, tr("Destination file exists")); return false; } + unsetError(); close(); if(error() == QFile::NoError) { if (fileEngine()->rename(newName)) { @@ -849,6 +850,7 @@ QFile::copy(const QString &newName) d->setError(QFile::CopyError, tr("Destination file exists")); return false; } + unsetError(); close(); if(error() == QFile::NoError) { if(fileEngine()->copy(newName)) { @@ -908,6 +910,7 @@ QFile::copy(const QString &newName) out.setAutoRemove(false); #endif } + close(); } if(!error) { QFile::setPermissions(newName, permissions()); diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 96e0f82..36b1ed8 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -537,8 +537,7 @@ QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo) void QFileInfo::setFile(const QString &file) { - Q_D(QFileInfo); - d->initFileEngine(file); + *this = QFileInfo(file); } /*! @@ -555,8 +554,7 @@ void QFileInfo::setFile(const QString &file) void QFileInfo::setFile(const QFile &file) { - Q_D(QFileInfo); - d->initFileEngine(file.fileName()); + *this = QFileInfo(file.fileName()); } /*! @@ -573,8 +571,7 @@ void QFileInfo::setFile(const QFile &file) void QFileInfo::setFile(const QDir &dir, const QString &file) { - Q_D(QFileInfo); - d->initFileEngine(dir.filePath(file)); + *this = QFileInfo(dir.filePath(file)); } /*! @@ -921,7 +918,7 @@ QString QFileInfo::suffix() const \bold{Note:} The QDir returned always corresponds to the object's parent directory, even if the QFileInfo represents a directory. - + For each of the follwing, dir() returns a QDir for \c{"~/examples/191697"}. diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h deleted file mode 100644 index 7d66581..0000000 --- a/src/corelib/io/qfileinfo_p.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@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 for the convenience -// of QIODevice. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qfileinfo.h" - -QT_BEGIN_NAMESPACE - -class QFileInfoPrivate -{ -public: - QFileInfoPrivate(const QFileInfo *copy=0); - ~QFileInfoPrivate(); - - void initFileEngine(const QString &); - - enum Access { - ReadAccess, - WriteAccess, - ExecuteAccess - }; - bool hasAccess(Access access) const; - - uint getFileFlags(QAbstractFileEngine::FileFlags) const; - QDateTime &getFileTime(QAbstractFileEngine::FileTime) const; - QString getFileName(QAbstractFileEngine::FileName) const; - - enum { - CachedFileFlags = 0x01, - CachedLinkTypeFlag = 0x02, - CachedBundleTypeFlag= 0x04, - CachedMTime = 0x10, - CachedCTime = 0x20, - CachedATime = 0x40, - CachedSize = 0x08 - }; - - struct Data - { - inline Data() - : ref(1), fileEngine(0), cache_enabled(1) - { - clear(); - } - - inline Data(const Data ©) - : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)), - fileName(copy.fileName), cache_enabled(copy.cache_enabled) - { - clear(); - } - - inline ~Data() - { - delete fileEngine; - } - - inline void clear() - { - fileNames.clear(); - fileFlags = 0; - cachedFlags = 0; - } - - mutable QAtomicInt ref; - - QAbstractFileEngine *fileEngine; - mutable QString fileName; - mutable QHash<int, QString> fileNames; - mutable uint cachedFlags : 31; - mutable uint 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) - { if (cache_enabled) cachedFlags |= c; } - } *data; - - inline void reset() { - detach(); - data->clear(); - } - - void detach(); -}; - - -QT_END_NAMESPACE -#endif - diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 18b92e2..7a6a85b 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -935,6 +935,8 @@ bool QFSFileEngine::setSize(qint64 size) Q_D(QFSFileEngine); if (d->fd != -1) return !QT_FTRUNCATE(d->fd, size); + if (d->fh) + return !QT_FTRUNCATE(QT_FILENO(d->fh), size); return !QT_TRUNCATE(d->nativeFilePath.constData(), size); } diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 63506c2..c5b54b4 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1392,8 +1392,6 @@ bool QFSFileEnginePrivate::doStat() const if (tmpAttributes != -1) { fileAttrib = tmpAttributes; could_stat = true; - } else { - return false; } #endif } else { diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index c739054..2ccc6ea 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -48,6 +48,10 @@ #include "qstringlist.h" #include <limits.h> +#ifdef QIODEVICE_DEBUG +# include <ctype.h> +#endif + QT_BEGIN_NAMESPACE #ifdef QIODEVICE_DEBUG @@ -362,7 +366,7 @@ QIODevice::QIODevice() { #if defined QIODEVICE_DEBUG QFile *file = qobject_cast<QFile *>(this); - printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, className(), + printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, metaObject()->className(), qPrintable(file ? file->fileName() : QString())); #endif } @@ -375,7 +379,7 @@ QIODevice::QIODevice(QObject *parent) : QObject(*new QIODevicePrivate, parent) { #if defined QIODEVICE_DEBUG - printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, className()); + printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, metaObject()->className()); #endif } @@ -945,9 +949,9 @@ QByteArray QIODevice::readAll() QByteArray tmp; if (d->isSequential() || size() == 0) { - // Read it in chunks, bytesAvailable() is unreliable for sequential - // devices. - const int chunkSize = 4096; + // Read it in chunks. Use bytesAvailable() as an unreliable hint for + // sequential devices, but try to read 4K as a minimum. + int chunkSize = qMax(qint64(4096), bytesAvailable()); qint64 totalRead = 0; forever { tmp.resize(tmp.size() + chunkSize); @@ -956,6 +960,7 @@ QByteArray QIODevice::readAll() if (readBytes <= 0) return tmp; totalRead += readBytes; + chunkSize = qMax(qint64(4096), bytesAvailable()); } } else { // Read it all in one go. diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp new file mode 100644 index 0000000..6233fde --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -0,0 +1,542 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnoncontiguousbytedevice_p.h" +#include <QObject> +#include <QBuffer> +#include <QDebug> +#include <QFile> + +QT_BEGIN_NAMESPACE + +/*! + \class QNonContiguousByteDevice + \brief A QNonContiguousByteDevice is a representation of a + file, array or buffer that allows access with a read pointer. + \since 4.6 + + \inmodule QtCore + + The goal of this class is to have a data representation that + allows us to avoid doing a memcpy as we have to do with QIODevice. + + \sa QNonContiguousByteDeviceFactory + + \internal +*/ +/*! + \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len) + + Return a byte pointer for at most \a maximumLength bytes of that device. + if \a maximumLength is -1, the caller does not care about the length and + the device may return what it desires to. + The actual number of bytes the pointer is valid for is returned in + the \a len variable. + \a len will be -1 if EOF or an error occurs. + If it was really EOF can then afterwards be checked with atEnd() + Returns 0 if it is not possible to read at that position. + + \sa atEnd() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount) + + will advance the internal read pointer by \a amount bytes. + The old readPointer is invalid after this call. + + \sa readPointer() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::atEnd() + + Returns true if everything has been read and the read + pointer cannot be advanced anymore. + + \sa readPointer(), advanceReadPointer(), reset() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::reset() + + Moves the internal read pointer back to the beginning. + Returns false if this was not possible. + + \sa atEnd(), disableReset() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::disableReset() + + Disable the reset() call, e.g. it will always + do nothing and return false. + + \sa reset() + + \internal +*/ +/*! + \fn virtual qint64 QNonContiguousByteDevice::size() + + Returns the size of the complete device or -1 if unknown. + May also return less/more than what can be actually read with readPointer() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readyRead() + + Emitted when there is data available + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total) + + Emitted when data has been "read" by advancing the read pointer + + \internal +*/ + +QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false) +{ +}; + +QNonContiguousByteDevice::~QNonContiguousByteDevice() +{ +}; + +void QNonContiguousByteDevice::disableReset() +{ + resetDisabled = true; +} + +QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice() +{ + buffer = b; + byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos()); + arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray); + arrayImpl->setParent(this); + connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead())); + connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64))); +} + +QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl() +{ +} + +const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + return arrayImpl->readPointer(maximumLength, len); +} + +bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount) +{ + return arrayImpl->advanceReadPointer(amount); +} + +bool QNonContiguousByteDeviceBufferImpl::atEnd() +{ + return arrayImpl->atEnd(); +} + +bool QNonContiguousByteDeviceBufferImpl::reset() +{ + if (resetDisabled) + return false; + return arrayImpl->reset(); +} + +qint64 QNonContiguousByteDeviceBufferImpl::size() +{ + return arrayImpl->size(); +} + +QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0) +{ + byteArray = ba; +} + +QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl() +{ +} + +const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + if (maximumLength != -1) + len = qMin(maximumLength, size() - currentPosition); + else + len = size() - currentPosition; + + return byteArray->constData() + currentPosition; +} + +bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +} + +bool QNonContiguousByteDeviceByteArrayImpl::atEnd() +{ + return currentPosition >= size(); +} + +bool QNonContiguousByteDeviceByteArrayImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +} + +qint64 QNonContiguousByteDeviceByteArrayImpl::size() +{ + return byteArray->size(); +} + +QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb) + : QNonContiguousByteDevice(), currentPosition(0) +{ + ringBuffer = rb; +} + +QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl() +{ +}; + +const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len); + + if (maximumLength != -1) + len = qMin(len, maximumLength); + + return returnValue; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::atEnd() +{ + return currentPosition >= size(); +}; + +bool QNonContiguousByteDeviceRingBufferImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +}; + +qint64 QNonContiguousByteDeviceRingBufferImpl::size() +{ + return ringBuffer->size(); +}; + +QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d) + : QNonContiguousByteDevice(), + currentReadBuffer(0), currentReadBufferSize(16*1024), + currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0), + eof(false) +{ + device = d; + initialPosition = d->pos(); + connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection); + connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection); +}; + +QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl() +{ + delete currentReadBuffer; +}; + +const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (eof == true) { + len = -1; + return 0; + } + + if (currentReadBuffer == 0) + currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc + + if (maximumLength == -1) + maximumLength = currentReadBufferSize; + + if (currentReadBufferAmount - currentReadBufferPosition > 0) { + len = currentReadBufferAmount - currentReadBufferPosition; + return currentReadBuffer->data() + currentReadBufferPosition; + } + + qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize)); + + if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) { + eof = true; + len = -1; + // size was unknown before, emit a readProgress with the final size + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + return 0; + } + + currentReadBufferAmount = haveRead; + currentReadBufferPosition = 0; + + len = haveRead; + return currentReadBuffer->data(); +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) +{ + totalAdvancements += amount; + + // normal advancement + currentReadBufferPosition += amount; + + // advancing over that what has actually been read before + if (currentReadBufferPosition > currentReadBufferAmount) { + qint64 i = currentReadBufferPosition - currentReadBufferAmount; + while (i > 0) { + if (device->getChar(0) == false) { + emit readProgress(totalAdvancements - i, size()); + return false; // ### FIXME handle eof + } + i--; + } + + currentReadBufferPosition = 0; + currentReadBufferAmount = 0; + } + + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + else + emit readProgress(totalAdvancements, size()); + + return true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() +{ + return eof == true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::reset() +{ + if (resetDisabled) + return false; + + if (device->seek(initialPosition)) { + eof = false; // assume eof is false, it will be true after a read has been attempted + return true; + } + + return false; +}; + +qint64 QNonContiguousByteDeviceIoDeviceImpl::size() +{ + // note that this is different from the size() implementation of QIODevice! + + if (device->isSequential()) + return -1; + + return device->size() - initialPosition; +}; + +QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) +{ + byteDevice = bd; + connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead())); + + open(ReadOnly); +} + +QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice() +{ + +} + +bool QByteDeviceWrappingIoDevice::isSequential() const +{ + return (byteDevice->size() == -1); +} + +bool QByteDeviceWrappingIoDevice::atEnd() const +{ + return byteDevice->atEnd(); +} + +bool QByteDeviceWrappingIoDevice::reset() +{ + return byteDevice->reset(); +} + +qint64 QByteDeviceWrappingIoDevice::size() const +{ + if (isSequential()) + return 0; + + return byteDevice->size(); +} + + +qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize) +{ + qint64 len; + const char *readPointer = byteDevice->readPointer(maxSize, len); + if (len == -1) + return -1; + + memcpy(data, readPointer, len); + byteDevice->advanceReadPointer(len); + return len; +} + +qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize) +{ + return -1; +} + +/*! + \class QNonContiguousByteDeviceFactory + \since 4.6 + + \inmodule QtCore + + Creates a QNonContiguousByteDevice out of a QIODevice, + QByteArray etc. + + \sa QNonContiguousByteDevice + + \internal +*/ + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device); + + Create a QNonContiguousByteDevice out of a QIODevice. + For QFile, QBuffer and all other QIoDevice, sequential or not. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device) +{ + // shortcut if it is a QBuffer + if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) { + return new QNonContiguousByteDeviceBufferImpl(buffer); + } + + // ### FIXME special case if device is a QFile that supports map() + // then we can actually deal with the file without using read/peek + + // generic QIODevice + return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer); + + Create a QNonContiguousByteDevice out of a QRingBuffer. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer) +{ + return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer); +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray); + + Create a QNonContiguousByteDevice out of a QByteArray. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray) +{ + return new QNonContiguousByteDeviceByteArrayImpl(byteArray); +}; + +/*! + \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice); + + Wrap the \a byteDevice (possibly again) into a QIODevice. + + \internal +*/ +QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice) +{ + // ### FIXME if it already has been based on QIoDevice, we could that one out again + // and save some calling + + // needed for FTP backend + + return new QByteDeviceWrappingIoDevice(byteDevice); +} + +QT_END_NAMESPACE + diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h new file mode 100644 index 0000000..2a7e40b --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNONCONTIGUOUSBYTEDEVICE_H +#define QNONCONTIGUOUSBYTEDEVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QtCore/qbytearray.h> +#include <QtCore/qbuffer.h> +#include <QtCore/qiodevice.h> +#include "private/qringbuffer_p.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QNonContiguousByteDevice : public QObject +{ + Q_OBJECT +public: + virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; + virtual bool advanceReadPointer(qint64 amount) = 0; + virtual bool atEnd() = 0; + virtual bool reset() = 0; + void disableReset(); + virtual qint64 size() = 0; + +protected: + QNonContiguousByteDevice(); + virtual ~QNonContiguousByteDevice(); + + bool resetDisabled; +signals: + void readyRead(); + void readProgress(qint64 current, qint64 total); +}; + +class Q_CORE_EXPORT QNonContiguousByteDeviceFactory +{ +public: + static QNonContiguousByteDevice* create(QIODevice *device); + static QNonContiguousByteDevice* create(QByteArray *byteArray); + static QNonContiguousByteDevice* create(QRingBuffer *ringBuffer); + static QIODevice* wrap(QNonContiguousByteDevice* byteDevice); +}; + +// the actual implementations +// + +class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba); + ~QNonContiguousByteDeviceByteArrayImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QByteArray* byteArray; + qint64 currentPosition; +}; + +class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb); + ~QNonContiguousByteDeviceRingBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QRingBuffer* ringBuffer; + qint64 currentPosition; +}; + + +class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d); + ~QNonContiguousByteDeviceIoDeviceImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QIODevice* device; + QByteArray* currentReadBuffer; + qint64 currentReadBufferSize; + qint64 currentReadBufferAmount; + qint64 currentReadBufferPosition; + qint64 totalAdvancements; + bool eof; + qint64 initialPosition; +}; + +class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceBufferImpl(QBuffer *b); + ~QNonContiguousByteDeviceBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QBuffer* buffer; + QByteArray byteArray; + QNonContiguousByteDeviceByteArrayImpl* arrayImpl; +}; + +// ... and the reverse thing +class QByteDeviceWrappingIoDevice : public QIODevice +{ + Q_OBJECT +public: + QByteDeviceWrappingIoDevice (QNonContiguousByteDevice *bd); + ~QByteDeviceWrappingIoDevice (); + virtual bool isSequential () const; + virtual bool atEnd () const; + virtual bool reset (); + virtual qint64 size () const; +protected: + virtual qint64 readData ( char * data, qint64 maxSize ); + virtual qint64 writeData ( const char * data, qint64 maxSize ); + + QNonContiguousByteDevice *byteDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index a128482..30f4291 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -101,6 +101,29 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE +static QHash<QString, QString> environmentHashFromList(const QStringList &environment) +{ + QHash<QString, QString> result; + QStringList::ConstIterator it = environment.constBegin(), + end = environment.constEnd(); + for ( ; it != end; ++it) { + int equals = it->indexOf(QLatin1Char('=')); + + QString name = *it; + QString value; + if (equals != -1) { + name.truncate(equals); +#ifdef Q_OS_WIN + name = name.toUpper(); +#endif + value = it->mid(equals + 1); + } + result.insert(name, value); + } + + return result; +} + void QProcessPrivate::Channel::clear() { switch (type) { @@ -416,6 +439,7 @@ QProcessPrivate::QProcessPrivate() sequenceNumber = 0; exitCode = 0; exitStatus = QProcess::NormalExit; + environment = 0; startupSocketNotifier = 0; deathNotifier = 0; notifier = 0; @@ -442,6 +466,7 @@ QProcessPrivate::QProcessPrivate() */ QProcessPrivate::~QProcessPrivate() { + delete environment; if (stdinChannel.process) stdinChannel.process->stdoutChannel.clear(); if (stdoutChannel.process) @@ -1191,29 +1216,83 @@ QProcess::ProcessState QProcess::state() const \snippet doc/src/snippets/qprocess-environment/main.cpp 0 - \sa environment(), systemEnvironment() + \sa environment(), systemEnvironment(), setEnvironmentHash() */ void QProcess::setEnvironment(const QStringList &environment) { - Q_D(QProcess); - d->environment = environment; + setEnvironmentHash(environmentHashFromList(environment)); } /*! Returns the environment that QProcess will use when starting a process, or an empty QStringList if no environment has been set - using setEnvironment(). If no environment has been set, the - environment of the calling process will be used. + using setEnvironment() or setEnvironmentHash(). If no environment + has been set, the environment of the calling process will be used. \note The environment settings are ignored on Windows CE, as there is no concept of an environment. - \sa setEnvironment(), systemEnvironment() + \sa environmentHash(), setEnvironment(), systemEnvironment() */ QStringList QProcess::environment() const { Q_D(const QProcess); - return d->environment; + + QStringList result; + if (!d->environment) + return result; + + QHash<QString, QString>::ConstIterator it = d->environment->constBegin(), + end = d->environment->constEnd(); + for ( ; it != end; ++it) { + QString data = it.key(); + data.reserve(data.length() + it.value().length() + 1); + data.append(QLatin1Char('=')); + data.append(it.value()); + result << data; + } + return result; +} + +/*! + \since 4.5 + Sets the environment that QProcess will use when starting a process to the + \a environment hash map. + + For example, the following code adds the \c{C:\\BIN} directory to the list of + executable paths (\c{PATHS}) on Windows and sets \c{TMPDIR}: + + \snippet doc/src/snippets/qprocess-environment/main.cpp 1 + + \sa environment(), systemEnvironmentHash(), setEnvironment() +*/ +void QProcess::setEnvironmentHash(const QHash<QString, QString> &environment) +{ + Q_D(QProcess); + if (!d->environment) + d->environment = new QHash<QString, QString>(environment); + else + *d->environment = environment; +} + +/*! + \since 4.5 + Returns the environment that QProcess will use when starting a + process, or an empty QHash if no environment has been set using + setEnvironment() or setEnvironmentHash(). If no environment has + been set, the environment of the calling process will be used. + + \note The environment settings are ignored on Windows CE, + as there is no concept of an environment. + + \sa setEnvironmentHash(), setEnvironment(), systemEnvironmentHash() +*/ +QHash<QString, QString> QProcess::environmentHash() const +{ + Q_D(const QProcess); + if (d->environment) + return *d->environment; + return QHash<QString, QString>(); } /*! @@ -1812,7 +1891,7 @@ QT_END_INCLUDE_NAMESPACE \snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 8 - \sa environment(), setEnvironment() + \sa systemEnvironmentHash(), environment(), setEnvironment() */ QStringList QProcess::systemEnvironment() { @@ -1825,6 +1904,18 @@ QStringList QProcess::systemEnvironment() } /*! + \since 4.5 + + Returns the environment of the calling process as a QHash. + + \sa systemEnvironment(), environmentHash(), setEnvironmentHash() +*/ +QHash<QString, QString> QProcess::systemEnvironmentHash() +{ + return environmentHashFromList(systemEnvironment()); +} + +/*! \typedef Q_PID \relates QProcess diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 54a96c7..bf9a5a6 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -53,6 +53,8 @@ QT_MODULE(Core) #ifndef QT_NO_PROCESS +template <class Key, class T> class QHash; + #if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)) || defined(qdoc) typedef qint64 Q_PID; #else @@ -121,6 +123,8 @@ public: void setEnvironment(const QStringList &environment); QStringList environment() const; + void setEnvironmentHash(const QHash<QString, QString> &environment); + QHash<QString, QString> environmentHash() const; QProcess::ProcessError error() const; QProcess::ProcessState state() const; @@ -156,6 +160,7 @@ public: static bool startDetached(const QString &program); static QStringList systemEnvironment(); + static QHash<QString, QString> systemEnvironmentHash(); public Q_SLOTS: void terminate(); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 33059dd..f67fd2d 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -161,7 +161,7 @@ public: QString program; QStringList arguments; - QStringList environment; + QHash<QString, QString> *environment; QRingBuffer outputReadBuffer; QRingBuffer errorReadBuffer; diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 33d4a47..2f05f6e 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -531,8 +531,12 @@ bool QProcessPrivate::createChannel(Channel &channel) } } -static char **_q_dupEnvironment(const QStringList &environment, int *envc) +static char **_q_dupEnvironment(const QHash<QString, QString> *environment, int *envc) { + *envc = 0; + if (!environment) + return 0; // use the default environment + // if LD_LIBRARY_PATH exists in the current environment, but // not in the environment list passed by the programmer, then // copy it over. @@ -541,27 +545,29 @@ static char **_q_dupEnvironment(const QStringList &environment, int *envc) #else static const char libraryPath[] = "LD_LIBRARY_PATH"; #endif - const QString libraryPathString = QLatin1String(libraryPath); - QStringList env = environment; - QStringList matches = env.filter( - QRegExp(QLatin1Char('^') + libraryPathString + QLatin1Char('='))); - const QString envLibraryPath = QString::fromLocal8Bit(::getenv(libraryPath)); - if (matches.isEmpty() && !envLibraryPath.isEmpty()) { - QString entry = libraryPathString; - entry += QLatin1Char('='); - entry += envLibraryPath; - env << libraryPathString + QLatin1Char('=') + envLibraryPath; - } - - char **envp = new char *[env.count() + 1]; - envp[env.count()] = 0; - - for (int j = 0; j < env.count(); ++j) { - QString item = env.at(j); - envp[j] = ::strdup(item.toLocal8Bit().constData()); + const QByteArray envLibraryPath = qgetenv(libraryPath); + bool needToAddLibraryPath = !envLibraryPath.isEmpty() && + !environment->contains(QLatin1String(libraryPath)); + + char **envp = new char *[environment->count() + 2]; + envp[environment->count()] = 0; + envp[environment->count() + 1] = 0; + + QHash<QString, QString>::ConstIterator it = environment->constBegin(); + const QHash<QString, QString>::ConstIterator end = environment->constEnd(); + for ( ; it != end; ++it) { + QByteArray key = it.key().toLocal8Bit(); + QByteArray value = it.value().toLocal8Bit(); + key.reserve(key.length() + 1 + value.length()); + key.append('='); + key.append(value); + + envp[(*envc)++] = ::strdup(key.constData()); } - *envc = env.count(); + if (needToAddLibraryPath) + envp[(*envc)++] = ::strdup(QByteArray(libraryPath) + '=' + + envLibraryPath); return envp; } @@ -800,7 +806,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv q->setupChildProcess(); // execute the process - if (environment.isEmpty()) { + if (!envp) { qt_native_execvp(argv[0], argv); } else { if (path) { diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 0e36760..5d862e5 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -304,44 +304,69 @@ static QString qt_create_commandline(const QString &program, const QStringList & return args; } -static QByteArray qt_create_environment(const QStringList &environment) +static QByteArray qt_create_environment(const QHash<QString, QString> *environment) { QByteArray envlist; - if (!environment.isEmpty()) { - QStringList envStrings = environment; - int pos = 0; - // add PATH if necessary (for DLL loading) - if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) { + if (environment) { + QHash<QString, QString> copy = *environment; + + // add PATH if necessary (for DLL loading) + if (!copy.contains(QLatin1String("PATH"))) { QByteArray path = qgetenv("PATH"); if (!path.isEmpty()) - envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path))); + copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path)); } + // add systemroot if needed - if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) { - QByteArray systemRoot = qgetenv("SystemRoot"); + if (!copy.contains(QLatin1String("SYSTEMROOT"))) { + QByteArray systemRoot = qgetenv("SYSTEMROOT"); if (!systemRoot.isEmpty()) - envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot))); + copy.insert(QLatin1String("SYSTEMROOT"), QString::fromLocal8Bit(systemRoot)); } + + int pos = 0; + QHash<QString, QString>::ConstIterator it = copy.constBegin(), + end = copy.constEnd(); #ifdef UNICODE if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) { - for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); ++it) { - QString tmp = *it; - uint tmpSize = sizeof(TCHAR) * (tmp.length()+1); + static const TCHAR equal = L'='; + static const TCHAR nul = L'\0'; + + for ( ; it != end; ++it) { + uint tmpSize = sizeof(TCHAR) * (it.key().length() + it.value().length() + 2); + // ignore empty strings + if (tmpSize == sizeof(TCHAR)*2) + continue; envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data()+pos, tmp.utf16(), tmpSize); + + tmpSize = it.key().length() * sizeof(TCHAR); + memcpy(envlist.data()+pos, it.key().utf16(), tmpSize); + pos += tmpSize; + + memcpy(envlist.data()+pos, &equal, sizeof(TCHAR)); + pos += sizeof(TCHAR); + + tmpSize = it.value().length() * sizeof(TCHAR); + memcpy(envlist.data()+pos, it.value().utf16(), tmpSize); pos += tmpSize; - } - // add the 2 terminating 0 (actually 4, just to be on the safe side) - envlist.resize( envlist.size()+4 ); - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; + + memcpy(envlist.data()+pos, &nul, sizeof(TCHAR)); + pos += sizeof(TCHAR); + } + // add the 2 terminating 0 (actually 4, just to be on the safe side) + envlist.resize( envlist.size()+4 ); + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; } else #endif // UNICODE { - for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++) { - QByteArray tmp = (*it).toLocal8Bit(); + for ( ; it != end; it++) { + QByteArray tmp = it.key().toLocal8Bit(); + tmp.append('='); + tmp.append(it.value().toLocal8Bit()); + uint tmpSize = tmp.length() + 1; envlist.resize(envlist.size() + tmpSize); memcpy(envlist.data()+pos, tmp.data(), tmpSize); @@ -418,7 +443,7 @@ void QProcessPrivate::startProcess() }; success = CreateProcessW(0, (WCHAR*)args.utf16(), 0, 0, TRUE, dwCreationFlags, - environment.isEmpty() ? 0 : envlist.data(), + environment ? envlist.data() : 0, workingDirectory.isEmpty() ? 0 : (WCHAR*)QDir::toNativeSeparators(workingDirectory).utf16(), &startupInfo, pid); @@ -437,7 +462,7 @@ void QProcessPrivate::startProcess() }; success = CreateProcessA(0, args.toLocal8Bit().data(), - 0, 0, TRUE, dwCreationFlags, environment.isEmpty() ? 0 : envlist.data(), + 0, 0, TRUE, dwCreationFlags, environment ? envlist.data() : 0, workingDirectory.isEmpty() ? 0 : QDir::toNativeSeparators(workingDirectory).toLocal8Bit().data(), &startupInfo, pid); diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index a1f921e..3b704f6 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -60,6 +60,37 @@ QT_BEGIN_NAMESPACE + +class QStringSplitter +{ +public: + QStringSplitter(const QString &s) + : m_string(s), m_data(m_string.constData()), m_len(s.length()), m_pos(0) + { + m_splitChar = QLatin1Char('/'); + } + + inline bool hasNext() { + while (m_pos < m_len && m_data[m_pos] == m_splitChar) + ++m_pos; + return m_pos < m_len; + } + + inline QStringRef next() { + int start = m_pos; + while (m_pos < m_len && m_data[m_pos] != m_splitChar) + ++m_pos; + return QStringRef(&m_string, start, m_pos - start); + } + + QString m_string; + const QChar *m_data; + QChar m_splitChar; + int m_len; + int m_pos; +}; + + //resource glue class QResourceRoot { @@ -101,6 +132,16 @@ protected: } }; +static QString cleanPath(const QString &_path) +{ + QString path = QDir::cleanPath(_path); + // QDir::cleanPath does not remove two trailing slashes under _Windows_ + // due to support for UNC paths. Remove those manually. + if (path.startsWith(QLatin1String("//"))) + path.remove(0, 1); + return path; +} + Q_DECLARE_TYPEINFO(QResourceRoot, Q_MOVABLE_TYPE); Q_GLOBAL_STATIC_WITH_ARGS(QMutex, resourceMutex, (QMutex::Recursive)) @@ -216,9 +257,10 @@ QResourcePrivate::load(const QString &file) related.clear(); QMutexLocker lock(resourceMutex()); const ResourceList *list = resourceList(); + QString cleaned = cleanPath(file); for(int i = 0; i < list->size(); ++i) { QResourceRoot *res = list->at(i); - const int node = res->findNode(file); + const int node = res->findNode(cleaned); if(node != -1) { if(related.isEmpty()) { container = res->isContainer(node); @@ -292,6 +334,7 @@ QResourcePrivate::ensureChildren() const if(path.startsWith(QLatin1Char(':'))) path = path.mid(1); QSet<QString> kids; + QString cleaned = cleanPath(path); for(int i = 0; i < related.size(); ++i) { QResourceRoot *res = related.at(i); if(res->mappingRootSubdir(path, &k) && !k.isEmpty()) { @@ -300,7 +343,7 @@ QResourcePrivate::ensureChildren() const kids.insert(k); } } else { - const int node = res->findNode(path); + const int node = res->findNode(cleaned); if(node != -1) { QStringList related_children = res->children(node); for(int kid = 0; kid < related_children.size(); ++kid) { @@ -406,7 +449,7 @@ QString QResource::absoluteFilePath() const } /*! - Returns true if the resource really exists in the resource heirarchy, + Returns true if the resource really exists in the resource hierarchy, false otherwise. */ @@ -562,18 +605,20 @@ inline QString QResourceRoot::name(int node) const (names[name_offset+1] << 0); name_offset += 2; name_offset += 4; //jump past hash - for(int i = 0; i < name_length*2; i+=2) - ret += QChar(names[name_offset+i+1], names[name_offset+i]); + + ret.resize(name_length); + QChar *strData = ret.data(); + for(int i = 0; i < name_length*2; i+=2) { + QChar c(names[name_offset+i+1], names[name_offset+i]); + *strData = c; + ++strData; + } return ret; } + int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const { - QString path = QDir::cleanPath(_path); - // QDir::cleanPath does not remove two trailing slashes under _Windows_ - // due to support for UNC paths. Remove those manually. - if (path.startsWith(QLatin1String("//"))) - path.remove(0, 1); - + QString path = _path; { QString root = mappingRoot(); if(!root.isEmpty()) { @@ -604,12 +649,11 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const //now iterate up the tree int node = -1; - QStringList segments = path.split(QLatin1Char('/'), QString::SkipEmptyParts); -#ifdef DEBUG_RESOURCE_MATCH - qDebug() << "****" << segments; -#endif - for(int i = 0; child_count && i < segments.size(); ++i) { - const QString &segment = segments[i]; + + QStringSplitter splitter(path); + while (child_count && splitter.hasNext()) { + QStringRef segment = splitter.next(); + #ifdef DEBUG_RESOURCE_MATCH qDebug() << " CHILDREN" << segment; for(int j = 0; j < child_count; ++j) { @@ -651,7 +695,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const (tree[offset+1] << 0); offset += 2; - if(i == segments.size()-1) { + if(!splitter.hasNext()) { if(!(flags & Directory)) { const short country = (tree[offset+0] << 8) + (tree[offset+1] << 0); diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 484e79a..14fc2d4 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -2295,7 +2295,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, As mentioned in the \l{Fallback Mechanism} section, QSettings stores settings for an application in up to four locations, depending on whether the settings are user-specific or - system-wide and whether the the settings are application-specific + system-wide and whether the settings are application-specific or organization-wide. For simplicity, we're assuming the organization is called MySoft and the application is called Star Runner. diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index dd72fd9..93d07e0 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -146,7 +146,7 @@ inline QString QSettingsGroup::toString() const return result; } -class Q_CORE_EXPORT QConfFile +class QConfFile { public: ParsedSettingsMap mergedKeyMap() const; diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 1167671..612d7f7 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -411,6 +411,7 @@ public: QString writeBuffer; QString readBuffer; int readBufferOffset; + int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer qint64 readBufferStartDevicePos; // streaming parameters @@ -437,6 +438,7 @@ QTextStreamPrivate::QTextStreamPrivate(QTextStream *q_ptr) #ifndef QT_NO_TEXTCODEC readConverterSavedState(0), #endif + readConverterSavedStateOffset(0), locale(QLocale::C) { this->q_ptr = q_ptr; @@ -559,13 +561,8 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes) if (!codec || autoDetectUnicode) { autoDetectUnicode = false; - if (bytesRead >= 4 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe && uchar(buf[2]) == 0 && uchar(buf[3]) == 0) - || (uchar(buf[0]) == 0 && uchar(buf[1]) == 0 && uchar(buf[2]) == 0xfe && uchar(buf[3]) == 0xff))) { - codec = QTextCodec::codecForName("UTF-32"); - } else if (bytesRead >= 2 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe) - || (uchar(buf[0]) == 0xfe && uchar(buf[1]) == 0xff))) { - codec = QTextCodec::codecForName("UTF-16"); - } else if (!codec) { + codec = QTextCodec::codecForUtfText(QByteArray::fromRawData(buf, bytesRead), 0); + if (!codec) { codec = QTextCodec::codecForLocale(); writeConverterState.flags |= QTextCodec::IgnoreHeader; } @@ -835,6 +832,10 @@ inline void QTextStreamPrivate::consume(int size) readBufferOffset = 0; readBuffer.clear(); saveConverterState(device->pos()); + } else if (readBufferOffset > QTEXTSTREAM_BUFFERSIZE) { + readBuffer = readBuffer.remove(0,readBufferOffset); + readConverterSavedStateOffset += readBufferOffset; + readBufferOffset = 0; } } } @@ -856,6 +857,7 @@ inline void QTextStreamPrivate::saveConverterState(qint64 newPos) #endif readBufferStartDevicePos = newPos; + readConverterSavedStateOffset = 0; } /*! \internal @@ -1220,7 +1222,7 @@ qint64 QTextStream::pos() const // Rewind the device to get to the current position Ensure that // readBufferOffset is unaffected by fillReadBuffer() - int oldReadBufferOffset = d->readBufferOffset; + int oldReadBufferOffset = d->readBufferOffset + d->readConverterSavedStateOffset; while (d->readBuffer.size() < oldReadBufferOffset) { if (!thatd->fillReadBuffer(1)) return qint64(-1); diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 9ce9a2e..d1a5cdd 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -4759,6 +4759,12 @@ void QUrl::setEncodedQueryItems(const QList<QPair<QByteArray, QByteArray> > &que Inserts the pair \a key = \a value into the query string of the URL. + The key/value pair is encoded before it is added to the query. The + pair is converted into separate strings internally. The \a key and + \a value is first encoded into UTF-8 and then delimited by the + character returned by valueDelimiter(). Each key/value pair is + delimited by the character returned by pairDelimiter(). + \sa addEncodedQueryItem() */ void QUrl::addQueryItem(const QString &key, const QString &value) |