summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qnoncontiguousbytedevice.cpp
blob: db286c763e353a37e6645dc99ceb44efbff1f0ab (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
// Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qnoncontiguousbytedevice_p.h"#include <qbuffer.h>#include <qdebug.h>#include <qfile.h>#include <utility> QT_BEGIN_NAMESPACE /*! \class QNonContiguousByteDevice \inmodule QtCore \brief A QNonContiguousByteDevice is a representation of a file, array or buffer that allows access with a read pointer. \since 4.6 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() const Returns \c 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 \c false if this was not possible. \sa atEnd() \internal*//*! \fn virtual qint64 QNonContiguousByteDevice::size() const 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*)nullptr){}QNonContiguousByteDevice::~QNonContiguousByteDevice(){}QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray ba):QNonContiguousByteDevice(),byteArray(std::move(ba)),view(byteArray){}QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QBuffer *buffer):QNonContiguousByteDevice(),byteArray(buffer->buffer()),view(QByteArrayView(byteArray).sliced(buffer->pos(), buffer->size() - buffer->pos())){}QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl(){}const char*QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len){if(atEnd()) { len = -1;returnnullptr;}if(maximumLength != -1) len =qMin(maximumLength,size() - currentPosition);else len =size() - currentPosition;return view.data() + currentPosition;}boolQNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount){ currentPosition += amount; emit readProgress(currentPosition,size());return true;}boolQNonContiguousByteDeviceByteArrayImpl::atEnd()const{return currentPosition >=size();}boolQNonContiguousByteDeviceByteArrayImpl::reset(){ currentPosition =0;return true;} qint64 QNonContiguousByteDeviceByteArrayImpl::size()const{return view.size();} qint64 QNonContiguousByteDeviceByteArrayImpl::pos()const{return currentPosition;}QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(std::shared_ptr<QRingBuffer> rb):QNonContiguousByteDevice(),ringBuffer(std::move(rb)){}QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl(){}const char*QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len){if(atEnd()) { len = -1;returnnullptr;}const char*returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);if(maximumLength != -1) len =qMin(len, maximumLength);return returnValue;}boolQNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount){ currentPosition += amount; emit readProgress(currentPosition,size());return true;}boolQNonContiguousByteDeviceRingBufferImpl::atEnd()const{return currentPosition >=size();} qint64 QNonContiguousByteDeviceRingBufferImpl::pos()const{return currentPosition;}boolQNonContiguousByteDeviceRingBufferImpl::reset(){ currentPosition =0;return true;} qint64 QNonContiguousByteDeviceRingBufferImpl::size()const{return ringBuffer->size();}QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d):QNonContiguousByteDevice(),device(d),currentReadBuffer(nullptr),currentReadBufferSize(16*1024),currentReadBufferAmount(0),currentReadBufferPosition(0),totalAdvancements(0),eof(false),initialPosition(d->pos()){connect(device, &QIODevice::readyRead,this,&QNonContiguousByteDevice::readyRead);connect(device, &QIODevice::readChannelFinished,this,&QNonContiguousByteDevice::readyRead);}QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl(){delete currentReadBuffer;}const char*QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len){if(eof) { len = -1;returnnullptr;}if(currentReadBuffer ==nullptr) currentReadBuffer =newQByteArray(currentReadBufferSize,'\0');// lazy allocif(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 sizeif(size() == -1) emit readProgress(totalAdvancements, totalAdvancements);returnnullptr;} currentReadBufferAmount = haveRead; currentReadBufferPosition =0; len = haveRead;return currentReadBuffer->data();}boolQNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount){ totalAdvancements += amount;// normal advancement currentReadBufferPosition += amount;if(size() == -1) emit readProgress(totalAdvancements, totalAdvancements);else emit readProgress(totalAdvancements,size());// advancing over that what has actually been read beforeif(currentReadBufferPosition > currentReadBufferAmount) { qint64 i = currentReadBufferPosition - currentReadBufferAmount;while(i >0) {if(!device->getChar(nullptr)) { emit readProgress(totalAdvancements - i,size());return false;// ### FIXME handle eof} i--;} currentReadBufferPosition =0; currentReadBufferAmount =0;}return true;}boolQNonContiguousByteDeviceIoDeviceImpl::atEnd()const{return eof;}boolQNonContiguousByteDeviceIoDeviceImpl::reset(){bool reset = (initialPosition ==0) ? device->reset() : device->seek(initialPosition);if(reset) { eof =false;// assume eof is false, it will be true after a read has been attempted totalAdvancements =0;// reset the progress counterif(currentReadBuffer) {delete currentReadBuffer; currentReadBuffer =nullptr;} currentReadBufferAmount =0; currentReadBufferPosition =0;return true;}return false;} qint64 QNonContiguousByteDeviceIoDeviceImpl::size()const{// note that this is different from the size() implementation of QIODevice!if(device->isSequential())return-1;return device->size() - initialPosition;} qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()const{if(device->isSequential())return-1;return device->pos();}QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd):QIODevice(nullptr),byteDevice(bd){connect(bd, &QNonContiguousByteDevice::readyRead,this, &QIODevice::readyRead);open(ReadOnly);}QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()=default;boolQByteDeviceWrappingIoDevice::isSequential()const{return(byteDevice->size() == -1);}boolQByteDeviceWrappingIoDevice::atEnd()const{return byteDevice->atEnd();}boolQByteDeviceWrappingIoDevice::reset(){return byteDevice->reset();} qint64 QByteDeviceWrappingIoDevice::size()const{if(isSequential())return0;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){Q_UNUSED(data);Q_UNUSED(maxSize);return-1;}/*! \class QNonContiguousByteDeviceFactory \inmodule QtCore \since 4.6 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 QBufferif(QBuffer *buffer = qobject_cast<QBuffer *>(device)) {return newQNonContiguousByteDeviceByteArrayImpl(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 QIODevicereturn newQNonContiguousByteDeviceIoDeviceImpl(device);// FIXME}/*! Create a QNonContiguousByteDevice out of a QIODevice, return it in a std::shared_ptr. For QFile, QBuffer and all other QIODevice, sequential or not. \internal*/std::shared_ptr<QNonContiguousByteDevice>QNonContiguousByteDeviceFactory::createShared(QIODevice *device){// shortcut if it is a QBufferif(QBuffer *buffer = qobject_cast<QBuffer*>(device))returnstd::make_shared<QNonContiguousByteDeviceByteArrayImpl>(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 QIODevicereturnstd::make_shared<QNonContiguousByteDeviceIoDeviceImpl>(device);// FIXME}/*! \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer) Create a QNonContiguousByteDevice out of a QRingBuffer. \internal*/ QNonContiguousByteDevice *QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer){return newQNonContiguousByteDeviceRingBufferImpl(std::move(ringBuffer));}/*! Create a QNonContiguousByteDevice out of a QRingBuffer, return it in a std::shared_ptr. \internal*/std::shared_ptr<QNonContiguousByteDevice>QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer){returnstd::make_shared<QNonContiguousByteDeviceRingBufferImpl>(std::move(ringBuffer));}/*! \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray) Create a QNonContiguousByteDevice out of a QByteArray. \internal*/ QNonContiguousByteDevice*QNonContiguousByteDeviceFactory::create(const QByteArray &byteArray){return newQNonContiguousByteDeviceByteArrayImpl(byteArray);}/*! Create a QNonContiguousByteDevice out of a QByteArray. \internal*/std::shared_ptr<QNonContiguousByteDevice>QNonContiguousByteDeviceFactory::createShared(const QByteArray &byteArray){returnstd::make_shared<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 backendreturn newQByteDeviceWrappingIoDevice(byteDevice);} QT_END_NAMESPACE #include"moc_qnoncontiguousbytedevice_p.cpp"
close