| 1 | // |
| 2 | // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) |
| 3 | // |
| 4 | // Distributed under the Boost Software License, Version 1.0. |
| 5 | // https://www.boost.org/LICENSE_1_0.txt |
| 6 | |
| 7 | #ifndef BOOST_LOCALE_ICONV_FIXER_HPP |
| 8 | #define BOOST_LOCALE_ICONV_FIXER_HPP |
| 9 | |
| 10 | #include <boost/core/exchange.hpp> |
| 11 | #include <iconv.h> |
| 12 | |
| 13 | namespace boost { namespace locale { |
| 14 | class iconv_handle { |
| 15 | iconv_t h_; |
| 16 | void close() |
| 17 | { |
| 18 | if(*this) |
| 19 | iconv_close(cd: h_); |
| 20 | } |
| 21 | |
| 22 | public: |
| 23 | explicit iconv_handle(iconv_t h = iconv_t(-1)) : h_(h) {} |
| 24 | |
| 25 | iconv_handle(const iconv_handle& rhs) = delete; |
| 26 | iconv_handle(iconv_handle&& rhs) noexcept : h_(exchange(t&: rhs.h_, u: iconv_t(-1))) {} |
| 27 | |
| 28 | iconv_handle& operator=(const iconv_handle& rhs) = delete; |
| 29 | iconv_handle& operator=(iconv_handle&& rhs) noexcept |
| 30 | { |
| 31 | h_ = exchange(t&: rhs.h_, u: iconv_t(-1)); |
| 32 | return *this; |
| 33 | } |
| 34 | iconv_handle& operator=(iconv_t h) |
| 35 | { |
| 36 | close(); |
| 37 | h_ = h; |
| 38 | return *this; |
| 39 | } |
| 40 | ~iconv_handle() { close(); } |
| 41 | |
| 42 | operator iconv_t() const { return h_; } |
| 43 | explicit operator bool() const { return h_ != iconv_t(-1); } |
| 44 | }; |
| 45 | |
| 46 | extern "C" { |
| 47 | #if defined(__ICONV_F_HIDE_INVALID) && defined(__FreeBSD__) |
| 48 | # define BOOST_LOCALE_ICONV_FUNC __iconv |
| 49 | # define BOOST_LOCALE_ICONV_FLAGS , __ICONV_F_HIDE_INVALID, 0 |
| 50 | |
| 51 | // GNU variant |
| 52 | typedef size_t (*const_iconv_ptr_type)(iconv_t, const char**, size_t*, char**, size_t*, uint32_t, size_t*); |
| 53 | // POSIX variant |
| 54 | typedef size_t (*nonconst_iconv_ptr_type)(iconv_t, char**, size_t*, char**, size_t*, uint32_t, size_t*); |
| 55 | #else |
| 56 | # define BOOST_LOCALE_ICONV_FUNC iconv |
| 57 | # define BOOST_LOCALE_ICONV_FLAGS |
| 58 | |
| 59 | typedef size_t (*const_iconv_ptr_type)(iconv_t, const char**, size_t*, char**, size_t*); |
| 60 | typedef size_t (*nonconst_iconv_ptr_type)(iconv_t, char**, size_t*, char**, size_t*); |
| 61 | #endif |
| 62 | } |
| 63 | |
| 64 | inline size_t |
| 65 | call_iconv_impl(const_iconv_ptr_type ptr, iconv_t d, const char** in, size_t* insize, char** out, size_t* outsize) |
| 66 | { |
| 67 | return ptr(d, in, insize, out, outsize BOOST_LOCALE_ICONV_FLAGS); |
| 68 | } |
| 69 | inline size_t call_iconv_impl(nonconst_iconv_ptr_type ptr, |
| 70 | iconv_t d, |
| 71 | const char** in, |
| 72 | size_t* insize, |
| 73 | char** out, |
| 74 | size_t* outsize) |
| 75 | { |
| 76 | return ptr(d, const_cast<char**>(in), insize, out, outsize BOOST_LOCALE_ICONV_FLAGS); |
| 77 | } |
| 78 | |
| 79 | inline size_t call_iconv(iconv_t d, const char** in, size_t* insize, char** out, size_t* outsize) |
| 80 | { |
| 81 | return call_iconv_impl(BOOST_LOCALE_ICONV_FUNC, d, in, insize, out, outsize); |
| 82 | } |
| 83 | |
| 84 | // Convenience overload when the adjusted in/out ptrs are not required |
| 85 | inline size_t call_iconv(iconv_t d, const char* in, size_t* insize, char* out, size_t* outsize) |
| 86 | { |
| 87 | return call_iconv(d, in: &in, insize, out: &out, outsize); |
| 88 | } |
| 89 | // Disambiguation |
| 90 | inline size_t call_iconv(iconv_t d, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t) |
| 91 | { |
| 92 | return call_iconv_impl(BOOST_LOCALE_ICONV_FUNC, d, in: nullptr, insize: nullptr, out: nullptr, outsize: nullptr); |
| 93 | } |
| 94 | }} // namespace boost::locale |
| 95 | |
| 96 | #endif |
| 97 | |