• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kfilterdev.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000, 2006 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "kfilterdev.h"
00020 #include "kfilterbase.h"
00021 #include <kdebug.h>
00022 #include <stdio.h> // for EOF
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; // Used as 'input buffer' when reading, as 'output buffer' when writing
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 //static
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 /* auto-delete "base" */);
00093    }
00094    return 0;
00095 }
00096 
00097 bool KFilterDev::open( QIODevice::OpenMode mode )
00098 {
00099     if (isOpen()) {
00100         kWarning(7005) << "already open";
00101         return true; // QFile returns false, but well, the device -is- open...
00102     }
00103     //kDebug(7005) << mode;
00104     if ( mode == QIODevice::ReadOnly )
00105     {
00106         d->buffer.resize(0);
00107     }
00108     else
00109     {
00110         d->buffer.resize( BUFFER_SIZE );
00111         d->filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00112     }
00113     d->bNeedHeader = !d->bSkipHeaders;
00114     d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
00115     d->filter->init( mode );
00116     d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
00117     bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
00118     d->result = KFilterBase::Ok;
00119 
00120     if ( !ret )
00121         kWarning(7005) << "KFilterDev::open: Couldn't open underlying device";
00122     else
00123         setOpenMode( mode );
00124 
00125     return ret;
00126 }
00127 
00128 void KFilterDev::close()
00129 {
00130     if ( !isOpen() )
00131         return;
00132     if ( d->filter->mode() == QIODevice::WriteOnly )
00133         write( 0L, 0 ); // finish writing
00134     //kDebug(7005) << "Calling terminate().";
00135 
00136     d->filter->terminate();
00137     if ( d->bOpenedUnderlyingDevice )
00138         d->filter->device()->close();
00139     setOpenMode( QIODevice::NotOpen );
00140 }
00141 
00142 bool KFilterDev::seek( qint64 pos )
00143 {
00144     qint64 ioIndex = this->pos(); // current position
00145     if ( ioIndex == pos )
00146         return true;
00147 
00148     //kDebug(7005) << "seek(" << pos << ") called";
00149 
00150     Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
00151 
00152     if ( pos == 0 )
00153     {
00154         // We can forget about the cached data
00155         d->bNeedHeader = !d->bSkipHeaders;
00156         d->result = KFilterBase::Ok;
00157         d->filter->setInBuffer(0L,0);
00158         d->filter->reset();
00159         QIODevice::seek(pos);
00160         return d->filter->device()->reset();
00161     }
00162 
00163     if ( ioIndex > pos ) // we can start from here
00164         pos = pos - ioIndex;
00165     else
00166     {
00167         // we have to start from 0 ! Ugly and slow, but better than the previous
00168         // solution (KTarGz was allocating everything into memory)
00169         if (!seek(0)) // recursive
00170             return false;
00171     }
00172 
00173     //kDebug(7005) << "reading " << pos << " dummy bytes";
00174     QByteArray dummy( qMin( pos, (qint64)3*BUFFER_SIZE ), 0 );
00175     d->bIgnoreData = true;
00176     bool result = ( read( dummy.data(), pos ) == pos );
00177     d->bIgnoreData = false;
00178     QIODevice::seek(pos);
00179     return result;
00180 }
00181 
00182 bool KFilterDev::atEnd() const
00183 {
00184     return (d->result == KFilterBase::End)
00185         && QIODevice::atEnd() // take QIODevice's internal buffer into account
00186         && d->filter->device()->atEnd();
00187 }
00188 
00189 qint64 KFilterDev::readData( char *data, qint64 maxlen )
00190 {
00191     Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
00192     //kDebug(7005) << "maxlen=" << maxlen;
00193     KFilterBase* filter = d->filter;
00194 
00195     uint dataReceived = 0;
00196 
00197     // We came to the end of the stream
00198     if ( d->result == KFilterBase::End )
00199         return dataReceived;
00200 
00201     // If we had an error, return -1.
00202     if ( d->result != KFilterBase::Ok )
00203         return -1;
00204 
00205 
00206     qint64 outBufferSize;
00207     if ( d->bIgnoreData )
00208     {
00209         outBufferSize = qMin( maxlen, (qint64)3*BUFFER_SIZE );
00210     }
00211     else
00212     {
00213         outBufferSize = maxlen;
00214     }
00215     outBufferSize -= dataReceived;
00216     qint64 availOut = outBufferSize;
00217     filter->setOutBuffer( data, outBufferSize );
00218 
00219     while ( dataReceived < maxlen )
00220     {
00221         if (filter->inBufferEmpty())
00222         {
00223             // Not sure about the best size to set there.
00224             // For sure, it should be bigger than the header size (see comment in readHeader)
00225             d->buffer.resize( BUFFER_SIZE );
00226             // Request data from underlying device
00227             int size = filter->device()->read( d->buffer.data(),
00228                                                d->buffer.size() );
00229             //kDebug(7005) << "got" << size << "bytes from device";
00230             if (size) {
00231                 filter->setInBuffer( d->buffer.data(), size );
00232             } else {
00233                 // Not enough data available in underlying device for now
00234                 break;
00235             }
00236         }
00237         if (d->bNeedHeader)
00238         {
00239             (void) filter->readHeader();
00240             d->bNeedHeader = false;
00241         }
00242 
00243         d->result = filter->uncompress();
00244 
00245         if (d->result == KFilterBase::Error)
00246         {
00247             kWarning(7005) << "KFilterDev: Error when uncompressing data";
00248             break;
00249         }
00250 
00251         // We got that much data since the last time we went here
00252         uint outReceived = availOut - filter->outBufferAvailable();
00253         //kDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
00254         if( availOut < (uint)filter->outBufferAvailable() )
00255             kWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
00256 
00257         dataReceived += outReceived;
00258         if ( !d->bIgnoreData )  // Move on in the output buffer
00259         {
00260             data += outReceived;
00261             availOut = maxlen - dataReceived;
00262         }
00263         else if ( maxlen - dataReceived < outBufferSize )
00264         {
00265             availOut = maxlen - dataReceived;
00266         }
00267         if (d->result == KFilterBase::End)
00268         {
00269             //kDebug(7005) << "got END. dataReceived=" << dataReceived;
00270             break; // Finished.
00271         }
00272         filter->setOutBuffer( data, availOut );
00273     }
00274 
00275     return dataReceived;
00276 }
00277 
00278 qint64 KFilterDev::writeData( const char *data /*0 to finish*/, qint64 len )
00279 {
00280     KFilterBase* filter = d->filter;
00281     Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
00282     // If we had an error, return 0.
00283     if ( d->result != KFilterBase::Ok )
00284         return 0;
00285 
00286     bool finish = (data == 0L);
00287     if (!finish)
00288     {
00289         filter->setInBuffer( data, len );
00290         if (d->bNeedHeader)
00291         {
00292             (void)filter->writeHeader( d->origFileName );
00293             d->bNeedHeader = false;
00294         }
00295     }
00296 
00297     uint dataWritten = 0;
00298     uint availIn = len;
00299     while ( dataWritten < len || finish )
00300     {
00301 
00302         d->result = filter->compress( finish );
00303 
00304         if (d->result == KFilterBase::Error)
00305         {
00306             kWarning(7005) << "KFilterDev: Error when compressing data";
00307             // What to do ?
00308             break;
00309         }
00310 
00311         // Wrote everything ?
00312         if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
00313         {
00314             // We got that much data since the last time we went here
00315             uint wrote = availIn - filter->inBufferAvailable();
00316 
00317             //kDebug(7005) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
00318 
00319             // Move on in the input buffer
00320             data += wrote;
00321             dataWritten += wrote;
00322 
00323             availIn = len - dataWritten;
00324             //kDebug(7005) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
00325             if ( availIn > 0 )
00326                 filter->setInBuffer( data, availIn );
00327         }
00328 
00329         if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
00330         {
00331             //kDebug(7005) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
00332             int towrite = d->buffer.size() - filter->outBufferAvailable();
00333             if ( towrite > 0 )
00334             {
00335                 // Write compressed data to underlying device
00336                 int size = filter->device()->write( d->buffer.data(), towrite );
00337                 if ( size != towrite ) {
00338                     kWarning(7005) << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
00339                     return 0; // indicate an error (happens on disk full)
00340                 }
00341                 //else
00342                     //kDebug(7005) << " wrote " << size << " bytes";
00343             }
00344             if (d->result == KFilterBase::End)
00345             {
00346                 //kDebug(7005) << " END";
00347                 Q_ASSERT(finish); // hopefully we don't get end before finishing
00348                 break;
00349             }
00350             d->buffer.resize(BUFFER_SIZE);
00351             filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00352         }
00353     }
00354 
00355     return dataWritten;
00356 }
00357 
00358 void KFilterDev::setOrigFileName( const QByteArray & fileName )
00359 {
00360     d->origFileName = fileName;
00361 }
00362 
00363 void KFilterDev::setSkipHeaders()
00364 {
00365     d->bSkipHeaders = true;
00366 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal