From 369be99d82a7c1182e3693756ab545cea86bb90d Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 8 Sep 2022 14:52:19 +0200 Subject: webp: support sequential input device if full file is available Since we do no random access during decoding, just a readAll() of the whole image file. So if it is all available already, we can handle a sequential device. That is useful for Quick AnimationImage, which will pass a finished QNetworkReply as the input device. This commit removes some seek() calls in the header checking, that supposedly should reset the device position. These were in practice either no-ops or bugs, since the device is only being peeked, so the position never changes in the first place, and a QImageIOHandler is supposed to read from the device at the position it is at when passed. Fixes: QTBUG-70245 Change-Id: I5a4ff5fa4bbd19b0545ad41645969d714b4dc7d5 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Shawn Rutledge --- src/plugins/imageformats/webp/qwebphandler.cpp | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 59513f6..922868c 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -9,6 +9,7 @@ #include #include #include +#include static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h @@ -66,21 +67,23 @@ bool QWebpHandler::ensureScanned() const m_scanState = ScanError; - if (device()->isSequential()) { - qWarning() << "Sequential devices are not supported"; + QWebpHandler *that = const_cast(this); + const int headerBytesNeeded = sizeof(WebPBitstreamFeatures); + QByteArray header = device()->peek(headerBytesNeeded); + if (header.size() < headerBytesNeeded) return false; - } - qint64 oldPos = device()->pos(); - device()->seek(0); - - QWebpHandler *that = const_cast(this); - QByteArray header = device()->peek(sizeof(WebPBitstreamFeatures)); + // We do no random access during decoding, just a readAll() of the whole image file. So if + // if it is all available already, we can accept a sequential device. The riff header contains + // the file size minus 8 bytes header + qint64 byteSize = qFromLittleEndian(header.constData() + 4); + if (device()->isSequential() && device()->bytesAvailable() < byteSize + 8) { + qWarning() << "QWebpHandler: Insufficient data available in sequential device"; + return false; + } if (WebPGetFeatures((const uint8_t*)header.constData(), header.size(), &(that->m_features)) == VP8_STATUS_OK) { if (m_features.has_animation) { // For animation, we have to read and scan whole file to determine loop count and images count - device()->seek(oldPos); - if (that->ensureDemuxer()) { that->m_loop = WebPDemuxGetI(m_demuxer, WEBP_FF_LOOP_COUNT); that->m_frameCount = WebPDemuxGetI(m_demuxer, WEBP_FF_FRAME_COUNT); @@ -93,17 +96,13 @@ bool QWebpHandler::ensureScanned() const if (that->m_features.has_alpha) that->m_composited->fill(Qt::transparent); - // We do not reset device position since we have read in all data m_scanState = ScanSuccess; - return true; } } else { m_scanState = ScanSuccess; } } - device()->seek(oldPos); - return m_scanState == ScanSuccess; } @@ -126,7 +125,7 @@ bool QWebpHandler::ensureDemuxer() bool QWebpHandler::read(QImage *image) { - if (!ensureScanned() || device()->isSequential() || !ensureDemuxer()) + if (!ensureScanned() || !ensureDemuxer()) return false; QRect prevFrameRect; -- cgit v1.2.1