• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kioslave

kgzipfilter.cpp

Go to the documentation of this file.
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 "kgzipfilter.h"
00020 #include <time.h>
00021 #include <zlib.h>
00022 #include <kdebug.h>
00023 #include <klibloader.h>
00024 
00025 /* gzip flag byte */
00026 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
00027 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
00028 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
00029 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
00030 #define COMMENT      0x10 /* bit 4 set: file comment present */
00031 #define RESERVED     0xE0 /* bits 5..7: reserved */
00032 
00033 
00034 // #define DEBUG_GZIP
00035 
00036 class KGzipFilterFactory : public KLibFactory
00037 {
00038 public:
00039     KGzipFilterFactory() : KLibFactory() {}
00040     ~KGzipFilterFactory(){}
00041     QObject *createObject( QObject *parent, const char *name, const char*className, const QStringList & args )
00042     {
00043         Q_UNUSED(parent);
00044         Q_UNUSED(name);
00045         Q_UNUSED(className);
00046         Q_UNUSED(args);
00047         return new KGzipFilter;
00048     }
00049 };
00050 
00051 K_EXPORT_COMPONENT_FACTORY( kgzipfilter, KGzipFilterFactory )
00052 
00053 // Not really necessary anymore, now that this is a dynamically-loaded lib.
00054 class KGzipFilter::KGzipFilterPrivate
00055 {
00056 public:
00057     z_stream zStream;
00058     bool bCompressed;
00059 };
00060 
00061 KGzipFilter::KGzipFilter()
00062 {
00063     d = new KGzipFilterPrivate;
00064     d->zStream.zalloc = (alloc_func)0;
00065     d->zStream.zfree = (free_func)0;
00066     d->zStream.opaque = (voidpf)0;
00067 }
00068 
00069 
00070 KGzipFilter::~KGzipFilter()
00071 {
00072     delete d;
00073 }
00074 
00075 void KGzipFilter::init( int mode )
00076 {
00077     d->zStream.next_in = Z_NULL;
00078     d->zStream.avail_in = 0;
00079     if ( mode == IO_ReadOnly )
00080     {
00081         int result = inflateInit2(&d->zStream, -MAX_WBITS); // windowBits is passed < 0 to suppress zlib header
00082         if ( result != Z_OK )
00083             kdDebug(7005) << "inflateInit returned " << result << endl;
00084         // No idea what to do with result :)
00085     } else if ( mode == IO_WriteOnly )
00086     {
00087         int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); // same here
00088         if ( result != Z_OK )
00089             kdDebug(7005) << "deflateInit returned " << result << endl;
00090     } else {
00091         kdWarning(7005) << "KGzipFilter: Unsupported mode " << mode << ". Only IO_ReadOnly and IO_WriteOnly supported" << endl;
00092     }
00093     m_mode = mode;
00094     d->bCompressed = true;
00095     m_headerWritten = false;
00096 }
00097 
00098 void KGzipFilter::terminate()
00099 {
00100     if ( m_mode == IO_ReadOnly )
00101     {
00102         int result = inflateEnd(&d->zStream);
00103         if ( result != Z_OK )
00104             kdDebug(7005) << "inflateEnd returned " << result << endl;
00105     } else if ( m_mode == IO_WriteOnly )
00106     {
00107         int result = deflateEnd(&d->zStream);
00108         if ( result != Z_OK )
00109             kdDebug(7005) << "deflateEnd returned " << result << endl;
00110     }
00111 }
00112 
00113 
00114 void KGzipFilter::reset()
00115 {
00116     if ( m_mode == IO_ReadOnly )
00117     {
00118         int result = inflateReset(&d->zStream);
00119         if ( result != Z_OK )
00120             kdDebug(7005) << "inflateReset returned " << result << endl;
00121     } else if ( m_mode == IO_WriteOnly ) {
00122         int result = deflateReset(&d->zStream);
00123         if ( result != Z_OK )
00124             kdDebug(7005) << "deflateReset returned " << result << endl;
00125         m_headerWritten = false;
00126     }
00127 }
00128 
00129 bool KGzipFilter::readHeader()
00130 {
00131 #ifdef DEBUG_GZIP
00132     kdDebug(7005) << "KGzipFilter::readHeader avail=" << d->zStream.avail_in << endl;
00133 #endif
00134     // Assume not compressed until we successfully decode the header
00135     d->bCompressed = false;
00136     // Assume the first block of data contains the whole header.
00137     // The right way is to build this as a big state machine which
00138     // is a pain in the ass.
00139     // With 8K-blocks, we don't risk much anyway.
00140     Bytef *p = d->zStream.next_in;
00141     int i = d->zStream.avail_in;
00142     if ((i -= 10)  < 0) return false; // Need at least 10 bytes
00143 #ifdef DEBUG_GZIP
00144     kdDebug(7005) << "KGzipFilter::readHeader first byte is " << QString::number(*p,16) << endl;
00145 #endif
00146     if (*p++ != 0x1f) return false; // GZip magic
00147 #ifdef DEBUG_GZIP
00148     kdDebug(7005) << "KGzipFilter::readHeader second byte is " << QString::number(*p,16) << endl;
00149 #endif
00150     if (*p++ != 0x8b) return false;
00151     int method = *p++;
00152     int flags = *p++;
00153     if ((method != Z_DEFLATED) || (flags & RESERVED) != 0) return false;
00154     p += 6;
00155     if ((flags & EXTRA_FIELD) != 0) // skip extra field
00156     {
00157         if ((i -= 2) < 0) return false; // Need at least 2 bytes
00158         int len = *p++;
00159         len += (*p++) << 8;
00160         if ((i -= len) < 0) return false; // Need at least len bytes
00161         p += len;
00162     }
00163     if ((flags & ORIG_NAME) != 0) // skip original file name
00164     {
00165 #ifdef DEBUG_GZIP
00166         kdDebug(7005) << "ORIG_NAME=" << p << endl;
00167 #endif
00168         while( (i > 0) && (*p))
00169         {
00170             i--; p++;
00171         }
00172         if (--i <= 0) return false;
00173         p++;
00174     }
00175     if ((flags & COMMENT) != 0) // skip comment
00176     {
00177         while( (i > 0) && (*p))
00178         {
00179             i--; p++;
00180         }
00181         if (--i <= 0) return false;
00182         p++;
00183     }
00184     if ((flags & HEAD_CRC) != 0) // skip the header crc
00185     {
00186         if ((i-=2) < 0) return false;
00187         p += 2;
00188     }
00189 
00190     d->zStream.avail_in = i;
00191     d->zStream.next_in = p;
00192     d->bCompressed = true;
00193 #ifdef DEBUG_GZIP
00194     kdDebug(7005) << "header OK" << endl;
00195 #endif
00196     return true;
00197 }
00198 
00199 /* Output a 16 bit value, lsb first */
00200 #define put_short(w) \
00201     *p++ = (uchar) ((w) & 0xff); \
00202     *p++ = (uchar) ((ushort)(w) >> 8);
00203 
00204 /* Output a 32 bit value to the bit stream, lsb first */
00205 #define put_long(n) \
00206     put_short((n) & 0xffff); \
00207     put_short(((ulong)(n)) >> 16);
00208 
00209 bool KGzipFilter::writeHeader( const QCString & fileName )
00210 {
00211     Bytef *p = d->zStream.next_out;
00212     int i = d->zStream.avail_out;
00213     *p++ = 0x1f;
00214     *p++ = 0x8b;
00215     *p++ = Z_DEFLATED;
00216     *p++ = ORIG_NAME;
00217     put_long( time( 0L ) ); // Modification time (in unix format)
00218     *p++ = 0; // Extra flags (2=max compress, 4=fastest compress)
00219     *p++ = 3; // Unix
00220 
00221     uint len = fileName.length();
00222     for ( uint j = 0 ; j < len ; ++j )
00223         *p++ = fileName[j];
00224     *p++ = 0;
00225     int headerSize = p - d->zStream.next_out;
00226     i -= headerSize;
00227     Q_ASSERT(i>0);
00228     m_crc = crc32(0L, Z_NULL, 0);
00229     d->zStream.next_out = p;
00230     d->zStream.avail_out = i;
00231     m_headerWritten = true;
00232     return true;
00233 }
00234 
00235 void KGzipFilter::writeFooter()
00236 {
00237     Q_ASSERT( m_headerWritten );
00238     if (!m_headerWritten) kdDebug() << kdBacktrace();
00239     Bytef *p = d->zStream.next_out;
00240     int i = d->zStream.avail_out;
00241     //kdDebug(7005) << "KGzipFilter::writeFooter writing CRC= " << QString::number( m_crc, 16 ) << endl;
00242     put_long( m_crc );
00243     //kdDebug(7005) << "KGzipFilter::writing writing totalin= " << d->zStream.total_in << endl;
00244     put_long( d->zStream.total_in );
00245     i -= p - d->zStream.next_out;
00246     d->zStream.next_out = p;
00247     d->zStream.avail_out = i;
00248 }
00249 
00250 void KGzipFilter::setOutBuffer( char * data, uint maxlen )
00251 {
00252     d->zStream.avail_out = maxlen;
00253     d->zStream.next_out = (Bytef *) data;
00254 }
00255 void KGzipFilter::setInBuffer( const char * data, uint size )
00256 {
00257 #ifdef DEBUG_GZIP
00258     kdDebug(7005) << "KGzipFilter::setInBuffer avail_in=" << size << endl;
00259 #endif
00260     d->zStream.avail_in = size;
00261     d->zStream.next_in = (Bytef*) data;
00262 }
00263 int KGzipFilter::inBufferAvailable() const
00264 {
00265     return d->zStream.avail_in;
00266 }
00267 int KGzipFilter::outBufferAvailable() const
00268 {
00269     return d->zStream.avail_out;
00270 }
00271 
00272 KGzipFilter::Result KGzipFilter::uncompress_noop()
00273 {
00274     // I'm not sure we really need support for that (uncompressed streams),
00275     // but why not, it can't hurt to have it. One case I can think of is someone
00276     // naming a tar file "blah.tar.gz" :-)
00277     if ( d->zStream.avail_in > 0 )
00278     {
00279         int n = (d->zStream.avail_in < d->zStream.avail_out) ? d->zStream.avail_in : d->zStream.avail_out;
00280         memcpy( d->zStream.next_out, d->zStream.next_in, n );
00281         d->zStream.avail_out -= n;
00282         d->zStream.next_in += n;
00283         d->zStream.avail_in -= n;
00284         return OK;
00285     } else
00286         return END;
00287 }
00288 
00289 KGzipFilter::Result KGzipFilter::uncompress()
00290 {
00291     Q_ASSERT ( m_mode == IO_ReadOnly );
00292     if ( d->bCompressed )
00293     {
00294 #ifdef DEBUG_GZIP
00295         kdDebug(7005) << "Calling inflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable() << endl;
00296         kdDebug(7005) << "    next_in=" << d->zStream.next_in << endl;
00297 #endif
00298         int result = inflate(&d->zStream, Z_SYNC_FLUSH);
00299 #ifdef DEBUG_GZIP
00300         kdDebug(7005) << " -> inflate returned " << result << endl;
00301         kdDebug(7005) << "Now avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable() << endl;
00302         kdDebug(7005) << "    next_in=" << d->zStream.next_in << endl;
00303 #else
00304         if ( result != Z_OK && result != Z_STREAM_END )
00305             kdDebug(7005) << "Warning: inflate() returned " << result << endl;
00306 #endif
00307         return ( result == Z_OK ? OK : ( result == Z_STREAM_END ? END : ERROR ) );
00308     } else
00309         return uncompress_noop();
00310 }
00311 
00312 KGzipFilter::Result KGzipFilter::compress( bool finish )
00313 {
00314     Q_ASSERT ( d->bCompressed );
00315     Q_ASSERT ( m_mode == IO_WriteOnly );
00316 
00317     Bytef* p = d->zStream.next_in;
00318     ulong len = d->zStream.avail_in;
00319 #ifdef DEBUG_GZIP
00320     kdDebug(7005) << "  calling deflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable() << endl;
00321 #endif
00322     int result = deflate(&d->zStream, finish ? Z_FINISH : Z_NO_FLUSH);
00323     if ( result != Z_OK && result != Z_STREAM_END )
00324         kdDebug(7005) << "  deflate returned " << result << endl;
00325     if ( m_headerWritten )
00326     {
00327         //kdDebug(7005) << "Computing CRC for the next " << len - d->zStream.avail_in << " bytes" << endl;
00328         m_crc = crc32(m_crc, p, len - d->zStream.avail_in);
00329     }
00330     if ( result == Z_STREAM_END && m_headerWritten )
00331     {
00332         //kdDebug(7005) << "KGzipFilter::compress finished, write footer" << endl;
00333         writeFooter();
00334     }
00335     return ( result == Z_OK ? OK : ( result == Z_STREAM_END ? END : ERROR ) );
00336 }

kioslave

Skip menu "kioslave"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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