| // |
| // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) |
| // |
| // 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) |
| // |
| #ifndef BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP |
| #define BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP |
| |
| #include <boost/locale/encoding.hpp> |
| #include "../util/iconv.hpp" |
| #include <errno.h> |
| #include "conv.hpp" |
| #include <assert.h> |
| #include <vector> |
| |
| namespace boost { |
| namespace locale { |
| namespace conv { |
| namespace impl { |
| |
| class iconverter_base { |
| public: |
| |
| iconverter_base() : |
| cvt_((iconv_t)(-1)) |
| { |
| } |
| |
| virtual ~iconverter_base() |
| { |
| close(); |
| } |
| |
| size_t conv(char const **inbufc,size_t *inchar_left, |
| char **outbuf,size_t *outchar_left) |
| { |
| char **inbuf = const_cast<char **>(inbufc); |
| return call_iconv(cvt_,inbuf,inchar_left,outbuf,outchar_left); |
| } |
| |
| bool open(char const *to,char const *from,method_type how) |
| { |
| close(); |
| cvt_ = iconv_open(to,from); |
| how_ = how; |
| return cvt_ != (iconv_t)(-1); |
| } |
| |
| template<typename OutChar,typename InChar> |
| std::basic_string<OutChar> real_convert(InChar const *ubegin,InChar const *uend) |
| { |
| std::basic_string<OutChar> sresult; |
| |
| sresult.reserve(uend - ubegin); |
| |
| OutChar result[64]; |
| |
| char *out_start = reinterpret_cast<char *>(&result[0]); |
| char const *begin = reinterpret_cast<char const *>(ubegin); |
| char const *end = reinterpret_cast<char const *>(uend); |
| |
| enum { normal , unshifting , done } state = normal; |
| |
| while(state!=done) { |
| |
| size_t in_left = end - begin; |
| size_t out_left = sizeof(result); |
| |
| char *out_ptr = out_start; |
| size_t res = 0; |
| if(in_left == 0) |
| state = unshifting; |
| |
| if(state == normal) |
| res = conv(&begin,&in_left,&out_ptr,&out_left); |
| else |
| res = conv(0,0,&out_ptr,&out_left); |
| |
| int err = errno; |
| |
| size_t output_count = (out_ptr - out_start) / sizeof(OutChar); |
| |
| sresult.append(&result[0],output_count); |
| |
| if(res == (size_t)(-1)) { |
| if(err == EILSEQ || err == EINVAL) { |
| if(how_ == stop) { |
| throw conversion_error(); |
| } |
| |
| if(begin != end) { |
| begin+=sizeof(InChar); |
| if(begin >= end) |
| break; |
| } |
| else { |
| break; |
| } |
| } |
| else if (err==E2BIG) { |
| continue; |
| } |
| else { |
| // We should never get there |
| // but if we do |
| if(how_ == stop) |
| throw conversion_error(); |
| else |
| break; |
| } |
| } |
| if(state == unshifting) |
| state = done; |
| } |
| return sresult; |
| } |
| |
| |
| private: |
| |
| void close() |
| { |
| if(cvt_!=(iconv_t)(-1)) { |
| iconv_close(cvt_); |
| cvt_ = (iconv_t)(-1); |
| } |
| } |
| |
| iconv_t cvt_; |
| |
| method_type how_; |
| |
| }; |
| |
| template<typename CharType> |
| class iconv_from_utf : public iconverter_base, public converter_from_utf<CharType> |
| { |
| public: |
| |
| typedef CharType char_type; |
| |
| virtual bool open(char const *charset,method_type how) |
| { |
| return iconverter_base::open(charset,utf_name<CharType>(),how); |
| } |
| |
| virtual std::string convert(char_type const *ubegin,char_type const *uend) |
| { |
| return real_convert<char,char_type>(ubegin,uend); |
| } |
| }; |
| |
| class iconv_between: public iconverter_base, public converter_between |
| { |
| public: |
| virtual bool open(char const *to_charset,char const *from_charset,method_type how) |
| { |
| return iconverter_base::open(to_charset,from_charset,how); |
| } |
| virtual std::string convert(char const *begin,char const *end) |
| { |
| return real_convert<char,char>(begin,end); |
| } |
| |
| }; |
| |
| |
| template<typename CharType> |
| class iconv_to_utf : public iconverter_base, public converter_to_utf<CharType> |
| { |
| public: |
| |
| typedef CharType char_type; |
| typedef std::basic_string<char_type> string_type; |
| |
| virtual bool open(char const *charset,method_type how) |
| { |
| return iconverter_base::open(utf_name<CharType>(),charset,how); |
| } |
| |
| virtual string_type convert(char const *begin,char const *end) |
| { |
| return real_convert<char_type,char>(begin,end); |
| } |
| }; |
| |
| |
| |
| |
| } // impl |
| } // conv |
| } // locale |
| } // boost |
| |
| |
| |
| |
| #endif |
| // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 |