kdecore Library API Documentation

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"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Jul 20 12:28:48 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003