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