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)
8 * \file code_conversion.cpp
9 * \author Andrey Semashev
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.
16 #include <boost/log/detail/config.hpp>
22 #include <boost/log/exceptions.hpp>
23 #include <boost/log/detail/code_conversion.hpp>
24 #if defined(BOOST_WINDOWS)
27 #include <boost/winapi/get_last_error.hpp>
28 #include <boost/winapi/character_code_conversion.hpp>
30 #include <boost/log/detail/header.hpp>
34 BOOST_LOG_OPEN_NAMESPACE
38 BOOST_LOG_ANONYMOUS_NAMESPACE
{
40 //! The function performs character conversion with the specified facet
41 template< typename LocalCharT
>
42 inline std::codecvt_base::result
convert(
43 std::codecvt
< LocalCharT
, char, std::mbstate_t > const& fac
,
44 std::mbstate_t& state
,
45 const char*& pSrcBegin
,
47 LocalCharT
*& pDstBegin
,
50 return fac
.in(state
, pSrcBegin
, pSrcEnd
, pSrcBegin
, pDstBegin
, pDstEnd
, pDstBegin
);
53 //! The function performs character conversion with the specified facet
54 template< typename LocalCharT
>
55 inline 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
,
63 return fac
.out(state
, pSrcBegin
, pSrcEnd
, pSrcBegin
, pDstBegin
, pDstEnd
, pDstBegin
);
68 #if defined(BOOST_MSVC)
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)
76 template< typename SourceCharT
, typename TargetCharT
, typename FacetT
>
77 inline std::size_t code_convert(const SourceCharT
* begin
, const SourceCharT
* end
, std::basic_string
< TargetCharT
>& converted
, std::size_t max_size
, FacetT
const& fac
)
79 typedef typename
FacetT::state_type state_type
;
80 TargetCharT converted_buffer
[256];
82 const SourceCharT
* const original_begin
= begin
;
83 state_type state
= state_type();
84 std::size_t buf_size
= (std::min
)(max_size
, sizeof(converted_buffer
) / sizeof(*converted_buffer
));
85 while (begin
!= end
&& buf_size
> 0u)
87 TargetCharT
* dest
= converted_buffer
;
88 std::codecvt_base::result res
= convert(
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
;
105 case std::codecvt_base::noconv
:
107 // Not possible, unless both character types are actually equivalent
108 const std::size_t size
= (std::min
)(max_size
, static_cast< std::size_t >(end
- begin
));
109 converted
.append(begin
, begin
+ size
);
115 case std::codecvt_base::partial
:
116 // Some characters were converted, some were not
117 if (dest
!= converted_buffer
)
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
;
124 // ...and go on for the next part
129 // Nothing was converted
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.
138 default: // std::codecvt_base::error
139 BOOST_LOG_THROW_DESCR(conversion_error
, "Could not convert character encoding");
142 buf_size
= (std::min
)(max_size
, sizeof(converted_buffer
) / sizeof(*converted_buffer
));
146 return static_cast< std::size_t >(begin
- original_begin
);
149 #if defined(BOOST_MSVC)
153 //! The function converts one string to the character type of another
154 BOOST_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
)
156 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< wchar_t, char, std::mbstate_t > >(loc
)) == len
;
159 //! The function converts one string to the character type of another
160 BOOST_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
)
162 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< wchar_t, char, std::mbstate_t > >(loc
)) == len
;
165 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
167 #if !defined(BOOST_NO_CXX11_CHAR16_T)
169 //! The function converts one string to the character type of another
170 BOOST_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
)
172 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< char16_t
, char, std::mbstate_t > >(loc
)) == len
;
175 //! The function converts one string to the character type of another
176 BOOST_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
)
178 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< char16_t
, char, std::mbstate_t > >(loc
)) == len
;
181 //! The function converts one string to the character type of another
182 BOOST_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
)
184 std::string temp_str
;
185 code_convert(str1
, str1
+ len
, temp_str
, temp_str
.max_size(), std::use_facet
< std::codecvt
< char16_t
, char, std::mbstate_t > >(loc
));
186 const std::size_t temp_size
= temp_str
.size();
187 return code_convert(temp_str
.c_str(), temp_str
.c_str() + temp_size
, str2
, max_size
, std::use_facet
< std::codecvt
< wchar_t, char, std::mbstate_t > >(loc
)) == temp_size
;
192 #if !defined(BOOST_NO_CXX11_CHAR32_T)
194 //! The function converts one string to the character type of another
195 BOOST_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
)
197 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< char32_t
, char, std::mbstate_t > >(loc
)) == len
;
200 //! The function converts one string to the character type of another
201 BOOST_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
)
203 return code_convert(str1
, str1
+ len
, str2
, max_size
, std::use_facet
< std::codecvt
< char32_t
, char, std::mbstate_t > >(loc
)) == len
;
206 //! The function converts one string to the character type of another
207 BOOST_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
)
209 std::string temp_str
;
210 code_convert(str1
, str1
+ len
, temp_str
, temp_str
.max_size(), std::use_facet
< std::codecvt
< char32_t
, char, std::mbstate_t > >(loc
));
211 const std::size_t temp_size
= temp_str
.size();
212 return code_convert(temp_str
.c_str(), temp_str
.c_str() + temp_size
, str2
, max_size
, std::use_facet
< std::codecvt
< wchar_t, char, std::mbstate_t > >(loc
)) == temp_size
;
217 #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T)
219 //! The function converts one string to the character type of another
220 BOOST_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
)
222 std::string temp_str
;
223 code_convert(str1
, str1
+ len
, temp_str
, temp_str
.max_size(), std::use_facet
< std::codecvt
< char16_t
, char, std::mbstate_t > >(loc
));
224 const std::size_t temp_size
= temp_str
.size();
225 return code_convert(temp_str
.c_str(), temp_str
.c_str() + temp_size
, str2
, max_size
, std::use_facet
< std::codecvt
< char32_t
, char, std::mbstate_t > >(loc
)) == temp_size
;
228 //! The function converts one string to the character type of another
229 BOOST_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
)
231 std::string temp_str
;
232 code_convert(str1
, str1
+ len
, temp_str
, temp_str
.max_size(), std::use_facet
< std::codecvt
< char32_t
, char, std::mbstate_t > >(loc
));
233 const std::size_t temp_size
= temp_str
.size();
234 return code_convert(temp_str
.c_str(), temp_str
.c_str() + temp_size
, str2
, max_size
, std::use_facet
< std::codecvt
< char16_t
, char, std::mbstate_t > >(loc
)) == temp_size
;
239 #endif // !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
241 #if defined(BOOST_WINDOWS)
243 //! Converts UTF-8 to UTF-16
244 std::wstring
utf8_to_utf16(const char* str
)
246 std::size_t utf8_len
= std::strlen(str
);
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");
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))
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))
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());
270 //! Converts UTF-16 to UTF-8
271 std::string
utf16_to_utf8(const wchar_t* wstr
)
273 std::size_t utf16_len
= std::wcslen(wstr
);
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");
279 const boost::winapi::DWORD_ flags
=
280 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
281 boost::winapi::WC_ERR_INVALID_CHARS_
;
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))
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))
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());
303 #endif // defined(BOOST_WINDOWS)
307 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
311 #include <boost/log/detail/footer.hpp>