KSquare Utilities
KKB::Compressor Class Reference

Simple class that will compress and decompress specified buffers using the routines provided in zlib. More...

#include <Compressor.h>

Static Public Member Functions

static void * CreateCompressedBuffer (void *source, kkuint32 sourceLen, kkuint32 &compressedBuffLen)
 
static void * Decompress (const void *compressedBuff, kkuint32 compressedBuffLen, kkuint32 &unCompressedLen)
 
static void Decompress (const void *compressedBuff, kkuint32 compressedBuffLen, uchar *&unCompressedBuff, kkuint32 &unCompressedBuffSize, kkuint32 &unCompressedBuffLen)
 

Detailed Description

Simple class that will compress and decompress specified buffers using the routines provided in zlib.

Author
Kurt Kramer

Definition at line 17 of file Compressor.h.

Member Function Documentation

void * Compressor::CreateCompressedBuffer ( void *  source,
kkuint32  sourceLen,
kkuint32 compressedBuffLen 
)
static

Definition at line 22 of file Compressor.cpp.

Referenced by KKB::Raster::ToCompressor().

26 {
27 #ifdef ZLIB_H
28 
29  // following code was lifted from example provided by zlib "zpipe.c"
30  kkint32 ret;
31  z_stream strm;
32 
33 
34  Bytef* outputBuffer = NULL;
35  kkuint32 outputBufferSize = sourceLen * 2;
36 
37  outputBuffer = new Bytef[outputBufferSize];
38 
39  uchar* compressedBuff = NULL;
40  compressedBuffLen = 0;
41 
42  // The first thing we do is to initialize the zlib state for compression using deflateInit(). This must be done
43  // before the first use of deflate(). The zalloc, zfree, and opaque fields in the strm structure must be initialized
44  // before calling deflateInit(). Here they are set to the zlib constant Z_NULL to request that zlib use the default
45  // memory allocation routines. An application may also choose to provide custom memory allocation routines here.
46  // deflateInit() will allocate on the order of 256K bytes for the internal state. (See zlib Technical Details.)
47  // deflateInit() is called with a pointer to the structure to be initialized and the compression level, which is
48  // an integer in the range of -1 to 9. Lower compression levels result in faster execution, but less compression.
49  // Higher levels result in greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, equal
50  // to -1, provides a good compromise between compression and speed and is equivalent to level 6. Level 0 actually
51  // does no compression at all, and in fact expands the data slightly to produce the zlib format (it is not a
52  // byte-for-byte copy of the input). More advanced applications of zlib may use deflateInit2() here instead. Such an
53  // application may want to reduce how much memory will be used, at some price in compression. Or it may need to request
54  // a gzip header and trailer instead of a zlib header and trailer, or raw encoding with no header or trailer at all.
55 
56  // We must check the return value of deflateInit() against the zlib constant Z_OK to make sure that it was able to
57  // allocate memory for the internal state, and that the provided arguments were valid. deflateInit() will also check
58  // that the version of zlib that the zlib.h file came from matches the version of zlib actually linked with the
59  // program. This is especially important for environments in which zlib is a shared library.
60 
61  // Note that an application can initialize multiple, independent zlib streams, which can operate in parallel. The state
62  // information maintained in the structure allows the zlib routines to be reentrant.
63 
64 
65  /* allocate deflate state */
66  strm.zalloc = Z_NULL;
67  strm.zfree = Z_NULL;
68  strm.opaque = Z_NULL;
69  ret = deflateInit (&strm, Z_DEFAULT_COMPRESSION); // 'Z_DEFAULT_COMPRESSION' will balance between speed and compression; 0 = no compression, 9 = best compression
70  if (ret != Z_OK)
71  {
72  // Initialization Failed
73  compressedBuffLen = 0;
74  return NULL;
75  }
76 
77  // With the pleasantries out of the way, now we can get down to business. The outer do-loop reads all of the input
78  // file and exits at the bottom of the loop once end-of-file is reached. This loop contains the only call of deflate().
79  // So we must make sure that all of the input data has been processed and that all of the output data has been generated
80  // and consumed before we fall out of the loop at the bottom.
81 
82  {
83  // This was originally a a loop that read from a file; but now we have a input buffer with a known amount of data.
84  strm.avail_in = sourceLen; // Number of bytes in 'source' to compress.
85  strm.next_in = (Bytef*)source; // pointer to data that needs to be compressed.
86 
87  do
88  {
89  // We will stay in this loop until all data in source is processed. If the output buffer is not large enough
90  // we may need to make more than one iteration.
91 
92  strm.avail_out = outputBufferSize;
93  strm.next_out = outputBuffer;
94 
95  // Now we call the compression engine itself, deflate(). It takes as many of the avail_in bytes at next_in as it can
96  // process, and writes as many as avail_out bytes to next_out. Those counters and pointers are then updated past the
97  // input data consumed and the output data written. It is the amount of output space available that may limit how much
98  // input is consumed. Hence the inner loop to make sure that all of the input is consumed by providing more output
99  // space each time. Since avail_in and next_in are updated by deflate(), we don't have to mess with those between
100  // deflate() calls until it's all used up.
101 
102  // The parameters to deflate() are a pointer to the stream structure containing the input and output information and
103  // the internal compression engine state, and a parameter indicating whether and how to flush data to the output.
104  // Normally deflate will consume several K bytes of input data before producing any output (except for the header),
105  // in order to accumulate statistics on the data for optimum compression. It will then put out a burst of compressed
106  // data, and proceed to consume more input before the next burst. Eventually, deflate() must be told to terminate the
107  // stream, complete the compression with provided input data, and write out the trailer check value. deflate() will
108  // continue to compress normally as long as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided,
109  // deflate() will begin to complete the compressed output stream. However depending on how much output space is
110  // provided, deflate() may have to be called several times until it has provided the complete compressed stream, even
111  // after it has consumed all of the input. The flush parameter must continue to be Z_FINISH for those subsequent calls.
112 
113  ret = deflate (&strm, Z_FINISH);
114  if (ret == Z_STREAM_ERROR)
115  {
116  cerr << "Compressor::CreateCompressedBuffer ***ERROR** deflate returned error[" << ret << "]." << std::endl;
117  compressedBuffLen = 0;
118  return NULL;
119  }
120 
121  // Now we compute how much output deflate() provided on the last call, which is the difference between how much space
122  // was provided before the call, and how much output space is still available after the call. Then that data, if any,
123  // is written to the output file. We can then reuse the output buffer for the next call of deflate(). Again if there
124  // is a file i/o error, we call deflateEnd() before returning to avoid a memory leak.
125  kkint32 have = outputBufferSize - strm.avail_out;
126  {
127  if (compressedBuff == NULL)
128  {
129  compressedBuff = new uchar[have];
130  compressedBuffLen = have;
131  memcpy (compressedBuff, outputBuffer, have);
132  }
133  else
134  {
135  kkuint32 newCompressedBuffLen = compressedBuffLen + have;
136  uchar* newCompressedBuff = new uchar[newCompressedBuffLen];
137  memcpy (newCompressedBuff, compressedBuff, compressedBuffLen);
138  memcpy (newCompressedBuff + compressedBuffLen, outputBuffer, have);
139  delete[] compressedBuff;
140  compressedBuff = newCompressedBuff;
141  compressedBuffLen = newCompressedBuffLen;
142  }
143  }
144  } while (strm.avail_out == 0);
145 
146 
147  if (strm.avail_in != 0)
148  {
149  // There is still input data; so something went wrong. We will prompt a diagnostic message and return NULL
150  cerr << "Compressor::CreateCompressedBuffer - The input buffer was not fully processed." << std::endl;
151  delete[] compressedBuff; compressedBuff = NULL;
152  delete[] outputBuffer; outputBuffer = NULL;
153  return NULL;
154  }
155  }
156 
157  // The process is complete, but we still need to deallocate the state to avoid a memory leak (or rather more like a memory
158  // hemorrhage if you didn't do this). Then finally we can return with a happy return value.
159  /* clean up and return */
160  (void)deflateEnd (&strm);
161 
162  delete[] outputBuffer; outputBuffer = NULL;
163 
164  return compressedBuff;
165 
166 #else
167  // For right now the linux version will not be doing compression.
168  return NULL;
169 #endif
170 } /* CreateCompressedBuffer*/
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
__int32 kkint32
Definition: KKBaseTypes.h:88
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
void * Compressor::Decompress ( const void *  compressedBuff,
kkuint32  compressedBuffLen,
kkuint32 unCompressedLen 
)
static

