Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/GZipCodec.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
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 // GZipCodec
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   /* z_stream_s */
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/*autodected gzip header*/) != 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/*gz compression*/, 8/*mem level*/, 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     // flush data
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   /*if ( mReadBytes >= ??? )
00205     return 0;*/
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     // copy uncompressed data
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     // remove read data from the buffer
00223     // mUncompressedBuffer.erase( mUncompressedBuffer.begin(), mUncompressedBuffer.begin() + (size_t)bytes );
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   /*if (!isOpen())
00302     return false;*/
00303   /*if ( mReadBytes >= ??? )
00304     return false;*/
00305   int have = 0;
00306   int ret  = 0;
00307   /*long long compressed_read_bytes = stream()->position();*/
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 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:29.
Permission is granted to use this page to write and publish articles regarding Visualization Library.