Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r63031 - in trunk: boost/iostreams/filter libs/iostreams/doc/classes
From: steven_at_[hidden]
Date: 2010-06-16 21:37:03


Author: steven_watanabe
Date: 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
New Revision: 63031
URL: http://svn.boost.org/trac/boost/changeset/63031

Log:
Make gzip_decompressor a DualUseFilter. Fixes #1579.
Text files modified:
   trunk/boost/iostreams/filter/gzip.hpp | 99 +++++++++++++++++++++++++++++++++------
   trunk/boost/iostreams/filter/symmetric.hpp | 5 +
   trunk/boost/iostreams/filter/test.hpp | 29 +++++++++++
   trunk/boost/iostreams/filter/zlib.hpp | 12 ++++
   trunk/libs/iostreams/doc/classes/gzip.html | 2
   5 files changed, 125 insertions(+), 22 deletions(-)

Modified: trunk/boost/iostreams/filter/gzip.hpp
==============================================================================
--- trunk/boost/iostreams/filter/gzip.hpp (original)
+++ trunk/boost/iostreams/filter/gzip.hpp 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
@@ -247,27 +247,23 @@
     template<typename Sink>
     void close(Sink& snk, BOOST_IOS::openmode m)
     {
- if (m == BOOST_IOS::out) {
- try {
-
- // Close zlib compressor.
- base_type::close(snk, BOOST_IOS::out);
+ try {
+ // Close zlib compressor.
+ base_type::close(snk, m);
 
+ if (m == BOOST_IOS::out) {
                 if (flags_ & f_header_done) {
 
                     // Write final fields of gzip file format.
                     write_long(this->crc(), snk);
                     write_long(this->total_in(), snk);
                 }
-
- } catch (...) {
- close_impl();
- throw;
             }
+ } catch(...) {
             close_impl();
- } else {
- close_impl();
+ throw;
         }
+ close_impl();
     }
 private:
     static gzip_params normalize_params(gzip_params p);
@@ -275,13 +271,24 @@
     std::streamsize read_string(char* s, std::streamsize n, std::string& str);
 
     template<typename Sink>
- static void write_long(long n, Sink& next)
+ static void write_long(long n, Sink& next, boost::mpl::true_)
     {
         boost::iostreams::put(next, static_cast<char>(0xFF & n));
         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 8)));
         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 16)));
         boost::iostreams::put(next, static_cast<char>(0xFF & (n >> 24)));
     }
+ template<typename Sink>
+ static void write_long(long n, Sink& next, boost::mpl::false_)
+ {
+ }
+ template<typename Sink>
+ static void write_long(long n, Sink& next)
+ {
+ typedef typename category_of<Sink>::type category;
+ typedef is_convertible<category, output> can_write;
+ write_long(n, next, can_write());
+ }
 
     void close_impl()
     {
@@ -398,12 +405,58 @@
 public:
     typedef char char_type;
     struct category
- : multichar_input_filter_tag,
+ : dual_use,
+ filter_tag,
+ multichar_tag,
           closable_tag
         { };
     basic_gzip_decompressor( int window_bits = gzip::default_window_bits,
                              int buffer_size = default_device_buffer_size );
 
+ template<typename Sink>
+ std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
+ {
+ std::streamsize result = 0;
+ while(result < n) {
+ if(state_ == s_start) {
+ state_ = s_header;
+ header_.reset();
+ footer_.reset();
+ }
+ if (state_ == s_header) {
+ int c = s[result++];
+ header_.process(c);
+ if (header_.done())
+ state_ = s_body;
+ } else if (state_ == s_body) {
+ try {
+ std::streamsize amt =
+ base_type::write(snk, s + result, n - result);
+ result += amt;
+ if (!this->eof()) {
+ break;
+ } else {
+ state_ = s_footer;
+ }
+ } catch (const zlib_error& e) {
+ boost::throw_exception(gzip_error(e));
+ }
+ } else { // state_ == s_footer
+ if (footer_.done()) {
+ if (footer_.crc() != this->crc())
+ boost::throw_exception(gzip_error(gzip::bad_crc));
+
+ base_type::close(snk, BOOST_IOS::out);
+ state_ = s_start;
+ } else {
+ int c = s[result++];
+ footer_.process(c);
+ }
+ }
+ }
+ return result;
+ }
+
     template<typename Source>
     std::streamsize read(Source& src, char_type* s, std::streamsize n)
     {
@@ -476,16 +529,28 @@
     }
 
     template<typename Source>
- void close(Source& src)
+ void close(Source& src, BOOST_IOS::openmode m)
     {
         try {
- base_type::close(src, BOOST_IOS::in);
+ base_type::close(src, m);
         } catch (const zlib_error& e) {
             state_ = s_start;
- header_.reset();
- footer_.reset();
             boost::throw_exception(gzip_error(e));
         }
+ if (m == BOOST_IOS::out) {
+ if (state_ == s_start || state_ == s_header)
+ boost::throw_exception(gzip_error(gzip::bad_header));
+ else if (state_ == s_body)
+ boost::throw_exception(gzip_error(gzip::bad_footer));
+ else if (state_ == s_footer) {
+ if (!footer_.done())
+ boost::throw_exception(gzip_error(gzip::bad_footer));
+ else if(footer_.crc() != this->crc())
+ boost::throw_exception(gzip_error(gzip::bad_crc));
+ } else {
+ assert(!"Bad state");
+ }
+ }
         state_ = s_start;
     }
 

Modified: trunk/boost/iostreams/filter/symmetric.hpp
==============================================================================
--- trunk/boost/iostreams/filter/symmetric.hpp (original)
+++ trunk/boost/iostreams/filter/symmetric.hpp 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
@@ -147,7 +147,10 @@
         for (next_s = s, end_s = s + n; next_s != end_s; ) {
             if (buf.ptr() == buf.eptr() && !flush(snk))
                 break;
- filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false);
+ if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) {
+ flush(snk);
+ break;
+ }
         }
         return static_cast<std::streamsize>(next_s - s);
     }

