Ice 3.7 C++98 API Reference
Loading...
Searching...
No Matches
IconvStringConverter.h
Go to the documentation of this file.
1//
2// Copyright (c) ZeroC, Inc. All rights reserved.
3//
4
5#ifndef ICE_ICONV_STRING_CONVERTER
6#define ICE_ICONV_STRING_CONVERTER
7
8#include <Ice/Config.h>
9
10//
11// For all platforms except Windows
12//
13#ifndef _WIN32
14
15#include <Ice/StringConverter.h>
16#include <IceUtil/StringUtil.h>
19
20#include <algorithm>
21#include <iconv.h>
22#include <langinfo.h>
23
24#if (defined(__APPLE__) && _LIBICONV_VERSION < 0x010B)
25//
26// See http://sourceware.org/bugzilla/show_bug.cgi?id=2962
27//
28# define ICE_CONST_ICONV_INBUF 1
29#endif
30
31namespace Ice
32{
33
38class ICE_API IconvInitializationException : public IceUtil::ExceptionHelper<IconvInitializationException>
39{
40public:
41
48 IconvInitializationException(const char* file, int line, const std::string& reason);
49
50#ifndef ICE_CPP11_COMPILER
52#endif
53
58 virtual std::string ice_id() const;
59
64 virtual void ice_print(std::ostream& str) const;
65
66#ifndef ICE_CPP11_MAPPING
72#endif
73
78 std::string reason() const;
79
80private:
81
82 std::string _reason;
83};
84
85}
86
87namespace IceInternal
88{
89
90//
91// Converts charT encoded with internalCode to and from UTF-8 byte sequences
92//
93// The implementation allocates a pair of iconv_t on each thread, to avoid
94// opening / closing iconv_t objects all the time.
95//
96//
97template<typename charT>
98class IconvStringConverter : public IceUtil::BasicStringConverter<charT>
99{
100public:
101
102 IconvStringConverter(const std::string&);
103
104 virtual ~IconvStringConverter();
105
106 virtual Ice::Byte* toUTF8(const charT*, const charT*, Ice::UTF8Buffer&) const;
107
108 virtual void fromUTF8(const Ice::Byte*, const Ice::Byte*, std::basic_string<charT>&) const;
109
110private:
111
112 std::pair<iconv_t, iconv_t> createDescriptors() const;
113 std::pair<iconv_t, iconv_t> getDescriptors() const;
114
115 static void cleanupKey(void*);
116 static void close(std::pair<iconv_t, iconv_t>);
117
118 mutable pthread_key_t _key;
119 const std::string _internalCode;
120};
121
122//
123// Implementation
124//
125
126#ifdef __SUNPRO_CC
127extern "C"
128{
129 typedef void (*IcePthreadKeyDestructor)(void*);
130}
131#endif
132
133template<typename charT>
134IconvStringConverter<charT>::IconvStringConverter(const std::string& internalCode) :
135 _internalCode(internalCode)
136{
137 //
138 // Verify that iconv supports conversion to/from internalCode
139 //
140 try
141 {
142 close(createDescriptors());
143 }
144 catch(const Ice::IllegalConversionException& sce)
145 {
146 throw Ice::IconvInitializationException(__FILE__, __LINE__, sce.reason());
147 }
148
149 //
150 // Create thread-specific key
151 //
152#ifdef __SUNPRO_CC
153 int rs = pthread_key_create(&_key, reinterpret_cast<IcePthreadKeyDestructor>(&cleanupKey));
154#else
155 int rs = pthread_key_create(&_key, &cleanupKey);
156#endif
157
158 if(rs != 0)
159 {
160 throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rs);
161 }
162}
163
164template<typename charT>
165IconvStringConverter<charT>::~IconvStringConverter()
166{
167 void* val = pthread_getspecific(_key);
168 if(val != 0)
169 {
170 cleanupKey(val);
171 }
172 if(pthread_key_delete(_key) != 0)
173 {
174 assert(0);
175 }
176}
177
178template<typename charT> std::pair<iconv_t, iconv_t>
179IconvStringConverter<charT>::createDescriptors() const
180{
181 std::pair<iconv_t, iconv_t> cdp;
182
183 const char* externalCode = "UTF-8";
184
185 cdp.first = iconv_open(_internalCode.c_str(), externalCode);
186 if(cdp.first == iconv_t(-1))
187 {
188 std::ostringstream os;
189 os << "iconv cannot convert from " << externalCode << " to " << _internalCode;
190 throw Ice::IllegalConversionException(__FILE__, __LINE__, os.str());
191 }
192
193 cdp.second = iconv_open(externalCode, _internalCode.c_str());
194 if(cdp.second == iconv_t(-1))
195 {
196 iconv_close(cdp.first);
197 std::ostringstream os;
198 os << "iconv cannot convert from " << _internalCode << " to " << externalCode;
199 throw Ice::IllegalConversionException(__FILE__, __LINE__, os.str());
200 }
201 return cdp;
202}
203
204template<typename charT> std::pair<iconv_t, iconv_t>
205IconvStringConverter<charT>::getDescriptors() const
206{
207 void* val = pthread_getspecific(_key);
208 if(val != 0)
209 {
210 return *static_cast<std::pair<iconv_t, iconv_t>*>(val);
211 }
212 else
213 {
214 std::pair<iconv_t, iconv_t> cdp = createDescriptors();
215 int rs = pthread_setspecific(_key, new std::pair<iconv_t, iconv_t>(cdp));
216 if(rs != 0)
217 {
218 throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rs);
219 }
220 return cdp;
221 }
222}
223
224template<typename charT> /*static*/ void
225IconvStringConverter<charT>::cleanupKey(void* val)
226{
227 std::pair<iconv_t, iconv_t>* cdp = static_cast<std::pair<iconv_t, iconv_t>*>(val);
228
229 close(*cdp);
230 delete cdp;
231}
232
233template<typename charT> /*static*/ void
234IconvStringConverter<charT>::close(std::pair<iconv_t, iconv_t> cdp)
235{
236#ifndef NDEBUG
237 int rs = iconv_close(cdp.first);
238 assert(rs == 0);
239
240 rs = iconv_close(cdp.second);
241 assert(rs == 0);
242#else
243 iconv_close(cdp.first);
244 iconv_close(cdp.second);
245#endif
246}
247
248template<typename charT> Ice::Byte*
249IconvStringConverter<charT>::toUTF8(const charT* sourceStart,
250 const charT* sourceEnd,
251 Ice::UTF8Buffer& buf) const
252{
253 iconv_t cd = getDescriptors().second;
254
255 //
256 // Reset cd
257 //
258#ifdef NDEBUG
259 iconv(cd, 0, 0, 0, 0);
260#else
261 size_t rs = iconv(cd, 0, 0, 0, 0);
262 assert(rs == 0);
263#endif
264
265#ifdef ICE_CONST_ICONV_INBUF
266 const char* inbuf = reinterpret_cast<const char*>(sourceStart);
267#else
268 char* inbuf = reinterpret_cast<char*>(const_cast<charT*>(sourceStart));
269#endif
270 size_t inbytesleft = static_cast<size_t>(sourceEnd - sourceStart) * sizeof(charT);
271 char* outbuf = 0;
272
273 size_t count = 0;
274 //
275 // Loop while we need more buffer space
276 //
277 do
278 {
279 size_t howMany = std::max(inbytesleft, size_t(4));
280 outbuf = reinterpret_cast<char*>(buf.getMoreBytes(howMany,
281 reinterpret_cast<Ice::Byte*>(outbuf)));
282 count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &howMany);
283 } while(count == size_t(-1) && errno == E2BIG);
284
285 if(count == size_t(-1))
286 {
287 throw Ice::IllegalConversionException(__FILE__, __LINE__,
288 errno == 0 ? "Unknown error" : IceUtilInternal::errorToString(errno));
289 }
290 return reinterpret_cast<Ice::Byte*>(outbuf);
291}
292
293template<typename charT> void
294IconvStringConverter<charT>::fromUTF8(const Ice::Byte* sourceStart, const Ice::Byte* sourceEnd,
295 std::basic_string<charT>& target) const
296{
297 iconv_t cd = getDescriptors().first;
298
299 //
300 // Reset cd
301 //
302#ifdef NDEBUG
303 iconv(cd, 0, 0, 0, 0);
304#else
305 size_t rs = iconv(cd, 0, 0, 0, 0);
306 assert(rs == 0);
307#endif
308
309#ifdef ICE_CONST_ICONV_INBUF
310 const char* inbuf = reinterpret_cast<const char*>(sourceStart);
311#else
312 char* inbuf = reinterpret_cast<char*>(const_cast<Ice::Byte*>(sourceStart));
313#endif
314 assert(sourceEnd > sourceStart);
315 size_t inbytesleft = static_cast<size_t>(sourceEnd - sourceStart);
316
317 char* outbuf = 0;
318 size_t outbytesleft = 0;
319 size_t count = 0;
320
321 //
322 // Loop while we need more buffer space
323 //
324 do
325 {
326 size_t bytesused = 0;
327 if(outbuf != 0)
328 {
329 bytesused = static_cast<size_t>(outbuf - reinterpret_cast<const char*>(target.data()));
330 }
331
332 const size_t increment = std::max<size_t>(inbytesleft, 4);
333 target.resize(target.size() + increment);
334 outbuf = const_cast<char*>(reinterpret_cast<const char*>(target.data())) + bytesused;
335 outbytesleft += increment * sizeof(charT);
336
337 count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
338
339 } while(count == size_t(-1) && errno == E2BIG);
340
341 if(count == size_t(-1))
342 {
343 throw Ice::IllegalConversionException(__FILE__, __LINE__,
344 errno == 0 ? "Unknown error" : IceUtilInternal::errorToString(errno));
345 }
346
347 target.resize(target.size() - (outbytesleft / sizeof(charT)));
348}
349}
350
351namespace Ice
352{
353
360template<typename charT>
362createIconvStringConverter(const std::string& internalCodeWithDefault = "")
363{
364 std::string internalCode = internalCodeWithDefault;
365
366 if(internalCode.empty())
367 {
368 internalCode = nl_langinfo(CODESET);
369 }
370
371 return ICE_MAKE_SHARED(IceInternal::IconvStringConverter<charT>, internalCode);
372}
373
374}
375
376#endif
377#endif
#define ICE_MAKE_SHARED(T,...)
Definition Config.h:376
#define ICE_HANDLE
Definition Config.h:373
#define ICE_API
Definition Config.h:197
A StringConverter converts narrow or wide-strings to and from UTF-8 byte sequences.
Definition StringConverter.h:50
Helper template for the implementation of Ice::Exception.
Definition Exception.h:161
std::string reason() const
Provides the reason this exception was thrown.
virtual Byte * getMoreBytes(size_t howMany, Byte *firstUnused)=0
Obtains more bytes.
virtual void ice_print(std::ostream &str) const
Prints a description of this exception to the given stream.
IconvInitializationException(const char *file, int line, const std::string &reason)
Constructs the exception with a reason.
virtual IconvInitializationException * ice_clone() const
Polymorphically clones this exception.
std::string reason() const
Obtains the reason for the failure.
virtual std::string ice_id() const
Obtains the Slice type ID of this exception.
Definition BuiltinSequences.h:113
IceUtil::IllegalConversionException IllegalConversionException
Indicates an error occurred during string conversion.
Definition StringConverter.h:27
unsigned char Byte
The mapping for the Slice byte type.
Definition Config.h:50
IceUtil::UTF8Buffer UTF8Buffer
Encapsulates bytes in the UTF-8 encoding.
Definition StringConverter.h:16
::IceUtil::Handle< IceUtil::BasicStringConverter< charT > > createIconvStringConverter(const std::string &internalCodeWithDefault="")
Creates a string converter for the given code.
Definition IconvStringConverter.h:362