1// Copyright Vladimir Prus 2004.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt
4// or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#include <fstream>
7#include <locale.h>
8#include <locale>
9#include <iostream>
10#include <string>
11#include <locale>
12#include <stdexcept>
13
14#include <boost/config.hpp>
15
16#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
17# define BOOST_PROGRAM_OPTIONS_SOURCE
18#endif
19#include <boost/program_options/config.hpp>
20#include <boost/program_options/detail/convert.hpp>
21#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
22#include <boost/throw_exception.hpp>
23
24#include <boost/bind/bind.hpp>
25
26using namespace std;
27using namespace boost::placeholders;
28
29namespace boost { namespace detail {
30
31 /* Internal function to actually perform conversion.
32 The logic in from_8_bit and to_8_bit function is exactly
33 the same, except that one calls 'in' method of codecvt and another
34 calls the 'out' method, and that syntax difference makes straightforward
35 template implementation impossible.
36
37 This functions takes a 'fun' argument, which should have the same
38 parameters and return type and the in/out methods. The actual converting
39 function will pass functional objects created with boost::bind.
40 Experiments show that the performance loss is less than 10%.
41 */
42 template<class ToChar, class FromChar, class Fun>
43 std::basic_string<ToChar>
44 convert(const std::basic_string<FromChar>& s, Fun fun)
45
46 {
47 std::basic_string<ToChar> result;
48
49 std::mbstate_t state = std::mbstate_t();
50
51 const FromChar* from = s.data();
52 const FromChar* from_end = s.data() + s.size();
53 // The interface of cvt is not really iterator-like, and it's
54 // not possible the tell the required output size without the conversion.
55 // All we can is convert data by pieces.
56 while(from != from_end) {
57
58 // std::basic_string does not provide non-const pointers to the data,
59 // so converting directly into string is not possible.
60 ToChar buffer[32];
61
62 ToChar* to_next = buffer;
63 // Need variable because boost::bind doesn't work with rvalues.
64 ToChar* to_end = buffer + 32;
65 std::codecvt_base::result r =
66 fun(state, from, from_end, from, buffer, to_end, to_next);
67
68 if (r == std::codecvt_base::error)
69 boost::throw_exception(
70 e: std::logic_error("character conversion failed"));
71 // 'partial' is not an error, it just means not all source
72 // characters were converted. However, we need to check that at
73 // least one new target character was produced. If not, it means
74 // the source data is incomplete, and since we don't have extra
75 // data to add to source, it's error.
76 if (to_next == buffer)
77 boost::throw_exception(
78 e: std::logic_error("character conversion failed"));
79
80 // Add converted characters
81 result.append(buffer, to_next);
82 }
83
84 return result;
85 }
86}}
87
88namespace boost {
89
90#ifndef BOOST_NO_STD_WSTRING
91 BOOST_PROGRAM_OPTIONS_DECL std::wstring
92 from_8_bit(const std::string& s,
93 const std::codecvt<wchar_t, char, std::mbstate_t>& cvt)
94 {
95 return detail::convert<wchar_t>(
96 s,
97 fun: boost::bind(f: &std::codecvt<wchar_t, char, mbstate_t>::in,
98 a1: &cvt,
99 a2: _1, a3: _2, a4: _3, a5: _4, a6: _5, a7: _6, a8: _7));
100 }
101
102 BOOST_PROGRAM_OPTIONS_DECL std::string
103 to_8_bit(const std::wstring& s,
104 const std::codecvt<wchar_t, char, std::mbstate_t>& cvt)
105 {
106 return detail::convert<char>(
107 s,
108 fun: boost::bind(f: &codecvt<wchar_t, char, mbstate_t>::out,
109 a1: &cvt,
110 a2: _1, a3: _2, a4: _3, a5: _4, a6: _5, a7: _6, a8: _7));
111 }
112
113
114 namespace {
115 boost::program_options::detail::utf8_codecvt_facet
116 utf8_facet;
117 }
118
119 BOOST_PROGRAM_OPTIONS_DECL std::wstring
120 from_utf8(const std::string& s)
121 {
122 return from_8_bit(s, cvt: utf8_facet);
123 }
124
125 BOOST_PROGRAM_OPTIONS_DECL std::string
126 to_utf8(const std::wstring& s)
127 {
128 return to_8_bit(s, cvt: utf8_facet);
129 }
130
131 BOOST_PROGRAM_OPTIONS_DECL std::wstring
132 from_local_8_bit(const std::string& s)
133 {
134 typedef codecvt<wchar_t, char, mbstate_t> facet_type;
135 return from_8_bit(s,
136 BOOST_USE_FACET(facet_type, locale()));
137 }
138
139 BOOST_PROGRAM_OPTIONS_DECL std::string
140 to_local_8_bit(const std::wstring& s)
141 {
142 typedef codecvt<wchar_t, char, mbstate_t> facet_type;
143 return to_8_bit(s,
144 BOOST_USE_FACET(facet_type, locale()));
145 }
146#endif
147
148 namespace program_options
149 {
150 BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::string& s)
151 {
152 return s;
153 }
154
155#ifndef BOOST_NO_STD_WSTRING
156 BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::wstring& s)
157 {
158 return to_utf8(s);
159 }
160#endif
161 }
162
163
164}
165

source code of boost/libs/program_options/src/convert.cpp