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.) 5 6 // See http://www.boost.org/libs/iostreams for documentation. 7 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. 14 15 // The first codecvt facet, null_padded_codecvt, is statefull, with state_type 16 // equal to int. 17 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. 21 22 #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED 23 #define BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED 24 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. 31 32 #ifdef BOOST_NO_STDC_NAMESPACE 33 namespace std { using ::mbstate_t; } 34 #endif 35 36 namespace boost { namespace iostreams { namespace test { 37 38 //------------------Definition of null_padded_codecvt_state-------------------// 39 40 class null_padded_codecvt_state { 41 public: null_padded_codecvt_state(int val=0)42 null_padded_codecvt_state(int val = 0) : val_(val) { } operator int() const43 operator int() const { return val_; } val()44 int& val() { return val_; } val() const45 const int& val() const { return val_; } 46 private: 47 int val_; 48 }; 49 50 } } } 51 52 BOOST_IOSTREAMS_CODECVT_SPEC(boost::iostreams::test::null_padded_codecvt_state) 53 54 namespace boost { namespace iostreams { namespace test { 55 56 //------------------Definition of null_padded_codevt--------------------------// 57 58 // 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. 62 // 63 class null_padded_codecvt 64 : public iostreams::detail::codecvt_helper< 65 wchar_t, char, null_padded_codecvt_state 66 > 67 { 68 public: 69 typedef null_padded_codecvt_state state_type; 70 private: 71 std::codecvt_base::result do_in(state_type & state,const char * first1,const char * last1,const char * & next1,wchar_t * first2,wchar_t * last2,wchar_t * & next2) const72 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 75 { 76 using namespace std; 77 if (state < 0 || state > 3) 78 return codecvt_base::error; 79 next1 = first1; 80 next2 = first2; 81 while (next2 != last2 && next1 != last1) { 82 while (next1 != last1) { 83 if (state == 0) { 84 if (*next1 < 1 || *next1 > 3) 85 return codecvt_base::error; 86 state = *next1++; 87 } else if (state == 1) { 88 *next2++ = (unsigned char) *next1++; 89 state = 0; 90 break; 91 } else { 92 if (*next1++ != 0) 93 return codecvt_base::error; 94 --state.val(); 95 } 96 } 97 } 98 return next2 == last2 ? 99 codecvt_base::ok : 100 codecvt_base::partial; 101 } 102 103 std::codecvt_base::result do_out(state_type & state,const wchar_t * first1,const wchar_t * last1,const wchar_t * & next1,char * first2,char * last2,char * & next2) const104 do_out( state_type& state, const wchar_t* first1, const wchar_t* last1, 105 const wchar_t*& next1, char* first2, char* last2, 106 char*& next2 ) const 107 { 108 using namespace std; 109 if (state < 0 || state > 3) 110 return codecvt_base::error; 111 next1 = first1; 112 next2 = first2; 113 while (next1 != last1 && next2 != last2) { 114 while (next2 != last2) { 115 if (state == 0) { 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) { 121 state = 0; 122 *next2++ = static_cast<unsigned char>(*next1++); 123 break; 124 } else { 125 --state.val(); 126 *next2++ = 0; 127 } 128 } 129 } 130 return next1 == last1 ? 131 codecvt_base::ok : 132 codecvt_base::partial; 133 } 134 135 std::codecvt_base::result do_unshift(state_type & state,char *,char * last2,char * & next2) const136 do_unshift( state_type& state, 137 char* /* first2 */, 138 char* last2, 139 char*& next2 ) const 140 { 141 using namespace std; 142 next2 = last2; 143 while (state.val()-- > 0) 144 if (next2 != last2) 145 *next2++ = 0; 146 else 147 return codecvt_base::partial; 148 return codecvt_base::ok; 149 } 150 do_always_noconv() const151 bool do_always_noconv() const throw() { return false; } 152 do_max_length() const153 int do_max_length() const throw() { return 4; } 154 do_encoding() const155 int do_encoding() const throw() { return -1; } 156 do_length(BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type & state,const char * first1,const char * last1,std::size_t len2) const157 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(). 161 int st = state; 162 std::size_t result = 0; 163 const char* next1 = first1; 164 while (result < len2 && next1 != last1) { 165 while (next1 != last1) { 166 if (st == 0) { 167 if (*next1 < 1 || *next1 > 3) 168 return static_cast<int>(result); // error. 169 st = *next1++; 170 } else if (st == 1) { 171 ++result; 172 st = 0; 173 break; 174 } else { 175 if (*next1++ != 0) 176 return static_cast<int>(result); // error. 177 --st; 178 } 179 } 180 } 181 return static_cast<int>(result); 182 } 183 }; 184 185 //------------------Definition of stateless_null_padded_codevt----------------// 186 187 class stateless_null_padded_codecvt 188 : public std::codecvt<wchar_t, char, std::mbstate_t> 189 { 190 std::codecvt_base::result do_in(state_type &,const char * first1,const char * last1,const char * & next1,wchar_t * first2,wchar_t * last2,wchar_t * & next2) const191 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 194 { 195 using namespace std; 196 for ( next1 = first1, next2 = first2; 197 next1 != last1 && next2 != last2; ) 198 { 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; 204 ++next1; 205 while (len-- > 1) 206 if (*next1++ != 0) 207 return codecvt_base::error; 208 *next2++ = (unsigned char) *next1++; 209 } 210 return next1 == last1 && next2 == last2 ? 211 codecvt_base::ok : 212 codecvt_base::partial; 213 } 214 215 std::codecvt_base::result do_out(state_type &,const wchar_t * first1,const wchar_t * last1,const wchar_t * & next1,char * first2,char * last2,char * & next2) const216 do_out( state_type&, const wchar_t* first1, const wchar_t* last1, 217 const wchar_t*& next1, char* first2, char* last2, 218 char*& next2 ) const 219 { 220 using namespace std; 221 for ( next1 = first1, next2 = first2; 222 next1 != last1 && next2 != last2; ) 223 { 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); 230 while (skip-- > 1) 231 *next2++ = 0; 232 *next2++ = (unsigned char) *next1++; 233 } 234 return codecvt_base::ok; 235 } 236 237 std::codecvt_base::result do_unshift(state_type &,char *,char *,char * &) const238 do_unshift( state_type&, 239 char* /* first2 */, 240 char* /* last2 */, 241 char*& /* next2 */ ) const 242 { 243 return std::codecvt_base::ok; 244 } 245 do_always_noconv() const246 bool do_always_noconv() const throw() { return false; } 247 do_max_length() const248 int do_max_length() const throw() { return 4; } 249 do_encoding() const250 int do_encoding() const throw() { return -1; } 251 do_length(BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type &,const char * first1,const char * last1,std::size_t len2) const252 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) 259 { 260 int len = (unsigned char) *next1; 261 if (len < 1 || len > 3 || last1 - next1 < len + 1) 262 return static_cast<int>(result); // error. 263 ++next1; 264 while (len-- > 1) 265 if (*next1++ != 0) 266 return static_cast<int>(result); // error. 267 ++next1; 268 } 269 return static_cast<int>(result); 270 } 271 }; 272 273 } } } // End namespaces detail, iostreams, boost. 274 275 #endif // #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED 276