summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/StringConverter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Ice/StringConverter.cpp')
-rw-r--r--cpp/src/Ice/StringConverter.cpp388
1 files changed, 388 insertions, 0 deletions
diff --git a/cpp/src/Ice/StringConverter.cpp b/cpp/src/Ice/StringConverter.cpp
new file mode 100644
index 00000000000..05de87a5d92
--- /dev/null
+++ b/cpp/src/Ice/StringConverter.cpp
@@ -0,0 +1,388 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 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.
+//
+// **********************************************************************
+
+#include <Ice/StringConverter.h>
+#include <IceUtil/IceUtil.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/ScopedArray.h>
+#include <Ice/Initialize.h>
+#include <Ice/Instance.h>
+#include <Ice/LocalException.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/Communicator.h>
+#ifndef _WIN32
+#include <Ice/IconvStringConverter.h>
+#endif
+
+using namespace IceUtil;
+using namespace IceUtilInternal;
+using namespace std;
+
+namespace Ice
+{
+
+UnicodeWstringConverter::UnicodeWstringConverter(ConversionFlags flags) :
+ _conversionFlags(flags)
+{
+}
+
+Byte*
+UnicodeWstringConverter::toUTF8(const wchar_t* sourceStart,
+ const wchar_t* sourceEnd,
+ UTF8Buffer& buffer) const
+{
+ //
+ // The "chunk size" is the maximum of the number of characters in the
+ // source and 6 (== max bytes necessary to encode one Unicode character).
+ //
+ size_t chunkSize = std::max<size_t>(static_cast<size_t>(sourceEnd - sourceStart), 6);
+
+ Byte* targetStart = buffer.getMoreBytes(chunkSize, 0);
+ Byte* targetEnd = targetStart + chunkSize;
+
+ ConversionResult result;
+
+ while((result =
+ convertUTFWstringToUTF8(sourceStart, sourceEnd,
+ targetStart, targetEnd, _conversionFlags))
+ == targetExhausted)
+ {
+ targetStart = buffer.getMoreBytes(chunkSize, targetStart);
+ targetEnd = targetStart + chunkSize;
+ }
+
+ switch(result)
+ {
+ case conversionOK:
+ break;
+ case sourceExhausted:
+ throw StringConversionException(__FILE__, __LINE__, "wide string source exhausted");
+ case sourceIllegal:
+ throw StringConversionException(__FILE__, __LINE__, "wide string source illegal");
+ default:
+ {
+ assert(0);
+ throw StringConversionException(__FILE__, __LINE__);
+ }
+ }
+ return targetStart;
+}
+
+
+void
+UnicodeWstringConverter::fromUTF8(const Byte* sourceStart, const Byte* sourceEnd,
+ wstring& target) const
+{
+ if(sourceStart == sourceEnd)
+ {
+ target = L"";
+ return;
+ }
+
+ ConversionResult result =
+ convertUTF8ToUTFWstring(sourceStart, sourceEnd, target, _conversionFlags);
+
+ switch(result)
+ {
+ case conversionOK:
+ break;
+ case sourceExhausted:
+ throw StringConversionException(__FILE__, __LINE__, "UTF-8 string source exhausted");
+ case sourceIllegal:
+ throw StringConversionException(__FILE__, __LINE__, "UTF-8 string source illegal");
+ default:
+ {
+ assert(0);
+ throw StringConversionException(__FILE__, __LINE__);
+ }
+ }
+}
+
+#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 = static_cast<int>(sourceEnd - sourceStart);
+ if(sourceSize == 0)
+ {
+ return buffer.getMoreBytes(1, 0);
+ }
+
+ int size = 0;
+ int writtenWchar = 0;
+ ScopedArray<wchar_t> wbuffer;
+ do
+ {
+ size = size == 0 ? 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__, IceUtilInternal::lastErrorToString());
+ }
+
+ //
+ // 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
+ //
+ int size = 0;
+ int writtenChar = 0;
+ ScopedArray<char> buffer;
+ do
+ {
+ size = size == 0 ? static_cast<int>(sourceEnd - sourceStart) + 2 : 2 * size;
+ buffer.reset(new char[size]);
+ writtenChar = WideCharToMultiByte(_cp, 0, wtarget.data(), static_cast<int>(wtarget.size()),
+ buffer.get(), size, 0, 0);
+ } while(writtenChar == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+
+ if(writtenChar == 0)
+ {
+ throw StringConversionException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
+ }
+
+ target.assign(buffer.get(), writtenChar);
+}
+
+#endif
+
+StringConverterPlugin::StringConverterPlugin(const CommunicatorPtr& communicator,
+ const StringConverterPtr& stringConverter,
+ const WstringConverterPtr& wstringConverter)
+{
+ if(communicator == 0)
+ {
+ throw PluginInitializationException(__FILE__, __LINE__, "Communicator cannot be null");
+ }
+
+ IceInternal::InstancePtr instance = IceInternal::getInstance(communicator);
+
+ if(stringConverter != 0)
+ {
+ instance->setStringConverter(stringConverter);
+ }
+ if(wstringConverter != 0)
+ {
+ instance->setWstringConverter(wstringConverter);
+ }
+}
+
+void
+StringConverterPlugin::initialize()
+{
+}
+
+void
+StringConverterPlugin::destroy()
+{
+}
+
+}
+
+//
+// The entry point for the "string converter" plug-in built-in the Ice library
+//
+extern "C"
+{
+
+using namespace Ice;
+
+ICE_DECLSPEC_EXPORT Plugin*
+createStringConverter(const CommunicatorPtr& communicator, const string& name, const StringSeq& args)
+{
+ StringConverterPtr stringConverter;
+ WstringConverterPtr wstringConverter;
+
+ if(args.size() > 2)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": too many arguments";
+ return 0;
+ }
+
+ try
+ {
+
+#ifdef _WIN32
+
+ int cp = -1;
+
+ for(size_t i = 0; i < args.size(); ++i)
+ {
+ if(args[i].find("windows=") == 0)
+ {
+ cp = atoi(args[i].substr(strlen("windows=")).c_str());
+ }
+ else if(args[i].find("iconv=") != 0)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": invalid \"" << args[i] << "\" argument";
+ return 0;
+ }
+ }
+
+ if(cp == -1)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": missing windows=<code page> argument";
+ return 0;
+ }
+
+ if(cp == 0 || cp == INT_MAX || cp < 0)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": invalid Windows code page";
+ return 0;
+ }
+
+ stringConverter = new WindowsStringConverter(static_cast<unsigned int>(cp));
+#else
+ StringSeq iconvArgs;
+
+ for(size_t i = 0; i < args.size(); ++i)
+ {
+ if(args[i].find("iconv=") == 0)
+ {
+ if(!IceUtilInternal::splitString(args[i].substr(strlen("iconv=")), ", \t\r\n", iconvArgs))
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": invalid iconv argument";
+ return 0;
+ }
+ }
+ else if(args[i].find("windows=") != 0)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": invalid \"" << args[i] << "\" argument";
+ return 0;
+ }
+ }
+
+ switch(iconvArgs.size())
+ {
+ case 0:
+ {
+ stringConverter = new IconvStringConverter<char>;
+ break;
+ }
+ case 1:
+ {
+ stringConverter = new IconvStringConverter<char>(iconvArgs[0].c_str());
+ break;
+ }
+ case 2:
+ {
+ stringConverter = new IconvStringConverter<char>(iconvArgs[0].c_str());
+ wstringConverter = new IconvStringConverter<wchar_t>(iconvArgs[1].c_str());
+ break;
+ }
+ default:
+ {
+ assert(0);
+ }
+ }
+
+#endif
+
+ return new StringConverterPlugin(communicator, stringConverter, wstringConverter);
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": creation failed with " << ex.what();
+ return 0;
+ }
+ catch(...)
+ {
+ Error out(communicator->getLogger());
+ out << "Plugin " << name << ": creation failed with unknown exception";
+ return 0;
+ }
+}
+}
+
+string
+Ice::nativeToUTF8(const Ice::StringConverterPtr& converter, const string& str)
+{
+ if(!converter)
+ {
+ return str;
+ }
+ if(str.empty())
+ {
+ return str;
+ }
+ IceInternal::UTF8BufferI buffer;
+ Ice::Byte* last = converter->toUTF8(str.data(), str.data() + str.size(), buffer);
+ return string(reinterpret_cast<const char*>(buffer.getBuffer()), last - buffer.getBuffer());
+}
+
+string
+Ice::nativeToUTF8(const Ice::CommunicatorPtr& ic, const string& str)
+{
+ return nativeToUTF8(IceInternal::getInstance(ic)->initializationData().stringConverter, str);
+}
+
+string
+Ice::UTF8ToNative(const Ice::StringConverterPtr& converter, const string& str)
+{
+ if(!converter)
+ {
+ return str;
+ }
+ if(str.empty())
+ {
+ return str;
+ }
+ string tmp;
+ converter->fromUTF8(reinterpret_cast<const Ice::Byte*>(str.data()),
+ reinterpret_cast<const Ice::Byte*>(str.data() + str.size()), tmp);
+ return tmp;
+}
+
+string
+Ice::UTF8ToNative(const Ice::CommunicatorPtr& ic, const std::string& str)
+{
+ return UTF8ToNative(IceInternal::getInstance(ic)->initializationData().stringConverter, str);
+}