// ********************************************************************** // // Copyright (c) 2003-2010 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 #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #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(static_cast(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(sourceEnd - sourceStart); if(sourceSize == 0) { return buffer.getMoreBytes(1, 0); } int size = 0; int writtenWchar = 0; ScopedArray 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 buffer; do { size = size == 0 ? static_cast(sourceEnd - sourceStart) + 2 : 2 * size; buffer.reset(new char[size]); writtenChar = WideCharToMultiByte(_cp, 0, wtarget.data(), static_cast(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* createIceStringConverter(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= 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(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; break; } case 1: { stringConverter = new IconvStringConverter(iconvArgs[0].c_str()); break; } case 2: { stringConverter = new IconvStringConverter(iconvArgs[0].c_str()); wstringConverter = new IconvStringConverter(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(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(str.data()), reinterpret_cast(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); }