1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3//
4// Distributed under the Boost Software License, Version 1.0.
5// https://www.boost.org/LICENSE_1_0.txt
6
7#ifndef BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP
8#define BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP
9
10#include <boost/locale/encoding.hpp>
11#include "boost/locale/util/encoding.hpp"
12#include "boost/locale/util/iconv.hpp"
13#include <boost/assert.hpp>
14#include <cerrno>
15#include <string>
16
17namespace boost { namespace locale { namespace conv { namespace impl {
18
19 class iconverter_base {
20 public:
21 bool do_open(const char* to, const char* from, method_type how)
22 {
23 cvt_ = iconv_open(tocode: to, fromcode: from);
24 how_ = how;
25 return static_cast<bool>(cvt_);
26 }
27
28 template<typename OutChar, typename InChar>
29 std::basic_string<OutChar> real_convert(const InChar* ubegin, const InChar* uend)
30 {
31 std::basic_string<OutChar> sresult;
32
33 sresult.reserve(uend - ubegin);
34
35 OutChar tmp_buf[64];
36
37 char* out_start = reinterpret_cast<char*>(tmp_buf);
38 const char* begin = reinterpret_cast<const char*>(ubegin);
39 const char* end = reinterpret_cast<const char*>(uend);
40
41 bool is_unshifting = false;
42
43 for(;;) {
44 size_t in_left = end - begin;
45 size_t out_left = sizeof(tmp_buf);
46 char* out_ptr = out_start;
47
48 if(in_left == 0)
49 is_unshifting = true;
50
51 const auto old_in_left = in_left;
52 const size_t res = (!is_unshifting) ? conv(inbuf: &begin, inchar_left: &in_left, outbuf: &out_ptr, outchar_left: &out_left) :
53 conv(inbuf: nullptr, inchar_left: nullptr, outbuf: &out_ptr, outchar_left: &out_left);
54
55 if(res != 0 && res != (size_t)(-1)) {
56 if(how_ == stop)
57 throw conversion_error();
58 }
59
60 const size_t output_count = (out_ptr - out_start) / sizeof(OutChar);
61 sresult.append(tmp_buf, output_count);
62
63 if(res == (size_t)(-1)) {
64 const int err = errno;
65 BOOST_ASSERT_MSG(err == EILSEQ || err == EINVAL || err == E2BIG, "Invalid error code from IConv");
66 if(err == EILSEQ || err == EINVAL) {
67 if(how_ == stop)
68 throw conversion_error();
69
70 if(begin != end) {
71 begin += sizeof(InChar);
72 if(begin >= end)
73 break;
74 } else
75 break;
76 } else if(err == E2BIG) {
77 if(in_left != old_in_left || out_ptr != out_start) // Check to avoid infinite loop
78 continue;
79 throw std::runtime_error("No progress, IConv is faulty!"); // LCOV_EXCL_LINE
80 } else // Invalid error code, shouldn't ever happen or iconv has a bug
81 throw conversion_error(); // LCOV_EXCL_LINE
82 }
83 if(is_unshifting)
84 break;
85 }
86 return sresult;
87 }
88
89 private:
90 size_t conv(const char** inbuf, size_t* inchar_left, char** outbuf, size_t* outchar_left)
91 {
92 return call_iconv(d: cvt_, in: inbuf, insize: inchar_left, out: outbuf, outsize: outchar_left);
93 }
94
95 iconv_handle cvt_;
96 method_type how_;
97 };
98
99 template<typename CharType>
100 class iconv_from_utf final : public detail::utf_decoder<CharType> {
101 public:
102 bool open(const std::string& charset, method_type how)
103 {
104 return self_.do_open(to: charset.c_str(), from: util::utf_name<CharType>(), how);
105 }
106
107 std::string convert(const CharType* ubegin, const CharType* uend) override
108 {
109 return self_.template real_convert<char>(ubegin, uend);
110 }
111
112 private:
113 iconverter_base self_;
114 };
115
116 class iconv_between final : public detail::narrow_converter {
117 public:
118 bool open(const std::string& to_charset, const std::string& from_charset, method_type how)
119 {
120 return self_.do_open(to: to_charset.c_str(), from: from_charset.c_str(), how);
121 }
122 std::string convert(const char* begin, const char* end) override
123 {
124 return self_.real_convert<char, char>(ubegin: begin, uend: end);
125 }
126
127 private:
128 iconverter_base self_;
129 };
130
131 template<typename CharType>
132 class iconv_to_utf final : public detail::utf_encoder<CharType> {
133 public:
134 bool open(const std::string& charset, method_type how)
135 {
136 return self_.do_open(to: util::utf_name<CharType>(), from: charset.c_str(), how);
137 }
138
139 std::basic_string<CharType> convert(const char* begin, const char* end) override
140 {
141 return self_.template real_convert<CharType>(begin, end);
142 }
143
144 private:
145 iconverter_base self_;
146 };
147
148}}}} // namespace boost::locale::conv::impl
149
150#endif
151

source code of boost/libs/locale/src/boost/locale/encoding/iconv_converter.hpp