summaryrefslogtreecommitdiff
path: root/lang/qt/src/dataprovider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lang/qt/src/dataprovider.cpp')
-rw-r--r--lang/qt/src/dataprovider.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/lang/qt/src/dataprovider.cpp b/lang/qt/src/dataprovider.cpp
new file mode 100644
index 0000000..533b67d
--- /dev/null
+++ b/lang/qt/src/dataprovider.cpp
@@ -0,0 +1,282 @@
+/* dataprovider.cpp
+ Copyright (C) 2004 Klar�vdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ This file is part of QGPGME.
+
+ QGPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ QGPGME is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with QGPGME; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+// -*- c++ -*-
+
+#include <dataprovider.h>
+
+#include <error.h>
+
+#include <QIODevice>
+#include <QProcess>
+
+#include <cstdio>
+#include <cstring>
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+//
+//
+// QByteArrayDataProvider
+//
+//
+
+static bool resizeAndInit(QByteArray &ba, size_t newSize)
+{
+ const size_t oldSize = ba.size();
+ ba.resize(newSize);
+ const bool ok = (newSize == static_cast<size_t>(ba.size()));
+ if (ok) {
+ memset(ba.data() + oldSize, 0, newSize - oldSize);
+ }
+ return ok;
+}
+
+QByteArrayDataProvider::QByteArrayDataProvider()
+ : GpgME::DataProvider(), mOff(0) {}
+
+QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
+ : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
+
+QByteArrayDataProvider::~QByteArrayDataProvider() {}
+
+ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ if (mOff >= mArray.size()) {
+ return 0; // EOF
+ }
+ size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
+ assert(amount > 0);
+ memcpy(buffer, mArray.data() + mOff, amount);
+ mOff += amount;
+ return amount;
+}
+
+ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ if (mOff >= mArray.size()) {
+ resizeAndInit(mArray, mOff + bufSize);
+ }
+ if (mOff >= mArray.size()) {
+ Error::setSystemError(GPG_ERR_EIO);
+ return -1;
+ }
+ assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
+ memcpy(mArray.data() + mOff, buffer, bufSize);
+ mOff += bufSize;
+ return bufSize;
+}
+
+off_t QByteArrayDataProvider::seek(off_t offset, int whence)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
+#endif
+ int newOffset = mOff;
+ switch (whence) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset += offset;
+ break;
+ case SEEK_END:
+ newOffset = mArray.size() + offset;
+ break;
+ default:
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ return mOff = newOffset;
+}
+
+void QByteArrayDataProvider::release()
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::release()" );
+#endif
+ mArray = QByteArray();
+}
+
+//
+//
+// QIODeviceDataProvider
+//
+//
+
+QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
+ : GpgME::DataProvider(),
+ mIO(io),
+ mErrorOccurred(false),
+ mHaveQProcess(qobject_cast<QProcess *>(io.get()))
+{
+ assert(mIO);
+}
+
+QIODeviceDataProvider::~QIODeviceDataProvider() {}
+
+bool QIODeviceDataProvider::isSupported(Operation op) const
+{
+ const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
+ bool canRead = true;
+ if (proc) {
+ canRead = proc->readChannel() == QProcess::StandardOutput;
+ }
+
+ switch (op) {
+ case Read: return mIO->isReadable() && canRead;
+ case Write: return mIO->isWritable();
+ case Seek: return !mIO->isSequential();
+ case Release: return true;
+ default: return false;
+ }
+}
+
+static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
+{
+ while (!io->bytesAvailable()) {
+ if (!io->waitForReadyRead(-1)) {
+ if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
+ if (p->error() == QProcess::UnknownError &&
+ p->exitStatus() == QProcess::NormalExit &&
+ p->exitCode() == 0) {
+ return 0;
+ } else {
+ Error::setSystemError(GPG_ERR_EIO);
+ return -1;
+ }
+ } else {
+ return 0; // assume EOF (loses error cases :/ )
+ }
+ }
+ }
+ return io->read(buffer, maxSize);
+}
+
+ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ const qint64 numRead = mHaveQProcess
+ ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
+ : mIO->read(static_cast<char *>(buffer), bufSize);
+
+ //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no
+ //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
+
+ ssize_t rc = numRead;
+ if (numRead < 0 && !Error::hasSystemError()) {
+ if (mErrorOccurred) {
+ Error::setSystemError(GPG_ERR_EIO);
+ } else {
+ rc = 0;
+ }
+ }
+ if (numRead < 0) {
+ mErrorOccurred = true;
+ }
+ return rc;
+}
+
+ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+
+ return mIO->write(static_cast<const char *>(buffer), bufSize);
+}
+
+off_t QIODeviceDataProvider::seek(off_t offset, int whence)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
+#endif
+ if (mIO->isSequential()) {
+ Error::setSystemError(GPG_ERR_ESPIPE);
+ return (off_t) - 1;
+ }
+ qint64 newOffset = mIO->pos();
+ switch (whence) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset += offset;
+ break;
+ case SEEK_END:
+ newOffset = mIO->size() + offset;
+ break;
+ default:
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ if (!mIO->seek(newOffset)) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ return newOffset;
+}
+
+void QIODeviceDataProvider::release()
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::release()" );
+#endif
+ mIO->close();
+}