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
dereference() const72 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
increment()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
equal(this_t const & rhs) const88 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
sliding_bufferboost::archive::iterators::wchar_from_mb::sliding_buffer102 sliding_buffer() :
103 m_next_available(m_buffer.begin()),
104 m_next(m_buffer.begin()),
105 m_done(false)
106 {}
107 // copy ctor
sliding_bufferboost::archive::iterators::wchar_from_mb::sliding_buffer108 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 composible buy using templated constructor
128 template<class T>
wchar_from_mb(T start)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
wchar_from_mb()137 wchar_from_mb(){}
138
139 // copy ctor
wchar_from_mb(const wchar_from_mb & rhs)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>
drain()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 m_mbs,
172 m_input.m_buffer.begin(),
173 m_input.m_next_available,
174 input_new_start,
175 m_output.m_buffer.begin(),
176 m_output.m_buffer.end(),
177 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