tdeio/tdeio
kfilterdev.cpp
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 <tqfile.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 TQByteArray buffer;
00041 TQCString ungetchBuffer;
00042 TQCString 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 TQIODevice* KFilterDev::createFilterDevice(KFilterBase* base, TQFile* file)
00067 {
00068 if (file==0)
00069 return 0;
00070
00071
00072 if (base==0)
00073 return TQT_TQIODEVICE(new TQFile(file->name()));
00074
00075 base->setDevice(TQT_TQIODEVICE(file));
00076 return new KFilterDev(base);
00077 }
00078 #endif
00079
00080
00081 TQIODevice * KFilterDev::deviceForFile( const TQString & fileName, const TQString & mimetype,
00082 bool forceFilter )
00083 {
00084 TQFile * f = new TQFile( fileName );
00085 KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
00086 : KFilterBase::findFilterByMimeType( mimetype );
00087 if ( base )
00088 {
00089 base->setDevice(TQT_TQIODEVICE(f), true);
00090 return new KFilterDev(base, true);
00091 }
00092 if(!forceFilter)
00093 return TQT_TQIODEVICE(f);
00094 else
00095 {
00096 delete f;
00097 return 0L;
00098 }
00099 }
00100
00101 TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & mimetype)
00102 {
00103 return device( inDevice, mimetype, true );
00104 }
00105
00106 TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & 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( TQ_OpenMode 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( (TQ_OpenMode)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 TQIODevice::at(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 #ifdef USE_QT4
00173 qint64 KFilterDev::size() const
00174 #else // USE_QT4
00175 TQIODevice::Offset KFilterDev::size() const
00176 #endif // USE_QT4
00177 {
00178
00179
00180
00181
00182
00183
00184 kdDebug(7005) << "KFilterDev::size - can't be implemented, returning -1" << endl;
00185
00186 return (uint)-1;
00187 }
00188
00189 TQIODevice::Offset KFilterDev::at() const
00190 {
00191 return TQIODevice::at();
00192 }
00193
00194 bool KFilterDev::at( TQIODevice::Offset pos )
00195 {
00196
00197
00198 if ( TQIODevice::at() == pos )
00199 return true;
00200
00201 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00202
00203 if ( pos == 0 )
00204 {
00205 TQIODevice::at(0);
00206
00207 d->ungetchBuffer.resize(0);
00208 d->bNeedHeader = !d->bSkipHeaders;
00209 d->result = KFilterBase::OK;
00210 filter->setInBuffer(0L,0);
00211 filter->reset();
00212 return filter->device()->reset();
00213 }
00214
00215 if ( TQIODevice::at() < pos )
00216 pos = pos - TQIODevice::at();
00217 else
00218 {
00219
00220
00221 if (!at(0))
00222 return false;
00223 }
00224
00225
00226 TQByteArray dummy( TQMIN( pos, 3*BUFFER_SIZE ) );
00227 d->bIgnoreData = true;
00228 bool result = ( (TQIODevice::Offset)readBlock( dummy.data(), pos ) == pos );
00229 d->bIgnoreData = false;
00230 return result;
00231 }
00232
00233 bool KFilterDev::atEnd() const
00234 {
00235 return filter->device()->atEnd() && (d->result == KFilterBase::END)
00236 && d->ungetchBuffer.isEmpty();
00237 }
00238
00239 TQT_TQIO_LONG KFilterDev::tqreadBlock( char *data, TQT_TQIO_ULONG maxlen )
00240 {
00241 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00242
00243
00244 uint dataReceived = 0;
00245 if ( !d->ungetchBuffer.isEmpty() )
00246 {
00247 uint len = d->ungetchBuffer.length();
00248 if ( !d->bIgnoreData )
00249 {
00250 while ( ( dataReceived < len ) && ( dataReceived < maxlen ) )
00251 {
00252 *data = d->ungetchBuffer[ len - dataReceived - 1 ];
00253 data++;
00254 dataReceived++;
00255 }
00256 }
00257 else
00258 {
00259 dataReceived = TQMIN( len, maxlen );
00260 }
00261 d->ungetchBuffer.truncate( len - dataReceived );
00262 TQIODevice::at(TQIODevice::at() + dataReceived);
00263 }
00264
00265
00266
00267 if ( d->result == KFilterBase::END )
00268 return dataReceived;
00269
00270
00271 if ( d->result != KFilterBase::OK )
00272 return -1;
00273
00274
00275 TQ_ULONG outBufferSize;
00276 if ( d->bIgnoreData )
00277 {
00278 outBufferSize = TQMIN( maxlen, 3*BUFFER_SIZE );
00279 }
00280 else
00281 {
00282 outBufferSize = maxlen;
00283 }
00284 outBufferSize -= dataReceived;
00285 TQ_ULONG availOut = outBufferSize;
00286 filter->setOutBuffer( data, outBufferSize );
00287
00288 bool decompressedAll = false;
00289 while ( dataReceived < maxlen )
00290 {
00291 if (filter->inBufferEmpty())
00292 {
00293
00294
00295 d->buffer.resize( BUFFER_SIZE );
00296
00297 int size = filter->device()->readBlock( d->buffer.data(),
00298 d->buffer.size() );
00299 if ( size )
00300 filter->setInBuffer( d->buffer.data(), size );
00301 else {
00302 if ( decompressedAll )
00303 {
00304
00305
00306 d->result = KFilterBase::END;
00307 break;
00308 }
00309 }
00310
00311 }
00312 if (d->bNeedHeader)
00313 {
00314 (void) filter->readHeader();
00315 d->bNeedHeader = false;
00316 }
00317
00318 d->result = filter->uncompress();
00319
00320 if (d->result == KFilterBase::ERROR)
00321 {
00322 kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
00323 break;
00324 }
00325
00326
00327 uint outReceived = availOut - filter->outBufferAvailable();
00328
00329 if( availOut < (uint)filter->outBufferAvailable() )
00330 kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
00331
00332 dataReceived += outReceived;
00333 if ( !d->bIgnoreData )
00334 {
00335 data += outReceived;
00336 availOut = maxlen - dataReceived;
00337 }
00338 else if ( maxlen - dataReceived < outBufferSize )
00339 {
00340 availOut = maxlen - dataReceived;
00341 }
00342 TQIODevice::at(TQIODevice::at() + outReceived);
00343 if (d->result == KFilterBase::END)
00344 {
00345
00346 break;
00347 }
00348 if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
00349 {
00350 decompressedAll = true;
00351 }
00352 filter->setOutBuffer( data, availOut );
00353 }
00354
00355 return dataReceived;
00356 }
00357
00358 TQT_TQIO_LONG KFilterDev::tqwriteBlock( const char *data , TQT_TQIO_ULONG len )
00359 {
00360 Q_ASSERT ( filter->mode() == IO_WriteOnly );
00361
00362 if ( d->result != KFilterBase::OK )
00363 return 0;
00364
00365 bool finish = (data == 0L);
00366 if (!finish)
00367 {
00368 filter->setInBuffer( data, len );
00369 if (d->bNeedHeader)
00370 {
00371 (void)filter->writeHeader( d->origFileName );
00372 d->bNeedHeader = false;
00373 }
00374 }
00375
00376 uint dataWritten = 0;
00377 uint availIn = len;
00378 while ( dataWritten < len || finish )
00379 {
00380
00381 d->result = filter->compress( finish );
00382
00383 if (d->result == KFilterBase::ERROR)
00384 {
00385 kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
00386
00387 break;
00388 }
00389
00390
00391 if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
00392 {
00393
00394 uint wrote = availIn - filter->inBufferAvailable();
00395
00396
00397
00398
00399 data += wrote;
00400 dataWritten += wrote;
00401 TQIODevice::at(TQIODevice::at() + wrote);
00402
00403 availIn = len - dataWritten;
00404
00405 if ( availIn > 0 )
00406 filter->setInBuffer( data, availIn );
00407 }
00408
00409 if (filter->outBufferFull() || (d->result == KFilterBase::END))
00410 {
00411
00412 int towrite = d->buffer.size() - filter->outBufferAvailable();
00413 if ( towrite > 0 )
00414 {
00415
00416 int size = filter->device()->writeBlock( d->buffer.data(), towrite );
00417 if ( size != towrite ) {
00418 kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
00419 return 0;
00420 }
00421
00422
00423 }
00424 d->buffer.resize( 8*1024 );
00425 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00426 if (d->result == KFilterBase::END)
00427 {
00428
00429 Q_ASSERT(finish);
00430 break;
00431 }
00432 }
00433 }
00434
00435 return dataWritten;
00436 }
00437
00438 int KFilterDev::getch()
00439 {
00440 Q_ASSERT ( filter->mode() == IO_ReadOnly );
00441
00442 if ( !d->ungetchBuffer.isEmpty() ) {
00443 int len = d->ungetchBuffer.length();
00444 int ch = d->ungetchBuffer[ len-1 ];
00445 d->ungetchBuffer.truncate( len - 1 );
00446 TQIODevice::at(TQIODevice::at() + 1);
00447
00448 return ch;
00449 }
00450 char buf[1];
00451 int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
00452
00453 return ret;
00454 }
00455
00456 int KFilterDev::putch( int c )
00457 {
00458
00459 char buf[1];
00460 buf[0] = c;
00461 return writeBlock( buf, 1 ) == 1 ? c : -1;
00462 }
00463
00464 int KFilterDev::ungetch( int ch )
00465 {
00466
00467 if ( ch == EOF )
00468 return ch;
00469
00470
00471 d->ungetchBuffer +=ch;
00472 TQIODevice::at(TQIODevice::at() - 1);
00473 return ch;
00474 }
00475
00476 void KFilterDev::setOrigFileName( const TQCString & fileName )
00477 {
00478 d->origFileName = fileName;
00479 }
00480
00481 void KFilterDev::setSkipHeaders()
00482 {
00483 d->bSkipHeaders = true;
00484 }