2 Copyright (C) 2004 Klarävdalens Datakonsult AB
3 Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
4 Software engineering by Intevation GmbH
6 This file is part of QGPGME.
8 QGPGME is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Library General Public License as published
10 by the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 QGPGME is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with QGPGME; see the file COPYING.LIB. If not, write to the
20 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
29 #include <dataprovider.h>
40 using namespace QGpgME;
41 using namespace GpgME;
45 // QByteArrayDataProvider
49 static bool resizeAndInit(QByteArray &ba, size_t newSize)
51 const size_t oldSize = ba.size();
53 const bool ok = (newSize == static_cast<size_t>(ba.size()));
55 memset(ba.data() + oldSize, 0, newSize - oldSize);
60 QByteArrayDataProvider::QByteArrayDataProvider()
61 : GpgME::DataProvider(), mOff(0) {}
63 QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
64 : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
66 QByteArrayDataProvider::~QByteArrayDataProvider() {}
68 ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
71 //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
77 Error::setSystemError(GPG_ERR_EINVAL);
80 if (mOff >= mArray.size()) {
83 size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
85 memcpy(buffer, mArray.data() + mOff, amount);
90 ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
93 //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
99 Error::setSystemError(GPG_ERR_EINVAL);
102 if (mOff >= mArray.size()) {
103 resizeAndInit(mArray, mOff + bufSize);
105 if (mOff >= mArray.size()) {
106 Error::setSystemError(GPG_ERR_EIO);
109 assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
110 memcpy(mArray.data() + mOff, buffer, bufSize);
115 off_t QByteArrayDataProvider::seek(off_t offset, int whence)
118 //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
120 int newOffset = mOff;
129 newOffset = mArray.size() + offset;
132 Error::setSystemError(GPG_ERR_EINVAL);
135 return mOff = newOffset;
138 void QByteArrayDataProvider::release()
141 //qDebug( "QByteArrayDataProvider::release()" );
143 mArray = QByteArray();
148 // QIODeviceDataProvider
152 QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
153 : GpgME::DataProvider(),
155 mErrorOccurred(false),
156 mHaveQProcess(qobject_cast<QProcess *>(io.get()))
161 QIODeviceDataProvider::~QIODeviceDataProvider() {}
163 bool QIODeviceDataProvider::isSupported(Operation op) const
165 const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
168 canRead = proc->readChannel() == QProcess::StandardOutput;
172 case Read: return mIO->isReadable() && canRead;
173 case Write: return mIO->isWritable();
174 case Seek: return !mIO->isSequential();
175 case Release: return true;
176 default: return false;
180 static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
182 while (!io->bytesAvailable()) {
183 if (!io->waitForReadyRead(-1)) {
184 if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
185 if (p->error() == QProcess::UnknownError &&
186 p->exitStatus() == QProcess::NormalExit &&
187 p->exitCode() == 0) {
191 } // continue reading even if process ended to ensure
192 // everything is read.
194 Error::setSystemError(GPG_ERR_EIO);
198 return 0; // assume EOF (loses error cases :/ )
202 return io->read(buffer, maxSize);
205 ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
208 //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
214 Error::setSystemError(GPG_ERR_EINVAL);
217 const qint64 numRead = mHaveQProcess
218 ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
219 : mIO->read(static_cast<char *>(buffer), bufSize);
221 //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no
222 //errno is set, gpgme doesn't detect the error and loops forever. So return 0 on the very first -1 in case errno is 0
224 ssize_t rc = numRead;
225 if (numRead < 0 && !Error::hasSystemError()) {
226 if (mErrorOccurred) {
227 Error::setSystemError(GPG_ERR_EIO);
233 mErrorOccurred = true;
238 ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
241 //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
247 Error::setSystemError(GPG_ERR_EINVAL);
251 return mIO->write(static_cast<const char *>(buffer), bufSize);
254 off_t QIODeviceDataProvider::seek(off_t offset, int whence)
257 //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
259 if (mIO->isSequential()) {
260 Error::setSystemError(GPG_ERR_ESPIPE);
263 qint64 newOffset = mIO->pos();
272 newOffset = mIO->size() + offset;
275 Error::setSystemError(GPG_ERR_EINVAL);
278 if (!mIO->seek(newOffset)) {
279 Error::setSystemError(GPG_ERR_EINVAL);
285 void QIODeviceDataProvider::release()
288 //qDebug( "QIODeviceDataProvider::release()" );