Visualization Library 2.1.0

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

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
GZipCodec.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
33 #include <vlCore/GZipCodec.hpp>
34 #include <vlCore/Log.hpp>
35 #include <vlCore/Say.hpp>
36 #include "zlib.h"
37 
38 using namespace vl;
39 
40 //-----------------------------------------------------------------------------
41 // GZipCodec
42 //-----------------------------------------------------------------------------
43 GZipCodec::GZipCodec(VirtualFile* stream): mStream(stream)
44 {
46  mReadBytes = -1;
47  mWrittenBytes = -1;
48  mZStream = new z_stream_s;
49  memset(mZStream, 0, sizeof(z_stream_s));
50  mUncompressedSize = -1;
51  mWarnOnSeek = true;
52 }
53 //-----------------------------------------------------------------------------
55 {
57  mReadBytes = -1;
58  mWrittenBytes = -1;
59  mZStream = new z_stream_s;
60  memset(mZStream, 0, sizeof(z_stream_s));
61  mUncompressedSize = -1;
62  setPath(gz_path);
63  mWarnOnSeek = true;
64 }
65 //-----------------------------------------------------------------------------
67 {
68  close();
69  delete mZStream; mZStream = NULL;
70  mUncompressedSize = -1;
71  mWrittenBytes = -1;
72 }
73 //-----------------------------------------------------------------------------
75 {
76  if (isOpen())
77  {
78  Log::error("GZipCodec::open(): file already open.\n");
79  return false;
80  }
81  switch(mode)
82  {
83  case OM_ReadOnly: mMode = ZDecompress; break;
84  case OM_WriteOnly: mMode = ZCompress; break;
85  default: mMode = ZNone;
86  }
87  mReadBytes = 0;
88  mWrittenBytes = 0;
90  mUncompressedBuffer.clear();
91  /* z_stream_s */
92  memset(mZStream, 0, sizeof(z_stream_s));
93  mZStream->zalloc = Z_NULL;
94  mZStream->zfree = Z_NULL;
95  mZStream->opaque = Z_NULL;
96  mZStream->avail_in = 0;
97  mZStream->next_in = Z_NULL;
98  if (mMode == ZDecompress)
99  {
100  if ( inflateInit2(mZStream, 15+32/*autodected gzip header*/) != Z_OK )
101  {
102  Log::error("GZipCodec::open(): inflateInit2 failed.\n");
103  return false;
104  }
105  }
106  else
107  if (mMode == ZCompress)
108  {
109  if (deflateInit2(mZStream, compressionLevel(), Z_DEFLATED, 15+16/*gz compression*/, 8/*mem level*/, Z_DEFAULT_STRATEGY) != Z_OK)
110  {
111  Log::error("GZipCodec::open(): deflateInit2 failed.\n");
112  return false;
113  }
114  }
115  if (!stream() && !path().empty())
116  {
118  setStream(file.get());
119  }
120  if (!stream())
121  {
122  Log::error("GZipCodec::open(): no input or output stream defined. See the setStream() method documentation.\n");
123  return false;
124  }
125  if (!stream()->open(mode))
126  {
127  Log::error("GZipCodec::open(): input or output stream open failed.\n");
128  return false;
129  }
130  mStreamSize = stream()->size();
131  return true;
132 }
133 //-----------------------------------------------------------------------------
135 {
136  if ( mMode == ZDecompress )
137  inflateEnd(mZStream);
138  else
139  if ( mMode == ZCompress )
140  {
141  // flush data
142  unsigned char next_out[CHUNK_SIZE];
143  unsigned char dummy_buffer=0;
144  mZStream->avail_in = 0;
145  mZStream->next_in = (Bytef*)&dummy_buffer;
146  do
147  {
148  mZStream->avail_out = CHUNK_SIZE;
149  mZStream->next_out = next_out;
150  int ret = deflate(mZStream, Z_FINISH);
151  if (ret == Z_STREAM_ERROR)
152  {
153  Log::error("GZStream::write(): Z_STREAM_ERROR.\n");
154  deflateEnd(mZStream);
155  memset(mZStream, 0, sizeof(z_stream_s));
156  break;
157  }
158  unsigned have = CHUNK_SIZE - mZStream->avail_out;
159  if (have>0)
160  {
161  long long written = stream()->write(next_out, have);
162  if (written < have)
163  Log::error("GZStream: write failed.\n");
164  }
165  } while (mZStream->avail_out == 0);
166  deflateEnd(mZStream);
167  }
168  if (stream())
169  stream()->close();
170  memset(mZStream, 0, sizeof(z_stream_s));
171  mMode = ZNone;
172  mReadBytes = -1;
173  mWrittenBytes = -1;
175  mUncompressedBuffer.clear();
176 }
177 //-----------------------------------------------------------------------------
179 {
180  ref<GZipCodec> file = new GZipCodec;
181  file->operator=(*this);
182  return file;
183 }
184 //-----------------------------------------------------------------------------
186 {
187  close();
188  super::operator=(other);
190  if (other.mStream)
191  mStream = other.mStream->clone();
192  return *this;
193 }
194 //-----------------------------------------------------------------------------
195 long long GZipCodec::read_Implementation(void* buffer, long long bytes_to_read)
196 {
197  if ( bytes_to_read < 1 )
198  return 0;
199  if (!isOpen())
200  {
201  Log::error("GZStream::read(): read requested on closed stream.\n");
202  return 0;
203  }
204  /*if ( mReadBytes >= ??? )
205  return 0;*/
206  long long read_bytes = 0;
207  if ( mUncompressedBuffer.empty() )
209  if ( mUncompressedBuffer.empty() )
210  return 0;
211  do
212  {
213  long long bytes = bytes_to_read < (int)mUncompressedBuffer.size()-mUncompressedBufferPtr ? bytes_to_read : (int)mUncompressedBuffer.size()-mUncompressedBufferPtr;
214  // copy uncompressed data
216  if (bytes)
217  memcpy((char*)buffer+read_bytes, &mUncompressedBuffer[0]+mUncompressedBufferPtr, (size_t)bytes);
218  mReadBytes += bytes;
219  read_bytes += bytes;
220  mUncompressedBufferPtr += (int)bytes;
221  bytes_to_read -= bytes;
222  // remove read data from the buffer
223  // mUncompressedBuffer.erase( mUncompressedBuffer.begin(), mUncompressedBuffer.begin() + (size_t)bytes );
225  {
226  mUncompressedBuffer.clear();
228  }
229  } while( bytes_to_read && fillUncompressedBuffer() && !mUncompressedBuffer.empty() );
230  return read_bytes;
231 }
232 //-----------------------------------------------------------------------------
233 long long GZipCodec::write_Implementation(const void* buffer, long long byte_count)
234 {
235  unsigned char next_out[CHUNK_SIZE];
236  mZStream->avail_in = (uInt)byte_count;
237  mZStream->next_in = (Bytef*)buffer;
238  do
239  {
240  mZStream->avail_out = CHUNK_SIZE;
241  mZStream->next_out = next_out;
242  int ret = deflate(mZStream, Z_NO_FLUSH);
243  if (ret == Z_STREAM_ERROR)
244  {
245  Log::error("GZStream::write(): Z_STREAM_ERROR.\n");
246  return 0;
247  }
248  unsigned have = CHUNK_SIZE - mZStream->avail_out;
249  if (have>0)
250  {
251  long long written = stream()->write(next_out, have);
252  if (written < have)
253  Log::error("GZStream: write failed.\n");
254  }
255  } while (mZStream->avail_out == 0);
256  mWrittenBytes += byte_count;
257  return byte_count;
258 }
259 //-----------------------------------------------------------------------------
261 {
262  return mReadBytes;
263 }
264 //-----------------------------------------------------------------------------
266 {
267  close();
268  open(OM_ReadOnly);
269 }
270 //-----------------------------------------------------------------------------
272 {
273  if (mMode == ZDecompress)
274  {
275  if (warnOnSeek())
276  Log::print( Say("Performance warning: GZipCodec::seek() requested for file %s. For maximum performances avoid seeking a GZipCodec, especially avoid seeking backwards.\n") << path() );
277 
278  if (pos<position())
279  resetStream();
280 
281  unsigned char buffer[CHUNK_SIZE];
282  long long remained = pos - position();
283  long long eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
284  while ( (remained -= read(buffer, eat_bytes)) )
285  eat_bytes = remained < CHUNK_SIZE ? remained : CHUNK_SIZE;
286  return position() == pos;
287  }
288  else
289  {
290  Log::error("GZStream: seek supported only by OM_ReadOnly open mode.\n");
291  return false;
292  }
293 }
294 //-----------------------------------------------------------------------------
296 {
298  VL_CHECK( mUncompressedBuffer.empty() )
300  VL_CHECK(isOpen())
301  /*if (!isOpen())
302  return false;*/
303  /*if ( mReadBytes >= ??? )
304  return false;*/
305  int have = 0;
306  int ret = 0;
307  /*long long compressed_read_bytes = stream()->position();*/
308  long long bytes_to_read = CHUNK_SIZE < (mStreamSize - stream()->position())?
309  CHUNK_SIZE : (mStreamSize - stream()->position());
310  mZStream->avail_in = (uInt)stream()->read(mZipBufferIn, bytes_to_read);
311  if (mZStream->avail_in == 0)
312  return true;
313  mZStream->next_in = mZipBufferIn;
314  do
315  {
316  mZStream->avail_out = CHUNK_SIZE;
317  mZStream->next_out = mZipBufferOut;
318  ret = inflate(mZStream, Z_NO_FLUSH);
319  switch (ret)
320  {
321  case Z_STREAM_ERROR:
322  case Z_NEED_DICT:
323  case Z_DATA_ERROR:
324  case Z_MEM_ERROR:
325  close();
326  Log::error("GZStream: error reading gzip stream.\n");
327  return false;
328  }
329  have = CHUNK_SIZE - mZStream->avail_out;
330  if (!have)
331  break;
332  int start = (int)mUncompressedBuffer.size();
333  mUncompressedBuffer.resize(start + have);
334  memcpy(&mUncompressedBuffer[0] + start, mZipBufferOut, have);
335  }
336  while ( mZStream->avail_out == 0 );
337  return true;
338 }
339 //-----------------------------------------------------------------------------
341 {
342  if (mMode == ZDecompress || mMode == ZNone)
343  {
344  if (stream() && mUncompressedSize == -1)
345  {
346  if (stream()->isOpen())
347  {
348  long long pos = stream()->position();
349  stream()->seekEnd(-4);
351  stream()->seekSet(pos);
352  }
353  else
354  {
355  stream()->open(OM_ReadOnly);
356  stream()->seekEnd(-4);
358  stream()->close();
359  }
360  }
361  return mUncompressedSize;
362  }
363  else
364  return -1;
365 }
366 //-----------------------------------------------------------------------------
367 long long GZipCodec::size() const
368 {
369  if (mMode == ZCompress)
370  return mWrittenBytes;
371  else
372  return const_cast<GZipCodec*>(this)->uncompressedSize();
373 }
374 //-----------------------------------------------------------------------------
376 {
377  if (stream() && stream()->isOpen())
378  stream()->close();
379  mStream = str;
380  mUncompressedSize = -1;
381  mWrittenBytes = -1;
382  setPath( str ? str->path() : String() );
383 }
384 //-----------------------------------------------------------------------------
386 {
387  double comp = (double)compressedSize();
388  double unco = (double)size();
389  return float(comp/unco);
390 }
391 //-----------------------------------------------------------------------------
long long read(void *buffer, long long byte_count)
Reads byte_count bytes from a file. Returns the number of bytes actually read.
Definition: VirtualFile.cpp:82
int mUncompressedBufferPtr
Definition: GZipCodec.hpp:132
virtual long long write_Implementation(const void *buffer, long long byte_count)
Definition: GZipCodec.cpp:233
long long compressedSize() const
Returns the size of the compressed stream as returned by stream()->size().
Definition: GZipCodec.hpp:104
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
virtual long long size() const
Returns the uncompressed size of the stream. This is not a thread safe function.
Definition: GZipCodec.cpp:367
A simple String formatting class.
Definition: Say.hpp:124
virtual bool open(EOpenMode mode)
Opens a compressed stream.
Definition: GZipCodec.cpp:74
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
bool seekSet_Implementation(long long pos)
Definition: GZipCodec.cpp:271
bool fillUncompressedBuffer()
Definition: GZipCodec.cpp:295
void setStream(VirtualFile *stream)
Installs the VirtualFile representing the GZip file to be read or to be written.
Definition: GZipCodec.cpp:375
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
long long mUncompressedSize
Definition: GZipCodec.hpp:134
~GZipCodec()
Destructor.
Definition: GZipCodec.cpp:66
GZipCodec & operator=(const GZipCodec &other)
Definition: GZipCodec.cpp:185
virtual long long position_Implementation() const
Definition: GZipCodec.cpp:260
virtual long long read_Implementation(void *buffer, long long bytes_to_read)
Definition: GZipCodec.cpp:195
GZipCodec(VirtualFile *stream=NULL)
Constructor.
Definition: GZipCodec.cpp:43
float compressionRatio() const
Returns the compression ratio computed as compressedsize/uncompressedsize.
Definition: GZipCodec.cpp:385
long long mWrittenBytes
Definition: GZipCodec.hpp:125
virtual void close()=0
Closes the file.
void resetStream()
Definition: GZipCodec.cpp:265
int mCompressionLevel
Definition: GZipCodec.hpp:122
virtual void close()
Closes the GZipStream.
Definition: GZipCodec.cpp:134
const String & path() const
Returns the path of the file.
Definition: VirtualFile.hpp:98
Visualization Library main namespace.
long long mStreamSize
Definition: GZipCodec.hpp:133
std::vector< char > mUncompressedBuffer
Definition: GZipCodec.hpp:131
enum vl::GZipCodec::@0 mMode
static void print(const String &message)
Application message for the user.
Definition: Log.cpp:136
The GZipCodec class is a VirtualFile that transparently encodes and decodes a stream of data using th...
Definition: GZipCodec.hpp:43
long long write(const void *buffer, long long byte_count)
Writes byte_count bytes to a file. Returns the number of bytes actually written.
Definition: VirtualFile.cpp:90
virtual bool open(EOpenMode mode)=0
Opens the file in the specified mode.
#define NULL
Definition: OpenGLDefs.hpp:81
bool seekSet(long long offset)
Changes the current read/write position of a file.
virtual long long size() const =0
Returns the size of the file in bytes.
long long mReadBytes
Definition: GZipCodec.hpp:124
VLCORE_EXPORT ref< VirtualFile > locateFile(const String &path)
Utility function, equivalent to vl::defFileSystem()->locateFile(path)
Definition: VirtualFile.cpp:41
void setPath(const String &name)
Changes the path bound to a VirtualFile. Use carefully this function, you shouldn&#39;t rename a VirtualF...
unsigned char mZipBufferOut[CHUNK_SIZE]
Definition: GZipCodec.hpp:130
long long uncompressedSize()
Returns the uncompressed size of the stream.
Definition: GZipCodec.cpp:340
virtual bool isOpen() const
Returns true if the file is open for read or writing.
Definition: GZipCodec.hpp:66
unsigned char mZipBufferIn[CHUNK_SIZE]
Definition: GZipCodec.hpp:129
unsigned int readUInt32(bool little_endian_data=true)
Reads single entry.
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
bool seekEnd(long long offset)
Changes the current read/write position of a file.
virtual ref< VirtualFile > clone() const
Returns an equivalent GZipCodec.
Definition: GZipCodec.cpp:178
ref< VirtualFile > mStream
Definition: GZipCodec.hpp:123
long long position() const
Returns the current position in the file.
Definition: VirtualFile.cpp:98
bool warnOnSeek() const
Definition: GZipCodec.hpp:109
#define VL_CHECK(expr)
Definition: checks.hpp:73
int compressionLevel() const
Definition: GZipCodec.hpp:86
const VirtualFile * stream() const
Returns the VirtualFile representing the GZip file to be read or to be written.
Definition: GZipCodec.hpp:92
z_stream_s * mZStream
Definition: GZipCodec.hpp:128