• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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