1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2004-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.)
6 // See http://www.boost.org/libs/iostreams for documentation.
8 // Contains the definitions of two codecvt facets useful for testing code
9 // conversion. Both represent the "null padded" character encoding described as
10 // follows. A wide character can be represented by the encoding if its value V
11 // is within the range of an unsigned char. The first char of the sequence
12 // representing V is V % 3 + 1. This is followed by V % 3 null characters, and
13 // finally by V itself.
15 // The first codecvt facet, null_padded_codecvt, is statefull, with state_type
18 // The second codecvt facet, stateless_null_padded_codecvt, is stateless. At
19 // each point in a conversion, no characters are consumed unless there is room
20 // in the output sequence to write an entire multibyte sequence.
22 #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED
23 #define BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED
25 #include <boost/config.hpp> // NO_STDC_NAMESPACE
26 #include <boost/iostreams/detail/codecvt_helper.hpp>
27 #include <boost/iostreams/detail/config/wide_streams.hpp>
28 #include <cstddef> // mbstate_t.
29 #include <locale> // codecvt.
30 #include <boost/integer_traits.hpp> // const_max.
32 #ifdef BOOST_NO_STDC_NAMESPACE
33 namespace std { using ::mbstate_t; }
36 namespace boost { namespace iostreams { namespace test {
38 //------------------Definition of null_padded_codecvt_state-------------------//
40 class null_padded_codecvt_state {
42 null_padded_codecvt_state(int val = 0) : val_(val) { }
43 operator int() const { return val_; }
44 int& val() { return val_; }
45 const int& val() const { return val_; }
52 BOOST_IOSTREAMS_CODECVT_SPEC(boost::iostreams::test::null_padded_codecvt_state)
54 namespace boost { namespace iostreams { namespace test {
56 //------------------Definition of null_padded_codevt--------------------------//
59 // state is initially 0. After a single character is consumed, state is set to
60 // the number of characters in the current multibyte sequence and decremented
61 // as each character is consumed until its value reaches 0 again.
63 class null_padded_codecvt
64 : public iostreams::detail::codecvt_helper<
65 wchar_t, char, null_padded_codecvt_state
69 typedef null_padded_codecvt_state state_type;
71 std::codecvt_base::result
72 do_in( state_type& state, const char* first1, const char* last1,
73 const char*& next1, wchar_t* first2, wchar_t* last2,
74 wchar_t*& next2 ) const
77 if (state < 0 || state > 3)
78 return codecvt_base::error;
81 while (next2 != last2 && next1 != last1) {
82 while (next1 != last1) {
84 if (*next1 < 1 || *next1 > 3)
85 return codecvt_base::error;
87 } else if (state == 1) {
88 *next2++ = (unsigned char) *next1++;
93 return codecvt_base::error;
98 return next2 == last2 ?
100 codecvt_base::partial;
103 std::codecvt_base::result
104 do_out( state_type& state, const wchar_t* first1, const wchar_t* last1,
105 const wchar_t*& next1, char* first2, char* last2,
109 if (state < 0 || state > 3)
110 return codecvt_base::error;
113 while (next1 != last1 && next2 != last2) {
114 while (next2 != last2) {
116 if (*next1 > integer_traits<unsigned char>::const_max)
117 return codecvt_base::noconv;
118 state = *next1 % 3 + 1;
119 *next2++ = static_cast<char>(state);
120 } else if (state == 1) {
122 *next2++ = static_cast<unsigned char>(*next1++);
130 return next1 == last1 ?
132 codecvt_base::partial;
135 std::codecvt_base::result
136 do_unshift( state_type& state,
143 while (state.val()-- > 0)
147 return codecvt_base::partial;
148 return codecvt_base::ok;
151 bool do_always_noconv() const throw() { return false; }
153 int do_max_length() const throw() { return 4; }
155 int do_encoding() const throw() { return -1; }
157 int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type& state,
158 const char* first1, const char* last1,
159 std::size_t len2 ) const throw()
160 { // Implementation should follow that of do_in().
162 std::size_t result = 0;
163 const char* next1 = first1;
164 while (result < len2 && next1 != last1) {
165 while (next1 != last1) {
167 if (*next1 < 1 || *next1 > 3)
168 return static_cast<int>(result); // error.
170 } else if (st == 1) {
176 return static_cast<int>(result); // error.
181 return static_cast<int>(result);
185 //------------------Definition of stateless_null_padded_codevt----------------//
187 class stateless_null_padded_codecvt
188 : public std::codecvt<wchar_t, char, std::mbstate_t>
190 std::codecvt_base::result
191 do_in( state_type&, const char* first1, const char* last1,
192 const char*& next1, wchar_t* first2, wchar_t* last2,
193 wchar_t*& next2 ) const
196 for ( next1 = first1, next2 = first2;
197 next1 != last1 && next2 != last2; )
199 int len = (unsigned char) *next1;
200 if (len < 1 || len > 3)
201 return codecvt_base::error;
202 if (last1 - next1 < len + 1)
203 return codecvt_base::partial;
207 return codecvt_base::error;
208 *next2++ = (unsigned char) *next1++;
210 return next1 == last1 && next2 == last2 ?
212 codecvt_base::partial;
215 std::codecvt_base::result
216 do_out( state_type&, const wchar_t* first1, const wchar_t* last1,
217 const wchar_t*& next1, char* first2, char* last2,
221 for ( next1 = first1, next2 = first2;
222 next1 != last1 && next2 != last2; )
224 if (*next1 > integer_traits<unsigned char>::const_max)
225 return codecvt_base::noconv;
226 int skip = *next1 % 3 + 2;
227 if (last2 - next2 < skip)
228 return codecvt_base::partial;
229 *next2++ = static_cast<char>(--skip);
232 *next2++ = (unsigned char) *next1++;
234 return codecvt_base::ok;
237 std::codecvt_base::result
238 do_unshift( state_type&,
241 char*& /* next2 */ ) const
243 return std::codecvt_base::ok;
246 bool do_always_noconv() const throw() { return false; }
248 int do_max_length() const throw() { return 4; }
250 int do_encoding() const throw() { return -1; }
252 int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type&,
253 const char* first1, const char* last1,
254 std::size_t len2 ) const throw()
255 { // Implementation should follow that of do_in().
256 std::size_t result = 0;
257 for ( const char* next1 = first1;
258 next1 != last1 && result < len2; ++result)
260 int len = (unsigned char) *next1;
261 if (len < 1 || len > 3 || last1 - next1 < len + 1)
262 return static_cast<int>(result); // error.
266 return static_cast<int>(result); // error.
269 return static_cast<int>(result);
273 } } } // End namespaces detail, iostreams, boost.
275 #endif // #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED