src/corelib/io/qbuffer.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qbuffer.h"
       
    43 #include "private/qiodevice_p.h"
       
    44 
       
    45 QT_BEGIN_NAMESPACE
       
    46 
       
    47 /** QBufferPrivate **/
       
    48 class QBufferPrivate : public QIODevicePrivate
       
    49 {
       
    50     Q_DECLARE_PUBLIC(QBuffer)
       
    51 
       
    52 public:
       
    53     QBufferPrivate()
       
    54     : buf(0)
       
    55 #ifndef QT_NO_QOBJECT
       
    56         , writtenSinceLastEmit(0), signalConnectionCount(0), signalsEmitted(false)
       
    57 #endif
       
    58     { }
       
    59     ~QBufferPrivate() { }
       
    60 
       
    61     QByteArray *buf;
       
    62     QByteArray defaultBuf;
       
    63     int ioIndex;
       
    64 
       
    65 #ifndef QT_NO_QOBJECT
       
    66     // private slots
       
    67     void _q_emitSignals();
       
    68 
       
    69     qint64 writtenSinceLastEmit;
       
    70     int signalConnectionCount;
       
    71     bool signalsEmitted;
       
    72 #endif
       
    73 };
       
    74 
       
    75 #ifndef QT_NO_QOBJECT
       
    76 void QBufferPrivate::_q_emitSignals()
       
    77 {
       
    78     Q_Q(QBuffer);
       
    79     emit q->bytesWritten(writtenSinceLastEmit);
       
    80     writtenSinceLastEmit = 0;
       
    81     emit q->readyRead();
       
    82     signalsEmitted = false;
       
    83 }
       
    84 #endif
       
    85 
       
    86 /*!
       
    87     \class QBuffer
       
    88     \reentrant
       
    89     \brief The QBuffer class provides a QIODevice interface for a QByteArray.
       
    90 
       
    91     \ingroup io
       
    92 
       
    93     QBuffer allows you to access a QByteArray using the QIODevice
       
    94     interface. The QByteArray is treated just as a standard random-accessed
       
    95     file. Example:
       
    96 
       
    97     \snippet doc/src/snippets/buffer/buffer.cpp 0
       
    98 
       
    99     By default, an internal QByteArray buffer is created for you when
       
   100     you create a QBuffer. You can access this buffer directly by
       
   101     calling buffer(). You can also use QBuffer with an existing
       
   102     QByteArray by calling setBuffer(), or by passing your array to
       
   103     QBuffer's constructor.
       
   104 
       
   105     Call open() to open the buffer. Then call write() or
       
   106     putChar() to write to the buffer, and read(), readLine(),
       
   107     readAll(), or getChar() to read from it. size() returns the
       
   108     current size of the buffer, and you can seek to arbitrary
       
   109     positions in the buffer by calling seek(). When you are done with
       
   110     accessing the buffer, call close().
       
   111 
       
   112     The following code snippet shows how to write data to a
       
   113     QByteArray using QDataStream and QBuffer:
       
   114 
       
   115     \snippet doc/src/snippets/buffer/buffer.cpp 1
       
   116 
       
   117     Effectively, we convert the application's QPalette into a byte
       
   118     array. Here's how to read the data from the QByteArray:
       
   119 
       
   120     \snippet doc/src/snippets/buffer/buffer.cpp 2
       
   121 
       
   122     QTextStream and QDataStream also provide convenience constructors
       
   123     that take a QByteArray and that create a QBuffer behind the
       
   124     scenes.
       
   125 
       
   126     QBuffer emits readyRead() when new data has arrived in the
       
   127     buffer. By connecting to this signal, you can use QBuffer to
       
   128     store temporary data before processing it. For example, you can
       
   129     pass the buffer to QFtp when downloading a file from an FTP
       
   130     server. Whenever a new payload of data has been downloaded,
       
   131     readyRead() is emitted, and you can process the data that just
       
   132     arrived. QBuffer also emits bytesWritten() every time new data
       
   133     has been written to the buffer.
       
   134 
       
   135     \sa QFile, QDataStream, QTextStream, QByteArray
       
   136 */
       
   137 
       
   138 #ifdef QT_NO_QOBJECT
       
   139 QBuffer::QBuffer()
       
   140     : QIODevice(*new QBufferPrivate)
       
   141 {
       
   142     Q_D(QBuffer);
       
   143     d->buf = &d->defaultBuf;
       
   144     d->ioIndex = 0;
       
   145 }
       
   146 QBuffer::QBuffer(QByteArray *buf)
       
   147     : QIODevice(*new QBufferPrivate)
       
   148 {
       
   149     Q_D(QBuffer);
       
   150     d->buf = buf ? buf : &d->defaultBuf;
       
   151     d->ioIndex = 0;
       
   152     d->defaultBuf.clear();
       
   153 }
       
   154 #else
       
   155 /*!
       
   156     Constructs an empty buffer with the given \a parent. You can call
       
   157     setData() to fill the buffer with data, or you can open it in
       
   158     write mode and use write().
       
   159 
       
   160     \sa open()
       
   161 */
       
   162 QBuffer::QBuffer(QObject *parent)
       
   163     : QIODevice(*new QBufferPrivate, parent)
       
   164 {
       
   165     Q_D(QBuffer);
       
   166     d->buf = &d->defaultBuf;
       
   167     d->ioIndex = 0;
       
   168 }
       
   169 
       
   170 /*!
       
   171     Constructs a QBuffer that uses the QByteArray pointed to by \a
       
   172     byteArray as its internal buffer, and with the given \a parent.
       
   173     The caller is responsible for ensuring that \a byteArray remains
       
   174     valid until the QBuffer is destroyed, or until setBuffer() is
       
   175     called to change the buffer. QBuffer doesn't take ownership of
       
   176     the QByteArray.
       
   177 
       
   178     If you open the buffer in write-only mode or read-write mode and
       
   179     write something into the QBuffer, \a byteArray will be modified.
       
   180 
       
   181     Example:
       
   182 
       
   183     \snippet doc/src/snippets/buffer/buffer.cpp 3
       
   184 
       
   185     \sa open(), setBuffer(), setData()
       
   186 */
       
   187 QBuffer::QBuffer(QByteArray *byteArray, QObject *parent)
       
   188     : QIODevice(*new QBufferPrivate, parent)
       
   189 {
       
   190     Q_D(QBuffer);
       
   191     d->buf = byteArray ? byteArray : &d->defaultBuf;
       
   192     d->defaultBuf.clear();
       
   193     d->ioIndex = 0;
       
   194 }
       
   195 #endif
       
   196 
       
   197 /*!
       
   198     Destroys the buffer.
       
   199 */
       
   200 
       
   201 QBuffer::~QBuffer()
       
   202 {
       
   203 }
       
   204 
       
   205 /*!
       
   206     Makes QBuffer uses the QByteArray pointed to by \a
       
   207     byteArray as its internal buffer. The caller is responsible for
       
   208     ensuring that \a byteArray remains valid until the QBuffer is
       
   209     destroyed, or until setBuffer() is called to change the buffer.
       
   210     QBuffer doesn't take ownership of the QByteArray.
       
   211 
       
   212     Does nothing if isOpen() is true.
       
   213 
       
   214     If you open the buffer in write-only mode or read-write mode and
       
   215     write something into the QBuffer, \a byteArray will be modified.
       
   216 
       
   217     Example:
       
   218 
       
   219     \snippet doc/src/snippets/buffer/buffer.cpp 4
       
   220 
       
   221     If \a byteArray is 0, the buffer creates its own internal
       
   222     QByteArray to work on. This byte array is initially empty.
       
   223 
       
   224     \sa buffer(), setData(), open()
       
   225 */
       
   226 
       
   227 void QBuffer::setBuffer(QByteArray *byteArray)
       
   228 {
       
   229     Q_D(QBuffer);
       
   230     if (isOpen()) {
       
   231         qWarning("QBuffer::setBuffer: Buffer is open");
       
   232         return;
       
   233     }
       
   234     if (byteArray) {
       
   235         d->buf = byteArray;
       
   236     } else {
       
   237         d->buf = &d->defaultBuf;
       
   238     }
       
   239     d->defaultBuf.clear();
       
   240     d->ioIndex = 0;
       
   241 }
       
   242 
       
   243 /*!
       
   244     Returns a reference to the QBuffer's internal buffer. You can use
       
   245     it to modify the QByteArray behind the QBuffer's back.
       
   246 
       
   247     \sa setBuffer(), data()
       
   248 */
       
   249 
       
   250 QByteArray &QBuffer::buffer()
       
   251 {
       
   252     Q_D(QBuffer);
       
   253     return *d->buf;
       
   254 }
       
   255 
       
   256 /*!
       
   257     \overload
       
   258 
       
   259     This is the same as data().
       
   260 */
       
   261 
       
   262 const QByteArray &QBuffer::buffer() const
       
   263 {
       
   264     Q_D(const QBuffer);
       
   265     return *d->buf;
       
   266 }
       
   267 
       
   268 
       
   269 /*!
       
   270     Returns the data contained in the buffer.
       
   271 
       
   272     This is the same as buffer().
       
   273 
       
   274     \sa setData(), setBuffer()
       
   275 */
       
   276 
       
   277 const QByteArray &QBuffer::data() const
       
   278 {
       
   279     Q_D(const QBuffer);
       
   280     return *d->buf;
       
   281 }
       
   282 
       
   283 /*!
       
   284     Sets the contents of the internal buffer to be \a data. This is
       
   285     the same as assigning \a data to buffer().
       
   286 
       
   287     Does nothing if isOpen() is true.
       
   288 
       
   289     \sa setBuffer()
       
   290 */
       
   291 void QBuffer::setData(const QByteArray &data)
       
   292 {
       
   293     Q_D(QBuffer);
       
   294     if (isOpen()) {
       
   295         qWarning("QBuffer::setData: Buffer is open");
       
   296         return;
       
   297     }
       
   298     *d->buf = data;
       
   299     d->ioIndex = 0;
       
   300 }
       
   301 
       
   302 /*!
       
   303     \fn void QBuffer::setData(const char *data, int size)
       
   304 
       
   305     \overload
       
   306 
       
   307     Sets the contents of the internal buffer to be the first \a size
       
   308     bytes of \a data.
       
   309 */
       
   310 
       
   311 /*!
       
   312    \reimp
       
   313 */
       
   314 bool QBuffer::open(OpenMode flags)
       
   315 {
       
   316     Q_D(QBuffer);
       
   317 
       
   318     if ((flags & Append) == Append)
       
   319         flags |= WriteOnly;
       
   320     setOpenMode(flags);
       
   321     if (!(isReadable() || isWritable())) {
       
   322         qWarning("QFile::open: File access not specified");
       
   323         return false;
       
   324     }
       
   325 
       
   326     if ((flags & QIODevice::Truncate) == QIODevice::Truncate) {
       
   327         d->buf->resize(0);
       
   328     }
       
   329     if ((flags & QIODevice::Append) == QIODevice::Append) // append to end of buffer
       
   330         seek(d->buf->size());
       
   331     else
       
   332         seek(0);
       
   333 
       
   334     return true;
       
   335 }
       
   336 
       
   337 /*!
       
   338     \reimp
       
   339 */
       
   340 void QBuffer::close()
       
   341 {
       
   342     QIODevice::close();
       
   343 }
       
   344 
       
   345 /*!
       
   346     \reimp
       
   347 */
       
   348 qint64 QBuffer::pos() const
       
   349 {
       
   350     return QIODevice::pos();
       
   351 }
       
   352 
       
   353 /*!
       
   354     \reimp
       
   355 */
       
   356 qint64 QBuffer::size() const
       
   357 {
       
   358     Q_D(const QBuffer);
       
   359     return qint64(d->buf->size());
       
   360 }
       
   361 
       
   362 /*!
       
   363     \reimp
       
   364 */
       
   365 bool QBuffer::seek(qint64 pos)
       
   366 {
       
   367     Q_D(QBuffer);
       
   368     if (pos > d->buf->size() && isWritable()) {
       
   369         if (seek(d->buf->size())) {
       
   370             const qint64 gapSize = pos - d->buf->size();
       
   371             if (write(QByteArray(gapSize, 0)) != gapSize) {
       
   372                 qWarning("QBuffer::seek: Unable to fill gap");
       
   373                 return false;
       
   374             }
       
   375         } else {
       
   376             return false;
       
   377         }
       
   378     } else if (pos > d->buf->size() || pos < 0) {
       
   379         qWarning("QBuffer::seek: Invalid pos: %d", int(pos));
       
   380         return false;
       
   381     }
       
   382     d->ioIndex = int(pos);
       
   383     return QIODevice::seek(pos);
       
   384 }
       
   385 
       
   386 /*!
       
   387     \reimp
       
   388 */
       
   389 bool QBuffer::atEnd() const
       
   390 {
       
   391     return QIODevice::atEnd();
       
   392 }
       
   393 
       
   394 /*!
       
   395    \reimp
       
   396 */
       
   397 bool QBuffer::canReadLine() const
       
   398 {
       
   399     Q_D(const QBuffer);
       
   400     if (!isOpen())
       
   401         return false;
       
   402 
       
   403     return d->buf->indexOf('\n', int(pos())) != -1 || QIODevice::canReadLine();
       
   404 }
       
   405 
       
   406 /*!
       
   407     \reimp
       
   408 */
       
   409 qint64 QBuffer::readData(char *data, qint64 len)
       
   410 {
       
   411     Q_D(QBuffer);
       
   412     if ((len = qMin(len, qint64(d->buf->size()) - d->ioIndex)) <= 0)
       
   413         return qint64(0);
       
   414     memcpy(data, d->buf->constData() + d->ioIndex, len);
       
   415     d->ioIndex += int(len);
       
   416     return len;
       
   417 }
       
   418 
       
   419 /*!
       
   420     \reimp
       
   421 */
       
   422 qint64 QBuffer::writeData(const char *data, qint64 len)
       
   423 {
       
   424     Q_D(QBuffer);
       
   425     int extraBytes = d->ioIndex + len - d->buf->size();
       
   426     if (extraBytes > 0) { // overflow
       
   427         int newSize = d->buf->size() + extraBytes;
       
   428         d->buf->resize(newSize);
       
   429         if (d->buf->size() != newSize) { // could not resize
       
   430             qWarning("QBuffer::writeData: Memory allocation error");
       
   431             return -1;
       
   432         }
       
   433     }
       
   434 
       
   435     memcpy(d->buf->data() + d->ioIndex, (uchar *)data, int(len));
       
   436     d->ioIndex += int(len);
       
   437 
       
   438 #ifndef QT_NO_QOBJECT
       
   439     d->writtenSinceLastEmit += len;
       
   440     if (d->signalConnectionCount && !d->signalsEmitted && !signalsBlocked()) {
       
   441         d->signalsEmitted = true;
       
   442         QMetaObject::invokeMethod(this, "_q_emitSignals", Qt::QueuedConnection);
       
   443     }
       
   444 #endif
       
   445     return len;
       
   446 }
       
   447 
       
   448 #ifndef QT_NO_QOBJECT
       
   449 /*!
       
   450     \reimp
       
   451     \internal
       
   452 */
       
   453 void QBuffer::connectNotify(const char *signal)
       
   454 {
       
   455     if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0)
       
   456         d_func()->signalConnectionCount++;
       
   457 }
       
   458 
       
   459 /*!
       
   460     \reimp
       
   461     \internal
       
   462 */
       
   463 void QBuffer::disconnectNotify(const char *signal)
       
   464 {
       
   465     if (!signal || strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0)
       
   466         d_func()->signalConnectionCount--;
       
   467 }
       
   468 #endif
       
   469 
       
   470 QT_END_NAMESPACE
       
   471 
       
   472 #ifndef QT_NO_QOBJECT
       
   473 # include "moc_qbuffer.cpp"
       
   474 #endif
       
   475