summaryrefslogtreecommitdiff
path: root/libs/log/src/code_conversion.cpp
blob: c4288fe99aafc6a44bb152dea4b94bebbe387c31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 *          Copyright Andrey Semashev 2007 - 2015.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   code_conversion.cpp
 * \author Andrey Semashev
 * \date   08.11.2008
 *
 * \brief  This header is the Boost.Log library implementation, see the library documentation
 *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
 */

#include <locale>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <boost/log/exceptions.hpp>
#include <boost/log/detail/code_conversion.hpp>
#include <boost/log/detail/header.hpp>

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace aux {

BOOST_LOG_ANONYMOUS_NAMESPACE {

    //! The function performs character conversion with the specified facet
    template< typename LocalCharT >
    inline std::codecvt_base::result convert(
        std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
        std::mbstate_t& state,
        const char*& pSrcBegin,
        const char* pSrcEnd,
        LocalCharT*& pDstBegin,
        LocalCharT* pDstEnd)
    {
        return fac.in(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
    }

    //! The function performs character conversion with the specified facet
    template< typename LocalCharT >
    inline std::codecvt_base::result convert(
        std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
        std::mbstate_t& state,
        const LocalCharT*& pSrcBegin,
        const LocalCharT* pSrcEnd,
        char*& pDstBegin,
        char* pDstEnd)
    {
        return fac.out(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
    }

} // namespace

template< typename SourceCharT, typename TargetCharT, typename FacetT >
inline void code_convert(const SourceCharT* begin, const SourceCharT* end, std::basic_string< TargetCharT >& converted, FacetT const& fac)
{
    typedef typename FacetT::state_type state_type;
    TargetCharT converted_buffer[256];

    state_type state = state_type();
    while (begin != end)
    {
        TargetCharT* dest = converted_buffer;
        std::codecvt_base::result res = convert(
            fac,
            state,
            begin,
            end,
            dest,
            dest + sizeof(converted_buffer) / sizeof(*converted_buffer));

        switch (res)
        {
        case std::codecvt_base::ok:
            // All characters were successfully converted
            // 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.
            converted.append(converted_buffer, dest);
            break;

        case std::codecvt_base::partial:
            // Some characters were converted, some were not
            if (dest != converted_buffer)
            {
                // Some conversion took place, so it seems like
                // the destination buffer might not have been long enough
                converted.append(converted_buffer, dest);

                // ...and go on for the next part
                break;
            }
            else
            {
                // Nothing was converted, looks like the tail of the
                // source buffer contains only part of the last character.
                // Leave it as it is.
                return;
            }

        case std::codecvt_base::noconv:
            // Not possible, unless both character types are actually equivalent
            converted.append(reinterpret_cast< const TargetCharT* >(begin), reinterpret_cast< const TargetCharT* >(end));
            return;

        default: // std::codecvt_base::error
            BOOST_LOG_THROW_DESCR(conversion_error, "Could not convert character encoding");
        }
    }
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const wchar_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}

// Note: MSVC 2015 (aka VC14) implement char16_t and char32_t types but not codecvt locale facets
#if !defined(BOOST_MSVC)

#if !defined(BOOST_NO_CXX11_CHAR16_T)

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char16_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
}

#endif

#if !defined(BOOST_NO_CXX11_CHAR32_T)

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char32_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
{
    code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
}

#endif

#endif // !defined(BOOST_MSVC)

} // namespace aux

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>