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 <boost/log/detail/config.hpp>
17#include <cstddef>
18#include <locale>
19#include <string>
20#include <stdexcept>
21#include <algorithm>
22#include <boost/log/exceptions.hpp>
23#include <boost/log/detail/code_conversion.hpp>
24#if defined(BOOST_WINDOWS)
25#include <cstring>
26#include <limits>
27#include <boost/winapi/get_last_error.hpp>
28#include <boost/winapi/character_code_conversion.hpp>
29#endif
30#include <boost/log/detail/header.hpp>
31
32namespace boost {
33
34BOOST_LOG_OPEN_NAMESPACE
35
36namespace aux {
37
38BOOST_LOG_ANONYMOUS_NAMESPACE {
39
40//! The function performs character conversion with the specified facet
41template< typename LocalCharT >
42inline std::codecvt_base::result convert(
43 std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
44 std::mbstate_t& state,
45 const char*& pSrcBegin,
46 const char* pSrcEnd,
47 LocalCharT*& pDstBegin,
48 LocalCharT* pDstEnd)
49{
50 return fac.in(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
51}
52
53//! The function performs character conversion with the specified facet
54template< typename LocalCharT >
55inline std::codecvt_base::result convert(
56 std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
57 std::mbstate_t& state,
58 const LocalCharT*& pSrcBegin,
59 const LocalCharT* pSrcEnd,
60 char*& pDstBegin,
61 char* pDstEnd)
62{
63 return fac.out(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
64}
65
66} // namespace
67
68#if defined(BOOST_MSVC)
69#pragma warning(push)
70// conversion from 'X' to 'Y', possible loss of data
71// This warning is triggered for the noconv case below, where we convert wchar_t to char if the locale facet
72// reports that no code conversion is needed. In such a case, no data loss will happen.
73#pragma warning(disable: 4244)
74#endif
75
76template< typename SourceCharT, typename TargetCharT, typename FacetT >
77inline std::size_t code_convert(const SourceCharT* begin, const SourceCharT* end, std::basic_string< TargetCharT >& converted, std::size_t max_size, FacetT const& fac)
78{
79 typedef typename FacetT::state_type state_type;
80 TargetCharT converted_buffer[256];
81
82 const SourceCharT* const original_begin = begin;
83 state_type state = state_type();
84 std::size_t buf_size = (std::min)(a: max_size, b: sizeof(converted_buffer) / sizeof(*converted_buffer));
85 while (begin != end && buf_size > 0u)
86 {
87 TargetCharT* dest = converted_buffer;
88 std::codecvt_base::result res = convert(
89 fac,
90 state,
91 begin,
92 end,
93 dest,
94 dest + buf_size);
95
96 switch (res)
97 {
98 case std::codecvt_base::ok:
99 // All characters were successfully converted
100 // 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.
101 converted.append(converted_buffer, dest);
102 max_size -= dest - converted_buffer;
103 break;
104
105 case std::codecvt_base::noconv:
106 {
107 // Not possible, unless both character types are actually equivalent
108 const std::size_t size = (std::min)(a: max_size, b: static_cast< std::size_t >(end - begin));
109 converted.append(begin, begin + size);
110 begin += size;
111 max_size -= size;
112 }
113 goto done;
114
115 case std::codecvt_base::partial:
116 // Some characters were converted, some were not
117 if (dest != converted_buffer)
118 {
119 // Some conversion took place, so it seems like
120 // the destination buffer might not have been long enough
121 converted.append(converted_buffer, dest);
122 max_size -= dest - converted_buffer;
123
124 // ...and go on for the next part
125 break;
126 }
127 else
128 {
129 // Nothing was converted
130 if (begin == end)
131 goto done;
132
133 // Looks like the tail of the source buffer contains only part of the last character.
134 // In this case we intentionally fall through to throw an exception.
135 }
136 BOOST_FALLTHROUGH;
137
138 default: // std::codecvt_base::error
139 BOOST_LOG_THROW_DESCR(conversion_error, "Could not convert character encoding");
140 }
141
142 buf_size = (std::min)(a: max_size, b: sizeof(converted_buffer) / sizeof(*converted_buffer));
143 }
144
145done:
146 return static_cast< std::size_t >(begin - original_begin);
147}
148
149#if defined(BOOST_MSVC)
150#pragma warning(pop)
151#endif
152
153//! The function converts one string to the character type of another
154BOOST_LOG_API bool code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
155{
156 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc: loc)) == len;
157}
158
159//! The function converts one string to the character type of another
160BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
161{
162 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc: loc)) == len;
163}
164
165#if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
166
167#if !defined(BOOST_NO_CXX11_CHAR16_T)
168
169//! The function converts one string to the character type of another
170BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
171{
172 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc: loc)) == len;
173}
174
175//! The function converts one string to the character type of another
176BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc)
177{
178 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc: loc)) == len;
179}
180
181//! The function converts one string to the character type of another
182BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
183{
184 std::string temp_str;
185 code_convert(begin: str1, end: str1 + len, converted&: temp_str, max_size: temp_str.max_size(), fac: std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc: loc));
186 const std::size_t temp_size = temp_str.size();
187 return code_convert(begin: temp_str.c_str(), end: temp_str.c_str() + temp_size, converted&: str2, max_size, fac: std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc: loc)) == temp_size;
188}
189
190#endif
191
192#if !defined(BOOST_NO_CXX11_CHAR32_T)
193
194//! The function converts one string to the character type of another
195BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
196{
197 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc: loc)) == len;
198}
199
200//! The function converts one string to the character type of another
201BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc)
202{
203 return code_convert(begin: str1, end: str1 + len, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc: loc)) == len;
204}
205
206//! The function converts one string to the character type of another
207BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
208{
209 std::string temp_str;
210 code_convert(begin: str1, end: str1 + len, converted&: temp_str, max_size: temp_str.max_size(), fac: std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc: loc));
211 const std::size_t temp_size = temp_str.size();
212 return code_convert(begin: temp_str.c_str(), end: temp_str.c_str() + temp_size, converted&: str2, max_size, fac: std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc: loc)) == temp_size;
213}
214
215#endif
216
217#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T)
218
219//! The function converts one string to the character type of another
220BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc)
221{
222 std::string temp_str;
223 code_convert(begin: str1, end: str1 + len, converted&: temp_str, max_size: temp_str.max_size(), fac: std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc: loc));
224 const std::size_t temp_size = temp_str.size();
225 return code_convert(begin: temp_str.c_str(), end: temp_str.c_str() + temp_size, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc: loc)) == temp_size;
226}
227
228//! The function converts one string to the character type of another
229BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc)
230{
231 std::string temp_str;
232 code_convert(begin: str1, end: str1 + len, converted&: temp_str, max_size: temp_str.max_size(), fac: std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc: loc));
233 const std::size_t temp_size = temp_str.size();
234 return code_convert(begin: temp_str.c_str(), end: temp_str.c_str() + temp_size, converted&: str2, max_size, fac: std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc: loc)) == temp_size;
235}
236
237#endif
238
239#endif // !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
240
241#if defined(BOOST_WINDOWS)
242
243//! Converts UTF-8 to UTF-16
244std::wstring utf8_to_utf16(const char* str)
245{
246 std::size_t utf8_len = std::strlen(str);
247 if (utf8_len == 0)
248 return std::wstring();
249 else if (BOOST_UNLIKELY(utf8_len > static_cast< std::size_t >((std::numeric_limits< int >::max)())))
250 BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-8 string too long");
251
252 int len = boost::winapi::MultiByteToWideChar(boost::winapi::CP_UTF8_, boost::winapi::MB_ERR_INVALID_CHARS_, str, static_cast< int >(utf8_len), NULL, 0);
253 if (BOOST_LIKELY(len > 0))
254 {
255 std::wstring wstr;
256 wstr.resize(len);
257
258 len = boost::winapi::MultiByteToWideChar(boost::winapi::CP_UTF8_, boost::winapi::MB_ERR_INVALID_CHARS_, str, static_cast< int >(utf8_len), &wstr[0], len);
259 if (BOOST_LIKELY(len > 0))
260 {
261 return wstr;
262 }
263 }
264
265 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
266 BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to convert UTF-8 to UTF-16", (err));
267 BOOST_LOG_UNREACHABLE_RETURN(std::wstring());
268}
269
270//! Converts UTF-16 to UTF-8
271std::string utf16_to_utf8(const wchar_t* wstr)
272{
273 std::size_t utf16_len = std::wcslen(wstr);
274 if (utf16_len == 0)
275 return std::string();
276 else if (BOOST_UNLIKELY(utf16_len > static_cast< std::size_t >((std::numeric_limits< int >::max)())))
277 BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-16 string too long");
278
279 const boost::winapi::DWORD_ flags =
280#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
281 boost::winapi::WC_ERR_INVALID_CHARS_;
282#else
283 0u;
284#endif
285 int len = boost::winapi::WideCharToMultiByte(boost::winapi::CP_UTF8_, flags, wstr, static_cast< int >(utf16_len), NULL, 0, NULL, NULL);
286 if (BOOST_LIKELY(len > 0))
287 {
288 std::string str;
289 str.resize(len);
290
291 len = boost::winapi::WideCharToMultiByte(boost::winapi::CP_UTF8_, flags, wstr, static_cast< int >(utf16_len), &str[0], len, NULL, NULL);
292 if (BOOST_LIKELY(len > 0))
293 {
294 return str;
295 }
296 }
297
298 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
299 BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to convert UTF-16 to UTF-8", (err));
300 BOOST_LOG_UNREACHABLE_RETURN(std::string());
301}
302
303#endif // defined(BOOST_WINDOWS)
304
305} // namespace aux
306
307BOOST_LOG_CLOSE_NAMESPACE // namespace log
308
309} // namespace boost
310
311#include <boost/log/detail/footer.hpp>
312

source code of boost/libs/log/src/code_conversion.cpp