summaryrefslogtreecommitdiffstats
path: root/kdecore/kbufferedio.h
blob: 47579738d470639c868db0fead7fe0e0b9746447 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*
 *  This file is part of the KDE libraries
 *  Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
 *
 *  This library 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.
 *
 *  This library 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 this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#ifndef KBUFFEREDIO_H
#define KBUFFEREDIO_H

#include <qcstring.h>
#include <qptrlist.h>
#include "kasyncio.h"

class KBufferedIOPrivate;
/**
 * This abstract class implements basic functionality for buffered
 * input/output.
 *
 * Through the available methods, you can find out how many bytes are
 * available for reading, how many are still unsent and you can peek at
 * the buffered data.
 *
 * This class was intentionally written to resemble QSocket, because
 * KExtendedSocket is a subclass of this one. This is so that applications
 * written using QSocket's buffering characteristics will be more easily
 * ported to the more powerful KExtendedSocket class.
 *
 * KBufferedIO already provides a powerful internal buffering algorithm. However,
 * this does not include the I/O itself, which must be implemented in
 * derived classes. Thus, to implement a class that does some I/O, you must
 * override, in addition to the pure virtual QIODevice methods, these two:
 * @li closeNow()
 * @li waitForMore()
 *
 * If your derived class reimplements the buffering algorithm, you must then
 * decide which buffering functions to override. For instance, you may want to
 * change the protected functions like feedReadBuffer() and consumeReadBuffer().
 *
 * @author Thiago Macieira <thiagom@mail.com>
 * @short Buffered I/O
 */
class KDECORE_EXPORT KBufferedIO: public KAsyncIO
{
  Q_OBJECT

protected:
  // no default public constructor
  KBufferedIO();

public:
  /**
   * The modes for closed() signal
   */
  enum closeModes
  {
    availRead = 0x01,
    dirtyWrite = 0x02,
    involuntary = 0x10,
    delayed = 0x20,
    closedNow = 0x40
  };

  /**
   * Destroys this class. The flushing of the buffers is implementation dependant.
   * The default implementation discards the contents
   */
  virtual ~KBufferedIO();

  /**
   * Closes the stream now, discarding the contents of the
   * write buffer. That is, we won't try to flush that
   * buffer before closing. If you want that buffer to be
   * flushed, you can call QIODevice::flush(), which is blocking, and
   * then closeNow, or you can call QIODevice::close() for a delayed
   * close.
   */
  virtual void closeNow() = 0;

  /**
   * Sets the internal buffer size to value.
   *
   * Not all implementations support this.
   *
   * The parameters may be 0 to make the class unbuffered or -1
   * to let the class choose the size (which may be unlimited) or
   * -2 to leave the buffer size untouched.
   *
   * Note that setting the write buffer size to any value smaller than
   * the current size of the buffer will force it to flush first,
   * which can make this call blocking.
   *
   * The default implementation does not support setting the buffer
   * sizes. You can only call this function with values -1 for "don't care"
   * or -2 for "unchanged"
   * @param rsize	the size of the read buffer
   * @param wsize	the size of the write buffer
   * @return true if setting both was ok. If false is returned, the
   * buffers were left unchanged.
   */
  virtual bool setBufferSize(int rsize, int wsize = -2);

  /**
   * Returns the number of bytes available for reading in the read buffer
   * @return the number of bytes available for reading
   */
  virtual int bytesAvailable() const;

  /**
   * Waits for more data to be available and returns the amount of available data then.
   * 
   * @param msec	number of milliseconds to wait, -1 to wait forever
   * @return -1 if we cannot wait (e.g., that doesn't make sense in this stream)
   */
  virtual int waitForMore(int msec) = 0;

  /**
   * Returns the number of bytes yet to write, still in the write buffer
   * @return the number of unwritten bytes in the write buffer
   */
  virtual int bytesToWrite() const;

  /**
   * Checks whether there is enough data in the buffer to read a line
   *
   * The default implementation reads directly from inBuf, so if your
   * implementation changes the meaning of that member, then you must override
   * this function.
   * @return true when there is enough data in the buffer to read a line
   */
  virtual bool canReadLine() const;

  // readBlock, peekBlock and writeBlock are not defined in this class (thus, left
  // pure virtual) because this does not mean only reading and writing
  // to the buffers. It may be necessary to do I/O to complete the
  // transaction (e.g., user wants to read more than is in the buffer).
  // Reading and writing to the buffer are available for access through
  // protected member functions

