1// 2// Copyright (c) 2009-2011 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_IMPL_ICONV_CODEPAGE_HPP 9#define BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP 10 11#include <boost/locale/encoding.hpp> 12#include "../util/iconv.hpp" 13#include <errno.h> 14#include "conv.hpp" 15#include <assert.h> 16#include <vector> 17 18namespace boost { 19namespace locale { 20namespace conv { 21namespace impl { 22 23class iconverter_base { 24public: 25 26 iconverter_base() : 27 cvt_((iconv_t)(-1)) 28 { 29 } 30 31 ~iconverter_base() 32 { 33 close(); 34 } 35 36 size_t conv(char const **inbufc,size_t *inchar_left, 37 char **outbuf,size_t *outchar_left) 38 { 39 char **inbuf = const_cast<char **>(inbufc); 40 return call_iconv(cvt_,inbuf,inchar_left,outbuf,outchar_left); 41 } 42 43 bool do_open(char const *to,char const *from,method_type how) 44 { 45 close(); 46 cvt_ = iconv_open(to,from); 47 how_ = how; 48 return cvt_ != (iconv_t)(-1); 49 } 50 51 template<typename OutChar,typename InChar> 52 std::basic_string<OutChar> real_convert(InChar const *ubegin,InChar const *uend) 53 { 54 std::basic_string<OutChar> sresult; 55 56 sresult.reserve(uend - ubegin); 57 58 OutChar result[64]; 59 60 char *out_start = reinterpret_cast<char *>(&result[0]); 61 char const *begin = reinterpret_cast<char const *>(ubegin); 62 char const *end = reinterpret_cast<char const *>(uend); 63 64 enum { normal , unshifting , done } state = normal; 65 66 while(state!=done) { 67 68 size_t in_left = end - begin; 69 size_t out_left = sizeof(result); 70 71 char *out_ptr = out_start; 72 size_t res = 0; 73 if(in_left == 0) 74 state = unshifting; 75 76 if(state == normal) 77 res = conv(&begin,&in_left,&out_ptr,&out_left); 78 else 79 res = conv(0,0,&out_ptr,&out_left); 80 81 int err = errno; 82 83 size_t output_count = (out_ptr - out_start) / sizeof(OutChar); 84 85 if(res!=0 && res!=(size_t)(-1)) { 86 if(how_ == stop) { 87 throw conversion_error(); 88 } 89 } 90 91 sresult.append(&result[0],output_count); 92 93 if(res == (size_t)(-1)) { 94 if(err == EILSEQ || err == EINVAL) { 95 if(how_ == stop) { 96 throw conversion_error(); 97 } 98 99 if(begin != end) { 100 begin+=sizeof(InChar); 101 if(begin >= end) 102 break; 103 } 104 else { 105 break; 106 } 107 } 108 else if (err==E2BIG) { 109 continue; 110 } 111 else { 112 // We should never get there 113 // but if we do 114 if(how_ == stop) 115 throw conversion_error(); 116 else 117 break; 118 } 119 } 120 if(state == unshifting) 121 state = done; 122 } 123 return sresult; 124 } 125 126 127private: 128 129 void close() 130 { 131 if(cvt_!=(iconv_t)(-1)) { 132 iconv_close(cvt_); 133 cvt_ = (iconv_t)(-1); 134 } 135 } 136 137 iconv_t cvt_; 138 139 method_type how_; 140 141}; 142 143template<typename CharType> 144class iconv_from_utf : public converter_from_utf<CharType> 145{ 146public: 147 148 typedef CharType char_type; 149 150 virtual bool open(char const *charset,method_type how) 151 { 152 return self_.do_open(charset,utf_name<CharType>(),how); 153 } 154 155 virtual std::string convert(char_type const *ubegin,char_type const *uend) 156 { 157 return self_.template real_convert<char,char_type>(ubegin,uend); 158 } 159 virtual ~iconv_from_utf() {} 160private: 161 iconverter_base self_; 162}; 163 164class iconv_between: public converter_between 165{ 166public: 167 virtual bool open(char const *to_charset,char const *from_charset,method_type how) 168 { 169 return self_.do_open(to_charset,from_charset,how); 170 } 171 virtual std::string convert(char const *begin,char const *end) 172 { 173 return self_.real_convert<char,char>(begin,end); 174 } 175 virtual ~iconv_between() {} 176private: 177 iconverter_base self_; 178 179}; 180 181template<typename CharType> 182class iconv_to_utf : public converter_to_utf<CharType> 183{ 184public: 185 186 typedef CharType char_type; 187 typedef std::basic_string<char_type> string_type; 188 189 virtual bool open(char const *charset,method_type how) 190 { 191 return self_.do_open(utf_name<CharType>(),charset,how); 192 } 193 194 virtual string_type convert(char const *begin,char const *end) 195 { 196 return self_.template real_convert<char_type,char>(begin,end); 197 } 198 virtual ~iconv_to_utf() {} 199private: 200 iconverter_base self_; 201}; 202 203 204 205} // impl 206} // conv 207} // locale 208} // boost 209 210 211 212 213#endif 214// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 215