• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kio
 

kio/kio

kfilterdev.cpp
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 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 <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; // Used as 'input buffer' when reading, as 'output buffer' when writing
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 //this one is static
00065 // Cumbersome API. To be removed in KDE 3.0.
00066 TQIODevice* KFilterDev::createFilterDevice(KFilterBase* base, TQFile* file)
00067 {
00068    if (file==0)
00069       return 0;
00070 
00071    //we don't need a filter
00072    if (base==0)
00073        return TQT_TQIODEVICE(new TQFile(file->name())); // A bit strange IMHO. We ask for a TQFile but we create another one !?! (DF)
00074 
00075    base->setDevice(TQT_TQIODEVICE(file));
00076    return new KFilterDev(base);
00077 }
00078 #endif
00079 
00080 //static
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 /* auto-delete "base" */);
00115    }
00116    return 0;
00117 }
00118 
00119 bool KFilterDev::open( TQ_OpenMode mode )
00120 {
00121     //kdDebug(7005) << "KFilterDev::open " << mode << endl;
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     //kdDebug(7005) << "KFilterDev::close" << endl;
00154     if ( filter->mode() == IO_WriteOnly )
00155         writeBlock( 0L, 0 ); // finish writing
00156     //kdDebug(7005) << "KFilterDev::close. Calling terminate()." << endl;
00157 
00158     filter->terminate();
00159     if ( d->bOpenedUnderlyingDevice )
00160         filter->device()->close();
00161 
00162     setState( 0 ); // not IO_Open
00163 }
00164 
00165 void KFilterDev::flush()
00166 {
00167     //kdDebug(7005) << "KFilterDev::flush" << endl;
00168     filter->device()->flush();
00169     // Hmm, might not be enough...
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     // Well, hmm, Houston, we have a problem.
00179     // We can't know the size of the uncompressed data
00180     // before uncompressing it.......
00181 
00182     // But readAll, which is not virtual, needs the size.........
00183 
00184     kdDebug(7005) << "KFilterDev::size - can't be implemented, returning -1" << endl;
00185     //abort();
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     //kdDebug(7005) << "KFilterDev::at " << pos << "  currently at " << TQIODevice::at() << endl;
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         // We can forget about the cached data
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 ) // we can start from here
00216         pos = pos - TQIODevice::at();
00217     else
00218     {
00219         // we have to start from 0 ! Ugly and slow, but better than the previous
00220         // solution (KTarGz was allocating everything into memory)
00221         if (!at(0)) // sets ioIndex to 0
00222             return false;
00223     }
00224 
00225     //kdDebug(7005) << "KFilterDev::at : reading " << pos << " dummy bytes" << endl;
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     //kdDebug(7005) << "KFilterDev::readBlock maxlen=" << maxlen << endl;
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     // If we came to the end of the stream
00266     // return what we got from the ungetchBuffer.
00267     if ( d->result == KFilterBase::END )
00268         return dataReceived;
00269 
00270     // If we had an error, return -1.
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             // Not sure about the best size to set there.
00294             // For sure, it should be bigger than the header size (see comment in readHeader)
00295             d->buffer.resize( BUFFER_SIZE );
00296             // Request data from underlying device
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                     // We decoded everything there was to decode. So -> done.
00305                     //kdDebug(7005) << "Seems we're done. dataReceived=" << dataReceived << endl;
00306                     d->result = KFilterBase::END;
00307                     break;
00308                 }
00309             }
00310             //kdDebug(7005) << "KFilterDev::readBlock got " << size << " bytes from device" << endl;
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         // We got that much data since the last time we went here
00327         uint outReceived = availOut - filter->outBufferAvailable();
00328         //kdDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived << endl;
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 )  // Move on in the output buffer
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             //kdDebug(7005) << "KFilterDev::readBlock got END. dataReceived=" << dataReceived << endl;
00346             break; // Finished.
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 /*0 to finish*/, TQT_TQIO_ULONG len )
00359 {
00360     Q_ASSERT ( filter->mode() == IO_WriteOnly );
00361     // If we had an error, return 0.
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             // What to do ?
00387             break;
00388         }
00389 
00390         // Wrote everything ?
00391         if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
00392         {
00393             // We got that much data since the last time we went here
00394             uint wrote = availIn - filter->inBufferAvailable();
00395 
00396             //kdDebug(7005) << " Wrote everything for now. avail_in = " << filter->inBufferAvailable() << " result=" << d->result << " wrote=" << wrote << endl;
00397 
00398             // Move on in the input buffer
00399             data += wrote;
00400             dataWritten += wrote;
00401             TQIODevice::at(TQIODevice::at() + wrote);
00402 
00403             availIn = len - dataWritten;
00404             //kdDebug(7005) << " KFilterDev::writeBlock availIn=" << availIn << " dataWritten=" << dataWritten << " ioIndex=" << ioIndex << endl;
00405             if ( availIn > 0 ) // Not sure this will ever happen
00406                 filter->setInBuffer( data, availIn );
00407         }
00408 
00409         if (filter->outBufferFull() || (d->result == KFilterBase::END))
00410         {
00411             //kdDebug(7005) << " KFilterDev::writeBlock writing to underlying. avail_out=" << filter->outBufferAvailable() << endl;
00412             int towrite = d->buffer.size() - filter->outBufferAvailable();
00413             if ( towrite > 0 )
00414             {
00415                 // Write compressed data to underlying device
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; // indicate an error (happens on disk full)
00420                 }
00421                 //else
00422                     //kdDebug(7005) << " KFilterDev::writeBlock wrote " << size << " bytes" << endl;
00423             }
00424             d->buffer.resize( 8*1024 );
00425             filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
00426             if (d->result == KFilterBase::END)
00427             {
00428                 //kdDebug(7005) << " KFilterDev::writeBlock END" << endl;
00429                 Q_ASSERT(finish); // hopefully we don't get end before finishing
00430                 break;
00431             }
00432         }
00433     }
00434 
00435     return dataWritten;
00436 }
00437 
00438 int KFilterDev::getch()
00439 {
00440     Q_ASSERT ( filter->mode() == IO_ReadOnly );
00441     //kdDebug(7005) << "KFilterDev::getch" << endl;
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         //kdDebug(7005) << "KFilterDev::getch from ungetch: " << TQString(TQChar(ch)) << endl;
00448         return ch;
00449     }
00450     char buf[1];
00451     int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
00452     //kdDebug(7005) << "KFilterDev::getch ret=" << TQString(TQChar(ret)) << endl;
00453     return ret;
00454 }
00455 
00456 int KFilterDev::putch( int c )
00457 {
00458     //kdDebug(7005) << "KFilterDev::putch" << endl;
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     //kdDebug(7005) << "KFilterDev::ungetch " << TQString(TQChar(ch)) << endl;
00467     if ( ch == EOF )                            // cannot unget EOF
00468         return ch;
00469 
00470     // pipe or similar => we cannot ungetch, so do it manually
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 }

kio/kio

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

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |