| // |
| // 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) |
| // |
| #define BOOST_LOCALE_SOURCE |
| #include <boost/locale/encoding.hpp> |
| #include "../encoding/conv.hpp" |
| #include "all_generator.hpp" |
| #include "uconv.hpp" |
| #include <unicode/ucnv.h> |
| #include <unicode/ucnv_err.h> |
| #include <boost/locale/util.hpp> |
| #include "codecvt.hpp" |
| |
| #ifdef BOOST_MSVC |
| # pragma warning(disable : 4244) // loose data |
| #endif |
| |
| #include "icu_util.hpp" |
| #include <vector> |
| namespace boost { |
| namespace locale { |
| namespace impl_icu { |
| class uconv_converter : public util::base_converter { |
| public: |
| |
| uconv_converter(std::string const &encoding) : |
| encoding_(encoding) |
| { |
| UErrorCode err=U_ZERO_ERROR; |
| |
| // No need to check err each time, this |
| // is how ICU works. |
| cvt_ = ucnv_open(encoding.c_str(),&err); |
| ucnv_setFromUCallBack(cvt_,UCNV_FROM_U_CALLBACK_STOP,0,0,0,&err); |
| ucnv_setToUCallBack(cvt_,UCNV_TO_U_CALLBACK_STOP,0,0,0,&err); |
| |
| if(!cvt_ || U_FAILURE(err)) { |
| if(cvt_) |
| ucnv_close(cvt_); |
| throw conv::invalid_charset_error(encoding); |
| } |
| |
| max_len_ = ucnv_getMaxCharSize(cvt_); |
| } |
| |
| virtual ~uconv_converter() |
| { |
| ucnv_close(cvt_); |
| } |
| |
| virtual bool is_thread_safe() const |
| { |
| return false; |
| } |
| |
| virtual uconv_converter *clone() const |
| { |
| return new uconv_converter(encoding_); |
| } |
| |
| uint32_t to_unicode(char const *&begin,char const *end) |
| { |
| UErrorCode err=U_ZERO_ERROR; |
| char const *tmp = begin; |
| UChar32 c=ucnv_getNextUChar(cvt_,&tmp,end,&err); |
| ucnv_reset(cvt_); |
| if(err == U_TRUNCATED_CHAR_FOUND) { |
| return incomplete; |
| } |
| if(U_FAILURE(err)) { |
| return illegal; |
| } |
| |
| begin = tmp; |
| return c; |
| } |
| |
| uint32_t from_unicode(uint32_t u,char *begin,char const *end) |
| { |
| UChar code_point[2]={0}; |
| int len; |
| if(u<=0xFFFF) { |
| if(0xD800 <=u && u<= 0xDFFF) // No surragates |
| return illegal; |
| code_point[0]=u; |
| len=1; |
| } |
| else { |
| u-=0x10000; |
| code_point[0]=0xD800 | (u>>10); |
| code_point[1]=0xDC00 | (u & 0x3FF); |
| len=2; |
| } |
| UErrorCode err=U_ZERO_ERROR; |
| int olen = ucnv_fromUChars(cvt_,begin,end-begin,code_point,len,&err); |
| ucnv_reset(cvt_); |
| if(err == U_BUFFER_OVERFLOW_ERROR) |
| return incomplete; |
| if(U_FAILURE(err)) |
| return illegal; |
| return olen; |
| } |
| |
| virtual int max_len() const |
| { |
| return max_len_; |
| } |
| |
| private: |
| std::string encoding_; |
| UConverter *cvt_; |
| int max_len_; |
| }; |
| |
| std::auto_ptr<util::base_converter> create_uconv_converter(std::string const &encoding) |
| { |
| std::auto_ptr<util::base_converter> cvt; |
| try { |
| cvt.reset(new uconv_converter(encoding)); |
| } |
| catch(std::exception const &/*e*/) |
| { |
| // no encoding so we return empty pointer |
| } |
| return cvt; |
| } |
| |
| std::locale create_codecvt(std::locale const &in,std::string const &encoding,character_facet_type type) |
| { |
| std::auto_ptr<util::base_converter> cvt; |
| if(conv::impl::normalize_encoding(encoding.c_str())=="utf8") |
| cvt = util::create_utf8_converter(); |
| else { |
| cvt = util::create_simple_converter(encoding); |
| if(!cvt.get()) { |
| try { |
| cvt = create_uconv_converter(encoding); |
| } |
| catch(std::exception const &/*e*/) |
| { |
| // not too much we can do |
| } |
| } |
| } |
| return util::create_codecvt(in,cvt,type); |
| } |
| |
| } // impl_icu |
| } // locale |
| } // boost |
| |
| // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 |