diff options
-rwxr-xr-x | cpp/allTests.py | 4 | ||||
-rw-r--r-- | cpp/include/Ice/Ice.h | 4 | ||||
-rw-r--r-- | cpp/include/Ice/IconvStringConverter.h | 2 | ||||
-rwxr-xr-x | cpp/include/Ice/StringConverter.h | 29 | ||||
-rwxr-xr-x | cpp/src/Ice/StringConverter.cpp | 126 | ||||
-rw-r--r-- | cpp/test/Ice/Makefile.mak | 2 | ||||
-rw-r--r-- | cpp/test/Ice/stringConverter/Client.cpp | 27 | ||||
-rwxr-xr-x | cpp/test/Ice/stringConverter/Makefile.mak | 8 |
8 files changed, 185 insertions, 17 deletions
diff --git a/cpp/allTests.py b/cpp/allTests.py index b19e4510ddb..1394e3039af 100755 --- a/cpp/allTests.py +++ b/cpp/allTests.py @@ -94,6 +94,7 @@ tests = [ \ "Ice/servantLocator", \ "Ice/threads", \ "Ice/interceptor", \ + "Ice/stringConverter", \ "IceSSL/configuration", \ "Freeze/dbmap", \ "Freeze/complex", \ @@ -129,9 +130,6 @@ if isCygwin() == 0: tests += [ \ ] -if not isWin32() or os.getenv("ICONV_HOME") != None: - tests.insert(0, "Ice/stringConverter") - if isWin32(): tests.insert(0, "IceUtil/condvar") diff --git a/cpp/include/Ice/Ice.h b/cpp/include/Ice/Ice.h index 4d8f53a8703..85de61f222e 100644 --- a/cpp/include/Ice/Ice.h +++ b/cpp/include/Ice/Ice.h @@ -34,4 +34,8 @@ #include <Ice/Router.h> #include <Ice/DispatchInterceptor.h> +#ifndef _WIN32 +#include <Ice/IconvStringConverter.h> +#endif + #endif diff --git a/cpp/include/Ice/IconvStringConverter.h b/cpp/include/Ice/IconvStringConverter.h index 185a2bb4b8e..8b532c8739e 100644 --- a/cpp/include/Ice/IconvStringConverter.h +++ b/cpp/include/Ice/IconvStringConverter.h @@ -10,7 +10,7 @@ #ifndef ICE_ICONV_STRING_CONVERTER #define ICE_ICONV_STRING_CONVERTER -#include <Ice/Ice.h> +#include <Ice/StringConverter.h> #include <algorithm> #include <iconv.h> diff --git a/cpp/include/Ice/StringConverter.h b/cpp/include/Ice/StringConverter.h index d2aa1dffa7a..2b59c622e8b 100755 --- a/cpp/include/Ice/StringConverter.h +++ b/cpp/include/Ice/StringConverter.h @@ -70,11 +70,32 @@ class ICE_API UnicodeWstringConverter : public WstringConverter { public: - virtual Byte* toUTF8(const wchar_t* sourceStart, const wchar_t* sourceEnd, - UTF8Buffer&) const; + virtual Byte* toUTF8(const wchar_t*, const wchar_t*, UTF8Buffer&) const; - virtual void fromUTF8(const Byte* sourceStart, const Byte* sourceEnd, - std::wstring& target) const; + virtual void fromUTF8(const Byte*, const Byte*, std::wstring&) const; }; + +#ifdef _WIN32 + +// +// Converts to/from UTF-8 using MultiByteToWideChar and WideCharToMultiByte +// + +class ICE_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 + } #endif diff --git a/cpp/src/Ice/StringConverter.cpp b/cpp/src/Ice/StringConverter.cpp index 985111f9aa9..1d426877379 100755 --- a/cpp/src/Ice/StringConverter.cpp +++ b/cpp/src/Ice/StringConverter.cpp @@ -8,12 +8,49 @@ // ********************************************************************** #include <Ice/StringConverter.h> -#include <IceUtil/Unicode.h> +#include <IceUtil/IceUtil.h> #include <Ice/LocalException.h> using namespace IceUtil; using namespace std; + +#ifdef _WIN32 +namespace +{ +// +// Helper function +// + +string getMessageForLastError() +{ + LPVOID lpMsgBuf = 0; + DWORD ok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR)&lpMsgBuf, + 0, + NULL); + + string msg; + if(ok) + { + msg = (LPCTSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + } + else + { + msg = "Unknown Windows error"; + } + return msg; +} +} +#endif + + namespace Ice { @@ -64,6 +101,12 @@ void UnicodeWstringConverter::fromUTF8(const Byte* sourceStart, const Byte* sourceEnd, wstring& target) const { + if(sourceStart == sourceEnd) + { + target = L""; + return; + } + ConversionResult result = convertUTF8ToUTFWstring(sourceStart, sourceEnd, target, lenientConversion); @@ -82,4 +125,85 @@ UnicodeWstringConverter::fromUTF8(const Byte* sourceStart, const Byte* sourceEnd } } } + +#ifdef _WIN32 +WindowsStringConverter::WindowsStringConverter(unsigned int cp) : + _cp(cp) +{ +} + +Byte* +WindowsStringConverter::toUTF8(const char* sourceStart, + const char* sourceEnd, + UTF8Buffer& buffer) const +{ + // + // First convert to UTF-16 + // + int sourceSize = sourceEnd - sourceStart; + assert(sourceSize > 0); + + size_t size = 0; + int writtenWchar = 0; + IceUtil::ScopedArray<wchar_t> wbuffer; + do + { + size = size == 0 ? static_cast<size_t>(sourceSize) + 2 : 2 * size; + wbuffer.reset(new wchar_t[size]); + + writtenWchar = MultiByteToWideChar(_cp, MB_ERR_INVALID_CHARS, sourceStart, + sourceSize, wbuffer.get(), size); + } while(writtenWchar == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + if(writtenWchar == 0) + { + throw StringConversionException(__FILE__, __LINE__, getMessageForLastError()); + } + + // + // Then convert this UTF-16 wbuffer into UTF-8 + // + return _unicodeWstringConverter.toUTF8(wbuffer.get(), wbuffer.get() + writtenWchar, buffer); +} + +void +WindowsStringConverter::fromUTF8(const Byte* sourceStart, const Byte* sourceEnd, + string& target) const +{ + if(sourceStart == sourceEnd) + { + target = ""; + return; + } + + // + // First convert to wstring (UTF-16) + // + wstring wtarget; + _unicodeWstringConverter.fromUTF8(sourceStart, sourceEnd, wtarget); + + // + // And then to a multi-byte narrow string + // + size_t size = 0; + int writtenChar = 0; + IceUtil::ScopedArray<char> buffer; + do + { + size = size == 0 ? static_cast<size_t>(sourceEnd - sourceStart) + 2 : 2 * size; + buffer.reset(new char[size]); + writtenChar = WideCharToMultiByte(_cp, 0, wtarget.data(), wtarget.size(), + buffer.get(), size, 0, 0); + } while(writtenChar == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + if(writtenChar == 0) + { + throw StringConversionException(__FILE__, __LINE__, getMessageForLastError()); + } + + target.assign(buffer.get(), writtenChar); +} + +#endif + } diff --git a/cpp/test/Ice/Makefile.mak b/cpp/test/Ice/Makefile.mak index 77888312c28..dfe04be6621 100644 --- a/cpp/test/Ice/Makefile.mak +++ b/cpp/test/Ice/Makefile.mak @@ -32,9 +32,7 @@ SUBDIRS = proxy \ servantLocator \ threads \ interceptor \ -!if "$(ICONV_HOME)" != "" stringConverter -!endif $(EVERYTHING):: @for %i in ( $(SUBDIRS) ) do \ diff --git a/cpp/test/Ice/stringConverter/Client.cpp b/cpp/test/Ice/stringConverter/Client.cpp index 795535d6ece..8186e64151e 100644 --- a/cpp/test/Ice/stringConverter/Client.cpp +++ b/cpp/test/Ice/stringConverter/Client.cpp @@ -10,7 +10,14 @@ #include <Ice/Ice.h> #include <TestCommon.h> #include <Test.h> + +#if defined(ICONV_ON_WINDOWS) +// +// On Windows, Ice/IcongStringConverter.h is not included by Ice/Ice.h +// #include <Ice/IconvStringConverter.h> +#endif + #include <iostream> #include <locale.h> @@ -49,26 +56,34 @@ public: }; static bool useLocale = false; +static bool useIconv = true; int main(int argc, char* argv[]) { Client app; +#ifndef _WIN32 // // Switch to French locale // (we just used the codeset for as default internal code for // initData.stringConverter below) // - -#ifndef _WIN32 + useLocale = (setlocale(LC_ALL, "fr_FR.ISO8859-15") != 0 || setlocale(LC_ALL, "fr_FR.iso885915@euro") != 0); #endif Ice::InitializationData initData; -#if defined(__hpux) +#if defined(_WIN32) && !defined(ICONV_ON_WINDOWS) + // + // 28605 == ISO 8859-15 codepage + // + initData.stringConverter = new Ice::WindowsStringConverter(28605); + useIconv = false; + +#elif defined(__hpux) if(useLocale) { initData.stringConverter = new Ice::IconvStringConverter<char>; @@ -132,11 +147,15 @@ Client::run(int, char*[]) char oe = char(0xBD); // A single character in ISO Latin 9 string msg = string("tu me fends le c") + oe + "ur!"; - cout << "testing iconv string converter"; + cout << "testing string converter"; if(useLocale) { cout << " (using locale)"; } + if(useIconv) + { + cout << " (using iconv)"; + } cout << "..." << flush; wstring wmsg = clientPrx->widen(msg); test(clientPrx->narrow(wmsg) == msg); diff --git a/cpp/test/Ice/stringConverter/Makefile.mak b/cpp/test/Ice/stringConverter/Makefile.mak index adf6d97b850..5b266e2c656 100755 --- a/cpp/test/Ice/stringConverter/Makefile.mak +++ b/cpp/test/Ice/stringConverter/Makefile.mak @@ -19,14 +19,18 @@ SRCS = $(OBJS:.obj=.cpp) !include $(top_srcdir)/config/Make.rules.mak -CPPFLAGS = -I. -I../../include -I$(ICONV_HOME)/include $(CPPFLAGS) -DICE_NO_ERRNO -DWIN32_LEAN_AND_MEAN +CPPFLAGS = -I. -I../../include $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN +!if "$(ICONV_HOME)" != "" +CPPFLAGS = $(CPPFLAGS) -I$(ICONV_HOME)\include -DICONV_ON_WINDOWS -DICE_NO_ERRNO +LIBS = $(LIBS) -LIBPATH:$(ICONV_HOME)\lib $(ICONV_LIB) +!endif !if "$(CPP_COMPILER)" != "BCC2006" && "$(OPTIMIZE)" != "yes" PDBFLAGS = /pdb:$(CLIENT:.exe=.pdb) !endif $(CLIENT): $(OBJS) - $(LINK) $(LD_EXEFLAGS) $(PDBFLAGS) $(SETARGV) $(OBJS) $(PREOUT)$@ $(PRELIBS)$(LIBNAME) $(LIBS) /LIBPATH:$(ICONV_HOME)\lib $(ICONV_LIB) + $(LINK) $(LD_EXEFLAGS) $(PDBFLAGS) $(SETARGV) $(OBJS) $(PREOUT)$@ $(PRELIBS)$(LIBNAME) $(LIBS) @if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \ $(MT) -nologo -manifest $@.manifest -outputresource:$@;#1 && del /q $@.manifest |