Modified: trunk/boost/iostreams/filter/test.hpp
==============================================================================
--- trunk/boost/iostreams/filter/test.hpp (original)
+++ trunk/boost/iostreams/filter/test.hpp 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
@@ -250,7 +250,7 @@
             );
             if (dest != data)
                 return false;
- }
+ }
         {
             array_source src(data.data(), data.data() + data.size());
             std::string temp;
@@ -266,6 +266,33 @@
                 );
             } catch(std::ios_base::failure&) {}
         }
+ {
+ array_source src(data.data(), data.data() + data.size());
+ std::string temp;
+ std::string dest;
+ iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
+ iostreams::copy(
+ non_blocking_source(temp, inc),
+ compose(in, iostreams::back_inserter(dest))
+ );
+ if (dest != data)
+ return false;
+ }
+ {
+ array_source src(data.data(), data.data() + data.size());
+ std::string temp;
+ std::string dest;
+ iostreams::copy(compose(out, src), non_blocking_sink(temp, inc));
+ // truncate the file, this should not loop, it may throw
+ // std::ios_base::failure, which we swallow.
+ try {
+ temp.resize(temp.size() / 2);
+ iostreams::copy(
+ non_blocking_source(temp, inc),
+ compose(in, iostreams::back_inserter(dest))
+ );
+ } catch(std::ios_base::failure&) {}
+ }
     }
     return true;
 }

Modified: trunk/boost/iostreams/filter/zlib.hpp
==============================================================================
--- trunk/boost/iostreams/filter/zlib.hpp (original)
+++ trunk/boost/iostreams/filter/zlib.hpp 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
@@ -244,6 +244,9 @@
     bool filter( const char*& begin_in, const char* end_in,
                  char*& begin_out, char* end_out, bool flush );
     void close();
+ bool eof() const { return eof_; }
+private:
+ bool eof_;
 };
 
 } // End namespace detail.
@@ -293,6 +296,7 @@
                              int buffer_size = default_device_buffer_size );
     zlib::ulong crc() { return this->filter().crc(); }
     int total_out() { return this->filter().total_out(); }
+ bool eof() { return this->filter().eof(); }
 };
 BOOST_IOSTREAMS_PIPABLE(basic_zlib_decompressor, 1)
 
@@ -357,6 +361,7 @@
 
 template<typename Alloc>
 zlib_decompressor_impl<Alloc>::zlib_decompressor_impl(const zlib_params& p)
+ : eof_(false)
 { init(p, false, static_cast<zlib_allocator<Alloc>&>(*this)); }
 
 template<typename Alloc>
@@ -380,11 +385,14 @@
     int result = xinflate(zlib::sync_flush);
     after(src_begin, dest_begin, false);
     zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
- return result != zlib::stream_end;
+ return !(eof_ = result == zlib::stream_end);
 }
 
 template<typename Alloc>
-void zlib_decompressor_impl<Alloc>::close() { reset(false, true); }
+void zlib_decompressor_impl<Alloc>::close() {
+ eof_ = false;
+ reset(false, true);
+}
 
 } // End namespace detail.
 

Modified: trunk/libs/iostreams/doc/classes/gzip.html
==============================================================================
--- trunk/libs/iostreams/doc/classes/gzip.html (original)
+++ trunk/libs/iostreams/doc/classes/gzip.html 2010-06-16 21:37:02 EDT (Wed, 16 Jun 2010)
@@ -248,7 +248,7 @@
 
 <H4>Description</H4>
 
-<P>Model of InputFilter which decompresses data in the G<SPAN STYLE="font-size:80%">ZIP</SPAN> format (<A CLASS="bib_ref" HREF="../bibliography.html#deutsch3">[Deutsch3]</A>).</P>
+<P>Model of DualUseFilter which decompresses data in the G<SPAN STYLE="font-size:80%">ZIP</SPAN> format (<A CLASS="bib_ref" HREF="../bibliography.html#deutsch3">[Deutsch3]</A>).</P>
 
 <H4>Synopsis</H4>
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk