diff -r 000000000000 -r 1918ee327afb src/corelib/io/qbuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/corelib/io/qbuffer.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,475 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbuffer.h" +#include "private/qiodevice_p.h" + +QT_BEGIN_NAMESPACE + +/** QBufferPrivate **/ +class QBufferPrivate : public QIODevicePrivate +{ + Q_DECLARE_PUBLIC(QBuffer) + +public: + QBufferPrivate() + : buf(0) +#ifndef QT_NO_QOBJECT + , writtenSinceLastEmit(0), signalConnectionCount(0), signalsEmitted(false) +#endif + { } + ~QBufferPrivate() { } + + QByteArray *buf; + QByteArray defaultBuf; + int ioIndex; + +#ifndef QT_NO_QOBJECT + // private slots + void _q_emitSignals(); + + qint64 writtenSinceLastEmit; + int signalConnectionCount; + bool signalsEmitted; +#endif +}; + +#ifndef QT_NO_QOBJECT +void QBufferPrivate::_q_emitSignals() +{ + Q_Q(QBuffer); + emit q->bytesWritten(writtenSinceLastEmit); + writtenSinceLastEmit = 0; + emit q->readyRead(); + signalsEmitted = false; +} +#endif + +/*! + \class QBuffer + \reentrant + \brief The QBuffer class provides a QIODevice interface for a QByteArray. + + \ingroup io + + QBuffer allows you to access a QByteArray using the QIODevice + interface. The QByteArray is treated just as a standard random-accessed + file. Example: + + \snippet doc/src/snippets/buffer/buffer.cpp 0 + + By default, an internal QByteArray buffer is created for you when + you create a QBuffer. You can access this buffer directly by + calling buffer(). You can also use QBuffer with an existing + QByteArray by calling setBuffer(), or by passing your array to + QBuffer's constructor. + + Call open() to open the buffer. Then call write() or + putChar() to write to the buffer, and read(), readLine(), + readAll(), or getChar() to read from it. size() returns the + current size of the buffer, and you can seek to arbitrary + positions in the buffer by calling seek(). When you are done with + accessing the buffer, call close(). + + The following code snippet shows how to write data to a + QByteArray using QDataStream and QBuffer: + + \snippet doc/src/snippets/buffer/buffer.cpp 1 + + Effectively, we convert the application's QPalette into a byte + array. Here's how to read the data from the QByteArray: + + \snippet doc/src/snippets/buffer/buffer.cpp 2 + + QTextStream and QDataStream also provide convenience constructors + that take a QByteArray and that create a QBuffer behind the + scenes. + + QBuffer emits readyRead() when new data has arrived in the + buffer. By connecting to this signal, you can use QBuffer to + store temporary data before processing it. For example, you can + pass the buffer to QFtp when downloading a file from an FTP + server. Whenever a new payload of data has been downloaded, + readyRead() is emitted, and you can process the data that just + arrived. QBuffer also emits bytesWritten() every time new data + has been written to the buffer. + + \sa QFile, QDataStream, QTextStream, QByteArray +*/ + +#ifdef QT_NO_QOBJECT +QBuffer::QBuffer() + : QIODevice(*new QBufferPrivate) +{ + Q_D(QBuffer); + d->buf = &d->defaultBuf; + d->ioIndex = 0; +} +QBuffer::QBuffer(QByteArray *buf) + : QIODevice(*new QBufferPrivate) +{ + Q_D(QBuffer); + d->buf = buf ? buf : &d->defaultBuf; + d->ioIndex = 0; + d->defaultBuf.clear(); +} +#else +/*! + Constructs an empty buffer with the given \a parent. You can call + setData() to fill the buffer with data, or you can open it in + write mode and use write(). + + \sa open() +*/ +QBuffer::QBuffer(QObject *parent) + : QIODevice(*new QBufferPrivate, parent) +{ + Q_D(QBuffer); + d->buf = &d->defaultBuf; + d->ioIndex = 0; +} + +/*! + Constructs a QBuffer that uses the QByteArray pointed to by \a + byteArray as its internal buffer, and with the given \a parent. + The caller is responsible for ensuring that \a byteArray remains + valid until the QBuffer is destroyed, or until setBuffer() is + called to change the buffer. QBuffer doesn't take ownership of + the QByteArray. + + If you open the buffer in write-only mode or read-write mode and + write something into the QBuffer, \a byteArray will be modified. + + Example: + + \snippet doc/src/snippets/buffer/buffer.cpp 3 + + \sa open(), setBuffer(), setData() +*/ +QBuffer::QBuffer(QByteArray *byteArray, QObject *parent) + : QIODevice(*new QBufferPrivate, parent) +{ + Q_D(QBuffer); + d->buf = byteArray ? byteArray : &d->defaultBuf; + d->defaultBuf.clear(); + d->ioIndex = 0; +} +#endif + +/*! + Destroys the buffer. +*/ + +QBuffer::~QBuffer() +{ +} + +/*! + Makes QBuffer uses the QByteArray pointed to by \a + byteArray as its internal buffer. The caller is responsible for + ensuring that \a byteArray remains valid until the QBuffer is + destroyed, or until setBuffer() is called to change the buffer. + QBuffer doesn't take ownership of the QByteArray. + + Does nothing if isOpen() is true. + + If you open the buffer in write-only mode or read-write mode and + write something into the QBuffer, \a byteArray will be modified. + + Example: + + \snippet doc/src/snippets/buffer/buffer.cpp 4 + + If \a byteArray is 0, the buffer creates its own internal + QByteArray to work on. This byte array is initially empty. + + \sa buffer(), setData(), open() +*/ + +void QBuffer::setBuffer(QByteArray *byteArray) +{ + Q_D(QBuffer); + if (isOpen()) { + qWarning("QBuffer::setBuffer: Buffer is open"); + return; + } + if (byteArray) { + d->buf = byteArray; + } else { + d->buf = &d->defaultBuf; + } + d->defaultBuf.clear(); + d->ioIndex = 0; +} + +/*! + Returns a reference to the QBuffer's internal buffer. You can use + it to modify the QByteArray behind the QBuffer's back. + + \sa setBuffer(), data() +*/ + +QByteArray &QBuffer::buffer() +{ + Q_D(QBuffer); + return *d->buf; +} + +/*! + \overload + + This is the same as data(). +*/ + +const QByteArray &QBuffer::buffer() const +{ + Q_D(const QBuffer); + return *d->buf; +} + + +/*! + Returns the data contained in the buffer. + + This is the same as buffer(). + + \sa setData(), setBuffer() +*/ + +const QByteArray &QBuffer::data() const +{ + Q_D(const QBuffer); + return *d->buf; +} + +/*! + Sets the contents of the internal buffer to be \a data. This is + the same as assigning \a data to buffer(). + + Does nothing if isOpen() is true. + + \sa setBuffer() +*/ +void QBuffer::setData(const QByteArray &data) +{ + Q_D(QBuffer); + if (isOpen()) { + qWarning("QBuffer::setData: Buffer is open"); + return; + } + *d->buf = data; + d->ioIndex = 0; +} + +/*! + \fn void QBuffer::setData(const char *data, int size) + + \overload + + Sets the contents of the internal buffer to be the first \a size + bytes of \a data. +*/ + +/*! + \reimp +*/ +bool QBuffer::open(OpenMode flags) +{ + Q_D(QBuffer); + + if ((flags & Append) == Append) + flags |= WriteOnly; + setOpenMode(flags); + if (!(isReadable() || isWritable())) { + qWarning("QFile::open: File access not specified"); + return false; + } + + if ((flags & QIODevice::Truncate) == QIODevice::Truncate) { + d->buf->resize(0); + } + if ((flags & QIODevice::Append) == QIODevice::Append) // append to end of buffer + seek(d->buf->size()); + else + seek(0); + + return true; +} + +/*! + \reimp +*/ +void QBuffer::close() +{ + QIODevice::close(); +} + +/*! + \reimp +*/ +qint64 QBuffer::pos() const +{ + return QIODevice::pos(); +} + +/*! + \reimp +*/ +qint64 QBuffer::size() const +{ + Q_D(const QBuffer); + return qint64(d->buf->size()); +} + +/*! + \reimp +*/ +bool QBuffer::seek(qint64 pos) +{ + Q_D(QBuffer); + if (pos > d->buf->size() && isWritable()) { + if (seek(d->buf->size())) { + const qint64 gapSize = pos - d->buf->size(); + if (write(QByteArray(gapSize, 0)) != gapSize) { + qWarning("QBuffer::seek: Unable to fill gap"); + return false; + } + } else { + return false; + } + } else if (pos > d->buf->size() || pos < 0) { + qWarning("QBuffer::seek: Invalid pos: %d", int(pos)); + return false; + } + d->ioIndex = int(pos); + return QIODevice::seek(pos); +} + +/*! + \reimp +*/ +bool QBuffer::atEnd() const +{ + return QIODevice::atEnd(); +} + +/*! + \reimp +*/ +bool QBuffer::canReadLine() const +{ + Q_D(const QBuffer); + if (!isOpen()) + return false; + + return d->buf->indexOf('\n', int(pos())) != -1 || QIODevice::canReadLine(); +} + +/*! + \reimp +*/ +qint64 QBuffer::readData(char *data, qint64 len) +{ + Q_D(QBuffer); + if ((len = qMin(len, qint64(d->buf->size()) - d->ioIndex)) <= 0) + return qint64(0); + memcpy(data, d->buf->constData() + d->ioIndex, len); + d->ioIndex += int(len); + return len; +} + +/*! + \reimp +*/ +qint64 QBuffer::writeData(const char *data, qint64 len) +{ + Q_D(QBuffer); + int extraBytes = d->ioIndex + len - d->buf->size(); + if (extraBytes > 0) { // overflow + int newSize = d->buf->size() + extraBytes; + d->buf->resize(newSize); + if (d->buf->size() != newSize) { // could not resize + qWarning("QBuffer::writeData: Memory allocation error"); + return -1; + } + } + + memcpy(d->buf->data() + d->ioIndex, (uchar *)data, int(len)); + d->ioIndex += int(len); + +#ifndef QT_NO_QOBJECT + d->writtenSinceLastEmit += len; + if (d->signalConnectionCount && !d->signalsEmitted && !signalsBlocked()) { + d->signalsEmitted = true; + QMetaObject::invokeMethod(this, "_q_emitSignals", Qt::QueuedConnection); + } +#endif + return len; +} + +#ifndef QT_NO_QOBJECT +/*! + \reimp + \internal +*/ +void QBuffer::connectNotify(const char *signal) +{ + if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0) + d_func()->signalConnectionCount++; +} + +/*! + \reimp + \internal +*/ +void QBuffer::disconnectNotify(const char *signal) +{ + if (!signal || strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0) + d_func()->signalConnectionCount--; +} +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_QOBJECT +# include "moc_qbuffer.cpp" +#endif +