3#ifndef ICE_ICONV_STRING_CONVERTER
4#define ICE_ICONV_STRING_CONVERTER
11# include "LocalExceptions.h"
12# include "StringConverter.h"
13# include "StringUtil.h"
31 template<
typename charT>
class IconvStringConverter final :
public Ice::BasicStringConverter<charT>
34 IconvStringConverter(
const std::string&);
36 std::byte* toUTF8(
const charT*,
const charT*, Ice::UTF8Buffer&)
const final;
38 void fromUTF8(
const std::byte*,
const std::byte*, std::basic_string<charT>&)
const final;
41 struct DescriptorHolder
43 std::pair<iconv_t, iconv_t> descriptor;
46 DescriptorHolder(
const std::string& internalCode) : descriptor(iconv_t(-1), iconv_t(-1))
48 const char* externalCode =
"UTF-8";
50 descriptor.first = iconv_open(internalCode.c_str(), externalCode);
51 if (descriptor.first == iconv_t(-1))
53 std::ostringstream os;
54 os <<
"iconv cannot convert from " << externalCode <<
" to " << internalCode;
55 throw Ice::FeatureNotSupportedException{__FILE__, __LINE__, os.str()};
58 descriptor.second = iconv_open(externalCode, internalCode.c_str());
59 if (descriptor.second == iconv_t(-1))
61 iconv_close(descriptor.first);
62 std::ostringstream os;
63 os <<
"iconv cannot convert from " << internalCode <<
" to " << externalCode;
64 throw Ice::FeatureNotSupportedException{__FILE__, __LINE__, os.str()};
70 [[maybe_unused]]
int rs = iconv_close(descriptor.first);
73 rs = iconv_close(descriptor.second);
77 DescriptorHolder(
const DescriptorHolder&) =
delete;
78 DescriptorHolder& operator=(
const DescriptorHolder&) =
delete;
81 [[nodiscard]] std::pair<iconv_t, iconv_t> getDescriptors()
const;
83 const std::string _internalCode;
90 template<
typename charT>
91 IconvStringConverter<charT>::IconvStringConverter(
const std::string& internalCode) : _internalCode(internalCode)
96 const DescriptorHolder descriptorHolder(internalCode);
99 template<
typename charT> std::pair<iconv_t, iconv_t> IconvStringConverter<charT>::getDescriptors()
const
101 static const thread_local DescriptorHolder descriptorHolder(_internalCode);
102 return descriptorHolder.descriptor;
105 template<
typename charT>
107 IconvStringConverter<charT>::toUTF8(
const charT* sourceStart,
const charT* sourceEnd,
Ice::UTF8Buffer& buf)
const
109 iconv_t cd = getDescriptors().second;
114 [[maybe_unused]]
size_t rs = iconv(cd,
nullptr,
nullptr,
nullptr,
nullptr);
116 char* inbuf =
reinterpret_cast<char*
>(
const_cast<charT*
>(sourceStart));
117 size_t inbytesleft =
static_cast<size_t>(sourceEnd - sourceStart) *
sizeof(charT);
118 std::byte* outbuf =
nullptr;
126 size_t howMany = std::max(inbytesleft,
size_t(4));
128 count = iconv(cd, &inbuf, &inbytesleft,
reinterpret_cast<char**
>(&outbuf), &howMany);
129 }
while (count ==
size_t(-1) && errno == E2BIG);
131 if (count ==
size_t(-1))
133 int errorCode = errno;
134 std::ostringstream os;
135 os <<
"iconv failed with: " << (errorCode == 0 ?
"unknown error" : IceInternal::errorToString(errorCode));
141 template<
typename charT>
142 void IconvStringConverter<charT>::fromUTF8(
143 const std::byte* sourceStart,
144 const std::byte* sourceEnd,
145 std::basic_string<charT>& target)
const
147 iconv_t cd = getDescriptors().first;
152 [[maybe_unused]]
size_t rs = iconv(cd,
nullptr,
nullptr,
nullptr,
nullptr);
154 char* inbuf =
reinterpret_cast<char*
>(
const_cast<std::byte*
>(sourceStart));
155 assert(sourceEnd > sourceStart);
156 auto inbytesleft =
static_cast<size_t>(sourceEnd - sourceStart);
158 char* outbuf =
nullptr;
159 size_t outbytesleft = 0;
167 size_t bytesUsed = 0;
170 bytesUsed =
static_cast<size_t>(outbuf -
reinterpret_cast<const char*
>(target.data()));
173 const size_t increment = std::max<size_t>(inbytesleft, 4);
174 target.resize(target.size() + increment);
175 outbuf =
const_cast<char*
>(
reinterpret_cast<const char*
>(target.data())) + bytesUsed;
176 outbytesleft += increment *
sizeof(charT);
178 count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
180 }
while (count ==
size_t(-1) && errno == E2BIG);
182 if (count ==
size_t(-1))
184 int errorCode = errno;
185 std::ostringstream os;
186 os <<
"iconv failed with: " << (errorCode == 0 ?
"unknown error" : IceInternal::errorToString(errorCode));
190 target.resize(target.size() - (outbytesleft /
sizeof(charT)));
200 template<
typename charT>
201 std::shared_ptr<Ice::BasicStringConverter<charT>>
204 std::string internalCode = internalCodeWithDefault;
206 if (internalCode.empty())
208 internalCode = nl_langinfo(CODESET);
211 return std::make_shared<IceInternal::IconvStringConverter<charT>>(internalCode);
This exception indicates the failure of a string conversion.
virtual std::byte * getMoreBytes(size_t howMany, std::byte *firstUnused)=0
Obtains more bytes.
Provides bytes to toUTF8.
std::shared_ptr< Ice::BasicStringConverter< charT > > createIconvStringConverter(const std::string &internalCodeWithDefault="")
Creates a string converter for the given code.