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

# kbufferedio.cpp

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:20 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001