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.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:09 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003