kdecore Library API Documentation

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"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:45 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001