LCOV - code coverage report
Current view: top level - lang/qt/src - dataprovider.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 84 129 65.1 %
Date: 2018-11-15 08:49:49 Functions: 15 18 83.3 %

          Line data    Source code
       1             : /* dataprovider.cpp
       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
       5             : 
       6             :    This file is part of QGPGME.
       7             : 
       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.
      12             : 
      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.
      17             : 
      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. */
      22             : 
      23             : // -*- c++ -*-
      24             : 
      25             : #ifdef HAVE_CONFIG_H
      26             :  #include "config.h"
      27             : #endif
      28             : 
      29             : #include <dataprovider.h>
      30             : 
      31             : #include <error.h>
      32             : 
      33             : #include <QIODevice>
      34             : #include <QProcess>
      35             : 
      36             : #include <cstdio>
      37             : #include <cstring>
      38             : #include <cassert>
      39             : 
      40             : using namespace QGpgME;
      41             : using namespace GpgME;
      42             : 
      43             : //
      44             : //
      45             : // QByteArrayDataProvider
      46             : //
      47             : //
      48             : 
      49          59 : static bool resizeAndInit(QByteArray &ba, size_t newSize)
      50             : {
      51          59 :     const size_t oldSize = ba.size();
      52          59 :     ba.resize(newSize);
      53          59 :     const bool ok = (newSize == static_cast<size_t>(ba.size()));
      54          59 :     if (ok) {
      55          59 :         memset(ba.data() + oldSize, 0, newSize - oldSize);
      56             :     }
      57          59 :     return ok;
      58             : }
      59             : 
      60          57 : QByteArrayDataProvider::QByteArrayDataProvider()
      61          57 :     : GpgME::DataProvider(), mOff(0) {}
      62             : 
      63           4 : QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
      64           4 :     : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
      65             : 
      66          61 : QByteArrayDataProvider::~QByteArrayDataProvider() {}
      67             : 
      68          11 : ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
      69             : {
      70             : #ifndef NDEBUG
      71             :     //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
      72             : #endif
      73          11 :     if (bufSize == 0) {
      74           0 :         return 0;
      75             :     }
      76          11 :     if (!buffer) {
      77           0 :         Error::setSystemError(GPG_ERR_EINVAL);
      78           0 :         return -1;
      79             :     }
      80          11 :     if (mOff >= mArray.size()) {
      81           5 :         return 0; // EOF
      82             :     }
      83           6 :     size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
      84           6 :     assert(amount > 0);
      85           6 :     memcpy(buffer, mArray.data() + mOff, amount);
      86           6 :     mOff += amount;
      87           6 :     return amount;
      88             : }
      89             : 
      90          59 : ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
      91             : {
      92             : #ifndef NDEBUG
      93             :     //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
      94             : #endif
      95          59 :     if (bufSize == 0) {
      96           0 :         return 0;
      97             :     }
      98          59 :     if (!buffer) {
      99           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     100           0 :         return -1;
     101             :     }
     102          59 :     if (mOff >= mArray.size()) {
     103          59 :         resizeAndInit(mArray, mOff + bufSize);
     104             :     }
     105          59 :     if (mOff >= mArray.size()) {
     106           0 :         Error::setSystemError(GPG_ERR_EIO);
     107           0 :         return -1;
     108             :     }
     109          59 :     assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
     110          59 :     memcpy(mArray.data() + mOff, buffer, bufSize);
     111          59 :     mOff += bufSize;
     112          59 :     return bufSize;
     113             : }
     114             : 
     115         151 : off_t QByteArrayDataProvider::seek(off_t offset, int whence)
     116             : {
     117             : #ifndef NDEBUG
     118             :     //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
     119             : #endif
     120         151 :     int newOffset = mOff;
     121         151 :     switch (whence) {
     122             :     case SEEK_SET:
     123          90 :         newOffset = offset;
     124          90 :         break;
     125             :     case SEEK_CUR:
     126           0 :         newOffset += offset;
     127           0 :         break;
     128             :     case SEEK_END:
     129          61 :         newOffset = mArray.size() + offset;
     130          61 :         break;
     131             :     default:
     132           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     133           0 :         return (off_t) - 1;
     134             :     }
     135         151 :     return mOff = newOffset;
     136             : }
     137             : 
     138          61 : void QByteArrayDataProvider::release()
     139             : {
     140             : #ifndef NDEBUG
     141             :     //qDebug( "QByteArrayDataProvider::release()" );
     142             : #endif
     143          61 :     mArray = QByteArray();
     144          61 : }
     145             : 
     146             : //
     147             : //
     148             : // QIODeviceDataProvider
     149             : //
     150             : //
     151             : 
     152          27 : QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
     153             :     : GpgME::DataProvider(),
     154             :       mIO(io),
     155             :       mErrorOccurred(false),
     156          27 :       mHaveQProcess(qobject_cast<QProcess *>(io.get()))
     157             : {
     158          27 :     assert(mIO);
     159          27 : }
     160             : 
     161          27 : QIODeviceDataProvider::~QIODeviceDataProvider() {}
     162             : 
     163         135 : bool QIODeviceDataProvider::isSupported(Operation op) const
     164             : {
     165         135 :     const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
     166         135 :     bool canRead = true;
     167         135 :     if (proc) {
     168           0 :         canRead = proc->readChannel() == QProcess::StandardOutput;
     169             :     }
     170             : 
     171         135 :     switch (op) {
     172          27 :     case Read:    return mIO->isReadable() && canRead;
     173          27 :     case Write:   return mIO->isWritable();
     174          54 :     case Seek:    return !mIO->isSequential();
     175          27 :     case Release: return true;
     176           0 :     default:      return false;
     177             :     }
     178             : }
     179             : 
     180           0 : static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
     181             : {
     182           0 :     while (!io->bytesAvailable()) {
     183           0 :         if (!io->waitForReadyRead(-1)) {
     184           0 :             if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
     185           0 :                 if (p->error() == QProcess::UnknownError &&
     186           0 :                         p->exitStatus() == QProcess::NormalExit &&
     187           0 :                         p->exitCode() == 0) {
     188           0 :                     if (io->atEnd()) {
     189             :                         // EOF
     190           0 :                         return 0;
     191             :                     } // continue reading even if process ended to ensure
     192             :                       // everything is read.
     193             :                 } else {
     194           0 :                     Error::setSystemError(GPG_ERR_EIO);
     195           0 :                     return -1;
     196             :                 }
     197             :             } else {
     198           0 :                 return 0; // assume EOF (loses error cases :/ )
     199             :             }
     200             :         }
     201             :     }
     202           0 :     return io->read(buffer, maxSize);
     203             : }
     204             : 
     205         307 : ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
     206             : {
     207             : #ifndef NDEBUG
     208             :     //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
     209             : #endif
     210         307 :     if (bufSize == 0) {
     211           0 :         return 0;
     212             :     }
     213         307 :     if (!buffer) {
     214           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     215           0 :         return -1;
     216             :     }
     217         307 :     const qint64 numRead = mHaveQProcess
     218         614 :                            ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
     219         614 :                            : mIO->read(static_cast<char *>(buffer), bufSize);
     220             : 
     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
     223             : 
     224         307 :     ssize_t rc = numRead;
     225         307 :     if (numRead < 0 && !Error::hasSystemError()) {
     226           0 :         if (mErrorOccurred) {
     227           0 :             Error::setSystemError(GPG_ERR_EIO);
     228             :         } else {
     229           0 :             rc = 0;
     230             :         }
     231             :     }
     232         307 :     if (numRead < 0) {
     233           0 :         mErrorOccurred = true;
     234             :     }
     235         307 :     return rc;
     236             : }
     237             : 
     238           2 : ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
     239             : {
     240             : #ifndef NDEBUG
     241             :     //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
     242             : #endif
     243           2 :     if (bufSize == 0) {
     244           0 :         return 0;
     245             :     }
     246           2 :     if (!buffer) {
     247           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     248           0 :         return -1;
     249             :     }
     250             : 
     251           2 :     return mIO->write(static_cast<const char *>(buffer), bufSize);
     252             : }
     253             : 
     254          54 : off_t QIODeviceDataProvider::seek(off_t offset, int whence)
     255             : {
     256             : #ifndef NDEBUG
     257             :     //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
     258             : #endif
     259          54 :     if (mIO->isSequential()) {
     260           0 :         Error::setSystemError(GPG_ERR_ESPIPE);
     261           0 :         return (off_t) - 1;
     262             :     }
     263          54 :     qint64 newOffset = mIO->pos();
     264          54 :     switch (whence) {
     265             :     case SEEK_SET:
     266          27 :         newOffset = offset;
     267          27 :         break;
     268             :     case SEEK_CUR:
     269           0 :         newOffset += offset;
     270           0 :         break;
     271             :     case SEEK_END:
     272          27 :         newOffset = mIO->size() + offset;
     273          27 :         break;
     274             :     default:
     275           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     276           0 :         return (off_t) - 1;
     277             :     }
     278          54 :     if (!mIO->seek(newOffset)) {
     279           0 :         Error::setSystemError(GPG_ERR_EINVAL);
     280           0 :         return (off_t) - 1;
     281             :     }
     282          54 :     return newOffset;
     283             : }
     284             : 
     285          27 : void QIODeviceDataProvider::release()
     286             : {
     287             : #ifndef NDEBUG
     288             :     //qDebug( "QIODeviceDataProvider::release()" );
     289             : #endif
     290          27 :     mIO->close();
     291          27 : }

Generated by: LCOV version 1.13