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->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
00111 d->filter->init( mode );
00112 d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
00113 bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
00114 d->result = KFilterBase::Ok;
00115
00116 if ( !ret )
00117 kWarning(7005) << "KFilterDev::open: Couldn't open underlying device";
00118 else
00119 setOpenMode( mode );
00120
00121 return ret;
00122 }
00123
00124 void KFilterDev::close()
00125 {
00126 if ( !isOpen() )
00127 return;
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
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 while ( dataReceived < maxlen )
00216 {
00217 if (filter->inBufferEmpty())
00218 {
00219
00220
00221 d->buffer.resize( BUFFER_SIZE );
00222
00223 int size = filter->device()->read( d->buffer.data(),
00224 d->buffer.size() );
00225
00226 if (size) {
00227 filter->setInBuffer( d->buffer.data(), size );
00228 } else {
00229
00230 break;
00231 }
00232 }
00233 if (d->bNeedHeader)
00234 {
00235 (void) filter->readHeader();
00236 d->bNeedHeader = false;
00237 }
00238
00239 d->result = filter->uncompress();
00240
00241 if (d->result == KFilterBase::Error)
00242 {
00243 kWarning(7005) << "KFilterDev: Error when uncompressing data";
00244 break;
00245 }
00246
00247
00248 uint outReceived = availOut - filter->outBufferAvailable();
00249
00250 if( availOut < (uint)filter->outBufferAvailable() )
00251 kWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
00252
00253 dataReceived += outReceived;
00254 if ( !d->bIgnoreData )
00255 {
00256 data += outReceived;
00257 availOut = maxlen - dataReceived;
00258 }
00259 else if ( maxlen - dataReceived < outBufferSize )
00260 {
00261 availOut = maxlen - dataReceived;
00262 }
00263 if (d->result == KFilterBase::End)
00264 {
00265
00266 break;
00267 }
00268 filter->setOutBuffer( data, availOut );
00269 }
00270
00271 return dataReceived;
00272 }
00273
00274 qint64 KFilterDev::writeData( const char *data , qint64 len )
00275 {
00276 KFilterBase* filter = d->filter;
00277 Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
00278
00279 if ( d->result != KFilterBase::Ok )
00280 return 0;
00281
00282 bool finish = (data == 0L);
00283 if (!finish)
00284 {
00285 filter->setInBuffer( data, len );
00286 if (d->bNeedHeader)
00287 {
00288 (void)filter->writeHeader( d->origFileName );
00289 d->bNeedHeader = false;
00290 }
00291 }
00292
00293 uint dataWritten = 0;
00294 uint availIn = len;
00295 while ( dataWritten < len || finish )
00296 {
00297
00298 d->result = filter->compress( finish );
00299
00300 if (d->result == KFilterBase::Error)
00301 {
00302 kWarning(7005) << "KFilterDev: Error when compressing data";
00303
00304 break;
00305 }
00306
00307
00308 if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
00309 {
00310
00311 uint wrote = availIn - filter->inBufferAvailable();
00312
00313
00314
00315
00316 data += wrote;
00317 dataWritten += wrote;
00318
00319 availIn = len - dataWritten;
00320
00321 if ( availIn > 0 )
00322 filter->setInBuffer( data, availIn );
00323 }
00324
00325 if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
00326 {
00327
00328 int towrite = d->buffer.size() - filter->outBufferAvailable();
00329 if ( towrite > 0 )
00330 {
00331
00332 int size = filter->device()->write( d->buffer.data(), towrite );
00333 if ( size != towrite ) {
00334 kWarning(7005) << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
00335 return 0;
00336 }
00337
00338
00339 }
00340 if (d->result == KFilterBase::End)
00341 {
00342
00343 Q_ASSERT(finish);
00344 break;
00345 }
00346 d->buffer.resize(BUFFER_SIZE);
00347 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00348 }
00349 }
00350
00351 return dataWritten;
00352 }
00353
00354 void KFilterDev::setOrigFileName( const QByteArray & fileName )
00355 {
00356 d->origFileName = fileName;
00357 }
00358
00359 void KFilterDev::setSkipHeaders()
00360 {
00361 d->bSkipHeaders = true;
00362 }