  /**
   * Reads into the user buffer at most maxlen bytes, but does not
   * consume that data from the read buffer. This is useful to check
   * whether we already have the needed data to process something.
   *
   * This function may want to try and read more data from the system
   * provided it won't block.
   *
   * @param data	the user buffer pointer, at least maxlen bytes long
   * @param maxlen	the maximum length to be peeked
   * @return the number of bytes actually copied.
   */
  virtual int peekBlock(char *data, uint maxlen) = 0;

  /**
   * Unreads some data. That is, write the data to the beginning of the
   * read buffer, so that next calls to readBlock or peekBlock will see
   * this data instead.
   *
   * Note not all devices implement this since this could mean a semantic
   * problem. For instance, sockets are sequential devices, so they won't
   * accept unreading.
   * @param data	the data to be unread
   * @param len	the size of the data
   * @return the number of bytes actually unread
   */
  virtual int unreadBlock(const char *data, uint len);

signals:
  /**
   * This signal gets sent whenever bytes are written from the buffer.
   * @param nbytes the number of bytes sent.
   */
  void bytesWritten(int nbytes);

  // There is no read signal here. We use the readyRead signal inherited
  // from KAsyncIO for that purpose

  /**
   * This signal gets sent when the stream is closed. The @p state parameter
   * will give the current state, in OR-ed bits:
   * @li availRead:	read buffer contains data to be read
   * @li dirtyWrite:	write buffer wasn't empty when the stream closed
   * @li involuntary:	the stream wasn't closed due to user request
   *			(i.e., call to close). Probably remote end closed it
   * @li delayed:	the stream was closed voluntarily by the user, but it
   *			happened only after the write buffer was emptied
   * @li closedNow:	the stream was closed voluntarily by the user, by
   *			explicitly calling closeNow, which means the
   *			write buffer's contents may have been discarded
   * @param state the state (see function description)
   */
  void closed(int state);

protected:
  /**
   * For an explanation on how this buffer work, please refer to the comments
   * at the top of kbufferedio.cpp, @ref impldetails .
   */
  QPtrList<QByteArray> inBuf;

  /**
   * For an explanation on how this buffer work, please refer to the comments
   * at the top of kbufferedio.cpp, @ref impldetails .
   */
  QPtrList<QByteArray> outBuf;

  unsigned inBufIndex /** Offset into first input buffer. */, 
    outBufIndex /** Offset into first output buffer. */ ;

  /**
   * Consumes data from the input buffer.
   * That is, this will copy the data stored in the input (read) buffer
   * into the given @p destbuffer, as much as @p nbytes.
   * @param nbytes	the maximum amount of bytes to copy into the buffer
   * @param destbuffer	the destination buffer into which to copy the data
   * @param discard	whether to discard the copied data after the operation
   * @return the real amount of data copied. If it is less than
   * nbytes, then all the buffer was copied.
   */
  virtual unsigned consumeReadBuffer(unsigned nbytes, char *destbuffer, bool discard = true);

  /**
   * Consumes data from the output buffer.
   * Since this is called whenever we managed to send data out the wire, we
   * can only discard this amount from the buffer. There is no copying and no
   * "peeking" for the output buffer.
   *
   * Note this function should be called AFTER the data was sent. After it
   * is called, the data is no longer available in the buffer. And don't pass
   * wrong nbytes values.
   * @param nbytes	the amount of bytes to discard
   */
  virtual void consumeWriteBuffer(unsigned nbytes);

  /**
   * Feeds data into the input buffer.
   * This happens when we detected available data in the device and read it.

   * The data will be appended to the buffer or inserted at the beginning,
   * depending on whether @p atBeginning is set or not.
   * @param nbytes	the number of bytes in the buffer
   * @param buffer	the data that was read
   * @param atBeginning	whether to append or insert at the beginning
   * @return the number of bytes that have been appended
   */
  virtual unsigned feedReadBuffer(unsigned nbytes, const char *buffer, bool atBeginning = false);

  /**
   * Feeds data into the output buffer.
   * This happens when the user told us to write some data.
   * The data will be appended to the buffer.
   * @param nbytes	the number of bytes in the buffer
   * @param buffer	the data that is to be written
   * @return the number of bytes that have been appended
   */
  virtual unsigned feedWriteBuffer(unsigned nbytes, const char *buffer);

  /**
   * Returns the number of bytes in the read buffer
   * @return the size of the read buffer in bytes
   */
  virtual unsigned readBufferSize() const;

  /**
   * Returns the number of bytes in the write buffer
   * @return the size of the write buffer in bytes
   */
  virtual unsigned writeBufferSize() const;

protected:
  virtual void virtual_hook( int id, void* data );
private:
  KBufferedIOPrivate *d;
};

#endif // KBUFFEREDIO_H