1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 
19 #if defined(ON_DLL_EXPORTS)
20 // When compiling a Windows DLL opennurbs, we
21 // statically link ./zlib/.../zlib....lib into
22 // the opennurbs DLL.
23 
24 
25 #define OPENNURBS_ZLIB_FILE_NAME "zlib.lib"
26 
27 //////////////////////////////////////////////////////////////
28 //
29 // OPENNURBS_ZLIB_OUTPUT_DIR is the directory containing zlib
30 // relative to the "opennurbs" directory.
31 //
32 // OPENNURBS_ZLIB_OUTPUT_DIR must not have a trailing slash
33 //
34 #define OPENNURBS_ZLIB_OUTPUT_ROOT_DIR "."
35 
36 
37 #if defined(WIN64) && defined(_M_X64)
38 
39 // 64 bit Windows zlib linking instructions
40 
41 #if defined(NDEBUG)
42 
43 // release x64 libs
44 #define OPENNURBS_CONFIGURATION_DIR "x64/Release"
45 
46 #else // _DEBUG
47 
48 // debug  x64 libs
49 #define OPENNURBS_CONFIGURATION_DIR "x64/Debug"
50 
51 #endif // if NDEBUG else _DEBUG
52 
53 #elif defined(WIN32) && defined(_M_IX86)
54 
55 // 32 bit Windows zlib linking instructions
56 
57 #if defined(NDEBUG)
58 
59 // release 32 bit WIndows libs
60 #define OPENNURBS_CONFIGURATION_DIR "Release"
61 
62 #else // _DEBUG
63 
64 // debug 32 bit WIndows libs
65 #define OPENNURBS_CONFIGURATION_DIR "Debug"
66 
67 #endif // if NDEBUG else _DEBUG
68 
69 #endif // if WIN64 else WIN32
70 
71 #pragma comment(lib, "\"" OPENNURBS_ZLIB_OUTPUT_ROOT_DIR "/" OPENNURBS_CONFIGURATION_DIR "/" OPENNURBS_ZLIB_FILE_NAME "\"")
72 
73 #endif // ON_DLL_EXPORTS
74 
75 
WriteCompressedBuffer(std::size_t sizeof__inbuffer,const void * inbuffer)76 bool ON_BinaryArchive::WriteCompressedBuffer(
77         std::size_t sizeof__inbuffer,  // sizeof uncompressed input data
78         const void* inbuffer  // uncompressed input data
79         )
80 {
81   std::size_t compressed_size = 0;
82   bool rc = false;
83 
84   if ( !WriteMode() )
85     return false;
86   if ( sizeof__inbuffer > 0 && 0 == inbuffer )
87     return false;
88 
89 
90   // number of bytes of uncompressed data
91 
92   if (!WriteSize(sizeof__inbuffer))
93     return false;
94   if ( 0 == sizeof__inbuffer )
95     return true;
96 
97   // 32 bit crc of uncompressed data
98   const unsigned int buffer_crc = ON_CRC32( 0, sizeof__inbuffer, inbuffer );
99   if (!WriteInt(buffer_crc))
100     return false;
101 
102   unsigned char method = (sizeof__inbuffer > 128) ? 1 : 0;
103   if ( method ) {
104     if ( !CompressionInit() ) {
105       CompressionEnd();
106       method = 0;
107     }
108   }
109   if ( !WriteChar(method) )
110     return false;
111 
112   switch ( method )
113   {
114   case 0: // uncompressed
115     rc = WriteByte(sizeof__inbuffer, inbuffer);
116     if ( rc )
117     {
118       compressed_size = sizeof__inbuffer;
119     }
120     break;
121 
122   case 1: // compressed
123     compressed_size = WriteDeflate( sizeof__inbuffer, inbuffer );
124     rc = ( compressed_size > 0 ) ? true : false;
125     CompressionEnd();
126     break;
127   }
128 
129 
130   return rc;
131 }
132 
ReadCompressedBufferSize(std::size_t * sizeof__outbuffer)133 bool ON_BinaryArchive::ReadCompressedBufferSize( std::size_t* sizeof__outbuffer )
134 {
135   return ReadSize(sizeof__outbuffer);
136 }
137 
ReadCompressedBuffer(std::size_t sizeof__outbuffer,void * outbuffer,int * bFailedCRC)138 bool ON_BinaryArchive::ReadCompressedBuffer( // read and uncompress
139   std::size_t sizeof__outbuffer,  // sizeof of uncompressed buffer to read
140   void* outbuffer,           // uncompressed output data returned here
141   int* bFailedCRC
142   )
143 {
144   bool rc = false;
145   unsigned int buffer_crc0 = 0;
146   unsigned int buffer_crc1 = 0;
147   char method = 0;
148 
149   if ( bFailedCRC)
150     *bFailedCRC = false;
151   if ( !ReadMode() )
152     return false;
153   if ( 0 == sizeof__outbuffer )
154     return true;
155   if ( 0 == outbuffer )
156     return false;
157 
158   if ( !ReadInt(&buffer_crc0) ) // 32 bit crc of uncompressed buffer
159     return false;
160 
161   if ( !ReadChar(&method) )
162     return false;
163 
164   if ( method != 0 && method != 1 )
165     return false;
166 
167   switch(method)
168   {
169   case 0: // uncompressed
170     rc = ReadByte(sizeof__outbuffer, outbuffer);
171     break;
172   case 1: // compressed
173     rc = CompressionInit();
174     if (rc)
175       rc = ReadInflate( sizeof__outbuffer, outbuffer );
176     CompressionEnd();
177     break;
178   }
179 
180   if (rc )
181   {
182     buffer_crc1 = ON_CRC32( 0, sizeof__outbuffer, outbuffer );
183     if ( buffer_crc1 != buffer_crc0 )
184     {
185       ON_ERROR("ON_BinaryArchive::ReadCompressedBuffer() crc error");
186       if ( bFailedCRC )
187         *bFailedCRC = true;
188     }
189   }
190 
191   return rc;
192 }
193 
WriteDeflate(std::size_t sizeof___inbuffer,const void * in___buffer)194 std::size_t ON_BinaryArchive::WriteDeflate( // returns number of bytes written
195         std::size_t sizeof___inbuffer,  // sizeof uncompressed input data ( > 0 )
196         const void* in___buffer     // uncompressed input data ( != NULL )
197         )
198 {
199   /*
200     In "standard" (in 2005) 32 bit code
201 
202       sizeof(int)     = 4 bytes,
203       sizeof(long)    = 4 bytes,
204       sizeof(pointer) = 4 bytes, and
205       sizeof(std::size_t)  = 4 bytes.
206 
207     Theoretically I don't need to use multiple input buffer
208     chunks in case.  But I'm paranoid and I will use multiple
209     input chunks when sizeof_inbuffer > 2GB in order to dodge
210     any potential zlib signed verses unsigned compare bugs or
211     having a signed int i++ roll over to a negative number.
212 
213     In "standard" code that has 64 bit pointers
214 
215       sizeof(int)     >= 4 bytes, (it's 4 on MS VS2005)
216       sizeof(long)    >= 4 bytes, (it's 4 on MS VS2005)
217       sizeof(pointer)  = 8 bytes, and
218       sizeof(std::size_t)   = 8 bytes.
219 
220     So, I'm going to assume the ints and longs in the zlib code
221     are 4 bytes, but I could have sizeof_inbuffer > 4GB.
222     This means I have to use multiple input buffer chunks.
223     In this case I still use multiple input chunks when
224     sizeof_inbuffer > 2GB in order to dodge any potential zlib
225     signed verses unsigned compare bugs or having a signed
226     int i++ roll over to a negative number.
227 
228     So, I set
229 
230        const std::size_t max_avail = (largest signed 4 byte integer - 15)
231 
232     and feed inflate and deflate buffers with size <= max_avail.
233 
234 
235     This information below is from the zlib 1.2.3 FAQ.
236 
237     32. Can zlib work with greater than 4 GB of data?
238 
239         Yes. inflate() and deflate() will process any amount of data correctly.
240         Each call of inflate() or deflate() is limited to input and output chunks
241         of the maximum value that can be stored in the compiler's "unsigned int"
242         type, but there is no limit to the number of chunks. Note however that the
243         strm.total_in and strm_total_out counters may be limited to 4 GB. These
244         counters are provided as a convenience and are not used internally by
245         inflate() or deflate(). The application can easily set up its own counters
246         updated after each call of inflate() or deflate() to count beyond 4 GB.
247         compress() and uncompress() may be limited to 4 GB, since they operate in a
248         single call. gzseek() and gztell() may be limited to 4 GB depending on how
249         zlib is compiled. See the zlibCompileFlags() function in zlib.h.
250 
251         The word "may" appears several times above since there is a 4 GB limit
252         only if the compiler's "long" type is 32 bits. If the compiler's "long"
253         type is 64 bits, then the limit is 16 exabytes.
254   */
255 
256   const std::size_t max_avail = 0x7FFFFFF0;
257 
258   //  Compressed information is saved in a chunk.
259   bool rc = BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,0);
260   if ( !rc )
261     return false;
262 
263   std::size_t out__count = 0;
264   int zrc = Z_OK;
265 
266   std::size_t my_avail_in = sizeof___inbuffer;
267   unsigned char* my_next_in = (unsigned char*)in___buffer;
268 
269   std::size_t d = my_avail_in;
270   if ( d > max_avail )
271     d = max_avail;
272   m_zlib.strm.next_in = my_next_in;
273   m_zlib.strm.avail_in = (unsigned int)d;
274   my_avail_in -= d;
275   my_next_in  += d;
276 
277   m_zlib.strm.next_out = m_zlib.buffer;
278   m_zlib.strm.avail_out = m_zlib.sizeof_x_buffer;
279 
280   // counter guards prevents infinte loops if there is a bug in zlib return codes.
281   int counter = 512;
282   int flush = Z_NO_FLUSH;
283 
284   std::size_t deflate_output_count = 0;
285 
286   while( rc && counter > 0 )
287   {
288     // Call zlib's deflate function.  It can either process
289     // more input from m_zlib.strm.next_in[], create more
290     // compressed output in m_zlib.strm.next_out[], or do both.
291     if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in )
292     {
293       // no uncompressed input is left - switch to finish mode
294       flush = Z_FINISH;
295     }
296     zrc = z_deflate( &m_zlib.strm, flush );
297     if ( zrc < 0 )
298     {
299       // Something went haywire - bail out.
300       ON_ERROR("ON_BinaryArchive::WriteDeflate - z_deflate failure");
301       rc = false;
302       break;
303     }
304 
305     deflate_output_count = m_zlib.sizeof_x_buffer - m_zlib.strm.avail_out;
306     if ( deflate_output_count > 0 )
307     {
308       // The last call to deflate created output.  Send
309       // this output to the archive.
310       rc = WriteChar( deflate_output_count, m_zlib.buffer );
311       if ( !rc )
312         break;
313       out__count += deflate_output_count;
314       m_zlib.strm.next_out  = m_zlib.buffer;
315       m_zlib.strm.avail_out = m_zlib.sizeof_x_buffer;
316     }
317 
318     if ( Z_FINISH == flush && Z_STREAM_END == zrc )
319     {
320       // no input left, all pending compressing is finished,
321       // and all compressed output has been returned.
322       break;
323     }
324 
325     if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail )
326     {
327       // inbuffer[] had more than max_zlib_avail_in bytes in it
328       // and I am feeding inbuffer[] to deflate in smaller chunks
329       // that the 32 bit integers in the zlib code can handle.
330       if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in )
331       {
332         // The call to deflate() used up all the input
333         // in m_zlib.strm.next_in[].  I can feed it another chunk
334         // from inbuffer[]
335         d = my_avail_in;
336         if ( d > max_avail )
337           d = max_avail;
338         m_zlib.strm.next_in = my_next_in;
339         m_zlib.strm.avail_in = (unsigned int)d;
340       }
341       else
342       {
343         // The call to deflate left some input in m_zlib.strm.next_in[],
344         // but I can increase m_zlib.strm.avail_in.
345         d =  max_avail - m_zlib.strm.avail_in;
346         if ( d > my_avail_in )
347           d = my_avail_in;
348         m_zlib.strm.avail_in += (unsigned int)d;
349       }
350 
351       my_avail_in -= d;
352       my_next_in  += d;
353     }
354     else if ( 0 == deflate_output_count )
355     {
356       // no buffer changes this time
357       counter--;
358     }
359 
360     if ( zrc != Z_OK )
361     {
362       break;
363     }
364   }
365 
366   if ( !EndWrite3dmChunk() )
367   {
368     rc = false;
369   }
370 
371   if ( 0 == counter )
372   {
373     rc = false;
374   }
375 
376   return (rc ? out__count : 0);
377 }
378 
379 
ReadInflate(std::size_t sizeof___outbuffer,void * out___buffer)380 bool ON_BinaryArchive::ReadInflate(
381         std::size_t sizeof___outbuffer,  // sizeof uncompressed data
382         void* out___buffer          // buffer for uncompressed data
383         )
384 {
385   const std::size_t max_avail = 0x7FFFFFF0; // See max_avail comment in ON_BinaryArchive::WriteInflate
386 
387   std::size_t sizeof__inbuffer = 0;
388   void* in___buffer = 0;
389   bool rc = false;
390 
391   // read compressed buffer from 3dm archive
392   bool bValidCompressedBuffer = false;
393   {
394     ON__UINT32 tcode = 0;
395     ON__INT64  big_value = 0;
396     rc = BeginRead3dmBigChunk(&tcode,&big_value );
397     if (!rc)
398     {
399       if ( 0 != out___buffer && sizeof___outbuffer > 0 )
400         memset(out___buffer,0,sizeof___outbuffer);
401       return false;
402     }
403     if (   tcode == TCODE_ANONYMOUS_CHUNK
404         && big_value > 4
405         && sizeof___outbuffer > 0
406         && 0 != out___buffer )
407     {
408       // read compressed buffer from the archive
409       sizeof__inbuffer = (std::size_t)(big_value-4); // the last 4 bytes in this chunk are a 32 bit crc
410       in___buffer = onmalloc(sizeof__inbuffer);
411       if ( !in___buffer )
412       {
413         rc = false;
414       }
415       else
416       {
417         rc = ReadByte( sizeof__inbuffer, in___buffer );
418       }
419     }
420     else
421     {
422       // Either I have the wrong chunk, or the input
423       // parameters are bogus.
424       rc = false;
425     }
426     int c0 = m_bad_CRC_count;
427     if ( !EndRead3dmChunk() )
428     {
429       rc = false;
430     }
431     bValidCompressedBuffer = ( m_bad_CRC_count > c0 )
432                            ? false
433                            : rc;
434   }
435 
436   if ( !bValidCompressedBuffer && 0 != out___buffer && sizeof___outbuffer > 0 )
437   {
438     // Decompression will fail, but we might get something valid
439     // at the start if the data flaw was near the end of the buffer.
440     memset(out___buffer,0,sizeof___outbuffer);
441   }
442 
443   if ( !rc )
444   {
445     if ( in___buffer )
446     {
447       onfree(in___buffer);
448       in___buffer = 0;
449     }
450     return false;
451   }
452 
453   int zrc = -1;
454 
455   // set up zlib in buffer
456   unsigned char* my_next_in = (unsigned char*)in___buffer;
457   std::size_t my_avail_in = sizeof__inbuffer;
458 
459   std::size_t d = my_avail_in;
460   if ( d > max_avail )
461     d = max_avail;
462   m_zlib.strm.next_in  = my_next_in;
463   m_zlib.strm.avail_in = (unsigned int)d;
464   my_next_in  += d;
465   my_avail_in -= d;
466 
467   // set up zlib out buffer
468   unsigned char* my_next_out = (unsigned char*)out___buffer;
469   std::size_t my_avail_out = sizeof___outbuffer;
470 
471   d = my_avail_out;
472   if ( d > max_avail )
473     d = max_avail;
474   m_zlib.strm.next_out  = my_next_out;
475   m_zlib.strm.avail_out = (unsigned int)d;
476   my_next_out  += d;
477   my_avail_out -= d;
478 
479   // counter guards against infinte loop if there are
480   // bugs in zlib return codes
481   int counter = 512;
482   int flush = Z_NO_FLUSH;
483 
484   while ( rc && counter > 0 )
485   {
486     // Call zlib's inflate function.  It can either process
487     // more input from m_zlib.strm.next_in[], create more
488     // uncompressed output in m_zlib.strm.next_out[], or do both.
489     if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in )
490     {
491       // no compressed input is left - switch to finish mode
492       flush = Z_FINISH;
493     }
494     zrc = z_inflate( &m_zlib.strm, flush );
495     if ( zrc < 0 )
496     {
497       // Something went haywire - bail out.
498       ON_ERROR("ON_BinaryArchive::ReadInflate - z_inflate failure");
499       rc = false;
500       break;
501     }
502 
503     if ( Z_FINISH == flush && Z_STREAM_END == zrc )
504     {
505       // no input left, all pending decompression is finished,
506       // and all decompressed output has been returned.
507       break;
508     }
509 
510     d = 0;
511     if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail )
512     {
513       if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in )
514       {
515         // The call to inflate() used up all the input
516         // in m_zlib.strm.next_in[].  I can feed it another chunk
517         // from inbuffer[]
518         d = my_avail_in;
519         if ( d > max_avail )
520           d = max_avail;
521         m_zlib.strm.next_in  = my_next_in;
522         m_zlib.strm.avail_in = (unsigned int)d;
523       }
524       else
525       {
526         // The call to inflate() left some input in m_zlib.strm.next_in[],
527         // but I can increase m_zlib.strm.avail_in.
528         d =  max_avail - m_zlib.strm.avail_in;
529         if ( d > my_avail_in )
530           d = my_avail_in;
531         m_zlib.strm.avail_in += (unsigned int)d;
532       }
533       my_next_in  += d;
534       my_avail_in -= d;
535     }
536 
537     if ( my_avail_out > 0 && m_zlib.strm.avail_out < max_avail )
538     {
539       // increase m_zlib.strm.next_out[] buffer
540       if ( 0 == m_zlib.strm.avail_out || 0 == m_zlib.strm.next_out )
541       {
542         d = my_avail_out;
543         if ( d > max_avail )
544           d = max_avail;
545         m_zlib.strm.next_out  = my_next_out;
546         m_zlib.strm.avail_out = (unsigned int)d;
547       }
548       else
549       {
550         d = max_avail - m_zlib.strm.avail_out;
551         if ( d > my_avail_out )
552           d = my_avail_out;
553         m_zlib.strm.avail_out += ((unsigned int)d);
554       }
555       my_next_out  += d;
556       my_avail_out -= d;
557     }
558     else if ( 0 == d )
559     {
560       // no buffer changes
561       counter--;
562     }
563   }
564 
565   if (in___buffer )
566   {
567     onfree(in___buffer);
568     in___buffer = 0;
569   }
570 
571   if ( 0 == counter )
572   {
573     rc = false;
574   }
575 
576   return rc;
577 }
578 
CompressionInit()579 bool ON_BinaryArchive::CompressionInit()
580 {
581   // inflateInit() and deflateInit() are in zlib 1.3.3
582   bool rc = false;
583   if ( WriteMode() ) {
584     rc = ( m_zlib.mode == ON::write ) ? true : false;
585     if ( !rc ) {
586       CompressionEnd();
587       if ( Z_OK == deflateInit( &m_zlib.strm, Z_BEST_COMPRESSION ) ) {
588         m_zlib.mode = ON::write;
589         rc = true;
590       }
591       else {
592         memset(&m_zlib.strm,0,sizeof(m_zlib.strm));
593       }
594     }
595   }
596   else if ( ReadMode() ) {
597     rc = ( m_zlib.mode == ON::read ) ? true : false;
598     if ( !rc ) {
599       CompressionEnd();
600       if ( Z_OK == inflateInit( &m_zlib.strm ) ) {
601         m_zlib.mode = ON::read;
602         rc = true;
603       }
604       else {
605         memset(&m_zlib.strm,0,sizeof(m_zlib.strm));
606       }
607     }
608   }
609   else {
610     CompressionEnd();
611   }
612   return rc;
613 }
614 
CompressionEnd()615 void ON_BinaryArchive::CompressionEnd()
616 {
617   // inflateEnd() and deflateEnd() are in zlib 1.3.3
618   switch ( m_zlib.mode ) {
619   case ON::read:
620   case ON::read3dm:
621     inflateEnd(&m_zlib.strm);
622     break;
623   case ON::write:
624   case ON::write3dm:
625     deflateEnd(&m_zlib.strm);
626     break;
627   default: // to quiet lint
628     break;
629   }
630   memset(&m_zlib.strm,0,sizeof(m_zlib.strm));
631   m_zlib.mode = ON::unknown_archive_mode;
632 }
633 
634 
635 
636 struct ON_CompressedBufferHelper
637 {
638   int action; // 1 = compress, 2 = uncompress
639   enum
640   {
641     sizeof_x_buffer = 16384
642   };
643   unsigned char    buffer[sizeof_x_buffer];
644   z_stream         strm;
645   std::size_t           m_buffer_compressed_capacity;
646 };
647 
ON_CompressedBuffer()648 ON_CompressedBuffer::ON_CompressedBuffer()
649                     : m_sizeof_uncompressed(0),
650                       m_sizeof_compressed(0),
651                       m_crc_uncompressed(0),
652                       m_crc_compressed(0),
653                       m_method(0),
654                       m_sizeof_element(0),
655                       m_buffer_compressed_capacity(0),
656                       m_buffer_compressed(0)
657 {
658 }
659 
~ON_CompressedBuffer()660 ON_CompressedBuffer::~ON_CompressedBuffer()
661 {
662   Destroy();
663 }
664 
ON_CompressedBuffer(const ON_CompressedBuffer & src)665 ON_CompressedBuffer::ON_CompressedBuffer(const ON_CompressedBuffer& src)
666                     : m_sizeof_uncompressed(0),
667                       m_sizeof_compressed(0),
668                       m_crc_uncompressed(0),
669                       m_crc_compressed(0),
670                       m_method(0),
671                       m_sizeof_element(0),
672                       m_buffer_compressed_capacity(0),
673                       m_buffer_compressed(0)
674 {
675   *this = src;
676 }
677 
operator =(const ON_CompressedBuffer & src)678 ON_CompressedBuffer& ON_CompressedBuffer::operator=(const ON_CompressedBuffer& src)
679 {
680   if ( this != &src )
681   {
682     Destroy();
683     if( src.m_buffer_compressed && src.m_sizeof_compressed > 0 )
684     {
685       m_sizeof_uncompressed = src.m_sizeof_uncompressed;
686       m_sizeof_compressed   = src.m_sizeof_compressed;
687       m_crc_uncompressed    = src.m_crc_uncompressed;
688       m_crc_compressed      = src.m_crc_compressed;
689       m_method              = src.m_method;
690       m_sizeof_element      = src.m_sizeof_element;
691 
692       m_buffer_compressed = onmalloc(m_sizeof_compressed);
693       if( m_buffer_compressed )
694       {
695         m_buffer_compressed_capacity = m_sizeof_compressed;
696         memcpy(m_buffer_compressed,src.m_buffer_compressed,m_sizeof_compressed);
697       }
698     }
699   }
700   return *this;
701 }
702 
Write(ON_BinaryArchive & binary_archive) const703 bool ON_CompressedBuffer::Write( ON_BinaryArchive& binary_archive ) const
704 {
705   bool rc = binary_archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
706   if ( !rc )
707     return false;
708 
709   for(;;)
710   {
711     rc = binary_archive.WriteSize(m_sizeof_uncompressed);
712     if (!rc)
713       break;
714     rc = binary_archive.WriteSize((m_buffer_compressed && m_sizeof_compressed>0) ? m_sizeof_compressed : 0);
715     if (!rc)
716       break;
717     rc = binary_archive.WriteInt(m_crc_uncompressed);
718     if (!rc)
719       break;
720     rc = binary_archive.WriteInt(m_crc_compressed);
721     if (!rc)
722       break;
723     rc = binary_archive.WriteInt(m_method);
724     if (!rc)
725       break;
726     rc = binary_archive.WriteInt(m_sizeof_element);
727     if (!rc)
728       break;
729     if ( m_buffer_compressed && m_sizeof_compressed > 0 )
730     {
731       rc = binary_archive.WriteByte(m_sizeof_compressed,m_buffer_compressed);
732       if (!rc)
733         break;
734     }
735     break;
736   }
737 
738   if ( !binary_archive.EndWrite3dmChunk() )
739     rc = false;
740 
741   return rc;
742 }
743 
Read(ON_BinaryArchive & binary_archive)744 bool ON_CompressedBuffer::Read( ON_BinaryArchive& binary_archive )
745 {
746   int major_version = 0;
747   int minor_version = 0;
748   bool rc = binary_archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
749   if ( !rc )
750     return false;
751 
752   for(;;)
753   {
754     rc = ( 1 == major_version );
755     if ( !rc )
756       break;
757     rc = binary_archive.ReadSize(&m_sizeof_uncompressed);
758     if (!rc)
759       break;
760     rc = binary_archive.ReadSize(&m_sizeof_compressed);
761     if (!rc)
762       break;
763     rc = binary_archive.ReadInt(&m_crc_uncompressed);
764     if (!rc)
765       break;
766     rc = binary_archive.ReadInt(&m_crc_compressed);
767     if (!rc)
768       break;
769     rc = binary_archive.ReadInt(&m_method);
770     if (!rc)
771       break;
772     rc = binary_archive.ReadInt(&m_sizeof_element);
773     if (!rc)
774       break;
775     if ( m_sizeof_compressed > 0 )
776     {
777       m_buffer_compressed = onmalloc(m_sizeof_compressed);
778       if ( m_buffer_compressed )
779       {
780         m_buffer_compressed_capacity = m_sizeof_compressed;
781         rc = binary_archive.ReadByte(m_sizeof_compressed,m_buffer_compressed);
782       }
783       else
784       {
785         m_sizeof_compressed =0;
786       }
787       if (!rc)
788         break;
789     }
790 
791     break;
792   }
793 
794   if ( !binary_archive.EndRead3dmChunk() )
795     rc = false;
796 
797   return rc;
798 }
799 
Destroy()800 void ON_CompressedBuffer::Destroy()
801 {
802   if ( m_buffer_compressed )
803     onfree(m_buffer_compressed);
804 
805   m_sizeof_uncompressed = 0;
806   m_sizeof_compressed   = 0;
807   m_crc_uncompressed    = 0;
808   m_crc_compressed      = 0;
809   m_method              = 0;
810   m_sizeof_element      = 0;
811   m_buffer_compressed   = 0;
812   m_buffer_compressed_capacity = 0;
813 }
814 
Compress(std::size_t sizeof__inbuffer,const void * inbuffer,int sizeof_element)815 bool ON_CompressedBuffer::Compress(
816         std::size_t sizeof__inbuffer,  // sizeof uncompressed input data
817         const void* inbuffer,     // uncompressed input data
818         int sizeof_element
819         )
820 {
821   Destroy();
822 
823   //std::size_t compressed_size = 0;
824   bool rc = false;
825 
826   if ( sizeof__inbuffer > 0 && 0 == inbuffer )
827     return false;
828 
829   if ( 0 == sizeof__inbuffer )
830     return true;
831 
832   // number of bytes of uncompressed data
833   m_sizeof_uncompressed = sizeof__inbuffer;
834 
835   ON_CompressedBufferHelper helper;
836   memset(&helper,0,sizeof(helper));
837   helper.action = 1;
838 
839   bool bToggleByteOrder = false;
840   switch(sizeof_element)
841   {
842   case 2:
843   case 4:
844   case 8:
845     if ( 0 == (sizeof__inbuffer%sizeof_element) )
846     {
847       m_sizeof_element = sizeof_element;
848       bToggleByteOrder = (ON::big_endian == ON::Endian());
849     }
850     break;
851   };
852 
853   if ( bToggleByteOrder )
854   {
855     ON_BinaryFile::ToggleByteOrder(
856       (int)(sizeof__inbuffer/m_sizeof_element),
857       m_sizeof_element,
858       inbuffer,
859       (void*)inbuffer
860       );
861   }
862 
863   m_method = (sizeof__inbuffer > 128) ? 1 : 0;
864   if ( m_method )
865   {
866     if ( !CompressionInit(&helper) )
867     {
868       CompressionEnd(&helper);
869       m_method = 0;
870     }
871     else
872     {
873       m_buffer_compressed = onmalloc(sizeof__inbuffer/4);
874       std::size_t sizeof_compressed = DeflateHelper( &helper, sizeof__inbuffer, inbuffer );
875       CompressionEnd(&helper);
876       if ( sizeof_compressed > 0 && sizeof_compressed == m_sizeof_compressed )
877       {
878         rc = true;
879         if ( 2*m_buffer_compressed_capacity > 3*m_sizeof_compressed )
880         {
881           // release memory we don't need
882           m_buffer_compressed_capacity = m_sizeof_compressed;
883           m_buffer_compressed = onrealloc(m_buffer_compressed,m_buffer_compressed_capacity);
884         }
885       }
886       else
887       {
888         Destroy();
889         m_method = 0;
890       }
891     }
892   }
893 
894   if ( 0 ==  m_method )
895   {
896     // uncompressed
897     m_buffer_compressed = onmalloc(sizeof__inbuffer);
898     if ( m_buffer_compressed )
899     {
900       m_sizeof_compressed = sizeof__inbuffer;
901       m_buffer_compressed_capacity = sizeof__inbuffer;
902       memcpy(m_buffer_compressed,inbuffer,sizeof__inbuffer);
903       rc = true;
904     }
905   }
906 
907   if ( bToggleByteOrder )
908   {
909     ON_BinaryFile::ToggleByteOrder(
910       (int)(sizeof__inbuffer/m_sizeof_element),
911       m_sizeof_element,
912       inbuffer,
913       (void*)inbuffer
914       );
915   }
916 
917   if (rc)
918   {
919     m_crc_uncompressed = ON_CRC32( 0, sizeof__inbuffer, inbuffer );
920     m_crc_compressed   = ON_CRC32( 0, m_sizeof_compressed, m_buffer_compressed );
921   }
922 
923   return rc;
924 }
925 
Uncompress(void * outbuffer,int * bFailedCRC) const926 bool ON_CompressedBuffer::Uncompress(
927           void* outbuffer,
928           int* bFailedCRC
929           ) const
930 {
931   bool rc = false;
932 
933   if ( bFailedCRC)
934     *bFailedCRC = false;
935   if ( 0 == m_sizeof_uncompressed )
936     return true;
937   if ( 0 == outbuffer )
938     return false;
939 
940   if ( m_method != 0 && m_method != 1 )
941     return false;
942 
943   ON__UINT32 compressed_crc = ON_CRC32( 0, m_sizeof_compressed, m_buffer_compressed );
944   if ( compressed_crc != m_crc_compressed )
945   {
946     // m_buffer_compressed is corrupt - let's hope the corruption
947     // is near the end and we ge something useful from the
948     // beginning.
949     memset(outbuffer,0,m_sizeof_uncompressed);
950     if ( bFailedCRC)
951       *bFailedCRC = false;
952   }
953 
954   switch(m_method)
955   {
956   case 0: // uncompressed
957     if (    m_buffer_compressed
958          && m_sizeof_uncompressed == m_sizeof_compressed
959          )
960     {
961       memcpy(outbuffer,m_buffer_compressed,m_sizeof_uncompressed);
962       rc = true;
963     }
964     break;
965 
966   case 1: // compressed
967     {
968       ON_CompressedBufferHelper helper;
969       memset(&helper,0,sizeof(helper));
970       helper.action = 2;
971       rc = CompressionInit(&helper);
972       if (rc)
973       {
974         rc = InflateHelper( &helper, m_sizeof_uncompressed, outbuffer );
975         CompressionEnd(&helper);
976       }
977     }
978     break;
979   }
980 
981   switch(m_sizeof_element)
982   {
983   case 2:
984   case 4:
985   case 8:
986     if ( 0 == (m_sizeof_uncompressed%m_sizeof_element) )
987     {
988       if ( ON::big_endian == ON::Endian() )
989       {
990         ON_BinaryFile::ToggleByteOrder(
991           (int)(m_sizeof_uncompressed/m_sizeof_element),
992           m_sizeof_element,
993           outbuffer,
994           outbuffer
995           );
996       }
997     }
998     break;
999   };
1000 
1001 
1002   if (rc )
1003   {
1004     ON__UINT32 uncompressed_crc = ON_CRC32( 0, m_sizeof_uncompressed, outbuffer );
1005     if ( uncompressed_crc != m_crc_uncompressed )
1006     {
1007       ON_ERROR("ON_CompressedBuffer::Uncompress() crc error");
1008       if ( bFailedCRC )
1009         *bFailedCRC = true;
1010     }
1011   }
1012 
1013   return rc;
1014 }
1015 
WriteChar(std::size_t count,const void * buffer)1016 bool ON_CompressedBuffer::WriteChar(
1017         std::size_t count, const void* buffer
1018         )
1019 {
1020   bool rc = true;
1021   if ( count > 0 && buffer )
1022   {
1023     if ( count + m_sizeof_compressed > m_buffer_compressed_capacity )
1024     {
1025       std::size_t delta = count + m_sizeof_compressed - m_buffer_compressed_capacity;
1026       if ( delta < 2048 )
1027         delta = 2048;
1028       if ( delta < m_buffer_compressed_capacity/4 )
1029         delta = m_buffer_compressed_capacity/4;
1030       m_buffer_compressed_capacity += delta;
1031       m_buffer_compressed = onrealloc(m_buffer_compressed,m_buffer_compressed_capacity);
1032       if ( !m_buffer_compressed )
1033       {
1034         m_buffer_compressed_capacity = 0;
1035         m_sizeof_compressed = 0;
1036         return false;
1037       }
1038     }
1039     memcpy(((char*)m_buffer_compressed)+m_sizeof_compressed,buffer,count);
1040     m_sizeof_compressed += count;
1041   }
1042   else
1043   {
1044     rc = (0 == count);
1045   }
1046   return rc;
1047 }
1048 
1049 
DeflateHelper(ON_CompressedBufferHelper * helper,std::size_t sizeof___inbuffer,const void * in___buffer)1050 std::size_t ON_CompressedBuffer::DeflateHelper( // returns number of bytes written
1051         ON_CompressedBufferHelper* helper,
1052         std::size_t sizeof___inbuffer,  // sizeof uncompressed input data ( > 0 )
1053         const void* in___buffer     // uncompressed input data ( != NULL )
1054         )
1055 {
1056   /*
1057     In "standard" (in 2005) 32 bit code
1058 
1059       sizeof(int)     = 4 bytes,
1060       sizeof(long)    = 4 bytes,
1061       sizeof(pointer) = 4 bytes, and
1062       sizeof(std::size_t)  = 4 bytes.
1063 
1064     Theoretically I don't need to use multiple input buffer
1065     chunks in case.  But I'm paranoid and I will use multiple
1066     input chunks when sizeof_inbuffer > 2GB in order to dodge
1067     any potential zlib signed verses unsigned compare bugs or
1068     having a signed int i++ roll over to a negative number.
1069 
1070     In "standard" code that has 64 bit pointers
1071 
1072       sizeof(int)     >= 4 bytes, (it's 4 on MS VS2005)
1073       sizeof(long)    >= 4 bytes, (it's 4 on MS VS2005)
1074       sizeof(pointer)  = 8 bytes, and
1075       sizeof(std::size_t)   = 8 bytes.
1076 
1077     So, I'm going to assume the ints and longs in the zlib code
1078     are 4 bytes, but I could have sizeof_inbuffer > 4GB.
1079     This means I have to use multiple input buffer chunks.
1080     In this case I still use multiple input chunks when
1081     sizeof_inbuffer > 2GB in order to dodge any potential zlib
1082     signed verses unsigned compare bugs or having a signed
1083     int i++ roll over to a negative number.
1084 
1085     So, I set
1086 
1087        const std::size_t max_avail = (largest signed 4 byte integer - 15)
1088 
1089     and feed inflate and deflate buffers with size <= max_avail.
1090 
1091 
1092     This information below is from the zlib 1.2.3 FAQ.
1093 
1094     32. Can zlib work with greater than 4 GB of data?
1095 
1096         Yes. inflate() and deflate() will process any amount of data correctly.
1097         Each call of inflate() or deflate() is limited to input and output chunks
1098         of the maximum value that can be stored in the compiler's "unsigned int"
1099         type, but there is no limit to the number of chunks. Note however that the
1100         strm.total_in and strm_total_out counters may be limited to 4 GB. These
1101         counters are provided as a convenience and are not used internally by
1102         inflate() or deflate(). The application can easily set up its own counters
1103         updated after each call of inflate() or deflate() to count beyond 4 GB.
1104         compress() and uncompress() may be limited to 4 GB, since they operate in a
1105         single call. gzseek() and gztell() may be limited to 4 GB depending on how
1106         zlib is compiled. See the zlibCompileFlags() function in zlib.h.
1107 
1108         The word "may" appears several times above since there is a 4 GB limit
1109         only if the compiler's "long" type is 32 bits. If the compiler's "long"
1110         type is 64 bits, then the limit is 16 exabytes.
1111   */
1112 
1113   const std::size_t max_avail = 0x7FFFFFF0;
1114 
1115   //  Compressed information is saved in a chunk.
1116   bool rc = true;
1117 
1118   std::size_t out__count = 0;
1119   int zrc = Z_OK;
1120 
1121   std::size_t my_avail_in = sizeof___inbuffer;
1122   unsigned char* my_next_in = (unsigned char*)in___buffer;
1123 
1124   std::size_t d = my_avail_in;
1125   if ( d > max_avail )
1126     d = max_avail;
1127 
1128   ON_CompressedBufferHelper& m_zlib = *helper;
1129 
1130   m_zlib.strm.next_in = my_next_in;
1131   m_zlib.strm.avail_in = (unsigned int)d;
1132   my_avail_in -= d;
1133   my_next_in  += d;
1134 
1135   m_zlib.strm.next_out = m_zlib.buffer;
1136   m_zlib.strm.avail_out = m_zlib.sizeof_x_buffer;
1137 
1138   // counter guards prevents infinte loops if there is a bug in zlib return codes.
1139   int counter = 512;
1140   int flush = Z_NO_FLUSH;
1141 
1142   std::size_t deflate_output_count = 0;
1143 
1144   while( rc && counter > 0 )
1145   {
1146     // Call zlib's deflate function.  It can either process
1147     // more input from m_zlib.strm.next_in[], create more
1148     // compressed output in m_zlib.strm.next_out[], or do both.
1149     if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in )
1150     {
1151       // no uncompressed input is left - switch to finish mode
1152       flush = Z_FINISH;
1153     }
1154     zrc = z_deflate( &m_zlib.strm, flush );
1155     if ( zrc < 0 )
1156     {
1157       // Something went haywire - bail out.
1158       ON_ERROR("ON_CompressedBuffer::DeflateHelper - z_deflate failure");
1159       rc = false;
1160       break;
1161     }
1162 
1163     deflate_output_count = m_zlib.sizeof_x_buffer - m_zlib.strm.avail_out;
1164     if ( deflate_output_count > 0 )
1165     {
1166       // The last call to deflate created output.  Send
1167       // this output to the archive.
1168       rc = WriteChar( deflate_output_count, m_zlib.buffer );
1169       if ( !rc )
1170         break;
1171       out__count += deflate_output_count;
1172       m_zlib.strm.next_out  = m_zlib.buffer;
1173       m_zlib.strm.avail_out = m_zlib.sizeof_x_buffer;
1174     }
1175 
1176     if ( Z_FINISH == flush && Z_STREAM_END == zrc )
1177     {
1178       // no input left, all pending compressing is finished,
1179       // and all compressed output has been returned.
1180       break;
1181     }
1182 
1183     if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail )
1184     {
1185       // inbuffer[] had more than max_zlib_avail_in bytes in it
1186       // and I am feeding inbuffer[] to deflate in smaller chunks
1187       // that the 32 bit integers in the zlib code can handle.
1188       if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in )
1189       {
1190         // The call to deflate() used up all the input
1191         // in m_zlib.strm.next_in[].  I can feed it another chunk
1192         // from inbuffer[]
1193         d = my_avail_in;
1194         if ( d > max_avail )
1195           d = max_avail;
1196         m_zlib.strm.next_in = my_next_in;
1197         m_zlib.strm.avail_in = (unsigned int)d;
1198       }
1199       else
1200       {
1201         // The call to deflate left some input in m_zlib.strm.next_in[],
1202         // but I can increase m_zlib.strm.avail_in.
1203         d =  max_avail - m_zlib.strm.avail_in;
1204         if ( d > my_avail_in )
1205           d = my_avail_in;
1206         m_zlib.strm.avail_in += (unsigned int)d;
1207       }
1208 
1209       my_avail_in -= d;
1210       my_next_in  += d;
1211     }
1212     else if ( 0 == deflate_output_count )
1213     {
1214       // no buffer changes this time
1215       counter--;
1216     }
1217 
1218     if ( zrc != Z_OK )
1219     {
1220       break;
1221     }
1222   }
1223 
1224   if ( 0 == counter )
1225   {
1226     rc = false;
1227   }
1228 
1229   return (rc ? out__count : 0);
1230 }
1231 
1232 
InflateHelper(ON_CompressedBufferHelper * helper,std::size_t sizeof___outbuffer,void * out___buffer) const1233 bool ON_CompressedBuffer::InflateHelper(
1234         ON_CompressedBufferHelper* helper,
1235         std::size_t sizeof___outbuffer,  // sizeof uncompressed data
1236         void* out___buffer          // buffer for uncompressed data
1237         ) const
1238 {
1239   const std::size_t max_avail = 0x7FFFFFF0; // See max_avail comment in ON_CompressedBuffer::InflateHelper
1240 
1241   bool rc = true;
1242 
1243   int zrc = -1;
1244 
1245   // set up zlib in buffer
1246   unsigned char* my_next_in = (unsigned char*)m_buffer_compressed;
1247   std::size_t my_avail_in = m_sizeof_compressed;
1248 
1249   std::size_t d = my_avail_in;
1250   if ( d > max_avail )
1251     d = max_avail;
1252 
1253   struct ON_CompressedBufferHelper& m_zlib = *helper;
1254 
1255   m_zlib.strm.next_in  = my_next_in;
1256   m_zlib.strm.avail_in = (unsigned int)d;
1257   my_next_in  += d;
1258   my_avail_in -= d;
1259 
1260   // set up zlib out buffer
1261   unsigned char* my_next_out = (unsigned char*)out___buffer;
1262   std::size_t my_avail_out = sizeof___outbuffer;
1263 
1264   d = my_avail_out;
1265   if ( d > max_avail )
1266     d = max_avail;
1267   m_zlib.strm.next_out  = my_next_out;
1268   m_zlib.strm.avail_out = (unsigned int)d;
1269   my_next_out  += d;
1270   my_avail_out -= d;
1271 
1272   // counter guards against infinte loop if there are
1273   // bugs in zlib return codes
1274   int counter = 512;
1275   int flush = Z_NO_FLUSH;
1276 
1277   while ( rc && counter > 0 )
1278   {
1279     // Call zlib's inflate function.  It can either process
1280     // more input from m_zlib.strm.next_in[], create more
1281     // uncompressed output in m_zlib.strm.next_out[], or do both.
1282     if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in )
1283     {
1284       // no compressed input is left - switch to finish mode
1285       flush = Z_FINISH;
1286     }
1287     zrc = z_inflate( &m_zlib.strm, flush );
1288     if ( zrc < 0 )
1289     {
1290       // Something went haywire - bail out.
1291       ON_ERROR("ON_CompressedBuffer::InflateHelper - z_inflate failure");
1292       rc = false;
1293       break;
1294     }
1295 
1296     if ( Z_FINISH == flush && Z_STREAM_END == zrc )
1297     {
1298       // no input left, all pending decompression is finished,
1299       // and all decompressed output has been returned.
1300       break;
1301     }
1302 
1303     d = 0;
1304     if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail )
1305     {
1306       if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in )
1307       {
1308         // The call to inflate() used up all the input
1309         // in m_zlib.strm.next_in[].  I can feed it another chunk
1310         // from inbuffer[]
1311         d = my_avail_in;
1312         if ( d > max_avail )
1313           d = max_avail;
1314         m_zlib.strm.next_in  = my_next_in;
1315         m_zlib.strm.avail_in = (unsigned int)d;
1316       }
1317       else
1318       {
1319         // The call to inflate() left some input in m_zlib.strm.next_in[],
1320         // but I can increase m_zlib.strm.avail_in.
1321         d =  max_avail - m_zlib.strm.avail_in;
1322         if ( d > my_avail_in )
1323           d = my_avail_in;
1324         m_zlib.strm.avail_in += (unsigned int)d;
1325       }
1326       my_next_in  += d;
1327       my_avail_in -= d;
1328     }
1329 
1330     if ( my_avail_out > 0 && m_zlib.strm.avail_out < max_avail )
1331     {
1332       // increase m_zlib.strm.next_out[] buffer
1333       if ( 0 == m_zlib.strm.avail_out || 0 == m_zlib.strm.next_out )
1334       {
1335         d = my_avail_out;
1336         if ( d > max_avail )
1337           d = max_avail;
1338         m_zlib.strm.next_out  = my_next_out;
1339         m_zlib.strm.avail_out = (unsigned int)d;
1340       }
1341       else
1342       {
1343         d = max_avail - m_zlib.strm.avail_out;
1344         if ( d > my_avail_out )
1345           d = my_avail_out;
1346         m_zlib.strm.avail_out += ((unsigned int)d);
1347       }
1348       my_next_out  += d;
1349       my_avail_out -= d;
1350     }
1351     else if ( 0 == d )
1352     {
1353       // no buffer changes
1354       counter--;
1355     }
1356   }
1357 
1358   if ( 0 == counter )
1359   {
1360     rc = false;
1361   }
1362 
1363   return rc;
1364 }
1365 
CompressionInit(struct ON_CompressedBufferHelper * helper) const1366 bool ON_CompressedBuffer::CompressionInit( struct ON_CompressedBufferHelper* helper ) const
1367 {
1368   bool rc = false;
1369 
1370   if ( helper )
1371   {
1372     // inflateInit() and deflateInit() are in zlib 1.3.3
1373     if ( 1 == helper->action )
1374     {
1375       // begin compression using zlib's deflate tool
1376       if ( Z_OK == deflateInit( &helper->strm, Z_BEST_COMPRESSION ) )
1377       {
1378         rc = true;
1379       }
1380       else
1381       {
1382         memset(&helper->strm,0,sizeof(helper->strm));
1383         helper->action = 0;
1384       }
1385     }
1386     else if ( 2 == helper->action )
1387     {
1388       // begin uncompression using zlib's inflate tool
1389       if ( Z_OK == inflateInit( &helper->strm ) )
1390       {
1391         rc = true;
1392       }
1393       else
1394       {
1395         memset(&helper->strm,0,sizeof(helper->strm));
1396         helper->action = 0;
1397       }
1398     }
1399   }
1400 
1401   return rc;
1402 }
1403 
CompressionEnd(struct ON_CompressedBufferHelper * helper) const1404 bool ON_CompressedBuffer::CompressionEnd( struct ON_CompressedBufferHelper* helper ) const
1405 {
1406   bool rc = false;
1407 
1408   if ( helper )
1409   {
1410     // inflateEnd() and deflateEnd() are in zlib 1.3.3
1411     if ( 1 == helper->action )
1412     {
1413       // finish compression
1414       deflateEnd(&helper->strm);
1415       rc = true;
1416     }
1417     else if ( 2 == helper->action )
1418     {
1419       // finish decompression
1420       inflateEnd(&helper->strm);
1421       rc = true;
1422     }
1423     memset(&helper->strm,0,sizeof(helper->strm));
1424     helper->action = 0;
1425   }
1426 
1427   return rc;
1428 }
1429 
1430 
1431