| 1 | #ifndef BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP |
| 2 | #define BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP |
| 3 | |
| 4 | // MS compatible compilers support #pragma once |
| 5 | #if defined(_MSC_VER) |
| 6 | # pragma once |
| 7 | #endif |
| 8 | |
| 9 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
| 10 | // wchar_from_mb.hpp |
| 11 | |
| 12 | // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . |
| 13 | // Use, modification and distribution is subject to the Boost Software |
| 14 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| 15 | // http://www.boost.org/LICENSE_1_0.txt) |
| 16 | |
| 17 | // See http://www.boost.org for updates, documentation, and revision history. |
| 18 | |
| 19 | #include <cctype> |
| 20 | #include <cstddef> // size_t |
| 21 | #ifndef BOOST_NO_CWCHAR |
| 22 | #include <cwchar> // mbstate_t |
| 23 | #endif |
| 24 | #include <algorithm> // copy |
| 25 | |
| 26 | #include <boost/config.hpp> |
| 27 | #if defined(BOOST_NO_STDC_NAMESPACE) |
| 28 | namespace std{ |
| 29 | using ::mbstate_t; |
| 30 | } // namespace std |
| 31 | #endif |
| 32 | #include <boost/assert.hpp> |
| 33 | #include <boost/core/ignore_unused.hpp> |
| 34 | #include <boost/array.hpp> |
| 35 | #include <boost/iterator/iterator_adaptor.hpp> |
| 36 | #include <boost/archive/detail/utf8_codecvt_facet.hpp> |
| 37 | #include <boost/archive/iterators/dataflow_exception.hpp> |
| 38 | #include <boost/serialization/throw_exception.hpp> |
| 39 | |
| 40 | #include <iostream> |
| 41 | |
| 42 | namespace boost { |
| 43 | namespace archive { |
| 44 | namespace iterators { |
| 45 | |
| 46 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
| 47 | // class used by text archives to translate char strings to wchar_t |
| 48 | // strings of the currently selected locale |
| 49 | template<class Base> |
| 50 | class wchar_from_mb |
| 51 | : public boost::iterator_adaptor< |
| 52 | wchar_from_mb<Base>, |
| 53 | Base, |
| 54 | wchar_t, |
| 55 | single_pass_traversal_tag, |
| 56 | wchar_t |
| 57 | > |
| 58 | { |
| 59 | friend class boost::iterator_core_access; |
| 60 | typedef typename boost::iterator_adaptor< |
| 61 | wchar_from_mb<Base>, |
| 62 | Base, |
| 63 | wchar_t, |
| 64 | single_pass_traversal_tag, |
| 65 | wchar_t |
| 66 | > super_t; |
| 67 | |
| 68 | typedef wchar_from_mb<Base> this_t; |
| 69 | |
| 70 | void drain(); |
| 71 | |
| 72 | wchar_t dereference() const { |
| 73 | if(m_output.m_next == m_output.m_next_available) |
| 74 | return static_cast<wchar_t>(0); |
| 75 | return * m_output.m_next; |
| 76 | } |
| 77 | |
| 78 | void increment(){ |
| 79 | if(m_output.m_next == m_output.m_next_available) |
| 80 | return; |
| 81 | if(++m_output.m_next == m_output.m_next_available){ |
| 82 | if(m_input.m_done) |
| 83 | return; |
| 84 | drain(); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | bool equal(this_t const & rhs) const { |
| 89 | return dereference() == rhs.dereference(); |
| 90 | } |
| 91 | |
| 92 | boost::archive::detail::utf8_codecvt_facet m_codecvt_facet; |
| 93 | std::mbstate_t m_mbs; |
| 94 | |
| 95 | template<typename T> |
| 96 | struct sliding_buffer { |
| 97 | boost::array<T, 32> m_buffer; |
| 98 | typename boost::array<T, 32>::const_iterator m_next_available; |
| 99 | typename boost::array<T, 32>::iterator m_next; |
| 100 | bool m_done; |
| 101 | // default ctor |
| 102 | sliding_buffer() : |
| 103 | m_next_available(m_buffer.begin()), |
| 104 | m_next(m_buffer.begin()), |
| 105 | m_done(false) |
| 106 | {} |
| 107 | // copy ctor |
| 108 | sliding_buffer(const sliding_buffer & rhs) : |
| 109 | m_next_available( |
| 110 | std::copy( |
| 111 | rhs.m_buffer.begin(), |
| 112 | rhs.m_next_available, |
| 113 | m_buffer.begin() |
| 114 | ) |
| 115 | ), |
| 116 | m_next( |
| 117 | m_buffer.begin() + (rhs.m_next - rhs.m_buffer.begin()) |
| 118 | ), |
| 119 | m_done(rhs.m_done) |
| 120 | {} |
| 121 | }; |
| 122 | |
| 123 | sliding_buffer<typename iterator_value<Base>::type> m_input; |
| 124 | sliding_buffer<typename iterator_value<this_t>::type> m_output; |
| 125 | |
| 126 | public: |
| 127 | // make composable by using templated constructor |
| 128 | template<class T> |
| 129 | wchar_from_mb(T start) : |
| 130 | super_t(Base(static_cast< T >(start))), |
| 131 | m_mbs(std::mbstate_t()) |
| 132 | { |
| 133 | BOOST_ASSERT(std::mbsinit(&m_mbs)); |
| 134 | drain(); |
| 135 | } |
| 136 | // default constructor used as an end iterator |
| 137 | wchar_from_mb(){} |
| 138 | |
| 139 | // copy ctor |
| 140 | wchar_from_mb(const wchar_from_mb & rhs) : |
| 141 | super_t(rhs.base_reference()), |
| 142 | m_mbs(rhs.m_mbs), |
| 143 | m_input(rhs.m_input), |
| 144 | m_output(rhs.m_output) |
| 145 | {} |
| 146 | }; |
| 147 | |
| 148 | template<class Base> |
| 149 | void wchar_from_mb<Base>::drain(){ |
| 150 | BOOST_ASSERT(! m_input.m_done); |
| 151 | for(;;){ |
| 152 | typename boost::iterators::iterator_reference<Base>::type c = *(this->base_reference()); |
| 153 | // a null character in a multibyte stream is takes as end of string |
| 154 | if(0 == c){ |
| 155 | m_input.m_done = true; |
| 156 | break; |
| 157 | } |
| 158 | ++(this->base_reference()); |
| 159 | * const_cast<typename iterator_value<Base>::type *>( |
| 160 | (m_input.m_next_available++) |
| 161 | ) = c; |
| 162 | // if input buffer is full - we're done for now |
| 163 | if(m_input.m_buffer.end() == m_input.m_next_available) |
| 164 | break; |
| 165 | } |
| 166 | const typename boost::iterators::iterator_value<Base>::type * input_new_start; |
| 167 | typename iterator_value<this_t>::type * next_available; |
| 168 | |
| 169 | BOOST_ATTRIBUTE_UNUSED // redundant with ignore_unused below but clarifies intention |
| 170 | std::codecvt_base::result r = m_codecvt_facet.in( |
| 171 | state&: m_mbs, |
| 172 | from: m_input.m_buffer.begin(), |
| 173 | from_end: m_input.m_next_available, |
| 174 | from_next&: input_new_start, |
| 175 | to: m_output.m_buffer.begin(), |
| 176 | to_end: m_output.m_buffer.end(), |
| 177 | to_next&: next_available |
| 178 | ); |
| 179 | BOOST_ASSERT(std::codecvt_base::ok == r); |
| 180 | m_output.m_next_available = next_available; |
| 181 | m_output.m_next = m_output.m_buffer.begin(); |
| 182 | |
| 183 | // we're done with some of the input so shift left. |
| 184 | m_input.m_next_available = std::copy( |
| 185 | input_new_start, |
| 186 | m_input.m_next_available, |
| 187 | m_input.m_buffer.begin() |
| 188 | ); |
| 189 | m_input.m_next = m_input.m_buffer.begin(); |
| 190 | } |
| 191 | |
| 192 | } // namespace iterators |
| 193 | } // namespace archive |
| 194 | } // namespace boost |
| 195 | |
| 196 | #endif // BOOST_ARCHIVE_ITERATORS_WCHAR_FROM_MB_HPP |
| 197 | |