// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) // (C) Copyright 2004-2007 Jonathan Turkanis // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) // See http://www.boost.org/libs/iostreams for documentation. // Contains the definitions of two codecvt facets useful for testing code // conversion. Both represent the "null padded" character encoding described as // follows. A wide character can be represented by the encoding if its value V // is within the range of an unsigned char. The first char of the sequence // representing V is V % 3 + 1. This is followed by V % 3 null characters, and // finally by V itself. // The first codecvt facet, null_padded_codecvt, is statefull, with state_type // equal to int. // The second codecvt facet, stateless_null_padded_codecvt, is stateless. At // each point in a conversion, no characters are consumed unless there is room // in the output sequence to write an entire multibyte sequence. #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED #define BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED #include // NO_STDC_NAMESPACE #include #include #include // mbstate_t. #include // codecvt. #include // const_max. #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::mbstate_t; } #endif namespace boost { namespace iostreams { namespace test { //------------------Definition of null_padded_codecvt_state-------------------// class null_padded_codecvt_state { public: null_padded_codecvt_state(int val = 0) : val_(val) { } operator int() const { return val_; } int& val() { return val_; } const int& val() const { return val_; } private: int val_; }; } } } BOOST_IOSTREAMS_CODECVT_SPEC(boost::iostreams::test::null_padded_codecvt_state) namespace boost { namespace iostreams { namespace test { //------------------Definition of null_padded_codevt--------------------------// // // state is initially 0. After a single character is consumed, state is set to // the number of characters in the current multibyte sequence and decremented // as each character is consumed until its value reaches 0 again. // class null_padded_codecvt : public iostreams::detail::codecvt_helper< wchar_t, char, null_padded_codecvt_state > { public: typedef null_padded_codecvt_state state_type; private: 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 ) const { using namespace std; if (state < 0 || state > 3) return codecvt_base::error; next1 = first1; next2 = first2; while (next2 != last2 && next1 != last1) { while (next1 != last1) { if (state == 0) { if (*next1 < 1 || *next1 > 3) return codecvt_base::error; state = *next1++; } else if (state == 1) { *next2++ = (unsigned char) *next1++; state = 0; break; } else { if (*next1++ != 0) return codecvt_base::error; --state.val(); } } } return next2 == last2 ? codecvt_base::ok : codecvt_base::partial; } 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 ) const { using namespace std; if (state < 0 || state > 3) return codecvt_base::error; next1 = first1; next2 = first2; while (next1 != last1 && next2 != last2) { while (next2 != last2) { if (state == 0) { if (*next1 > integer_traits::const_max) return codecvt_base::noconv; state = *next1 % 3 + 1; *next2++ = static_cast(state); } else if (state == 1) { state = 0; *next2++ = static_cast(*next1++); break; } else { --state.val(); *next2++ = 0; } } } return next1 == last1 ? codecvt_base::ok : codecvt_base::partial; } std::codecvt_base::result do_unshift( state_type& state, char* /* first2 */, char* last2, char*& next2 ) const { using namespace std; next2 = last2; while (state.val()-- > 0) if (next2 != last2) *next2++ = 0; else return codecvt_base::partial; return codecvt_base::ok; } bool do_always_noconv() const throw() { return false; } int do_max_length() const throw() { return 4; } int do_encoding() const throw() { return -1; } int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type& state, const char* first1, const char* last1, std::size_t len2 ) const throw() { // Implementation should follow that of do_in(). int st = state; std::size_t result = 0; const char* next1 = first1; while (result < len2 && next1 != last1) { while (next1 != last1) { if (st == 0) { if (*next1 < 1 || *next1 > 3) return static_cast(result); // error. st = *next1++; } else if (st == 1) { ++result; st = 0; break; } else { if (*next1++ != 0) return static_cast(result); // error. --st; } } } return static_cast(result); } }; //------------------Definition of stateless_null_padded_codevt----------------// class stateless_null_padded_codecvt : public std::codecvt { 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 ) const { using namespace std; for ( next1 = first1, next2 = first2; next1 != last1 && next2 != last2; ) { int len = (unsigned char) *next1; if (len < 1 || len > 3) return codecvt_base::error; if (last1 - next1 < len + 1) return codecvt_base::partial; ++next1; while (len-- > 1) if (*next1++ != 0) return codecvt_base::error; *next2++ = (unsigned char) *next1++; } return next1 == last1 && next2 == last2 ? codecvt_base::ok : codecvt_base::partial; } 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 ) const { using namespace std; for ( next1 = first1, next2 = first2; next1 != last1 && next2 != last2; ) { if (*next1 > integer_traits::const_max) return codecvt_base::noconv; int skip = *next1 % 3 + 2; if (last2 - next2 < skip) return codecvt_base::partial; *next2++ = static_cast(--skip); while (skip-- > 1) *next2++ = 0; *next2++ = (unsigned char) *next1++; } return codecvt_base::ok; } std::codecvt_base::result do_unshift( state_type&, char* /* first2 */, char* /* last2 */, char*& /* next2 */ ) const { return std::codecvt_base::ok; } bool do_always_noconv() const throw() { return false; } int do_max_length() const throw() { return 4; } int do_encoding() const throw() { return -1; } int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER state_type&, const char* first1, const char* last1, std::size_t len2 ) const throw() { // Implementation should follow that of do_in(). std::size_t result = 0; for ( const char* next1 = first1; next1 != last1 && result < len2; ++result) { int len = (unsigned char) *next1; if (len < 1 || len > 3 || last1 - next1 < len + 1) return static_cast(result); // error. ++next1; while (len-- > 1) if (*next1++ != 0) return static_cast(result); // error. ++next1; } return static_cast(result); } }; } } } // End namespaces detail, iostreams, boost. #endif // #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED