KDECore
kfilterdev.cpp
Go to the documentation of this file.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 <QtCore/QFile>
00026
00027 #define BUFFER_SIZE 8*1024
00028
00029 class KFilterDev::Private
00030 {
00031 public:
00032 Private() : 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 QByteArray origFileName;
00042 KFilterBase::Result result;
00043 KFilterBase *filter;
00044 };
00045
00046 KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
00047 : d(new Private)
00048 {
00049 assert(_filter);
00050 d->filter = _filter;
00051 d->autoDeleteFilterBase = autoDeleteFilterBase;
00052 }
00053
00054 KFilterDev::~KFilterDev()
00055 {
00056 if ( isOpen() )
00057 close();
00058 if ( d->autoDeleteFilterBase )
00059 delete d->filter;
00060 delete d;
00061 }
00062
00063
00064 QIODevice * KFilterDev::deviceForFile( const QString & fileName, const QString & mimetype,
00065 bool forceFilter )
00066 {
00067 QFile * f = new QFile( fileName );
00068 KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
00069 : KFilterBase::findFilterByMimeType( mimetype );
00070 if ( base )
00071 {
00072 base->setDevice(f, true);
00073 return new KFilterDev(base, true);
00074 }
00075 if(!forceFilter)
00076 return f;
00077 else
00078 {
00079 delete f;
00080 return 0L;
00081 }
00082 }
00083
00084 QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice )
00085 {
00086 if (inDevice==0)
00087 return 0;
00088 KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
00089 if ( base )
00090 {
00091 base->setDevice(inDevice, autoDeleteInDevice);
00092 return new KFilterDev(base, true );
00093 }
00094 return 0;
00095 }
00096
00097 bool KFilterDev::open( QIODevice::OpenMode mode )
00098 {
00099
00100 if ( mode == QIODevice::ReadOnly )
00101 {
00102 d->buffer.resize(0);
00103 }
00104 else
00105 {
00106 d->buffer.resize( BUFFER_SIZE );
00107 d->filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00108 }
00109 d->bNeedHeader = !d->bSkipHeaders;
00110 d->filter->init( mode );
00111 d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
00112 bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
00113 d->result = KFilterBase::Ok;
00114
00115 if ( !ret )
00116 kWarning(7005) << "KFilterDev::open: Couldn't open underlying device";
00117 else
00118 setOpenMode( mode );
00119
00120 return ret;
00121 }
00122
00123 void KFilterDev::close()
00124 {
00125 if ( !isOpen() )
00126 return;
00127
00128 if ( d->filter->mode() == QIODevice::WriteOnly )
00129 write( 0L, 0 );
00130
00131
00132 d->filter->terminate();
00133 if ( d->bOpenedUnderlyingDevice )
00134 d->filter->device()->close();
00135 setOpenMode( QIODevice::NotOpen );
00136 }
00137
00138 bool KFilterDev::seek( qint64 pos )
00139 {
00140 qint64 ioIndex = this->pos();
00141 if ( ioIndex == pos )
00142 return true;
00143
00144 kDebug(7005) << "KFilterDev::seek(" << pos << ") called";
00145
00146 Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
00147
00148 if ( pos == 0 )
00149 {
00150
00151 d->bNeedHeader = !d->bSkipHeaders;
00152 d->result = KFilterBase::Ok;
00153 d->filter->setInBuffer(0L,0);
00154 d->filter->reset();
00155 QIODevice::seek(pos);
00156 return d->filter->device()->reset();
00157 }
00158
00159 if ( ioIndex > pos )
00160 pos = pos - ioIndex;
00161 else
00162 {
00163
00164
00165 if (!seek(0))
00166 return false;
00167 }
00168
00169
00170 QByteArray dummy( qMin( pos, (qint64)3*BUFFER_SIZE ), 0 );
00171 d->bIgnoreData = true;
00172 bool result = ( read( dummy.data(), pos ) == pos );
00173 d->bIgnoreData = false;
00174 QIODevice::seek(pos);
00175 return result;
00176 }
00177
00178 bool KFilterDev::atEnd() const
00179 {
00180 return (d->result == KFilterBase::End)
00181 && QIODevice::atEnd()
00182 && d->filter->device()->atEnd();
00183 }
00184
00185 qint64 KFilterDev::readData( char *data, qint64 maxlen )
00186 {
00187 Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
00188
00189 KFilterBase* filter = d->filter;
00190
00191 uint dataReceived = 0;
00192
00193
00194 if ( d->result == KFilterBase::End )
00195 return dataReceived;
00196
00197
00198 if ( d->result != KFilterBase::Ok )
00199 return -1;
00200
00201
00202 qint64 outBufferSize;
00203 if ( d->bIgnoreData )
00204 {
00205 outBufferSize = qMin( maxlen, (qint64)3*BUFFER_SIZE );
00206 }
00207 else
00208 {
00209 outBufferSize = maxlen;
00210 }
00211 outBufferSize -= dataReceived;
00212 qint64 availOut = outBufferSize;
00213 filter->setOutBuffer( data, outBufferSize );
00214
00215 bool decompressedAll = false;
00216 while ( dataReceived < maxlen )
00217 {
00218 if (filter->inBufferEmpty())
00219 {
00220
00221
00222 d->buffer.resize( BUFFER_SIZE );
00223
00224 int size = filter->device()->read( d->buffer.data(),
00225 d->buffer.size() );
00226 if ( size )
00227 filter->setInBuffer( d->buffer.data(), size );
00228 else {
00229 if ( decompressedAll )
00230 {
00231
00232
00233 d->result = KFilterBase::End;
00234 break;
00235 }
00236 }
00237
00238 }
00239 if (d->bNeedHeader)
00240 {
00241 (void) filter->readHeader();
00242 d->bNeedHeader = false;
00243 }
00244
00245 d->result = filter->uncompress();
00246
00247 if (d->result == KFilterBase::Error)
00248 {
00249 kWarning(7005) << "KFilterDev: Error when uncompressing data";
00250 break;
00251 }
00252
00253
00254 uint outReceived = availOut - filter->outBufferAvailable();
00255
00256 if( availOut < (uint)filter->outBufferAvailable() )
00257 kWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
00258
00259 dataReceived += outReceived;
00260 if ( !d->bIgnoreData )
00261 {
00262 data += outReceived;
00263 availOut = maxlen - dataReceived;
00264 }
00265 else if ( maxlen - dataReceived < outBufferSize )
00266 {
00267 availOut = maxlen - dataReceived;
00268 }
00269 if (d->result == KFilterBase::End)
00270 {
00271
00272 break;
00273 }
00274 if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
00275 {
00276 decompressedAll = true;
00277 }
00278 filter->setOutBuffer( data, availOut );
00279 }
00280
00281 return dataReceived;
00282 }
00283
00284 qint64 KFilterDev::writeData( const char *data , qint64 len )
00285 {
00286 KFilterBase* filter = d->filter;
00287 Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
00288
00289 if ( d->result != KFilterBase::Ok )
00290 return 0;
00291
00292 bool finish = (data == 0L);
00293 if (!finish)
00294 {
00295 filter->setInBuffer( data, len );
00296 if (d->bNeedHeader)
00297 {
00298 (void)filter->writeHeader( d->origFileName );
00299 d->bNeedHeader = false;
00300 }
00301 }
00302
00303 uint dataWritten = 0;
00304 uint availIn = len;
00305 while ( dataWritten < len || finish )
00306 {
00307
00308 d->result = filter->compress( finish );
00309
00310 if (d->result == KFilterBase::Error)
00311 {
00312 kWarning(7005) << "KFilterDev: Error when compressing data";
00313
00314 break;
00315 }
00316
00317
00318 if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
00319 {
00320
00321 uint wrote = availIn - filter->inBufferAvailable();
00322
00323
00324
00325
00326 data += wrote;
00327 dataWritten += wrote;
00328
00329 availIn = len - dataWritten;
00330
00331 if ( availIn > 0 )
00332 filter->setInBuffer( data, availIn );
00333 }
00334
00335 if (filter->outBufferFull() || (d->result == KFilterBase::End))
00336 {
00337
00338 int towrite = d->buffer.size() - filter->outBufferAvailable();
00339 if ( towrite > 0 )
00340 {
00341
00342 int size = filter->device()->write( d->buffer.data(), towrite );
00343 if ( size != towrite ) {
00344 kWarning(7005) << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
00345 return 0;
00346 }
00347
00348
00349 }
00350 d->buffer.resize( 8*1024 );
00351 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00352 if (d->result == KFilterBase::End)
00353 {
00354
00355 Q_ASSERT(finish);
00356 break;
00357 }
00358 }
00359 }
00360
00361 return dataWritten;
00362 }
00363
00364 void KFilterDev::setOrigFileName( const QByteArray & fileName )
00365 {
00366 d->origFileName = fileName;
00367 }
00368
00369 void KFilterDev::setSkipHeaders()
00370 {
00371 d->bSkipHeaders = true;
00372 }