src/corelib/io/qnoncontiguousbytedevice.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 "qnoncontiguousbytedevice_p.h"
       
    43 #include <qbuffer.h>
       
    44 #include <qdebug.h>
       
    45 #include <qfile.h>
       
    46 
       
    47 QT_BEGIN_NAMESPACE
       
    48 
       
    49 /*!
       
    50     \class QNonContiguousByteDevice
       
    51     \brief A QNonContiguousByteDevice is a representation of a
       
    52     file, array or buffer that allows access with a read pointer.
       
    53     \since 4.6
       
    54 
       
    55     \inmodule QtCore
       
    56 
       
    57     The goal of this class is to have a data representation that
       
    58     allows us to avoid doing a memcpy as we have to do with QIODevice.
       
    59 
       
    60     \sa QNonContiguousByteDeviceFactory
       
    61 
       
    62     \internal
       
    63 */
       
    64 /*!
       
    65     \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len)
       
    66 
       
    67     Return a byte pointer for at most \a maximumLength bytes of that device.
       
    68     if \a maximumLength is -1, the caller does not care about the length and
       
    69     the device may return what it desires to.
       
    70     The actual number of bytes the pointer is valid for is returned in
       
    71     the \a len variable.
       
    72     \a len will be -1 if EOF or an error occurs.
       
    73     If it was really EOF can then afterwards be checked with atEnd()
       
    74     Returns 0 if it is not possible to read at that position.
       
    75 
       
    76     \sa atEnd()
       
    77 
       
    78     \internal
       
    79 */
       
    80 /*!
       
    81     \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount)
       
    82 
       
    83      will advance the internal read pointer by \a amount bytes.
       
    84      The old readPointer is invalid after this call.
       
    85 
       
    86     \sa readPointer()
       
    87 
       
    88     \internal
       
    89 */
       
    90 /*!
       
    91     \fn virtual bool QNonContiguousByteDevice::atEnd()
       
    92 
       
    93      Returns true if everything has been read and the read
       
    94      pointer cannot be advanced anymore.
       
    95 
       
    96     \sa readPointer(), advanceReadPointer(), reset()
       
    97 
       
    98     \internal
       
    99 */
       
   100 /*!
       
   101     \fn virtual bool QNonContiguousByteDevice::reset()
       
   102 
       
   103     Moves the internal read pointer back to the beginning.
       
   104     Returns false if this was not possible.
       
   105 
       
   106     \sa atEnd(), disableReset()
       
   107 
       
   108     \internal
       
   109 */
       
   110 /*!
       
   111     \fn void QNonContiguousByteDevice::disableReset()
       
   112 
       
   113     Disable the reset() call, e.g. it will always
       
   114     do nothing and return false.
       
   115 
       
   116     \sa reset()
       
   117 
       
   118     \internal
       
   119 */
       
   120 /*!
       
   121     \fn virtual qint64 QNonContiguousByteDevice::size()
       
   122 
       
   123     Returns the size of the complete device or -1 if unknown.
       
   124     May also return less/more than what can be actually read with readPointer()
       
   125 
       
   126     \internal
       
   127 */
       
   128 /*!
       
   129     \fn void QNonContiguousByteDevice::readyRead()
       
   130 
       
   131     Emitted when there is data available
       
   132 
       
   133     \internal
       
   134 */
       
   135 /*!
       
   136     \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total)
       
   137 
       
   138     Emitted when data has been "read" by advancing the read pointer
       
   139 
       
   140     \internal
       
   141 */
       
   142 
       
   143 QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false)
       
   144 {
       
   145 }
       
   146 
       
   147 QNonContiguousByteDevice::~QNonContiguousByteDevice()
       
   148 {
       
   149 }
       
   150 
       
   151 void QNonContiguousByteDevice::disableReset()
       
   152 {
       
   153     resetDisabled = true;
       
   154 }
       
   155 
       
   156 QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice()
       
   157 {
       
   158     buffer = b;
       
   159     byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos());
       
   160     arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray);
       
   161     arrayImpl->setParent(this);
       
   162     connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead()));
       
   163     connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64)));
       
   164 }
       
   165 
       
   166 QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl()
       
   167 {
       
   168 }
       
   169 
       
   170 const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
       
   171 {
       
   172     return arrayImpl->readPointer(maximumLength, len);
       
   173 }
       
   174 
       
   175 bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount)
       
   176 {
       
   177     return arrayImpl->advanceReadPointer(amount);
       
   178 }
       
   179 
       
   180 bool QNonContiguousByteDeviceBufferImpl::atEnd()
       
   181 {
       
   182     return arrayImpl->atEnd();
       
   183 }
       
   184 
       
   185 bool QNonContiguousByteDeviceBufferImpl::reset()
       
   186 {
       
   187     if (resetDisabled)
       
   188         return false;
       
   189     return arrayImpl->reset();
       
   190 }
       
   191 
       
   192 qint64 QNonContiguousByteDeviceBufferImpl::size()
       
   193 {
       
   194     return arrayImpl->size();
       
   195 }
       
   196 
       
   197 QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0)
       
   198 {
       
   199     byteArray = ba;
       
   200 }
       
   201 
       
   202 QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl()
       
   203 {
       
   204 }
       
   205 
       
   206 const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len)
       
   207 {
       
   208     if (atEnd()) {
       
   209         len = -1;
       
   210         return 0;
       
   211     }
       
   212 
       
   213     if (maximumLength != -1)
       
   214         len = qMin(maximumLength, size() - currentPosition);
       
   215     else
       
   216         len = size() - currentPosition;
       
   217 
       
   218     return byteArray->constData() + currentPosition;
       
   219 }
       
   220 
       
   221 bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount)
       
   222 {
       
   223     currentPosition += amount;
       
   224     emit readProgress(currentPosition, size());
       
   225     return true;
       
   226 }
       
   227 
       
   228 bool QNonContiguousByteDeviceByteArrayImpl::atEnd()
       
   229 {
       
   230     return currentPosition >= size();
       
   231 }
       
   232 
       
   233 bool QNonContiguousByteDeviceByteArrayImpl::reset()
       
   234 {
       
   235     if (resetDisabled)
       
   236         return false;
       
   237 
       
   238     currentPosition = 0;
       
   239     return true;
       
   240 }
       
   241 
       
   242 qint64 QNonContiguousByteDeviceByteArrayImpl::size()
       
   243 {
       
   244     return byteArray->size();
       
   245 }
       
   246 
       
   247 QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb)
       
   248     : QNonContiguousByteDevice(), currentPosition(0)
       
   249 {
       
   250     ringBuffer = rb;
       
   251 }
       
   252 
       
   253 QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl()
       
   254 {
       
   255 }
       
   256 
       
   257 const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len)
       
   258 {
       
   259     if (atEnd()) {
       
   260         len = -1;
       
   261         return 0;
       
   262     }
       
   263 
       
   264     const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);
       
   265 
       
   266     if (maximumLength != -1)
       
   267         len = qMin(len, maximumLength);
       
   268 
       
   269     return returnValue;
       
   270 }
       
   271 
       
   272 bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount)
       
   273 {
       
   274     currentPosition += amount;
       
   275     emit readProgress(currentPosition, size());
       
   276     return true;
       
   277 }
       
   278 
       
   279 bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
       
   280 {
       
   281     return currentPosition >= size();
       
   282 }
       
   283 
       
   284 bool QNonContiguousByteDeviceRingBufferImpl::reset()
       
   285 {
       
   286     if (resetDisabled)
       
   287         return false;
       
   288 
       
   289     currentPosition = 0;
       
   290     return true;
       
   291 }
       
   292 
       
   293 qint64 QNonContiguousByteDeviceRingBufferImpl::size()
       
   294 {
       
   295     return ringBuffer->size();
       
   296 }
       
   297 
       
   298 QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
       
   299     : QNonContiguousByteDevice(),
       
   300     currentReadBuffer(0), currentReadBufferSize(16*1024),
       
   301     currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
       
   302     eof(false)
       
   303 {
       
   304     device = d;
       
   305     initialPosition = d->pos();
       
   306     connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
       
   307     connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
       
   308 }
       
   309 
       
   310 QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
       
   311 {
       
   312     delete currentReadBuffer;
       
   313 }
       
   314 
       
   315 const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
       
   316 {
       
   317     if (eof == true) {
       
   318         len = -1;
       
   319         return 0;
       
   320     }
       
   321 
       
   322     if (currentReadBuffer == 0)
       
   323         currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc
       
   324 
       
   325     if (maximumLength == -1)
       
   326         maximumLength = currentReadBufferSize;
       
   327 
       
   328     if (currentReadBufferAmount - currentReadBufferPosition > 0) {
       
   329         len = currentReadBufferAmount - currentReadBufferPosition;
       
   330         return currentReadBuffer->data() + currentReadBufferPosition;
       
   331     }
       
   332 
       
   333     qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize));
       
   334 
       
   335     if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
       
   336         eof = true;
       
   337         len = -1;
       
   338         // size was unknown before, emit a readProgress with the final size
       
   339         if (size() == -1)
       
   340             emit readProgress(totalAdvancements, totalAdvancements);
       
   341         return 0;
       
   342     }
       
   343 
       
   344     currentReadBufferAmount = haveRead;
       
   345     currentReadBufferPosition = 0;
       
   346 
       
   347     len = haveRead;
       
   348     return currentReadBuffer->data();
       
   349 }
       
   350 
       
   351 bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
       
   352 {
       
   353     totalAdvancements += amount;
       
   354 
       
   355     // normal advancement
       
   356     currentReadBufferPosition += amount;
       
   357 
       
   358     // advancing over that what has actually been read before
       
   359     if (currentReadBufferPosition > currentReadBufferAmount) {
       
   360         qint64 i = currentReadBufferPosition - currentReadBufferAmount;
       
   361         while (i > 0) {
       
   362             if (device->getChar(0) == false) {
       
   363                 emit readProgress(totalAdvancements - i, size());
       
   364                 return false; // ### FIXME handle eof
       
   365             }
       
   366             i--;
       
   367         }
       
   368 
       
   369         currentReadBufferPosition = 0;
       
   370         currentReadBufferAmount = 0;
       
   371     }
       
   372 
       
   373     if (size() == -1)
       
   374         emit readProgress(totalAdvancements, totalAdvancements);
       
   375     else
       
   376         emit readProgress(totalAdvancements, size());
       
   377 
       
   378     return true;
       
   379 }
       
   380 
       
   381 bool QNonContiguousByteDeviceIoDeviceImpl::atEnd()
       
   382 {
       
   383     return eof == true;
       
   384 }
       
   385 
       
   386 bool QNonContiguousByteDeviceIoDeviceImpl::reset()
       
   387 {
       
   388     if (resetDisabled)
       
   389         return false;
       
   390 
       
   391     if (device->seek(initialPosition)) {
       
   392         eof = false; // assume eof is false, it will be true after a read has been attempted
       
   393         return true;
       
   394     }
       
   395 
       
   396     return false;
       
   397 }
       
   398 
       
   399 qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
       
   400 {
       
   401     // note that this is different from the size() implementation of QIODevice!
       
   402 
       
   403     if (device->isSequential())
       
   404         return -1;
       
   405 
       
   406     return device->size() - initialPosition;
       
   407 }
       
   408 
       
   409 QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
       
   410 {
       
   411     byteDevice = bd;
       
   412     connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
       
   413 
       
   414     open(ReadOnly);
       
   415 }
       
   416 
       
   417 QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()
       
   418 {
       
   419 
       
   420 }
       
   421 
       
   422 bool QByteDeviceWrappingIoDevice::isSequential() const
       
   423 {
       
   424     return (byteDevice->size() == -1);
       
   425 }
       
   426 
       
   427 bool QByteDeviceWrappingIoDevice::atEnd() const
       
   428 {
       
   429     return byteDevice->atEnd();
       
   430 }
       
   431 
       
   432 bool QByteDeviceWrappingIoDevice::reset()
       
   433 {
       
   434     return byteDevice->reset();
       
   435 }
       
   436 
       
   437 qint64 QByteDeviceWrappingIoDevice::size() const
       
   438 {
       
   439     if (isSequential())
       
   440         return 0;
       
   441 
       
   442     return byteDevice->size();
       
   443 }
       
   444 
       
   445 
       
   446 qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize)
       
   447 {
       
   448     qint64 len;
       
   449     const char *readPointer = byteDevice->readPointer(maxSize, len);
       
   450     if (len == -1)
       
   451         return -1;
       
   452 
       
   453     memcpy(data, readPointer, len);
       
   454     byteDevice->advanceReadPointer(len);
       
   455     return len;
       
   456 }
       
   457 
       
   458 qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize)
       
   459 {
       
   460     Q_UNUSED(data);
       
   461     Q_UNUSED(maxSize);
       
   462     return -1;
       
   463 }
       
   464 
       
   465 /*!
       
   466     \class QNonContiguousByteDeviceFactory
       
   467     \since 4.6
       
   468 
       
   469     \inmodule QtCore
       
   470 
       
   471     Creates a QNonContiguousByteDevice out of a QIODevice,
       
   472     QByteArray etc.
       
   473 
       
   474     \sa QNonContiguousByteDevice
       
   475 
       
   476     \internal
       
   477 */
       
   478 
       
   479 /*!
       
   480     \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device);
       
   481 
       
   482     Create a QNonContiguousByteDevice out of a QIODevice.
       
   483     For QFile, QBuffer and all other QIoDevice, sequential or not.
       
   484 
       
   485     \internal
       
   486 */
       
   487 QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device)
       
   488 {
       
   489     // shortcut if it is a QBuffer
       
   490     if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) {
       
   491         return new QNonContiguousByteDeviceBufferImpl(buffer);
       
   492     }
       
   493 
       
   494     // ### FIXME special case if device is a QFile that supports map()
       
   495     // then we can actually deal with the file without using read/peek
       
   496 
       
   497     // generic QIODevice
       
   498     return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME
       
   499 }
       
   500 
       
   501 /*!
       
   502     \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer);
       
   503 
       
   504     Create a QNonContiguousByteDevice out of a QRingBuffer.
       
   505 
       
   506     \internal
       
   507 */
       
   508 QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer)
       
   509 {
       
   510     return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer);
       
   511 }
       
   512 
       
   513 /*!
       
   514     \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray);
       
   515 
       
   516     Create a QNonContiguousByteDevice out of a QByteArray.
       
   517 
       
   518     \internal
       
   519 */
       
   520 QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray)
       
   521 {
       
   522     return new QNonContiguousByteDeviceByteArrayImpl(byteArray);
       
   523 }
       
   524 
       
   525 /*!
       
   526     \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice);
       
   527 
       
   528     Wrap the \a byteDevice (possibly again) into a QIODevice.
       
   529 
       
   530     \internal
       
   531 */
       
   532 QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice)
       
   533 {
       
   534     // ### FIXME if it already has been based on QIoDevice, we could that one out again
       
   535     // and save some calling
       
   536 
       
   537     // needed for FTP backend
       
   538 
       
   539     return new QByteDeviceWrappingIoDevice(byteDevice);
       
   540 }
       
   541 
       
   542 QT_END_NAMESPACE
       
   543