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 // To do: handle bidirection streams and output-seekable components.
9 
10 #ifndef BOOST_IOSTREAMS_SKIP_HPP_INCLUDED
11 #define BOOST_IOSTREAMS_SKIP_HPP_INCLUDED
12 
13 #if defined(_MSC_VER)
14 # pragma once
15 #endif
16 
17 #include <boost/iostreams/char_traits.hpp>
18 #include <boost/iostreams/detail/ios.hpp>  // failure.
19 #include <boost/iostreams/operations.hpp>
20 #include <boost/iostreams/seek.hpp>
21 #include <boost/iostreams/traits.hpp>
22 #include <boost/mpl/and.hpp>
23 #include <boost/mpl/bool.hpp>
24 #include <boost/mpl/or.hpp>
25 #include <boost/throw_exception.hpp>
26 #include <boost/type_traits/is_convertible.hpp>
27 
28 namespace boost { namespace iostreams {
29 
30 namespace detail {
31 
32 template<typename Device>
skip(Device & dev,stream_offset off,mpl::true_)33 void skip(Device& dev, stream_offset off, mpl::true_)
34 { iostreams::seek(dev, off, BOOST_IOS::cur); }
35 
36 template<typename Device>
skip(Device & dev,stream_offset off,mpl::false_)37 void skip(Device& dev, stream_offset off, mpl::false_)
38 {   // gcc 2.95 needs namespace qualification for char_traits.
39     typedef typename char_type_of<Device>::type  char_type;
40     typedef iostreams::char_traits<char_type>    traits_type;
41     for (stream_offset z = 0; z < off; ) {
42         typename traits_type::int_type c;
43         if (traits_type::is_eof(c = iostreams::get(dev)))
44             boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad skip offset"));
45         if (!traits_type::would_block(c))
46             ++z;
47     }
48 }
49 
50 template<typename Filter, typename Device>
skip(Filter & flt,Device & dev,stream_offset off,BOOST_IOS::openmode which,mpl::true_)51 void skip( Filter& flt, Device& dev, stream_offset off,
52            BOOST_IOS::openmode which, mpl::true_ )
53 { boost::iostreams::seek(flt, dev, off, BOOST_IOS::cur, which); }
54 
55 template<typename Filter, typename Device>
skip(Filter & flt,Device & dev,stream_offset off,BOOST_IOS::openmode,mpl::false_)56 void skip( Filter& flt, Device& dev, stream_offset off,
57            BOOST_IOS::openmode, mpl::false_ )
58 {
59     typedef typename char_type_of<Device>::type char_type;
60     char_type c;
61     for (stream_offset z = 0; z < off; ) {
62         std::streamsize amt;
63         if ((amt = iostreams::read(flt, dev, &c, 1)) == -1)
64             boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad skip offset"));
65         if (amt == 1)
66             ++z;
67     }
68 }
69 
70 } // End namespace detail.
71 
72 template<typename Device>
skip(Device & dev,stream_offset off)73 void skip(Device& dev, stream_offset off)
74 {
75     typedef typename mode_of<Device>::type     mode;
76     typedef mpl::or_<
77         is_convertible<mode, input_seekable>,
78         is_convertible<mode, output_seekable>
79     >                                          can_seek;
80     BOOST_STATIC_ASSERT(
81         (can_seek::value || is_convertible<mode, input>::value)
82     );
83     detail::skip(dev, off, can_seek());
84 }
85 
86 template<typename Filter, typename Device>
skip(Filter & flt,Device & dev,stream_offset off,BOOST_IOS::openmode which=BOOST_IOS::in|BOOST_IOS::out)87 void skip( Filter& flt, Device& dev, stream_offset off,
88            BOOST_IOS::openmode which = BOOST_IOS::in | BOOST_IOS::out )
89 {
90     typedef typename mode_of<Filter>::type                 filter_mode;
91     typedef typename mode_of<Device>::type                 device_mode;
92     typedef mpl::or_<
93         mpl::and_<
94             is_convertible<filter_mode, input_seekable>,
95             is_convertible<device_mode, input_seekable>
96         >,
97         mpl::and_<
98             is_convertible<filter_mode, output_seekable>,
99             is_convertible<device_mode, output_seekable>
100         >
101     >                                                      can_seek;
102     BOOST_STATIC_ASSERT(
103         ( can_seek::value ||
104           (is_convertible<filter_mode, input>::value &&
105           is_convertible<device_mode, input>::value) )
106     );
107     detail::skip(flt, dev, off, which, can_seek());
108 }
109 
110 } } // End namespaces iostreams, boost.
111 
112 #endif // #ifndef BOOST_IOSTREAMS_SKIP_HPP_INCLUDED //------------------------//
113