• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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