# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlCore/ZippedFile.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.com                                               */
    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/ZippedFile.hpp>
    00033 #include <vlCore/CRC32CheckSum.hpp>
    00034 #include <vlCore/Log.hpp>
    00035 #include <vlCore/Say.hpp>
    00036 #include <zlib.h>
    00037 #include <stdio.h>
    00038
    00039 using namespace vl;
    00040
    00041 namespace
    00042 {
    00043 //-----------------------------------------------------------------------------
    00044   inline int zcompress(FILE *source, FILE *dest, int level)
    00045   {
    00046     const int CHUNK_SIZE = 128*1024;
    00047     int ret, flush;
    00048     unsigned have;
    00049     z_stream strm;
    00050     unsigned char in[CHUNK_SIZE];
    00051     unsigned char out[CHUNK_SIZE];
    00052
    00053     strm.zalloc = Z_NULL;
    00054     strm.zfree = Z_NULL;
    00055     strm.opaque = Z_NULL;
    00056     ret = deflateInit(&strm, level);
    00057     if (ret != Z_OK)
    00058       return ret;
    00059
    00060     do
    00061     {
    00062       strm.avail_in = (uInt)fread(in, 1, CHUNK_SIZE, source);
    00063       if (ferror(source))
    00064       {
    00065         deflateEnd(&strm);
    00066         return Z_ERRNO;
    00067       }
    00068       flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
    00069       strm.next_in = in;
    00070
    00071       do
    00072       {
    00073         strm.avail_out = CHUNK_SIZE;
    00074         strm.next_out = out;
    00075
    00076         ret = deflate(&strm, flush);
    00077         VL_CHECK(ret != Z_STREAM_ERROR);
    00078
    00079         have = CHUNK_SIZE - strm.avail_out;
    00080         if (fwrite(out, 1, have, dest) != have || ferror(dest))
    00081         {
    00082           deflateEnd(&strm);
    00083           return Z_ERRNO;
    00084         }
    00085
    00086       } while (strm.avail_out == 0);
    00087
    00088       VL_CHECK(strm.avail_in == 0);
    00089
    00090     } while (flush != Z_FINISH);
    00091
    00092     VL_CHECK(ret == Z_STREAM_END);
    00093
    00094     (void)deflateEnd(&strm);
    00095     return Z_OK;
    00096   }
    00097 //-----------------------------------------------------------------------------
    00098   inline int zdecompress(FILE *source, FILE *dest)
    00099   {
    00100     const int CHUNK_SIZE = 128*1024;
    00101     int ret;
    00102     unsigned have;
    00103     z_stream strm;
    00104     unsigned char in[CHUNK_SIZE];
    00105     unsigned char out[CHUNK_SIZE];
    00106
    00107     strm.zalloc = Z_NULL;
    00108     strm.zfree = Z_NULL;
    00109     strm.opaque = Z_NULL;
    00110     strm.avail_in = 0;
    00111     strm.next_in = Z_NULL;
    00112     ret = inflateInit(&strm);
    00113     if (ret != Z_OK)
    00114         return ret;
    00115
    00116     do
    00117     {
    00118       strm.avail_in = (uInt)fread(in, 1, CHUNK_SIZE, source);
    00119       if (ferror(source))
    00120       {
    00121         inflateEnd(&strm);
    00122         return Z_ERRNO;
    00123       }
    00124       if (strm.avail_in == 0)
    00125         break;
    00126       strm.next_in = in;
    00127
    00128       do
    00129       {
    00130         strm.avail_out = CHUNK_SIZE;
    00131         strm.next_out = out;
    00132
    00133         ret = inflate(&strm, Z_NO_FLUSH);
    00134         VL_CHECK(ret != Z_STREAM_ERROR);
    00135         switch (ret)
    00136         {
    00137         case Z_NEED_DICT:
    00138           ret = Z_DATA_ERROR;
    00139         case Z_DATA_ERROR:
    00140         case Z_MEM_ERROR:
    00141           inflateEnd(&strm);
    00142           return ret;
    00143         }
    00144
    00145         have = CHUNK_SIZE - strm.avail_out;
    00146         if (fwrite(out, 1, have, dest) != have || ferror(dest))
    00147         {
    00148           inflateEnd(&strm);
    00149           return Z_ERRNO;
    00150         }
    00151       }
    00152       while (strm.avail_out == 0);
    00153
    00154       VL_CHECK(strm.avail_in == 0);
    00155
    00156     } while (ret != Z_STREAM_END);
    00157
    00158     inflateEnd(&strm);
    00159     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
    00160   }
    00161 //-----------------------------------------------------------------------------
    00162   inline int zdecompress(VirtualFile *source, char *dest, unsigned int bytes_to_read)
    00163   {
    00164     const unsigned int CHUNK_SIZE = 128*1024;
    00165     int ret;
    00166     unsigned have;
    00167     z_stream strm;
    00168     unsigned char in[CHUNK_SIZE];
    00169     unsigned char out[CHUNK_SIZE];
    00170
    00171     strm.zalloc = Z_NULL;
    00172     strm.zfree = Z_NULL;
    00173     strm.opaque = Z_NULL;
    00174     strm.avail_in = 0;
    00175     strm.next_in = Z_NULL;
    00176
    00177     ret = inflateInit2(&strm, -15);
    00178     if (ret != Z_OK)
    00179       return ret;
    00180
    00181     do
    00182     {
    00183       unsigned int byte_count = CHUNK_SIZE < bytes_to_read  ? CHUNK_SIZE : bytes_to_read;
    00184       strm.avail_in = (uInt)source->read(in, byte_count);
    00185       bytes_to_read -= strm.avail_in;
    00186
    00187       if (strm.avail_in == 0)
    00188         break;
    00189       strm.next_in = in;
    00190
    00191       do
    00192       {
    00193         strm.avail_out = CHUNK_SIZE;
    00194         strm.next_out = out;
    00195
    00196         ret = inflate(&strm, Z_NO_FLUSH);
    00197         VL_CHECK(ret != Z_STREAM_ERROR);
    00198         switch (ret)
    00199         {
    00200         case Z_NEED_DICT:
    00201           ret = Z_DATA_ERROR;
    00202         case Z_DATA_ERROR:
    00203         case Z_MEM_ERROR:
    00204           inflateEnd(&strm);
    00205           return ret;
    00206         }
    00207
    00208         have = CHUNK_SIZE - strm.avail_out;
    00209         memcpy(dest, out, have);
    00210         dest += have;
    00211       }
    00212       while (strm.avail_out == 0);
    00213
    00214       VL_CHECK(strm.avail_in == 0);
    00215
    00216     } while (ret != Z_STREAM_END);
    00217
    00218     inflateEnd(&strm);
    00219     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
    00220   }
    00221 }
    00222 //-----------------------------------------------------------------------------
    00223 // ZippedFile
    00224 //-----------------------------------------------------------------------------
    00225 ZippedFile::ZippedFile()
    00226 {
    00227   mReadBytes = -1;
    00228   mZStream = new z_stream_s;
    00229   memset(mZStream, 0, sizeof(z_stream_s));
    00230 }
    00231 //-----------------------------------------------------------------------------
    00232 ZippedFile::~ZippedFile()
    00233 {
    00234   close();
    00235   mReadBytes = -1;
    00236   delete mZStream; mZStream = NULL;
    00237 }
    00238 //-----------------------------------------------------------------------------
    00239 ZippedFileInfo* ZippedFile::zippedFileInfo() const { return mZippedFileInfo.get(); }
    00240 //-----------------------------------------------------------------------------
    00241 void ZippedFile::setZippedFileInfo(ZippedFileInfo* info) { mZippedFileInfo = info; }
    00242 //-----------------------------------------------------------------------------
    00243 bool ZippedFile::exists() const
    00244 {
    00245   return zippedFileInfo() && zippedFileInfo()->sourceZipFile() && zippedFileInfo()->zippedFileOffset();
    00246 }
    00247 //-----------------------------------------------------------------------------
    00248 bool ZippedFile::open(EOpenMode mode)
    00249 {
    00250   if ( zippedFileInfo()->versionNeeded() > 20 )
    00251   {
    00252     Log::error("ZippedFile::open(): unsupported archive version.\n");
    00253     return false;
    00254   }
    00255
    00256   /*if ( zippedFileInfo()->generalPurposeFlag() & 1 )
    00257   {
    00258     Log::error("ZippedFile::extract(): encription not supported.\n");
    00259     return false;
    00260   }*/
    00261
    00262   if ( zippedFileInfo()->compressionMethod() != 8 && zippedFileInfo()->compressionMethod() != 0 )
    00263   {
    00264     Log::error("ZippedFile::open(): unsupported compression method.\n");
    00265     return false;
    00266   }
    00267
    00268   if ( isOpen() )
    00269   {
    00270     Log::error("ZippedFile::open(): file already open.\n");
    00271     return false;
    00272   }
    00273
    00274   if ( mode != OM_ReadOnly )
    00275   {
    00276     Log::error("ZippedFile::open(): only OM_ReadOnly mode is supported.\n");
    00277     return false;
    00278   }
    00279
    00280   if ( !zippedFileInfo()->sourceZipFile() )
    00281   {
    00282     Log::error("ZippedFile::open(): no source zip stream defined.\n");
    00283     return false;
    00284   }
    00285
    00286   if ( zippedFileInfo()->sourceZipFile()->isOpen() )
    00287   {
    00288     Log::error("ZippedFile::open(): source zip stream is already open. Only one ZippedFile at a time can read from the same source.\n");
    00289     return false;
    00290   }
    00291
    00292   if ( !zippedFileInfo()->sourceZipFile()->open(mode) )
    00293   {
    00294     Log::error("ZippedFile::open(): could not open source zip stream.\n");
    00295     return false;
    00296   }
    00297
    00298   if ( !zippedFileInfo()->sourceZipFile()->seekSet( zippedFileInfo()->zippedFileOffset() ) )
    00299   {
    00300     Log::error("ZippedFile::open(): error seeking beginning of compressed file.\n");
    00301     zippedFileInfo()->sourceZipFile()->close();
    00302     return false;
    00303   }
    00304
    00305   /* inflate state */
    00306   mZStream->zalloc   = Z_NULL;
    00307   mZStream->zfree    = Z_NULL;
    00308   mZStream->opaque   = Z_NULL;
    00309   mZStream->avail_in = 0;
    00310   mZStream->next_in  = Z_NULL;
    00311   if ( zippedFileInfo()->compressionMethod() == 8 && inflateInit2(mZStream, -15) != Z_OK )
    00312   {
    00313     zippedFileInfo()->sourceZipFile()->close();
    00314     return false;
    00315   }
    00316
    00317   mReadBytes = 0;
    00318   mUncompressedBufferPtr = 0;
    00319   mUncompressedBuffer.clear();
    00320
    00321   return true;
    00322 }
    00323 //-----------------------------------------------------------------------------
    00324 bool ZippedFile::isOpen() const { return mReadBytes != -1; }
    00325 //-----------------------------------------------------------------------------
    00326 void ZippedFile::close()
    00327 {
    00328   if ( mZStream->next_in != Z_NULL )
    00329     inflateEnd(mZStream);
    00330   memset(mZStream, 0, sizeof(z_stream_s));
    00331   mReadBytes = -1;
    00332   if (zippedFileInfo() && zippedFileInfo()->sourceZipFile())
    00333     zippedFileInfo()->sourceZipFile()->close();
    00334   mUncompressedBufferPtr = 0;
    00335   mUncompressedBuffer.clear();
    00336 }
    00337 //-----------------------------------------------------------------------------
    00338 long long ZippedFile::size() const
    00339 {
    00340   if ( mZippedFileInfo )
    00341     return mZippedFileInfo->uncompressedSize();
    00342   else
    00343     return 0;
    00344 }
    00345 //-----------------------------------------------------------------------------
    00346 void ZippedFile::resetStream()
    00347 {
    00348   close();
    00349   open(OM_ReadOnly);
    00350 }
    00351 //-----------------------------------------------------------------------------
    00352 bool ZippedFile::seekSet_Implementation(long long pos)
    00353 {
    00354   if (pos<position())
    00355     resetStream();
    00356
    00357   unsigned char buffer[CHUNK_SIZE];
    00358   long long remained = pos - position();
    00359   long long eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
    00360   while ( (remained -= read(buffer, eat_bytes)) )
    00361     eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
    00362
    00363   return position() == pos;
    00364 }
    00365 //-----------------------------------------------------------------------------
    00366 long long ZippedFile::read_Implementation(void* buffer, long long bytes_to_read)
    00367 {
    00368   if ( bytes_to_read < 1 )
    00369     return 0;
    00370
    00371   if (!isOpen())
    00372     return 0;
    00373
    00374   if ( mReadBytes >= zippedFileInfo()->uncompressedSize() )
    00375     return 0;
    00376
    00377   if ( zippedFileInfo()->compressionMethod() == 0 )
    00378   {
    00379     long long bytes = zippedFileInfo()->uncompressedSize() - mReadBytes;
    00380     bytes = bytes < bytes_to_read ? bytes : bytes_to_read;
    00381     long long read_bytes = zippedFileInfo()->sourceZipFile()->read(buffer, bytes);
    00382     mReadBytes += read_bytes;
    00383     return read_bytes;
    00384   }
    00385   else
    00386   if ( zippedFileInfo()->compressionMethod() == 8 )
    00387   {
    00388
    00389     long long read_bytes = 0;
    00390
    00391     if ( mUncompressedBuffer.empty() )
    00392       fillUncompressedBuffer();
    00393
    00394     do
    00395     {
    00396       long long bytes = bytes_to_read < (int)mUncompressedBuffer.size()-mUncompressedBufferPtr ? bytes_to_read : (int)mUncompressedBuffer.size()-mUncompressedBufferPtr;
    00397       // copy uncompressed data
    00398       VL_CHECK( mUncompressedBufferPtr < (int)mUncompressedBuffer.size() )
    00399       if (bytes)
    00400         memcpy((char*)buffer+read_bytes, &mUncompressedBuffer[0]+mUncompressedBufferPtr, (size_t)bytes);
    00401
    00402       mReadBytes += bytes;
    00403       read_bytes += bytes;
    00404       mUncompressedBufferPtr += (int)bytes;
    00405       bytes_to_read -= bytes;
    00406       // remove read data from the buffer
    00407       // mUncompressedBuffer.erase( mUncompressedBuffer.begin(), mUncompressedBuffer.begin() + (size_t)bytes );
    00408       if(mUncompressedBufferPtr == (int)mUncompressedBuffer.size())
    00409       {
    00410         mUncompressedBuffer.clear();
    00411         mUncompressedBufferPtr = 0;
    00412       }
    00413
    00414     } while( bytes_to_read && fillUncompressedBuffer() );
    00415
    00416     return read_bytes;
    00417   }
    00418   else
    00419     return 0;
    00420 }
    00421 //-----------------------------------------------------------------------------
    00422 bool ZippedFile::extract(char* destination, bool check_sum)
    00423 {
    00424   ZippedFileInfo* zfile_info = zippedFileInfo();
    00425
    00426   if ( zfile_info->mUncompressedSize == 0 )
    00427     return true;
    00428
    00429   if (isOpen())
    00430   {
    00431     Log::error("ZippedFile::extract(): the file is already open.\n");
    00432     return false;
    00433   }
    00434
    00435   if ( zfile_info->versionNeeded() > 20 )
    00436   {
    00437     Log::error("ZippedFile::extract(): unsupported archive version.\n");
    00438     return false;
    00439   }
    00440
    00441   if ( zfile_info->generalPurposeFlag() & 1 )
    00442   {
    00443     Log::error("ZippedFile::extract(): encription not supported.\n");
    00444     return false;
    00445   }
    00446
    00447   ref<VirtualFile> zip = zfile_info->sourceZipFile();
    00448
    00449   if ( !zip )
    00450   {
    00451     Log::error("ZippedFile::extract(): no source zip stream defined.\n");
    00452     return false;
    00453   }
    00454
    00455   if ( zip->isOpen() )
    00456   {
    00457     Log::error("ZippedFile::extract(): source zip stream is already open. Only one ZippedFile at a time can read from the same source.\n");
    00458     return false;
    00459   }
    00460
    00461   if ( !zip->open(OM_ReadOnly) )
    00462   {
    00463     Log::error("ZippedFile::extract(): could not open source zip stream.\n");
    00464     return false;
    00465   }
    00466
    00467   if ( !zip->seekSet( zfile_info->zippedFileOffset() ) )
    00468   {
    00469     Log::error("ZippedFile::extract(): not a seek-able zip stream.\n");
    00470     zip->close();
    00471     return false;
    00472   }
    00473
    00474   switch(zfile_info->mCompressionMethod)
    00475   {
    00476     default:
    00477       Log::error("ZippedFile::extract(): unsupported compression method.\n");
    00478       break;
    00479     case 0: // store
    00480     case 8: // deflate 32K
    00481     {
    00482       if (zfile_info->mCompressionMethod == 8)
    00483         zdecompress( zip.get(), destination, zfile_info->mCompressedSize );
    00484       else
    00485       if (zfile_info->mCompressionMethod == 0)
    00486         zip->read( destination, zfile_info->mUncompressedSize );
    00487
    00488       if (check_sum)
    00489       {
    00490         CRC32CheckSum checksum;
    00491         unsigned int crc = checksum.compute( destination, (int)zfile_info->mUncompressedSize );
    00492         // printf("crc = 0x%08x | 0x%08x -> %s\n", crc, zfile_info->mCRC32, zfile_info->mCRC32 == crc ? "MATCH" : "ERROR!");
    00493         VL_CHECK( zfile_info->mCRC32 == crc );
    00494         if ( zfile_info->mCRC32 != crc )
    00495         {
    00496           zip->close();
    00497           return false;
    00498         }
    00499       }
    00500     }
    00501   }
    00502
    00503   zip->close();
    00504   return true;
    00505 }
    00506 //-----------------------------------------------------------------------------
    00507 bool ZippedFile::fillUncompressedBuffer()
    00508 {
    00509   VL_CHECK(mUncompressedBufferPtr == (int)mUncompressedBuffer.size())
    00510
    00511   VL_CHECK( mUncompressedBuffer.empty() )
    00512
    00513   mUncompressedBufferPtr = 0;
    00514
    00515   if (!isOpen())
    00516     return false;
    00517
    00518   if ( mReadBytes >= zippedFileInfo()->uncompressedSize() )
    00519     return false;
    00520
    00521   int have = 0;
    00522   int ret  = 0;
    00523
    00524   unsigned int compressed_read_bytes = (int)(zippedFileInfo()->sourceZipFile()->position() - zippedFileInfo()->zippedFileOffset());
    00525
    00526   int bytes_to_read = (unsigned)CHUNK_SIZE < (zippedFileInfo()->compressedSize() - compressed_read_bytes)?
    00527                       (unsigned)CHUNK_SIZE : (zippedFileInfo()->compressedSize() - compressed_read_bytes);
    00528   mZStream->avail_in = (uInt)zippedFileInfo()->sourceZipFile()->read(mZipBufferIn, bytes_to_read);
    00529
    00530   if (mZStream->avail_in == 0)
    00531     return false;
    00532   mZStream->next_in = mZipBufferIn;
    00533
    00534   do
    00535   {
    00536     mZStream->avail_out = CHUNK_SIZE;
    00537     mZStream->next_out  = mZipBufferOut;
    00538
    00539     ret = inflate(mZStream, Z_NO_FLUSH);
    00540     VL_CHECK(ret != Z_STREAM_ERROR);
    00541     switch (ret)
    00542     {
    00543     case Z_NEED_DICT:
    00544     case Z_DATA_ERROR:
    00545     case Z_MEM_ERROR:
    00546         inflateEnd(mZStream);
    00547         memset(mZStream, 0, sizeof(z_stream_s));
    00548         Log::error("ZippedFile::read(): error reading zip stream.\n");
    00549         return false;
    00550     }
    00551
    00552     have = CHUNK_SIZE - mZStream->avail_out;
    00553     if (!have)
    00554       break;
    00555     int start = (int)mUncompressedBuffer.size();
    00556     mUncompressedBuffer.resize(start + have);
    00557     memcpy(&mUncompressedBuffer[0] + start, mZipBufferOut, have);
    00558   }
    00559   while ( mZStream->avail_out == 0 );
    00560
    00561   return true;
    00562 }
    00563 //-----------------------------------------------------------------------------
    00564 ref<VirtualFile> ZippedFile::clone() const
    00565 {
    00566   ref<ZippedFile> file = new ZippedFile;
    00567   file->operator=(*this);
    00568   return file;
    00569 }
    00570 //-----------------------------------------------------------------------------

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:22.
Permission is granted to use this page to write and publish articles regarding Visualization Library.