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
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlCore/VisualizationLibrary.hpp>
00033 #include <vlCore/GZipCodec.hpp>
00034 #include <vlCore/Log.hpp>
00035 #include <vlCore/Say.hpp>
00036 #include <zlib.h>
00037
00038 using namespace vl;
00039
00040
00041
00042
00043 GZipCodec::GZipCodec(VirtualFile* stream): mStream(stream)
00044 {
00045 mCompressionLevel = 6;
00046 mReadBytes = -1;
00047 mWrittenBytes = -1;
00048 mZStream = new z_stream_s;
00049 memset(mZStream, 0, sizeof(z_stream_s));
00050 mUncompressedSize = -1;
00051 mWarnOnSeek = true;
00052 }
00053
00054 GZipCodec::GZipCodec(const String& gz_path): mStream(NULL)
00055 {
00056 mCompressionLevel = 6;
00057 mReadBytes = -1;
00058 mWrittenBytes = -1;
00059 mZStream = new z_stream_s;
00060 memset(mZStream, 0, sizeof(z_stream_s));
00061 mUncompressedSize = -1;
00062 setPath(gz_path);
00063 mWarnOnSeek = true;
00064 }
00065
00066 GZipCodec::~GZipCodec()
00067 {
00068 close();
00069 delete mZStream; mZStream = NULL;
00070 mUncompressedSize = -1;
00071 mWrittenBytes = -1;
00072 }
00073
00074 bool GZipCodec::open(EOpenMode mode)
00075 {
00076 if (isOpen())
00077 {
00078 Log::error("GZipCodec::open(): file already open.\n");
00079 return false;
00080 }
00081 switch(mode)
00082 {
00083 case OM_ReadOnly: mMode = ZDecompress; break;
00084 case OM_WriteOnly: mMode = ZCompress; break;
00085 default: mMode = ZNone;
00086 }
00087 mReadBytes = 0;
00088 mWrittenBytes = 0;
00089 mUncompressedBufferPtr = 0;
00090 mUncompressedBuffer.clear();
00091
00092 memset(mZStream, 0, sizeof(z_stream_s));
00093 mZStream->zalloc = Z_NULL;
00094 mZStream->zfree = Z_NULL;
00095 mZStream->opaque = Z_NULL;
00096 mZStream->avail_in = 0;
00097 mZStream->next_in = Z_NULL;
00098 if (mMode == ZDecompress)
00099 {
00100 if ( inflateInit2(mZStream, 15+32) != Z_OK )
00101 {
00102 Log::error("GZipCodec::open(): inflateInit2 failed.\n");
00103 return false;
00104 }
00105 }
00106 else
00107 if (mMode == ZCompress)
00108 {
00109 if (deflateInit2(mZStream, compressionLevel(), Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
00110 {
00111 Log::error("GZipCodec::open(): deflateInit2 failed.\n");
00112 return false;
00113 }
00114 }
00115 if (!stream() && !path().empty())
00116 {
00117 ref<VirtualFile> file = vl::locateFile(path());
00118 setStream(file.get());
00119 }
00120 if (!stream())
00121 {
00122 Log::error("GZipCodec::open(): no input or output stream defined. See the setStream() method documentation.\n");
00123 return false;
00124 }
00125 if (!stream()->open(mode))
00126 {
00127 Log::error("GZipCodec::open(): input or output stream open failed.\n");
00128 return false;
00129 }
00130 mStreamSize = stream()->size();
00131 return true;
00132 }
00133
00134 void GZipCodec::close()
00135 {
00136 if ( mMode == ZDecompress )
00137 inflateEnd(mZStream);
00138 else
00139 if ( mMode == ZCompress )
00140 {
00141
00142 unsigned char next_out[CHUNK_SIZE];
00143 unsigned char dummy_buffer=0;
00144 mZStream->avail_in = 0;
00145 mZStream->next_in = (Bytef*)&dummy_buffer;
00146 do
00147 {
00148 mZStream->avail_out = CHUNK_SIZE;
00149 mZStream->next_out = next_out;
00150 int ret = deflate(mZStream, Z_FINISH);
00151 if (ret == Z_STREAM_ERROR)
00152 {
00153 Log::error("GZStream::write(): Z_STREAM_ERROR.\n");
00154 deflateEnd(mZStream);
00155 memset(mZStream, 0, sizeof(z_stream_s));
00156 break;
00157 }
00158 unsigned have = CHUNK_SIZE - mZStream->avail_out;
00159 if (have>0)
00160 {
00161 long long written = stream()->write(next_out, have);
00162 if (written < have)
00163 Log::error("GZStream: write failed.\n");
00164 }
00165 } while (mZStream->avail_out == 0);
00166 deflateEnd(mZStream);
00167 }
00168 if (stream())
00169 stream()->close();
00170 memset(mZStream, 0, sizeof(z_stream_s));
00171 mMode = ZNone;
00172 mReadBytes = -1;
00173 mWrittenBytes = -1;
00174 mUncompressedBufferPtr = 0;
00175 mUncompressedBuffer.clear();
00176 }
00177
00178 ref<VirtualFile> GZipCodec::clone() const
00179 {
00180 ref<GZipCodec> file = new GZipCodec;
00181 file->operator=(*this);
00182 return file;
00183 }
00184
00185 GZipCodec& GZipCodec::operator=(const GZipCodec& other)
00186 {
00187 close();
00188 super::operator=(other);
00189 mCompressionLevel = other.mCompressionLevel;
00190 if (other.mStream)
00191 mStream = other.mStream->clone();
00192 return *this;
00193 }
00194
00195 long long GZipCodec::read_Implementation(void* buffer, long long bytes_to_read)
00196 {
00197 if ( bytes_to_read < 1 )
00198 return 0;
00199 if (!isOpen())
00200 {
00201 Log::error("GZStream::read(): read requested on closed stream.\n");
00202 return 0;
00203 }
00204
00205
00206 long long read_bytes = 0;
00207 if ( mUncompressedBuffer.empty() )
00208 fillUncompressedBuffer();
00209 if ( mUncompressedBuffer.empty() )
00210 return 0;
00211 do
00212 {
00213 long long bytes = bytes_to_read < (int)mUncompressedBuffer.size()-mUncompressedBufferPtr ? bytes_to_read : (int)mUncompressedBuffer.size()-mUncompressedBufferPtr;
00214
00215 VL_CHECK( mUncompressedBufferPtr < (int)mUncompressedBuffer.size() )
00216 if (bytes)
00217 memcpy((char*)buffer+read_bytes, &mUncompressedBuffer[0]+mUncompressedBufferPtr, (size_t)bytes);
00218 mReadBytes += bytes;
00219 read_bytes += bytes;
00220 mUncompressedBufferPtr += (int)bytes;
00221 bytes_to_read -= bytes;
00222
00223
00224 if(mUncompressedBufferPtr == (int)mUncompressedBuffer.size())
00225 {
00226 mUncompressedBuffer.clear();
00227 mUncompressedBufferPtr = 0;
00228 }
00229 } while( bytes_to_read && fillUncompressedBuffer() && !mUncompressedBuffer.empty() );
00230 return read_bytes;
00231 }
00232
00233 long long GZipCodec::write_Implementation(const void* buffer, long long byte_count)
00234 {
00235 unsigned char next_out[CHUNK_SIZE];
00236 mZStream->avail_in = (uInt)byte_count;
00237 mZStream->next_in = (Bytef*)buffer;
00238 do
00239 {
00240 mZStream->avail_out = CHUNK_SIZE;
00241 mZStream->next_out = next_out;
00242 int ret = deflate(mZStream, Z_NO_FLUSH);
00243 if (ret == Z_STREAM_ERROR)
00244 {
00245 Log::error("GZStream::write(): Z_STREAM_ERROR.\n");
00246 return 0;
00247 }
00248 unsigned have = CHUNK_SIZE - mZStream->avail_out;
00249 if (have>0)
00250 {
00251 long long written = stream()->write(next_out, have);
00252 if (written < have)
00253 Log::error("GZStream: write failed.\n");
00254 }
00255 } while (mZStream->avail_out == 0);
00256 mWrittenBytes += byte_count;
00257 return byte_count;
00258 }
00259
00260 long long GZipCodec::position_Implementation() const
00261 {
00262 return mReadBytes;
00263 }
00264
00265 void GZipCodec::resetStream()
00266 {
00267 close();
00268 open(OM_ReadOnly);
00269 }
00270
00271 bool GZipCodec::seekSet_Implementation(long long pos)
00272 {
00273 if (mMode == ZDecompress)
00274 {
00275 if (warnOnSeek())
00276 Log::print( Say("Performance warning: GZipCodec::seek() requested for file %s. For maximum performances avoid seeking a GZipCodec, especially avoid seeking backwards.\n") << path() );
00277
00278 if (pos<position())
00279 resetStream();
00280
00281 unsigned char buffer[CHUNK_SIZE];
00282 long long remained = pos - position();
00283 long long eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
00284 while ( (remained -= read(buffer, eat_bytes)) )
00285 eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
00286 return position() == pos;
00287 }
00288 else
00289 {
00290 Log::error("GZStream: seek supported only by OM_ReadOnly open mode.\n");
00291 return false;
00292 }
00293 }
00294
00295 bool GZipCodec::fillUncompressedBuffer()
00296 {
00297 VL_CHECK(mUncompressedBufferPtr == (int)mUncompressedBuffer.size())
00298 VL_CHECK( mUncompressedBuffer.empty() )
00299 mUncompressedBufferPtr = 0;
00300 VL_CHECK(isOpen())
00301
00302
00303
00304
00305 int have = 0;
00306 int ret = 0;
00307
00308 long long bytes_to_read = CHUNK_SIZE < (mStreamSize - stream()->position())?
00309 CHUNK_SIZE : (mStreamSize - stream()->position());
00310 mZStream->avail_in = (uInt)stream()->read(mZipBufferIn, bytes_to_read);
00311 if (mZStream->avail_in == 0)
00312 return true;
00313 mZStream->next_in = mZipBufferIn;
00314 do
00315 {
00316 mZStream->avail_out = CHUNK_SIZE;
00317 mZStream->next_out = mZipBufferOut;
00318 ret = inflate(mZStream, Z_NO_FLUSH);
00319 switch (ret)
00320 {
00321 case Z_STREAM_ERROR:
00322 case Z_NEED_DICT:
00323 case Z_DATA_ERROR:
00324 case Z_MEM_ERROR:
00325 close();
00326 Log::error("GZStream: error reading gzip stream.\n");
00327 return false;
00328 }
00329 have = CHUNK_SIZE - mZStream->avail_out;
00330 if (!have)
00331 break;
00332 int start = (int)mUncompressedBuffer.size();
00333 mUncompressedBuffer.resize(start + have);
00334 memcpy(&mUncompressedBuffer[0] + start, mZipBufferOut, have);
00335 }
00336 while ( mZStream->avail_out == 0 );
00337 return true;
00338 }
00339
00340 long long GZipCodec::uncompressedSize()
00341 {
00342 if (mMode == ZDecompress || mMode == ZNone)
00343 {
00344 if (stream() && mUncompressedSize == -1)
00345 {
00346 if (stream()->isOpen())
00347 {
00348 long long pos = stream()->position();
00349 stream()->seekEnd(-4);
00350 mUncompressedSize = stream()->readUInt32();
00351 stream()->seekSet(pos);
00352 }
00353 else
00354 {
00355 stream()->open(OM_ReadOnly);
00356 stream()->seekEnd(-4);
00357 mUncompressedSize = stream()->readUInt32();
00358 stream()->close();
00359 }
00360 }
00361 return mUncompressedSize;
00362 }
00363 else
00364 return -1;
00365 }
00366
00367 long long GZipCodec::size() const
00368 {
00369 if (mMode == ZCompress)
00370 return mWrittenBytes;
00371 else
00372 return const_cast<GZipCodec*>(this)->uncompressedSize();
00373 }
00374
00375 void GZipCodec::setStream(VirtualFile* str)
00376 {
00377 if (stream() && stream()->isOpen())
00378 stream()->close();
00379 mStream = str;
00380 mUncompressedSize = -1;
00381 mWrittenBytes = -1;
00382 setPath( str ? str->path() : String() );
00383 }
00384
00385 float GZipCodec::compressionRatio() const
00386 {
00387 double comp = (double)compressedSize();
00388 double unco = (double)size();
00389 return float(comp/unco);
00390 }
00391