fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / FileIO / Base / OSGZStream.inl
blob2afb756dc191f7b9ef5ab60e5a92b437a43231dd
2 OSG_BEGIN_NAMESPACE
4 //*****************************************************************************
5 //  template class basic_zip_streambuf
6 //*****************************************************************************
8 //-----------------------------------------------------------------------------
9 // PUBLIC
10 //-----------------------------------------------------------------------------
12 /* Construct a zip stream
13  * More info on the following parameters can be found in the zlib documentation.
14  */
16 #ifdef OSG_DEBUG_OLD_C_CASTS
17 # if ZLIB_VERNUM >= 0x1270
18 #  ifdef deflateInit2
19 #   undef deflateInit2
20 #   define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
21            deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
22                          (strategy), ZLIB_VERSION, int(sizeof(z_stream)))
24 #  endif
25 # endif
26 #endif
28 template <class charT, class traits> inline
29 basic_zip_streambuf<charT, 
30                     traits>::basic_zip_streambuf(
31                         ostream_reference ostream,
32                         int               level,
33                         EStrategy         strategy,
34                         int               window_size,
35                         int               memory_level,
36                         size_t            buffer_size ) :
37     _ostream      (ostream       ),
38     _zip_stream   (              ),
39     _err          (0             ),
40     _output_buffer(buffer_size, 0),
41     _buffer       (buffer_size, 0),
42     _crc          (0             )
44     _zip_stream.zalloc = NULL;
45     _zip_stream.zfree  = NULL;
47     _zip_stream.next_in   = NULL;
48     _zip_stream.avail_in  = 0;
49     _zip_stream.avail_out = 0;
50     _zip_stream.next_out  = NULL;
52     if(level > 9)
53         level = 9;
54         
55     if(memory_level > 9)
56         memory_level = 9;
57         
58     _err=deflateInit2(&_zip_stream, 
59                       level, 
60                       Z_DEFLATED,
61                       window_size, 
62                       memory_level,
63                       static_cast<int>(strategy));
65     this->setp(&(_buffer[0]), &(_buffer[_buffer.size() - 1]));
68 #ifdef OSG_DEBUG_OLD_C_CASTS
69 # if ZLIB_VERNUM >= 0x1270
70 #  ifdef deflateInit2
71 #   undef deflateInit2
72 #   define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
73            deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
74                          (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
75 #  endif
76 # endif
77 #endif
79 /* Destructor
80  */
81 template <class charT, class traits> inline
82 basic_zip_streambuf<charT, traits>::~basic_zip_streambuf(void)
84     flush();
85     _ostream.flush();
86     _err=deflateEnd(&_zip_stream);
89 /* Do the synchronization
90  * @todo
91  * document correctly!
92  */
93 template <class charT, class traits> inline
94 int basic_zip_streambuf<charT, traits>::sync(void)
95
96     if(this->pptr() && this->pptr() > this->pbase()) 
97     {
98         /*int c =*/ overflow(EOF);
100         // ACHTUNG wenn das drin ist hoert er nach dem ersten endl auf!
101         /*
102           if ( c == EOF)
103           return -1;
104         */
105     }
107     return 0;
110 /* <unknown purpose>
111  * @todo
112  * document correctly!
113  */
114 template <class charT, class traits> inline
115 typename basic_zip_streambuf<charT, traits>::int_type
116 basic_zip_streambuf<charT, traits>::overflow(int_type c)
118     int w = static_cast<int>(this->pptr() - this->pbase());
119     if (c != EOF)
120     {
121         *this->pptr() = c;
122         ++w;
123     }
124     if (zip_to_stream(this->pbase(), w))
125     {
126         this->setp(this->pbase(), this->epptr() - 1);
127         return c;
128     }
129     else
130     {
131         return EOF;
132     }
135 /* flushes the zip buffer and output buffer.
137  *    This method should be called at the end of the compression. Calling flush
138  *    multiple times, will lower the compression ratio.
139  */
140 template <class charT, class traits> inline
141 std::streamsize basic_zip_streambuf<charT, traits>::flush(void)
143     std::streamsize written_byte_size = 0, total_written_byte_size = 0;
145     size_t remainder = 0;
147     // updating crc
148     _crc = crc32(_crc,  _zip_stream.next_in,
149                  _zip_stream.avail_in);        
151     do
152     {
153         _err = deflate(&_zip_stream, Z_FINISH);
154         if(_err == Z_OK || _err == Z_STREAM_END)
155         {
156             written_byte_size = static_cast<std::streamsize>(_output_buffer.size()) - _zip_stream.avail_out;
157             total_written_byte_size += written_byte_size;
158             // ouput buffer is full, dumping to ostream
159             _ostream.write( reinterpret_cast<const char_type*>(&(_output_buffer[0])),
160                             static_cast<std::streamsize>(written_byte_size/sizeof(char_type)*sizeof(char)));
161             
162             // checking if some bytes were not written.
163             if((remainder = written_byte_size%sizeof(char_type)) != 0)
164             {
165                 // copy to the beginning of the stream
166                 memcpy(&(_output_buffer[0]), 
167                        &(_output_buffer[written_byte_size-remainder]), remainder);
168                     
169             }
170                 
171             _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size() - remainder);
172             _zip_stream.next_out = &_output_buffer[remainder];
173         }
174     }
175     while(_err == Z_OK);
177     _ostream.flush();
179     return total_written_byte_size;
182 /* returns a reference to the output stream
183  */
184 template <class charT, class traits> inline 
185 typename basic_zip_streambuf<charT, traits>::ostream_reference
186 basic_zip_streambuf<charT, traits>::get_ostream(void) const
188     return _ostream;
191 /* returns the latest zlib error status
192  */
193 template <class charT, class traits> inline
194 int basic_zip_streambuf<charT, traits>::get_zerr(void) const
196     return _err;
199 /* returns the crc of the input data compressed so far.
200  */
201 template <class charT, class traits> inline
202 unsigned long
203 basic_zip_streambuf<charT, traits>:: get_crc(void) const
205     return _crc;
208 /*  returns the size (bytes) of the input data compressed so far.
209  */
210 template <class charT, class traits> inline
211 unsigned long
212 basic_zip_streambuf<charT, traits>::get_in_size(void) const
214     return _zip_stream.total_in;
217 /*  returns the size (bytes) of the compressed data so far.
218  */
219 template <class charT, class traits> inline
220 long 
221 basic_zip_streambuf<charT, traits>::get_out_size(void) const
223     return _zip_stream.total_out;
226 //-----------------------------------------------------------------------------
227 // PRIVATE
228 //-----------------------------------------------------------------------------
230 /* <undocumented>
231  * @todo
232  * document!
233  */
234 template <class charT, class traits> inline
235 bool basic_zip_streambuf<charT, traits>::zip_to_stream(
236     char_type *buffer,
237     std::streamsize buffer_size)
238 {    
239     std::streamsize written_byte_size = 0, total_written_byte_size = 0;
241     _zip_stream.next_in = reinterpret_cast<byte_buffer_type>(buffer);
242     _zip_stream.avail_in = static_cast<uInt>(buffer_size * sizeof(char_type));
243     _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size());
244     _zip_stream.next_out = &_output_buffer[0];
245     size_t remainder = 0;
247     // updating crc
248     _crc = crc32(_crc, _zip_stream.next_in,
249                  _zip_stream.avail_in);        
251     do
252     {
253         _err = deflate(&_zip_stream, 0);
254     
255         if (_err == Z_OK  || _err == Z_STREAM_END)
256         {
257             written_byte_size= static_cast<std::streamsize>(_output_buffer.size()) -
258                 _zip_stream.avail_out;
259             total_written_byte_size += written_byte_size;
260             // ouput buffer is full, dumping to ostream
262             _ostream.write(reinterpret_cast<const char_type*>(&_output_buffer[0]), 
263                            static_cast<std::streamsize>(written_byte_size / sizeof(char_type)));
264                                                 
265             // checking if some bytes were not written.
266             if((remainder = written_byte_size % sizeof(char_type)) != 0)
267             {
268                 // copy to the beginning of the stream
269                 memcpy(&_output_buffer[0], 
270                        &_output_buffer[written_byte_size-remainder],
271                        remainder);
272             }
273                 
274             _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size()-remainder);
275             _zip_stream.next_out = &_output_buffer[remainder];
276         }
277     } 
278     while(_zip_stream.avail_in != 0 && _err == Z_OK);
279     
280     return _err == Z_OK;
289 //*****************************************************************************
290 //  template class basic_unzip_streambuf
291 //*****************************************************************************
293 //-----------------------------------------------------------------------------
294 // PUBLIC
295 //-----------------------------------------------------------------------------
297 /* Constructor
298  */
300 #ifdef OSG_DEBUG_OLD_C_CASTS
301 # if ZLIB_VERNUM >= 0x1270
302 #  ifdef inflateInit2
303 #   undef inflateInit2
304 #   define inflateInit2(strm, windowBits) \
305            inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
306                          int(sizeof(z_stream)))
308 #  endif
309 # endif
310 #endif
312 template <class charT, class traits> inline
313 basic_unzip_streambuf<charT, traits>::basic_unzip_streambuf(
314     istream_reference istream,
315     int               window_size,
316     size_t            read_buffer_size,
317     size_t            input_buffer_size) :
319     _input_buffer(input_buffer_size),
320     _buffer      (read_buffer_size ),
321     _streamType  (UNKNOWN_ST       ),
322     _istream     (istream          ),
323     _zip_stream  (                 ),
324     _err         (0                ),
325     _crc         (0                )
327     // setting zalloc, zfree and opaque
328     _zip_stream.zalloc = NULL;
329     _zip_stream.zfree  = NULL;
331     _zip_stream.next_in   = NULL;
332     _zip_stream.avail_in  = 0;
333     _zip_stream.avail_out = 0;
334     _zip_stream.next_out  = NULL;
336     _err = inflateInit2(&_zip_stream, window_size);
337         
338     this->setg(&_buffer[0] + 4,     // beginning of putback area
339                &_buffer[0] + 4,     // read position
340                &_buffer[0] + 4);    // end position    
343 #ifdef OSG_DEBUG_OLD_C_CASTS
344 # if ZLIB_VERNUM >= 0x1270
345 #  ifdef inflateInit2
346 #   undef inflateInit2
347 #   define inflateInit2(strm, windowBits) \
348            inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
349                         (int)sizeof(z_stream))
351 #  endif
352 # endif
353 #endif
356  * @todo document!
357  */
358 template <class charT, class traits> inline
359 basic_unzip_streambuf<charT, traits>::~basic_unzip_streambuf(void)
361     inflateEnd(&_zip_stream);
366  * @todo document!
367  */
368 template <class charT, class traits> inline
369 typename basic_unzip_streambuf<charT, traits>::int_type
370 basic_unzip_streambuf<charT, traits>::underflow(void)
372     if(this->gptr() && ( this->gptr() < this->egptr()))
373         return * reinterpret_cast<unsigned char *>(this->gptr());
374      
375     int n_putback = static_cast<int>(this->gptr() - this->eback());
376     if(n_putback > 4)
377         n_putback = 4;
378        
379     memcpy(&_buffer[0] + (4 - n_putback),
380            this->gptr() - n_putback,
381            n_putback * sizeof(char_type));
382   
383     int num = 
384         unzip_from_stream(&_buffer[0] + 4, 
385                           static_cast<std::streamsize>((_buffer.size() - 4) *
386                                                        sizeof(char_type)));
387         
388     if(num <= 0) // ERROR or EOF
389         return EOF;
390     
391     // reset buffer pointers
392     this->setg(&_buffer[0] + (4 - n_putback),   // beginning of putback area
393                &_buffer[0] + 4,                 // read position
394                &_buffer[0] + 4 + num);          // end of buffer
395     
396     // return next character
397     return * reinterpret_cast<unsigned char *>(this->gptr());    
400 /* returns the compressed input istream
401  */
402 template <class charT, class traits> inline
403 typename basic_unzip_streambuf<charT, traits>::istream_reference
404 basic_unzip_streambuf<charT, traits>::get_istream(void)
406     return _istream;
409 /* returns the zlib stream structure
410  */
411 template <class charT, class traits> inline
412 z_stream &
413 basic_unzip_streambuf<charT, traits>::get_zip_stream(void)
415     return _zip_stream;
418 /* returns the latest zlib error state
419  */
420 template <class charT, class traits> inline
422 basic_unzip_streambuf<charT, traits>::get_zerr(void) const
424     return _err;
427 /* returns the crc of the uncompressed data so far
428  */
429 template <class charT, class traits> inline
430 unsigned long
431 basic_unzip_streambuf<charT, traits>::get_crc(void) const
433     return _crc;
436 /* returns the number of uncompressed bytes
437  */
438 template <class charT, class traits> inline
439 long
440 basic_unzip_streambuf<charT, traits>::get_out_size(void) const
442     return _zip_stream.total_out;
445 /* returns the number of read compressed bytes
446  */
447 template <class charT, class traits> inline
448 long
449 basic_unzip_streambuf<charT, traits>::get_in_size(void) const
451     return _zip_stream.total_in;
455 //-----------------------------------------------------------------------------
456 // PRIVATE
457 //-----------------------------------------------------------------------------
459 /* 
460  */
461 template <class charT, class traits> inline
462 void
463 basic_unzip_streambuf<charT, traits>::put_back_from_zip_stream(void)
465     if(_zip_stream.avail_in == 0)
466         return;
468     _istream.clear(std::ios::goodbit);
469     _istream.seekg(-intf(_zip_stream.avail_in),
470                    std::ios_base::cur);
472     _zip_stream.avail_in = 0;
475 /* 
476  */
477 template <class charT, class traits> inline
478 std::streamsize
479 basic_unzip_streambuf<charT, traits>::unzip_from_stream(char_type* buffer,
480                                                         std::streamsize buffer_size)
482     _zip_stream.next_out  = 
483         reinterpret_cast<byte_buffer_type>(buffer);
484     _zip_stream.avail_out = 
485         static_cast<uInt>(buffer_size * sizeof(char_type));
486     size_t count = _zip_stream.avail_in;
488     do
489     {
490         if(_zip_stream.avail_in == 0)
491             count=fill_input_buffer();
493         if(_zip_stream.avail_in)
494         {
495           switch (_streamType) {
496           case GZIP_ST:            
497             _err = inflate(&_zip_stream,  Z_SYNC_FLUSH);
498             break;
499           case DATA_ST:
500             if (_zip_stream.avail_out < count)
501               count = _zip_stream.avail_out;
502             memcpy ( _zip_stream.next_out, _zip_stream.next_in, count );
503             _zip_stream.avail_in  -= count;
504             _zip_stream.avail_out -= count;
505             _zip_stream.next_in   += count;
506             _zip_stream.next_out  += count;
507             break;
508           default:
509             FWARNING (("Unknown _streamType: %d\n", _streamType ));
510             break;
511           }            
512         }
513     }
514     while(_err==Z_OK && _zip_stream.avail_out != 0 && count != 0);
516     // updating crc
517     _crc = crc32(_crc, reinterpret_cast<byte_buffer_type>(buffer),
518                  buffer_size - _zip_stream.avail_out / sizeof(char_type));
519         
520     std::streamsize n_read = 
521         buffer_size - _zip_stream.avail_out / sizeof(char_type);
522         
523     // check if it is the end
524     if (_err == Z_STREAM_END)
525         put_back_from_zip_stream();                
526         
527     return n_read;
531 /* 
532  */
533 template <class charT, class traits> inline
534 size_t
535 basic_unzip_streambuf<charT, traits>::fill_input_buffer(void)
537     _zip_stream.next_in = &_input_buffer[0];
538     _istream.read(reinterpret_cast<char_type*>(&_input_buffer[0]), 
539                   static_cast<std::streamsize>(_input_buffer.size() /
540                                                sizeof(char_type)));
541         
542     return _zip_stream.avail_in = _istream.gcount()*sizeof(char_type);
551 //*****************************************************************************
552 //  template class basic_zip_ostream
553 //*****************************************************************************
555 //-----------------------------------------------------------------------------
556 // PUBLIC
557 //-----------------------------------------------------------------------------
560  */
561 template <class charT, class traits> inline
562 basic_zip_ostream<charT, traits>::basic_zip_ostream(ostream_reference ostream,
563                                                     bool isGzip,
564                                                     int level,
565                                                     EStrategy strategy,
566                                                     int window_size,
567                                                     int memory_level,
568                                                     size_t buffer_size) :
569     basic_zip_streambuf<charT, traits>(ostream, level, strategy, window_size,
570                                        memory_level, buffer_size),
571     std::basic_ostream<charT, traits>(this),
572     _is_gzip(isGzip),
573     _added_footer(false)
575     if(_is_gzip)
576         add_header();
579 /* Destructor
580  */
581 template <class charT, class traits> inline
582 basic_zip_ostream<charT, traits>::~basic_zip_ostream(void)
584     if(_is_gzip)
585         add_footer();
588 /* returns true if it is a gzip
589  */
590 template <class charT, class traits> inline
591 bool basic_zip_ostream<charT, traits>::is_gzip(void) const
593     return _is_gzip;
596 /* flush inner buffer and zipper buffer
597  */
599 template <class charT, class traits> inline
600 basic_zip_ostream<charT, traits>& basic_zip_ostream<charT, traits>::zflush(void)
602     std::basic_ostream<charT, traits>::flush();
603     basic_zip_streambuf<charT, traits>::flush();
604     return *this;
607 template <class charT, class traits> inline
608 void basic_zip_ostream<charT, traits>::finished(void)
610     if(_is_gzip)
611         add_footer();
612     else
613         zflush();
617 //-----------------------------------------------------------------------------
618 // PRIVATE
619 //-----------------------------------------------------------------------------
622  * @todo document!
623  */
624 template <class charT, class traits> inline
625 basic_zip_ostream<charT,traits>& basic_zip_ostream<charT, traits>::add_header(void)
627     char_type zero = 0;
628         
629     this->get_ostream() << static_cast<char_type>(detail::gz_magic[0])
630                         << static_cast<char_type>(detail::gz_magic[1])
631                         << static_cast<char_type>(Z_DEFLATED)
632                         << zero //flags
633                         << zero<<zero<<zero<<zero // time
634                         << zero //xflags
635                         << static_cast<char_type>(OS_CODE);
636         
637     return *this;
641  * @todo document!
642  */
643 template <class charT, class traits> inline
644 basic_zip_ostream<charT,traits>& basic_zip_ostream<charT, traits>::add_footer(void)
646     if(_added_footer)
647         return *this;
649     zflush();
651     _added_footer = true;
653     // Writes crc and length in LSB order to the stream.
654     unsigned long crc = this->get_crc();
655     for(int n=0;n<4;++n)
656     {
657         this->get_ostream().put(int(crc & 0xff));
658         crc >>= 8;
659     }
661     unsigned long length = this->get_in_size();
662     for(int n=0;n<4;++n)
663     {
664         this->get_ostream().put(int(length & 0xff));
665         length >>= 8;
666     }
668     return *this;
676 //*****************************************************************************
677 //  template class basic_zip_istream
678 //*****************************************************************************
680 //-----------------------------------------------------------------------------
681 // PUBLIC
682 //-----------------------------------------------------------------------------
684 /* Constructor
685  */
686 template <class charT, class traits> inline
687 basic_zip_istream<charT, traits>::basic_zip_istream(istream_reference istream,
688                                                     int window_size,
689                                                     size_t read_buffer_size,
690                                                     size_t input_buffer_size)
691     : basic_unzip_streambuf<charT, traits>(istream, window_size,
692                                            read_buffer_size, input_buffer_size),
693       std::basic_istream<charT, traits>(this),
694       _is_gzip(false),
695       _gzip_crc(0),
696       _gzip_data_size(0)
698     if(this->get_zerr() == Z_OK)
699         check_header();
702 /* returns true if it is a gzip file
703  */
704 template <class charT, class traits> inline
705 bool
706 basic_zip_istream<charT, traits>::is_gzip(void) const
708     return _is_gzip;
711 /* return crc check result
713  * This must be called after the reading of compressed data is finished!  This
714  * method compares it to the crc of the uncompressed data.
716  *    \return true if crc check is succesful
717  */
718 template <class charT, class traits> inline
719 bool
720 basic_zip_istream<charT, traits>::check_crc(void)
722     read_footer();
723     return this->get_crc() == static_cast<unsigned long>(_gzip_crc);
726 /* return data size check
727  */
728 template <class charT, class traits> inline
729 bool
730 basic_zip_istream<charT, traits>::check_data_size(void) const
732     return this->get_out_size() == _gzip_data_size;
735 /* return the crc value in the file
736  */
737 template <class charT, class traits> inline
738 long
739 basic_zip_istream<charT, traits>::get_gzip_crc(void) const
741     return _gzip_crc;
744 /* return the data size in the file
745  */
746 template <class charT, class traits> inline
747 long
748 basic_zip_istream<charT, traits>::get_gzip_data_size(void) const
750     return _gzip_data_size;
753 //-----------------------------------------------------------------------------
754 // PROTECTED
755 //-----------------------------------------------------------------------------
758  * @todo document!
759  */
760 template <class charT, class traits> inline
762 basic_zip_istream<charT, traits>::check_header(void)
764     int method; /* method byte */
765     int localFlags;  /* flags byte */
766     uInt len;
767     int c;
768     int err=0;
769     z_stream &zip_stream = this->get_zip_stream();
771     /* Check the gzip magic header */
772     zip_stream.next_in = &this->_input_buffer[0];
773     this->get_istream().read( reinterpret_cast<char*>(&this->_input_buffer[0]), 2 );
774     zip_stream.avail_in = this->get_istream().gcount();
776     if ( (zip_stream.avail_in >= 2) &&
777          (this->_input_buffer[0] == detail::gz_magic[0]) &&
778          (this->_input_buffer[1] == detail::gz_magic[1]) ) {      
779       this->_streamType = BufferType::GZIP_ST;
780       zip_stream.avail_in = 0;
781     } 
782     else {
783       this->_streamType = BufferType::DATA_ST;            
784       _is_gzip = false;
785       err = zip_stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
786       return err;
787     }
788     
789     _is_gzip = true;
790     method = int(this->get_istream().get());
791     localFlags  = int(this->get_istream().get());
792     if (method != Z_DEFLATED || (localFlags & detail::gz_reserved) != 0) 
793     {
794         err = Z_DATA_ERROR;
795         return err;
796     }
798     /* Discard time, xflags and OS code: */
799     for (len = 0; len < 6; len++) 
800         this->get_istream().get();
801     
802     if ((localFlags & detail::gz_extra_field) != 0) 
803     { 
804         /* skip the extra field */
805         len  =  uInt(this->get_istream().get());
806         len += uInt(this->get_istream().get())<<8;
807         /* len is garbage if EOF but the loop below will quit anyway */
808         while (len-- != 0 && this->get_istream().get() != EOF) ;
809     }
810     if ((localFlags & detail::gz_orig_name) != 0) 
811     { 
812         /* skip the original file name */
813         while ((c = this->get_istream().get()) != 0 && c != EOF) ;
814     }
815     if ((localFlags & detail::gz_comment) != 0) 
816     {   
817         /* skip the .gz file comment */
818         while ((c = this->get_istream().get()) != 0 && c != EOF) ;
819     }
820     if ((localFlags & detail::gz_head_crc) != 0) 
821     {  /* skip the header crc */
822         for (len = 0; len < 2; len++) 
823             this->get_istream().get();
824     }
825     err = this->get_istream().eof() ? Z_DATA_ERROR : Z_OK;
827     return err;
831  * @todo document!
832  */
833 template <class charT, class traits> inline
834 void
835 basic_zip_istream<charT, traits>::read_footer(void)
836 {        
837     if(_is_gzip)
838     {
839         _gzip_crc = 0;
840         for(int n=0;n<4;++n)
841             _gzip_crc += ((int(this->get_istream().get()) & 0xff) << (8*n));
843         _gzip_data_size = 0;
844         for(int n=0;n<4;++n)
845             _gzip_data_size += 
846                 ((int(this->get_istream().get()) & 0xff) << (8*n));
847     }
850 OSG_END_NAMESPACE