Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / iostreams / filter / gzip.hpp
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2003-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5
6 // See http://www.boost.org/libs/iostreams for documentation.
7
8 // Contains the definitions of the class templates gzip_compressor and
9 // gzip_decompressor for reading and writing files in the gzip file format
10 // (RFC 1952). Based in part on work of Jonathan de Halleux; see [...]
11
12 #ifndef BOOST_IOSTREAMS_GZIP_HPP_INCLUDED
13 #define BOOST_IOSTREAMS_GZIP_HPP_INCLUDED
14
15 #if defined(_MSC_VER)
16 # pragma once
17 #endif
18
19 #include <boost/config.hpp> // STATIC_CONSTANT, STDC_NAMESPACE, 
20                             // DINKUMWARE_STDLIB, __STL_CONFIG_H.
21 #include <algorithm>                      // min.
22 #include <boost/assert.hpp>
23 #include <cstdio>                         // EOF.
24 #include <cstddef>                        // size_t.
25 #include <ctime>                          // std::time_t.
26 #include <memory>                         // allocator.
27 #include <boost/config.hpp>               // Put size_t in std.
28 #include <boost/detail/workaround.hpp>
29 #include <boost/cstdint.hpp>              // uint8_t, uint32_t.
30 #include <boost/iostreams/checked_operations.hpp>
31 #include <boost/iostreams/constants.hpp>  // buffer size.
32 #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
33 #include <boost/iostreams/detail/adapter/range_adapter.hpp>
34 #include <boost/iostreams/detail/char_traits.hpp>
35 #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
36 #include <boost/iostreams/detail/error.hpp>
37 #include <boost/iostreams/operations.hpp>
38 #include <boost/iostreams/device/back_inserter.hpp>
39 #include <boost/iostreams/filter/zlib.hpp>
40 #include <boost/iostreams/pipeline.hpp>     
41 #include <boost/iostreams/putback.hpp>
42 #include <boost/throw_exception.hpp>
43
44 // Must come last.
45 #if defined(BOOST_MSVC)
46 # pragma warning(push)
47 # pragma warning(disable:4244)    // Possible truncation
48 # pragma warning(disable:4251)    // Missing DLL interface for std::string
49 # pragma warning(disable:4309)    // Truncation of constant value.
50 #endif
51
52 #ifdef BOOST_NO_STDC_NAMESPACE
53 namespace std { using ::time_t; }
54 #endif
55
56 namespace boost { namespace iostreams {
57                     
58 //------------------Definitions of constants----------------------------------//
59
60 namespace gzip {
61
62 using namespace boost::iostreams::zlib;
63
64     // Error codes used by gzip_error.
65
66 const int zlib_error        = 1;
67 const int bad_crc           = 2; // Recorded crc doesn't match data.
68 const int bad_length        = 3; // Recorded length doesn't match data.
69 const int bad_header        = 4; // Malformed header.
70 const int bad_footer        = 5; // Malformed footer.
71 const int bad_method        = 6; // Unsupported compression method.
72
73 namespace magic {
74
75     // Magic numbers used by gzip header.
76
77 const int id1               = 0x1f;
78 const int id2               = 0x8b;
79
80 } // End namespace magic.
81
82 namespace method {
83
84     // Codes used for the 'CM' byte of the gzip header.
85
86 const int deflate           = 8;
87
88 } // End namespace method.
89
90 namespace flags {
91
92     // Codes used for the 'FLG' byte of the gzip header.
93
94 const int text              = 1;
95 const int header_crc        = 2;
96 const int extra             = 4;
97 const int name              = 8;
98 const int comment           = 16;
99
100 } // End namespace flags.
101
102 namespace extra_flags {
103
104     // Codes used for the 'XFL' byte of the gzip header.
105
106 const int best_compression  = 2;
107 const int best_speed        = 4;
108
109 } // End namespace extra_flags.
110
111     // Codes used for the 'OS' byte of the gzip header.
112
113 const int os_fat            = 0;
114 const int os_amiga          = 1;
115 const int os_vms            = 2;
116 const int os_unix           = 3;
117 const int os_vm_cms         = 4;
118 const int os_atari          = 5;
119 const int os_hpfs           = 6;
120 const int os_macintosh      = 7;
121 const int os_z_system       = 8;
122 const int os_cp_m           = 9;
123 const int os_tops_20        = 10;
124 const int os_ntfs           = 11;
125 const int os_qdos           = 12;
126 const int os_acorn          = 13;
127 const int os_unknown        = 255;
128
129 } // End namespace gzip.
130
131 //------------------Definition of gzip_params---------------------------------//
132
133 //
134 // Class name: gzip_params.
135 // Description: Subclass of zlib_params with an additional field
136 //      representing a file name.
137 //
138 struct gzip_params : zlib_params {
139
140     // Non-explicit constructor.
141     gzip_params( int level              = gzip::default_compression,
142                  int method             = gzip::deflated,
143                  int window_bits        = gzip::default_window_bits,
144                  int mem_level          = gzip::default_mem_level,
145                  int strategy           = gzip::default_strategy,
146                  std::string file_name_  = "",
147                  std::string comment_    = "",
148                  std::time_t mtime_      = 0 )
149         : zlib_params(level, method, window_bits, mem_level, strategy),
150           file_name(file_name_), comment(comment_), mtime(mtime_)
151         { }
152     std::string  file_name;
153     std::string  comment;
154     std::time_t  mtime;
155 };
156
157 //------------------Definition of gzip_error----------------------------------//
158
159 //
160 // Class name: gzip_error.
161 // Description: Subclass of std::ios_base::failure thrown to indicate
162 //     zlib errors other than out-of-memory conditions.
163 //
164 class gzip_error : public BOOST_IOSTREAMS_FAILURE {
165 public:
166     explicit gzip_error(int error)
167         : BOOST_IOSTREAMS_FAILURE("gzip error"),
168           error_(error), zlib_error_code_(zlib::okay) { }
169     explicit gzip_error(const zlib_error& e)
170         : BOOST_IOSTREAMS_FAILURE("gzip error"),
171           error_(gzip::zlib_error), zlib_error_code_(e.error())
172         { }
173     int error() const { return error_; }
174     int zlib_error_code() const { return zlib_error_code_; }
175 private:
176     int error_;
177     int zlib_error_code_;
178 };
179
180 //------------------Definition of gzip_compressor-----------------------------//
181
182 //
183 // Template name: gzip_compressor
184 // Description: Model of OutputFilter implementing compression in the
185 //      gzip format.
186 //
187 template<typename Alloc = std::allocator<char> >
188 class basic_gzip_compressor : basic_zlib_compressor<Alloc> {
189 private:
190     typedef basic_zlib_compressor<Alloc>  base_type;
191 public:
192     typedef char char_type;
193     struct category
194         : dual_use,
195           filter_tag,
196           multichar_tag,
197           closable_tag
198         { };
199     basic_gzip_compressor( const gzip_params& = gzip::default_compression,
200                            std::streamsize buffer_size = default_device_buffer_size );
201
202     template<typename Source>
203     std::streamsize read(Source& src, char_type* s, std::streamsize n)
204     {
205         std::streamsize result = 0;
206
207         // Read header.
208         if (!(flags_ & f_header_done))
209             result += read_string(s, n, header_);
210
211         // Read body.
212         if (!(flags_ & f_body_done)) {
213
214             // Read from basic_zlib_filter.
215             std::streamsize amt = base_type::read(src, s + result, n - result);
216             if (amt != -1) {
217                 result += amt;
218                 if (amt < n - result) { // Double-check for EOF.
219                     amt = base_type::read(src, s + result, n - result);
220                     if (amt != -1)
221                         result += amt;
222                 }
223             }
224             if (amt == -1)
225                 prepare_footer();
226         }
227
228         // Read footer.
229         if ((flags_ & f_body_done) != 0 && result < n)
230             result += read_string(s + result, n - result, footer_);
231
232         return result != 0 ? result : -1;
233     }
234
235     template<typename Sink>
236     std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
237     {
238         if (!(flags_ & f_header_done)) {
239             std::streamsize amt = 
240                 static_cast<std::streamsize>(header_.size() - offset_);
241             offset_ += boost::iostreams::write_if(snk, header_.data() + offset_, amt);
242             if (offset_ == header_.size())
243                 flags_ |= f_header_done;
244             else
245                 return 0;
246         }
247         return base_type::write(snk, s, n);
248     }
249
250     template<typename Sink>
251     void close(Sink& snk, BOOST_IOS::openmode m)
252     {
253         try {
254             if (m == BOOST_IOS::out && !(flags_ & f_header_done))
255                 this->write(snk, 0, 0);
256
257             // Close zlib compressor.
258             base_type::close(snk, m);
259
260             if (m == BOOST_IOS::out) {
261                 if (flags_ & f_header_done) {
262
263                     // Write final fields of gzip file format.
264                     write_long(this->crc(), snk);
265                     write_long(this->total_in(), snk);
266                 }
267             }
268         } catch(...) {
269             close_impl();
270             throw;
271         }
272         close_impl();
273     }
274 private:
275     static gzip_params normalize_params(gzip_params p);
276     void prepare_footer();
277     std::streamsize read_string(char* s, std::streamsize n, std::string& str);
278
279     template<typename Sink>
280     static void write_long(long n, Sink& next, boost::mpl::true_)
281     {
282         boost::iostreams::put(next, static_cast<char>(0xFF & n));
283         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 8)));
284         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 16)));
285         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 24)));
286     }
287     template<typename Sink>
288     static void write_long(long, Sink&, boost::mpl::false_)
289     {
290     }
291     template<typename Sink>
292     static void write_long(long n, Sink& next)
293     {
294         typedef typename category_of<Sink>::type category;
295         typedef is_convertible<category, output> can_write;
296         write_long(n, next, can_write());
297     }
298
299     void close_impl()
300     {
301         footer_.clear();
302         offset_ = 0;
303         flags_ = 0;
304     }
305
306     enum state_type {
307         f_header_done = 1,
308         f_body_done = f_header_done << 1,
309         f_footer_done = f_body_done << 1
310     };
311     std::string  header_;
312     std::string  footer_;
313     std::size_t  offset_;
314     int          flags_;
315 };
316 BOOST_IOSTREAMS_PIPABLE(basic_gzip_compressor, 1)
317
318 typedef basic_gzip_compressor<> gzip_compressor;
319
320 //------------------Definition of helper templates for decompression----------//
321
322 namespace detail {
323
324 // Processes gzip headers
325 class BOOST_IOSTREAMS_DECL gzip_header {
326 public:
327     gzip_header() { reset(); }
328
329     // Members for processing header data
330     void process(char c);
331     bool done() const { return state_ == s_done; }
332     void reset();
333
334     // Members for accessing header data
335     std::string file_name() const { return file_name_; }
336     std::string comment() const { return comment_; }
337     bool text() const { return (flags_ & gzip::flags::text) != 0; }
338     int os() const { return os_; }
339     std::time_t mtime() const { return mtime_; }
340 private:
341     enum state_type {
342         s_id1       = 1,
343         s_id2       = s_id1 + 1,
344         s_cm        = s_id2 + 1,
345         s_flg       = s_cm + 1,
346         s_mtime     = s_flg + 1,
347         s_xfl       = s_mtime + 1,
348         s_os        = s_xfl + 1,
349         s_xlen      = s_os + 1,
350         s_extra     = s_xlen + 1,
351         s_name      = s_extra + 1,
352         s_comment   = s_name + 1,
353         s_hcrc      = s_comment + 1,
354         s_done      = s_hcrc + 1
355     };
356     std::string  file_name_;
357     std::string  comment_;
358     int          os_;
359     std::time_t  mtime_;
360     int          flags_;
361     int          state_;
362     int          offset_;  // Offset within fixed-length region.
363     int          xlen_;    // Bytes remaining in extra field.
364 };
365
366 // Processes gzip footers
367 class BOOST_IOSTREAMS_DECL gzip_footer {
368 public:
369     gzip_footer() { reset(); }
370     
371     // Members for processing footer data
372     void process(char c);
373     bool done() const { return state_ == s_done; }
374     void reset();
375     
376     // Members for accessing footer data
377     zlib::ulong crc() const { return crc_; }
378     zlib::ulong uncompressed_size() const { return isize_; }
379 private:
380     enum state_type {
381         s_crc     = 1,
382         s_isize   = s_crc + 1,
383         s_done    = s_isize + 1
384     };
385     zlib::ulong  crc_;
386     zlib::ulong  isize_;
387     int          state_;
388     int          offset_; 
389 };
390
391 } // End namespace boost::iostreams::detail.
392
393 //------------------Definition of basic_gzip_decompressor---------------------//
394
395 //
396 // Template name: basic_gzip_decompressor
397 // Description: Model of InputFilter implementing compression in the
398 //      gzip format.
399 //
400 template<typename Alloc = std::allocator<char> >
401 class basic_gzip_decompressor : basic_zlib_decompressor<Alloc> {
402 private:
403     typedef basic_zlib_decompressor<Alloc>   base_type;
404     typedef typename base_type::string_type  string_type;
405 public:
406     typedef char char_type;
407     struct category
408         : dual_use,
409           filter_tag,
410           multichar_tag,
411           closable_tag
412         { };
413     basic_gzip_decompressor( int window_bits = gzip::default_window_bits,
414                              std::streamsize buffer_size = default_device_buffer_size );
415
416     template<typename Sink>
417     std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
418     {
419         std::streamsize result = 0;
420         while(result < n) {
421             if(state_ == s_start) {
422                 state_ = s_header;
423                 header_.reset();
424                 footer_.reset();
425             }
426             if (state_ == s_header) {
427                 int c = s[result++];
428                 header_.process(c);
429                 if (header_.done())
430                     state_ = s_body;
431             } else if (state_ == s_body) {
432                 try {
433                     std::streamsize amt = 
434                         base_type::write(snk, s + result, n - result);
435                     result += amt;
436                     if (!this->eof()) {
437                         break;
438                     } else {
439                         state_ = s_footer;
440                     }
441                 } catch (const zlib_error& e) {
442                     boost::throw_exception(gzip_error(e));
443                 }
444             } else { // state_ == s_footer
445                 if (footer_.done()) {
446                     if (footer_.crc() != this->crc())
447                         boost::throw_exception(gzip_error(gzip::bad_crc));
448
449                     base_type::close(snk, BOOST_IOS::out);
450                     state_ = s_start;
451                 } else {
452                     int c = s[result++];
453                     footer_.process(c);
454                 }
455             }
456         }
457         return result;
458     }
459
460     template<typename Source>
461     std::streamsize read(Source& src, char_type* s, std::streamsize n)
462     {
463         typedef char_traits<char>  traits_type;
464         std::streamsize            result = 0;
465         peekable_source<Source>    peek(src, putback_);
466         while (result < n && state_ != s_done) {
467             if (state_ == s_start) {
468                 state_ = s_header;
469                 header_.reset();
470                 footer_.reset();
471             }
472             if (state_ == s_header) {
473                 int c = boost::iostreams::get(peek);
474                 if (traits_type::is_eof(c)) {
475                     boost::throw_exception(gzip_error(gzip::bad_header));
476                 } else if (traits_type::would_block(c)) {
477                     break;
478                 }
479                 header_.process(c);
480                 if (header_.done())
481                     state_ = s_body;
482             } else if (state_ == s_body) {
483                 try {
484                     std::streamsize amt = 
485                         base_type::read(peek, s + result, n - result);
486                     if (amt != -1) {
487                         result += amt;
488                         if (amt < n - result)
489                             break;
490                     } else {
491                         peek.putback(this->unconsumed_input());
492                         state_ = s_footer;
493                     }
494                 } catch (const zlib_error& e) {
495                     boost::throw_exception(gzip_error(e));
496                 }
497             } else { // state_ == s_footer
498                 int c = boost::iostreams::get(peek);
499                 if (traits_type::is_eof(c)) {
500                     boost::throw_exception(gzip_error(gzip::bad_footer));
501                 } else if (traits_type::would_block(c)) {
502                     break;
503                 }
504                 footer_.process(c);
505                 if (footer_.done()) {
506                     if (footer_.crc() != this->crc())
507                         boost::throw_exception(gzip_error(gzip::bad_crc));
508                     c = boost::iostreams::get(peek);
509                     if (traits_type::is_eof(c)) {
510                         state_ = s_done;
511                     } else {
512                         peek.putback(c);
513                         base_type::close(peek, BOOST_IOS::in);
514                         state_ = s_start;
515                         header_.reset();
516                         footer_.reset();
517                     }
518                 }
519             }
520         }
521         if (peek.has_unconsumed_input()) {
522             putback_ = peek.unconsumed_input();
523         } else {
524             putback_.clear();
525         }
526         return result != 0 || state_ != s_done ?
527             result :
528             -1;
529     }
530
531     template<typename Source>
532     void close(Source& src, BOOST_IOS::openmode m)
533     {
534         try {
535             base_type::close(src, m);
536         } catch (const zlib_error& e) {
537             state_ = s_start;
538             boost::throw_exception(gzip_error(e));
539         }
540         if (m == BOOST_IOS::out) {
541             if (state_ == s_start || state_ == s_header)
542                 boost::throw_exception(gzip_error(gzip::bad_header));
543             else if (state_ == s_body)
544                 boost::throw_exception(gzip_error(gzip::bad_footer));
545             else if (state_ == s_footer) {
546                 if (!footer_.done())
547                     boost::throw_exception(gzip_error(gzip::bad_footer));
548                 else if(footer_.crc() != this->crc())
549                     boost::throw_exception(gzip_error(gzip::bad_crc));
550             } else {
551                 BOOST_ASSERT(!"Bad state");
552             }
553         }
554         state_ = s_start;
555     }
556
557     std::string file_name() const { return header_.file_name(); }
558     std::string comment() const { return header_.comment(); }
559     bool text() const { return header_.text(); }
560     int os() const { return header_.os(); }
561     std::time_t mtime() const { return header_.mtime(); }
562 private:
563     static gzip_params make_params(int window_bits);
564
565     // Source adapter allowing an arbitrary character sequence to be put back.
566     template<typename Source>
567     struct peekable_source {
568         typedef char char_type;
569         struct category : source_tag, peekable_tag { };
570         explicit peekable_source(Source& src, const string_type& putback = "") 
571             : src_(src), putback_(putback), offset_(0)
572             { }
573         std::streamsize read(char* s, std::streamsize n)
574         {
575             std::streamsize result = 0;
576
577             // Copy characters from putback buffer
578             std::streamsize pbsize = 
579                 static_cast<std::streamsize>(putback_.size());
580             if (offset_ < pbsize) {
581                 result = (std::min)(n, pbsize - offset_);
582                 BOOST_IOSTREAMS_CHAR_TRAITS(char)::copy(
583                     s, putback_.data() + offset_, result);
584                 offset_ += result;
585                 if (result == n)
586                     return result;
587             }
588
589             // Read characters from src_
590             std::streamsize amt = 
591                 boost::iostreams::read(src_, s + result, n - result);
592             return amt != -1 ? 
593                 result + amt : 
594                 result ? result : -1;
595         }
596         bool putback(char c)
597         {
598             if (offset_) {
599                 putback_[--offset_] = c;
600             } else {
601                 boost::throw_exception(
602                     boost::iostreams::detail::bad_putback());
603             }
604             return true;
605         }
606         void putback(const string_type& s)
607         {
608             putback_.replace(0, offset_, s);
609             offset_ = 0;
610         }
611
612         // Returns true if some characters have been putback but not re-read.
613         bool has_unconsumed_input() const 
614         {
615             return offset_ < static_cast<std::streamsize>(putback_.size());
616         }
617
618         // Returns the sequence of characters that have been put back but not re-read.
619         string_type unconsumed_input() const
620         {
621             return string_type(putback_, offset_, putback_.size() - offset_);
622         }
623         Source&          src_;
624         string_type      putback_;
625         std::streamsize  offset_;
626     };
627
628     enum state_type {
629         s_start   = 1,
630         s_header  = s_start + 1,
631         s_body    = s_header + 1,
632         s_footer  = s_body + 1,
633         s_done    = s_footer + 1
634     };
635     detail::gzip_header  header_;
636     detail::gzip_footer  footer_;
637     string_type          putback_;
638     int                  state_;
639 };
640 BOOST_IOSTREAMS_PIPABLE(basic_gzip_decompressor, 1)
641
642 typedef basic_gzip_decompressor<> gzip_decompressor;
643
644 //------------------Implementation of gzip_compressor-------------------------//
645
646 template<typename Alloc>
647 basic_gzip_compressor<Alloc>::basic_gzip_compressor
648     (const gzip_params& p, std::streamsize buffer_size)
649     : base_type(normalize_params(p), buffer_size),
650       offset_(0), flags_(0)
651 {
652     // Calculate gzip header.
653     bool has_name = !p.file_name.empty();
654     bool has_comment = !p.comment.empty();
655
656     std::string::size_type length =
657         10 +
658         (has_name ? p.file_name.size() + 1 : 0) +
659         (has_comment ? p.comment.size() + 1 : 0);
660         // + 2; // Header crc confuses gunzip.
661     int flags =
662         //gzip::flags::header_crc +
663         (has_name ? gzip::flags::name : 0) +
664         (has_comment ? gzip::flags::comment : 0);
665     int extra_flags =
666         ( p.level == zlib::best_compression ?
667               gzip::extra_flags::best_compression :
668               0 ) +
669         ( p.level == zlib::best_speed ?
670               gzip::extra_flags::best_speed :
671               0 );
672     header_.reserve(length);
673     header_ += gzip::magic::id1;                         // ID1.
674     header_ += gzip::magic::id2;                         // ID2.
675     header_ += gzip::method::deflate;                    // CM.
676     header_ += static_cast<char>(flags);                 // FLG.
677     header_ += static_cast<char>(0xFF & p.mtime);        // MTIME.
678     header_ += static_cast<char>(0xFF & (p.mtime >> 8));
679     header_ += static_cast<char>(0xFF & (p.mtime >> 16));
680     header_ += static_cast<char>(0xFF & (p.mtime >> 24));
681     header_ += static_cast<char>(extra_flags);           // XFL.
682     header_ += static_cast<char>(gzip::os_unknown);      // OS.
683     if (has_name) {
684         header_ += p.file_name;
685         header_ += '\0';
686     }
687     if (has_comment) {
688         header_ += p.comment;
689         header_ += '\0';
690     }
691 }
692
693 template<typename Alloc>
694 gzip_params basic_gzip_compressor<Alloc>::normalize_params(gzip_params p)
695 {
696     p.noheader = true;
697     p.calculate_crc = true;
698     return p;
699 }
700
701 template<typename Alloc>
702 void basic_gzip_compressor<Alloc>::prepare_footer()
703 {
704     boost::iostreams::back_insert_device<std::string> out(footer_);
705     write_long(this->crc(), out);
706     write_long(this->total_in(), out);
707     flags_ |= f_body_done;
708     offset_ = 0;
709 }
710
711 template<typename Alloc>
712 std::streamsize basic_gzip_compressor<Alloc>::read_string
713     (char* s, std::streamsize n, std::string& str)
714 {
715     std::streamsize avail =
716         static_cast<std::streamsize>(str.size() - offset_);
717     std::streamsize amt = (std::min)(avail, n);
718     std::copy( str.data() + offset_,
719                str.data() + offset_ + amt,
720                s );
721     offset_ += amt;
722     if ( !(flags_ & f_header_done) &&
723          offset_ == static_cast<std::size_t>(str.size()) )
724     {
725         flags_ |= f_header_done;
726     }
727     return amt;
728 }
729
730 //------------------Implementation of gzip_decompressor-----------------------//
731
732 template<typename Alloc>
733 basic_gzip_decompressor<Alloc>::basic_gzip_decompressor
734     (int window_bits, std::streamsize buffer_size)
735     : base_type(make_params(window_bits), buffer_size),
736       state_(s_start)
737     { }
738
739 template<typename Alloc>
740 gzip_params basic_gzip_decompressor<Alloc>::make_params(int window_bits)
741 {
742     gzip_params p;
743     p.window_bits = window_bits;
744     p.noheader = true;
745     p.calculate_crc = true;
746     return p;
747 }
748
749 //----------------------------------------------------------------------------//
750
751 } } // End namespaces iostreams, boost.
752
753 #if defined(BOOST_MSVC)
754 # pragma warning(pop)
755 #endif
756
757 #endif // #ifndef BOOST_IOSTREAMS_GZIP_HPP_INCLUDED