Definition at line 177 of file Compressor.cpp.

References KKB::GlobalGoalKeeper::EndBlock(), and KKB::GlobalGoalKeeper::StartBlock().

Referenced by KKB::Raster::FromCompressor().

181 {
182 #ifdef ZLIB_H
183  if (compressedBuff == NULL)
184  return NULL;
185 
187 
188  kkuint32 have = 0;
189  uchar* unCompressedBuff = NULL;
190 
191  Bytef* outBuffer = NULL;
192  kkint32 outBufferLen = 0;
193 
194  kkint32 ret;
195  z_stream strm;
196 
197  /* allocate inflate state */
198  strm.zalloc = Z_NULL;
199  strm.zfree = Z_NULL;
200  strm.opaque = Z_NULL;
201  strm.avail_in = 0;
202  strm.next_in = Z_NULL;
203 
204  ret = inflateInit (&strm);
205  if (ret != Z_OK)
206  {
207  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflateInit' failed." << std::endl;
208  unCompressedLen = 0;
210  return NULL;
211  }
212 
213 
214  outBufferLen = compressedBuffLen * 4;
215  outBuffer = new Bytef[outBufferLen];
216 
217  strm.avail_in = compressedBuffLen;
218  strm.next_in = (Bytef*)compressedBuff; // Bytef = a far pointer to a unsigned char.
219  // Not sure if on some platforms this may cause a problem.
220 
221  /* run inflate() on input until output buffer not full */
222  do
223  {
224  strm.avail_out = outBufferLen;
225  strm.next_out = outBuffer;
226 
227  ret = inflate (&strm, Z_NO_FLUSH);
228  if (ret == Z_STREAM_ERROR)
229  {
230  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflate' failed." << std::endl;
231  delete[] outBuffer; outBuffer = NULL;
232  delete[] unCompressedBuff; unCompressedBuff = NULL;
233  unCompressedLen = 0;
235  return NULL;
236  }
237 
238  switch (ret)
239  {
240  case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */
241  case Z_DATA_ERROR:
242  case Z_MEM_ERROR:
243  {
244  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflate' failed." << std::endl;
245  (void)inflateEnd (&strm);
246  delete[] outBuffer; outBuffer = NULL;
247  delete[] unCompressedBuff; unCompressedBuff = NULL;
248  unCompressedLen = 0;
250  return NULL;
251  }
252  }
253 
254  have = outBufferLen - strm.avail_out;
255  if (unCompressedBuff == NULL)
256  {
257  unCompressedBuff = new uchar[have];
258  unCompressedLen = have;
259  memcpy (unCompressedBuff, outBuffer, have);
260  }
261  else
262  {
263  kkint32 newUnCompressedLen = unCompressedLen + have;
264  uchar* newUnCompressedBuff = new uchar[newUnCompressedLen];
265  memcpy (newUnCompressedBuff, unCompressedBuff, unCompressedLen);
266  memcpy (newUnCompressedBuff + unCompressedLen, outBuffer, have);
267  delete[] unCompressedBuff;
268  unCompressedBuff = newUnCompressedBuff;
269  unCompressedLen = newUnCompressedLen;
270  newUnCompressedBuff = NULL;
271  }
272  }
273  while (strm.avail_out == 0);
274 
275  /* clean up and return */
276  (void)inflateEnd(&strm);
277 
278  delete[] outBuffer;
279  outBuffer = NULL;
280 
282 
283  return unCompressedBuff;
284 #else
285  return NULL;
286 #endif
287 } /* Decompress */
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
__int32 kkint32
Definition: KKBaseTypes.h:88
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
void Compressor::Decompress ( const void *  compressedBuff,
kkuint32  compressedBuffLen,
uchar *&  unCompressedBuff,
kkuint32 unCompressedBuffSize,
kkuint32 unCompressedBuffLen 
)
static

