Chris@16: // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) Chris@16: // (C) Copyright 2003-2007 Jonathan Turkanis Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) Chris@16: // See http://www.boost.org/libs/iostreams for documentation. Chris@16: Chris@16: // This material is heavily indebted to the discussion and code samples in Chris@16: // A. Langer and K. Kreft, "Standard C++ IOStreams and Locales", Chris@16: // Addison-Wesley, 2000, pp. 228-43. Chris@16: Chris@16: // User "GMSB" provided an optimization for small seeks. Chris@16: Chris@16: #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED Chris@16: #define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED Chris@16: Chris@16: #include // min, max. Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // Member template friends. Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // Must come last. Chris@16: #include // MSVC, BCC 5.x Chris@16: Chris@16: namespace boost { namespace iostreams { namespace detail { Chris@16: Chris@16: // Chris@16: // Description: The implementation of basic_streambuf used by chains. Chris@16: // Chris@16: template Chris@16: class indirect_streambuf Chris@16: : public linked_streambuf::type, Tr> Chris@16: { Chris@16: public: Chris@16: typedef typename char_type_of::type char_type; Chris@16: BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr) Chris@16: private: Chris@16: typedef typename category_of::type category; Chris@16: typedef concept_adapter wrapper; Chris@16: typedef detail::basic_buffer buffer_type; Chris@16: typedef indirect_streambuf my_type; Chris@16: typedef detail::linked_streambuf base_type; Chris@16: typedef linked_streambuf streambuf_type; Chris@16: public: Chris@16: indirect_streambuf(); Chris@16: Chris@16: void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS()); Chris@16: bool is_open() const; Chris@16: void close(); Chris@16: bool auto_close() const; Chris@16: void set_auto_close(bool close); Chris@16: bool strict_sync(); Chris@16: Chris@16: // Declared in linked_streambuf. Chris@16: T* component() { return &*obj(); } Chris@16: protected: Chris@16: #if !BOOST_WORKAROUND(__GNUC__, == 2) Chris@16: BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type) Chris@16: #endif Chris@16: Chris@16: //----------virtual functions---------------------------------------------// Chris@16: Chris@16: #ifndef BOOST_IOSTREAMS_NO_LOCALE Chris@16: void imbue(const std::locale& loc); Chris@16: #endif Chris@16: #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES Chris@16: public: Chris@16: #endif Chris@16: int_type underflow(); Chris@16: int_type pbackfail(int_type c); Chris@16: int_type overflow(int_type c); Chris@16: int sync(); Chris@16: pos_type seekoff( off_type off, BOOST_IOS::seekdir way, Chris@16: BOOST_IOS::openmode which ); Chris@16: pos_type seekpos(pos_type sp, BOOST_IOS::openmode which); Chris@16: Chris@16: // Declared in linked_streambuf. Chris@16: void set_next(streambuf_type* next); Chris@16: void close_impl(BOOST_IOS::openmode m); Chris@16: const std::type_info& component_type() const { return typeid(T); } Chris@16: void* component_impl() { return component(); } Chris@16: private: Chris@16: Chris@16: //----------Accessor functions--------------------------------------------// Chris@16: Chris@16: wrapper& obj() { return *storage_; } Chris@16: streambuf_type* next() const { return next_; } Chris@16: buffer_type& in() { return buffer_.first(); } Chris@16: buffer_type& out() { return buffer_.second(); } Chris@16: bool can_read() const { return is_convertible::value; } Chris@16: bool can_write() const { return is_convertible::value; } Chris@16: bool output_buffered() const { return (flags_ & f_output_buffered) != 0; } Chris@16: bool shared_buffer() const { return is_convertible::value; } Chris@16: void set_flags(int f) { flags_ = f; } Chris@16: Chris@16: //----------State changing functions--------------------------------------// Chris@16: Chris@16: virtual void init_get_area(); Chris@16: virtual void init_put_area(); Chris@16: Chris@16: //----------Utility function----------------------------------------------// Chris@16: Chris@16: pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way, Chris@16: BOOST_IOS::openmode which ); Chris@16: void sync_impl(); Chris@16: Chris@16: enum flag_type { Chris@16: f_open = 1, Chris@16: f_output_buffered = f_open << 1, Chris@16: f_auto_close = f_output_buffered << 1 Chris@16: }; Chris@16: Chris@16: optional storage_; Chris@16: streambuf_type* next_; Chris@16: double_object< Chris@16: buffer_type, Chris@16: is_convertible< Chris@16: Mode, Chris@16: two_sequence Chris@16: > Chris@16: > buffer_; Chris@16: std::streamsize pback_size_; Chris@16: int flags_; Chris@16: }; Chris@16: Chris@16: //--------------Implementation of indirect_streambuf--------------------------// Chris@16: Chris@16: template Chris@16: indirect_streambuf::indirect_streambuf() Chris@16: : next_(0), pback_size_(0), flags_(f_auto_close) { } Chris@16: Chris@16: //--------------Implementation of open, is_open and close---------------------// Chris@16: Chris@16: template Chris@16: void indirect_streambuf::open Chris@16: (const T& t, std::streamsize buffer_size, std::streamsize pback_size) Chris@16: { Chris@16: using namespace std; Chris@16: Chris@16: // Normalize buffer sizes. Chris@16: buffer_size = Chris@16: (buffer_size != -1) ? Chris@16: buffer_size : Chris@16: iostreams::optimal_buffer_size(t); Chris@16: pback_size = Chris@16: (pback_size != -1) ? Chris@16: pback_size : Chris@16: default_pback_buffer_size; Chris@16: Chris@16: // Construct input buffer. Chris@16: if (can_read()) { Chris@16: pback_size_ = (std::max)(std::streamsize(2), pback_size); // STLPort needs 2. Chris@16: std::streamsize size = Chris@16: pback_size_ + Chris@16: ( buffer_size ? buffer_size: 1 ); Chris@16: in().resize(size); Chris@16: if (!shared_buffer()) Chris@16: init_get_area(); Chris@16: } Chris@16: Chris@16: // Construct output buffer. Chris@16: if (can_write() && !shared_buffer()) { Chris@16: if (buffer_size != 0) Chris@16: out().resize(buffer_size); Chris@16: init_put_area(); Chris@16: } Chris@16: Chris@16: storage_.reset(wrapper(t)); Chris@16: flags_ |= f_open; Chris@16: if (can_write() && buffer_size > 1) Chris@16: flags_ |= f_output_buffered; Chris@16: this->set_true_eof(false); Chris@16: this->set_needs_close(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool indirect_streambuf::is_open() const Chris@16: { return (flags_ & f_open) != 0; } Chris@16: Chris@16: template Chris@16: void indirect_streambuf::close() Chris@16: { Chris@16: using namespace std; Chris@16: base_type* self = this; Chris@16: detail::execute_all( Chris@16: detail::call_member_close(*self, BOOST_IOS::in), Chris@16: detail::call_member_close(*self, BOOST_IOS::out), Chris@16: detail::call_reset(storage_), Chris@16: detail::clear_flags(flags_) Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: bool indirect_streambuf::auto_close() const Chris@16: { return (flags_ & f_auto_close) != 0; } Chris@16: Chris@16: template Chris@16: void indirect_streambuf::set_auto_close(bool close) Chris@16: { flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); } Chris@16: Chris@16: //--------------Implementation virtual functions------------------------------// Chris@16: Chris@16: #ifndef BOOST_IOSTREAMS_NO_LOCALE Chris@16: template Chris@16: void indirect_streambuf::imbue(const std::locale& loc) Chris@16: { Chris@16: if (is_open()) { Chris@16: obj().imbue(loc); Chris@16: if (next_) Chris@16: next_->pubimbue(loc); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: template Chris@16: typename indirect_streambuf::int_type Chris@16: indirect_streambuf::underflow() Chris@16: { Chris@16: using namespace std; Chris@16: if (!gptr()) init_get_area(); Chris@16: buffer_type& buf = in(); Chris@16: if (gptr() < egptr()) return traits_type::to_int_type(*gptr()); Chris@16: Chris@16: // Fill putback buffer. Chris@16: std::streamsize keep = Chris@16: (std::min)( static_cast(gptr() - eback()), Chris@16: pback_size_ ); Chris@16: if (keep) Chris@16: traits_type::move( buf.data() + (pback_size_ - keep), Chris@16: gptr() - keep, keep ); Chris@16: Chris@16: // Set pointers to reasonable values in case read throws. Chris@16: setg( buf.data() + pback_size_ - keep, Chris@16: buf.data() + pback_size_, Chris@16: buf.data() + pback_size_ ); Chris@16: Chris@16: // Read from source. Chris@16: std::streamsize chars = Chris@16: obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_); Chris@16: if (chars == -1) { Chris@16: this->set_true_eof(true); Chris@16: chars = 0; Chris@16: } Chris@16: setg(eback(), gptr(), buf.data() + pback_size_ + chars); Chris@16: return chars != 0 ? Chris@16: traits_type::to_int_type(*gptr()) : Chris@16: traits_type::eof(); Chris@16: } Chris@16: Chris@16: template Chris@16: typename indirect_streambuf::int_type Chris@16: indirect_streambuf::pbackfail(int_type c) Chris@16: { Chris@16: if (gptr() != eback()) { Chris@16: gbump(-1); Chris@16: if (!traits_type::eq_int_type(c, traits_type::eof())) Chris@16: *gptr() = traits_type::to_char_type(c); Chris@16: return traits_type::not_eof(c); Chris@16: } else { Chris@16: boost::throw_exception(bad_putback()); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: typename indirect_streambuf::int_type Chris@16: indirect_streambuf::overflow(int_type c) Chris@16: { Chris@16: if ( (output_buffered() && pptr() == 0) || Chris@16: (shared_buffer() && gptr() != 0) ) Chris@16: { Chris@16: init_put_area(); Chris@16: } Chris@16: if (!traits_type::eq_int_type(c, traits_type::eof())) { Chris@16: if (output_buffered()) { Chris@16: if (pptr() == epptr()) { Chris@16: sync_impl(); Chris@16: if (pptr() == epptr()) Chris@16: return traits_type::eof(); Chris@16: } Chris@16: *pptr() = traits_type::to_char_type(c); Chris@16: pbump(1); Chris@16: } else { Chris@16: char_type d = traits_type::to_char_type(c); Chris@16: if (obj().write(&d, 1, next_) != 1) Chris@16: return traits_type::eof(); Chris@16: } Chris@16: } Chris@16: return traits_type::not_eof(c); Chris@16: } Chris@16: Chris@16: template Chris@16: int indirect_streambuf::sync() Chris@16: { Chris@16: try { // sync() is no-throw. Chris@16: sync_impl(); Chris@16: obj().flush(next_); Chris@16: return 0; Chris@16: } catch (...) { return -1; } Chris@16: } Chris@16: Chris@16: template Chris@16: bool indirect_streambuf::strict_sync() Chris@16: { Chris@16: try { // sync() is no-throw. Chris@16: sync_impl(); Chris@16: return obj().flush(next_); Chris@16: } catch (...) { return false; } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename indirect_streambuf::pos_type Chris@16: indirect_streambuf::seekoff Chris@16: (off_type off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which) Chris@16: { return seek_impl(off, way, which); } Chris@16: Chris@16: template Chris@16: inline typename indirect_streambuf::pos_type Chris@16: indirect_streambuf::seekpos Chris@16: (pos_type sp, BOOST_IOS::openmode which) Chris@16: { Chris@16: return seek_impl(position_to_offset(sp), BOOST_IOS::beg, which); Chris@16: } Chris@16: Chris@16: template Chris@16: typename indirect_streambuf::pos_type Chris@16: indirect_streambuf::seek_impl Chris@16: (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which) Chris@16: { Chris@16: if ( gptr() != 0 && way == BOOST_IOS::cur && which == BOOST_IOS::in && Chris@16: eback() - gptr() <= off && off <= egptr() - gptr() ) Chris@16: { // Small seek optimization Chris@16: gbump(off); Chris@16: return obj().seek(0, BOOST_IOS::cur, BOOST_IOS::in, next_) - Chris@16: static_cast(egptr() - gptr()); Chris@16: } Chris@16: if (pptr() != 0) Chris@16: this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6. Chris@16: if (way == BOOST_IOS::cur && gptr()) Chris@16: off -= static_cast(egptr() - gptr()); Chris@16: setg(0, 0, 0); Chris@16: setp(0, 0); Chris@16: return obj().seek(off, way, which, next_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void indirect_streambuf::set_next Chris@16: (streambuf_type* next) Chris@16: { next_ = next; } Chris@16: Chris@16: template Chris@16: inline void indirect_streambuf::close_impl Chris@16: (BOOST_IOS::openmode which) Chris@16: { Chris@16: if (which == BOOST_IOS::in && is_convertible::value) { Chris@16: setg(0, 0, 0); Chris@16: } Chris@16: if (which == BOOST_IOS::out && is_convertible::value) { Chris@16: sync(); Chris@16: setp(0, 0); Chris@16: } Chris@16: if ( !is_convertible::value || Chris@16: is_convertible::value == (which == BOOST_IOS::in) ) Chris@16: { Chris@16: obj().close(which, next_); Chris@16: } Chris@16: } Chris@16: Chris@16: //----------State changing functions------------------------------------------// Chris@16: Chris@16: template Chris@16: void indirect_streambuf::sync_impl() Chris@16: { Chris@16: std::streamsize avail, amt; Chris@16: if ((avail = static_cast(pptr() - pbase())) > 0) { Chris@16: if ((amt = obj().write(pbase(), avail, next())) == avail) Chris@16: setp(out().begin(), out().end()); Chris@16: else { Chris@16: const char_type* ptr = pptr(); Chris@16: setp(out().begin() + amt, out().end()); Chris@16: pbump(ptr - pptr()); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void indirect_streambuf::init_get_area() Chris@16: { Chris@16: if (shared_buffer() && pptr() != 0) { Chris@16: sync_impl(); Chris@16: setp(0, 0); Chris@16: } Chris@16: setg(in().begin(), in().begin(), in().begin()); Chris@16: } Chris@16: Chris@16: template Chris@16: void indirect_streambuf::init_put_area() Chris@16: { Chris@16: using namespace std; Chris@16: if (shared_buffer() && gptr() != 0) Chris@16: setg(0, 0, 0); Chris@16: if (output_buffered()) Chris@16: setp(out().begin(), out().end()); Chris@16: else Chris@16: setp(0, 0); Chris@16: } Chris@16: Chris@16: //----------------------------------------------------------------------------// Chris@16: Chris@16: } } } // End namespaces detail, iostreams, boost. Chris@16: Chris@16: #include // MSVC, BCC 5.x Chris@16: Chris@16: #endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED