1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   code_conversion.cpp
9  * \author Andrey Semashev
10  * \date   08.11.2008
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <cstddef>
17 #include <locale>
18 #include <string>
19 #include <stdexcept>
20 #include <algorithm>
21 #include <boost/log/exceptions.hpp>
22 #include <boost/log/detail/code_conversion.hpp>
23 #include <boost/log/detail/header.hpp>
24 
25 namespace boost {
26 
27 BOOST_LOG_OPEN_NAMESPACE
28 
29 namespace aux {
30 
31 BOOST_LOG_ANONYMOUS_NAMESPACE {
32 
33     //! The function performs character conversion with the specified facet
34     template< typename LocalCharT >
35     inline std::codecvt_base::result convert(
36         std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
37         std::mbstate_t& state,
38         const char*& pSrcBegin,
39         const char* pSrcEnd,
40         LocalCharT*& pDstBegin,
41         LocalCharT* pDstEnd)
42     {
43         return fac.in(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
44     }
45 
46     //! The function performs character conversion with the specified facet
47     template< typename LocalCharT >
48     inline std::codecvt_base::result convert(
49         std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
50         std::mbstate_t& state,
51         const LocalCharT*& pSrcBegin,
52         const LocalCharT* pSrcEnd,
53         char*& pDstBegin,
54         char* pDstEnd)
55     {
56         return fac.out(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
57     }
58 
59 } // namespace
60 
61 template< typename SourceCharT, typename TargetCharT, typename FacetT >
62 inline void code_convert(const SourceCharT* begin, const SourceCharT* end, std::basic_string< TargetCharT >& converted, FacetT const& fac)
63 {
64     typedef typename FacetT::state_type state_type;
65     TargetCharT converted_buffer[256];
66 
67     state_type state = state_type();
68     while (begin != end)
69     {
70         TargetCharT* dest = converted_buffer;
71         std::codecvt_base::result res = convert(
72             fac,
73             state,
74             begin,
75             end,
76             dest,
77             dest + sizeof(converted_buffer) / sizeof(*converted_buffer));
78 
79         switch (res)
80         {
81         case std::codecvt_base::ok:
82             // All characters were successfully converted
83             // NOTE: MSVC 11 also returns ok when the source buffer was only partially consumed, so we also check that the begin pointer has reached the end.
84             converted.append(converted_buffer, dest);
85             break;
86 
87         case std::codecvt_base::partial:
88             // Some characters were converted, some were not
89             if (dest != converted_buffer)
90             {
91                 // Some conversion took place, so it seems like
92                 // the destination buffer might not have been long enough
93                 converted.append(converted_buffer, dest);
94 
95                 // ...and go on for the next part
96                 break;
97             }
98             else
99             {
100                 // Nothing was converted, looks like the tail of the
101                 // source buffer contains only part of the last character.
102                 // Leave it as it is.
103                 return;
104             }
105 
106         case std::codecvt_base::noconv:
107             // Not possible, unless both character types are actually equivalent
108             converted.append(reinterpret_cast< const TargetCharT* >(begin), reinterpret_cast< const TargetCharT* >(end));
109             return;
110 
111         default: // std::codecvt_base::error
112             BOOST_LOG_THROW_DESCR(conversion_error, "Could not convert character encoding");
113         }
114     }
115 }
116 
117 //! The function converts one string to the character type of another
code_convert_impl(const wchar_t * str1,std::size_t len,std::string & str2,std::locale const & loc)118 BOOST_LOG_API void code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
119 {
120     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
121 }
122 
123 //! The function converts one string to the character type of another
code_convert_impl(const char * str1,std::size_t len,std::wstring & str2,std::locale const & loc)124 BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
125 {
126     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
127 }
128 
129 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
130 
131 #if !defined(BOOST_NO_CXX11_CHAR16_T)
132 
133 //! The function converts one string to the character type of another
code_convert_impl(const char16_t * str1,std::size_t len,std::string & str2,std::locale const & loc)134 BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
135 {
136     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
137 }
138 
139 //! The function converts one string to the character type of another
code_convert_impl(const char * str1,std::size_t len,std::u16string & str2,std::locale const & loc)140 BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
141 {
142     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
143 }
144 
145 //! The function converts one string to the character type of another
code_convert_impl(const char16_t * str1,std::size_t len,std::wstring & str2,std::locale const & loc)146 BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
147 {
148     std::string temp_str;
149     code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
150     code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
151 }
152 
153 #endif
154 
155 #if !defined(BOOST_NO_CXX11_CHAR32_T)
156 
157 //! The function converts one string to the character type of another
code_convert_impl(const char32_t * str1,std::size_t len,std::string & str2,std::locale const & loc)158 BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
159 {
160     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
161 }
162 
163 //! The function converts one string to the character type of another
code_convert_impl(const char * str1,std::size_t len,std::u32string & str2,std::locale const & loc)164 BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
165 {
166     code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
167 }
168 
169 //! The function converts one string to the character type of another
code_convert_impl(const char32_t * str1,std::size_t len,std::wstring & str2,std::locale const & loc)170 BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
171 {
172     std::string temp_str;
173     code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
174     code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
175 }
176 
177 #endif
178 
179 #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T)
180 
181 //! The function converts one string to the character type of another
code_convert_impl(const char16_t * str1,std::size_t len,std::u32string & str2,std::locale const & loc)182 BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
183 {
184     std::string temp_str;
185     code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
186     code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
187 }
188 
189 //! The function converts one string to the character type of another
code_convert_impl(const char32_t * str1,std::size_t len,std::u16string & str2,std::locale const & loc)190 BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
191 {
192     std::string temp_str;
193     code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
194     code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
195 }
196 
197 #endif
198 
199 #endif // !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
200 
201 } // namespace aux
202 
203 BOOST_LOG_CLOSE_NAMESPACE // namespace log
204 
205 } // namespace boost
206 
207 #include <boost/log/detail/footer.hpp>
208