kioslave
kgzipfilter.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 "kgzipfilter.h"
00020 #include <time.h>
00021 #include <zlib.h>
00022 #include <kdebug.h>
00023 #include <klibloader.h>
00024
00025
00026 #define ASCII_FLAG 0x01
00027 #define HEAD_CRC 0x02
00028 #define EXTRA_FIELD 0x04
00029 #define ORIG_NAME 0x08
00030 #define COMMENT 0x10
00031 #define RESERVED 0xE0
00032
00033
00034
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
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);
00082 if ( result != Z_OK )
00083 kdDebug(7005) << "inflateInit returned " << result << endl;
00084
00085 } else if ( mode == IO_WriteOnly )
00086 {
00087 int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
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
00135 d->bCompressed = false;
00136
00137
00138
00139
00140 Bytef *p = d->zStream.next_in;
00141 int i = d->zStream.avail_in;
00142 if ((i -= 10) < 0) return false;
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;
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)
00156 {
00157 if ((i -= 2) < 0) return false;
00158 int len = *p++;
00159 len += (*p++) << 8;
00160 if ((i -= len) < 0) return false;
00161 p += len;
00162 }
00163 if ((flags & ORIG_NAME) != 0)
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)
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)
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
00200 #define put_short(w) \
00201 *p++ = (uchar) ((w) & 0xff); \
00202 *p++ = (uchar) ((ushort)(w) >> 8);
00203
00204
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 ) );
00218 *p++ = 0;
00219 *p++ = 3;
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
00242 put_long( m_crc );
00243
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
00275
00276
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
00328 m_crc = crc32(m_crc, p, len - d->zStream.avail_in);
00329 }
00330 if ( result == Z_STREAM_END && m_headerWritten )
00331 {
00332
00333 writeFooter();
00334 }
00335 return ( result == Z_OK ? OK : ( result == Z_STREAM_END ? END : ERROR ) );
00336 }