1 //
2 //  Copyright (c) 2015 Artyom Beilis (Tonkikh)
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_LOCALE_GENERIC_CODECVT_HPP
9 #define BOOST_LOCALE_GENERIC_CODECVT_HPP
10 
11 #include <boost/locale/utf.hpp>
12 #include <boost/cstdint.hpp>
13 #include <boost/static_assert.hpp>
14 #include <locale>
15 
16 namespace boost {
17 namespace locale {
18 
19 #ifndef BOOST_LOCALE_DOXYGEN
20 //
21 // Make sure that mbstate can keep 16 bit of UTF-16 sequence
22 //
23 BOOST_STATIC_ASSERT(sizeof(std::mbstate_t)>=2);
24 #endif
25 
26 #if defined(_MSC_VER) && _MSC_VER < 1700
27 // up to MSVC 11 (2012) do_length is non-standard it counts wide characters instead of narrow and does not change mbstate
28 #define BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
29 #endif
30 
31 ///
32 /// \brief A base class that used to define constants for generic_codecvt
33 ///
34 class generic_codecvt_base {
35 public:
36     ///
37     /// Initail state for converting to or from unicode code points, used by initial_state in derived classes
38     ///
39     enum initial_convertion_state {
40         to_unicode_state, ///< The state would be used by to_unicode functions
41         from_unicode_state ///< The state would be used by from_unicode functions
42     };
43 };
44 
45 ///
46 /// \brief Geneneric generic codecvt facet, various stateless encodings to UTF-16 and UTF-32 using wchar_t, char32_t and char16_t
47 ///
48 /// Implementations should dervide from this class defining itself as CodecvtImpl and provide following members
49 ///
50 /// - `state_type` - a type of special object that allows to store intermediate cached data, for example `iconv_t` descriptor
51 /// - `state_type initial_state(generic_codecvt_base::initial_convertion_state direction) const` - member function that creates initial state
52 /// - `int max_encoding_length() const` - a maximal length that one Unicode code point is represented, for UTF-8 for example it is 4 from ISO-8859-1 it is 1
53 /// - `utf::code_point to_unicode(state_type &state,char const *&begin,char const *end)` - extract first code point from the text in range [begin,end), in case of success begin would point to the next character sequence to be encoded to next code point, in case of incomplete sequence - utf::incomplete shell be returned, and in case of invalid input sequence utf::illegal shell be returned and begin would remain unmodified
54 /// - `utf::code_point from_unicode(state_type &state,utf::code_point u,char *begin,char const *end)` - convert a unicode code point `u` into a character seqnece at [begin,end). Return the length of the sequence in case of success, utf::incomplete in case of not enough room to encode the code point of utf::illegal in case conversion can not be performed
55 ///
56 ///
57 /// For example implementaion of codecvt for latin1/ISO-8859-1 character set
58 ///
59 /// \code
60 ///
61 /// template<typename CharType>
62 /// class latin1_codecvt :boost::locale::generic_codecvt<CharType,latin1_codecvt<CharType> >
63 /// {
64 /// public:
65 ///
66 ///     /* Standard codecvt constructor */
67 ///     latin1_codecvt(size_t refs = 0) : boost::locale::generic_codecvt<CharType,latin1_codecvt<CharType> >(refs)
68 ///     {
69 ///     }
70 ///
71 ///     /* State is unused but required by generic_codecvt */
72 ///     struct state_type {};
73 ///
74 ///     state_type initial_state(generic_codecvt_base::initial_convertion_state /*unused*/) const
75 ///     {
76 ///         return state_type();
77 ///     }
78 ///
79 ///     int max_encoding_length() const
80 ///     {
81 ///         return 1;
82 ///     }
83 ///
84 ///     boost::locale::utf::code_point to_unicode(state_type &,char const *&begin,char const *end) const
85 ///     {
86 ///        if(begin == end)
87 ///           return boost::locale::utf::incomplete;
88 ///        return *begin++;
89 ///     }
90 ///
91 ///     boost::locale::utf::code_point from_unicode(state_type &,boost::locale::utf::code_point u,char *begin,char const *end) const
92 ///     {
93 ///        if(u >= 256)
94 ///           return boost::locale::utf::illegal;
95 ///        if(begin == end)
96 ///           return boost::locale::utf::incomplete;
97 ///        *begin = u;
98 ///        return 1;
99 ///     }
100 /// };
101 ///
102 /// \endcode
103 ///
104 /// When external tools used for encoding conversion, the `state_type` is useful to save objects used for conversions. For example,
105 /// icu::UConverter can be saved in such a state for an efficient use:
106 ///
107 /// \code
108 /// template<typename CharType>
109 /// class icu_codecvt :boost::locale::generic_codecvt<CharType,icu_codecvt<CharType> >
110 /// {
111 /// public:
112 ///
113 ///     /* Standard codecvt constructor */
114 ///     icu_codecvt(std::string const &name,refs = 0) :
115 ///         boost::locale::generic_codecvt<CharType,latin1_codecvt<CharType> >(refs)
116 ///     { ... }
117 ///
118 ///     /* State is unused but required by generic_codecvt */
119 ///     struct std::unique_ptr<UConverter,void (*)(UConverter*)> state_type;
120 ///
121 ///     state_type &&initial_state(generic_codecvt_base::initial_convertion_state /*unused*/) const
122 ///     {
123 ///         UErrorCode err = U_ZERO_ERROR;
124 ///         state_type ptr(ucnv_safeClone(converter_,0,0,&err,ucnv_close);
125 ///         return std::move(ptr);
126 ///     }
127 ///
128 ///     boost::locale::utf::code_point to_unicode(state_type &ptr,char const *&begin,char const *end) const
129 ///     {
130 ///         UErrorCode err = U_ZERO_ERROR;
131 ///         boost::locale::utf::code_point cp = ucnv_getNextUChar(ptr.get(),&begin,end,&err);
132 ///         ...
133 ///     }
134 ///     ...
135 /// };
136 /// \endcode
137 ///
138 ///
139 template<typename CharType,typename CodecvtImpl,int CharSize=sizeof(CharType)>
140 class generic_codecvt;
141 
142 ///
143 /// \brief UTF-16 to/from UTF-8 codecvt facet to use with char16_t or wchar_t on Windows
144 ///
145 /// Note in order to fit the requirements of usability by std::wfstream it uses mbstate_t
146 /// to handle intermediate states in handling of variable length UTF-16 sequences
147 ///
148 /// Its member functions implement standard virtual functions of basic codecvt
149 ///
150 template<typename CharType,typename CodecvtImpl>
151 class generic_codecvt<CharType,CodecvtImpl,2> : public std::codecvt<CharType,char,std::mbstate_t>, public generic_codecvt_base
152 {
153 public:
154 
155     typedef CharType uchar;
156 
generic_codecvt(size_t refs=0)157     generic_codecvt(size_t refs = 0) :
158         std::codecvt<CharType,char,std::mbstate_t>(refs)
159     {
160     }
implementation() const161     CodecvtImpl const &implementation() const
162     {
163         return *static_cast<CodecvtImpl const *>(this);
164     }
165 
166 protected:
167 
168 
do_unshift(std::mbstate_t & s,char * from,char *,char * & next) const169     virtual std::codecvt_base::result do_unshift(std::mbstate_t &s,char *from,char * /*to*/,char *&next) const
170     {
171         boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&s);
172 #ifdef DEBUG_CODECVT
173         std::cout << "Entering unshift " << std::hex << state << std::dec << std::endl;
174 #endif
175         if(state != 0)
176             return std::codecvt_base::error;
177         next=from;
178         return std::codecvt_base::ok;
179     }
do_encoding() const180     virtual int do_encoding() const throw()
181     {
182         return 0;
183     }
do_max_length() const184     virtual int do_max_length() const throw()
185     {
186         return implementation().max_encoding_length();
187     }
do_always_noconv() const188     virtual bool do_always_noconv() const throw()
189     {
190         return false;
191     }
192 
193     virtual int
do_length(std::mbstate_t const & std_state,char const * from,char const * from_end,size_t max) const194     do_length(  std::mbstate_t
195     #ifdef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
196             const
197     #endif
198             &std_state,
199             char const *from,
200             char const *from_end,
201             size_t max) const
202     {
203         #ifndef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
204         char const *save_from = from;
205         boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
206         #else
207         size_t save_max = max;
208         boost::uint16_t state = *reinterpret_cast<boost::uint16_t const *>(&std_state);
209         #endif
210 
211         typedef typename CodecvtImpl::state_type state_type;
212         state_type cvt_state = implementation().initial_state(generic_codecvt_base::to_unicode_state);
213         while(max > 0 && from < from_end){
214             char const *prev_from = from;
215             boost::uint32_t ch=implementation().to_unicode(cvt_state,from,from_end);
216             if(ch==boost::locale::utf::incomplete || ch==boost::locale::utf::illegal) {
217                 from = prev_from;
218                 break;
219             }
220             max --;
221             if(ch > 0xFFFF) {
222                 if(state == 0) {
223                     from = prev_from;
224                     state = 1;
225                 }
226                 else {
227                     state = 0;
228                 }
229             }
230         }
231         #ifndef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
232         return from - save_from;
233         #else
234         return save_max - max;
235         #endif
236     }
237 
238 
239     virtual std::codecvt_base::result
do_in(std::mbstate_t & std_state,char const * from,char const * from_end,char const * & from_next,uchar * to,uchar * to_end,uchar * & to_next) const240     do_in(  std::mbstate_t &std_state,
241             char const *from,
242             char const *from_end,
243             char const *&from_next,
244             uchar *to,
245             uchar *to_end,
246             uchar *&to_next) const
247     {
248         std::codecvt_base::result r=std::codecvt_base::ok;
249 
250         // mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
251         // according to standard. We use it to keep a flag 0/1 for surrogate pair writing
252         //
253         // if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
254         // and first pair is written, but no input consumed
255         boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
256         typedef typename CodecvtImpl::state_type state_type;
257         state_type cvt_state = implementation().initial_state(generic_codecvt_base::to_unicode_state);
258         while(to < to_end && from < from_end)
259         {
260 #ifdef DEBUG_CODECVT
261             std::cout << "Entering IN--------------" << std::endl;
262             std::cout << "State " << std::hex << state <<std::endl;
263             std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
264 #endif
265             char const *from_saved = from;
266 
267             uint32_t ch=implementation().to_unicode(cvt_state,from,from_end);
268 
269             if(ch==boost::locale::utf::illegal) {
270                 from = from_saved;
271                 r=std::codecvt_base::error;
272                 break;
273             }
274             if(ch==boost::locale::utf::incomplete) {
275                 from = from_saved;
276                 r=std::codecvt_base::partial;
277                 break;
278             }
279             // Normal codepoints go direcly to stream
280             if(ch <= 0xFFFF) {
281                 *to++=ch;
282             }
283             else {
284                 // for  other codepoints we do following
285                 //
286                 // 1. We can't consume our input as we may find ourselfs
287                 //    in state where all input consumed but not all output written,i.e. only
288                 //    1st pair is written
289                 // 2. We only write first pair and mark this in the state, we also revert back
290                 //    the from pointer in order to make sure this codepoint would be read
291                 //    once again and then we would consume our input together with writing
292                 //    second surrogate pair
293                 ch-=0x10000;
294                 boost::uint16_t vh = ch >> 10;
295                 boost::uint16_t vl = ch & 0x3FF;
296                 boost::uint16_t w1 = vh + 0xD800;
297                 boost::uint16_t w2 = vl + 0xDC00;
298                 if(state == 0) {
299                     from = from_saved;
300                     *to++ = w1;
301                     state = 1;
302                 }
303                 else {
304                     *to++ = w2;
305                     state = 0;
306                 }
307             }
308         }
309         from_next=from;
310         to_next=to;
311         if(r == std::codecvt_base::ok && (from!=from_end || state!=0))
312             r = std::codecvt_base::partial;
313 #ifdef DEBUG_CODECVT
314         std::cout << "Returning ";
315         switch(r) {
316         case std::codecvt_base::ok:
317             std::cout << "ok" << std::endl;
318             break;
319         case std::codecvt_base::partial:
320             std::cout << "partial" << std::endl;
321             break;
322         case std::codecvt_base::error:
323             std::cout << "error" << std::endl;
324             break;
325         default:
326             std::cout << "other" << std::endl;
327             break;
328         }
329         std::cout << "State " << std::hex << state <<std::endl;
330         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
331 #endif
332         return r;
333     }
334 
335     virtual std::codecvt_base::result
do_out(std::mbstate_t & std_state,uchar const * from,uchar const * from_end,uchar const * & from_next,char * to,char * to_end,char * & to_next) const336     do_out( std::mbstate_t &std_state,
337             uchar const *from,
338             uchar const *from_end,
339             uchar const *&from_next,
340             char *to,
341             char *to_end,
342             char *&to_next) const
343     {
344         std::codecvt_base::result r=std::codecvt_base::ok;
345         // mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
346         // according to standard. We assume that sizeof(mbstate_t) >=2 in order
347         // to be able to store first observerd surrogate pair
348         //
349         // State: state!=0 - a first surrogate pair was observerd (state = first pair),
350         // we expect the second one to come and then zero the state
351         ///
352         boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
353         typedef typename CodecvtImpl::state_type state_type;
354         state_type cvt_state = implementation().initial_state(generic_codecvt_base::from_unicode_state);
355         while(to < to_end && from < from_end)
356         {
357 #ifdef DEBUG_CODECVT
358         std::cout << "Entering OUT --------------" << std::endl;
359         std::cout << "State " << std::hex << state <<std::endl;
360         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
361 #endif
362             boost::uint32_t ch=0;
363             if(state != 0) {
364                 // if the state idecates that 1st surrogate pair was written
365                 // we should make sure that the second one that comes is actually
366                 // second surrogate
367                 boost::uint16_t w1 = state;
368                 boost::uint16_t w2 = *from;
369                 // we don't forward from as writing may fail to incomplete or
370                 // partial conversion
371                 if(0xDC00 <= w2 && w2<=0xDFFF) {
372                     boost::uint16_t vh = w1 - 0xD800;
373                     boost::uint16_t vl = w2 - 0xDC00;
374                     ch=((uint32_t(vh) << 10)  | vl) + 0x10000;
375                 }
376                 else {
377                     // Invalid surrogate
378                     r=std::codecvt_base::error;
379                     break;
380                 }
381             }
382             else {
383                 ch = *from;
384                 if(0xD800 <= ch && ch<=0xDBFF) {
385                     // if this is a first surrogate pair we put
386                     // it into the state and consume it, note we don't
387                     // go forward as it should be illegal so we increase
388                     // the from pointer manually
389                     state = ch;
390                     from++;
391                     continue;
392                 }
393                 else if(0xDC00 <= ch && ch<=0xDFFF) {
394                     // if we observe second surrogate pair and
395                     // first only may be expected we should break from the loop with error
396                     // as it is illegal input
397                     r=std::codecvt_base::error;
398                     break;
399                 }
400             }
401             if(!boost::locale::utf::is_valid_codepoint(ch)) {
402                 r=std::codecvt_base::error;
403                 break;
404             }
405             boost::uint32_t len = implementation().from_unicode(cvt_state,ch,to,to_end);
406             if(len == boost::locale::utf::incomplete) {
407                 r=std::codecvt_base::partial;
408                 break;
409             }
410             else if(len == boost::locale::utf::illegal) {
411                 r=std::codecvt_base::error;
412                 break;
413             }
414             else
415                     to+= len;
416             state = 0;
417             from++;
418         }
419         from_next=from;
420         to_next=to;
421         if(r==std::codecvt_base::ok && from!=from_end)
422             r = std::codecvt_base::partial;
423 #ifdef DEBUG_CODECVT
424         std::cout << "Returning ";
425         switch(r) {
426         case std::codecvt_base::ok:
427             std::cout << "ok" << std::endl;
428             break;
429         case std::codecvt_base::partial:
430             std::cout << "partial" << std::endl;
431             break;
432         case std::codecvt_base::error:
433             std::cout << "error" << std::endl;
434             break;
435         default:
436             std::cout << "other" << std::endl;
437             break;
438         }
439         std::cout << "State " << std::hex << state <<std::endl;
440         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
441 #endif
442         return r;
443     }
444 
445 };
446 
447 ///
448 /// \brief UTF-32 to/from UTF-8 codecvt facet to use with char32_t or wchar_t on POSIX platforms
449 ///
450 /// Its member functions implement standard virtual functions of basic codecvt.
451 /// mbstate_t is not used for UTF-32 handling due to fixed length encoding
452 ///
453 template<typename CharType,typename CodecvtImpl>
454 class generic_codecvt<CharType,CodecvtImpl,4> : public std::codecvt<CharType,char,std::mbstate_t>, public generic_codecvt_base
455 {
456 public:
457     typedef CharType uchar;
458 
generic_codecvt(size_t refs=0)459     generic_codecvt(size_t refs = 0) :
460         std::codecvt<CharType,char,std::mbstate_t>(refs)
461     {
462     }
463 
implementation() const464     CodecvtImpl const &implementation() const
465     {
466         return *static_cast<CodecvtImpl const *>(this);
467     }
468 
469 protected:
470 
do_unshift(std::mbstate_t &,char * from,char *,char * & next) const471     virtual std::codecvt_base::result do_unshift(std::mbstate_t &/*s*/,char *from,char * /*to*/,char *&next) const
472     {
473         next=from;
474         return std::codecvt_base::ok;
475     }
do_encoding() const476     virtual int do_encoding() const throw()
477     {
478         return 0;
479     }
do_max_length() const480     virtual int do_max_length() const throw()
481     {
482         return implementation().max_encoding_length();
483     }
do_always_noconv() const484     virtual bool do_always_noconv() const throw()
485     {
486         return false;
487     }
488 
489     virtual int
do_length(std::mbstate_t const &,char const * from,char const * from_end,size_t max) const490     do_length(  std::mbstate_t
491     #ifdef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
492             const
493     #endif
494             &/*state*/,
495             char const *from,
496             char const *from_end,
497             size_t max) const
498     {
499         #ifndef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
500         char const *start_from = from;
501         #else
502         size_t save_max = max;
503         #endif
504         typedef typename CodecvtImpl::state_type state_type;
505         state_type cvt_state = implementation().initial_state(generic_codecvt_base::to_unicode_state);
506         while(max > 0 && from < from_end){
507             char const *save_from = from;
508             boost::uint32_t ch=implementation().to_unicode(cvt_state,from,from_end);
509             if(ch==boost::locale::utf::incomplete || ch==boost::locale::utf::illegal) {
510                 from = save_from;
511                 break;
512             }
513             max--;
514         }
515         #ifndef BOOST_LOCALE_DO_LENGTH_MBSTATE_CONST
516         return from - start_from;
517         #else
518         return save_max - max;
519         #endif
520     }
521 
522 
523     virtual std::codecvt_base::result
do_in(std::mbstate_t &,char const * from,char const * from_end,char const * & from_next,uchar * to,uchar * to_end,uchar * & to_next) const524     do_in(  std::mbstate_t &/*state*/,
525             char const *from,
526             char const *from_end,
527             char const *&from_next,
528             uchar *to,
529             uchar *to_end,
530             uchar *&to_next) const
531     {
532         std::codecvt_base::result r=std::codecvt_base::ok;
533 
534         // mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
535         // according to standard. We use it to keep a flag 0/1 for surrogate pair writing
536         //
537         // if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
538         // and first pair is written, but no input consumed
539         typedef typename CodecvtImpl::state_type state_type;
540         state_type cvt_state = implementation().initial_state(generic_codecvt_base::to_unicode_state);
541         while(to < to_end && from < from_end)
542         {
543 #ifdef DEBUG_CODECVT
544             std::cout << "Entering IN--------------" << std::endl;
545             std::cout << "State " << std::hex << state <<std::endl;
546             std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
547 #endif
548             char const *from_saved = from;
549 
550             uint32_t ch=implementation().to_unicode(cvt_state,from,from_end);
551 
552             if(ch==boost::locale::utf::illegal) {
553                 r=std::codecvt_base::error;
554                 from = from_saved;
555                 break;
556             }
557             if(ch==boost::locale::utf::incomplete) {
558                 r=std::codecvt_base::partial;
559                 from=from_saved;
560                 break;
561             }
562             *to++=ch;
563         }
564         from_next=from;
565         to_next=to;
566         if(r == std::codecvt_base::ok && from!=from_end)
567             r = std::codecvt_base::partial;
568 #ifdef DEBUG_CODECVT
569         std::cout << "Returning ";
570         switch(r) {
571         case std::codecvt_base::ok:
572             std::cout << "ok" << std::endl;
573             break;
574         case std::codecvt_base::partial:
575             std::cout << "partial" << std::endl;
576             break;
577         case std::codecvt_base::error:
578             std::cout << "error" << std::endl;
579             break;
580         default:
581             std::cout << "other" << std::endl;
582             break;
583         }
584         std::cout << "State " << std::hex << state <<std::endl;
585         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
586 #endif
587         return r;
588     }
589 
590     virtual std::codecvt_base::result
do_out(std::mbstate_t &,uchar const * from,uchar const * from_end,uchar const * & from_next,char * to,char * to_end,char * & to_next) const591     do_out( std::mbstate_t &/*std_state*/,
592             uchar const *from,
593             uchar const *from_end,
594             uchar const *&from_next,
595             char *to,
596             char *to_end,
597             char *&to_next) const
598     {
599         std::codecvt_base::result r=std::codecvt_base::ok;
600         typedef typename CodecvtImpl::state_type state_type;
601         state_type cvt_state = implementation().initial_state(generic_codecvt_base::from_unicode_state);
602         while(to < to_end && from < from_end)
603         {
604 #ifdef DEBUG_CODECVT
605         std::cout << "Entering OUT --------------" << std::endl;
606         std::cout << "State " << std::hex << state <<std::endl;
607         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
608 #endif
609             boost::uint32_t ch=0;
610             ch = *from;
611             if(!boost::locale::utf::is_valid_codepoint(ch)) {
612                 r=std::codecvt_base::error;
613                 break;
614             }
615             boost::uint32_t len = implementation().from_unicode(cvt_state,ch,to,to_end);
616             if(len == boost::locale::utf::incomplete) {
617                 r=std::codecvt_base::partial;
618                 break;
619             }
620             else if(len == boost::locale::utf::illegal) {
621                 r=std::codecvt_base::error;
622                 break;
623             }
624             to+=len;
625             from++;
626         }
627         from_next=from;
628         to_next=to;
629         if(r==std::codecvt_base::ok && from!=from_end)
630             r = std::codecvt_base::partial;
631 #ifdef DEBUG_CODECVT
632         std::cout << "Returning ";
633         switch(r) {
634         case std::codecvt_base::ok:
635             std::cout << "ok" << std::endl;
636             break;
637         case std::codecvt_base::partial:
638             std::cout << "partial" << std::endl;
639             break;
640         case std::codecvt_base::error:
641             std::cout << "error" << std::endl;
642             break;
643         default:
644             std::cout << "other" << std::endl;
645             break;
646         }
647         std::cout << "State " << std::hex << state <<std::endl;
648         std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
649 #endif
650         return r;
651     }
652 };
653 
654 
655 template<typename CharType,typename CodecvtImpl>
656 class generic_codecvt<CharType,CodecvtImpl,1> : public std::codecvt<CharType,char,std::mbstate_t>, public generic_codecvt_base
657 {
658 public:
659     typedef CharType uchar;
660 
implementation() const661     CodecvtImpl const &implementation() const
662     {
663         return *static_cast<CodecvtImpl const *>(this);
664     }
665 
generic_codecvt(size_t refs=0)666     generic_codecvt(size_t refs = 0) :  std::codecvt<char,char,std::mbstate_t>(refs)
667     {
668     }
669 };
670 
671 } // locale
672 } // namespace boost
673 
674 #endif
675 ///
676 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
677