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 #ifndef BOOST_IOSTREAMS_AGGREGATE_FILTER_HPP_INCLUDED 9 #define BOOST_IOSTREAMS_AGGREGATE_FILTER_HPP_INCLUDED 10 11 #if defined(_MSC_VER) 12 # pragma once 13 #endif 14 15 #include <algorithm> // copy, min. 16 #include <boost/assert.hpp> 17 #include <iterator> // back_inserter 18 #include <vector> 19 #include <boost/iostreams/constants.hpp> // default_device_buffer_size 20 #include <boost/iostreams/categories.hpp> 21 #include <boost/iostreams/detail/char_traits.hpp> 22 #include <boost/iostreams/detail/ios.hpp> // openmode, streamsize. 23 #include <boost/iostreams/pipeline.hpp> 24 #include <boost/iostreams/read.hpp> // check_eof 25 #include <boost/iostreams/write.hpp> 26 #include <boost/mpl/bool.hpp> 27 #include <boost/type_traits/is_convertible.hpp> 28 29 // Must come last. 30 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC. 31 32 namespace boost { namespace iostreams { 33 34 // 35 // Template name: aggregate_filter. 36 // Template parameters: 37 // Ch - The character type. 38 // Alloc - The allocator type. 39 // Description: Utility for defining DualUseFilters which filter an 40 // entire stream at once. To use, override the protected virtual 41 // member do_filter. 42 // Note: This filter should not be copied while it is in use. 43 // 44 template<typename Ch, typename Alloc = std::allocator<Ch> > 45 class aggregate_filter { 46 public: 47 typedef Ch char_type; 48 struct category 49 : dual_use, 50 filter_tag, 51 multichar_tag, 52 closable_tag 53 { }; aggregate_filter()54 aggregate_filter() : ptr_(0), state_(0) { } ~aggregate_filter()55 virtual ~aggregate_filter() { } 56 57 template<typename Source> read(Source & src,char_type * s,std::streamsize n)58 std::streamsize read(Source& src, char_type* s, std::streamsize n) 59 { 60 using namespace std; 61 BOOST_ASSERT(!(state_ & f_write)); 62 state_ |= f_read; 63 if (!(state_ & f_eof)) 64 do_read(src); 65 std::streamsize amt = 66 (std::min)(n, static_cast<std::streamsize>(data_.size() - ptr_)); 67 if (amt) { 68 BOOST_IOSTREAMS_CHAR_TRAITS(char_type)::copy(s, &data_[ptr_], amt); 69 ptr_ += amt; 70 } 71 return detail::check_eof(amt); 72 } 73 74 template<typename Sink> write(Sink &,const char_type * s,std::streamsize n)75 std::streamsize write(Sink&, const char_type* s, std::streamsize n) 76 { 77 BOOST_ASSERT(!(state_ & f_read)); 78 state_ |= f_write; 79 data_.insert(data_.end(), s, s + n); 80 return n; 81 } 82 83 template<typename Sink> close(Sink & sink,BOOST_IOS::openmode which)84 void close(Sink& sink, BOOST_IOS::openmode which) 85 { 86 if ((state_ & f_read) != 0 && which == BOOST_IOS::in) 87 close_impl(); 88 if ((state_ & f_write) != 0 && which == BOOST_IOS::out) { 89 try { 90 vector_type filtered; 91 do_filter(data_, filtered); 92 do_write( 93 sink, &filtered[0], 94 static_cast<std::streamsize>(filtered.size()) 95 ); 96 } catch (...) { 97 close_impl(); 98 throw; 99 } 100 close_impl(); 101 } 102 } 103 104 protected: 105 typedef std::vector<Ch, Alloc> vector_type; 106 typedef typename vector_type::size_type size_type; 107 private: 108 virtual void do_filter(const vector_type& src, vector_type& dest) = 0; do_close()109 virtual void do_close() { } 110 111 template<typename Source> do_read(Source & src)112 void do_read(Source& src) 113 { 114 using std::streamsize; 115 vector_type data; 116 while (true) { 117 const std::streamsize size = default_device_buffer_size; 118 Ch buf[size]; 119 std::streamsize amt; 120 if ((amt = boost::iostreams::read(src, buf, size)) == -1) 121 break; 122 data.insert(data.end(), buf, buf + amt); 123 } 124 do_filter(data, data_); 125 state_ |= f_eof; 126 } 127 128 template<typename Sink> do_write(Sink & sink,const char_type * s,std::streamsize n)129 void do_write(Sink& sink, const char_type* s, std::streamsize n) 130 { 131 typedef typename iostreams::category_of<Sink>::type category; 132 typedef is_convertible<category, output> can_write; 133 do_write(sink, s, n, can_write()); 134 } 135 136 template<typename Sink> do_write(Sink & sink,const char_type * s,std::streamsize n,mpl::true_)137 void do_write(Sink& sink, const char_type* s, std::streamsize n, mpl::true_) 138 { iostreams::write(sink, s, n); } 139 140 template<typename Sink> do_write(Sink &,const char_type *,std::streamsize,mpl::false_)141 void do_write(Sink&, const char_type*, std::streamsize, mpl::false_) { } 142 close_impl()143 void close_impl() 144 { 145 data_.clear(); 146 ptr_ = 0; 147 state_ = 0; 148 do_close(); 149 } 150 151 enum flag_type { 152 f_read = 1, 153 f_write = f_read << 1, 154 f_eof = f_write << 1 155 }; 156 157 // Note: typically will not be copied while vector contains data. 158 vector_type data_; 159 size_type ptr_; 160 int state_; 161 }; 162 BOOST_IOSTREAMS_PIPABLE(aggregate_filter, 1) 163 164 } } // End namespaces iostreams, boost. 165 166 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC. 167 168 #endif // #ifndef BOOST_IOSTREAMS_AGGREGATE_FILTER_HPP_INCLUDED 169