diff options
Diffstat (limited to 'cpp/include/IceUtil')
-rw-r--r-- | cpp/include/IceUtil/Exception.h | 21 | ||||
-rw-r--r-- | cpp/include/IceUtil/FileUtil.h | 1 | ||||
-rw-r--r-- | cpp/include/IceUtil/IceUtil.h | 4 | ||||
-rw-r--r-- | cpp/include/IceUtil/IconvStringConverter.h | 302 | ||||
-rw-r--r-- | cpp/include/IceUtil/StringConverter.h | 193 | ||||
-rw-r--r-- | cpp/include/IceUtil/UndefSysMacros.h | 42 | ||||
-rw-r--r-- | cpp/include/IceUtil/Unicode.h | 7 |
7 files changed, 568 insertions, 2 deletions
diff --git a/cpp/include/IceUtil/Exception.h b/cpp/include/IceUtil/Exception.h index 2709b64ee31..b3dca7824d5 100644 --- a/cpp/include/IceUtil/Exception.h +++ b/cpp/include/IceUtil/Exception.h @@ -135,6 +135,27 @@ private: static const char* _name; }; +#ifndef _WIN32 +class ICE_UTIL_API IconvInitializationException : public Exception +{ +public: + + IconvInitializationException(const char*, int, const std::string&); + virtual ~IconvInitializationException() throw(); + virtual std::string ice_name() const; + virtual void ice_print(std::ostream&) const; + virtual IconvInitializationException* ice_clone() const; + virtual void ice_throw() const; + + std::string reason() const; + +private: + + static const char* _name; + std::string _reason; +}; +#endif + } #endif diff --git a/cpp/include/IceUtil/FileUtil.h b/cpp/include/IceUtil/FileUtil.h index 7cb2cd55407..7fabce927b9 100644 --- a/cpp/include/IceUtil/FileUtil.h +++ b/cpp/include/IceUtil/FileUtil.h @@ -70,6 +70,7 @@ ICE_UTIL_API int rmdir(const std::string&); ICE_UTIL_API int mkdir(const std::string&, int); ICE_UTIL_API FILE* fopen(const std::string&, const std::string&); +ICE_UTIL_API FILE* freopen(const std::string&, const std::string&, FILE*); ICE_UTIL_API int open(const std::string&, int); #ifndef ICE_OS_WINRT diff --git a/cpp/include/IceUtil/IceUtil.h b/cpp/include/IceUtil/IceUtil.h index cba2207c079..b5e126a34c2 100644 --- a/cpp/include/IceUtil/IceUtil.h +++ b/cpp/include/IceUtil/IceUtil.h @@ -41,4 +41,8 @@ #include <IceUtil/Unicode.h> #include <IceUtil/UniquePtr.h> +#ifndef _WIN32 +# include <IceUtil/IconvStringConverter.h> +#endif + #endif diff --git a/cpp/include/IceUtil/IconvStringConverter.h b/cpp/include/IceUtil/IconvStringConverter.h new file mode 100644 index 00000000000..e6bef3c6d82 --- /dev/null +++ b/cpp/include/IceUtil/IconvStringConverter.h @@ -0,0 +1,302 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_UTIL_ICONV_STRING_CONVERTER +#define ICE_UTIL_ICONV_STRING_CONVERTER + +#include <IceUtil/StringConverter.h> +#include <IceUtil/UndefSysMacros.h> + +#include <algorithm> +#include <iconv.h> +#include <langinfo.h> +#include <string.h> // For strerror + +#if (defined(__APPLE__) && _LIBICONV_VERSION < 0x010B) || defined(__FreeBSD__) + // + // See http://sourceware.org/bugzilla/show_bug.cgi?id=2962 + // +# define ICE_CONST_ICONV_INBUF 1 +#endif + +namespace IceUtil +{ + +// +// Converts charT encoded with internalCode to and from UTF-8 byte sequences +// +// The implementation allocates a pair of iconv_t on each thread, to avoid +// opening / closing iconv_t objects all the time. +// +// +template<typename charT> +class IconvStringConverter : public BasicStringConverter<charT> +{ +public: + + IconvStringConverter(const char* = nl_langinfo(CODESET)); + + virtual ~IconvStringConverter(); + + virtual Byte* toUTF8(const charT*, const charT*, UTF8Buffer&) const; + + virtual void fromUTF8(const Byte*, const Byte*, std::basic_string<charT>&) const; + +private: + + std::pair<iconv_t, iconv_t> createDescriptors() const; + std::pair<iconv_t, iconv_t> getDescriptors() const; + + static void cleanupKey(void*); + static void close(std::pair<iconv_t, iconv_t>); + + mutable pthread_key_t _key; + const std::string _internalCode; +}; + +// +// Implementation +// + +#ifdef __SUNPRO_CC +extern "C" +{ + typedef void (*IcePthreadKeyDestructor)(void*); +} +#endif + +template<typename charT> +IconvStringConverter<charT>::IconvStringConverter(const char* internalCode) : + _internalCode(internalCode) +{ + // + // Verify that iconv supports conversion to/from internalCode + // + try + { + close(createDescriptors()); + } + catch(const IllegalConversionException& sce) + { + throw IconvInitializationException(__FILE__, __LINE__, sce.reason()); + } + + // + // Create thread-specific key + // +#ifdef __SUNPRO_CC + int rs = pthread_key_create(&_key, reinterpret_cast<IcePthreadKeyDestructor>(&cleanupKey)); +#else + int rs = pthread_key_create(&_key, &cleanupKey); +#endif + + if(rs != 0) + { + throw ThreadSyscallException(__FILE__, __LINE__, rs); + } +} + +template<typename charT> +IconvStringConverter<charT>::~IconvStringConverter() +{ + void* val = pthread_getspecific(_key); + if(val != 0) + { + cleanupKey(val); + } + if(pthread_key_delete(_key) != 0) + { + assert(0); + } +} + +template<typename charT> std::pair<iconv_t, iconv_t> +IconvStringConverter<charT>::createDescriptors() const +{ + std::pair<iconv_t, iconv_t> cdp; + + const char* externalCode = "UTF-8"; + + cdp.first = iconv_open(_internalCode.c_str(), externalCode); + if(cdp.first == iconv_t(-1)) + { + std::ostringstream os; + os << "iconv cannot convert from " << externalCode << " to " << _internalCode; + throw IllegalConversionException(__FILE__, __LINE__, os.str()); + } + + cdp.second = iconv_open(externalCode, _internalCode.c_str()); + if(cdp.second == iconv_t(-1)) + { + iconv_close(cdp.first); + std::ostringstream os; + os << "iconv cannot convert from " << _internalCode << " to " << externalCode; + throw IllegalConversionException(__FILE__, __LINE__, os.str()); + } + return cdp; +} + +template<typename charT> std::pair<iconv_t, iconv_t> +IconvStringConverter<charT>::getDescriptors() const +{ + void* val = pthread_getspecific(_key); + if(val != 0) + { + return *static_cast<std::pair<iconv_t, iconv_t>*>(val); + } + else + { + std::pair<iconv_t, iconv_t> cdp = createDescriptors(); + int rs = pthread_setspecific(_key, new std::pair<iconv_t, iconv_t>(cdp)); + if(rs != 0) + { + throw ThreadSyscallException(__FILE__, __LINE__, rs); + } + return cdp; + } +} + +template<typename charT> /*static*/ void +IconvStringConverter<charT>::cleanupKey(void* val) +{ + std::pair<iconv_t, iconv_t>* cdp = static_cast<std::pair<iconv_t, iconv_t>*>(val); + + close(*cdp); + delete cdp; +} + +template<typename charT> /*static*/ void +IconvStringConverter<charT>::close(std::pair<iconv_t, iconv_t> cdp) +{ +#ifndef NDEBUG + int rs = iconv_close(cdp.first); + assert(rs == 0); + + rs = iconv_close(cdp.second); + assert(rs == 0); +#else + iconv_close(cdp.first); + iconv_close(cdp.second); +#endif +} + +template<typename charT> Byte* +IconvStringConverter<charT>::toUTF8(const charT* sourceStart, const charT* sourceEnd, UTF8Buffer& buf) const +{ + iconv_t cd = getDescriptors().second; + + // + // Reset cd + // +#ifdef NDEBUG + iconv(cd, 0, 0, 0, 0); +#else + size_t rs = iconv(cd, 0, 0, 0, 0); + assert(rs == 0); +#endif + +#ifdef ICE_CONST_ICONV_INBUF + const char* inbuf = reinterpret_cast<const char*>(sourceStart); +#else + char* inbuf = reinterpret_cast<char*>(const_cast<charT*>(sourceStart)); +#endif + size_t inbytesleft = (sourceEnd - sourceStart) * sizeof(charT); + char* outbuf = 0; + + size_t count = 0; + // + // Loop while we need more buffer space + // + do + { + size_t howMany = std::max(inbytesleft, size_t(4)); + outbuf = reinterpret_cast<char*>(buf.getMoreBytes(howMany, reinterpret_cast<Byte*>(outbuf))); + count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &howMany); + } while(count == size_t(-1) && errno == E2BIG); + + if(count == size_t(-1)) + { + throw IllegalConversionException(__FILE__, __LINE__, errno != 0 ? strerror(errno) : "Unknown error"); + } + return reinterpret_cast<Byte*>(outbuf); +} + +template<typename charT> void +IconvStringConverter<charT>::fromUTF8(const Byte* sourceStart, const Byte* sourceEnd, + std::basic_string<charT>& target) const +{ + iconv_t cd = getDescriptors().first; + + // + // Reset cd + // +#ifdef NDEBUG + iconv(cd, 0, 0, 0, 0); +#else + size_t rs = iconv(cd, 0, 0, 0, 0); + assert(rs == 0); +#endif + +#ifdef ICE_CONST_ICONV_INBUF + const char* inbuf = reinterpret_cast<const char*>(sourceStart); +#else + char* inbuf = reinterpret_cast<char*>(const_cast<Byte*>(sourceStart)); +#endif + size_t inbytesleft = sourceEnd - sourceStart; + + // + // Result buffer + // + char* buf = 0; + size_t bufsize = 0; + + char* outbuf = 0; + size_t outbytesleft = 0; + + size_t count = 0; + + // + // Loop while we need more buffer space + // + do + { + size_t increment = std::max(inbytesleft * sizeof(wchar_t), size_t(8)); + bufsize += increment; + char* newbuf = static_cast<char*>(realloc(buf, bufsize)); + + if(newbuf == 0) + { + free(buf); + throw IllegalConversionException(__FILE__, __LINE__, "Out of memory"); + } + + outbuf = newbuf + (outbuf - buf); + outbytesleft += increment; + + buf = newbuf; + + count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + } while(count == size_t(-1) && errno == E2BIG); + + if(count == size_t(-1)) + { + free(buf); + throw IllegalConversionException(__FILE__, __LINE__, errno != 0 ? strerror(errno) : "Unknown error"); + } + + size_t length = (bufsize - outbytesleft) / sizeof(charT); + + std::basic_string<charT> result(reinterpret_cast<charT*>(buf), length); + target.swap(result); + free(buf); +} + +} + +#endif diff --git a/cpp/include/IceUtil/StringConverter.h b/cpp/include/IceUtil/StringConverter.h new file mode 100644 index 00000000000..b3e8d62f2b7 --- /dev/null +++ b/cpp/include/IceUtil/StringConverter.h @@ -0,0 +1,193 @@ +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_UTIL_STRING_CONVERTER_H +#define ICE_UTIL_STRING_CONVERTER_H + +#include <IceUtil/Config.h> +#include <IceUtil/Exception.h> +#include <IceUtil/Shared.h> +#include <IceUtil/Handle.h> +#include <IceUtil/Unicode.h> + +#include <string> + +namespace IceUtil +{ + +// +// Raised by string converters when an encoding converseion fails. +// +class ICE_UTIL_API IllegalConversionException : public ::IceUtil::Exception +{ +public: + + IllegalConversionException(const char*, int); + IllegalConversionException(const char*, int, const ::std::string&); + virtual ~IllegalConversionException() throw(); + + virtual ::std::string ice_name() const; + virtual void ice_print(::std::ostream&) const; + virtual IllegalConversionException* ice_clone() const; + virtual void ice_throw() const; + + std::string reason() const; + +private: + + std::string _reason; +}; + +// +// Provides bytes to toUTF8. Raises MemoryLimitException when too many +// bytes are requested. +// +class ICE_UTIL_API UTF8Buffer +{ +public: + virtual Byte* getMoreBytes(size_t howMany, Byte* firstUnused) = 0; + + virtual ~UTF8Buffer() {} +}; + +// +// A StringConverter converts narrow or wide-strings to and from UTF-8 byte sequences. +// It's used by the communicator during marshaling (toUTF8) and unmarshaling (fromUTF8). +// It report errors by raising IllegalConversionException or MemoryLimitException. +// +template<typename charT> +class BasicStringConverter : public IceUtil::Shared +{ +public: + // + // Returns a pointer to byte after the last written byte (which may be + // past the last byte returned by getMoreBytes). + // + virtual Byte* toUTF8(const charT* sourceStart, const charT* sourceEnd, + UTF8Buffer&) const = 0; + + // + // Unmarshals a UTF-8 sequence into a basic_string + // + virtual void fromUTF8(const Byte* sourceStart, const Byte* sourceEnd, + std::basic_string<charT>& target) const = 0; +}; + +typedef BasicStringConverter<char> StringConverter; +typedef IceUtil::Handle<StringConverter> StringConverterPtr; + +typedef BasicStringConverter<wchar_t> WstringConverter; +typedef IceUtil::Handle<WstringConverter> WstringConverterPtr; + +// +// Converts to and from UTF-16 or UTF-32 depending on sizeof(wchar_t) +// +class ICE_UTIL_API UnicodeWstringConverter : public WstringConverter +{ +public: + + UnicodeWstringConverter(ConversionFlags = lenientConversion); + + virtual Byte* toUTF8(const wchar_t*, const wchar_t*, UTF8Buffer&) const; + + virtual void fromUTF8(const Byte*, const Byte*, std::wstring&) const; + +private: + const ConversionFlags _conversionFlags; +}; + +#ifdef _WIN32 + +// +// Converts to/from UTF-8 using MultiByteToWideChar and WideCharToMultiByte +// +class ICE_UTIL_API WindowsStringConverter : public StringConverter +{ +public: + + explicit WindowsStringConverter(unsigned int); + + virtual Byte* toUTF8(const char*, const char*, UTF8Buffer&) const; + + virtual void fromUTF8(const Byte*, const Byte*, std::string& target) const; + +private: + unsigned int _cp; + UnicodeWstringConverter _unicodeWstringConverter; +}; +#endif + +// +// Retrive the per process narrow string converter. Access to the +// converter is protected by a static mutex. +// +ICE_UTIL_API StringConverterPtr getProcessStringConverter(); + +// +// Set the per process narrow string converter. Access to the +// converter is protected by a static mutex. +// +ICE_UTIL_API void setProcessStringConverter(const StringConverterPtr&); + +// +// Retrive the per process wide string converter. Access to the +// converter is protected by a static mutex. +// +ICE_UTIL_API WstringConverterPtr getProcessWstringConverter(); + +// +// Set the per process wide string converter. Access to the +// converter is protected by a static mutex. +// +ICE_UTIL_API void setProcessWstringConverter(const WstringConverterPtr&); + +// +// Convert the given wide string from the native wide string encoding to a +// narrow string with the native narrow string encoding. +// +// The StringConverter param can be null in that case the default narrow +// string encoding is assumed to be UTF8. +// +// The WstringConverter param can be null in that case the default wide +// string encoding is assumed, that would be UTF16 or UTF32 depending of +// the platform. +// +ICE_UTIL_API std::string +wnativeToNative(const StringConverterPtr&, const WstringConverterPtr&, const std::wstring&); + +// +// Convert the given narrow string from the native narrow string encoding +// to a wide string with the native wide string encoding. +// +// The StringConverter param can be null in that case the default narrow +// string encoding is assumed to be UTF8. +// +// The WstringConverter param can be null in that case the default wide +// string encoding is assumed, that would be UTF16 or UTF32 depending of +// the platform. +// +ICE_UTIL_API std::wstring +nativeToWnative(const StringConverterPtr&, const WstringConverterPtr&, const std::string&); + +// +// Converts the given string from the native narrow string encoding to +// UTF8 using the given converter. If the converter is null, returns +// the given string. +// +ICE_UTIL_API std::string +nativeToUTF8(const StringConverterPtr&, const std::string&); + +// +// Converts the given string from UTF8 to the native narrow string +// encoding using the given converter. If the converter is null, +// returns the given string. +// +ICE_UTIL_API std::string +UTF8ToNative(const StringConverterPtr&, const std::string&); + +} + +#endif diff --git a/cpp/include/IceUtil/UndefSysMacros.h b/cpp/include/IceUtil/UndefSysMacros.h new file mode 100644 index 00000000000..2dc931daf08 --- /dev/null +++ b/cpp/include/IceUtil/UndefSysMacros.h @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_UTIL_UNDEF_SYS_MACROS_H +#define ICE_UTIL_UNDEF_SYS_MACROS_H + +// +// This header includes macros that can end up being dragged into +// the generated code from system headers, such as major() or NDEBUG. +// If a Slice symbol has the same name as a macro, the generated +// code most likely won't compile (but, depending how the macro is +// defined, may even compile). +// +// Here, we undefine symbols that cause such problems. +// +// The #ifdef ... #endif protection is necessary to prevent +// warnings on some platforms. +// + +#ifdef major +#undef major +#endif + +#ifdef minor +#undef minor +#endif + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#endif diff --git a/cpp/include/IceUtil/Unicode.h b/cpp/include/IceUtil/Unicode.h index 40f002fa545..71a52b3e62f 100644 --- a/cpp/include/IceUtil/Unicode.h +++ b/cpp/include/IceUtil/Unicode.h @@ -22,8 +22,11 @@ enum ConversionFlags lenientConversion }; -ICE_UTIL_API std::string wstringToString(const std::wstring&, ConversionFlags = lenientConversion); -ICE_UTIL_API std::wstring stringToWstring(const std::string&, ConversionFlags = lenientConversion); +ICE_DEPRECATED_API std::string +wstringToString(const std::wstring&, ConversionFlags = lenientConversion); + +ICE_DEPRECATED_API std::wstring +stringToWstring(const std::string&, ConversionFlags = lenientConversion); typedef unsigned char Byte; |