• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // See http://www.boost.org/libs/iostreams for documentation.
6 
7 // This material is heavily indebted to the discussion and code samples in
8 // A. Langer and K. Kreft, "Standard C++ IOStreams and Locales",
9 // Addison-Wesley, 2000, pp. 228-43.
10 
11 // User "GMSB" provided an optimization for small seeks.
12 
13 #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
14 #define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
15 
16 #include <algorithm>                             // min, max.
17 #include <cassert>
18 #include <exception>
19 #include <boost/config.hpp>                      // Member template friends.
20 #include <boost/detail/workaround.hpp>
21 #include <boost/core/typeinfo.hpp>
22 #include <boost/iostreams/constants.hpp>
23 #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
24 #include <boost/iostreams/detail/buffer.hpp>
25 #include <boost/iostreams/detail/config/wide_streams.hpp>
26 #include <boost/iostreams/detail/double_object.hpp>
27 #include <boost/iostreams/detail/execute.hpp>
28 #include <boost/iostreams/detail/functional.hpp>
29 #include <boost/iostreams/detail/ios.hpp>
30 #include <boost/iostreams/detail/optional.hpp>
31 #include <boost/iostreams/detail/push.hpp>
32 #include <boost/iostreams/detail/streambuf/linked_streambuf.hpp>
33 #include <boost/iostreams/operations.hpp>
34 #include <boost/iostreams/positioning.hpp>
35 #include <boost/iostreams/traits.hpp>
36 #include <boost/iostreams/operations.hpp>
37 #include <boost/mpl/if.hpp>
38 #include <boost/throw_exception.hpp>
39 #include <boost/type_traits/is_convertible.hpp>
40 
41 // Must come last.
42 #include <boost/iostreams/detail/config/disable_warnings.hpp>  // MSVC, BCC 5.x
43 
44 namespace boost { namespace iostreams { namespace detail {
45 
46 //
47 // Description: The implementation of basic_streambuf used by chains.
48 //
49 template<typename T, typename Tr, typename Alloc, typename Mode>
50 class indirect_streambuf
51     : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
52 {
53 public:
54     typedef typename char_type_of<T>::type                    char_type;
55     BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
56 private:
57     typedef typename category_of<T>::type                     category;
58     typedef concept_adapter<T>                                wrapper;
59     typedef detail::basic_buffer<char_type, Alloc>            buffer_type;
60     typedef indirect_streambuf<T, Tr, Alloc, Mode>            my_type;
61     typedef detail::linked_streambuf<char_type, traits_type>  base_type;
62     typedef linked_streambuf<char_type, Tr>                   streambuf_type;
63 public:
64     indirect_streambuf();
65 
66     void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
67     bool is_open() const;
68     void close();
69     bool auto_close() const;
70     void set_auto_close(bool close);
71     bool strict_sync();
72 
73     // Declared in linked_streambuf.
component()74     T* component() { return &*obj(); }
75 protected:
76     BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
77 
78     //----------virtual functions---------------------------------------------//
79 
80 #ifndef BOOST_IOSTREAMS_NO_LOCALE
81     void imbue(const std::locale& loc);
82 #endif
83 #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
84     public:
85 #endif
86     int_type underflow();
87     int_type pbackfail(int_type c);
88     int_type overflow(int_type c);
89     int sync();
90     pos_type seekoff( off_type off, BOOST_IOS::seekdir way,
91                       BOOST_IOS::openmode which );
92     pos_type seekpos(pos_type sp, BOOST_IOS::openmode which);
93 
94     // Declared in linked_streambuf.
95     void set_next(streambuf_type* next);
96     void close_impl(BOOST_IOS::openmode m);
component_type() const97     const boost::core::typeinfo& component_type() const { return BOOST_CORE_TYPEID(T); }
component_impl()98     void* component_impl() { return component(); }
99 private:
100 
101     //----------Accessor functions--------------------------------------------//
102 
obj()103     wrapper& obj() { return *storage_; }
next() const104     streambuf_type* next() const { return next_; }
in()105     buffer_type& in() { return buffer_.first(); }
out()106     buffer_type& out() { return buffer_.second(); }
can_read() const107     bool can_read() const { return is_convertible<Mode, input>::value; }
can_write() const108     bool can_write() const { return is_convertible<Mode, output>::value; }
output_buffered() const109     bool output_buffered() const { return (flags_ & f_output_buffered) != 0; }
shared_buffer() const110     bool shared_buffer() const { return is_convertible<Mode, seekable>::value || is_convertible<Mode, dual_seekable>::value; }
set_flags(int f)111     void set_flags(int f) { flags_ = f; }
112 
113     //----------State changing functions--------------------------------------//
114 
115     virtual void init_get_area();
116     virtual void init_put_area();
117 
118     //----------Utility function----------------------------------------------//
119 
120     pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
121                         BOOST_IOS::openmode which );
122     void sync_impl();
123 
124     enum flag_type {
125         f_open             = 1,
126         f_output_buffered  = f_open << 1,
127         f_auto_close       = f_output_buffered << 1
128     };
129 
130     optional<wrapper>           storage_;
131     streambuf_type*             next_;
132     double_object<
133         buffer_type,
134         is_convertible<
135             Mode,
136             two_sequence
137         >
138     >                           buffer_;
139     std::streamsize             pback_size_;
140     int                         flags_;
141 };
142 
143 //--------------Implementation of indirect_streambuf--------------------------//
144 
145 template<typename T, typename Tr, typename Alloc, typename Mode>
indirect_streambuf()146 indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
147     : next_(0), pback_size_(0), flags_(f_auto_close) { }
148 
149 //--------------Implementation of open, is_open and close---------------------//
150 
151 template<typename T, typename Tr, typename Alloc, typename Mode>
open(const T & t,std::streamsize buffer_size,std::streamsize pback_size)152 void indirect_streambuf<T, Tr, Alloc, Mode>::open
153     (const T& t, std::streamsize buffer_size, std::streamsize pback_size)
154 {
155     using namespace std;
156 
157     // Normalize buffer sizes.
158     buffer_size =
159         (buffer_size != -1) ?
160         buffer_size :
161         iostreams::optimal_buffer_size(t);
162     pback_size =
163         (pback_size != -1) ?
164         pback_size :
165         default_pback_buffer_size;
166 
167     // Construct input buffer.
168     if (can_read()) {
169         pback_size_ = (std::max)(std::streamsize(2), pback_size); // STLPort needs 2.
170         std::streamsize size =
171             pback_size_ +
172             ( buffer_size ? buffer_size: std::streamsize(1) );
173         in().resize(static_cast<int>(size));
174         if (!shared_buffer())
175             init_get_area();
176     }
177 
178     // Construct output buffer.
179     if (can_write() && !shared_buffer()) {
180         if (buffer_size != std::streamsize(0))
181             out().resize(static_cast<int>(buffer_size));
182         init_put_area();
183     }
184 
185     storage_.reset(wrapper(t));
186     flags_ |= f_open;
187     if (can_write() && buffer_size > 1)
188         flags_ |= f_output_buffered;
189     this->set_true_eof(false);
190     this->set_needs_close();
191 }
192 
193 template<typename T, typename Tr, typename Alloc, typename Mode>
is_open() const194 inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open() const
195 { return (flags_ & f_open) != 0; }
196 
197 template<typename T, typename Tr, typename Alloc, typename Mode>
close()198 void indirect_streambuf<T, Tr, Alloc, Mode>::close()
199 {
200     using namespace std;
201     base_type* self = this;
202     detail::execute_all(
203         detail::call_member_close(*self, BOOST_IOS::in),
204         detail::call_member_close(*self, BOOST_IOS::out),
205         detail::call_reset(storage_),
206         detail::clear_flags(flags_)
207     );
208 }
209 
210 template<typename T, typename Tr, typename Alloc, typename Mode>
auto_close() const211 bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
212 { return (flags_ & f_auto_close) != 0; }
213 
214 template<typename T, typename Tr, typename Alloc, typename Mode>
set_auto_close(bool close)215 void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
216 { flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
217 
218 //--------------Implementation virtual functions------------------------------//
219 
220 #ifndef BOOST_IOSTREAMS_NO_LOCALE
221 template<typename T, typename Tr, typename Alloc, typename Mode>
imbue(const std::locale & loc)222 void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
223 {
224     if (is_open()) {
225         obj().imbue(loc);
226         if (next_)
227             next_->pubimbue(loc);
228     }
229 }
230 #endif
231 
232 template<typename T, typename Tr, typename Alloc, typename Mode>
233 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
underflow()234 indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
235 {
236     using namespace std;
237     if (!gptr()) init_get_area();
238     buffer_type& buf = in();
239     if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
240 
241     // Fill putback buffer.
242     std::streamsize keep =
243         (std::min)( static_cast<std::streamsize>(gptr() - eback()),
244                     pback_size_ );
245     if (keep)
246         traits_type::move( buf.data() + (pback_size_ - keep),
247                            gptr() - keep, keep );
248 
249     // Set pointers to reasonable values in case read throws.
250     setg( buf.data() + pback_size_ - keep,
251           buf.data() + pback_size_,
252           buf.data() + pback_size_ );
253 
254     // Read from source.
255     std::streamsize chars =
256         obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_);
257     if (chars == -1) {
258         this->set_true_eof(true);
259         chars = 0;
260     }
261     setg(eback(), gptr(), buf.data() + pback_size_ + chars);
262     return chars != 0 ?
263         traits_type::to_int_type(*gptr()) :
264         traits_type::eof();
265 }
266 
267 template<typename T, typename Tr, typename Alloc, typename Mode>
268 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
pbackfail(int_type c)269 indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
270 {
271     if (gptr() != eback()) {
272         gbump(-1);
273         if (!traits_type::eq_int_type(c, traits_type::eof()))
274             *gptr() = traits_type::to_char_type(c);
275         return traits_type::not_eof(c);
276     } else {
277         boost::throw_exception(bad_putback());
278     }
279 }
280 
281 template<typename T, typename Tr, typename Alloc, typename Mode>
282 typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
overflow(int_type c)283 indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
284 {
285     if ( (output_buffered() && pptr() == 0) ||
286          (shared_buffer() && gptr() != 0) )
287     {
288         init_put_area();
289     }
290     if (!traits_type::eq_int_type(c, traits_type::eof())) {
291         if (output_buffered()) {
292             if (pptr() == epptr()) {
293                 sync_impl();
294                 if (pptr() == epptr())
295                     return traits_type::eof();
296             }
297             *pptr() = traits_type::to_char_type(c);
298             pbump(1);
299         } else {
300             char_type d = traits_type::to_char_type(c);
301             if (obj().write(&d, 1, next_) != 1)
302                 return traits_type::eof();
303         }
304     }
305     return traits_type::not_eof(c);
306 }
307 
308 template<typename T, typename Tr, typename Alloc, typename Mode>
sync()309 int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
310 {
311     try { // sync() is no-throw.
312         sync_impl();
313         obj().flush(next_);
314         return 0;
315     } catch (...) { return -1; }
316 }
317 
318 template<typename T, typename Tr, typename Alloc, typename Mode>
strict_sync()319 bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
320 {
321     try { // sync() is no-throw.
322         sync_impl();
323         return obj().flush(next_);
324     } catch (...) { return false; }
325 }
326 
327 template<typename T, typename Tr, typename Alloc, typename Mode>
328 inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
seekoff(off_type off,BOOST_IOS::seekdir way,BOOST_IOS::openmode which)329 indirect_streambuf<T, Tr, Alloc, Mode>::seekoff
330     (off_type off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
331 { return seek_impl(off, way, which); }
332 
333 template<typename T, typename Tr, typename Alloc, typename Mode>
334 inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
seekpos(pos_type sp,BOOST_IOS::openmode which)335 indirect_streambuf<T, Tr, Alloc, Mode>::seekpos
336     (pos_type sp, BOOST_IOS::openmode which)
337 {
338     return seek_impl(position_to_offset(sp), BOOST_IOS::beg, which);
339 }
340 
341 template<typename T, typename Tr, typename Alloc, typename Mode>
342 typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
seek_impl(stream_offset off,BOOST_IOS::seekdir way,BOOST_IOS::openmode which)343 indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
344     (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
345 {
346     if ( gptr() != 0 && way == BOOST_IOS::cur && which == BOOST_IOS::in &&
347          eback() - gptr() <= off && off <= egptr() - gptr() )
348     {   // Small seek optimization
349         gbump(static_cast<int>(off));
350         return obj().seek(stream_offset(0), BOOST_IOS::cur, BOOST_IOS::in, next_) -
351                static_cast<off_type>(egptr() - gptr());
352     }
353     if (pptr() != 0)
354         this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
355     if (way == BOOST_IOS::cur && gptr())
356         off -= static_cast<off_type>(egptr() - gptr());
357     bool two_head = is_convertible<category, dual_seekable>::value ||
358                     is_convertible<category, bidirectional_seekable>::value;
359     if (two_head) {
360         BOOST_IOS::openmode both = BOOST_IOS::in | BOOST_IOS::out;
361         if ((which & both) == both)
362             boost::throw_exception(bad_seek());
363         if (which & BOOST_IOS::in) {
364             setg(0, 0, 0);
365         }
366         if (which & BOOST_IOS::out) {
367             setp(0, 0);
368         }
369     }
370     else {
371         setg(0, 0, 0);
372         setp(0, 0);
373     }
374     return obj().seek(off, way, which, next_);
375 }
376 
377 template<typename T, typename Tr, typename Alloc, typename Mode>
set_next(streambuf_type * next)378 inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
379     (streambuf_type* next)
380 { next_ = next; }
381 
382 template<typename T, typename Tr, typename Alloc, typename Mode>
close_impl(BOOST_IOS::openmode which)383 inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
384     (BOOST_IOS::openmode which)
385 {
386     if (which == BOOST_IOS::in && is_convertible<Mode, input>::value) {
387         setg(0, 0, 0);
388     }
389     if (which == BOOST_IOS::out && is_convertible<Mode, output>::value) {
390         sync();
391         setp(0, 0);
392     }
393     if ( !is_convertible<category, dual_use>::value ||
394          is_convertible<Mode, input>::value == (which == BOOST_IOS::in) )
395     {
396         obj().close(which, next_);
397     }
398 }
399 
400 //----------State changing functions------------------------------------------//
401 
402 template<typename T, typename Tr, typename Alloc, typename Mode>
sync_impl()403 void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
404 {
405     std::streamsize avail, amt;
406     if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
407         if ((amt = obj().write(pbase(), avail, next())) == avail)
408             setp(out().begin(), out().end());
409         else {
410             const char_type* ptr = pptr();
411             setp(out().begin() + amt, out().end());
412             pbump(static_cast<int>(ptr - pptr()));
413         }
414     }
415 }
416 
417 template<typename T, typename Tr, typename Alloc, typename Mode>
init_get_area()418 void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
419 {
420     if (shared_buffer() && pptr() != 0) {
421         sync_impl();
422         setp(0, 0);
423     }
424     setg(in().begin(), in().begin(), in().begin());
425 }
426 
427 template<typename T, typename Tr, typename Alloc, typename Mode>
init_put_area()428 void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
429 {
430     using namespace std;
431     if (shared_buffer() && gptr() != 0) {
432         obj().seek(static_cast<off_type>(gptr() - egptr()), BOOST_IOS::cur, BOOST_IOS::in, next_);
433         setg(0, 0, 0);
434     }
435     if (output_buffered())
436         setp(out().begin(), out().end());
437     else
438         setp(0, 0);
439 }
440 
441 //----------------------------------------------------------------------------//
442 
443 } } } // End namespaces detail, iostreams, boost.
444 
445 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
446 
447 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
448