Definition at line 294 of file Compressor.cpp.

300 {
301 #ifdef ZLIB_H
302  if (compressedBuff == NULL)
303  return;
304 
305  unCompressedBuffLen = 0;
306 
307  //kkuint32 have = 0;
308 
309  kkint32 ret;
310  z_stream strm;
311 
312  /* allocate inflate state */
313  strm.zalloc = Z_NULL;
314  strm.zfree = Z_NULL;
315  strm.opaque = Z_NULL;
316  strm.avail_in = 0;
317  strm.next_in = Z_NULL;
318 
319  ret = inflateInit (&strm);
320  if (ret != Z_OK)
321  {
322  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflateInit' failed." << std::endl;
323  unCompressedBuffLen = 0;
324  return;
325  }
326 
327 
328  if (unCompressedBuff == NULL)
329  {
330  unCompressedBuffSize = compressedBuffLen * 4;
331  unCompressedBuff = new uchar[unCompressedBuffSize];
332  }
333 
334  strm.avail_in = compressedBuffLen;
335  strm.next_in = (Bytef*)compressedBuff; // Bytef = a far pointer to a unsigned char.
336  // Not sure if on some platforms this may cause a problem.
337 
338  /* run inflate() on input until output buffer not full */
339  do
340  {
341  kkuint32 unCompressedBuffLeft = unCompressedBuffSize - unCompressedBuffLen;
342  if ((strm.avail_in * 1.2) > unCompressedBuffLeft)
343  {
344  kkuint32 increaseBy = (kkuint32)((strm.avail_in * 1.2) - unCompressedBuffLeft);
345  increaseBy = Max (increaseBy, (kkuint32)10240);
346 
347  kkuint32 newUncompressedBuffSize = unCompressedBuffSize + increaseBy;
348  uchar* newUnCompressedBuff = new uchar[newUncompressedBuffSize];
349  memcpy (newUnCompressedBuff, unCompressedBuff, unCompressedBuffSize);
350  delete unCompressedBuff;
351  unCompressedBuff = newUnCompressedBuff;
352  newUnCompressedBuff = NULL;
353  unCompressedBuffSize = newUncompressedBuffSize;
354  }
355 
356  strm.avail_out = unCompressedBuffSize - unCompressedBuffLen;
357  strm.next_out = (Bytef*)unCompressedBuff + unCompressedBuffLen;
358 
359  ret = inflate (&strm, Z_NO_FLUSH);
360  if (ret == Z_STREAM_ERROR)
361  {
362  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflate' failed." << std::endl;
363  unCompressedBuffLen = 0;
364  return;
365  }
366 
367  switch (ret)
368  {
369  case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */
370  case Z_DATA_ERROR:
371  case Z_MEM_ERROR:
372  {
373  cerr << "Compressor::Decompress ***ERROR*** zlib function call 'inflate' failed." << std::endl;
374  (void)inflateEnd (&strm);
375  unCompressedBuffLen = 0;
376  return;
377  }
378  }
379 
380  unCompressedBuffLen = strm.total_out;
381  }
382  while (strm.avail_in > 0);
383 
384  /* clean up and return */
385  (void)inflateEnd(&strm);
386 
387  return;
388 #else
389  return;
390 #endif
391 } /* Decompress */
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
__int32 kkint32
Definition: KKBaseTypes.h:88
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
T Max(T a, T b)
generic Max function, Both parameters must be of the same type.
Definition: KKBaseTypes.h:181

The documentation for this class was generated from the following files: