276 lines
9.4 KiB
C++
276 lines
9.4 KiB
C++
// (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 <boost/config.hpp> // NO_STDC_NAMESPACE
|
|
#include <boost/iostreams/detail/codecvt_helper.hpp>
|
|
#include <boost/iostreams/detail/config/wide_streams.hpp>
|
|
#include <cstddef> // mbstate_t.
|
|
#include <locale> // codecvt.
|
|
#include <boost/integer_traits.hpp> // 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<unsigned char>::const_max)
|
|
return codecvt_base::noconv;
|
|
state = *next1 % 3 + 1;
|
|
*next2++ = static_cast<char>(state);
|
|
} else if (state == 1) {
|
|
state = 0;
|
|
*next2++ = static_cast<unsigned char>(*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<int>(result); // error.
|
|
st = *next1++;
|
|
} else if (st == 1) {
|
|
++result;
|
|
st = 0;
|
|
break;
|
|
} else {
|
|
if (*next1++ != 0)
|
|
return static_cast<int>(result); // error.
|
|
--st;
|
|
}
|
|
}
|
|
}
|
|
return static_cast<int>(result);
|
|
}
|
|
};
|
|
|
|
//------------------Definition of stateless_null_padded_codevt----------------//
|
|
|
|
class stateless_null_padded_codecvt
|
|
: public std::codecvt<wchar_t, char, std::mbstate_t>
|
|
{
|
|
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<unsigned char>::const_max)
|
|
return codecvt_base::noconv;
|
|
int skip = *next1 % 3 + 2;
|
|
if (last2 - next2 < skip)
|
|
return codecvt_base::partial;
|
|
*next2++ = static_cast<char>(--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<int>(result); // error.
|
|
++next1;
|
|
while (len-- > 1)
|
|
if (*next1++ != 0)
|
|
return static_cast<int>(result); // error.
|
|
++next1;
|
|
}
|
|
return static_cast<int>(result);
|
|
}
|
|
};
|
|
|
|
} } } // End namespaces detail, iostreams, boost.
|
|
|
|
#endif // #ifndef BOOST_IOSTREAMS_TEST_NULL_PADDED_CODECVT_HPP_INCLUDED
|