| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kbufferedio.cpp

    00001 /*
    00002  *  This file is part of the KDE libraries
    00003  *  Copyright (C) 2001 Thiago Macieira <thiago.macieira@kdemail.net>
    00004  *
    00005  *  This library is free software; you can redistribute it and/or
    00006  *  modify it under the terms of the GNU Library General Public
    00007  *  License as published by the Free Software Foundation; either
    00008  *  version 2 of the License, or (at your option) any later version.
    00009  *
    00010  *  This library is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  *  Library General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU Library General Public License
    00016  *  along with this library; see the file COPYING.LIB.  If not, write to
    00017  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018  *  Boston, MA 02111-1307, USA.
    00019  */
    00020
    00021 #include "config.h"
    00022
    00023 #include <string.h>
    00024
    00025 #include <qptrlist.h>
    00026 #include <qcstring.h>
    00027 #include "kbufferedio.h"
    00028
    00029 /*
    00030  * The KBufferedIO class has two purposes: first, it defines an API on how
    00031  * that classes providing buffered I/O should provide. Next, it implements on
    00032  * top of that API a generic buffering, that should suffice for most cases.
    00033  *
    00034  * The buffering implemented consists of two separate buffer areas, one for
    00035  * the input (or read) buffer, and one for the output (or write) buffer. Each
    00036  * of those buffers is implemented through a QList of QByteArrays instead of
    00037  * simply QByteArrays. The idea is that, instead of having one large, contiguous
    00038  * buffer area, we have several small ones. Even though this could be seen as
    00039  * a waste of memory, it makes our life easier, because we can just append a new
    00040  * QByteArray to the list and not have to worry with copying the rest of the
    00041  * buffer, should we need to expand.
    00042  *
    00043  * This way, we have the capability of unlimited buffering, which can grow to
    00044  * the extent of available memory.
    00045  *
    00046  * For each buffer, we provide three kinds of functions, available as protected
    00047  * members: consume, feed and size. The size functions calculate the current
    00048  * size of the buffer, by adding each individual QByteArray size. The feed
    00049  * functions are used by the I/O functions that receive data from somewhere,
    00050  * i.e., from the system, in the case of the input buffer, and from the user,
    00051  * in the case of the output buffer. These two functions are used to give
    00052  * the buffers more data. And the consume functions are used by the functions
    00053  * that send out data (to the system, for the write buffer, and to the user,
    00054  * for the read buffer).
    00055  *
    00056  * Note that for your own implementation, you can have your readBlock function
    00057  * merely call consumeReadBuffer, similarly to peekBlock. As for
    00058  * the writeBlock function, you'd call feedWriteBuffer.
    00059  *
    00060  * Now, the function receiving data from the system will need to simply call
    00061  * feedReadBuffer, much in the same way of unreadBlock. The tricky part is
    00062  * for the output function. We do not provide a member function that copies
    00063  * data from the output buffer into another buffer for sending. We believe that
    00064  * would be a waste of resources and CPU time, since you'd have to allocate
    00065  * that buffer, copy data into it and then call the OS, which will likely just
    00066  * copy data out of it.
    00067  *
    00068  * Instead, we found it better to leave it to you to access outBuf member
    00069  * variable directly and use the buffers there. Should you want to copy that
    00070  * into a larger buffer before sending, that's up to you.
    00071  *
    00072  * Both buffers work in the same way: they're an "array" of buffers, each
    00073  * concatenated to the other. All data in all buffers is valid data, except
    00074  * for the first QByteArray, whose valid data starts at inBufIndex/outBufIndex
    00075  * bytes from the start. That is, the data starts in the first QByteArray buffer
    00076  * that many bytes from the start and goes on contiguously until the last
    00077  * QByteArray. This has been decided like that because we didn't want to
    00078  * create a new QByteArray of the remaining bytes in the first buffer, after
    00079  * a consume operation, because that could take some time. It is faster
    00080  * this way, although not really easy.
    00081  *
    00082  * If you want to take a look at an implementation of a buffered I/O class,
    00083  * refer to KExtendedSocket's source code.
    00084  */
    00085
    00086 // constructor
    00087 KBufferedIO::KBufferedIO() :
    00088   inBufIndex(0), outBufIndex(0)
    00089 {
    00090   inBuf.setAutoDelete(true);
    00091   outBuf.setAutoDelete(true);
    00092 }
    00093
    00094 // destructor
    00095 KBufferedIO::~KBufferedIO()
    00096 {
    00097 }
    00098
    00099 // sets the buffer sizes
    00100 // this implementation doesn't support setting the buffer sizes
    00101 // if any parameter is different than -1 or -2, fail
    00102 bool KBufferedIO::setBufferSize(int rsize, int wsize /* = -2 */)
    00103 {
    00104   if (wsize != -2 && wsize != -1)
    00105     return false;
    00106   if (rsize != -2 && rsize != -1)
    00107     return false;
    00108
    00109   return true;
    00110 }
    00111
    00112 int KBufferedIO::bytesAvailable() const
    00113 {
    00114   return readBufferSize();
    00115 }
    00116
    00117 int KBufferedIO::bytesToWrite() const
    00118 {
    00119   return writeBufferSize();
    00120 }
    00121
    00122 // This function will scan the read buffer for a '\n'
    00123 bool KBufferedIO::canReadLine() const
    00124 {
    00125   if (bytesAvailable() == 0)
    00126     return false;       // no new line in here
    00127
    00128   QByteArray* buf;
    00129
    00130   // scan each QByteArray for the occurrence of '\n'
    00131   QPtrList<QByteArray> &buflist = ((KBufferedIO*)this)->inBuf;
    00132   buf = buflist.first();
    00133   char *p = buf->data() + inBufIndex;
    00134   int n = buf->size() - inBufIndex;
    00135   while (buf != NULL)
    00136     {
    00137       while (n--)
    00138     if (*p++ == '\n')
    00139       return true;
    00140       buf = buflist.next();
    00141       if (buf != NULL)
    00142     {
    00143       p = buf->data();
    00144       n = buf->size();
    00145     }
    00146     }
    00147
    00148   return false;         // no new line found
    00149 }
    00150
    00151 // unreads the current data
    00152 // that is, writes into the read buffer, at the beginning
    00153 int KBufferedIO::unreadBlock(const char *data, uint len)
    00154 {
    00155   return feedReadBuffer(len, data, true);
    00156 }
    00157
    00158 //
    00159 // protected member functions
    00160 //
    00161
    00162 unsigned KBufferedIO::consumeReadBuffer(unsigned nbytes, char *destbuffer, bool discard)
    00163 {
    00164   {
    00165     register unsigned u = readBufferSize();
    00166     if (nbytes > u)
    00167       nbytes = u;       // we can't consume more than there is
    00168   }
    00169
    00170   QByteArray *buf;
    00171   unsigned copied = 0;
    00172   unsigned index = inBufIndex;
    00173
    00174   buf = inBuf.first();
    00175   while (nbytes && buf)
    00176     {
    00177       // should we copy it all?
    00178       unsigned to_copy = buf->size() - index;
    00179       if (to_copy > nbytes)
    00180     to_copy = nbytes;
    00181
    00182       if (destbuffer)
    00183     memcpy(destbuffer + copied, buf->data() + index, to_copy);
    00184       nbytes -= to_copy;
    00185       copied += to_copy;
    00186
    00187       if (buf->size() - index > to_copy)
    00188     {
    00189       index += to_copy;
    00190       break;    // we aren't copying everything, that means that's
    00191             // all the user wants
    00192     }
    00193       else
    00194     {
    00195       index = 0;
    00196       if (discard)
    00197         {
    00198           inBuf.remove();
    00199           buf = inBuf.first();
    00200         }
    00201       else
    00202         buf = inBuf.next();
    00203     }
    00204     }
    00205
    00206   if (discard)
    00207     inBufIndex = index;
    00208
    00209   return copied;
    00210 }
    00211
    00212 void KBufferedIO::consumeWriteBuffer(unsigned nbytes)
    00213 {
    00214   QByteArray *buf = outBuf.first();
    00215   if (buf == NULL)
    00216     return;         // nothing to consume
    00217
    00218   if (nbytes < buf->size() - outBufIndex)
    00219     // we want to consume less than there is in the first buffer
    00220     outBufIndex += nbytes;
    00221   else
    00222     {
    00223       nbytes -= buf->size() - outBufIndex;
    00224       outBufIndex = 0;
    00225       outBuf.remove();
    00226
    00227       while ((buf = outBuf.current()) != NULL)
    00228     if (buf->size() <= nbytes)
    00229       {
    00230         nbytes -= buf->size();
    00231         outBuf.remove();
    00232       }
    00233     else
    00234       {
    00235         outBufIndex = nbytes;
    00236         break;
    00237       }
    00238     }
    00239 }
    00240
    00241 unsigned KBufferedIO::feedReadBuffer(unsigned nbytes, const char *buffer, bool atBeginning)
    00242 {
    00243   if (nbytes == 0)
    00244     return 0;
    00245
    00246   QByteArray *a = new QByteArray(nbytes);
    00247   a->duplicate(buffer, nbytes);
    00248
    00249   if (atBeginning)
    00250     inBuf.prepend(a);
    00251   else
    00252     inBuf.append(a);
    00253
    00254   return nbytes;
    00255 }
    00256
    00257 unsigned KBufferedIO::feedWriteBuffer(unsigned nbytes, const char *buffer)
    00258 {
    00259   if (nbytes == 0)
    00260     return 0;
    00261
    00262   QByteArray *a = new QByteArray(nbytes);
    00263   a->duplicate(buffer, nbytes);
    00264   outBuf.append(a);
    00265   return nbytes;
    00266 }
    00267
    00268 unsigned KBufferedIO::readBufferSize() const
    00269 {
    00270   unsigned count = 0;
    00271   QByteArray *buf = ((KBufferedIO*)this)->inBuf.first();
    00272   while (buf != NULL)
    00273     {
    00274       count += buf->size();
    00275       buf = ((KBufferedIO*)this)->inBuf.next();
    00276     }
    00277
    00278   return count - inBufIndex;
    00279 }
    00280
    00281 unsigned KBufferedIO::writeBufferSize() const
    00282 {
    00283   unsigned count = 0;
    00284   QByteArray *buf = ((KBufferedIO*)this)->outBuf.first();
    00285   while (buf != NULL)
    00286     {
    00287       count += buf->size();
    00288       buf = (const_cast<KBufferedIO*>(this))->outBuf.next();
    00289     }
    00290
    00291   return count - outBufIndex;
    00292 }
    00293
    00294 void KBufferedIO::virtual_hook( int id, void* data )
    00295 { KAsyncIO::virtual_hook( id, data ); }
    00296
    00297 #include "kbufferedio.moc"

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:01 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003