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 virtual ~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 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 sresult.append(&result[0],output_count); 86 87 if(res == (size_t)(-1)) { 88 if(err == EILSEQ || err == EINVAL) { 89 if(how_ == stop) { 90 throw conversion_error(); 91 } 92 93 if(begin != end) { 94 begin+=sizeof(InChar); 95 if(begin >= end) 96 break; 97 } 98 else { 99 break; 100 } 101 } 102 else if (err==E2BIG) { 103 continue; 104 } 105 else { 106 // We should never get there 107 // but if we do 108 if(how_ == stop) 109 throw conversion_error(); 110 else 111 break; 112 } 113 } 114 if(state == unshifting) 115 state = done; 116 } 117 return sresult; 118 } 119 120 121private: 122 123 void close() 124 { 125 if(cvt_!=(iconv_t)(-1)) { 126 iconv_close(cvt_); 127 cvt_ = (iconv_t)(-1); 128 } 129 } 130 131 iconv_t cvt_; 132 133 method_type how_; 134 135}; 136 137template<typename CharType> 138class iconv_from_utf : public iconverter_base, public converter_from_utf<CharType> 139{ 140public: 141 142 typedef CharType char_type; 143 144 virtual bool open(char const *charset,method_type how) 145 { 146 return iconverter_base::open(charset,utf_name<CharType>(),how); 147 } 148 149 virtual std::string convert(char_type const *ubegin,char_type const *uend) 150 { 151 return real_convert<char,char_type>(ubegin,uend); 152 } 153}; 154 155class iconv_between: public iconverter_base, public converter_between 156{ 157public: 158 virtual bool open(char const *to_charset,char const *from_charset,method_type how) 159 { 160 return iconverter_base::open(to_charset,from_charset,how); 161 } 162 virtual std::string convert(char const *begin,char const *end) 163 { 164 return real_convert<char,char>(begin,end); 165 } 166 167}; 168 169 170template<typename CharType> 171class iconv_to_utf : public iconverter_base, public converter_to_utf<CharType> 172{ 173public: 174 175 typedef CharType char_type; 176 typedef std::basic_string<char_type> string_type; 177 178 virtual bool open(char const *charset,method_type how) 179 { 180 return iconverter_base::open(utf_name<CharType>(),charset,how); 181 } 182 183 virtual string_type convert(char const *begin,char const *end) 184 { 185 return real_convert<char_type,char>(begin,end); 186 } 187}; 188 189 190 191 192} // impl 193} // conv 194} // locale 195} // boost 196 197 198 199 200#endif 201// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 202