File indexing completed on 2025-01-30 09:44:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_IOSTREAMS_GZIP_HPP_INCLUDED
0013 #define BOOST_IOSTREAMS_GZIP_HPP_INCLUDED
0014
0015 #if defined(_MSC_VER)
0016 # pragma once
0017 #endif
0018
0019 #include <boost/config.hpp> // STATIC_CONSTANT, STDC_NAMESPACE,
0020
0021 #include <algorithm> // min.
0022 #include <boost/assert.hpp>
0023 #include <cstdio> // EOF.
0024 #include <cstddef> // size_t.
0025 #include <ctime> // std::time_t.
0026 #include <memory> // allocator.
0027 #include <boost/config.hpp> // Put size_t in std.
0028 #include <boost/detail/workaround.hpp>
0029 #include <boost/cstdint.hpp> // uint8_t, uint32_t.
0030 #include <boost/iostreams/checked_operations.hpp>
0031 #include <boost/iostreams/constants.hpp> // buffer size.
0032 #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
0033 #include <boost/iostreams/detail/adapter/range_adapter.hpp>
0034 #include <boost/iostreams/detail/char_traits.hpp>
0035 #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
0036 #include <boost/iostreams/detail/error.hpp>
0037 #include <boost/iostreams/operations.hpp>
0038 #include <boost/iostreams/device/back_inserter.hpp>
0039 #include <boost/iostreams/filter/zlib.hpp>
0040 #include <boost/iostreams/pipeline.hpp>
0041 #include <boost/iostreams/putback.hpp>
0042 #include <boost/throw_exception.hpp>
0043
0044
0045 #if defined(BOOST_MSVC)
0046 # pragma warning(push)
0047 # pragma warning(disable:4244)
0048 # pragma warning(disable:4251)
0049 # pragma warning(disable:4309)
0050 #endif
0051
0052 #ifdef BOOST_NO_STDC_NAMESPACE
0053 namespace std { using ::time_t; }
0054 #endif
0055
0056 namespace boost { namespace iostreams {
0057
0058
0059
0060 namespace gzip {
0061
0062 using namespace boost::iostreams::zlib;
0063
0064
0065
0066 const int zlib_error = 1;
0067 const int bad_crc = 2;
0068 const int bad_length = 3;
0069 const int bad_header = 4;
0070 const int bad_footer = 5;
0071 const int bad_method = 6;
0072
0073 namespace magic {
0074
0075
0076
0077 const int id1 = 0x1f;
0078 const int id2 = 0x8b;
0079
0080 }
0081
0082 namespace method {
0083
0084
0085
0086 const int deflate = 8;
0087
0088 }
0089
0090 namespace flags {
0091
0092
0093
0094 const int text = 1;
0095 const int header_crc = 2;
0096 const int extra = 4;
0097 const int name = 8;
0098 const int comment = 16;
0099
0100 }
0101
0102 namespace extra_flags {
0103
0104
0105
0106 const int best_compression = 2;
0107 const int best_speed = 4;
0108
0109 }
0110
0111
0112
0113 const int os_fat = 0;
0114 const int os_amiga = 1;
0115 const int os_vms = 2;
0116 const int os_unix = 3;
0117 const int os_vm_cms = 4;
0118 const int os_atari = 5;
0119 const int os_hpfs = 6;
0120 const int os_macintosh = 7;
0121 const int os_z_system = 8;
0122 const int os_cp_m = 9;
0123 const int os_tops_20 = 10;
0124 const int os_ntfs = 11;
0125 const int os_qdos = 12;
0126 const int os_acorn = 13;
0127 const int os_unknown = 255;
0128
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138 struct gzip_params : zlib_params {
0139
0140
0141 gzip_params( int level_ = gzip::default_compression,
0142 int method_ = gzip::deflated,
0143 int window_bits_ = gzip::default_window_bits,
0144 int mem_level_ = gzip::default_mem_level,
0145 int strategy_ = gzip::default_strategy,
0146 std::string file_name_ = "",
0147 std::string comment_ = "",
0148 std::time_t mtime_ = 0 )
0149 : zlib_params(level_, method_, window_bits_, mem_level_, strategy_),
0150 file_name(file_name_), comment(comment_), mtime(mtime_)
0151 { }
0152 std::string file_name;
0153 std::string comment;
0154 std::time_t mtime;
0155 };
0156
0157
0158
0159
0160
0161
0162
0163
0164 class gzip_error : public BOOST_IOSTREAMS_FAILURE {
0165 public:
0166 explicit gzip_error(int error)
0167 : BOOST_IOSTREAMS_FAILURE("gzip error"),
0168 error_(error), zlib_error_code_(zlib::okay) { }
0169 explicit gzip_error(const zlib_error& e)
0170 : BOOST_IOSTREAMS_FAILURE("gzip error"),
0171 error_(gzip::zlib_error), zlib_error_code_(e.error())
0172 { }
0173 int error() const { return error_; }
0174 int zlib_error_code() const { return zlib_error_code_; }
0175 private:
0176 int error_;
0177 int zlib_error_code_;
0178 };
0179
0180
0181
0182
0183
0184
0185
0186
0187 template<typename Alloc = std::allocator<char> >
0188 class basic_gzip_compressor : basic_zlib_compressor<Alloc> {
0189 private:
0190 typedef basic_zlib_compressor<Alloc> base_type;
0191 public:
0192 typedef char char_type;
0193 struct category
0194 : dual_use,
0195 filter_tag,
0196 multichar_tag,
0197 closable_tag
0198 { };
0199 basic_gzip_compressor( const gzip_params& = gzip::default_compression,
0200 std::streamsize buffer_size = default_device_buffer_size );
0201
0202 template<typename Source>
0203 std::streamsize read(Source& src, char_type* s, std::streamsize n)
0204 {
0205 std::streamsize result = 0;
0206
0207
0208 if (!(flags_ & f_header_done))
0209 result += read_string(s, n, header_);
0210
0211
0212 if (!(flags_ & f_body_done)) {
0213
0214
0215 std::streamsize amt = base_type::read(src, s + result, n - result);
0216 if (amt != -1) {
0217 result += amt;
0218 if (amt < n - result) {
0219 amt = base_type::read(src, s + result, n - result);
0220 if (amt != -1)
0221 result += amt;
0222 }
0223 }
0224 if (amt == -1)
0225 prepare_footer();
0226 }
0227
0228
0229 if ((flags_ & f_body_done) != 0 && result < n)
0230 result += read_string(s + result, n - result, footer_);
0231
0232 return result != 0 ? result : -1;
0233 }
0234
0235 template<typename Sink>
0236 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
0237 {
0238 if (!(flags_ & f_header_done)) {
0239 std::streamsize amt =
0240 static_cast<std::streamsize>(header_.size() - offset_);
0241 offset_ += boost::iostreams::write_if(snk, header_.data() + offset_, amt);
0242 if (offset_ == header_.size())
0243 flags_ |= f_header_done;
0244 else
0245 return 0;
0246 }
0247 return base_type::write(snk, s, n);
0248 }
0249
0250 template<typename Sink>
0251 void close(Sink& snk, BOOST_IOS::openmode m)
0252 {
0253 try {
0254 if (m == BOOST_IOS::out && !(flags_ & f_header_done))
0255 this->write(snk, 0, 0);
0256
0257
0258 base_type::close(snk, m);
0259
0260 if (m == BOOST_IOS::out) {
0261 if (flags_ & f_header_done) {
0262
0263
0264 write_long(this->crc(), snk);
0265 write_long(this->total_in(), snk);
0266 }
0267 }
0268 } catch(...) {
0269 close_impl();
0270 throw;
0271 }
0272 close_impl();
0273 }
0274 private:
0275 static gzip_params normalize_params(gzip_params p);
0276 void prepare_footer();
0277 std::streamsize read_string(char* s, std::streamsize n, std::string& str);
0278
0279 template<typename Sink>
0280 static void write_long(long n, Sink& next, boost::mpl::true_)
0281 {
0282 boost::iostreams::put(next, static_cast<char>(0xFF & n));
0283 boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 8)));
0284 boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 16)));
0285 boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 24)));
0286 }
0287 template<typename Sink>
0288 static void write_long(long, Sink&, boost::mpl::false_)
0289 {
0290 }
0291 template<typename Sink>
0292 static void write_long(long n, Sink& next)
0293 {
0294 typedef typename category_of<Sink>::type category;
0295 typedef is_convertible<category, output> can_write;
0296 write_long(n, next, can_write());
0297 }
0298
0299 void close_impl()
0300 {
0301 footer_.clear();
0302 offset_ = 0;
0303 flags_ = 0;
0304 }
0305
0306 enum state_type {
0307 f_header_done = 1,
0308 f_body_done = f_header_done << 1,
0309 f_footer_done = f_body_done << 1
0310 };
0311 std::string header_;
0312 std::string footer_;
0313 std::size_t offset_;
0314 int flags_;
0315 };
0316 BOOST_IOSTREAMS_PIPABLE(basic_gzip_compressor, 1)
0317
0318 typedef basic_gzip_compressor<> gzip_compressor;
0319
0320
0321
0322 namespace detail {
0323
0324
0325 class BOOST_IOSTREAMS_DECL gzip_header {
0326 public:
0327 gzip_header() { reset(); }
0328
0329
0330 void process(char c);
0331 bool done() const { return state_ == s_done; }
0332 void reset();
0333
0334
0335 std::string file_name() const { return file_name_; }
0336 std::string comment() const { return comment_; }
0337 bool text() const { return (flags_ & gzip::flags::text) != 0; }
0338 int os() const { return os_; }
0339 std::time_t mtime() const { return mtime_; }
0340 private:
0341 enum state_type {
0342 s_id1 = 1,
0343 s_id2 = s_id1 + 1,
0344 s_cm = s_id2 + 1,
0345 s_flg = s_cm + 1,
0346 s_mtime = s_flg + 1,
0347 s_xfl = s_mtime + 1,
0348 s_os = s_xfl + 1,
0349 s_xlen = s_os + 1,
0350 s_extra = s_xlen + 1,
0351 s_name = s_extra + 1,
0352 s_comment = s_name + 1,
0353 s_hcrc = s_comment + 1,
0354 s_done = s_hcrc + 1
0355 };
0356 std::string file_name_;
0357 std::string comment_;
0358 int os_;
0359 std::time_t mtime_;
0360 int flags_;
0361 int state_;
0362 int offset_;
0363 int xlen_;
0364 };
0365
0366
0367 class BOOST_IOSTREAMS_DECL gzip_footer {
0368 public:
0369 gzip_footer() { reset(); }
0370
0371
0372 void process(char c);
0373 bool done() const { return state_ == s_done; }
0374 void reset();
0375
0376
0377 zlib::ulong crc() const { return crc_; }
0378 zlib::ulong uncompressed_size() const { return isize_; }
0379 private:
0380 enum state_type {
0381 s_crc = 1,
0382 s_isize = s_crc + 1,
0383 s_done = s_isize + 1
0384 };
0385 zlib::ulong crc_;
0386 zlib::ulong isize_;
0387 int state_;
0388 int offset_;
0389 };
0390
0391 }
0392
0393
0394
0395
0396
0397
0398
0399
0400 template<typename Alloc = std::allocator<char> >
0401 class basic_gzip_decompressor : basic_zlib_decompressor<Alloc> {
0402 private:
0403 typedef basic_zlib_decompressor<Alloc> base_type;
0404 typedef typename base_type::string_type string_type;
0405 public:
0406 typedef char char_type;
0407 struct category
0408 : dual_use,
0409 filter_tag,
0410 multichar_tag,
0411 closable_tag
0412 { };
0413 basic_gzip_decompressor( int window_bits = gzip::default_window_bits,
0414 std::streamsize buffer_size = default_device_buffer_size );
0415
0416 template<typename Sink>
0417 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
0418 {
0419 std::streamsize result = 0;
0420 while(result < n) {
0421 if(state_ == s_start) {
0422 state_ = s_header;
0423 header_.reset();
0424 footer_.reset();
0425 }
0426 if (state_ == s_header) {
0427 int c = s[result++];
0428 header_.process(c);
0429 if (header_.done())
0430 state_ = s_body;
0431 } else if (state_ == s_body) {
0432 try {
0433 std::streamsize amt =
0434 base_type::write(snk, s + result, n - result);
0435 result += amt;
0436 if (!this->eof()) {
0437 break;
0438 } else {
0439 state_ = s_footer;
0440 }
0441 } catch (const zlib_error& e) {
0442 boost::throw_exception(gzip_error(e));
0443 }
0444 } else {
0445 if (footer_.done()) {
0446 if (footer_.crc() != this->crc())
0447 boost::throw_exception(gzip_error(gzip::bad_crc));
0448
0449 base_type::close(snk, BOOST_IOS::out);
0450 state_ = s_start;
0451 } else {
0452 int c = s[result++];
0453 footer_.process(c);
0454 }
0455 }
0456 }
0457 return result;
0458 }
0459
0460 template<typename Source>
0461 std::streamsize read(Source& src, char_type* s, std::streamsize n)
0462 {
0463 typedef char_traits<char> traits_type;
0464 std::streamsize result = 0;
0465 peekable_source<Source> peek(src, putback_);
0466 while (result < n && state_ != s_done) {
0467 if (state_ == s_start) {
0468 state_ = s_header;
0469 header_.reset();
0470 footer_.reset();
0471 }
0472 if (state_ == s_header) {
0473 int c = boost::iostreams::get(peek);
0474 if (traits_type::is_eof(c)) {
0475 boost::throw_exception(gzip_error(gzip::bad_header));
0476 } else if (traits_type::would_block(c)) {
0477 break;
0478 }
0479 header_.process(c);
0480 if (header_.done())
0481 state_ = s_body;
0482 } else if (state_ == s_body) {
0483 try {
0484 std::streamsize amt =
0485 base_type::read(peek, s + result, n - result);
0486 if (amt != -1) {
0487 result += amt;
0488 if (amt < n - result)
0489 break;
0490 } else {
0491 peek.putback(this->unconsumed_input());
0492 state_ = s_footer;
0493 }
0494 } catch (const zlib_error& e) {
0495 boost::throw_exception(gzip_error(e));
0496 }
0497 } else {
0498 int c = boost::iostreams::get(peek);
0499 if (traits_type::is_eof(c)) {
0500 boost::throw_exception(gzip_error(gzip::bad_footer));
0501 } else if (traits_type::would_block(c)) {
0502 break;
0503 }
0504 footer_.process(c);
0505 if (footer_.done()) {
0506 if (footer_.crc() != this->crc())
0507 boost::throw_exception(gzip_error(gzip::bad_crc));
0508 c = boost::iostreams::get(peek);
0509 if (traits_type::is_eof(c)) {
0510 state_ = s_done;
0511 } else {
0512 peek.putback(c);
0513 base_type::close(peek, BOOST_IOS::in);
0514 state_ = s_start;
0515 header_.reset();
0516 footer_.reset();
0517 }
0518 }
0519 }
0520 }
0521 if (peek.has_unconsumed_input()) {
0522 putback_ = peek.unconsumed_input();
0523 } else {
0524 putback_.clear();
0525 }
0526 return result != 0 || state_ != s_done ?
0527 result :
0528 -1;
0529 }
0530
0531 template<typename Source>
0532 void close(Source& src, BOOST_IOS::openmode m)
0533 {
0534 try {
0535 base_type::close(src, m);
0536 } catch (const zlib_error& e) {
0537 state_ = s_start;
0538 boost::throw_exception(gzip_error(e));
0539 }
0540 if (m == BOOST_IOS::out) {
0541 if (state_ == s_start || state_ == s_header)
0542 boost::throw_exception(gzip_error(gzip::bad_header));
0543 else if (state_ == s_body)
0544 boost::throw_exception(gzip_error(gzip::bad_footer));
0545 else if (state_ == s_footer) {
0546 if (!footer_.done())
0547 boost::throw_exception(gzip_error(gzip::bad_footer));
0548 else if(footer_.crc() != this->crc())
0549 boost::throw_exception(gzip_error(gzip::bad_crc));
0550 } else {
0551 BOOST_ASSERT(!"Bad state");
0552 }
0553 }
0554 state_ = s_start;
0555 }
0556
0557 std::string file_name() const { return header_.file_name(); }
0558 std::string comment() const { return header_.comment(); }
0559 bool text() const { return header_.text(); }
0560 int os() const { return header_.os(); }
0561 std::time_t mtime() const { return header_.mtime(); }
0562 private:
0563 static gzip_params make_params(int window_bits);
0564
0565
0566 template<typename Source>
0567 struct peekable_source {
0568 typedef char char_type;
0569 struct category : source_tag, peekable_tag { };
0570 explicit peekable_source(Source& src, const string_type& putback = "")
0571 : src_(src), putback_(putback), offset_(0)
0572 { }
0573 std::streamsize read(char* s, std::streamsize n)
0574 {
0575 std::streamsize result = 0;
0576
0577
0578 std::streamsize pbsize =
0579 static_cast<std::streamsize>(putback_.size());
0580 if (offset_ < pbsize) {
0581 result = (std::min)(n, pbsize - offset_);
0582 BOOST_IOSTREAMS_CHAR_TRAITS(char)::copy(
0583 s, putback_.data() + offset_, result);
0584 offset_ += result;
0585 if (result == n)
0586 return result;
0587 }
0588
0589
0590 std::streamsize amt =
0591 boost::iostreams::read(src_, s + result, n - result);
0592 return amt != -1 ?
0593 result + amt :
0594 result ? result : -1;
0595 }
0596 bool putback(char c)
0597 {
0598 if (offset_) {
0599 putback_[--offset_] = c;
0600 } else {
0601 boost::throw_exception(
0602 boost::iostreams::detail::bad_putback());
0603 }
0604 return true;
0605 }
0606 void putback(const string_type& s)
0607 {
0608 putback_.replace(0, offset_, s);
0609 offset_ = 0;
0610 }
0611
0612
0613 bool has_unconsumed_input() const
0614 {
0615 return offset_ < static_cast<std::streamsize>(putback_.size());
0616 }
0617
0618
0619 string_type unconsumed_input() const
0620 {
0621 return string_type(putback_, offset_, putback_.size() - offset_);
0622 }
0623 Source& src_;
0624 string_type putback_;
0625 std::streamsize offset_;
0626 };
0627
0628 enum state_type {
0629 s_start = 1,
0630 s_header = s_start + 1,
0631 s_body = s_header + 1,
0632 s_footer = s_body + 1,
0633 s_done = s_footer + 1
0634 };
0635 detail::gzip_header header_;
0636 detail::gzip_footer footer_;
0637 string_type putback_;
0638 int state_;
0639 };
0640 BOOST_IOSTREAMS_PIPABLE(basic_gzip_decompressor, 1)
0641
0642 typedef basic_gzip_decompressor<> gzip_decompressor;
0643
0644
0645
0646 template<typename Alloc>
0647 basic_gzip_compressor<Alloc>::basic_gzip_compressor
0648 (const gzip_params& p, std::streamsize buffer_size)
0649 : base_type(normalize_params(p), buffer_size),
0650 offset_(0), flags_(0)
0651 {
0652
0653 bool has_name = !p.file_name.empty();
0654 bool has_comment = !p.comment.empty();
0655
0656 std::string::size_type length =
0657 10 +
0658 (has_name ? p.file_name.size() + 1 : 0) +
0659 (has_comment ? p.comment.size() + 1 : 0);
0660
0661 int flags =
0662
0663 (has_name ? gzip::flags::name : 0) +
0664 (has_comment ? gzip::flags::comment : 0);
0665 int extra_flags =
0666 ( p.level == zlib::best_compression ?
0667 gzip::extra_flags::best_compression :
0668 0 ) +
0669 ( p.level == zlib::best_speed ?
0670 gzip::extra_flags::best_speed :
0671 0 );
0672 header_.reserve(length);
0673 header_ += gzip::magic::id1;
0674 header_ += static_cast<char>(gzip::magic::id2);
0675 header_ += gzip::method::deflate;
0676 header_ += static_cast<char>(flags);
0677 header_ += static_cast<char>(0xFF & p.mtime);
0678 header_ += static_cast<char>(0xFF & (p.mtime >> 8));
0679 header_ += static_cast<char>(0xFF & (p.mtime >> 16));
0680 header_ += static_cast<char>(0xFF & (p.mtime >> 24));
0681 header_ += static_cast<char>(extra_flags);
0682 header_ += static_cast<char>(gzip::os_unknown);
0683 if (has_name) {
0684 header_ += p.file_name;
0685 header_ += '\0';
0686 }
0687 if (has_comment) {
0688 header_ += p.comment;
0689 header_ += '\0';
0690 }
0691 }
0692
0693 template<typename Alloc>
0694 gzip_params basic_gzip_compressor<Alloc>::normalize_params(gzip_params p)
0695 {
0696 p.noheader = true;
0697 p.calculate_crc = true;
0698 return p;
0699 }
0700
0701 template<typename Alloc>
0702 void basic_gzip_compressor<Alloc>::prepare_footer()
0703 {
0704 boost::iostreams::back_insert_device<std::string> out(footer_);
0705 write_long(this->crc(), out);
0706 write_long(this->total_in(), out);
0707 flags_ |= f_body_done;
0708 offset_ = 0;
0709 }
0710
0711 template<typename Alloc>
0712 std::streamsize basic_gzip_compressor<Alloc>::read_string
0713 (char* s, std::streamsize n, std::string& str)
0714 {
0715 std::streamsize avail =
0716 static_cast<std::streamsize>(str.size() - offset_);
0717 std::streamsize amt = (std::min)(avail, n);
0718 std::copy( str.data() + offset_,
0719 str.data() + offset_ + amt,
0720 s );
0721 offset_ += amt;
0722 if ( !(flags_ & f_header_done) &&
0723 offset_ == static_cast<std::size_t>(str.size()) )
0724 {
0725 flags_ |= f_header_done;
0726 }
0727 return amt;
0728 }
0729
0730
0731
0732 template<typename Alloc>
0733 basic_gzip_decompressor<Alloc>::basic_gzip_decompressor
0734 (int window_bits, std::streamsize buffer_size)
0735 : base_type(make_params(window_bits), buffer_size),
0736 state_(s_start)
0737 { }
0738
0739 template<typename Alloc>
0740 gzip_params basic_gzip_decompressor<Alloc>::make_params(int window_bits)
0741 {
0742 gzip_params p;
0743 p.window_bits = window_bits;
0744 p.noheader = true;
0745 p.calculate_crc = true;
0746 return p;
0747 }
0748
0749
0750
0751 } }
0752
0753 #if defined(BOOST_MSVC)
0754 # pragma warning(pop)
0755 #endif
0756
0757 #endif