Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://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 //-----------------------------------------------------------------------------