1 /*
2     SPDX-FileCopyrightText: 2006-2009 Sebastian Trueg <trueg@k3b.org>
3     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "k3bactivepipe.h"
9 
10 #include <QDebug>
11 #include <QIODevice>
12 #include <QThread>
13 
14 
15 class K3b::ActivePipe::Private : public QThread
16 {
17 public:
Private(K3b::ActivePipe * pipe)18     Private( K3b::ActivePipe* pipe ) :
19         m_pipe( pipe ),
20         sourceIODevice(0),
21         sinkIODevice(0),
22         closeSinkIODevice( false ),
23         closeSourceIODevice( false ) {
24     }
25 
run()26     void run() override {
27         qDebug() << "(K3b::ActivePipe) writing from" << sourceIODevice << "to" << sinkIODevice;
28 
29         bytesRead = bytesWritten = 0;
30         buffer.resize( 10*2048 );
31 
32         bool fail = false;
33         qint64 r = 0;
34         while( !fail && ( r = m_pipe->readData( buffer.data(), buffer.size() ) ) > 0 ) {
35             bytesRead += r;
36 
37             ssize_t w = 0;
38             ssize_t ww = 0;
39             while( w < r ) {
40                 if( ( ww = m_pipe->write( buffer.data()+w, r-w ) ) > 0 ) {
41                     w += ww;
42                     bytesWritten += ww;
43                 }
44                 else {
45                     qDebug() << "write failed." << sinkIODevice->errorString();
46                     fail = true;
47                     break;
48                 }
49             }
50         }
51 
52         if ( r < 0 ) {
53             qDebug() << "Read failed:" << sourceIODevice->errorString();
54         }
55 
56         qDebug() << "Done:"
57                  << ( fail ? QLatin1String( "write failed" ) : QLatin1String( "write success" ) )
58                  << ( r != 0 ? QLatin1String( "read failed" ) : QLatin1String( "read success" ) )
59                  << "(total bytes read/written:" << bytesRead << "/" << bytesWritten << ")";
60     }
61 
_k3b_close()62     void _k3b_close() {
63         qDebug();
64         if ( closeWhenDone )
65             m_pipe->close();
66     }
67 
68 private:
69     K3b::ActivePipe* m_pipe;
70 
71 public:
72     QIODevice* sourceIODevice;
73     QIODevice* sinkIODevice;
74 
75     bool closeWhenDone;
76     bool closeSinkIODevice;
77     bool closeSourceIODevice;
78 
79     QByteArray buffer;
80 
81     quint64 bytesRead;
82     quint64 bytesWritten;
83 };
84 
85 
ActivePipe()86 K3b::ActivePipe::ActivePipe()
87 {
88     d = new Private( this );
89     connect( d, SIGNAL(finished()), this, SLOT(_k3b_close()) );
90 }
91 
92 
~ActivePipe()93 K3b::ActivePipe::~ActivePipe()
94 {
95     delete d;
96 }
97 
98 
open(OpenMode mode)99 bool K3b::ActivePipe::open( OpenMode mode )
100 {
101     return QIODevice::open( mode );
102 }
103 
104 
open(bool closeWhenDone)105 bool K3b::ActivePipe::open( bool closeWhenDone )
106 {
107     if( d->isRunning() )
108         return false;
109 
110     QIODevice::open( ReadWrite|Unbuffered );
111 
112     d->closeWhenDone = closeWhenDone;
113 
114     if( d->sourceIODevice && !d->sourceIODevice->isOpen() ) {
115         qDebug() << "Need to open source device:" << d->sourceIODevice;
116         if( !d->sourceIODevice->open( QIODevice::ReadOnly ) )
117             return false;
118     }
119 
120     if( d->sinkIODevice && !d->sinkIODevice->isOpen()  ) {
121         qDebug() << "Need to open sink device:" << d->sinkIODevice;
122         if( !d->sinkIODevice->open( QIODevice::WriteOnly ) )
123             return false;
124     }
125 
126     qDebug() << "(K3b::ActivePipe) successfully opened pipe.";
127 
128     // we only do active piping if both devices are set.
129     // Otherwise we only work as a conduit
130     if ( d->sourceIODevice && d->sinkIODevice ) {
131         d->start();
132     }
133 
134     return true;
135 }
136 
137 
close()138 void K3b::ActivePipe::close()
139 {
140     qDebug();
141     if( d->sourceIODevice && d->closeSourceIODevice )
142         d->sourceIODevice->close();
143     if( d->sinkIODevice && d->closeSinkIODevice )
144         d->sinkIODevice->close();
145     d->wait();
146 }
147 
148 
readFrom(QIODevice * dev,bool close)149 void K3b::ActivePipe::readFrom( QIODevice* dev, bool close )
150 {
151     d->sourceIODevice = dev;
152     d->closeSourceIODevice = close;
153 }
154 
155 
writeTo(QIODevice * dev,bool close)156 void K3b::ActivePipe::writeTo( QIODevice* dev, bool close )
157 {
158     d->sinkIODevice = dev;
159     d->closeSinkIODevice = close;
160 }
161 
162 
readData(char * data,qint64 max)163 qint64 K3b::ActivePipe::readData( char* data, qint64 max )
164 {
165     if( d->sourceIODevice ) {
166         return d->sourceIODevice->read( data, max );
167     }
168 
169     return -1;
170 }
171 
172 
writeData(const char * data,qint64 max)173 qint64 K3b::ActivePipe::writeData( const char* data, qint64 max )
174 {
175     if( d->sinkIODevice ) {
176         return d->sinkIODevice->write( data, max );
177     }
178     else
179         return -1;
180 }
181 
182 
bytesRead() const183 quint64 K3b::ActivePipe::bytesRead() const
184 {
185     return d->bytesRead;
186 }
187 
188 
bytesWritten() const189 quint64 K3b::ActivePipe::bytesWritten() const
190 {
191     return d->bytesWritten;
192 }
193 
194 #include "moc_k3bactivepipe.cpp"
195