libzypp  17.34.1
iodevice.cc
Go to the documentation of this file.
1 #include "private/iodevice_p.h"
2 
3 namespace zyppng {
4 
6  { }
7 
9 
10  IODevice::IODevice() : Base( *( new IODevicePrivate(*this)) )
11  { }
12 
14  { }
15 
16  bool IODevice::open( const OpenMode mode )
17  {
18  Z_D();
19 
20  d->_mode = mode;
21  d->_readChannels.clear();
22  if ( canRead() ) {
23  d->_readChannels.push_back( IOBuffer( d->_readBufChunkSize ) );
24  setReadChannel( 0 );
25  }
26 
27  return true;
28  }
29 
31  {
32  Z_D();
33  d->_mode = IODevice::Closed;
34  d->_readChannels.clear();
35  }
36 
37  void IODevice::setReadChannelCount ( uint channels ) {
38  Z_D();
39  if ( canRead() ) {
40  d->_readChannels.resize( channels );
41  }
42  }
43 
44  void IODevice::setReadChannel ( uint channel )
45  {
46  Z_D();
47  if ( !canRead() )
48  return;
49  if ( channel >= d->_readChannels.size() ) {
50  ERR << constants::outOfRangeErrMsg << std::endl;
51  throw std::out_of_range( constants::outOfRangeErrMsg.data() );
52  }
53  d->_currentReadChannel = channel;
54  readChannelChanged( channel );
55  }
56 
58  {
59  Z_D();
60  if ( !canRead() )
61  return 0;
62  return d->_currentReadChannel;
63  }
64 
66  {
67  Z_D();
68  if ( !canRead() )
69  return 0;
70  return d->_readChannels.size();
71  }
72 
73  bool IODevice::canRead() const
74  {
75  return ( d_func()->_mode & IODevice::ReadOnly );
76  }
77 
78  bool IODevice::canWrite() const
79  {
80  return ( d_func()->_mode & IODevice::WriteOnly );
81  }
82 
83  bool IODevice::isOpen() const
84  {
85  return d_func()->_mode != IODevice::Closed;
86  }
87 
88  bool IODevice::canReadLine() const
89  {
90  Z_D();
91  if ( !canRead() )
92  return false;
93 
94  return canReadLine( d->_currentReadChannel );
95  }
96 
97  int64_t IODevice::bytesAvailable() const
98  {
99  Z_D();
100  return bytesAvailable( d->_currentReadChannel );
101  }
102 
104  {
105  Z_D();
106  return readAll( d->_currentReadChannel );
107  }
108 
109  ByteArray IODevice::read( int64_t maxSize )
110  {
111  if ( !canRead() || maxSize <= 0 )
112  return {};
113  return read( d_func()->_currentReadChannel, maxSize );
114  }
115 
116  int64_t IODevice::read(char *buf, int64_t maxSize )
117  {
118  Z_D();
119  if ( !canRead() )
120  return -1;
121  return read( d->_currentReadChannel, buf, maxSize );
122  }
123 
124  ByteArray IODevice::readLine( const int64_t maxSize )
125  {
126  if ( !canRead() )
127  return {};
128 
129  return channelReadLine( d_func()->_currentReadChannel, maxSize );
130  }
131 
132  ByteArray IODevice::readAll( uint channel )
133  {
134  return read( channel, bytesAvailable( channel ) );
135  }
136 
137  ByteArray IODevice::read( uint channel, int64_t maxSize )
138  {
139  if ( !canRead() || maxSize <= 0 )
140  return {};
141 
142  ByteArray res( maxSize, '\0' );
143  const auto r = read( channel, res.data(), maxSize );
144  res.resize( r );
145  return res;
146  }
147 
148  int64_t IODevice::read( uint channel, char *buf, int64_t maxSize )
149  {
150  Z_D();
151  if ( !canRead() || maxSize < 0 )
152  return -1;
153 
154  if ( channel >= d->_readChannels.size() ) {
155  ERR << constants::outOfRangeErrMsg << std::endl;
156  throw std::out_of_range( constants::outOfRangeErrMsg.data() );
157  }
158 
159  int64_t readSoFar = d->_readChannels[ channel ].read( buf, maxSize );
160 
161  // try to read more from the device
162  if ( readSoFar < maxSize ) {
163  int64_t readFromDev = readData( channel, buf+readSoFar, maxSize - readSoFar );
164  if ( readFromDev > 0 )
165  return readSoFar + readFromDev;
166  }
167  return readSoFar;
168  }
169 
170  ByteArray IODevice::channelReadLine( uint channel, int64_t maxSize )
171  {
172  Z_D();
173  if ( !canRead() || maxSize < 0 )
174  return {};
175 
176  if ( channel >= d->_readChannels.size() ) {
177  ERR << constants::outOfRangeErrMsg << std::endl;
178  throw std::out_of_range( constants::outOfRangeErrMsg.data() );
179  }
180 
181  ByteArray result;
182  // largest possible ByteArray in int64_t boundaries
183  const auto maxBArrSize = int64_t( std::min( ByteArray::maxSize(), std::size_t(std::numeric_limits<int64_t>::max()) ) );
184  if ( maxSize > maxBArrSize ) {
185  ERR << "Calling channelReadLine with maxSize > int64_t(ByteArray::maxSize) " << std::endl;
186  maxSize = maxBArrSize - 1;
187  }
188 
189  // how much did we read?
190  int64_t readSoFar = 0;
191 
192  // if we have no size or the size is really big we read incrementally, use the buffer chunk size
193  // to read full chunks from the buffer if possible
194  if ( maxSize == 0 || maxSize >= (maxBArrSize - 1) ) {
195 
196  // largest possible ByteArray
197  maxSize = maxBArrSize;
198 
199  // we need to read in chunks until we get a \n
200  int64_t lastReadSize = 0;
201  result.resize (1); // leave room for \0
202  do {
203  result.resize( std::min( std::size_t(maxSize), std::size_t(result.size() + d->_readBufChunkSize )) );
204  lastReadSize = channelReadLine( channel, result.data() + readSoFar, result.size() - readSoFar );
205  if ( lastReadSize > 0)
206  readSoFar += lastReadSize;
207 
208  // check for equal _readBufSize,
209  // our readData request is always 1 byte bigger than the _readBufChunkSize because of the initial byte we allocated in the result buffer,
210  // so the \0 that is appended by readLine does not make a difference.
211  } while( lastReadSize == d->_readBufChunkSize
212  && result[readSoFar-1] != '\n' );
213 
214  } else {
215  result.resize( maxSize );
216  readSoFar = channelReadLine( channel, result.data(), result.size() );
217  }
218 
219  if ( readSoFar > 0 ) {
220  // we do not need to keep the \0 in the ByteArray
221  result.resize( readSoFar );
222  } else {
223  result.clear ();
224  }
225 
226  // make sure we do not waste memory
227  result.shrink_to_fit();
228 
229  return result;
230  }
231 
232  int64_t IODevice::channelReadLine( uint channel, char *buf, const int64_t maxSize )
233  {
234  Z_D();
235 
236  if ( !canRead() || maxSize < 0 )
237  return -1;
238 
239  if ( channel >= d->_readChannels.size() ) {
240  ERR << constants::outOfRangeErrMsg << std::endl;
241  throw std::out_of_range( constants::outOfRangeErrMsg.data() );
242  }
243 
244  if ( maxSize < 2 ) {
245  ERR << "channelReadLine needs at least a buffsize of 2" << std::endl;
246  return -1;
247  }
248 
249  int64_t toRead = maxSize - 1; // append \0 at the end
250  int64_t readSoFar = 0;
251  if ( d->_readChannels[channel].size () > 0 )
252  readSoFar = d->_readChannels[channel].readLine( buf, toRead + 1 /*IOBuffer appends \0*/ );
253 
254  if ( readSoFar == toRead || ( readSoFar > 0 && buf[readSoFar-1] == '\n' ) ) {
255  buf[readSoFar] = '\0';
256  return readSoFar;
257  }
258 
259  bool hasError = false;
260  // if we reach here, the buffer was either empty, or does not contain a \n, in both cases we need to
261  // read from the device directly until we hit a ending condition
262  while ( readSoFar < toRead ) {
263  const auto r = readData( channel, buf+readSoFar, 1 );
264  if ( r == 0 ) {
265  // no data available to be read -> EOF, or data stream empty
266  break;
267  }
268  else if ( r < 0 ) {
269  hasError = true;
270  break;
271  }
272  readSoFar+=r;
273 
274  if ( buf[readSoFar-1] == '\n' )
275  break;
276  }
277 
278  if ( readSoFar == 0 )
279  return hasError ? -1 : 0;
280 
281  buf[readSoFar] = '\0';
282  return readSoFar;
283  }
284 
285  int64_t IODevice::bytesAvailable ( uint channel ) const
286  {
287  Z_D();
288  if ( !canRead() )
289  return 0;
290  return d->_readChannels[channel].size() + rawBytesAvailable( channel );
291  }
292 
293  bool IODevice::canReadLine ( uint channel ) const
294  {
295  Z_D();
296  if ( !canRead() || channel >= d->_readChannels.size() )
297  return false;
298  return d->_readChannels[channel].canReadLine();
299  }
300 
302  {
303  if ( !canWrite() )
304  return 0;
305  return write( data.data(), data.size() );
306  }
307 
308  int64_t IODevice::write( const char *data, int64_t len)
309  {
310  if ( !canWrite() || len <= 0 )
311  return 0;
312  return writeData( data, len );
313  }
314 
315  bool IODevice::waitForReadyRead( int timeout)
316  {
317  Z_D();
318  if ( !canRead() )
319  return false;
320 
321  return waitForReadyRead( d->_currentReadChannel, timeout );
322  }
323 
325  {
326  return d_func()->_readyRead;
327  }
328 
330  {
331  return d_func()->_channelReadyRead;
332  }
333 
335  {
336  return d_func()->_sigBytesWritten;
337  }
338 
340  {
341  return d_func()->_sigAllBytesWritten;
342  }
343 }
344 
bool canReadLine() const
Definition: iodevice.cc:88
virtual int64_t rawBytesAvailable(uint channel) const =0
uint currentReadChannel() const
Definition: iodevice.cc:57
bool canRead() const
Definition: iodevice.cc:73
SignalProxy< void(int64_t)> sigBytesWritten()
Definition: iodevice.cc:334
int readChannelCount() const
Definition: iodevice.cc:65
virtual bool open(const OpenMode mode)
Definition: iodevice.cc:16
void setReadChannelCount(uint channels)
Definition: iodevice.cc:37
IODevicePrivate(IODevice &p)
Definition: iodevice.cc:5
ByteArray readAll()
Definition: iodevice.cc:103
void setReadChannel(uint channel)
Definition: iodevice.cc:44
ByteArray channelReadLine(uint channel, int64_t maxSize=0)
Definition: iodevice.cc:170
bool isOpen() const
Definition: iodevice.cc:83
#define ERR
Definition: Logger.h:100
#define Z_D()
Definition: zyppglobal.h:104
static std::size_t maxSize()
Definition: ByteArray.h:37
virtual int64_t writeData(const char *data, int64_t count)=0
virtual void readChannelChanged(uint channel)=0
int64_t write(const ByteArray &data)
Definition: iodevice.cc:301
ByteArray read(int64_t maxSize)
Definition: iodevice.cc:109
constexpr std::string_view outOfRangeErrMsg("Channel index out of range")
SignalProxy< void(uint)> sigChannelReadyRead()
Definition: iodevice.cc:329
SignalProxy< void()> sigReadyRead()
Definition: iodevice.cc:324
SignalProxy< void()> sigAllBytesWritten()
Definition: iodevice.cc:339
ZYPP_IMPL_PRIVATE(UnixSignalSource)
virtual int64_t bytesAvailable() const
Definition: iodevice.cc:97
virtual ByteArray readLine(const int64_t maxSize=0)
Definition: iodevice.cc:124
virtual void close()
Definition: iodevice.cc:30
bool write(const Pathname &path_r, const std::string &key_r, const std::string &val_r, const std::string &newcomment_r)
Add or change a value in sysconfig file path_r.
Definition: sysconfig.cc:80
virtual int64_t readData(uint channel, char *buffer, int64_t bufsize)=0
bool canWrite() const
Definition: iodevice.cc:78
bool waitForReadyRead(int timeout)
Definition: iodevice.cc:315