00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "kfilterdev.h"
00020 #include "kfilterbase.h"
00021 #include <kdebug.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <assert.h>
00025 #include <qfile.h>
00026
00027 #define BUFFER_SIZE 8*1024
00028
00029 class KFilterDev::KFilterDevPrivate
00030 {
00031 public:
00032 KFilterDevPrivate() : bNeedHeader(true), bSkipHeaders(false),
00033 autoDeleteFilterBase(false), bOpenedUnderlyingDevice(false),
00034 bIgnoreData(false){}
00035 bool bNeedHeader;
00036 bool bSkipHeaders;
00037 bool autoDeleteFilterBase;
00038 bool bOpenedUnderlyingDevice;
00039 bool bIgnoreData;
00040 QByteArray buffer;
00041 QCString ungetchBuffer;
00042 QCString origFileName;
00043 KFilterBase::Result result;
00044 };
00045
00046 KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
00047 : filter(_filter)
00048 {
00049 assert(filter);
00050 d = new KFilterDevPrivate;
00051 d->autoDeleteFilterBase = autoDeleteFilterBase;
00052 }
00053
00054 KFilterDev::~KFilterDev()
00055 {
00056 if ( isOpen() )
00057 close();
00058 if ( d->autoDeleteFilterBase )
00059 delete filter;
00060 delete d;
00061 }
00062
00063 #ifndef KDE_NO_COMPAT
00064
00065
00066 QIODevice* KFilterDev::createFilterDevice(KFilterBase* base, QFile* file)
00067 {
00068 if (file==0)
00069 return 0;
00070
00071
00072 if (base==0)
00073 return new QFile(file->name());
00074
00075 base->setDevice(file);
00076 return new KFilterDev(base);
00077 }
00078 #endif
00079
00080
00081 QIODevice * KFilterDev::deviceForFile( const QString & fileName, const QString & mimetype,
00082 bool forceFilter )
00083 {
00084 QFile * f = new QFile( fileName );
00085 KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
00086 : KFilterBase::findFilterByMimeType( mimetype );
00087 if ( base )
00088 {
00089 base->setDevice(f, true);
00090 return new KFilterDev(base, true);
00091 }
00092 if(!forceFilter)
00093 return f;
00094 else
00095 {
00096 delete f;
00097 return 0L;
00098 }
00099 }
00100
00101 QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype)
00102 {
00103 return device( inDevice, mimetype, true );
00104 }
00105
00106 QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice )
00107 {
00108 if (inDevice==0)
00109 return 0;
00110 KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
00111 if ( base )
00112 {
00113 base->setDevice(inDevice, autoDeleteInDevice);
00114 return new KFilterDev(base, true );
00115 }
00116 return 0;
00117 }
00118
00119 bool KFilterDev::open( int mode )
00120 {
00121
00122 if ( mode == IO_ReadOnly )
00123 {
00124 d->buffer.resize(0);
00125 d->ungetchBuffer.resize(0);
00126 }
00127 else
00128 {
00129 d->buffer.resize( BUFFER_SIZE );
00130 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00131 }
00132 d->bNeedHeader = !d->bSkipHeaders;
00133 filter->init( mode );
00134 d->bOpenedUnderlyingDevice = !filter->device()->isOpen();
00135 bool ret = d->bOpenedUnderlyingDevice ? filter->device()->open( mode ) : true;
00136 d->result = KFilterBase::OK;
00137
00138 if ( !ret )
00139 kdWarning(7005) << "KFilterDev::open: Couldn't open underlying device" << endl;
00140 else
00141 {
00142 setState( IO_Open );
00143 setMode( mode );
00144 }
00145 ioIndex = 0;
00146 return ret;
00147 }
00148
00149 void KFilterDev::close()
00150 {
00151 if ( !isOpen() )
00152 return;
00153
00154 if ( filter->mode() == IO_WriteOnly )
00155 writeBlock( 0L, 0 );
00156
00157
00158 filter->terminate();
00159 if ( d->bOpenedUnderlyingDevice )
00160 filter->device()->close();
00161
00162 setState( 0 );
00163 }
00164
00165 void KFilterDev::flush()
00166 {
00167
00168 filter->device()->flush();
00169
00170 }
00171
00172 QIODevice::Offset KFilterDev::size() const
00173 {
00174
00175
00176
00177
00178
00179
00180 kdWarning(7005) << "KFilterDev::size - can't be implemented !!!!!!!! Returning -1 " << endl;
00181
00182 return (uint)-1;
00183 }
00184
00185 QIODevice::Offset KFilterDev::at() const
00186 {
00187 return ioIndex;
00188 }
00189
00190 bool KFilterDev::at( QIODevice::Offset pos )
00191 {
00192
00193
00194 if ( ioIndex == pos )
00195 return true;
00196
00197 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00198
00199 if ( pos == 0 )
00200 {
00201 ioIndex = 0;
00202
00203 d->ungetchBuffer.resize(0);
00204 d->bNeedHeader = !d->bSkipHeaders;
00205 d->result = KFilterBase::OK;
00206 filter->setInBuffer(0L,0);
00207 filter->reset();
00208 return filter->device()->reset();
00209 }
00210
00211 if ( ioIndex < pos )
00212 pos = pos - ioIndex;
00213 else
00214 {
00215
00216
00217 if (!at(0))
00218 return false;
00219 }
00220
00221
00222 QByteArray dummy( QMIN( pos, 3*BUFFER_SIZE ) );
00223 d->bIgnoreData = true;
00224 bool result = ( (QIODevice::Offset)readBlock( dummy.data(), pos ) == pos );
00225 d->bIgnoreData = false;
00226 return result;
00227 }
00228
00229 bool KFilterDev::atEnd() const
00230 {
00231 return filter->device()->atEnd() && (d->result == KFilterBase::END)
00232 && d->ungetchBuffer.isEmpty();
00233 }
00234
00235 Q_LONG KFilterDev::readBlock( char *data, Q_ULONG maxlen )
00236 {
00237 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00238
00239
00240 uint dataReceived = 0;
00241 if ( !d->ungetchBuffer.isEmpty() )
00242 {
00243 uint len = d->ungetchBuffer.length();
00244 if ( !d->bIgnoreData )
00245 {
00246 while ( ( dataReceived < len ) && ( dataReceived < maxlen ) )
00247 {
00248 *data = d->ungetchBuffer[ len - dataReceived - 1 ];
00249 data++;
00250 dataReceived++;
00251 }
00252 }
00253 else
00254 {
00255 dataReceived = QMIN( len, maxlen );
00256 }
00257 d->ungetchBuffer.truncate( len - dataReceived );
00258 ioIndex += dataReceived;
00259 }
00260
00261
00262
00263 if ( d->result == KFilterBase::END )
00264 return dataReceived;
00265
00266
00267 if ( d->result != KFilterBase::OK )
00268 return -1;
00269
00270
00271 Q_ULONG outBufferSize;
00272 if ( d->bIgnoreData )
00273 {
00274 outBufferSize = QMIN( maxlen, 3*BUFFER_SIZE );
00275 }
00276 else
00277 {
00278 outBufferSize = maxlen;
00279 }
00280 outBufferSize -= dataReceived;
00281 Q_ULONG availOut = outBufferSize;
00282 filter->setOutBuffer( data, outBufferSize );
00283
00284 bool decompressedAll = false;
00285 while ( dataReceived < maxlen )
00286 {
00287 if (filter->inBufferEmpty())
00288 {
00289
00290
00291 d->buffer.resize( BUFFER_SIZE );
00292
00293 int size = filter->device()->readBlock( d->buffer.data(),
00294 d->buffer.size() );
00295 filter->setInBuffer( d->buffer.data(), size );
00296
00297 }
00298 if (d->bNeedHeader)
00299 {
00300 (void) filter->readHeader();
00301 d->bNeedHeader = false;
00302 }
00303
00304 d->result = filter->uncompress();
00305
00306 if (d->result == KFilterBase::ERROR)
00307 {
00308 kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
00309 break;
00310 }
00311
00312
00313 uint outReceived = availOut - filter->outBufferAvailable();
00314
00315 if( availOut < (uint)filter->outBufferAvailable() )
00316 kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
00317
00318 dataReceived += outReceived;
00319 if ( !d->bIgnoreData )
00320 {
00321 data += outReceived;
00322 availOut = maxlen - dataReceived;
00323 }
00324 else if ( maxlen - dataReceived < outBufferSize )
00325 {
00326 availOut = maxlen - dataReceived;
00327 }
00328 ioIndex += outReceived;
00329 if (d->result == KFilterBase::END)
00330 {
00331
00332 break;
00333 }
00334 if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
00335 {
00336 if (decompressedAll)
00337 {
00338
00339
00340 d->result = KFilterBase::END;
00341
00342 }
00343 decompressedAll = true;
00344 }
00345 filter->setOutBuffer( data, availOut );
00346 }
00347
00348 return dataReceived;
00349 }
00350
00351 Q_LONG KFilterDev::writeBlock( const char *data , Q_ULONG len )
00352 {
00353 Q_ASSERT ( filter->mode() == IO_WriteOnly );
00354
00355 if ( d->result != KFilterBase::OK )
00356 return 0;
00357
00358 bool finish = (data == 0L);
00359 if (!finish)
00360 {
00361 filter->setInBuffer( data, len );
00362 if (d->bNeedHeader)
00363 {
00364 (void)filter->writeHeader( d->origFileName );
00365 d->bNeedHeader = false;
00366 }
00367 }
00368
00369 uint dataWritten = 0;
00370 uint availIn = len;
00371 while ( dataWritten < len || finish )
00372 {
00373
00374 d->result = filter->compress( finish );
00375
00376 if (d->result == KFilterBase::ERROR)
00377 {
00378 kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
00379
00380 break;
00381 }
00382
00383
00384 if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
00385 {
00386
00387 uint wrote = availIn - filter->inBufferAvailable();
00388
00389
00390
00391
00392 data += wrote;
00393 dataWritten += wrote;
00394 ioIndex += wrote;
00395
00396 availIn = len - dataWritten;
00397
00398 if ( availIn > 0 )
00399 filter->setInBuffer( data, availIn );
00400 }
00401
00402 if (filter->outBufferFull() || (d->result == KFilterBase::END))
00403 {
00404
00405 int towrite = d->buffer.size() - filter->outBufferAvailable();
00406 if ( towrite > 0 )
00407 {
00408
00409 int size = filter->device()->writeBlock( d->buffer.data(), towrite );
00410 if ( size != towrite ) {
00411 kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
00412 return 0;
00413 }
00414
00415
00416 }
00417 d->buffer.resize( 8*1024 );
00418 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00419 if (d->result == KFilterBase::END)
00420 {
00421
00422 Q_ASSERT(finish);
00423 break;
00424 }
00425 }
00426 }
00427
00428 return dataWritten;
00429 }
00430
00431 int KFilterDev::getch()
00432 {
00433 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00434
00435 if ( !d->ungetchBuffer.isEmpty() ) {
00436 int len = d->ungetchBuffer.length();
00437 int ch = d->ungetchBuffer[ len-1 ];
00438 d->ungetchBuffer.truncate( len - 1 );
00439 ioIndex++;
00440
00441 return ch;
00442 }
00443 char buf[1];
00444 int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
00445
00446 return ret;
00447 }
00448
00449 int KFilterDev::putch( int c )
00450 {
00451
00452 char buf[1];
00453 buf[0] = c;
00454 return writeBlock( buf, 1 ) == 1 ? c : -1;
00455 }
00456
00457 int KFilterDev::ungetch( int ch )
00458 {
00459
00460 if ( ch == EOF )
00461 return ch;
00462
00463
00464 d->ungetchBuffer +=ch;
00465 ioIndex--;
00466 return ch;
00467 }
00468
00469 void KFilterDev::setOrigFileName( const QCString & fileName )
00470 {
00471 d->origFileName = fileName;
00472 }
00473
00474 void KFilterDev::setSkipHeaders()
00475 {
00476 d->bSkipHeaders = true;
00477 }