• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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     //kDebug(7005) << mode;
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 ); // finish writing
00130     //kDebug(7005) << "Calling terminate().";
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(); // current position
00141     if ( ioIndex == pos )
00142         return true;
00143 
00144     //kDebug(7005) << "seek(" << pos << ") called";
00145 
00146     Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
00147 
00148     if ( pos == 0 )
00149     {
00150         // We can forget about the cached data
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 ) // we can start from here
00160         pos = pos - ioIndex;
00161     else
00162     {
00163         // we have to start from 0 ! Ugly and slow, but better than the previous
00164         // solution (KTarGz was allocating everything into memory)
00165         if (!seek(0)) // recursive
00166             return false;
00167     }
00168 
00169     //kDebug(7005) << "reading " << pos << " dummy bytes";
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() // take QIODevice's internal buffer into account
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     //kDebug(7005) << "maxlen=" << maxlen;
00189     KFilterBase* filter = d->filter;
00190 
00191     uint dataReceived = 0;
00192 
00193     // We came to the end of the stream
00194     if ( d->result == KFilterBase::End )
00195         return dataReceived;
00196 
00197     // If we had an error, return -1.
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             // Not sure about the best size to set there.
00220             // For sure, it should be bigger than the header size (see comment in readHeader)
00221             d->buffer.resize( BUFFER_SIZE );
00222             // Request data from underlying device
00223             int size = filter->device()->read( d->buffer.data(),
00224                                                d->buffer.size() );
00225             //kDebug(7005) << "got" << size << "bytes from device";
00226             if (size) {
00227                 filter->setInBuffer( d->buffer.data(), size );
00228             } else {
00229                 // Not enough data available in underlying device for now
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         // We got that much data since the last time we went here
00248         uint outReceived = availOut - filter->outBufferAvailable();
00249         //kDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
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 )  // Move on in the output buffer
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             //kDebug(7005) << "got END. dataReceived=" << dataReceived;
00266             break; // Finished.
00267         }
00268         filter->setOutBuffer( data, availOut );
00269     }
00270 
00271     return dataReceived;
00272 }
00273 
00274 qint64 KFilterDev::writeData( const char *data /*0 to finish*/, qint64 len )
00275 {
00276     KFilterBase* filter = d->filter;
00277     Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
00278     // If we had an error, return 0.
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             // What to do ?
00304             break;
00305         }
00306 
00307         // Wrote everything ?
00308         if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
00309         {
00310             // We got that much data since the last time we went here
00311             uint wrote = availIn - filter->inBufferAvailable();
00312 
00313             //kDebug(7005) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
00314 
00315             // Move on in the input buffer
00316             data += wrote;
00317             dataWritten += wrote;
00318 
00319             availIn = len - dataWritten;
00320             //kDebug(7005) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
00321             if ( availIn > 0 )
00322                 filter->setInBuffer( data, availIn );
00323         }
00324 
00325         if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
00326         {
00327             //kDebug(7005) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
00328             int towrite = d->buffer.size() - filter->outBufferAvailable();
00329             if ( towrite > 0 )
00330             {
00331                 // Write compressed data to underlying device
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; // indicate an error (happens on disk full)
00336                 }
00337                 //else
00338                     //kDebug(7005) << " wrote " << size << " bytes";
00339             }
00340             if (d->result == KFilterBase::End)
00341             {
00342                 //kDebug(7005) << " END";
00343                 Q_ASSERT(finish); // hopefully we don't get end before finishing
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 }

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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