diff options
author | Bernard Normier <bernard@zeroc.com> | 2016-10-20 21:03:44 -0400 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2016-10-20 21:03:44 -0400 |
commit | 3cb9c15995b828c52dba34d0a222f572d5bbc41b (patch) | |
tree | 87bad249c2ee04972be5f3c7635880cb0c556128 | |
parent | updating IceBT to BlueZ 5 (diff) | |
download | ice-3cb9c15995b828c52dba34d0a222f572d5bbc41b.tar.bz2 ice-3cb9c15995b828c52dba34d0a222f572d5bbc41b.tar.xz ice-3cb9c15995b828c52dba34d0a222f572d5bbc41b.zip |
Added support for non-ASCII characters and universal character names
to stringified identities and proxies.
This includes a new Ice.ToStringMode property.
154 files changed, 2736 insertions, 1145 deletions
diff --git a/CHANGELOG-3.7.md b/CHANGELOG-3.7.md index 53995449484..c9770fabf4e 100644 --- a/CHANGELOG-3.7.md +++ b/CHANGELOG-3.7.md @@ -26,7 +26,7 @@ These are the changes since Ice 3.6.3. As a result, the Ice::DispatchStatus enumeration has been removed. See the Ice manual for details on the new dispatch interceptor API. -- The ice_getConnection() method now correctly returns a connection if +- The ice_getConnection() method now correctly returns a connection if connection caching is disabled (it previously returned a null connection). - The iOS SSL transport is now based on the same implementation as macOS. Most @@ -82,10 +82,14 @@ These are the changes since Ice 3.6.3. - Updating Windows build system to use MSBuild instead of nmake. -- Changed the parsing of hex escape sequences (\x....) in Slice string literals: - the parsing now stops after 2 hex digits. For example, \x0ab is now read as '\x0a' +- Changed the parsing of hex escape sequences (\x....) in Slice string literals: + the parsing now stops after 2 hex digits. For example, \x0ab is now read as '\x0a' followed by 'b'. Previously all the hex digits where read like in C++. +- Stringified identities and proxies now support non-ASCII characters + and universal character names (\unnnn and \Unnnnnnnn). See the property + Ice.ToStringMode and the static function/method identityToString. + ## Java Changes - Fixed a bug where unmarshaling Ice objects was really slow when using diff --git a/config/PropertyNames.xml b/config/PropertyNames.xml index 615fdd86c63..2e1f222005c 100644 --- a/config/PropertyNames.xml +++ b/config/PropertyNames.xml @@ -383,6 +383,7 @@ generated from the section label. <property name="ThreadPool.Client" class="threadpool" /> <property name="ThreadPool.Server" class="threadpool" /> <property name="ThreadPriority"/> + <property name="ToStringMode" /> <property name="Trace.Admin.Properties" /> <property name="Trace.Admin.Logger" /> <property name="Trace.Locator" /> diff --git a/config/makeprops.py b/config/makeprops.py index 015c4815260..127eea661a3 100755 --- a/config/makeprops.py +++ b/config/makeprops.py @@ -102,6 +102,13 @@ cppSrcPreamble = commonPreamble + """ """ javaPreamble = commonPreamble + """ +package com.zeroc.IceInternal; + +public final class %(classname)s +{ +""" + +javaCompatPreamble = commonPreamble + """ package IceInternal; public final class %(classname)s @@ -129,7 +136,7 @@ module.exports.Ice = Ice; def usage(): global progname - print >> sys.stderr, "Usage: " + progname + " [--{cpp|java|cs|js} file]" + print >> sys.stderr, "Usage: " + progname + " [--{cpp|java|java-compat|csharp|js} file]" def progError(msg): global progname @@ -456,11 +463,26 @@ class JavaPropertyHandler(PropertyHandler): self.srcFile.write(" };\n\n") def moveFiles(self, location): - dest = os.path.join(location, "java", "src", "Ice", "src", "main", "java", "IceInternal") + dest = os.path.join(location, "java", "src", "Ice", "src", "main", "java", "com", "zeroc", "IceInternal") + if os.path.exists(os.path.join(dest, self.className + ".java")): + os.remove(os.path.join(dest, self.className + ".java")) + shutil.move(self.className + ".java", dest) + +class JavaCompatPropertyHandler(JavaPropertyHandler): + def __init__(self, inputfile, c): + JavaPropertyHandler.__init__(self, inputfile, c) + + def startFiles(self): + self.srcFile = file(self.className + ".java", "wb") + self.srcFile.write(javaCompatPreamble % {'inputfile' : self.inputfile, 'classname' : self.className}) + + def moveFiles(self, location): + dest = os.path.join(location, "java-compat", "src", "Ice", "src", "main", "java", "IceInternal") if os.path.exists(os.path.join(dest, self.className + ".java")): os.remove(os.path.join(dest, self.className + ".java")) shutil.move(self.className + ".java", dest) + class CSPropertyHandler(PropertyHandler): def __init__(self, inputfile, c): PropertyHandler.__init__(self, inputfile, c) @@ -677,6 +699,8 @@ def main(): lang = "cpp" elif option == "--java": lang = "java" + elif option == "--java-compat": + lang = "java-compat" elif option == "--csharp": lang = "csharp" elif option == "--js": @@ -695,6 +719,7 @@ def main(): contentHandler = MultiHandler(infile, "") contentHandler.addHandlers([CppPropertyHandler(infile, className), JavaPropertyHandler(infile, className), + JavaCompatPropertyHandler(infile, className), CSPropertyHandler(infile, className), JSPropertyHandler(infile, className)]) else: @@ -702,6 +727,8 @@ def main(): contentHandler = CppPropertyHandler(infile, className) elif lang == "java": contentHandler = JavaPropertyHandler(infile, className) + elif lang == "java-compat": + contentHandler = JavaCompatPropertyHandler(infile, className) elif lang == "csharp": contentHandler = CSPropertyHandler(infile, className) elif lang == "js": diff --git a/cpp/include/Ice/Initialize.h b/cpp/include/Ice/Initialize.h index f64a62db13b..bbf822dff0a 100644 --- a/cpp/include/Ice/Initialize.h +++ b/cpp/include/Ice/Initialize.h @@ -11,7 +11,7 @@ #define ICE_INITIALIZE_H #include <IceUtil/Timer.h> -#include <Ice/CommunicatorF.h> +#include <Ice/Communicator.h> #include <Ice/PropertiesF.h> #include <Ice/InstanceF.h> #include <Ice/LoggerF.h> @@ -152,7 +152,8 @@ private: }; ICE_API Identity stringToIdentity(const std::string&); -ICE_API std::string identityToString(const Identity&); +ICE_API std::string identityToString(const Identity&, ToStringMode = ICE_ENUM(ToStringMode, Unicode)); + } namespace IceInternal diff --git a/cpp/include/IceUtil/StringUtil.h b/cpp/include/IceUtil/StringUtil.h index 2e0763e7a46..71497f558b5 100644 --- a/cpp/include/IceUtil/StringUtil.h +++ b/cpp/include/IceUtil/StringUtil.h @@ -7,8 +7,8 @@ // // ********************************************************************** -#ifndef ICE_STRING_UTIL_H -#define ICE_STRING_UTIL_H +#ifndef ICE_UTIL_STRING_UTIL_H +#define ICE_UTIL_STRING_UTIL_H #include <IceUtil/Config.h> #include <vector> @@ -17,10 +17,21 @@ namespace IceUtilInternal { // -// Add escape sequences (like "\n", or "\0xxx") to make a string -// readable in ASCII. +// Must be kept in sync with Ice::ToStringMode // -ICE_API std::string escapeString(const std::string&, const std::string&); +#ifdef ICE_CPP11_MAPPING +enum class ToStringMode : unsigned char +#else +enum ToStringMode +#endif +{ Unicode, ASCII, Compat }; + +// +// Add escape sequences (like "\n", or "\123") to the input string +// (first parameter). +// The second parameter adds characters to escape, and can be empty. +// +ICE_API std::string escapeString(const std::string&, const std::string&, ToStringMode); // // Remove escape sequences added by escapeString. Throws IllegalArgumentException @@ -35,7 +46,7 @@ ICE_API std::string unescapeString(const std::string&, std::string::size_type, s ICE_API bool splitString(const std::string&, const std::string&, std::vector<std::string>&); // -// Join a list of strings using the given delimiter. +// Join a list of strings using the given delimiter. // ICE_API std::string joinString(const std::vector<std::string>&, const std::string&); diff --git a/cpp/src/Glacier2/Blobject.cpp b/cpp/src/Glacier2/Blobject.cpp index 4b822469c81..1f58da34ffb 100644 --- a/cpp/src/Glacier2/Blobject.cpp +++ b/cpp/src/Glacier2/Blobject.cpp @@ -261,7 +261,7 @@ Glacier2::Blobject::invoke(ObjectPrx& proxy, const AMD_Object_ice_invokePtr& amd } if(_reverseConnection) { - out << "\nidentity = " << identityToString(proxy->ice_getIdentity()); + out << "\nidentity = " << _instance->communicator()->identityToString(proxy->ice_getIdentity()); } else { @@ -310,7 +310,7 @@ Glacier2::Blobject::invoke(ObjectPrx& proxy, const AMD_Object_ice_invokePtr& amd out << "routing override"; if(_reverseConnection) { - out << "\nidentity = " << identityToString(proxy->ice_getIdentity()); + out << "\nidentity = " << _instance->communicator()->identityToString(proxy->ice_getIdentity()); } else { diff --git a/cpp/src/Glacier2/ClientBlobject.cpp b/cpp/src/Glacier2/ClientBlobject.cpp index f10c3d614b8..d7aef4ae401 100644 --- a/cpp/src/Glacier2/ClientBlobject.cpp +++ b/cpp/src/Glacier2/ClientBlobject.cpp @@ -120,7 +120,7 @@ Glacier2::ClientBlobject::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr& { Trace out(_instance->logger(), "Glacier2"); out << "rejecting request: " << rejectedFilters << "\n"; - out << "identity: " << identityToString(current.id); + out << "identity: " << _instance->communicator()->identityToString(current.id); } ObjectNotExistException ex(__FILE__, __LINE__); diff --git a/cpp/src/Glacier2/FilterManager.cpp b/cpp/src/Glacier2/FilterManager.cpp index 95c52f9633a..7457367f0b9 100644 --- a/cpp/src/Glacier2/FilterManager.cpp +++ b/cpp/src/Glacier2/FilterManager.cpp @@ -34,7 +34,7 @@ stringToSeq(const string& str, vector<string>& seq) } static void -stringToSeq(const CommunicatorPtr& comm, const string& str, vector<Identity>& seq) +stringToSeq(const string& str, vector<Identity>& seq) { string const ws = " \t"; @@ -214,7 +214,7 @@ Glacier2::FilterManager::create(const InstancePtr& instance, const string& userI // IdentitySeq allowIdSeq; allow = props->getProperty("Glacier2.Filter.Identity.Accept"); - stringToSeq(instance->communicator(), allow, allowIdSeq); + stringToSeq(allow, allowIdSeq); Glacier2::IdentitySetIPtr identityFilter = new Glacier2::IdentitySetI(allowIdSeq); return new Glacier2::FilterManager(instance, categoryFilter, adapterIdFilter, identityFilter); diff --git a/cpp/src/Glacier2/Instance.h b/cpp/src/Glacier2/Instance.h index 65b0e70a848..ed1fd76f3ba 100644 --- a/cpp/src/Glacier2/Instance.h +++ b/cpp/src/Glacier2/Instance.h @@ -44,7 +44,7 @@ public: const Glacier2::Instrumentation::RouterObserverPtr& getObserver() const { return _observer; } void destroy(); - + private: friend class SessionRouterI; diff --git a/cpp/src/Glacier2/SessionRouterI.cpp b/cpp/src/Glacier2/SessionRouterI.cpp index 91b5e05db6f..9f774b79a8e 100644 --- a/cpp/src/Glacier2/SessionRouterI.cpp +++ b/cpp/src/Glacier2/SessionRouterI.cpp @@ -1150,7 +1150,7 @@ SessionRouterI::getRouterImpl(const ConnectionPtr& connection, const Ice::Identi { Trace out(_instance->logger(), "Glacier2"); out << "rejecting request. no session is associated with the connection.\n"; - out << "identity: " << identityToString(id); + out << "identity: " << _instance->communicator()->identityToString(id); } connection->close(true); throw ObjectNotExistException(__FILE__, __LINE__); diff --git a/cpp/src/Glacier2Lib/NullPermissionsVerifier.cpp b/cpp/src/Glacier2Lib/NullPermissionsVerifier.cpp index 31d33ad00a4..abc76a3b6e8 100644 --- a/cpp/src/Glacier2Lib/NullPermissionsVerifier.cpp +++ b/cpp/src/Glacier2Lib/NullPermissionsVerifier.cpp @@ -111,12 +111,12 @@ Init::checkPermissionVerifier(const string& val) // check if it's actually a stringified identity // (with typically missing " " because the category contains a space) - if(val == identityToString(_nullPVId)) + if(val == _communicator->identityToString(_nullPVId)) { createObjects(); return _adapter->createProxy(_nullPVId)->ice_toString(); // Return valid proxy to rewrite the property } - else if(val == identityToString(_nullSSLPVId)) + else if(val == _communicator->identityToString(_nullSSLPVId)) { createObjects(); return _adapter->createProxy(_nullSSLPVId)->ice_toString(); // Return valid proxy to rewrite the property diff --git a/cpp/src/Glacier2Lib/SessionHelper.cpp b/cpp/src/Glacier2Lib/SessionHelper.cpp index 34565f357e4..5a6c9354ae1 100644 --- a/cpp/src/Glacier2Lib/SessionHelper.cpp +++ b/cpp/src/Glacier2Lib/SessionHelper.cpp @@ -1215,7 +1215,9 @@ string Glacier2::SessionFactoryHelper::createProxyStr(const Ice::Identity& ident) { ostringstream os; - os << "\"" << Ice::identityToString(ident) << "\":" << _protocol << " -p " << getPortInternal() << " -h \"" << _routerHost << "\""; + os << "\"" << identityToString(ident, Ice::ICE_ENUM(ToStringMode, Unicode)) << "\":" << _protocol + << " -p " << getPortInternal() << " -h \"" << _routerHost << "\""; + if(_timeout > 0) { os << " -t " << _timeout; diff --git a/cpp/src/Ice/CommunicatorI.cpp b/cpp/src/Ice/CommunicatorI.cpp index 8a257ede66b..99c332f629e 100644 --- a/cpp/src/Ice/CommunicatorI.cpp +++ b/cpp/src/Ice/CommunicatorI.cpp @@ -89,7 +89,7 @@ Ice::CommunicatorI::stringToIdentity(const string& s) const string Ice::CommunicatorI::identityToString(const Identity& ident) const { - return Ice::identityToString(ident); + return Ice::identityToString(ident, _instance->toStringMode()); } ObjectAdapterPtr diff --git a/cpp/src/Ice/Exception.cpp b/cpp/src/Ice/Exception.cpp index 7e2fc340c9d..95136f5339a 100644 --- a/cpp/src/Ice/Exception.cpp +++ b/cpp/src/Ice/Exception.cpp @@ -14,6 +14,7 @@ #include <Ice/SlicedData.h> #include <Ice/OutputStream.h> #include <Ice/InputStream.h> +#include <Ice/Initialize.h> #include <IceUtil/StringUtil.h> #ifdef ICE_OS_WINRT # include <Ice/StringConverter.h> @@ -339,16 +340,7 @@ void Ice::IllegalIdentityException::ice_print(ostream& out) const { Exception::ice_print(out); - out << ":\nillegal identity: `"; - if(id.category.empty()) - { - out << IceUtilInternal::escapeString(id.name, "/"); - } - else - { - out << IceUtilInternal::escapeString(id.category, "/") << '/' << IceUtilInternal::escapeString(id.name, "/"); - } - out << "'"; + out << ":\nillegal identity: `" << identityToString(id, ICE_ENUM(ToStringMode, Unicode)) << "'"; } void @@ -362,16 +354,7 @@ Ice::IllegalServantException::ice_print(ostream& out) const static void printFailedRequestData(ostream& out, const RequestFailedException& ex) { - out << ":\nidentity: `"; - if(ex.id.category.empty()) - { - out << IceUtilInternal::escapeString(ex.id.name, "/"); - } - else - { - out << IceUtilInternal::escapeString(ex.id.category, "/") << '/' << IceUtilInternal::escapeString(ex.id.name, "/"); - } - out << "'"; + out << ":\nidentity: `" << identityToString(ex.id, ICE_ENUM(ToStringMode, Unicode)) << "'"; out << "\nfacet: " << ex.facet; out << "\noperation: " << ex.operation; } diff --git a/cpp/src/Ice/Incoming.cpp b/cpp/src/Ice/Incoming.cpp index 7b5e6741660..da4bb25cbc6 100644 --- a/cpp/src/Ice/Incoming.cpp +++ b/cpp/src/Ice/Incoming.cpp @@ -22,7 +22,7 @@ #include <Ice/Protocol.h> #include <Ice/ReplyStatus.h> #include <Ice/ResponseHandler.h> -#include <IceUtil/StringUtil.h> +#include <Ice/StringUtil.h> #include <typeinfo> using namespace std; @@ -222,9 +222,12 @@ IceInternal::IncomingBase::warning(const Exception& ex) const { Warning out(_os.instance()->initializationData().logger); + ToStringMode toStringMode = _os.instance()->toStringMode(); + out << "dispatch exception: " << ex; - out << "\nidentity: " << Ice::identityToString(_current.id); - out << "\nfacet: " << IceUtilInternal::escapeString(_current.facet, ""); + out << "\nidentity: " << identityToString(_current.id, toStringMode); + out << "\nfacet: "; + out << escapeString(_current.facet, "", toStringMode); out << "\noperation: " << _current.operation; if(_current.con) @@ -252,10 +255,11 @@ void IceInternal::IncomingBase::warning(const string& msg) const { Warning out(_os.instance()->initializationData().logger); + ToStringMode toStringMode = _os.instance()->toStringMode(); out << "dispatch exception: " << msg; - out << "\nidentity: " << Ice::identityToString(_current.id); - out << "\nfacet: " << IceUtilInternal::escapeString(_current.facet, ""); + out << "\nidentity: " << identityToString(_current.id, toStringMode); + out << "\nfacet: " << escapeString(_current.facet, "", toStringMode); out << "\noperation: " << _current.operation; if(_current.con) diff --git a/cpp/src/Ice/Initialize.cpp b/cpp/src/Ice/Initialize.cpp index 52f03678659..f1f92c3826d 100644 --- a/cpp/src/Ice/Initialize.cpp +++ b/cpp/src/Ice/Initialize.cpp @@ -16,7 +16,7 @@ #include <Ice/LoggerI.h> #include <Ice/Instance.h> #include <Ice/PluginManagerI.h> -#include <IceUtil/StringUtil.h> +#include <Ice/StringUtil.h> #include <IceUtil/Mutex.h> #include <IceUtil/MutexPtrLock.h> #include <Ice/StringConverter.h> @@ -357,15 +357,6 @@ IceInternal::getInstanceTimer(const CommunicatorPtr& communicator) Identity Ice::stringToIdentity(const string& s) { - // - // This method only accepts printable ascii. Since printable ascii is a subset - // of all narrow string encodings, it is not necessary to convert the string - // from the native string encoding. Any characters other than printable-ASCII - // will cause an IllegalArgumentException. Note that it can contain Unicode - // encoded in the escaped form which is the reason why we call fromUTF8 after - // unespcaping the printable ASCII string. - // - Identity ident; // @@ -376,7 +367,7 @@ Ice::stringToIdentity(const string& s) while((pos = s.find('/', pos)) != string::npos) { int escapes = 0; - while(static_cast<int>(pos)- escapes > 0 && s[pos - escapes - 1] == '\\') + while(static_cast<int>(pos) - escapes > 0 && s[pos - escapes - 1] == '\\') { escapes++; } @@ -396,7 +387,7 @@ Ice::stringToIdentity(const string& s) // Extra unescaped slash found. // IdentityParseException ex(__FILE__, __LINE__); - ex.str = "unescaped backslash in identity `" + s + "'"; + ex.str = "unescaped '/' in identity `" + s + "'"; throw ex; } } @@ -407,7 +398,7 @@ Ice::stringToIdentity(const string& s) { try { - ident.name = IceUtilInternal::unescapeString(s, 0, s.size()); + ident.name = unescapeString(s, 0, s.size()); } catch(const IceUtil::IllegalArgumentException& e) { @@ -420,7 +411,7 @@ Ice::stringToIdentity(const string& s) { try { - ident.category = IceUtilInternal::unescapeString(s, 0, slash); + ident.category = unescapeString(s, 0, slash); } catch(const IceUtil::IllegalArgumentException& e) { @@ -428,11 +419,12 @@ Ice::stringToIdentity(const string& s) ex.str = "invalid category in identity `" + s + "': " + e.reason(); throw ex; } + if(slash + 1 < s.size()) { try { - ident.name = IceUtilInternal::unescapeString(s, slash + 1, s.size()); + ident.name = unescapeString(s, slash + 1, s.size()); } catch(const IceUtil::IllegalArgumentException& e) { @@ -443,28 +435,18 @@ Ice::stringToIdentity(const string& s) } } - ident.name = UTF8ToNative(ident.name, getProcessStringConverter()); - ident.category = UTF8ToNative(ident.category, getProcessStringConverter()); - return ident; } string -Ice::identityToString(const Identity& ident) +Ice::identityToString(const Identity& ident, ToStringMode toStringMode) { - // - // This method returns the stringified identity. The returned string only - // contains printable ascii. It can contain UTF8 in the escaped form. - // - string name = nativeToUTF8(ident.name, getProcessStringConverter()); - string category = nativeToUTF8(ident.category, getProcessStringConverter()); - - if(category.empty()) + if(ident.category.empty()) { - return IceUtilInternal::escapeString(name, "/"); + return escapeString(ident.name, "/", toStringMode); } else { - return IceUtilInternal::escapeString(category, "/") + '/' + IceUtilInternal::escapeString(name, "/"); + return escapeString(ident.category, "/", toStringMode) + '/' + escapeString(ident.name, "/", toStringMode); } } diff --git a/cpp/src/Ice/Instance.cpp b/cpp/src/Ice/Instance.cpp index d99567e09f9..304036dec90 100644 --- a/cpp/src/Ice/Instance.cpp +++ b/cpp/src/Ice/Instance.cpp @@ -948,6 +948,7 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi _messageSizeMax(0), _batchAutoFlushSize(0), _collectObjects(false), + _toStringMode(ICE_ENUM(ToStringMode, Unicode)), _implicitContext(0), _stringConverter(Ice::getProcessStringConverter()), _wstringConverter(Ice::getProcessWstringConverter()), @@ -1189,6 +1190,21 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi const_cast<bool&>(_collectObjects) = _initData.properties->getPropertyAsInt("Ice.CollectObjects") > 0; + string toStringModeStr = _initData.properties->getPropertyWithDefault("Ice.ToStringMode", "Unicode"); + if(toStringModeStr == "ASCII") + { + const_cast<ToStringMode&>(_toStringMode) = ICE_ENUM(ToStringMode, ASCII); + } + else if(toStringModeStr == "Compat") + { + const_cast<ToStringMode&>(_toStringMode) = ICE_ENUM(ToStringMode, Compat); + } + else if(toStringModeStr != "Unicode") + { + throw InitializationException(__FILE__, __LINE__, "The value for Ice.ToStringMode must be Unicode, ASCII or Compat"); + } + + // // Client ACM enabled by default. Server ACM disabled by default. // diff --git a/cpp/src/Ice/Instance.h b/cpp/src/Ice/Instance.h index 22a39169c38..2e4fd503b16 100644 --- a/cpp/src/Ice/Instance.h +++ b/cpp/src/Ice/Instance.h @@ -110,6 +110,7 @@ public: size_t messageSizeMax() const { return _messageSizeMax; } size_t batchAutoFlushSize() const { return _batchAutoFlushSize; } bool collectObjects() const { return _collectObjects; } + Ice::ToStringMode toStringMode() const { return _toStringMode; } const ACMConfig& clientACM() const; const ACMConfig& serverACM() const; @@ -177,6 +178,7 @@ private: const size_t _messageSizeMax; // Immutable, not reset by destroy(). const size_t _batchAutoFlushSize; // Immutable, not reset by destroy(). const bool _collectObjects; // Immutable, not reset by destroy(). + const Ice::ToStringMode _toStringMode; // Immutable, not reset by destroy() ACMConfig _clientACM; ACMConfig _serverACM; RouterManagerPtr _routerManager; diff --git a/cpp/src/Ice/InstrumentationI.cpp b/cpp/src/Ice/InstrumentationI.cpp index 64ff4f91e07..0f816647a11 100644 --- a/cpp/src/Ice/InstrumentationI.cpp +++ b/cpp/src/Ice/InstrumentationI.cpp @@ -334,7 +334,7 @@ public: string getIdentity() const { - return identityToString(_current.id); + return _current.adapter->getCommunicator()->identityToString(_current.id); } private: @@ -443,7 +443,7 @@ public: catch(const Exception&) { // Either a fixed proxy or the communicator is destroyed. - os << identityToString(_proxy->ice_getIdentity()); + os << _proxy->ice_getCommunicator()->identityToString(_proxy->ice_getIdentity()); os << " [" << _operation << ']'; } } @@ -474,7 +474,7 @@ public: { if(_proxy) { - return identityToString(_proxy->ice_getIdentity()); + return _proxy->ice_getCommunicator()->identityToString(_proxy->ice_getIdentity()); } else { diff --git a/cpp/src/Ice/LocatorInfo.cpp b/cpp/src/Ice/LocatorInfo.cpp index 03264b5898c..74f65e2d808 100644 --- a/cpp/src/Ice/LocatorInfo.cpp +++ b/cpp/src/Ice/LocatorInfo.cpp @@ -785,12 +785,13 @@ IceInternal::LocatorInfo::getEndpointsException(const ReferencePtr& ref, const I Trace out(ref->getInstance()->initializationData().logger, ref->getInstance()->traceLevels()->locationCat); out << "object not found" << "\n"; - out << "object = " << Ice::identityToString(ref->getIdentity()); + out << "object = " << Ice::identityToString(ref->getIdentity(), + ref->getInstance()->toStringMode()); } NotRegisteredException ex(__FILE__, __LINE__); ex.kindOfObject = "object"; - ex.id = Ice::identityToString(ref->getIdentity()); + ex.id = Ice::identityToString(ref->getIdentity(), ref->getInstance()->toStringMode()); throw ex; } catch(const NotRegisteredException&) @@ -805,7 +806,8 @@ IceInternal::LocatorInfo::getEndpointsException(const ReferencePtr& ref, const I out << "couldn't contact the locator to retrieve adapter endpoints\n"; if(ref->getAdapterId().empty()) { - out << "object = " << Ice::identityToString(ref->getIdentity()) << "\n"; + out << "object = " << Ice::identityToString(ref->getIdentity(), ref->getInstance()->toStringMode()) + << "\n"; } else { @@ -840,7 +842,7 @@ IceInternal::LocatorInfo::getEndpointsTrace(const ReferencePtr& ref, if(ref->getAdapterId().empty()) { out << "object\n"; - out << "object = " << Ice::identityToString(ref->getIdentity()); + out << "object = " << Ice::identityToString(ref->getIdentity(), ref->getInstance()->toStringMode()); } else { @@ -863,7 +865,8 @@ IceInternal::LocatorInfo::trace(const string& msg, const ReferencePtr& ref, cons } else { - out << "object = " << Ice::identityToString(ref->getIdentity()) << '\n'; + out << "object = " << Ice::identityToString(ref->getIdentity(), ref->getInstance()->toStringMode()) + << '\n'; } const char* sep = endpoints.size() > 1 ? ":" : ""; @@ -901,7 +904,8 @@ IceInternal::LocatorInfo::getObjectRequest(const ReferencePtr& ref) if(ref->getInstance()->traceLevels()->location >= 1) { Trace out(ref->getInstance()->initializationData().logger, ref->getInstance()->traceLevels()->locationCat); - out << "searching for object by id\nobject = " << Ice::identityToString(ref->getIdentity()); + out << "searching for object by id\nobject = " << Ice::identityToString(ref->getIdentity(), + ref->getInstance()->toStringMode()); } map<Ice::Identity, RequestPtr>::const_iterator p = _objectRequests.find(ref->getIdentity()); diff --git a/cpp/src/Ice/ObjectAdapterI.cpp b/cpp/src/Ice/ObjectAdapterI.cpp index 18cc2dd87f0..0631186769d 100644 --- a/cpp/src/Ice/ObjectAdapterI.cpp +++ b/cpp/src/Ice/ObjectAdapterI.cpp @@ -682,7 +682,7 @@ Ice::ObjectAdapterI::getEndpoints() const EndpointSeq endpoints; transform(_incomingConnectionFactories.begin(), _incomingConnectionFactories.end(), - back_inserter(endpoints), + back_inserter(endpoints), #ifdef ICE_CPP11_MAPPING [](const IncomingConnectionFactoryPtr& factory) { @@ -1020,8 +1020,9 @@ Ice::ObjectAdapterI::initialize(const RouterPrxPtr& router) // if(_routerInfo->getAdapter()) { - throw AlreadyRegisteredException(__FILE__, __LINE__, "object adapter with router", - Ice::identityToString(router->ice_getIdentity())); + throw AlreadyRegisteredException(__FILE__, __LINE__, + "object adapter with router", + _communicator->identityToString(router->ice_getIdentity())); } // diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp index c1a1cde9335..1bf95a2df3b 100644 --- a/cpp/src/Ice/PropertyNames.cpp +++ b/cpp/src/Ice/PropertyNames.cpp @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 5 19:04:47 2016 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Tue Oct 18 11:38:00 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -163,6 +163,7 @@ const IceInternal::Property IcePropsData[] = IceInternal::Property("Ice.ThreadPool.Server.ThreadIdleTime", false, 0), IceInternal::Property("Ice.ThreadPool.Server.ThreadPriority", false, 0), IceInternal::Property("Ice.ThreadPriority", false, 0), + IceInternal::Property("Ice.ToStringMode", false, 0), IceInternal::Property("Ice.Trace.Admin.Properties", false, 0), IceInternal::Property("Ice.Trace.Admin.Logger", false, 0), IceInternal::Property("Ice.Trace.Locator", false, 0), diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h index 52e12f92225..e9c85a1e59f 100644 --- a/cpp/src/Ice/PropertyNames.h +++ b/cpp/src/Ice/PropertyNames.h @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 5 19:04:47 2016 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Tue Oct 18 11:38:00 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! diff --git a/cpp/src/Ice/Reference.cpp b/cpp/src/Ice/Reference.cpp index 86328e0880a..12296b9f04f 100644 --- a/cpp/src/Ice/Reference.cpp +++ b/cpp/src/Ice/Reference.cpp @@ -28,8 +28,8 @@ #include <Ice/ConnectionRequestHandler.h> #include <Ice/DefaultsAndOverrides.h> #include <Ice/Comparable.h> +#include <Ice/StringUtil.h> -#include <IceUtil/StringUtil.h> #include <IceUtil/Random.h> #include <IceUtil/MutexPtrLock.h> @@ -231,13 +231,18 @@ IceInternal::Reference::toString() const // ostringstream s; + ToStringMode toStringMode = _instance->toStringMode(); + const string separators = " :@"; + + string id = Ice::identityToString(_identity, toStringMode); + // // If the encoded identity string contains characters which // the reference parser uses as separators, then we enclose // the identity string in quotes. // - string id = Ice::identityToString(_identity); - if(id.find_first_of(" :@") != string::npos) + + if(id.find_first_of(separators) != string::npos) { s << '"' << id << '"'; } @@ -250,14 +255,13 @@ IceInternal::Reference::toString() const { s << " -f "; + string fs = escapeString(fs, "", toStringMode); // // If the encoded facet string contains characters which // the reference parser uses as separators, then we enclose // the facet string in quotes. // - string fs = nativeToUTF8(_facet, _instance->getStringConverter()); - fs = IceUtilInternal::escapeString(fs, ""); - if(fs.find_first_of(" :@") != string::npos) + if(fs.find_first_of(separators) != string::npos) { s << '"' << fs << '"'; } @@ -1224,8 +1228,7 @@ IceInternal::RoutableReference::toString() const // reference parser uses as separators, then we enclose the // adapter id string in quotes. // - string a = nativeToUTF8(_adapterId, getInstance()->getStringConverter()); - a = IceUtilInternal::escapeString(a, ""); + string a = escapeString(_adapterId, "", getInstance()->toStringMode()); if(a.find_first_of(" :@") != string::npos) { result.append("\""); diff --git a/cpp/src/Ice/ReferenceFactory.cpp b/cpp/src/Ice/ReferenceFactory.cpp index 3788324d81d..63b8df7effe 100644 --- a/cpp/src/Ice/ReferenceFactory.cpp +++ b/cpp/src/Ice/ReferenceFactory.cpp @@ -24,7 +24,7 @@ #include <Ice/Properties.h> #include <Ice/DefaultsAndOverrides.h> #include <Ice/PropertyNames.h> -#include <IceUtil/StringUtil.h> +#include <Ice/StringUtil.h> using namespace std; using namespace Ice; @@ -156,6 +156,7 @@ IceInternal::ReferenceFactory::create(const string& str, const string& propertyP // Parsing the identity may raise IdentityParseException. // Identity ident = Ice::stringToIdentity(idstr); + if(ident.name.empty()) { // @@ -279,7 +280,7 @@ IceInternal::ReferenceFactory::create(const string& str, const string& propertyP try { - facet = IceUtilInternal::unescapeString(argument, 0, argument.size()); + facet = unescapeString(argument, 0, argument.size()); } catch(const IceUtil::IllegalArgumentException& e) { @@ -288,7 +289,6 @@ IceInternal::ReferenceFactory::create(const string& str, const string& propertyP throw ex; } - facet = UTF8ToNative(facet, _instance->getStringConverter()); break; } @@ -554,7 +554,7 @@ IceInternal::ReferenceFactory::create(const string& str, const string& propertyP try { - adapter = IceUtilInternal::unescapeString(adapterstr, 0, adapterstr.size()); + adapter = unescapeString(adapterstr, 0, adapterstr.size()); } catch(const IceUtil::IllegalArgumentException& e) { @@ -569,8 +569,6 @@ IceInternal::ReferenceFactory::create(const string& str, const string& propertyP throw ex; } - adapter = UTF8ToNative(adapter, _instance->getStringConverter()); - return create(ident, facet, mode, secure, protocol, encoding, endpoints, adapter, propertyPrefix); break; } @@ -934,4 +932,3 @@ IceInternal::ReferenceFactory::create(const Identity& ident, invocationTimeout, ctx); } - diff --git a/cpp/src/Ice/ServantManager.cpp b/cpp/src/Ice/ServantManager.cpp index 3d1f51112ae..16c5da45d1f 100644 --- a/cpp/src/Ice/ServantManager.cpp +++ b/cpp/src/Ice/ServantManager.cpp @@ -12,7 +12,7 @@ #include <Ice/LocalException.h> #include <Ice/LoggerUtil.h> #include <Ice/Instance.h> -#include <IceUtil/StringUtil.h> +#include <Ice/StringUtil.h> using namespace std; using namespace Ice; @@ -44,11 +44,11 @@ IceInternal::ServantManager::addServant(const ObjectPtr& object, const Identity& { AlreadyRegisteredException ex(__FILE__, __LINE__); ex.kindOfObject = "servant"; - ex.id = Ice::identityToString(ident); + ToStringMode toStringMode = _instance->toStringMode(); + ex.id = Ice::identityToString(ident, toStringMode); if(!facet.empty()) { - string fs = nativeToUTF8(facet, _instance->getStringConverter()); - ex.id += " -f " + IceUtilInternal::escapeString(fs, ""); + ex.id += " -f " + escapeString(facet, "", toStringMode); } throw ex; } @@ -104,11 +104,11 @@ IceInternal::ServantManager::removeServant(const Identity& ident, const string& { NotRegisteredException ex(__FILE__, __LINE__); ex.kindOfObject = "servant"; - ex.id = Ice::identityToString(ident); + ToStringMode toStringMode = _instance->toStringMode(); + ex.id = Ice::identityToString(ident, toStringMode); if(!facet.empty()) { - string fs = nativeToUTF8(facet, _instance->getStringConverter()); - ex.id += " -f " + IceUtilInternal::escapeString(fs, ""); + ex.id += " -f " + escapeString(facet, "", toStringMode); } throw ex; } @@ -178,7 +178,7 @@ IceInternal::ServantManager::removeAllFacets(const Identity& ident) { NotRegisteredException ex(__FILE__, __LINE__); ex.kindOfObject = "servant"; - ex.id = Ice::identityToString(ident); + ex.id = Ice::identityToString(ident, _instance->toStringMode()); throw ex; } diff --git a/cpp/src/Ice/StringUtil.h b/cpp/src/Ice/StringUtil.h new file mode 100644 index 00000000000..70dab65bf88 --- /dev/null +++ b/cpp/src/Ice/StringUtil.h @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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_STRING_UTIL_H +#define ICE_STRING_UTIL_H + +#include <Ice/Initialize.h> +#include <IceUtil/StringUtil.h> + +namespace IceInternal +{ + +// +// Adapter for ToStringMode +// +inline std::string +escapeString(const std::string& s, const std::string& special, Ice::ToStringMode mode) +{ + return IceUtilInternal::escapeString(s, special, static_cast<IceUtilInternal::ToStringMode>(mode)); +} + +// +// Provided for consistency with escapeString +// +using IceUtilInternal::unescapeString; + +} + +#endif diff --git a/cpp/src/Ice/TraceUtil.cpp b/cpp/src/Ice/TraceUtil.cpp index 5e92c6c05d5..db7c0041b45 100644 --- a/cpp/src/Ice/TraceUtil.cpp +++ b/cpp/src/Ice/TraceUtil.cpp @@ -9,7 +9,7 @@ #include <IceUtil/Mutex.h> #include <IceUtil/MutexPtrLock.h> -#include <IceUtil/StringUtil.h> +#include <Ice/StringUtil.h> #include <Ice/TraceUtil.h> #include <Ice/Instance.h> #include <Ice/Object.h> @@ -29,16 +29,22 @@ using namespace IceInternal; static void printIdentityFacetOperation(ostream& s, InputStream& stream) { + ToStringMode toStringMode = ICE_ENUM(ToStringMode, Unicode); + if(stream.instance()) + { + toStringMode = stream.instance()->toStringMode(); + } + Identity identity; stream.read(identity); - s << "\nidentity = " << Ice::identityToString(identity); + s << "\nidentity = " << Ice::identityToString(identity, toStringMode); vector<string> facet; stream.read(facet); s << "\nfacet = "; if(!facet.empty()) { - s << IceUtilInternal::escapeString(facet[0], ""); + s << escapeString(facet[0], "", toStringMode); } string operation; diff --git a/cpp/src/IceBox/Admin.cpp b/cpp/src/IceBox/Admin.cpp index bf7fa5d5a05..c7c76bac161 100644 --- a/cpp/src/IceBox/Admin.cpp +++ b/cpp/src/IceBox/Admin.cpp @@ -116,7 +116,7 @@ Client::run(int argc, char* argv[]) return EXIT_FAILURE; } - managerProxy = "\"" + identityToString(managerIdentity) + "\" :" + managerEndpoints; + managerProxy = "\"" + communicator()->identityToString(managerIdentity) + "\" :" + managerEndpoints; } else { @@ -127,7 +127,7 @@ Client::run(int argc, char* argv[]) return EXIT_FAILURE; } - managerProxy = "\"" + identityToString(managerIdentity) + "\" @" + managerAdapterId; + managerProxy = "\"" + communicator()->identityToString(managerIdentity) + "\" @" + managerAdapterId; } base = communicator()->stringToProxy(managerProxy); diff --git a/cpp/src/IceGrid/AdminI.cpp b/cpp/src/IceGrid/AdminI.cpp index 60af9f7b2df..21e190250e5 100644 --- a/cpp/src/IceGrid/AdminI.cpp +++ b/cpp/src/IceGrid/AdminI.cpp @@ -688,7 +688,7 @@ AdminI::updateObject(const Ice::ObjectPrx& proxy, const ::Ice::Current&) if(id.category == _database->getInstanceName()) { DeploymentException ex; - ex.reason = "updating object `" + identityToString(id) + "' is not allowed:\n"; + ex.reason = "updating object `" + _database->getCommunicator()->identityToString(id) + "' is not allowed:\n"; ex.reason += "objects with identity category `" + id.category + "' are managed by IceGrid"; throw ex; } @@ -709,7 +709,7 @@ AdminI::addObjectWithType(const Ice::ObjectPrx& proxy, const string& type, const if(id.category == _database->getInstanceName()) { DeploymentException ex; - ex.reason = "adding object `" + identityToString(id) + "' is not allowed:\n"; + ex.reason = "adding object `" + _database->getCommunicator()->identityToString(id) + "' is not allowed:\n"; ex.reason += "objects with identity category `" + id.category + "' are managed by IceGrid"; throw ex; } @@ -727,7 +727,7 @@ AdminI::removeObject(const Ice::Identity& id, const Ice::Current&) if(id.category == _database->getInstanceName()) { DeploymentException ex; - ex.reason = "removing object `" + identityToString(id) + "' is not allowed:\n"; + ex.reason = "removing object `" + _database->getCommunicator()->identityToString(id) + "' is not allowed:\n"; ex.reason += "objects with identity category `" + id.category + "' are managed by IceGrid"; throw ex; } diff --git a/cpp/src/IceGrid/AllocatableObjectCache.cpp b/cpp/src/IceGrid/AllocatableObjectCache.cpp index ae3294bb51c..3a9799e1eac 100644 --- a/cpp/src/IceGrid/AllocatableObjectCache.cpp +++ b/cpp/src/IceGrid/AllocatableObjectCache.cpp @@ -134,7 +134,7 @@ AllocatableObjectCache::add(const ObjectInfo& info, const AllocatablePtr& parent if(getImpl(id)) { Ice::Error out(_communicator->getLogger()); - out << "can't add duplicate allocatable object `" << identityToString(id) << "'"; + out << "can't add duplicate allocatable object `" << _communicator->identityToString(id) << "'"; return; } @@ -151,7 +151,7 @@ AllocatableObjectCache::add(const ObjectInfo& info, const AllocatablePtr& parent if(_traceLevels && _traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "added allocatable object `" << identityToString(id) << "'"; + out << "added allocatable object `" << _communicator->identityToString(id) << "'"; } } @@ -177,7 +177,7 @@ AllocatableObjectCache::remove(const Ice::Identity& id) if(!entry) { Ice::Error out(_communicator->getLogger()); - out << "can't remove unknown object `" << identityToString(id) << "'"; + out << "can't remove unknown object `" << _communicator->identityToString(id) << "'"; } removeImpl(id); @@ -191,7 +191,7 @@ AllocatableObjectCache::remove(const Ice::Identity& id) if(_traceLevels && _traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "removed allocatable object `" << identityToString(id) << "'"; + out << "removed allocatable object `" << _communicator->identityToString(id) << "'"; } } diff --git a/cpp/src/IceGrid/Database.cpp b/cpp/src/IceGrid/Database.cpp index 694d59c073d..5c9167b784d 100644 --- a/cpp/src/IceGrid/Database.cpp +++ b/cpp/src/IceGrid/Database.cpp @@ -1483,7 +1483,7 @@ Database::addObject(const ObjectInfo& info) if(_traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "added object `" << identityToString(id) << "' (serial = `" << dbSerial << "')"; + out << "added object `" << _communicator->identityToString(id) << "' (serial = `" << dbSerial << "')"; } } _objectObserverTopic->waitForSyncedSubscribers(serial); @@ -1539,7 +1539,7 @@ Database::addOrUpdateObject(const ObjectInfo& info, Ice::Long dbSerial) if(_traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << (!update ? "added" : "updated") << " object `" << identityToString(id) << "' (serial = `" << dbSerial << "')"; + out << (!update ? "added" : "updated") << " object `" << _communicator->identityToString(id) << "' (serial = `" << dbSerial << "')"; } } _objectObserverTopic->waitForSyncedSubscribers(serial); @@ -1556,7 +1556,7 @@ Database::removeObject(const Ice::Identity& id, Ice::Long dbSerial) if(_objectCache.has(id)) { DeploymentException ex; - ex.reason = "removing object `" + identityToString(id) + "' is not allowed:\n"; + ex.reason = "removing object `" + _communicator->identityToString(id) + "' is not allowed:\n"; ex.reason += "the object was added with the application descriptor `"; ex.reason += _objectCache.get(id)->getApplication(); ex.reason += "'"; @@ -1590,7 +1590,7 @@ Database::removeObject(const Ice::Identity& id, Ice::Long dbSerial) if(_traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "removed object `" << identityToString(id) << "' (serial = `" << dbSerial << "')"; + out << "removed object `" << _communicator->identityToString(id) << "' (serial = `" << dbSerial << "')"; } } _objectObserverTopic->waitForSyncedSubscribers(serial); @@ -1609,7 +1609,7 @@ Database::updateObject(const Ice::ObjectPrx& proxy) if(_objectCache.has(id)) { DeploymentException ex; - ex.reason = "updating object `" + identityToString(id) + "' is not allowed:\n"; + ex.reason = "updating object `" + _communicator->identityToString(id) + "' is not allowed:\n"; ex.reason += "the object was added with the application descriptor `"; ex.reason += _objectCache.get(id)->getApplication(); ex.reason += "'"; @@ -1644,7 +1644,7 @@ Database::updateObject(const Ice::ObjectPrx& proxy) if(_traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "updated object `" << identityToString(id) << "' (serial = `" << dbSerial << "')"; + out << "updated object `" << _communicator->identityToString(id) << "' (serial = `" << dbSerial << "')"; } } _objectObserverTopic->waitForSyncedSubscribers(serial); @@ -1833,7 +1833,7 @@ Database::getAllObjectInfos(const string& expression) ObjectsMapROCursor cursor(_objects, txn); while(cursor.get(id, info, MDB_NEXT)) { - if(expression.empty() || IceUtilInternal::match(identityToString(id), expression, true)) + if(expression.empty() || IceUtilInternal::match(_communicator->identityToString(id), expression, true)) { infos.push_back(info); } @@ -2089,7 +2089,7 @@ Database::checkObjectForAddition(const Ice::Identity& objectId, if(found) { DeploymentException ex; - ex.reason = "object `" + identityToString(objectId) + "' is already registered"; + ex.reason = "object `" + _communicator->identityToString(objectId) + "' is already registered"; throw ex; } } @@ -2761,7 +2761,7 @@ Database::addObject(const IceDB::ReadWriteTxn& txn, const ObjectInfo& info, bool catch(const IceDB::KeyTooLongException& ex) { throw DeploymentException("object identity `" + - identityToString(info.proxy->ice_getIdentity()) + _communicator->identityToString(info.proxy->ice_getIdentity()) + "' is too long: " + ex.what()); } try diff --git a/cpp/src/IceGrid/DescriptorHelper.cpp b/cpp/src/IceGrid/DescriptorHelper.cpp index 7e1a531dbb5..3eef14ff351 100644 --- a/cpp/src/IceGrid/DescriptorHelper.cpp +++ b/cpp/src/IceGrid/DescriptorHelper.cpp @@ -650,11 +650,11 @@ Ice::Identity Resolver::operator()(const Ice::Identity& value, const string& name) const { assert(_communicator); - string str = asId(identityToString(value), name, false); + string str = asId(_communicator->identityToString(value), name, false); Ice::Identity id = Ice::stringToIdentity(str); if(id.name.empty()) { - exception("invalid object identity `" + identityToString(value) + "': name empty"); + exception("invalid object identity `" + _communicator->identityToString(value) + "': name empty"); } return id; } @@ -1387,7 +1387,7 @@ CommunicatorHelper::printObjectAdapter(const Ice::CommunicatorPtr& communicator, { out << nl << "well-known object"; out << sb; - out << nl << "identity = `" << identityToString(p->id) << "' "; + out << nl << "identity = `" << communicator->identityToString(p->id) << "' "; if(!p->type.empty()) { out << nl << "type = `" << p->type << "'"; @@ -1402,7 +1402,7 @@ CommunicatorHelper::printObjectAdapter(const Ice::CommunicatorPtr& communicator, { out << nl << "allocatable"; out << sb; - out << nl << "identity = `" << identityToString(p->id) << "' "; + out << nl << "identity = `" << communicator->identityToString(p->id) << "' "; if(!p->type.empty()) { out << nl << "type = `" << p->type << "'"; @@ -2825,7 +2825,7 @@ ApplicationHelper::ApplicationHelper(const Ice::CommunicatorPtr& communicator, { if(objectIds.count(*o) > 1) { - resolve.exception("duplicate object `" + identityToString(*o) + "'"); + resolve.exception("duplicate object `" + _communicator->identityToString(*o) + "'"); } } } diff --git a/cpp/src/IceGrid/ObjectCache.cpp b/cpp/src/IceGrid/ObjectCache.cpp index 9d7138e7050..cc76cc2d9b7 100644 --- a/cpp/src/IceGrid/ObjectCache.cpp +++ b/cpp/src/IceGrid/ObjectCache.cpp @@ -82,7 +82,7 @@ ObjectCache::add(const ObjectInfo& info, const string& application) if(getImpl(id)) { Ice::Error out(_communicator->getLogger()); - out << "can't add duplicate object `" << identityToString(id) << "'"; + out << "can't add duplicate object `" << _communicator->identityToString(id) << "'"; return; } @@ -99,7 +99,7 @@ ObjectCache::add(const ObjectInfo& info, const string& application) if(_traceLevels && _traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "added object `" << identityToString(id) << "'"; + out << "added object `" << _communicator->identityToString(id) << "'"; } } @@ -123,7 +123,7 @@ ObjectCache::remove(const Ice::Identity& id) if(!entry) { Ice::Error out(_communicator->getLogger()); - out << "can't remove unknown object `" << identityToString(id) << "'"; + out << "can't remove unknown object `" << _communicator->identityToString(id) << "'"; return; } removeImpl(id); @@ -138,7 +138,7 @@ ObjectCache::remove(const Ice::Identity& id) if(_traceLevels && _traceLevels->object > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->objectCat); - out << "removed object `" << identityToString(id) << "'"; + out << "removed object `" << _communicator->identityToString(id) << "'"; } } @@ -167,7 +167,7 @@ ObjectCache::getAll(const string& expression) ObjectInfoSeq infos; for(map<Ice::Identity, ObjectEntryPtr>::const_iterator p = _entries.begin(); p != _entries.end(); ++p) { - if(expression.empty() || IceUtilInternal::match(identityToString(p->first), expression, true)) + if(expression.empty() || IceUtilInternal::match(_communicator->identityToString(p->first), expression, true)) { infos.push_back(p->second->getObjectInfo()); } diff --git a/cpp/src/IceGrid/Parser.cpp b/cpp/src/IceGrid/Parser.cpp index 30f80de48c7..7a88d5247a6 100644 --- a/cpp/src/IceGrid/Parser.cpp +++ b/cpp/src/IceGrid/Parser.cpp @@ -2100,7 +2100,7 @@ Parser::removeObject(const list<string>& args) try { - _admin->removeObject(stringToIdentity((*(args.begin())))); + _admin->removeObject(Ice::stringToIdentity((*(args.begin())))); } catch(const Ice::Exception& ex) { @@ -2148,7 +2148,7 @@ Parser::describeObject(const list<string>& args) string arg = *(args.begin()); if(arg.find('*') == string::npos) { - ObjectInfo info = _admin->getObjectInfo(stringToIdentity(arg)); + ObjectInfo info = _admin->getObjectInfo(Ice::stringToIdentity(arg)); cout << "proxy = `" << _communicator->proxyToString(info.proxy) << "'" << endl; cout << "type = `" << info.type << "'" << endl; return; @@ -2198,7 +2198,7 @@ Parser::listObject(const list<string>& args) for(ObjectInfoSeq::const_iterator p = objects.begin(); p != objects.end(); ++p) { - cout << identityToString(p->proxy->ice_getIdentity()) << endl; + cout << _communicator->identityToString(p->proxy->ice_getIdentity()) << endl; } } catch(const Ice::Exception& ex) @@ -2957,11 +2957,11 @@ Parser::exception(const Ice::Exception& ex) } catch(const ObjectNotRegisteredException& ex) { - error("couldn't find object `" + identityToString(ex.id) + "'"); + error("couldn't find object `" + _communicator->identityToString(ex.id) + "'"); } catch(const ObjectExistsException& ex) { - error("object `" + identityToString(ex.id) + "' already exists"); + error("object `" + _communicator->identityToString(ex.id) + "' already exists"); } catch(const DeploymentException& ex) { diff --git a/cpp/src/IceGrid/ReplicaSessionManager.cpp b/cpp/src/IceGrid/ReplicaSessionManager.cpp index 77c324aea27..9895963a1c5 100644 --- a/cpp/src/IceGrid/ReplicaSessionManager.cpp +++ b/cpp/src/IceGrid/ReplicaSessionManager.cpp @@ -177,7 +177,7 @@ public: { ostringstream os; os << ex << ":\n"; - os << "id: " << identityToString(info.proxy->ice_getIdentity()); + os << "id: " << _database->getCommunicator()->identityToString(info.proxy->ice_getIdentity()); failure = os.str(); } receivedUpdate(ObjectObserverTopicName, serial, failure); @@ -196,7 +196,7 @@ public: { ostringstream os; os << ex << ":\n"; - os << "id: " << identityToString(info.proxy->ice_getIdentity()); + os << "id: " << _database->getCommunicator()->identityToString(info.proxy->ice_getIdentity()); failure = os.str(); } catch(const DeploymentException& ex) diff --git a/cpp/src/IceGrid/Util.cpp b/cpp/src/IceGrid/Util.cpp index 8c0d04cd911..c56e30717c0 100644 --- a/cpp/src/IceGrid/Util.cpp +++ b/cpp/src/IceGrid/Util.cpp @@ -207,7 +207,7 @@ IceGrid::toObjectInfo(const Ice::CommunicatorPtr& communicator, const ObjectDesc ObjectInfo info; info.type = obj.type; ostringstream proxyStr; - proxyStr << "\"" << identityToString(obj.id) << "\""; + proxyStr << "\"" << communicator->identityToString(obj.id) << "\""; if(!obj.proxyOptions.empty()) { proxyStr << ' ' << obj.proxyOptions; @@ -220,7 +220,7 @@ IceGrid::toObjectInfo(const Ice::CommunicatorPtr& communicator, const ObjectDesc catch(const Ice::ProxyParseException&) { ostringstream fallbackProxyStr; - fallbackProxyStr << "\"" << identityToString(obj.id) << "\"" << " @ \"" << adapterId << "\""; + fallbackProxyStr << "\"" << communicator->identityToString(obj.id) << "\"" << " @ \"" << adapterId << "\""; info.proxy = communicator->stringToProxy(fallbackProxyStr.str()); } return info; diff --git a/cpp/src/IcePatch2Lib/Util.cpp b/cpp/src/IcePatch2Lib/Util.cpp index 88798feaba5..63fc5087eeb 100644 --- a/cpp/src/IcePatch2Lib/Util.cpp +++ b/cpp/src/IcePatch2Lib/Util.cpp @@ -81,7 +81,7 @@ bool IcePatch2Internal::writeFileInfo(FILE* fp, const LargeFileInfo& info) { int rc = fprintf(fp, "%s\t%s\t" ICE_INT64_FORMAT "\t%d\n", - IceUtilInternal::escapeString(info.path, "").c_str(), + escapeString(info.path, "", IceUtilInternal::Compat).c_str(), bytesToString(info.checksum).c_str(), info.size, static_cast<int>(info.executable)); diff --git a/cpp/src/IceStorm/IceStormDB.cpp b/cpp/src/IceStorm/IceStormDB.cpp index 9a3c81022e3..b3a927c719e 100644 --- a/cpp/src/IceStorm/IceStormDB.cpp +++ b/cpp/src/IceStorm/IceStormDB.cpp @@ -231,8 +231,8 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " KEY = TOPIC(" << identityToString(q->first.topic) - << ") ID(" << identityToString(q->first.id) << ")" <<endl; + cout << " KEY = TOPIC(" << communicator()->identityToString(q->first.topic) + << ") ID(" << communicator()->identityToString(q->first.id) << ")" <<endl; } subscriberMap.put(txn, q->first, q->second); } @@ -286,8 +286,8 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " KEY = TOPIC(" << identityToString(key.topic) - << ") ID(" << identityToString(key.id) << ")" <<endl; + cout << " KEY = TOPIC(" << communicator()->identityToString(key.topic) + << ") ID(" << communicator()->identityToString(key.id) << ")" <<endl; } data.subscribers.insert(std::make_pair(key, record)); } diff --git a/cpp/src/IceStorm/InstrumentationI.cpp b/cpp/src/IceStorm/InstrumentationI.cpp index ad3495429c9..017a5196fd3 100644 --- a/cpp/src/IceStorm/InstrumentationI.cpp +++ b/cpp/src/IceStorm/InstrumentationI.cpp @@ -174,7 +174,7 @@ public: } catch(const ::Ice::FixedProxyException&) { - _id = identityToString(_proxy->ice_getIdentity()); + _id = _proxy->ice_getCommunicator()->identityToString(_proxy->ice_getIdentity()); } } return _id; @@ -206,7 +206,7 @@ public: string getIdentity() const { - return identityToString(_proxy->ice_getIdentity()); + return _proxy->ice_getCommunicator()->identityToString(_proxy->ice_getIdentity()); } private: diff --git a/cpp/src/IceStorm/Parser.cpp b/cpp/src/IceStorm/Parser.cpp index 6f802b11569..ca0c0c5ae7b 100644 --- a/cpp/src/IceStorm/Parser.cpp +++ b/cpp/src/IceStorm/Parser.cpp @@ -364,7 +364,7 @@ Parser::subscribers(const list<string>& args) IdentitySeq subscribers = topic->getSubscribers(); for(IdentitySeq::const_iterator j = subscribers.begin(); j != subscribers.end(); ++j) { - cout << "\t" << identityToString(*j) << endl; + cout << "\t" << _communicator->identityToString(*j) << endl; } } } @@ -379,7 +379,7 @@ Parser::current(const list<string>& args) { if(args.empty()) { - cout << identityToString(_defaultManager->ice_getIdentity()) << endl; + cout << _communicator->identityToString(_defaultManager->ice_getIdentity()) << endl; return; } else if(args.size() > 1) @@ -618,7 +618,7 @@ Parser::parse(const std::string& commands, bool debug) TopicManagerPrx Parser::findManagerById(const string& full, string& arg) const { - Ice::Identity id = stringToIdentity(full); + Ice::Identity id = Ice::stringToIdentity(full); arg = id.name; if(id.category.empty()) { diff --git a/cpp/src/IceStorm/Subscriber.cpp b/cpp/src/IceStorm/Subscriber.cpp index 529461f0f03..5c1740ad612 100644 --- a/cpp/src/IceStorm/Subscriber.cpp +++ b/cpp/src/IceStorm/Subscriber.cpp @@ -546,7 +546,7 @@ Subscriber::create( Ice::Identity perId; perId.category = instance->instanceName(); perId.name = "topic." + rec.topicName + ".publish." + - identityToString(rec.obj->ice_getIdentity()); + instance->communicator()->identityToString(rec.obj->ice_getIdentity()); Ice::ObjectPrx proxy = instance->publishAdapter()->add(per, perId); TraceLevelsPtr traceLevels = instance->traceLevels(); SubscriberPtr subscriber; @@ -829,7 +829,7 @@ Subscriber::error(bool dec, const Ice::Exception& e) if(_currentRetry == 0) { Ice::Warning warn(traceLevels->logger); - warn << traceLevels->subscriberCat << ":" << identityToString(_rec.id); + warn << traceLevels->subscriberCat << ":" << _instance->communicator()->identityToString(_rec.id); if(traceLevels->subscriber > 1) { warn << " endpoints: " << IceStormInternal::describeEndpoints(_rec.obj); @@ -842,7 +842,7 @@ Subscriber::error(bool dec, const Ice::Exception& e) if(traceLevels->subscriber > 0) { Ice::Trace out(traceLevels->logger, traceLevels->subscriberCat); - out << identityToString(_rec.id); + out << _instance->communicator()->identityToString(_rec.id); if(traceLevels->subscriber > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(_rec.obj); @@ -870,7 +870,7 @@ Subscriber::error(bool dec, const Ice::Exception& e) if(traceLevels->subscriber > 0) { Ice::Trace out(traceLevels->logger, traceLevels->subscriberCat); - out << identityToString(_rec.id); + out << _instance->communicator()->identityToString(_rec.id); if(traceLevels->subscriber > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(_rec.obj); diff --git a/cpp/src/IceStorm/TopicI.cpp b/cpp/src/IceStorm/TopicI.cpp index 3a9c3d65a79..acea59e5c15 100644 --- a/cpp/src/IceStorm/TopicI.cpp +++ b/cpp/src/IceStorm/TopicI.cpp @@ -399,7 +399,7 @@ TopicImpl::TopicImpl( if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << " recreate " << identityToString(id); + out << _name << " recreate " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(p->obj); @@ -418,7 +418,7 @@ TopicImpl::TopicImpl( catch(const Ice::Exception& ex) { Ice::Warning out(traceLevels->logger); - out << _name << " recreate " << identityToString(id); + out << _name << " recreate " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(p->obj); @@ -491,7 +491,7 @@ trace(Ice::Trace& out, const PersistentInstancePtr& instance, const vector<Subsc { out << ","; } - out << identityToString((*p)->id()); + out << instance->communicator()->identityToString((*p)->id()); } out << "]"; } @@ -516,7 +516,7 @@ TopicImpl::subscribeAndGetPublisher(const QoS& qos, const Ice::ObjectPrx& obj) if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": subscribeAndGetPublisher: " << identityToString(id); + out << _name << ": subscribeAndGetPublisher: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { @@ -600,7 +600,7 @@ TopicImpl::unsubscribe(const Ice::ObjectPrx& subscriber) if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": unsubscribe: " << identityToString(id); + out << _name << ": unsubscribe: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { @@ -637,7 +637,7 @@ TopicImpl::link(const TopicPrx& topic, Ice::Int cost) if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": link " << identityToString(topic->ice_getIdentity()) + out << _name << ": link " << _instance->communicator()->identityToString(topic->ice_getIdentity()) << " cost " << cost; } @@ -722,7 +722,7 @@ TopicImpl::unlink(const TopicPrx& topic) if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << " unlink " << identityToString(id); + out << _name << " unlink " << _instance->communicator()->identityToString(id); } Ice::IdentitySeq ids; @@ -746,7 +746,7 @@ TopicImpl::reap(const Ice::IdentitySeq& ids) { out << ","; } - out << identityToString(*p); + out << _instance->communicator()->identityToString(*p); } } @@ -1045,7 +1045,7 @@ TopicImpl::observerAddSubscriber(const LogUpdate& llu, const SubscriberRecord& r if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": add replica observer: " << identityToString(record.id); + out << _name << ": add replica observer: " << _instance->communicator()->identityToString(record.id); if(traceLevels->topic > 1) { @@ -1072,7 +1072,7 @@ TopicImpl::observerAddSubscriber(const LogUpdate& llu, const SubscriberRecord& r if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << identityToString(record.id) << ": already subscribed"; + out << _instance->communicator()->identityToString(record.id) << ": already subscribed"; } return; } @@ -1116,7 +1116,7 @@ TopicImpl::observerRemoveSubscriber(const LogUpdate& llu, const Ice::IdentitySeq { out << ","; } - out << identityToString(*id); + out << _instance->communicator()->identityToString(*id); } out << " llu: " << llu.generation << "/" << llu.iteration; } diff --git a/cpp/src/IceStorm/TopicManagerI.cpp b/cpp/src/IceStorm/TopicManagerI.cpp index 15696d70abc..5c4ad1c6cbc 100644 --- a/cpp/src/IceStorm/TopicManagerI.cpp +++ b/cpp/src/IceStorm/TopicManagerI.cpp @@ -421,14 +421,14 @@ TopicManagerImpl::observerInit(const LogUpdate& llu, const TopicContentSeq& cont out << "init"; for(TopicContentSeq::const_iterator p = content.begin(); p != content.end(); ++p) { - out << " topic: " << identityToString(p->id) << " subscribers: "; + out << " topic: " << _instance->communicator()->identityToString(p->id) << " subscribers: "; for(SubscriberRecordSeq::const_iterator q = p->records.begin(); q != p->records.end(); ++q) { if(q != p->records.begin()) { out << ","; } - out << identityToString(q->id); + out << _instance->communicator()->identityToString(q->id); if(traceLevels->topicMgr > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(q->obj); @@ -803,7 +803,7 @@ TopicManagerImpl::installTopic(const string& name, const Ice::Identity& id, bool if(create) { out << "creating new topic \"" << name << "\". id: " - << identityToString(id) + << _instance->communicator()->identityToString(id) << " subscribers: "; for(SubscriberRecordSeq::const_iterator q = subscribers.begin(); q != subscribers.end(); ++q) { @@ -813,7 +813,7 @@ TopicManagerImpl::installTopic(const string& name, const Ice::Identity& id, bool } if(traceLevels->topicMgr > 1) { - out << identityToString(q->id) + out << _instance->communicator()->identityToString(q->id) << " endpoints: " << IceStormInternal::describeEndpoints(q->obj); } } @@ -821,7 +821,7 @@ TopicManagerImpl::installTopic(const string& name, const Ice::Identity& id, bool else { out << "loading topic \"" << name << "\" from database. id: " - << identityToString(id) + << _instance->communicator()->identityToString(id) << " subscribers: "; for(SubscriberRecordSeq::const_iterator q = subscribers.begin(); q != subscribers.end(); ++q) { @@ -831,7 +831,7 @@ TopicManagerImpl::installTopic(const string& name, const Ice::Identity& id, bool } if(traceLevels->topicMgr > 1) { - out << identityToString(q->id) + out << _instance->communicator()->identityToString(q->id) << " endpoints: " << IceStormInternal::describeEndpoints(q->obj); } } diff --git a/cpp/src/IceStorm/TransientTopicI.cpp b/cpp/src/IceStorm/TransientTopicI.cpp index f11688d1a10..062db7014fb 100644 --- a/cpp/src/IceStorm/TransientTopicI.cpp +++ b/cpp/src/IceStorm/TransientTopicI.cpp @@ -178,7 +178,7 @@ TransientTopicImpl::subscribe(const QoS& origQoS, const Ice::ObjectPrx& obj, con if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": subscribe: " << identityToString(id); + out << _name << ": subscribe: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { @@ -280,7 +280,7 @@ TransientTopicImpl::subscribeAndGetPublisher(const QoS& qos, const Ice::ObjectPr if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": subscribeAndGetPublisher: " << identityToString(id); + out << _name << ": subscribeAndGetPublisher: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { @@ -338,7 +338,7 @@ TransientTopicImpl::unsubscribe(const Ice::ObjectPrx& subscriber, const Ice::Cur if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": unsubscribe: " << identityToString(id); + out << _name << ": unsubscribe: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(subscriber); @@ -374,7 +374,7 @@ TransientTopicImpl::link(const TopicPrx& topic, Ice::Int cost, const Ice::Curren if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << ": link " << identityToString(topic->ice_getIdentity()) + out << _name << ": link " << _instance->communicator()->identityToString(topic->ice_getIdentity()) << " cost " << cost; } @@ -434,7 +434,7 @@ TransientTopicImpl::unlink(const TopicPrx& topic, const Ice::Current&) if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); - out << _name << " unlink " << identityToString(id); + out << _name << " unlink " << _instance->communicator()->identityToString(id); } // Remove the subscriber from the subscribers list. Note diff --git a/cpp/src/IceStorm/TransientTopicManagerI.cpp b/cpp/src/IceStorm/TransientTopicManagerI.cpp index 5bd8449fd66..8c45a471f19 100644 --- a/cpp/src/IceStorm/TransientTopicManagerI.cpp +++ b/cpp/src/IceStorm/TransientTopicManagerI.cpp @@ -55,7 +55,7 @@ TransientTopicManagerImpl::create(const string& name, const Ice::Current&) { Ice::Trace out(traceLevels->logger, traceLevels->topicMgrCat); out << "creating new topic \"" << name << "\". id: " - << identityToString(id); + << _instance->communicator()->identityToString(id); } // diff --git a/cpp/src/IceUtil/StringUtil.cpp b/cpp/src/IceUtil/StringUtil.cpp index ec33cf8c587..0e7d9162d6c 100644 --- a/cpp/src/IceUtil/StringUtil.cpp +++ b/cpp/src/IceUtil/StringUtil.cpp @@ -35,96 +35,89 @@ toOctalString(unsigned int n) return string(s, charPos, (32 - charPos)); } +char +toHexDigit(Byte b) +{ + assert(b < 16); + if(b < 10) + { + return '0' + b; + } + else + { + return 'a' - 10 + b; + } +} + + +unsigned int +addContinuationByte(string::iterator& p, string::iterator end, unsigned int codePoint) +{ + if(p == end) + { + throw IllegalArgumentException(__FILE__, __LINE__, "UTF-8 sequence too short"); + } + + Byte b = static_cast<Byte>(*p++); + + if((b >> 6) != 2) + { + throw IllegalArgumentException(__FILE__, __LINE__, "Invalid UTF-8 sequence"); + } + return (codePoint << 6) + (b & 0x3F); +} + // -// Write the byte b as an escape sequence if it isn't a printable ASCII -// character and append the escape sequence to s. Additional characters -// that should be escaped can be passed in special. If b is any of these -// characters, b is preceded by a backslash in s. +// Appends a 2 to 4 bytes UTF-8 sequence as a universal character name // void -encodeChar(string::value_type b, string& s, const string& special) +appendUniversalName(char c, string::iterator& p, string::iterator end, string& result) { - switch(b) + unsigned int codePoint; + + Byte b = static_cast<Byte>(c); + if((b >> 5) == 0x06) { - case '\\': - { - s.append("\\\\"); - break; - } - - case '\'': - { - s.append("\\'"); - break; - } - - case '"': - { - s.append("\\\""); - break; - } - - case '\b': - { - s.append("\\b"); - break; - } - - case '\f': - { - s.append("\\f"); - break; - } - - case '\n': - { - s.append("\\n"); - break; - } - - case '\r': - { - s.append("\\r"); - break; - } - - case '\t': + // 2 bytes + codePoint = (b & 0x1F); + codePoint = addContinuationByte(p, end, codePoint); + } + else if((b >> 4) == 0x0E) + { + // 3 bytes + codePoint = (b & 0x0F); + codePoint = addContinuationByte(p, end, codePoint); + codePoint = addContinuationByte(p, end, codePoint); + } + else if((b >> 3) == 0x1E) + { + // 4 bytes + codePoint = (b & 0x07); + codePoint = addContinuationByte(p, end, codePoint); + codePoint = addContinuationByte(p, end, codePoint); + codePoint = addContinuationByte(p, end, codePoint); + } + else + { + ostringstream ostr; + ostr << "Invalid first byte 0x" << hex << static_cast<unsigned short>(b) << " in UTF-8 sequence" << endl; + throw IllegalArgumentException(__FILE__, __LINE__, ostr.str()); + } + + if(codePoint > 0xFFFF) + { + result.append("\\U"); + for(int j = 7; j >= 0; j--) { - s.append("\\t"); - break; + result.push_back(toHexDigit(static_cast<Byte>((codePoint >> (j * 4)) & 0x0F))); } - - default: + } + else + { + result.append("\\u"); + for(int j = 3; j >= 0; j--) { - unsigned char i = static_cast<unsigned char>(b); - if(!(i >= 32 && i <= 126)) - { - s.push_back('\\'); - string octal = toOctalString(i); - // - // Add leading zeroes so that we avoid problems during - // decoding. For example, consider the escaped string - // \0013 (i.e., a character with value 1 followed by the - // character '3'). If the leading zeroes were omitted, the - // result would be incorrectly interpreted as a single - // character with value 11. - // - for(string::size_type j = octal.size(); j < 3; j++) - { - s.push_back('0'); - } - s.append(octal); - } - else if(special.find(b) != string::npos) - { - s.push_back('\\'); - s.push_back(b); - } - else - { - s.push_back(b); - } - break; + result.push_back(toHexDigit(static_cast<Byte>((codePoint >> (j * 4)) & 0x0F))); } } } @@ -132,27 +125,153 @@ encodeChar(string::value_type b, string& s, const string& special) } // -// Add escape sequences (such as "\n", or "\007") to make a string -// readable in ASCII. Any characters that appear in special are -// prefixed with a backslash in the returned string. +// Add escape sequences. Any characters that appear in special are prefixed with a backslash in the returned string. // string -IceUtilInternal::escapeString(const string& s, const string& special) +IceUtilInternal::escapeString(const string& s, const string& special, ToStringMode toStringMode) { for(string::size_type i = 0; i < special.size(); ++i) { if(static_cast<unsigned char>(special[i]) < 32 || static_cast<unsigned char>(special[i]) > 126) { - throw IllegalArgumentException(__FILE__, __LINE__, "special characters must be in ASCII range 32-126"); + throw IllegalArgumentException(__FILE__, __LINE__, "Special characters must be in ASCII range 32-126"); } } - + + // + // First convert to UTF-8 + // + string u8s = nativeToUTF8(s, getProcessStringConverter()); + + string::iterator p = u8s.begin(); + string result; - for(string::size_type i = 0; i < s.size(); ++i) + + while(p != u8s.end()) { - encodeChar(s[i], result, special); + char c = *p++; + + switch(c) + { + case '\\': + { + result.append("\\\\"); + break; + } + + case '\'': + { + result.append("\\'"); + break; + } + + case '"': + { + result.append("\\\""); + break; + } + + case '\b': + { + result.append("\\b"); + break; + } + + case '\f': + { + result.append("\\f"); + break; + } + + case '\n': + { + result.append("\\n"); + break; + } + + case '\r': + { + result.append("\\r"); + break; + } + + case '\t': + { + result.append("\\t"); + break; + } + + default: + { + if(special.find(c) != string::npos) + { + result.push_back('\\'); + result.push_back(c); + } + else + { + unsigned char i = static_cast<unsigned char>(c); + + if(i < 32 || i > 126) + { + if(toStringMode == ICE_ENUM(ToStringMode, Compat)) + { + // append octal string + + result.push_back('\\'); + string octal = toOctalString(i); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the escaped string + // \0013 (i.e., a character with value 1 followed by the + // character '3'). If the leading zeroes were omitted, the + // result would be incorrectly interpreted as a single + // character with value 11. + // + for(string::size_type j = octal.size(); j < 3; j++) + { + result.push_back('0'); + } + result.append(octal); + } + else if(i < 32 || i == 127) + { + // append \u00nn + result.append("\\u00"); + result.push_back(toHexDigit(i >> 4)); + result.push_back(toHexDigit(i & 0x0F)); + } + else if(toStringMode == ICE_ENUM(ToStringMode, ASCII)) + { + // append \unnnn or \Unnnnnnnn after reading more UTF-8 bytes + appendUniversalName(c, p, u8s.end(), result); + } + else + { + // keep as is + result.push_back(c); + } + } + else + { + // printable ASCII character + result.push_back(c); + } + } + break; + } + } } - + + if(toStringMode == ICE_ENUM(ToStringMode, Unicode)) + { + // + // Convert back to Native + // + result = UTF8ToNative(result, getProcessStringConverter()); + } + // else it's a pure ASCII string + return result; } @@ -163,7 +282,7 @@ char checkChar(const string& s, string::size_type pos) { unsigned char c = static_cast<unsigned char>(s[pos]); - if(!(c >= 32 && c <= 126)) + if(c < 32 || c == 127) { ostringstream ostr; if(pos > 0) @@ -174,29 +293,74 @@ checkChar(const string& s, string::size_type pos) { ostr << "first character"; } - ostr << " is not a printable ASCII character (ordinal " << static_cast<int>(c) << ")"; + ostr << " has invalid ordinal value " << static_cast<int>(c); throw IllegalArgumentException(__FILE__, __LINE__, ostr.str()); } return c; } // -// Decode the character or escape sequence starting at start and return it. +// Append codePoint as a UTF-8 sequence +// +void +appendUTF8(unsigned int codePoint, bool inBMP, string& result) +{ + if(inBMP && codePoint >= 0xD800 && codePoint <= 0xDFFF) + { + throw IllegalArgumentException(__FILE__, __LINE__, + "A non-BMP character cannot be encoded with \\unnnn, use \\Unnnnnnnn instead"); + } + + if(codePoint <= 0x7F) + { + // ASCII + result.push_back(static_cast<char>(codePoint)); + } + else if(codePoint <= 0x7FF) + { + // 2 bytes + result.push_back(static_cast<char>((codePoint >> 6) | 0xC0)); + result.push_back(static_cast<char>((codePoint & 0x3F) | 0x80)); + } + else if(codePoint <= 0xFFFF) + { + // 3 bytes + result.push_back(static_cast<char>((codePoint >> 12) | 0xE0)); + result.push_back(static_cast<char>(((codePoint >> 6) & 0x3F) | 0x80)); + result.push_back(static_cast<char>((codePoint & 0x3F) | 0x80)); + } + else if(codePoint <= 0x10FFFF) + { + // 4 bytes + result.push_back(static_cast<char>((codePoint >> 18) | 0xF0)); + result.push_back(static_cast<char>(((codePoint >> 12) & 0x3F) | 0x80)); + result.push_back(static_cast<char>(((codePoint >> 6) & 0x3F) | 0x80)); + result.push_back(static_cast<char>((codePoint & 0x3F) | 0x80)); + } + else + { + throw IllegalArgumentException(__FILE__, __LINE__, "Invalid universal character name"); + } +} + +// +// Decode the character or escape sequence starting at start and appends it to result; // end marks the one-past-the-end position of the substring to be scanned. // nextStart is set to the index of the first character following the decoded // character or escape sequence. // -char -decodeChar(const string& s, string::size_type start, string::size_type end, string::size_type& nextStart) +bool +decodeChar(const string& s, string::size_type start, string::size_type end, string::size_type& nextStart, + string& result) { assert(start < end); assert(end <= s.size()); - char c; + bool pureASCII = true; if(s[start] != '\\') { - c = checkChar(s, start++); + result.push_back(checkChar(s, start++)); } else { @@ -204,43 +368,90 @@ decodeChar(const string& s, string::size_type start, string::size_type end, stri { throw IllegalArgumentException(__FILE__, __LINE__, "trailing backslash"); } - switch(s[++start]) + + char c = s[++start]; + + switch(c) { - case '\\': - case '\'': - case '"': + case '\\': + case '\'': + case '"': + { + ++start; + result.push_back(c); + break; + } + case 'b': { - c = s[start++]; + ++start; + result.push_back('\b'); break; } - case 'b': + case 'f': { ++start; - c = '\b'; + result.push_back('\f'); break; } - case 'f': + case 'n': { ++start; - c = '\f'; + result.push_back('\n'); break; } - case 'n': + case 'r': { ++start; - c = '\n'; + result.push_back('\r'); break; } - case 'r': + case 't': { ++start; - c = '\r'; + result.push_back('\t'); break; } - case 't': + case 'u': + case 'U': { + unsigned int codePoint = 0; + bool inBMP = (c == 'u'); + int size = inBMP ? 4 : 8; ++start; - c = '\t'; + while(size > 0 && start < end) + { + c = s[start++]; + int charVal = 0; + if(c >= '0' && c <= '9') + { + charVal = c - '0'; + } + else if(c >= 'a' && c <= 'f') + { + charVal = 10 + (c - 'a'); + } + else if(c >= 'A' && c <= 'F') + { + charVal = 10 + (c - 'A'); + } + else + { + break; // while + } + codePoint = codePoint * 16 + static_cast<unsigned int>(charVal); + --size; + } + if(size > 0) + { + throw IllegalArgumentException(__FILE__, __LINE__, + "Invalid universal character name: too few hex digits"); + } + + appendUTF8(codePoint, inBMP, result); + if(codePoint > 127) + { + pureASCII = false; + } break; } case '0': @@ -269,31 +480,26 @@ decodeChar(const string& s, string::size_type start, string::size_type end, stri ostr << "octal value \\" << oct << val << dec << " (" << val << ") is out of range"; throw IllegalArgumentException(__FILE__, __LINE__, ostr.str()); } - c = static_cast<char>(val); + result.push_back(static_cast<char>(val)); + if(val > 127) + { + pureASCII = false; + } break; } default: { - c = checkChar(s, start++); + if(static_cast<unsigned char>(c) > 127) + { + pureASCII = false; + } + result.push_back(checkChar(s, start++)); break; } } } nextStart = start; - return c; -} - -// -// Remove escape sequences from s and append the result to sb. -// Return true if successful, false otherwise. -// -void -decodeString(const string& s, string::size_type start, string::size_type end, string& sb) -{ - while(start < end) - { - sb.push_back(decodeChar(s, start, end, start)); - } + return pureASCII; } } @@ -306,11 +512,61 @@ IceUtilInternal::unescapeString(const string& s, string::size_type start, string { assert(start <= end && end <= s.size()); - string result; - result.reserve(end - start); - result.clear(); - decodeString(s, start, end, result); - return result; + // Optimization for strings without escapes + string::size_type p = s.find('\\', start); + if(p == string::npos || p >= end) + { + p = start; + while(p < end) + { + checkChar(s, p++); + } + return s.substr(start, end); + } + else + { + StringConverterPtr stringConverter = getProcessStringConverter(); + + const string* inputStringPtr = &s; + string u8s; + + if(stringConverter) + { + bool inputIsPureASCII = true; + string::size_type i = start; + while(i < end && inputIsPureASCII) + { + inputIsPureASCII = static_cast<unsigned char>(s[i++]) <= 127; + } + + if(!inputIsPureASCII) + { + u8s = nativeToUTF8(s.substr(start, end), stringConverter); + inputStringPtr = &u8s; + start = 0; + end = u8s.size(); + } + } + + bool resultIsPureASCII = true; + string result; + result.reserve(end - start); + while(start < end) + { + if(decodeChar(*inputStringPtr, start, end, start, result)) + { + resultIsPureASCII = false; + } + } + + if(stringConverter && !resultIsPureASCII) + { + // Need to convert from UTF-8 to Native + result = UTF8ToNative(result, stringConverter); + } + + return result; + } } bool @@ -328,7 +584,7 @@ IceUtilInternal::splitString(const string& str, const string& delim, vector<stri quoteChar = str[pos++]; continue; // Skip the quote } - else if(quoteChar == '\0' && str[pos] == '\\' && pos + 1 < length && + else if(quoteChar == '\0' && str[pos] == '\\' && pos + 1 < length && (str[pos + 1] == '\'' || str[pos + 1] == '"')) { ++pos; @@ -356,7 +612,7 @@ IceUtilInternal::splitString(const string& str, const string& delim, vector<stri continue; } } - + if(pos < length) { elt += str[pos++]; @@ -437,7 +693,7 @@ IceUtilInternal::checkQuote(const string& s, string::size_type start) // // Match `s' against the pattern `pat'. A * in the pattern acts // as a wildcard: it matches any non-empty sequence of characters. -// We match by hand here because it's portable across platforms +// We match by hand here because it's portable across platforms // (whereas regex() isn't). Only one * per pattern is supported. // bool @@ -500,7 +756,7 @@ IceUtilInternal::errorToString(int error, LPCVOID source) wstring lpMsgBuf(256, wchar_t()); DWORD stored = 0; - + while(stored == 0) { stored = FormatMessageW( @@ -531,7 +787,7 @@ IceUtilInternal::errorToString(int error, LPCVOID source) else { break; - } + } } } @@ -539,7 +795,7 @@ IceUtilInternal::errorToString(int error, LPCVOID source) #else LPWSTR msg = 0; - + DWORD stored = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | @@ -552,7 +808,7 @@ IceUtilInternal::errorToString(int error, LPCVOID source) 0, NULL); #endif - + if(stored > 0) { assert(msg && wcslen(msg) > 0); @@ -576,159 +832,159 @@ IceUtilInternal::errorToString(int error, LPCVOID source) return os.str(); } } - + switch(error) { case WSAEINTR: return "WSAEINTR"; - + case WSAEBADF: return "WSAEBADF"; - + case WSAEACCES: return "WSAEACCES"; - + case WSAEFAULT: return "WSAEFAULT"; - + case WSAEINVAL: return "WSAEINVAL"; - + case WSAEMFILE: return "WSAEMFILE"; - + case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK"; - + case WSAEINPROGRESS: return "WSAEINPROGRESS"; - + case WSAEALREADY: return "WSAEALREADY"; - + case WSAENOTSOCK: return "WSAENOTSOCK"; - + case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ"; - + case WSAEMSGSIZE: return "WSAEMSGSIZE"; - + case WSAEPROTOTYPE: return "WSAEPROTOTYPE"; - + case WSAENOPROTOOPT: return "WSAENOPROTOOPT"; - + case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT"; - + case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT"; - + case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP"; - + case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT"; - + case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT"; - + case WSAEADDRINUSE: return "WSAEADDRINUSE"; - + case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL"; - + case WSAENETDOWN: return "WSAENETDOWN"; - + case WSAENETUNREACH: return "WSAENETUNREACH"; - + case WSAENETRESET: return "WSAENETRESET"; - + case WSAECONNABORTED: return "WSAECONNABORTED"; - + case WSAECONNRESET: return "WSAECONNRESET"; - + case WSAENOBUFS: return "WSAENOBUFS"; - + case WSAEISCONN: return "WSAEISCONN"; - + case WSAENOTCONN: return "WSAENOTCONN"; - + case WSAESHUTDOWN: return "WSAESHUTDOWN"; - + case WSAETOOMANYREFS: return "WSAETOOMANYREFS"; - + case WSAETIMEDOUT: return "WSAETIMEDOUT"; - + case WSAECONNREFUSED: return "WSAECONNREFUSED"; - + case WSAELOOP: return "WSAELOOP"; - + case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; - + case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; - + case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH"; - + case WSAENOTEMPTY: return "WSAENOTEMPTY"; - + case WSAEPROCLIM: return "WSAEPROCLIM"; - + case WSAEUSERS: return "WSAEUSERS"; - + case WSAEDQUOT: return "WSAEDQUOT"; - + case WSAESTALE: return "WSAESTALE"; - + case WSAEREMOTE: return "WSAEREMOTE"; - + case WSAEDISCON: return "WSAEDISCON"; - + case WSASYSNOTREADY: return "WSASYSNOTREADY"; - + case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED"; - + case WSANOTINITIALISED: return "WSANOTINITIALISED"; - + case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND"; - + case WSATRY_AGAIN: return "WSATRY_AGAIN"; - + case WSANO_RECOVERY: return "WSANO_RECOVERY"; - + case WSANO_DATA: return "WSANO_DATA"; diff --git a/cpp/src/Slice/Preprocessor.cpp b/cpp/src/Slice/Preprocessor.cpp index c8e49029f25..57d5ed5f78f 100644 --- a/cpp/src/Slice/Preprocessor.cpp +++ b/cpp/src/Slice/Preprocessor.cpp @@ -83,11 +83,9 @@ Slice::Preprocessor::addQuotes(const string& arg) { // // Add quotes around the given argument to ensure that arguments - // with spaces will be preserved as a single argument. We also - // escape the "\" character to ensure that we don't end up with a - // \" at the end of the string. + // with spaces will be preserved as a single argument // - return "\"" + IceUtilInternal::escapeString(arg, "\\") + "\""; + return "\"" + escapeString(arg, "", IceUtilInternal::Unicode) + "\""; } string diff --git a/cpp/src/icegriddb/IceGridDB.cpp b/cpp/src/icegriddb/IceGridDB.cpp index 42b61f1ab92..8426d773d63 100644 --- a/cpp/src/icegriddb/IceGridDB.cpp +++ b/cpp/src/icegriddb/IceGridDB.cpp @@ -372,7 +372,7 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " NAME = " << identityToString(p->proxy->ice_getIdentity()) << endl; + cout << " NAME = " << communicator()->identityToString(p->proxy->ice_getIdentity()) << endl; } objs.put(txn, p->proxy->ice_getIdentity(), *p); } @@ -390,7 +390,7 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " NAME = " << identityToString(p->proxy->ice_getIdentity()) << endl; + cout << " NAME = " << communicator()->identityToString(p->proxy->ice_getIdentity()) << endl; } internalObjs.put(txn, p->proxy->ice_getIdentity(), *p); } @@ -483,7 +483,7 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " IDENTITY = " << identityToString(id) << endl; + cout << " IDENTITY = " << communicator()->identityToString(id) << endl; } data.objects.push_back(object); } @@ -503,7 +503,7 @@ Client::run(int argc, char* argv[]) { if(debug) { - cout << " IDENTITY = " << identityToString(id) << endl; + cout << " IDENTITY = " << communicator()->identityToString(id) << endl; } data.internalObjects.push_back(object); } diff --git a/cpp/test/Ice/interceptor/AMDInterceptorI.cpp b/cpp/test/Ice/interceptor/AMDInterceptorI.cpp index f790db8c6a0..7e546344602 100644 --- a/cpp/test/Ice/interceptor/AMDInterceptorI.cpp +++ b/cpp/test/Ice/interceptor/AMDInterceptorI.cpp @@ -172,4 +172,4 @@ DispatchInterceptorAsyncCallbackI::exception() test(false); return true; } -#endif
\ No newline at end of file +#endif diff --git a/cpp/test/Ice/location/AllTests.cpp b/cpp/test/Ice/location/AllTests.cpp index 80e10c780db..39ea56f9462 100644 --- a/cpp/test/Ice/location/AllTests.cpp +++ b/cpp/test/Ice/location/AllTests.cpp @@ -716,7 +716,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const string& ref) registry->addObject(adapter->add(ICE_MAKE_SHARED(HelloI), id)); adapter->activate(); - HelloPrxPtr helloPrx = ICE_CHECKED_CAST(HelloPrx, communicator->stringToProxy(identityToString(id))); + HelloPrxPtr helloPrx = ICE_CHECKED_CAST(HelloPrx, communicator->stringToProxy(communicator->identityToString(id))); test(!helloPrx->ice_getConnection()); adapter->deactivate(); diff --git a/cpp/test/Ice/operations/TestI.cpp b/cpp/test/Ice/operations/TestI.cpp index 91154cf5769..2adfceda6db 100644 --- a/cpp/test/Ice/operations/TestI.cpp +++ b/cpp/test/Ice/operations/TestI.cpp @@ -926,4 +926,4 @@ MyDerivedClassI::opMDict2(ICE_IN(Test::StringStringD) p1, Test::StringStringD& p return p1; } -#endif
\ No newline at end of file +#endif diff --git a/cpp/test/Ice/proxy/AllTests.cpp b/cpp/test/Ice/proxy/AllTests.cpp index 4fe2207c759..791c6c620a7 100644 --- a/cpp/test/Ice/proxy/AllTests.cpp +++ b/cpp/test/Ice/proxy/AllTests.cpp @@ -20,6 +20,7 @@ allTests(const Ice::CommunicatorPtr& communicator) { const string endp = getTestEndpoint(communicator, 0); cout << "testing stringToProxy... " << flush; + string ref = "test:" + endp; Ice::ObjectPrxPtr base = communicator->stringToProxy(ref); test(base); @@ -64,6 +65,7 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const Ice::ProxyParseException&) { } + b1 = communicator->stringToProxy("test\\040test"); test(b1->ice_getIdentity().name == "test test" && b1->ice_getIdentity().category.empty()); try @@ -74,10 +76,11 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const Ice::IdentityParseException&) { } + b1 = communicator->stringToProxy("test\\40test"); test(b1->ice_getIdentity().name == "test test"); - // Test some octal and hex corner cases. + // Test some octal corner cases. b1 = communicator->stringToProxy("test\\4test"); test(b1->ice_getIdentity().name == "test\4test"); b1 = communicator->stringToProxy("test\\04test"); @@ -98,6 +101,7 @@ allTests(const Ice::CommunicatorPtr& communicator) test(!b1); b1 = communicator->stringToProxy("\"\""); test(!b1); + try { b1 = communicator->stringToProxy("\"\" test"); // Invalid trailing characters. @@ -106,6 +110,7 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const Ice::ProxyParseException&) { } + try { b1 = communicator->stringToProxy("test:"); // Missing endpoint. @@ -142,8 +147,10 @@ allTests(const Ice::CommunicatorPtr& communicator) test(b1->ice_getIdentity().name == "test" && b1->ice_getIdentity().category == "category" && b1->ice_getAdapterId() == "adapter 1"); b1 = communicator->stringToProxy("\"category \\/test@foo/test\"@adapter"); - test(b1->ice_getIdentity().name == "test" && b1->ice_getIdentity().category == "category /test@foo" && - b1->ice_getAdapterId() == "adapter"); + + test(b1->ice_getIdentity().name == "test" && b1->ice_getIdentity().category == "category /test@foo" + && b1->ice_getAdapterId() == "adapter"); + b1 = communicator->stringToProxy("\"category \\/test@foo/test\"@\"adapter:tcp\""); test(b1->ice_getIdentity().name == "test" && b1->ice_getIdentity().category == "category /test@foo" && b1->ice_getAdapterId() == "adapter:tcp"); @@ -258,14 +265,85 @@ allTests(const Ice::CommunicatorPtr& communicator) // Test for bug ICE-5543: escaped escapes in stringToIdentity // Ice::Identity id = { "test", ",X2QNUAzSBcJ_e$AV;E\\" }; - Ice::Identity id2 = Ice::stringToIdentity(Ice::identityToString(id)); + Ice::Identity id2 = Ice::stringToIdentity(communicator->identityToString(id)); test(id == id2); id.name = "test"; id.category = ",X2QNUAz\\SB\\/cJ_e$AV;E\\\\"; - id2 = Ice::stringToIdentity(Ice::identityToString(id)); + id2 = Ice::stringToIdentity(communicator->identityToString(id)); + test(id == id2); + + id.name = "/test"; + id.category = "cat/"; + string idStr = communicator->identityToString(id); + test(idStr == "cat\\//\\/test"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); + + try + { + // Illegal character < 32 + id = Ice::stringToIdentity("xx\01FooBar"); + test(false); + } + catch(const Ice::IdentityParseException&) + { + } + + try + { + // Illegal surrogate + id = Ice::stringToIdentity("xx\\ud911"); + test(false); + } + catch(const Ice::IdentityParseException&) + { + } + + // Testing bytes 127 (\x7F) and € + id.name = "test"; + id.category = "\x7F\xE2\x82\xAC"; + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, Unicode)); + test(idStr == "\\u007f\xE2\x82\xAC/test"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); + test(Ice::identityToString(id) == idStr); + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, ASCII)); + test(idStr == "\\u007f\\u20ac/test"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, Compat)); + test(idStr == "\\177\\342\\202\\254/test"); + id2 = Ice::stringToIdentity(idStr); test(id == id2); + id2 = Ice::stringToIdentity(communicator->identityToString(id)); + test(id == id2); + + // More unicode characters +#ifdef ICE_CPP11_MAPPING + id.name = u8"banana \016-\U0001F34C\U000020AC\u00a2\u0024"; + id.category = u8"greek \U0001016A"; + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, Unicode)); + test(idStr == u8"greek \U0001016A/banana \\u000e-\U0001F34C\U000020AC\u00a2$"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, ASCII)); + test(idStr == "greek \\U0001016a/banana \\u000e-\\U0001f34c\\u20ac\\u00a2$"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); + + idStr = identityToString(id, Ice::ICE_ENUM(ToStringMode, Compat)); + test(idStr == "greek \\360\\220\\205\\252/banana \\016-\\360\\237\\215\\214\\342\\202\\254\\302\\242$"); + id2 = Ice::stringToIdentity(idStr); + test(id == id2); +#endif + cout << "ok" << endl; cout << "testing propertyToProxy... " << flush; @@ -445,10 +523,8 @@ allTests(const Ice::CommunicatorPtr& communicator) cout << "testing proxy methods... " << flush; -// Deprecated -// test(communicator->identityToString(base->ice_identity(communicator->stringToIdentity("other"))->ice_getIdentity()) -// == "other"); - test(Ice::identityToString(base->ice_identity(Ice::stringToIdentity("other"))->ice_getIdentity()) == "other"); + test(communicator->identityToString(base->ice_identity(Ice::stringToIdentity("other"))->ice_getIdentity()) + == "other"); test(base->ice_facet("facet")->ice_getFacet() == "facet"); test(base->ice_adapterId("id")->ice_getAdapterId() == "id"); test(base->ice_twoway()->ice_isTwoway()); diff --git a/cpp/test/Ice/proxy/run.py b/cpp/test/Ice/proxy/run.py index 7921ce9e9ff..38e60970744 100755 --- a/cpp/test/Ice/proxy/run.py +++ b/cpp/test/Ice/proxy/run.py @@ -23,5 +23,5 @@ import TestUtil TestUtil.queueClientServerTest() TestUtil.queueClientServerTest(configName = "amd", localOnly = True, message = "Running test with AMD server.", server = TestUtil.getTestExecutable("serveramd")) -TestUtil.queueCollocatedTest() +TestUtil.queueCollocatedTest(additionalOptions = "--Ice.ToStringMode=Compat") TestUtil.runQueuedTests() diff --git a/cpp/test/Ice/stringConverter/Client.cpp b/cpp/test/Ice/stringConverter/Client.cpp index 4a8e7027aea..f0d7f4df1cd 100644 --- a/cpp/test/Ice/stringConverter/Client.cpp +++ b/cpp/test/Ice/stringConverter/Client.cpp @@ -127,6 +127,22 @@ main(int argc, char* argv[]) wstring wmsg = proxy->widen(msg); test(proxy->narrow(wmsg) == msg); test(wmsg.size() == msg.size()); + + // Test stringToIdentity and identityToString + + string identStr = "cat/" + msg; + Ice::Identity ident = Ice::stringToIdentity(identStr); + test(ident.name == msg); + test(ident.category == "cat"); + test(identityToString(ident, Ice::ICE_ENUM(ToStringMode, Unicode)) == identStr); + + identStr = identityToString(ident, Ice::ICE_ENUM(ToStringMode, ASCII)); + test(identStr == "cat/tu me fends le c\\u0153ur!"); + test(Ice::stringToIdentity(identStr) == ident); + identStr = identityToString(ident, Ice::ICE_ENUM(ToStringMode, Compat)); + test(identStr == "cat/tu me fends le c\\305\\223ur!"); + test(Ice::stringToIdentity(identStr) == ident); + communicator->destroy(); cout << "ok" << endl; } @@ -134,7 +150,6 @@ main(int argc, char* argv[]) Ice::setProcessStringConverter(ICE_NULLPTR); Ice::setProcessWstringConverter(Ice::createUnicodeWstringConverter()); - string propValue = "Ice:createStringConverter"; if(useIconv && !useLocale) { diff --git a/cpp/test/IceGrid/deployer/AllTests.cpp b/cpp/test/IceGrid/deployer/AllTests.cpp index 222a243ba6c..d4cfa91c6bd 100644 --- a/cpp/test/IceGrid/deployer/AllTests.cpp +++ b/cpp/test/IceGrid/deployer/AllTests.cpp @@ -430,16 +430,16 @@ allTests(const Ice::CommunicatorPtr& comm) test(find_if(objs.begin(), objs.end(), bind2nd(ProxyIdentityEqual(comm),"ReplicatedObject")) != objs.end()); { - test(identityToString(query->findObjectByType("::TestId1")->ice_getIdentity()) == "cat/name1"); - test(identityToString(query->findObjectByType("::TestId2")->ice_getIdentity()) == "cat1/name1"); - test(identityToString(query->findObjectByType("::TestId3")->ice_getIdentity()) == "cat1/name1-bis"); - test(identityToString(query->findObjectByType("::TestId4")->ice_getIdentity()) == "c2\\/c2/n2\\/n2"); - test(identityToString(query->findObjectByType("::TestId5")->ice_getIdentity()) == "n2\\/n2"); + test(comm->identityToString(query->findObjectByType("::TestId1")->ice_getIdentity()) == "cat/name1"); + test(comm->identityToString(query->findObjectByType("::TestId2")->ice_getIdentity()) == "cat1/name1"); + test(comm->identityToString(query->findObjectByType("::TestId3")->ice_getIdentity()) == "cat1/name1-bis"); + test(comm->identityToString(query->findObjectByType("::TestId4")->ice_getIdentity()) == "c2\\/c2/n2\\/n2"); + test(comm->identityToString(query->findObjectByType("::TestId5")->ice_getIdentity()) == "n2\\/n2"); } { Ice::ObjectPrx obj = query->findObjectByType("::Test"); - string id = identityToString(obj->ice_getIdentity()); + string id = comm->identityToString(obj->ice_getIdentity()); test(id == "Server1" || id == "Server2" || id == "SimpleServer" || id == "IceBox1-Service1" || id == "IceBox1-Service2" || id == "IceBox2-Service1" || id == "IceBox2-Service2" || @@ -448,7 +448,7 @@ allTests(const Ice::CommunicatorPtr& comm) { Ice::ObjectPrx obj = query->findObjectByTypeOnLeastLoadedNode("::Test", LoadSample5); - string id = identityToString(obj->ice_getIdentity()); + string id = comm->identityToString(obj->ice_getIdentity()); test(id == "Server1" || id == "Server2" || id == "SimpleServer" || id == "IceBox1-Service1" || id == "IceBox1-Service2" || id == "IceBox2-Service1" || id == "IceBox2-Service2" || diff --git a/cpp/test/IceGrid/session/AllTests.cpp b/cpp/test/IceGrid/session/AllTests.cpp index e7f18c31519..dcf1d8414b8 100644 --- a/cpp/test/IceGrid/session/AllTests.cpp +++ b/cpp/test/IceGrid/session/AllTests.cpp @@ -269,7 +269,7 @@ public: Lock sync(*this); this->objects.erase(id); updated(updateSerial(0, "object removed `" + - identityToString(id) + "'")); + current.adapter->getCommunicator()->identityToString(id) + "'")); } int serial; diff --git a/csharp/src/Glacier2/SessionFactoryHelper.cs b/csharp/src/Glacier2/SessionFactoryHelper.cs index e21b713944d..28832b36b5b 100644 --- a/csharp/src/Glacier2/SessionFactoryHelper.cs +++ b/csharp/src/Glacier2/SessionFactoryHelper.cs @@ -147,7 +147,7 @@ public class SessionFactoryHelper { return getProtocol().Equals("ssl"); } - + /// <summary> /// Sets the protocol that will be used by the session factory to establish the connection.. /// </summary> @@ -161,7 +161,7 @@ public class SessionFactoryHelper { throw new ArgumentException("You must use a valid protocol"); } - + if(!protocol.Equals("tcp") && !protocol.Equals("ssl") && !protocol.Equals("wss") && @@ -240,11 +240,11 @@ public class SessionFactoryHelper return getPortInternal(); } } - + private int getPortInternal() { - return _port == 0 ? ((_protocol.Equals("ssl") || + return _port == 0 ? ((_protocol.Equals("ssl") || _protocol.Equals("wss"))? GLACIER2_SSL_PORT : GLACIER2_TCP_PORT) : _port; } @@ -362,7 +362,7 @@ public class SessionFactoryHelper // plug-in has already been setup we don't want to override the // configuration so it can be loaded from a custom location. // - if((_protocol.Equals("ssl") || _protocol.Equals("wss")) && + if((_protocol.Equals("ssl") || _protocol.Equals("wss")) && initData.properties.getProperty("Ice.Plugin.IceSSL").Length == 0) { initData.properties.setProperty("Ice.Plugin.IceSSL", "IceSSL:IceSSL.PluginFactory"); @@ -383,8 +383,8 @@ public class SessionFactoryHelper { StringBuilder sb = new StringBuilder(); sb.Append("\""); - sb.Append(Ice.Util.identityToString(ident)); - sb.Append("\":"); + sb.Append(Ice.Util.identityToString(ident, Ice.ToStringMode.Unicode)); + sb.Append("\":"); sb.Append(_protocol + " -p "); sb.Append(getPortInternal()); sb.Append(" -h \""); diff --git a/csharp/src/Ice/CommunicatorI.cs b/csharp/src/Ice/CommunicatorI.cs index dade480ecc5..d4f54bdca1d 100644 --- a/csharp/src/Ice/CommunicatorI.cs +++ b/csharp/src/Ice/CommunicatorI.cs @@ -65,7 +65,7 @@ namespace Ice public string identityToString(Ice.Identity ident) { - return Ice.Util.identityToString(ident); + return Ice.Util.identityToString(ident, instance_.toStringMode()); } public ObjectAdapter createObjectAdapter(string name) diff --git a/csharp/src/Ice/Incoming.cs b/csharp/src/Ice/Incoming.cs index 84608522cdb..9df6f1625c7 100644 --- a/csharp/src/Ice/Incoming.cs +++ b/csharp/src/Ice/Incoming.cs @@ -515,10 +515,11 @@ namespace IceInternal using(StringWriter sw = new StringWriter(CultureInfo.CurrentCulture)) { IceUtilInternal.OutputBase output = new IceUtilInternal.OutputBase(sw); + Ice.ToStringMode toStringMode = _instance.toStringMode(); output.setUseTab(false); output.print("dispatch exception:"); - output.print("\nidentity: " + Ice.Util.identityToString(_current.id)); - output.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(_current.facet, "")); + output.print("\nidentity: " + Ice.Util.identityToString(_current.id, toStringMode)); + output.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(_current.facet, "", toStringMode)); output.print("\noperation: " + _current.operation); if(_current.con != null) { diff --git a/csharp/src/Ice/Instance.cs b/csharp/src/Ice/Instance.cs index 97e797f6175..572bf8d8617 100644 --- a/csharp/src/Ice/Instance.cs +++ b/csharp/src/Ice/Instance.cs @@ -336,6 +336,13 @@ namespace IceInternal return _batchAutoFlushSize; } + public Ice.ToStringMode + toStringMode() + { + // No mutex lock, immutable + return _toStringMode; + } + public int cacheMessageBuffers() { // No mutex lock, immutable. @@ -862,6 +869,24 @@ namespace IceInternal } } + string toStringModeStr = _initData.properties.getPropertyWithDefault("Ice.ToStringMode", "Unicode"); + if(toStringModeStr == "Unicode") + { + _toStringMode = Ice.ToStringMode.Unicode; + } + else if(toStringModeStr == "ASCII") + { + _toStringMode = Ice.ToStringMode.ASCII; + } + else if(toStringModeStr == "Compat") + { + _toStringMode = Ice.ToStringMode.Compat; + } + else + { + throw new Ice.InitializationException("The value for Ice.ToStringMode must be Unicode, ASCII or Compat"); + } + _cacheMessageBuffers = _initData.properties.getPropertyAsIntWithDefault("Ice.CacheMessageBuffers", 2); _implicitContext = Ice.ImplicitContextI.create(_initData.properties.getProperty("Ice.ImplicitContext")); @@ -1539,6 +1564,7 @@ namespace IceInternal private DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy(). private int _messageSizeMax; // Immutable, not reset by destroy(). private int _batchAutoFlushSize; // Immutable, not reset by destroy(). + private Ice.ToStringMode _toStringMode; // Immutable, not reset by destroy(). private int _cacheMessageBuffers; // Immutable, not reset by destroy(). private ACMConfig _clientACM; // Immutable, not reset by destroy(). private ACMConfig _serverACM; // Immutable, not reset by destroy(). diff --git a/csharp/src/Ice/InstrumentationI.cs b/csharp/src/Ice/InstrumentationI.cs index a6d733af7fe..3eca65b7ed6 100644 --- a/csharp/src/Ice/InstrumentationI.cs +++ b/csharp/src/Ice/InstrumentationI.cs @@ -395,7 +395,7 @@ namespace IceInternal public string getIdentity() { - return Ice.Util.identityToString(_current.id); + return _current.adapter.getCommunicator().identityToString(_current.id); } readonly private Ice.Current _current; @@ -500,7 +500,7 @@ namespace IceInternal catch(Ice.Exception) { // Either a fixed proxy or the communicator is destroyed. - os.Append(Ice.Util.identityToString(_proxy.ice_getIdentity())); + os.Append(_proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity())); os.Append(" [").Append(_operation).Append(']'); } _id = os.ToString(); @@ -532,7 +532,7 @@ namespace IceInternal { if(_proxy != null) { - return Ice.Util.identityToString(_proxy.ice_getIdentity()); + return _proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity()); } else { diff --git a/csharp/src/Ice/LocatorInfo.cs b/csharp/src/Ice/LocatorInfo.cs index 01c064b9f4e..50eccbbb5fe 100644 --- a/csharp/src/Ice/LocatorInfo.cs +++ b/csharp/src/Ice/LocatorInfo.cs @@ -523,7 +523,8 @@ namespace IceInternal } else { - s.Append("object = " + Ice.Util.identityToString(r.getIdentity()) + "\n"); + s.Append("object = " + Ice.Util.identityToString(r.getIdentity(), r.getInstance().toStringMode()) + + "\n"); } s.Append("endpoints = "); @@ -569,13 +570,13 @@ namespace IceInternal { System.Text.StringBuilder s = new System.Text.StringBuilder(); s.Append("object not found\n"); - s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity())); + s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString()); } Ice.NotRegisteredException e = new Ice.NotRegisteredException(ex); e.kindOfObject = "object"; - e.id = Ice.Util.identityToString(@ref.getIdentity()); + e.id = Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode()); throw e; } catch(Ice.NotRegisteredException) @@ -595,7 +596,7 @@ namespace IceInternal } else { - s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity()) + "\n"); + s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode()) + "\n"); } s.Append("reason = " + ex); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString()); @@ -634,7 +635,7 @@ namespace IceInternal else { s.Append("object\n"); - s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity())); + s.Append("object = " + Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode())); } instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString()); } @@ -674,7 +675,7 @@ namespace IceInternal Instance instance = @ref.getInstance(); System.Text.StringBuilder s = new System.Text.StringBuilder(); s.Append("searching for object by id\nobject = "); - s.Append(Ice.Util.identityToString(@ref.getIdentity())); + s.Append(Ice.Util.identityToString(@ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.ToString()); } diff --git a/csharp/src/Ice/ObjectAdapterI.cs b/csharp/src/Ice/ObjectAdapterI.cs index bcdcd85ad3e..a1213d9ae99 100644 --- a/csharp/src/Ice/ObjectAdapterI.cs +++ b/csharp/src/Ice/ObjectAdapterI.cs @@ -926,7 +926,7 @@ namespace Ice { Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); ex.kindOfObject = "object adapter with router"; - ex.id = Ice.Util.identityToString(router.ice_getIdentity()); + ex.id = Ice.Util.identityToString(router.ice_getIdentity(), instance_.toStringMode()); throw ex; } diff --git a/csharp/src/Ice/PropertyNames.cs b/csharp/src/Ice/PropertyNames.cs index ef987e7ee17..c8f412c8e34 100644 --- a/csharp/src/Ice/PropertyNames.cs +++ b/csharp/src/Ice/PropertyNames.cs @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 5 19:04:47 2016 +// Generated by makeprops.py from file PropertyNames.xml, Thu Oct 20 16:20:13 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -165,6 +165,7 @@ namespace IceInternal new Property(@"^Ice\.ThreadPool\.Server\.ThreadIdleTime$", false, null), new Property(@"^Ice\.ThreadPool\.Server\.ThreadPriority$", false, null), new Property(@"^Ice\.ThreadPriority$", false, null), + new Property(@"^Ice\.ToStringMode$", false, null), new Property(@"^Ice\.Trace\.Admin\.Properties$", false, null), new Property(@"^Ice\.Trace\.Admin\.Logger$", false, null), new Property(@"^Ice\.Trace\.Locator$", false, null), diff --git a/csharp/src/Ice/Reference.cs b/csharp/src/Ice/Reference.cs index 37644c85a6e..19493d35d0a 100644 --- a/csharp/src/Ice/Reference.cs +++ b/csharp/src/Ice/Reference.cs @@ -290,12 +290,14 @@ namespace IceInternal // StringBuilder s = new StringBuilder(); + Ice.ToStringMode toStringMode = instance_.toStringMode(); + // // If the encoded identity string contains characters which // the reference parser uses as separators, then we enclose // the identity string in quotes. // - string id = Ice.Util.identityToString(identity_); + string id = Ice.Util.identityToString(identity_, toStringMode); if(IceUtilInternal.StringUtil.findFirstOf(id, " :@") != -1) { s.Append('"'); @@ -315,7 +317,7 @@ namespace IceInternal // the facet string in quotes. // s.Append(" -f "); - string fs = IceUtilInternal.StringUtil.escapeString(facet_, ""); + string fs = IceUtilInternal.StringUtil.escapeString(facet_, "", toStringMode); if(IceUtilInternal.StringUtil.findFirstOf(fs, " :@") != -1) { s.Append('"'); @@ -1057,7 +1059,7 @@ namespace IceInternal // the reference parser uses as separators, then we enclose // the adapter id string in quotes. // - string a = IceUtilInternal.StringUtil.escapeString(_adapterId, null); + string a = IceUtilInternal.StringUtil.escapeString(_adapterId, null, getInstance().toStringMode()); if(IceUtilInternal.StringUtil.findFirstOf(a, " :@") != -1) { s.Append('"'); diff --git a/csharp/src/Ice/ServantManager.cs b/csharp/src/Ice/ServantManager.cs index a369af5ef1d..526e205c514 100644 --- a/csharp/src/Ice/ServantManager.cs +++ b/csharp/src/Ice/ServantManager.cs @@ -37,11 +37,11 @@ public sealed class ServantManager if(m.ContainsKey(facet)) { Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, instance_.toStringMode()); ex.kindOfObject = "servant"; if(facet.Length > 0) { - ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "", instance_.toStringMode()); } throw ex; } @@ -87,11 +87,11 @@ public sealed class ServantManager if(m == null || !m.ContainsKey(facet)) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, instance_.toStringMode()); ex.kindOfObject = "servant"; if(facet.Length > 0) { - ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "", instance_.toStringMode()); } throw ex; } @@ -138,7 +138,7 @@ public sealed class ServantManager if(m == null) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, instance_.toStringMode()); ex.kindOfObject = "servant"; throw ex; } @@ -251,7 +251,7 @@ public sealed class ServantManager if(l != null) { Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); - ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = IceUtilInternal.StringUtil.escapeString(category, "", instance_.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } @@ -271,7 +271,7 @@ public sealed class ServantManager if(l == null) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = IceUtilInternal.StringUtil.escapeString(category, "", instance_.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } diff --git a/csharp/src/Ice/StringUtil.cs b/csharp/src/Ice/StringUtil.cs index d683cc8b92f..c8c392be86d 100644 --- a/csharp/src/Ice/StringUtil.cs +++ b/csharp/src/Ice/StringUtil.cs @@ -25,7 +25,7 @@ namespace IceUtilInternal { return findFirstOf(str, match, 0); } - + // // Return the index of the first character in str to // appear in match, starting from start. Returns -1 if none is @@ -42,10 +42,10 @@ namespace IceUtilInternal return i; } } - + return -1; } - + // // Return the index of the first character in str which does // not appear in match, starting from 0. Returns -1 if none is @@ -55,7 +55,7 @@ namespace IceUtilInternal { return findFirstNotOf(str, match, 0); } - + // // Return the index of the first character in str which does // not appear in match, starting from start. Returns -1 if none is @@ -72,114 +72,135 @@ namespace IceUtilInternal return i; } } - + return -1; } - - // - // Write the byte b as an escape sequence if it isn't a printable ASCII - // character and append the escape sequence to sb. Additional characters - // that should be escaped can be passed in special. If b is any of these - // characters, b is preceded by a backslash in sb. - // - private static void encodeChar(byte b, StringBuilder sb, string special) + + private static void + encodeChar(char c, StringBuilder sb, string special, Ice.ToStringMode toStringMode) { - switch((char)b) + switch(c) { - case '\\': + case '\\': { sb.Append("\\\\"); break; } - - case '\'': + + case '\'': { sb.Append("\\'"); break; } - - case '"': + + case '"': { sb.Append("\\\""); break; } - - case '\b': + + case '\b': { sb.Append("\\b"); break; } - - case '\f': + + case '\f': { sb.Append("\\f"); break; } - - case '\n': + + case '\n': { sb.Append("\\n"); break; } - - case '\r': + + case '\r': { sb.Append("\\r"); break; } - - case '\t': + + case '\t': { sb.Append("\\t"); break; } - - default: + default: { - if(!(b >= 32 && b <= 126)) + if(special != null && special.IndexOf(c) != -1) { sb.Append('\\'); - string octal = System.Convert.ToString(b, 8); - // - // Add leading zeroes so that we avoid problems during - // decoding. For example, consider the encoded string - // \0013 (i.e., a character with value 1 followed by - // the character '3'). If the leading zeroes were omitted, - // the result would be incorrectly interpreted by the - // decoder as a single character with value 11. - // - for(int j = octal.Length; j < 3; j++) - { - sb.Append('0'); - } - sb.Append(octal); - } - else if(special != null && special.IndexOf((char)b) != -1) - { - sb.Append('\\'); - sb.Append((char)b); + sb.Append(c); } else { - sb.Append((char)b); + int i = (int)c; + if(i < 32 || i > 126) + { + if(toStringMode == Ice.ToStringMode.Compat) + { + // + // When ToStringMode=Compat, c is a UTF-8 byte + // + Debug.Assert(i < 256); + + sb.Append('\\'); + string octal = System.Convert.ToString(i, 8); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(int j = octal.Length; j < 3; j++) + { + sb.Append('0'); + } + sb.Append(octal); + } + else if(i < 32 || i == 127 || toStringMode == Ice.ToStringMode.ASCII) + { + // append \\unnnn + sb.Append("\\u"); + string hex = System.Convert.ToString(i, 16); + for(int j = hex.Length; j < 4; j++) + { + sb.Append('0'); + } + sb.Append(hex); + } + else + { + // keep as is + sb.Append(c); + } + } + else + { + // printable ASCII character + sb.Append(c); + } } - } break; + } } } - + // - // Add escape sequences (such as "\n", or "\007") to make a string - // readable in ASCII. Any characters that appear in special are - // prefixed with a backslash in the returned string. + // Add escape sequences (such as "\n", or "\007") to the input string // - public static string escapeString(string s, string special) + public static string escapeString(string s, string special, Ice.ToStringMode toStringMode) { if(special != null) { for(int i = 0; i < special.Length; ++i) { - if((int)special[i] < 32 || (int)special[i] > 126) + if(special[i] < 32 || special[i] > 126) { throw new System.ArgumentException("special characters must be in ASCII range 32-126", "special"); @@ -187,22 +208,64 @@ namespace IceUtilInternal } } - UTF8Encoding utf8 = new UTF8Encoding(); - byte[] bytes = utf8.GetBytes(s); + if(toStringMode == Ice.ToStringMode.Compat) + { + // Encode UTF-8 bytes + + UTF8Encoding utf8 = new UTF8Encoding(); + byte[] bytes = utf8.GetBytes(s); - StringBuilder result = new StringBuilder(bytes.Length); - for(int i = 0; i < bytes.Length; i++) + StringBuilder result = new StringBuilder(bytes.Length); + for(int i = 0; i < bytes.Length; i++) + { + encodeChar((char)bytes[i], result, special, toStringMode); + } + + return result.ToString(); + } + else { - encodeChar(bytes[i], result, special); + StringBuilder result = new StringBuilder(s.Length); + + for(int i = 0; i < s.Length; i++) + { + char c = s[i]; + if(toStringMode == Ice.ToStringMode.Unicode || !System.Char.IsSurrogate(c)) + { + encodeChar(c, result, special, toStringMode); + } + else + { + Debug.Assert(toStringMode == Ice.ToStringMode.ASCII && System.Char.IsSurrogate(c)); + if(i + 1 == s.Length) + { + throw new System.ArgumentException("High surrogate without low surrogate"); + } + else + { + i++; + int codePoint = System.Char.ConvertToUtf32(c, s[i]); + // append \Unnnnnnnn + result.Append("\\U"); + string hex = System.Convert.ToString(codePoint, 16); + for(int j = hex.Length; j < 8; j++) + { + result.Append('0'); + } + result.Append(hex); + } + } + } + + return result.ToString(); } - - return result.ToString(); } - - private static char checkChar(string s, int pos) + + private static char + checkChar(string s, int pos) { char c = s[pos]; - if(!(c >= 32 && c <= 126)) + if(c < 32 || c == 127) { string msg; if(pos > 0) @@ -219,23 +282,22 @@ namespace IceUtilInternal return c; } + // - // Decode the character or escape sequence starting at start and return it. - // end marks the one-past-the-end position of the substring to be scanned. - // nextStart is set to the index of the first character following the decoded - // character or escape sequence. + // Decode the character or escape sequence starting at start and appends it to result; + // returns the index of the first character following the decoded character + // or escape sequence. // - private static char decodeChar(string s, int start, int end, out int nextStart) + private static int + decodeChar(string s, int start, int end, StringBuilder result, UTF8Encoding utf8Encoding) { Debug.Assert(start >= 0); Debug.Assert(start < end); Debug.Assert(end <= s.Length); - char c; - if(s[start] != '\\') { - c = checkChar(s, start++); + result.Append(checkChar(s, start++)); } else { @@ -243,45 +305,98 @@ namespace IceUtilInternal { throw new System.ArgumentException("trailing backslash"); } - switch(s[++start]) + + char c = s[++start]; + + switch(c) { - case '\\': - case '\'': - case '"': + case '\\': + case '\'': + case '"': + { + ++start; + result.Append(c); + break; + } + case 'b': { - c = s[start++]; + ++start; + result.Append('\b'); break; } - case 'b': + case 'f': { ++start; - c = '\b'; + result.Append('\f'); break; } - case 'f': + case 'n': { ++start; - c = '\f'; + result.Append('\n'); break; } - case 'n': + case 'r': { ++start; - c = '\n'; + result.Append('\r'); break; } - case 'r': + case 't': { ++start; - c = '\r'; + result.Append('\t'); break; } - case 't': + case 'u': + case 'U': { + int codePoint = 0; + bool inBMP = (c == 'u'); + int size = inBMP ? 4 : 8; ++start; - c = '\t'; + while(size > 0 && start < end) + { + c = s[start++]; + int charVal = 0; + if(c >= '0' && c <= '9') + { + charVal = c - '0'; + } + else if(c >= 'a' && c <= 'f') + { + charVal = 10 + (c - 'a'); + } + else if(c >= 'A' && c <= 'F') + { + charVal = 10 + (c - 'A'); + } + else + { + break; // while + } + codePoint = codePoint * 16 + charVal; + --size; + } + if(size > 0) + { + throw new System.ArgumentException("Invalid universal character name: too few hex digits"); + } + if(inBMP && System.Char.IsSurrogate((char)codePoint)) + { + throw new System.ArgumentException("A non-BMP character cannot be encoded with \\unnnn, use \\Unnnnnnnn instead"); + } + if(inBMP || codePoint <= 0xFFFF) + { + result.Append((char)codePoint); + } + else + { + result.Append(System.Char.ConvertFromUtf32(codePoint)); + } break; } + case '0': case '1': case '2': @@ -291,47 +406,63 @@ namespace IceUtilInternal case '6': case '7': { - int val = 0; - for(int j = 0; j < 3 && start < end; ++j) + // UTF-8 byte sequence encoded with octal escapes + + byte[] arr = new byte[end - start]; + int i = 0; + bool done = false; + while(!done) { - int charVal = s[start++] - '0'; - if(charVal < 0 || charVal > 7) + int val = 0; + for(int j = 0; j < 3 && start < end; ++j) { - --start; - break; + int charVal = s[start++] - '0'; + if(charVal < 0 || charVal > 7) + { + --start; + if(j == 0) + { + // first character after escape is not 0-7: + done = true; + --start; // go back to the previous backslash + } + break; // for + } + val = val * 8 + charVal; + } + + if(!done) + { + if(val > 255) + { + string msg = "octal value \\" + System.Convert.ToString(val, 8) + " (" + val + ") is out of range"; + throw new System.ArgumentException(msg); + } + arr[i++] = (byte)val; + + if((start + 1 < end) && s[start] == '\\') + { + start++; + // loop, read next octal escape sequence + } + else + { + done = true; + } } - val = val * 8 + charVal; - } - if(val > 255) - { - string msg = "octal value \\" + System.Convert.ToString(val, 8) + " (" + val + - ") is out of range"; - throw new System.ArgumentException(msg, "s"); } - c = System.Convert.ToChar(val); + + result.Append(utf8Encoding.GetString(arr, 0, i)); // May raise ArgumentException. break; } default: { - c = checkChar(s, start++); + result.Append(checkChar(s, start++)); break; } } } - nextStart = start; - return c; - } - - // - // Remove escape sequences from s and append the result to sb. - // Return true if successful, false otherwise. - // - private static void decodeString(string s, int start, int end, StringBuilder sb) - { - while(start < end) - { - sb.Append(decodeChar(s, start, end, out start)); - } + return start; } // @@ -342,18 +473,26 @@ namespace IceUtilInternal { Debug.Assert(start >= 0 && start <= end && end <= s.Length); - StringBuilder sb = new StringBuilder(); - decodeString(s, start, end, sb); - string decodedString = sb.ToString(); - - byte[] arr = new byte[decodedString.Length]; - for(int i = 0; i < arr.Length; ++i) + // Optimization for strings without escapes + if(start == end || s.IndexOf('\\', start, end - start) == -1) { - arr[i] = (byte)decodedString[i]; + int p = start; + while(p < end) + { + checkChar(s, p++); + } + return s.Substring(start, end - start); + } + else + { + StringBuilder sb = new StringBuilder(end - start); + UTF8Encoding utf8Encoding = new UTF8Encoding(false, true); + while(start < end) + { + start = decodeChar(s, start, end, sb, utf8Encoding); + } + return sb.ToString(); } - - UTF8Encoding utf8 = new UTF8Encoding(false, true); - return utf8.GetString(arr, 0, arr.Length); // May raise ArgumentException. } // @@ -402,7 +541,7 @@ namespace IceUtilInternal continue; } } - + if(pos < str.Length) { arr[n++] = str[pos++]; @@ -425,7 +564,7 @@ namespace IceUtilInternal { return checkQuote(s, 0); } - + // // If a single or double quotation mark is found at the start position, // then the position of the matching closing quote is returned. If no @@ -507,7 +646,7 @@ namespace IceUtilInternal public int Compare(string l, string r) { return string.CompareOrdinal(l, r); - } + } } public static System.Collections.Generic.IComparer<string> OrdinalStringComparer = new OrdinalStringComparerImpl(); diff --git a/csharp/src/Ice/TraceUtil.cs b/csharp/src/Ice/TraceUtil.cs index f815b712473..cb18fb957a9 100644 --- a/csharp/src/Ice/TraceUtil.cs +++ b/csharp/src/Ice/TraceUtil.cs @@ -175,15 +175,22 @@ namespace IceInternal { try { + + Ice.ToStringMode toStringMode = Ice.ToStringMode.Unicode; + if(str.instance() != null) + { + toStringMode = str.instance().toStringMode(); + } + Ice.Identity identity = new Ice.Identity(); identity.read__(str); - s.Write("\nidentity = " + Ice.Util.identityToString(identity)); + s.Write("\nidentity = " + Ice.Util.identityToString(identity, toStringMode)); string[] facet = str.readStringSeq(); s.Write("\nfacet = "); if(facet.Length > 0) { - s.Write(IceUtilInternal.StringUtil.escapeString(facet[0], "")); + s.Write(IceUtilInternal.StringUtil.escapeString(facet[0], "", toStringMode)); } string operation = str.readString(); diff --git a/csharp/src/Ice/Util.cs b/csharp/src/Ice/Util.cs index 3d97733c889..ef2ce56c6e1 100644 --- a/csharp/src/Ice/Util.cs +++ b/csharp/src/Ice/Util.cs @@ -322,17 +322,18 @@ namespace Ice /// Converts an object identity to a string. /// </summary> /// <param name="ident">The object identity to convert.</param> + /// <param name="toStringMode">Specifies if and how non-printable ASCII characters are escaped in the result.</param> /// <returns>The string representation of the object identity.</returns> - public static string identityToString(Identity ident) + public static string identityToString(Identity ident, ToStringMode toStringMode = ToStringMode.Unicode) { if(ident.category == null || ident.category.Length == 0) { - return IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + return IceUtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); } else { - return IceUtilInternal.StringUtil.escapeString(ident.category, "/") + '/' + - IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + return IceUtilInternal.StringUtil.escapeString(ident.category, "/", toStringMode) + '/' + + IceUtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); } } diff --git a/csharp/test/Ice/location/AllTests.cs b/csharp/test/Ice/location/AllTests.cs index 707520b4e36..129737c3073 100644 --- a/csharp/test/Ice/location/AllTests.cs +++ b/csharp/test/Ice/location/AllTests.cs @@ -603,7 +603,7 @@ public class AllTests : TestCommon.TestApp adapter.activate(); HelloPrx helloPrx = HelloPrxHelper.checkedCast( - communicator.stringToProxy("\"" + Ice.Util.identityToString(id) + "\"")); + communicator.stringToProxy("\"" + communicator.identityToString(id) + "\"")); test(helloPrx.ice_getConnection() == null); adapter.deactivate(); diff --git a/csharp/test/Ice/proxy/AllTests.cs b/csharp/test/Ice/proxy/AllTests.cs index 1998f785847..bd7d5aacbe9 100644 --- a/csharp/test/Ice/proxy/AllTests.cs +++ b/csharp/test/Ice/proxy/AllTests.cs @@ -254,11 +254,77 @@ public class AllTests : TestCommon.TestApp // Test for bug ICE-5543: escaped escapes in stringToIdentity // Ice.Identity id = new Ice.Identity("test", ",X2QNUAzSBcJ_e$AV;E\\"); - Ice.Identity id2 = Ice.Util.stringToIdentity(Ice.Util.identityToString(id)); + Ice.Identity id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); test(id.Equals(id2)); id = new Ice.Identity("test", ",X2QNUAz\\SB\\/cJ_e$AV;E\\\\"); - id2 = Ice.Util.stringToIdentity(Ice.Util.identityToString(id)); + id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.Equals(id2)); + + id = new Ice.Identity("/test", "cat/"); + string idStr = communicator.identityToString(id); + test(idStr == "cat\\//\\/test"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + + try + { + // Illegal character < 32 + id = Ice.Util.stringToIdentity("xx\01FooBar"); + test(false); + } + catch(Ice.IdentityParseException) + { + } + + try + { + // Illegal surrogate + id = Ice.Util.stringToIdentity("xx\\ud911"); + test(false); + } + catch(Ice.IdentityParseException) + { + } + + // Testing bytes 127 (\x7F, \177) and € + id = new Ice.Identity("test", "\x7f€"); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr == "\\u007f€/test"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + test(Ice.Util.identityToString(id) == idStr); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr == "\\u007f\\u20ac/test"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Compat); + test(idStr == "\\177\\342\\202\\254/test"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + + id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.Equals(id2)); + + // More unicode character + id = new Ice.Identity("banana \x0E-\ud83c\udf4c\u20ac\u00a2\u0024", "greek \ud800\udd6a"); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr == "greek \ud800\udd6a/banana \\u000e-\ud83c\udf4c\u20ac\u00a2$"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr == "greek \\U0001016a/banana \\u000e-\\U0001f34c\\u20ac\\u00a2$"); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.Equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Compat); + id2 = Ice.Util.stringToIdentity(idStr); + test(idStr == "greek \\360\\220\\205\\252/banana \\016-\\360\\237\\215\\214\\342\\202\\254\\302\\242$"); test(id.Equals(id2)); WriteLine("ok"); @@ -456,8 +522,6 @@ public class AllTests : TestCommon.TestApp test(communicator.identityToString( baseProxy.ice_identity(communicator.stringToIdentity("other")).ice_getIdentity()).Equals("other")); #pragma warning restore 612, 618 - test(Ice.Util.identityToString( - baseProxy.ice_identity(Ice.Util.stringToIdentity("other")).ice_getIdentity()).Equals("other")); test(baseProxy.ice_facet("facet").ice_getFacet().Equals("facet")); test(baseProxy.ice_adapterId("id").ice_getAdapterId().Equals("id")); test(baseProxy.ice_twoway().ice_isTwoway()); diff --git a/csharp/test/Ice/proxy/run.py b/csharp/test/Ice/proxy/run.py index d0771952158..88a9c6c01bc 100755 --- a/csharp/test/Ice/proxy/run.py +++ b/csharp/test/Ice/proxy/run.py @@ -23,5 +23,5 @@ import TestUtil TestUtil.queueClientServerTest() TestUtil.queueClientServerTest(configName = "amd", localOnly = True, message = "Running test with AMD server.", server="serveramd") -TestUtil.queueCollocatedTest() +TestUtil.queueCollocatedTest(additionalOptions = "--Ice.ToStringMode=Compat") TestUtil.runQueuedTests() diff --git a/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java index 72d7031cc94..97543a77755 100644 --- a/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java +++ b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java @@ -369,7 +369,7 @@ public class SessionFactoryHelper { StringBuilder sb = new StringBuilder(); sb.append("\""); - sb.append(Ice.Util.identityToString(ident)); + sb.append(Ice.Util.identityToString(ident, Ice.ToStringMode.Unicode)); sb.append("\":"); sb.append(_protocol + " -p "); sb.append(getPortInternal()); diff --git a/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java b/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java index 5523f7663b4..8ca4682639c 100644 --- a/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java +++ b/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java @@ -78,7 +78,7 @@ public final class CommunicatorI implements Communicator public String identityToString(Ice.Identity ident) { - return Ice.Util.identityToString(ident); + return Ice.Util.identityToString(ident, _instance.toStringMode()); } @Override diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java b/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java index 1aeef2206fa..53abcf4b4b6 100644 --- a/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java @@ -980,7 +980,8 @@ public final class ObjectAdapterI implements ObjectAdapter if(_routerInfo.getAdapter() != null) { throw new AlreadyRegisteredException("object adapter with router", - Ice.Util.identityToString(router.ice_getIdentity())); + Ice.Util.identityToString(router.ice_getIdentity(), + _instance.toStringMode())); } // diff --git a/java-compat/src/Ice/src/main/java/Ice/Util.java b/java-compat/src/Ice/src/main/java/Ice/Util.java index 3c2b04d8fd4..a758a316e00 100644 --- a/java-compat/src/Ice/src/main/java/Ice/Util.java +++ b/java-compat/src/Ice/src/main/java/Ice/Util.java @@ -324,23 +324,37 @@ public final class Util * * @param ident The object identity to convert. * + * @param toStringMode Specifies if and how non-printable ASCII characters are escaped in the result. + * * @return The string representation of the object identity. **/ - public static String - identityToString(Identity ident) + public static String identityToString(Identity ident, ToStringMode toStringMode) { if(ident.category == null || ident.category.length() == 0) { - return IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + return IceUtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); } else { - return IceUtilInternal.StringUtil.escapeString(ident.category, "/") + '/' + - IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + return IceUtilInternal.StringUtil.escapeString(ident.category, "/", toStringMode) + '/' + + IceUtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); } } /** + * Converts an object identity to a string. + * + * @param ident The object identity to convert. + * + * @return The string representation of the object identity using the default mode (Unicode) + **/ + // public static String identityToString(Identity ident) + // { + // return identityToString(ident, ToStringMode.Unicode); + // } + + + /** * Compares the object identities of two proxies. * * @param lhs A proxy. diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java index 095948736e3..5b9f377d807 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java @@ -319,7 +319,7 @@ public class CommunicatorObserverI implements Ice.Instrumentation.CommunicatorOb public String getIdentity() { - return Ice.Util.identityToString(_current.id); + return _current.adapter.getCommunicator().identityToString(_current.id); } final private Ice.Current _current; @@ -428,7 +428,7 @@ public class CommunicatorObserverI implements Ice.Instrumentation.CommunicatorOb catch(Exception ex) { // Either a fixed proxy or the communicator is destroyed. - os.append(Ice.Util.identityToString(_proxy.ice_getIdentity())); + os.append(_proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity())); os.append(" [").append(_operation).append(']'); } _id = os.toString(); @@ -458,7 +458,7 @@ public class CommunicatorObserverI implements Ice.Instrumentation.CommunicatorOb { if(_proxy != null) { - return Ice.Util.identityToString(_proxy.ice_getIdentity()); + return _proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity()); } else { diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java b/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java index 1e1b4c4dfa8..2723ce7a7b7 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java @@ -236,8 +236,8 @@ class IncomingBase IceUtilInternal.OutputBase out = new IceUtilInternal.OutputBase(pw); out.setUseTab(false); out.print("dispatch exception:"); - out.print("\nidentity: " + Ice.Util.identityToString(_current.id)); - out.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(_current.facet, "")); + out.print("\nidentity: " + Ice.Util.identityToString(_current.id, _instance.toStringMode())); + out.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(_current.facet, "", _instance.toStringMode())); out.print("\noperation: " + _current.operation); if(_current.con != null) { diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Instance.java b/java-compat/src/Ice/src/main/java/IceInternal/Instance.java index 30b78609ca8..997b64313f6 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/Instance.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/Instance.java @@ -393,6 +393,13 @@ public final class Instance implements Ice.ClassResolver return _batchAutoFlushSize; } + public Ice.ToStringMode + toStringMode() + { + // No mutex lock, immutable + return _toStringMode; + } + public int cacheMessageBuffers() { @@ -1018,6 +1025,24 @@ public final class Instance implements Ice.ClassResolver } } + String toStringModeStr = _initData.properties.getPropertyWithDefault("Ice.ToStringMode", "Unicode"); + if(toStringModeStr.equals("Unicode")) + { + _toStringMode = Ice.ToStringMode.Unicode; + } + else if(toStringModeStr.equals("ASCII")) + { + _toStringMode = Ice.ToStringMode.ASCII; + } + else if(toStringModeStr.equals("Compat")) + { + _toStringMode = Ice.ToStringMode.Compat; + } + else + { + throw new Ice.InitializationException("The value for Ice.ToStringMode must be Unicode, ASCII or Compat"); + } + _implicitContext = Ice.ImplicitContextI.create(_initData.properties.getProperty("Ice.ImplicitContext")); _routerManager = new RouterManager(); @@ -1820,6 +1845,7 @@ public final class Instance implements Ice.ClassResolver private final DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy(). private final int _messageSizeMax; // Immutable, not reset by destroy(). private final int _batchAutoFlushSize; // Immutable, not reset by destroy(). + private final Ice.ToStringMode _toStringMode; // Immutable, not reset by destroy(). private final int _cacheMessageBuffers; // Immutable, not reset by destroy(). private final ACMConfig _clientACM; // Immutable, not reset by destroy(). private final ACMConfig _serverACM; // Immutable, not reset by destroy(). diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java b/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java index 82c4dea0e25..65f0c20840c 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java @@ -466,7 +466,7 @@ public final class LocatorInfo else { s.append("object = "); - s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append(Ice.Util.identityToString(ref.getIdentity(), ref.getInstance().toStringMode())); s.append("\n"); } @@ -518,13 +518,13 @@ public final class LocatorInfo StringBuilder s = new StringBuilder(128); s.append("object not found\n"); s.append("object = "); - s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append(Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); } Ice.NotRegisteredException e = new Ice.NotRegisteredException(); e.kindOfObject = "object"; - e.id = Ice.Util.identityToString(ref.getIdentity()); + e.id = Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode()); throw e; } catch(Ice.NotRegisteredException ex) @@ -547,7 +547,7 @@ public final class LocatorInfo else { s.append("object = "); - s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append(Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); s.append("\n"); } s.append("reason = " + ex); @@ -591,7 +591,7 @@ public final class LocatorInfo { s.append("object\n"); s.append("object = "); - s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append(Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); s.append("\n"); } instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); @@ -630,7 +630,7 @@ public final class LocatorInfo StringBuilder s = new StringBuilder(128); s.append("searching for object by id\n"); s.append("object = "); - s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append(Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); } diff --git a/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java index 78fca903d04..54e72359604 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Aug 18 20:28:56 2016 +// Generated by makeprops.py from file PropertyNames.xml, Tue Oct 18 11:39:01 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -165,6 +165,7 @@ public final class PropertyNames new Property("Ice\\.ThreadPool\\.Server\\.ThreadIdleTime", false, null), new Property("Ice\\.ThreadPool\\.Server\\.ThreadPriority", false, null), new Property("Ice\\.ThreadPriority", false, null), + new Property("Ice\\.ToStringMode", false, null), new Property("Ice\\.Trace\\.Admin\\.Properties", false, null), new Property("Ice\\.Trace\\.Admin\\.Logger", false, null), new Property("Ice\\.Trace\\.Locator", false, null), @@ -980,7 +981,7 @@ public final class PropertyNames new Property("IceSSL\\.DHParams", false, null), new Property("IceSSL\\.EntropyDaemon", false, null), new Property("IceSSL\\.FindCert", false, null), - new Property("IceSSL\\.FindCert\\.[^\\s]+", true, "IceSSL.FindCert"), + new Property("IceSSL\\.FindCert\\.[^\\s]+", true, null), new Property("IceSSL\\.InitOpenSSL", false, null), new Property("IceSSL\\.KeyFile", true, null), new Property("IceSSL\\.Keychain", false, null), diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Reference.java b/java-compat/src/Ice/src/main/java/IceInternal/Reference.java index b7ea1dd2f32..48ac1b0788a 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/Reference.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/Reference.java @@ -306,13 +306,18 @@ public abstract class Reference implements Cloneable // StringBuilder s = new StringBuilder(128); + Ice.ToStringMode toStringMode = _instance.toStringMode(); + final String separators = " :@"; + + String id = Ice.Util.identityToString(_identity, toStringMode); + // // If the encoded identity string contains characters which // the reference parser uses as separators, then we enclose // the identity string in quotes. // - String id = Ice.Util.identityToString(_identity); - if(IceUtilInternal.StringUtil.findFirstOf(id, " :@") != -1) + + if(IceUtilInternal.StringUtil.findFirstOf(id, separators) != -1) { s.append('"'); s.append(id); @@ -331,8 +336,8 @@ public abstract class Reference implements Cloneable // the facet string in quotes. // s.append(" -f "); - String fs = IceUtilInternal.StringUtil.escapeString(_facet, ""); - if(IceUtilInternal.StringUtil.findFirstOf(fs, " :@") != -1) + String fs = IceUtilInternal.StringUtil.escapeString(_facet, "", toStringMode); + if(IceUtilInternal.StringUtil.findFirstOf(fs, separators) != -1) { s.append('"'); s.append(fs); @@ -481,16 +486,16 @@ public abstract class Reference implements Cloneable @Override public Reference clone() { - Reference c = null; - try - { - c = (Reference)super.clone(); - } - catch(CloneNotSupportedException ex) - { - assert false; - } - return c; + Reference c = null; + try + { + c = (Reference)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; } protected int _hashValue; diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java b/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java index 688b2ca9935..bdca554000a 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java @@ -353,7 +353,7 @@ public class RoutableReference extends Reference // the reference parser uses as separators, then we enclose // the adapter id string in quotes. // - String a = IceUtilInternal.StringUtil.escapeString(_adapterId, null); + String a = IceUtilInternal.StringUtil.escapeString(_adapterId, null, getInstance().toStringMode()); if(IceUtilInternal.StringUtil.findFirstOf(a, " :@") != -1) { s.append('"'); diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java b/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java index 2789304f276..aa74865221c 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java @@ -32,11 +32,11 @@ public final class ServantManager if(m.containsKey(facet)) { Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length() > 0) { - ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "", _instance.toStringMode()); } throw ex; } @@ -77,11 +77,11 @@ public final class ServantManager if(m == null || (obj = m.remove(facet)) == null) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length() > 0) { - ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, "", _instance.toStringMode()); } throw ex; } @@ -120,7 +120,7 @@ public final class ServantManager if(m == null) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = Ice.Util.identityToString(ident); + ex.id = Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; throw ex; } @@ -218,7 +218,7 @@ public final class ServantManager if(l != null) { Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); - ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = IceUtilInternal.StringUtil.escapeString(category, "", _instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } @@ -236,7 +236,7 @@ public final class ServantManager if(l == null) { Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); - ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = IceUtilInternal.StringUtil.escapeString(category, "", _instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java b/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java index 2ff165c475d..d50797350e5 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java @@ -166,15 +166,21 @@ public final class TraceUtil { try { + Ice.ToStringMode toStringMode = Ice.ToStringMode.Unicode; + if(stream.instance() != null) + { + toStringMode = stream.instance().toStringMode(); + } + Ice.Identity identity = new Ice.Identity(); identity.__read(stream); - out.write("\nidentity = " + Ice.Util.identityToString(identity)); + out.write("\nidentity = " + Ice.Util.identityToString(identity, toStringMode)); String[] facet = stream.readStringSeq(); out.write("\nfacet = "); if(facet.length > 0) { - out.write(IceUtilInternal.StringUtil.escapeString(facet[0], "")); + out.write(IceUtilInternal.StringUtil.escapeString(facet[0], "", toStringMode)); } String operation = stream.readString(); diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java index 953359c5c4b..5c274db2375 100644 --- a/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java @@ -75,97 +75,119 @@ public final class StringUtil return -1; } - // - // Write the byte b as an escape sequence if it isn't a printable ASCII - // character and append the escape sequence to sb. Additional characters - // that should be escaped can be passed in special. If b is any of these - // characters, b is preceded by a backslash in sb. - // private static void - encodeChar(byte b, StringBuilder sb, String special) + encodeChar(char c, StringBuilder sb, String special, Ice.ToStringMode toStringMode) { - switch(b) + switch(c) { - case (byte)'\\': + case '\\': { sb.append("\\\\"); break; } - case (byte)'\'': + case '\'': { sb.append("\\'"); break; } - case (byte)'"': + case '"': { sb.append("\\\""); break; } - case (byte)'\b': + case '\b': { sb.append("\\b"); break; } - case (byte)'\f': + case '\f': { sb.append("\\f"); break; } - case (byte)'\n': + case '\n': { sb.append("\\n"); break; } - case (byte)'\r': + case '\r': { sb.append("\\r"); break; } - case (byte)'\t': + case '\t': { sb.append("\\t"); break; } default: { - if(!(b >= 32 && b <= 126)) - { - sb.append('\\'); - String octal = Integer.toOctalString(b < 0 ? b + 256 : b); - // - // Add leading zeroes so that we avoid problems during - // decoding. For example, consider the encoded string - // \0013 (i.e., a character with value 1 followed by - // the character '3'). If the leading zeroes were omitted, - // the result would be incorrectly interpreted by the - // decoder as a single character with value 11. - // - for(int j = octal.length(); j < 3; j++) - { - sb.append('0'); - } - sb.append(octal); - } - else if(special != null && special.indexOf((char)b) != -1) + if(special != null && special.indexOf(c) != -1) { sb.append('\\'); - sb.append((char)b); + sb.append(c); } else { - sb.append((char)b); + if(c < 32 || c > 126) + { + if(toStringMode == Ice.ToStringMode.Compat) + { + // + // When ToStringMode=Compat, c is a UTF-8 byte + // + assert(c < 256); + + sb.append('\\'); + String octal = Integer.toOctalString(c); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(int j = octal.length(); j < 3; j++) + { + sb.append('0'); + } + sb.append(octal); + } + else if(c < 32 || c == 127 || toStringMode == Ice.ToStringMode.ASCII) + { + // append \\unnnn + sb.append("\\u"); + String hex = Integer.toHexString(c); + for(int j = hex.length(); j < 4; j++) + { + sb.append('0'); + } + sb.append(hex); + } + else + { + // keep as is + sb.append(c); + } + } + else + { + // printable ASCII character + sb.append(c); + } } + break; } } } // - // Add escape sequences (such as "\n", or "\007") to make a string - // readable in ASCII. Any characters that appear in special are - // prefixed with a backlash in the returned string. + // Add escape sequences (like "\n" to the input string) + // The second parameter adds characters to escape, and can be empty. // public static String - escapeString(String s, String special) + escapeString(String s, String special, Ice.ToStringMode toStringMode) { if(special != null) { @@ -178,31 +200,72 @@ public final class StringUtil } } - byte[] bytes = null; - try + if(toStringMode == Ice.ToStringMode.Compat) { - bytes = s.getBytes("UTF8"); + // Encode UTF-8 bytes + + byte[] bytes = null; + try + { + bytes = s.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return null; + } + + StringBuilder result = new StringBuilder(bytes.length); + for(int i = 0; i < bytes.length; i++) + { + encodeChar((char)(bytes[i] & 0xFF), result, special, toStringMode); + } + + return result.toString(); } - catch(java.io.UnsupportedEncodingException ex) + else { - assert(false); - return null; - } + StringBuilder result = new StringBuilder(s.length()); - StringBuilder result = new StringBuilder(bytes.length); - for(int i = 0; i < bytes.length; i++) - { - encodeChar(bytes[i], result, special); - } + for(int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + if(toStringMode == Ice.ToStringMode.Unicode || !Character.isSurrogate(c)) + { + encodeChar(c, result, special, toStringMode); + } + else + { + assert(toStringMode == Ice.ToStringMode.ASCII && Character.isSurrogate(c)); + if(i + 1 == s.length()) + { + throw new IllegalArgumentException("High surrogate without low surrogate"); + } + else + { + i++; + int codePoint = Character.toCodePoint(c, s.charAt(i)); + // append \Unnnnnnnn + result.append("\\U"); + String hex = Integer.toHexString(codePoint); + for(int j = hex.length(); j < 8; j++) + { + result.append('0'); + } + result.append(hex); + } + } + } - return result.toString(); + return result.toString(); + } } private static char checkChar(String s, int pos) { char c = s.charAt(pos); - if(!(c >= 32 && c <= 126)) + if(c < 32 || c == 127) { String msg; if(pos > 0) @@ -213,28 +276,27 @@ public final class StringUtil { msg = "first character"; } - msg += " is not a printable ASCII character (ordinal " + (int)c + ")"; + msg += " has invalid ordinal value " + (int)c; throw new IllegalArgumentException(msg); } return c; } // - // Decode the character or escape sequence starting at start and return it. - // newStart is set to the index of the first character following the decoded character + // Decode the character or escape sequence starting at start and appends it to result; + // returns the index of the first character following the decoded character // or escape sequence. // - private static char decodeChar(String s, int start, int end, Ice.Holder<Integer> nextStart) + private static int + decodeChar(String s, int start, int end, StringBuilder result) { assert(start >= 0); assert(start < end); assert(end <= s.length()); - char c; - if(s.charAt(start) != '\\') { - c = checkChar(s, start++); + result.append(checkChar(s, start++)); } else { @@ -242,45 +304,98 @@ public final class StringUtil { throw new IllegalArgumentException("trailing backslash"); } - switch(s.charAt(++start)) + + char c = s.charAt(++start); + + switch(c) { case '\\': case '\'': case '"': { - c = s.charAt(start++); + ++start; + result.append(c); break; } case 'b': { ++start; - c = '\b'; + result.append('\b'); break; } case 'f': { ++start; - c = '\f'; + result.append('\f'); break; } case 'n': { ++start; - c = '\n'; + result.append('\n'); break; } case 'r': { ++start; - c = '\r'; + result.append('\r'); break; } case 't': { ++start; - c = '\t'; + result.append('\t'); break; } + case 'u': + case 'U': + { + int codePoint = 0; + boolean inBMP = (c == 'u'); + int size = inBMP ? 4 : 8; + ++start; + while(size > 0 && start < end) + { + c = s.charAt(start++); + int charVal = 0; + if(c >= '0' && c <= '9') + { + charVal = c - '0'; + } + else if(c >= 'a' && c <= 'f') + { + charVal = 10 + (c - 'a'); + } + else if(c >= 'A' && c <= 'F') + { + charVal = 10 + (c - 'A'); + } + else + { + break; // while + } + codePoint = codePoint * 16 + charVal; + --size; + } + if(size > 0) + { + throw new IllegalArgumentException("Invalid universal character name: too few hex digits"); + } + if(inBMP && Character.isSurrogate((char)codePoint)) + { + throw new IllegalArgumentException("A non-BMP character cannot be encoded with \\unnnn, use \\Unnnnnnnn instead"); + } + if(inBMP || Character.isBmpCodePoint(codePoint)) + { + result.append((char)codePoint); + } + else + { + result.append(Character.toChars(codePoint)); + } + break; + } + case '0': case '1': case '2': @@ -290,49 +405,71 @@ public final class StringUtil case '6': case '7': { - int val = 0; - for(int j = 0; j < 3 && start < end; ++j) + // UTF-8 byte sequence encoded with octal escapes + + byte[] arr = new byte[end - start]; + int i = 0; + boolean done = false; + while(!done) { - int charVal = s.charAt(start++) - '0'; - if(charVal < 0 || charVal > 7) + int val = 0; + for(int j = 0; j < 3 && start < end; ++j) { - --start; - break; + int charVal = s.charAt(start++) - '0'; + if(charVal < 0 || charVal > 7) + { + --start; + if(j == 0) + { + // first character after escape is not 0-7: + done = true; + --start; // go back to the previous backslash + } + break; // for + } + val = val * 8 + charVal; } - val = val * 8 + charVal; + + if(!done) + { + if(val > 255) + { + String msg = "octal value \\" + Integer.toOctalString(val) + " (" + val + ") is out of range"; + throw new IllegalArgumentException(msg); + } + arr[i++] = (byte)val; + + if((start + 1 < end) && s.charAt(start) == '\\') + { + start++; + // loop, read next octal escape sequence + } + else + { + done = true; + } + } + } + + try + { + result.append(new String(arr, 0, i, "UTF8")); } - if(val > 255) + catch(java.io.UnsupportedEncodingException ex) { - String msg = "octal value \\" + Integer.toOctalString(val) + " (" + val + ") is out of range"; - throw new IllegalArgumentException(msg); + throw new IllegalArgumentException("unsupported encoding", ex); } - c = (char)val; break; } default: { - c = checkChar(s, start++); + result.append(checkChar(s, start++)); break; } } } - nextStart.value = start; - return c; - } - // - // Remove escape sequences from s and append the result to sb. - // Return true if successful, false otherwise. - // - private static void - decodeString(String s, int start, int end, StringBuilder sb) - { - Ice.Holder<Integer> nextStart = new Ice.Holder<Integer>(); - while(start < end) - { - sb.append(decodeChar(s, start, end, nextStart)); - start = nextStart.value; - } + return start; } // @@ -344,26 +481,29 @@ public final class StringUtil { assert(start >= 0 && start <= end && end <= s.length()); - StringBuilder sb = new StringBuilder(end - start); - decodeString(s, start, end, sb); - String decodedString = sb.toString(); - - byte[] arr = new byte[decodedString.length()]; - for(int i = 0; i < arr.length; ++i) - { - arr[i] = (byte)decodedString.charAt(i); - } - - try + // Optimization for strings without escapes + int p = s.indexOf('\\', start); + if(p == -1 || p >= end) { - return new String(arr, 0, arr.length, "UTF8"); + p = start; + while(p < end) + { + checkChar(s, p++); + } + return s.substring(start, end); } - catch(java.io.UnsupportedEncodingException ex) + else { - throw new IllegalArgumentException("unsupported encoding", ex); + StringBuilder sb = new StringBuilder(end - start); + while(start < end) + { + start = decodeChar(s, start, end, sb); + } + return sb.toString(); } } + // // Join a list of strings using the given delimiter. // diff --git a/java-compat/src/IceBox/src/main/java/IceBox/Admin.java b/java-compat/src/IceBox/src/main/java/IceBox/Admin.java index 52e39ee771e..0b363f83c6a 100644 --- a/java-compat/src/IceBox/src/main/java/IceBox/Admin.java +++ b/java-compat/src/IceBox/src/main/java/IceBox/Admin.java @@ -84,7 +84,7 @@ public final class Admin return 1; } - managerProxy = "\"" + Ice.Util.identityToString(managerIdentity) + "\" :" + managerEndpoints; + managerProxy = "\"" + communicator().identityToString(managerIdentity) + "\" :" + managerEndpoints; } else { @@ -95,7 +95,7 @@ public final class Admin return 1; } - managerProxy = "\"" + Ice.Util.identityToString(managerIdentity) + "\" @" + managerAdapterId; + managerProxy = "\"" + communicator().identityToString(managerIdentity) + "\" @" + managerAdapterId; } base = communicator().stringToProxy(managerProxy); diff --git a/java-compat/test/src/main/java/test/Ice/location/AllTests.java b/java-compat/test/src/main/java/test/Ice/location/AllTests.java index 33bada684a8..06eae325c60 100644 --- a/java-compat/test/src/main/java/test/Ice/location/AllTests.java +++ b/java-compat/test/src/main/java/test/Ice/location/AllTests.java @@ -682,7 +682,7 @@ public class AllTests // Note the quotes are necessary here due to ":" in the // java generated UUID. HelloPrx helloPrx = HelloPrxHelper.checkedCast( - communicator.stringToProxy("\"" + Ice.Util.identityToString(id) + "\"")); + communicator.stringToProxy("\"" + communicator.identityToString(id) + "\"")); test(helloPrx.ice_getConnection() == null); adapter.deactivate(); diff --git a/java-compat/test/src/main/java/test/Ice/proxy/AllTests.java b/java-compat/test/src/main/java/test/Ice/proxy/AllTests.java index 1b92d902a92..4db1ac8cebc 100644 --- a/java-compat/test/src/main/java/test/Ice/proxy/AllTests.java +++ b/java-compat/test/src/main/java/test/Ice/proxy/AllTests.java @@ -270,11 +270,77 @@ public class AllTests // Test for bug ICE-5543: escaped escapes in stringToIdentity // Ice.Identity id = new Ice.Identity("test", ",X2QNUAzSBcJ_e$AV;E\\"); - Ice.Identity id2 = Ice.Util.stringToIdentity(Ice.Util.identityToString(id)); + Ice.Identity id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); test(id.equals(id2)); id = new Ice.Identity("test", ",X2QNUAz\\SB\\/cJ_e$AV;E\\\\"); - id2 = Ice.Util.stringToIdentity(Ice.Util.identityToString(id)); + id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.equals(id2)); + + id = new Ice.Identity("/test", "cat/"); + String idStr = communicator.identityToString(id); + test(idStr.equals("cat\\//\\/test")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + try + { + // Illegal character < 32 + id = Ice.Util.stringToIdentity("xx\01FooBar"); + test(false); + } + catch(Ice.IdentityParseException e) + { + } + + try + { + // Illegal surrogate + id = Ice.Util.stringToIdentity("xx\\ud911"); + test(false); + } + catch(Ice.IdentityParseException e) + { + } + + // Testing bytes 127 (\x7F, \177) and € + id = new Ice.Identity("test", "\177€"); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr.equals("\\u007f€/test")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + // test(Ice.Util.identityToString(id).equals(idStr)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr.equals("\\u007f\\u20ac/test")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Compat); + test(idStr.equals("\\177\\342\\202\\254/test")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + id2 = Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.equals(id2)); + + // More unicode character + id = new Ice.Identity("banana \016-\ud83c\udf4c\u20ac\u00a2\u0024", "greek \ud800\udd6a"); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr.equals("greek \ud800\udd6a/banana \\u000e-\ud83c\udf4c\u20ac\u00a2$")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr.equals("greek \\U0001016a/banana \\u000e-\\U0001f34c\\u20ac\\u00a2$")); + id2 = Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.Util.identityToString(id, Ice.ToStringMode.Compat); + id2 = Ice.Util.stringToIdentity(idStr); + test(idStr.equals("greek \\360\\220\\205\\252/banana \\016-\\360\\237\\215\\214\\342\\202\\254\\302\\242$")); test(id.equals(id2)); out.println("ok"); @@ -461,8 +527,6 @@ public class AllTests out.print("testing proxy methods... "); out.flush(); - test(Ice.Util.identityToString( - base.ice_identity(Ice.Util.stringToIdentity("other")).ice_getIdentity()).equals("other")); test(base.ice_facet("facet").ice_getFacet().equals("facet")); test(base.ice_adapterId("id").ice_getAdapterId().equals("id")); test(base.ice_twoway().ice_isTwoway()); diff --git a/java-compat/test/src/main/java/test/Ice/proxy/run.py b/java-compat/test/src/main/java/test/Ice/proxy/run.py index 78cfe699505..0d0598cb160 100755 --- a/java-compat/test/src/main/java/test/Ice/proxy/run.py +++ b/java-compat/test/src/main/java/test/Ice/proxy/run.py @@ -24,5 +24,5 @@ import TestUtil TestUtil.queueClientServerTest() TestUtil.queueClientServerTest(configName = "amd", localOnly = True, message = "Running test with AMD server.", server="test.Ice.proxy.AMDServer") -TestUtil.queueCollocatedTest() +TestUtil.queueCollocatedTest(additionalOptions = "--Ice.ToStringMode=Compat") TestUtil.runQueuedTests() diff --git a/java/src/Glacier2/src/main/java/com/zeroc/Glacier2/SessionFactoryHelper.java b/java/src/Glacier2/src/main/java/com/zeroc/Glacier2/SessionFactoryHelper.java index f7b86f48c09..d7c293bd3c7 100644 --- a/java/src/Glacier2/src/main/java/com/zeroc/Glacier2/SessionFactoryHelper.java +++ b/java/src/Glacier2/src/main/java/com/zeroc/Glacier2/SessionFactoryHelper.java @@ -352,7 +352,7 @@ public class SessionFactoryHelper { StringBuilder sb = new StringBuilder(); sb.append("\""); - sb.append(Util.identityToString(ident)); + sb.append(Util.identityToString(ident, com.zeroc.Ice.ToStringMode.Unicode)); sb.append("\":"); sb.append(_protocol + " -p "); sb.append(getPortInternal()); diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/CommunicatorI.java b/java/src/Ice/src/main/java/com/zeroc/Ice/CommunicatorI.java index 64ff934f6d4..035c6b39f15 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/CommunicatorI.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/CommunicatorI.java @@ -74,11 +74,11 @@ public final class CommunicatorI implements Communicator return Util.stringToIdentity(s); } - @Override @SuppressWarnings("deprecation") + @Override public String identityToString(Identity ident) { - return Util.identityToString(ident); + return Util.identityToString(ident, _instance.toStringMode()); } @Override diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/ObjectAdapterI.java b/java/src/Ice/src/main/java/com/zeroc/Ice/ObjectAdapterI.java index 61cf6d72537..2ae50796171 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/ObjectAdapterI.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/ObjectAdapterI.java @@ -981,7 +981,7 @@ public final class ObjectAdapterI implements ObjectAdapter if(_routerInfo.getAdapter() != null) { throw new AlreadyRegisteredException("object adapter with router", - Util.identityToString(router.ice_getIdentity())); + _communicator.identityToString(router.ice_getIdentity())); } // diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/Util.java b/java/src/Ice/src/main/java/com/zeroc/Ice/Util.java index 20ec18f99bd..2cb75ec9cd0 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/Util.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/Util.java @@ -275,21 +275,36 @@ public final class Util * * @param ident The object identity to convert. * + * @param toStringMode Specifies if and how non-printable ASCII characters are escaped in the result. + * * @return The string representation of the object identity. **/ - public static String identityToString(Identity ident) + public static String identityToString(Identity ident, ToStringMode toStringMode) { if(ident.category == null || ident.category.length() == 0) { - return StringUtil.escapeString(ident.name, "/"); + return StringUtil.escapeString(ident.name, "/", toStringMode); } else { - return StringUtil.escapeString(ident.category, "/") + '/' + StringUtil.escapeString(ident.name, "/"); + return StringUtil.escapeString(ident.category, "/", toStringMode) + '/' + + StringUtil.escapeString(ident.name, "/", toStringMode); } } /** + * Converts an object identity to a string. + * + * @param ident The object identity to convert. + * + * @return The string representation of the object identity using the default mode (Unicode) + **/ + public static String identityToString(Identity ident) + { + return identityToString(ident, ToStringMode.Unicode); + } + + /** * Compares the object identities of two proxies. * * @param lhs A proxy. diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/CommunicatorObserverI.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/CommunicatorObserverI.java index d16ba494470..a3ffebca386 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/CommunicatorObserverI.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/CommunicatorObserverI.java @@ -320,7 +320,7 @@ public class CommunicatorObserverI implements com.zeroc.Ice.Instrumentation.Comm public String getIdentity() { - return com.zeroc.Ice.Util.identityToString(_current.id); + return _current.adapter.getCommunicator().identityToString(_current.id); } final private com.zeroc.Ice.Current _current; @@ -429,7 +429,7 @@ public class CommunicatorObserverI implements com.zeroc.Ice.Instrumentation.Comm catch(Exception ex) { // Either a fixed proxy or the communicator is destroyed. - os.append(com.zeroc.Ice.Util.identityToString(_proxy.ice_getIdentity())); + os.append(_proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity())); os.append(" [").append(_operation).append(']'); } _id = os.toString(); @@ -459,7 +459,7 @@ public class CommunicatorObserverI implements com.zeroc.Ice.Instrumentation.Comm { if(_proxy != null) { - return com.zeroc.Ice.Util.identityToString(_proxy.ice_getIdentity()); + return _proxy.ice_getCommunicator().identityToString(_proxy.ice_getIdentity()); } else { diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java index 8929771e994..67941f3b1e5 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java @@ -533,8 +533,8 @@ final public class Incoming implements com.zeroc.Ice.Request com.zeroc.IceUtilInternal.OutputBase out = new com.zeroc.IceUtilInternal.OutputBase(pw); out.setUseTab(false); out.print("dispatch exception:"); - out.print("\nidentity: " + Util.identityToString(_current.id)); - out.print("\nfacet: " + com.zeroc.IceUtilInternal.StringUtil.escapeString(_current.facet, "")); + out.print("\nidentity: " + Util.identityToString(_current.id, _instance.toStringMode())); + out.print("\nfacet: " + com.zeroc.IceUtilInternal.StringUtil.escapeString(_current.facet, "", _instance.toStringMode())); out.print("\noperation: " + _current.operation); if(_current.con != null) { diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Instance.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Instance.java index d4c3663560f..5bf70b1d2f6 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Instance.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Instance.java @@ -390,6 +390,13 @@ public final class Instance implements com.zeroc.Ice.ClassResolver return _batchAutoFlushSize; } + public com.zeroc.Ice.ToStringMode + toStringMode() + { + // No mutex lock, immutable + return _toStringMode; + } + public int cacheMessageBuffers() { @@ -1065,6 +1072,24 @@ public final class Instance implements com.zeroc.Ice.ClassResolver } } + String toStringModeStr = _initData.properties.getPropertyWithDefault("Ice.ToStringMode", "Unicode"); + if(toStringModeStr.equals("Unicode")) + { + _toStringMode = com.zeroc.Ice.ToStringMode.Unicode; + } + else if(toStringModeStr.equals("ASCII")) + { + _toStringMode = com.zeroc.Ice.ToStringMode.ASCII; + } + else if(toStringModeStr.equals("Compat")) + { + _toStringMode = com.zeroc.Ice.ToStringMode.Compat; + } + else + { + throw new com.zeroc.Ice.InitializationException("The value for Ice.ToStringMode must be Unicode, ASCII or Compat"); + } + _implicitContext = com.zeroc.Ice.ImplicitContextI.create(_initData.properties.getProperty("Ice.ImplicitContext")); @@ -1875,6 +1900,7 @@ public final class Instance implements com.zeroc.Ice.ClassResolver private final DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy(). private final int _messageSizeMax; // Immutable, not reset by destroy(). private final int _batchAutoFlushSize; // Immutable, not reset by destroy(). + private final com.zeroc.Ice.ToStringMode _toStringMode; // Immutable, not reset by destroy(). private final int _cacheMessageBuffers; // Immutable, not reset by destroy(). private final ACMConfig _clientACM; // Immutable, not reset by destroy(). private final ACMConfig _serverACM; // Immutable, not reset by destroy(). diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/LocatorInfo.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/LocatorInfo.java index f363157b13a..8e5cc8974ce 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/LocatorInfo.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/LocatorInfo.java @@ -462,7 +462,7 @@ public final class LocatorInfo else { s.append("object = "); - s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity())); + s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity(), ref.getInstance().toStringMode())); s.append("\n"); } @@ -514,13 +514,13 @@ public final class LocatorInfo StringBuilder s = new StringBuilder(128); s.append("object not found\n"); s.append("object = "); - s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity())); + s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); } com.zeroc.Ice.NotRegisteredException e = new com.zeroc.Ice.NotRegisteredException(); e.kindOfObject = "object"; - e.id = com.zeroc.Ice.Util.identityToString(ref.getIdentity()); + e.id = com.zeroc.Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode()); throw e; } catch(com.zeroc.Ice.NotRegisteredException ex) @@ -543,7 +543,7 @@ public final class LocatorInfo else { s.append("object = "); - s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity())); + s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); s.append("\n"); } s.append("reason = " + ex); @@ -587,7 +587,7 @@ public final class LocatorInfo { s.append("object\n"); s.append("object = "); - s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity())); + s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); s.append("\n"); } instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); @@ -626,7 +626,7 @@ public final class LocatorInfo StringBuilder s = new StringBuilder(128); s.append("searching for object by id\n"); s.append("object = "); - s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity())); + s.append(com.zeroc.Ice.Util.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); } diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java index 45647f08494..46750aa5e7a 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ..\config\PropertyNames.xml, Fri Jul 15 14:02:34 2016 +// Generated by makeprops.py from file PropertyNames.xml, Tue Oct 18 11:38:54 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -165,6 +165,7 @@ public final class PropertyNames new Property("Ice\\.ThreadPool\\.Server\\.ThreadIdleTime", false, null), new Property("Ice\\.ThreadPool\\.Server\\.ThreadPriority", false, null), new Property("Ice\\.ThreadPriority", false, null), + new Property("Ice\\.ToStringMode", false, null), new Property("Ice\\.Trace\\.Admin\\.Properties", false, null), new Property("Ice\\.Trace\\.Admin\\.Logger", false, null), new Property("Ice\\.Trace\\.Locator", false, null), @@ -980,7 +981,7 @@ public final class PropertyNames new Property("IceSSL\\.DHParams", false, null), new Property("IceSSL\\.EntropyDaemon", false, null), new Property("IceSSL\\.FindCert", false, null), - new Property("IceSSL\\.FindCert\\.[^\\s]+", true, "IceSSL.FindCert"), + new Property("IceSSL\\.FindCert\\.[^\\s]+", true, null), new Property("IceSSL\\.InitOpenSSL", false, null), new Property("IceSSL\\.KeyFile", true, null), new Property("IceSSL\\.Keychain", false, null), diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Reference.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Reference.java index e8420c9c6f7..2b2d2fc12e0 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Reference.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Reference.java @@ -306,13 +306,18 @@ public abstract class Reference implements Cloneable // StringBuilder s = new StringBuilder(128); + com.zeroc.Ice.ToStringMode toStringMode = _instance.toStringMode(); + final String separators = " :@"; + + String id = com.zeroc.Ice.Util.identityToString(_identity, toStringMode); + // // If the encoded identity string contains characters which // the reference parser uses as separators, then we enclose // the identity string in quotes. // - String id = com.zeroc.Ice.Util.identityToString(_identity); - if(com.zeroc.IceUtilInternal.StringUtil.findFirstOf(id, " :@") != -1) + + if(com.zeroc.IceUtilInternal.StringUtil.findFirstOf(id, separators) != -1) { s.append('"'); s.append(id); @@ -331,8 +336,8 @@ public abstract class Reference implements Cloneable // the facet string in quotes. // s.append(" -f "); - String fs = com.zeroc.IceUtilInternal.StringUtil.escapeString(_facet, ""); - if(com.zeroc.IceUtilInternal.StringUtil.findFirstOf(fs, " :@") != -1) + String fs = com.zeroc.IceUtilInternal.StringUtil.escapeString(_facet, "", toStringMode); + if(com.zeroc.IceUtilInternal.StringUtil.findFirstOf(fs, separators) != -1) { s.append('"'); s.append(fs); @@ -481,16 +486,16 @@ public abstract class Reference implements Cloneable @Override public Reference clone() { - Reference c = null; - try - { - c = (Reference)super.clone(); - } - catch(CloneNotSupportedException ex) - { - assert false; - } - return c; + Reference c = null; + try + { + c = (Reference)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; } protected int _hashValue; diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/RoutableReference.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/RoutableReference.java index b383011df95..4600da1e9d3 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/RoutableReference.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/RoutableReference.java @@ -353,7 +353,8 @@ public class RoutableReference extends Reference // the reference parser uses as separators, then we enclose // the adapter id string in quotes. // - String a = com.zeroc.IceUtilInternal.StringUtil.escapeString(_adapterId, null); + + String a = com.zeroc.IceUtilInternal.StringUtil.escapeString(_adapterId, null, getInstance().toStringMode()); if(com.zeroc.IceUtilInternal.StringUtil.findFirstOf(a, " :@") != -1) { s.append('"'); diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/ServantManager.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/ServantManager.java index d83dfb8e141..badc3786f45 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/ServantManager.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/ServantManager.java @@ -32,11 +32,12 @@ public final class ServantManager if(m.containsKey(facet)) { com.zeroc.Ice.AlreadyRegisteredException ex = new com.zeroc.Ice.AlreadyRegisteredException(); - ex.id = com.zeroc.Ice.Util.identityToString(ident); + ex.id = com.zeroc.Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length() > 0) { - ex.id += " -f " + com.zeroc.IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + com.zeroc.IceUtilInternal.StringUtil.escapeString(facet, "", + _instance.toStringMode()); } throw ex; } @@ -77,11 +78,12 @@ public final class ServantManager if(m == null || (obj = m.remove(facet)) == null) { com.zeroc.Ice.NotRegisteredException ex = new com.zeroc.Ice.NotRegisteredException(); - ex.id = com.zeroc.Ice.Util.identityToString(ident); + ex.id = com.zeroc.Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length() > 0) { - ex.id += " -f " + com.zeroc.IceUtilInternal.StringUtil.escapeString(facet, ""); + ex.id += " -f " + com.zeroc.IceUtilInternal.StringUtil.escapeString(facet, "", + _instance.toStringMode()); } throw ex; } @@ -120,7 +122,7 @@ public final class ServantManager if(m == null) { com.zeroc.Ice.NotRegisteredException ex = new com.zeroc.Ice.NotRegisteredException(); - ex.id = com.zeroc.Ice.Util.identityToString(ident); + ex.id = com.zeroc.Ice.Util.identityToString(ident, _instance.toStringMode()); ex.kindOfObject = "servant"; throw ex; } @@ -218,7 +220,8 @@ public final class ServantManager if(l != null) { com.zeroc.Ice.AlreadyRegisteredException ex = new com.zeroc.Ice.AlreadyRegisteredException(); - ex.id = com.zeroc.IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = com.zeroc.IceUtilInternal.StringUtil.escapeString(category, "", + _instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } @@ -236,7 +239,8 @@ public final class ServantManager if(l == null) { com.zeroc.Ice.NotRegisteredException ex = new com.zeroc.Ice.NotRegisteredException(); - ex.id = com.zeroc.IceUtilInternal.StringUtil.escapeString(category, ""); + ex.id = com.zeroc.IceUtilInternal.StringUtil.escapeString(category, "", + _instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/TraceUtil.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/TraceUtil.java index 4798d1be659..36b60e57168 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/TraceUtil.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/TraceUtil.java @@ -168,14 +168,20 @@ public final class TraceUtil { try { + com.zeroc.Ice.ToStringMode toStringMode = com.zeroc.Ice.ToStringMode.Unicode; + if(stream.instance() != null) + { + toStringMode = stream.instance().toStringMode(); + } + com.zeroc.Ice.Identity identity = com.zeroc.Ice.Identity.read(stream, null); - out.write("\nidentity = " + com.zeroc.Ice.Util.identityToString(identity)); + out.write("\nidentity = " + com.zeroc.Ice.Util.identityToString(identity, toStringMode)); String[] facet = stream.readStringSeq(); out.write("\nfacet = "); if(facet.length > 0) { - out.write(com.zeroc.IceUtilInternal.StringUtil.escapeString(facet[0], "")); + out.write(com.zeroc.IceUtilInternal.StringUtil.escapeString(facet[0], "", toStringMode)); } String operation = stream.readString(); diff --git a/java/src/Ice/src/main/java/com/zeroc/IceUtilInternal/StringUtil.java b/java/src/Ice/src/main/java/com/zeroc/IceUtilInternal/StringUtil.java index cf6de757a9c..782c352c218 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceUtilInternal/StringUtil.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceUtilInternal/StringUtil.java @@ -75,97 +75,119 @@ public final class StringUtil return -1; } - // - // Write the byte b as an escape sequence if it isn't a printable ASCII - // character and append the escape sequence to sb. Additional characters - // that should be escaped can be passed in special. If b is any of these - // characters, b is preceded by a backslash in sb. - // private static void - encodeChar(byte b, StringBuilder sb, String special) + encodeChar(char c, StringBuilder sb, String special, com.zeroc.Ice.ToStringMode toStringMode) { - switch(b) + switch(c) { - case (byte)'\\': + case '\\': { sb.append("\\\\"); break; } - case (byte)'\'': + case '\'': { sb.append("\\'"); break; } - case (byte)'"': + case '"': { sb.append("\\\""); break; } - case (byte)'\b': + case '\b': { sb.append("\\b"); break; } - case (byte)'\f': + case '\f': { sb.append("\\f"); break; } - case (byte)'\n': + case '\n': { sb.append("\\n"); break; } - case (byte)'\r': + case '\r': { sb.append("\\r"); break; } - case (byte)'\t': + case '\t': { sb.append("\\t"); break; } default: { - if(!(b >= 32 && b <= 126)) - { - sb.append('\\'); - String octal = Integer.toOctalString(b < 0 ? b + 256 : b); - // - // Add leading zeroes so that we avoid problems during - // decoding. For example, consider the encoded string - // \0013 (i.e., a character with value 1 followed by - // the character '3'). If the leading zeroes were omitted, - // the result would be incorrectly interpreted by the - // decoder as a single character with value 11. - // - for(int j = octal.length(); j < 3; j++) - { - sb.append('0'); - } - sb.append(octal); - } - else if(special != null && special.indexOf((char)b) != -1) + if(special != null && special.indexOf(c) != -1) { sb.append('\\'); - sb.append((char)b); + sb.append(c); } else { - sb.append((char)b); + if(c < 32 || c > 126) + { + if(toStringMode == com.zeroc.Ice.ToStringMode.Compat) + { + // + // When ToStringMode=Compat, c is a UTF-8 byte + // + assert(c < 256); + + sb.append('\\'); + String octal = Integer.toOctalString(c); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(int j = octal.length(); j < 3; j++) + { + sb.append('0'); + } + sb.append(octal); + } + else if(c < 32 || c == 127 || toStringMode == com.zeroc.Ice.ToStringMode.ASCII) + { + // append \\unnnn + sb.append("\\u"); + String hex = Integer.toHexString(c); + for(int j = hex.length(); j < 4; j++) + { + sb.append('0'); + } + sb.append(hex); + } + else + { + // keep as is + sb.append(c); + } + } + else + { + // printable ASCII character + sb.append(c); + } } + break; } } } // - // Add escape sequences (such as "\n", or "\007") to make a string - // readable in ASCII. Any characters that appear in special are - // prefixed with a backlash in the returned string. + // Add escape sequences (like "\n" to the input string) + // The second parameter adds characters to escape, and can be empty. // public static String - escapeString(String s, String special) + escapeString(String s, String special, com.zeroc.Ice.ToStringMode toStringMode) { if(special != null) { @@ -178,31 +200,72 @@ public final class StringUtil } } - byte[] bytes = null; - try + if(toStringMode == com.zeroc.Ice.ToStringMode.Compat) { - bytes = s.getBytes("UTF8"); + // Encode UTF-8 bytes + + byte[] bytes = null; + try + { + bytes = s.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return null; + } + + StringBuilder result = new StringBuilder(bytes.length); + for(int i = 0; i < bytes.length; i++) + { + encodeChar((char)(bytes[i] & 0xFF), result, special, toStringMode); + } + + return result.toString(); } - catch(java.io.UnsupportedEncodingException ex) + else { - assert(false); - return null; - } + StringBuilder result = new StringBuilder(s.length()); - StringBuilder result = new StringBuilder(bytes.length); - for(int i = 0; i < bytes.length; i++) - { - encodeChar(bytes[i], result, special); - } + for(int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + if(toStringMode == com.zeroc.Ice.ToStringMode.Unicode || !Character.isSurrogate(c)) + { + encodeChar(c, result, special, toStringMode); + } + else + { + assert(toStringMode == com.zeroc.Ice.ToStringMode.ASCII && Character.isSurrogate(c)); + if(i + 1 == s.length()) + { + throw new IllegalArgumentException("High surrogate without low surrogate"); + } + else + { + i++; + int codePoint = Character.toCodePoint(c, s.charAt(i)); + // append \Unnnnnnnn + result.append("\\U"); + String hex = Integer.toHexString(codePoint); + for(int j = hex.length(); j < 8; j++) + { + result.append('0'); + } + result.append(hex); + } + } + } - return result.toString(); + return result.toString(); + } } private static char checkChar(String s, int pos) { char c = s.charAt(pos); - if(!(c >= 32 && c <= 126)) + if(c < 32 || c == 127) { String msg; if(pos > 0) @@ -213,42 +276,27 @@ public final class StringUtil { msg = "first character"; } - msg += " is not a printable ASCII character (ordinal " + (int)c + ")"; + msg += " has invalid ordinal value " + (int)c; throw new IllegalArgumentException(msg); } return c; } - static class Holder<T> - { - public Holder() - { - } - - public Holder(T value) - { - this.value = value; - } - - public T value; - } - // - // Decode the character or escape sequence starting at start and return it. - // newStart is set to the index of the first character following the decoded character + // Decode the character or escape sequence starting at start and appends it to result; + // returns the index of the first character following the decoded character // or escape sequence. // - private static char decodeChar(String s, int start, int end, Holder<Integer> nextStart) + private static int + decodeChar(String s, int start, int end, StringBuilder result) { assert(start >= 0); assert(start < end); assert(end <= s.length()); - char c; - if(s.charAt(start) != '\\') { - c = checkChar(s, start++); + result.append(checkChar(s, start++)); } else { @@ -256,45 +304,98 @@ public final class StringUtil { throw new IllegalArgumentException("trailing backslash"); } - switch(s.charAt(++start)) + + char c = s.charAt(++start); + + switch(c) { case '\\': case '\'': case '"': { - c = s.charAt(start++); + ++start; + result.append(c); break; } case 'b': { ++start; - c = '\b'; + result.append('\b'); break; } case 'f': { ++start; - c = '\f'; + result.append('\f'); break; } case 'n': { ++start; - c = '\n'; + result.append('\n'); break; } case 'r': { ++start; - c = '\r'; + result.append('\r'); break; } case 't': { ++start; - c = '\t'; + result.append('\t'); + break; + } + case 'u': + case 'U': + { + int codePoint = 0; + boolean inBMP = (c == 'u'); + int size = inBMP ? 4 : 8; + ++start; + while(size > 0 && start < end) + { + c = s.charAt(start++); + int charVal = 0; + if(c >= '0' && c <= '9') + { + charVal = c - '0'; + } + else if(c >= 'a' && c <= 'f') + { + charVal = 10 + (c - 'a'); + } + else if(c >= 'A' && c <= 'F') + { + charVal = 10 + (c - 'A'); + } + else + { + break; // while + } + codePoint = codePoint * 16 + charVal; + --size; + } + if(size > 0) + { + throw new IllegalArgumentException("Invalid universal character name: too few hex digits"); + } + if(inBMP && Character.isSurrogate((char)codePoint)) + { + throw new IllegalArgumentException("A non-BMP character cannot be encoded with \\unnnn, use \\Unnnnnnnn instead"); + } + if(inBMP || Character.isBmpCodePoint(codePoint)) + { + result.append((char)codePoint); + } + else + { + result.append(Character.toChars(codePoint)); + } break; } + case '0': case '1': case '2': @@ -304,49 +405,71 @@ public final class StringUtil case '6': case '7': { - int val = 0; - for(int j = 0; j < 3 && start < end; ++j) + // UTF-8 byte sequence encoded with octal escapes + + byte[] arr = new byte[end - start]; + int i = 0; + boolean done = false; + while(!done) { - int charVal = s.charAt(start++) - '0'; - if(charVal < 0 || charVal > 7) + int val = 0; + for(int j = 0; j < 3 && start < end; ++j) { - --start; - break; + int charVal = s.charAt(start++) - '0'; + if(charVal < 0 || charVal > 7) + { + --start; + if(j == 0) + { + // first character after escape is not 0-7: + done = true; + --start; // go back to the previous backslash + } + break; // for + } + val = val * 8 + charVal; + } + + if(!done) + { + if(val > 255) + { + String msg = "octal value \\" + Integer.toOctalString(val) + " (" + val + ") is out of range"; + throw new IllegalArgumentException(msg); + } + arr[i++] = (byte)val; + + if((start + 1 < end) && s.charAt(start) == '\\') + { + start++; + // loop, read next octal escape sequence + } + else + { + done = true; + } } - val = val * 8 + charVal; } - if(val > 255) + + try { - String msg = "octal value \\" + Integer.toOctalString(val) + " (" + val + ") is out of range"; - throw new IllegalArgumentException(msg); + result.append(new String(arr, 0, i, "UTF8")); + } + catch(java.io.UnsupportedEncodingException ex) + { + throw new IllegalArgumentException("unsupported encoding", ex); } - c = (char)val; break; } default: { - c = checkChar(s, start++); + result.append(checkChar(s, start++)); break; } } } - nextStart.value = start; - return c; - } - // - // Remove escape sequences from s and append the result to sb. - // Return true if successful, false otherwise. - // - private static void - decodeString(String s, int start, int end, StringBuilder sb) - { - Holder<Integer> nextStart = new Holder<>(); - while(start < end) - { - sb.append(decodeChar(s, start, end, nextStart)); - start = nextStart.value; - } + return start; } // @@ -358,23 +481,25 @@ public final class StringUtil { assert(start >= 0 && start <= end && end <= s.length()); - StringBuilder sb = new StringBuilder(end - start); - decodeString(s, start, end, sb); - String decodedString = sb.toString(); - - byte[] arr = new byte[decodedString.length()]; - for(int i = 0; i < arr.length; ++i) + // Optimization for strings without escapes + int p = s.indexOf('\\', start); + if(p == -1 || p >= end) { - arr[i] = (byte)decodedString.charAt(i); - } - - try - { - return new String(arr, 0, arr.length, "UTF8"); + p = start; + while(p < end) + { + checkChar(s, p++); + } + return s.substring(start, end); } - catch(java.io.UnsupportedEncodingException ex) + else { - throw new IllegalArgumentException("unsupported encoding", ex); + StringBuilder sb = new StringBuilder(end - start); + while(start < end) + { + start = decodeChar(s, start, end, sb); + } + return sb.toString(); } } diff --git a/java/src/IceBox/src/main/java/com/zeroc/IceBox/Admin.java b/java/src/IceBox/src/main/java/com/zeroc/IceBox/Admin.java index ace16b7d0b7..6f1645bb53b 100644 --- a/java/src/IceBox/src/main/java/com/zeroc/IceBox/Admin.java +++ b/java/src/IceBox/src/main/java/com/zeroc/IceBox/Admin.java @@ -82,7 +82,7 @@ public final class Admin return 1; } - managerProxy = "\"" + com.zeroc.Ice.Util.identityToString(managerIdentity) + "\" :" + + managerProxy = "\"" + communicator().identityToString(managerIdentity) + "\" :" + managerEndpoints; } else @@ -94,7 +94,7 @@ public final class Admin return 1; } - managerProxy = "\"" + com.zeroc.Ice.Util.identityToString(managerIdentity) + "\" @" + + managerProxy = "\"" + communicator().identityToString(managerIdentity) + "\" @" + managerAdapterId; } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/AdapterEditor.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/AdapterEditor.java index 6b2477854f8..20415fa116f 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/AdapterEditor.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/AdapterEditor.java @@ -575,9 +575,11 @@ class AdapterEditor extends CommunicatorChildEditor private java.util.Map<String, String[]> objectDescriptorSeqToMap(java.util.List<ObjectDescriptor> objects) { java.util.Map<String, String[]> result = new java.util.TreeMap<>(); + com.zeroc.Ice.Communicator communicator = getAdapter().getRoot().getCoordinator().getCommunicator(); + for(ObjectDescriptor p : objects) { - String k = com.zeroc.Ice.Util.identityToString(p.id); + String k = communicator.identityToString(p.id); result.put(k, new String[]{p.type, getAdapter().lookupPropertyValue(k),p.proxyOptions}); } return result; @@ -587,11 +589,12 @@ class AdapterEditor extends CommunicatorChildEditor { String badIdentities = ""; java.util.LinkedList<ObjectDescriptor> result = new java.util.LinkedList<>(); + com.zeroc.Ice.Communicator communicator = getAdapter().getRoot().getCoordinator().getCommunicator(); for(java.util.Map.Entry<String, String[]> p : map.entrySet()) { try { - com.zeroc.Ice.Identity id = com.zeroc.Ice.Util.stringToIdentity(p.getKey()); + com.zeroc.Ice.Identity id = communicator.stringToIdentity(p.getKey()); String[] val = p.getValue(); result.add(new ObjectDescriptor(id, val[0], val[2])); } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/PropertiesField.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/PropertiesField.java index 782c476376e..cb6ad3998f0 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/PropertiesField.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/PropertiesField.java @@ -111,11 +111,11 @@ public class PropertiesField extends JTable for(ObjectDescriptor q : p.objects) { - hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id)); + hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id, com.zeroc.Ice.ToStringMode.Unicode)); } for(ObjectDescriptor q : p.allocatables) { - hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id)); + hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id, com.zeroc.Ice.ToStringMode.Unicode)); } } } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/ReplicaGroupEditor.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/ReplicaGroupEditor.java index 4f1642b15e8..c81585473f1 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/ReplicaGroupEditor.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/ReplicaGroupEditor.java @@ -422,9 +422,10 @@ class ReplicaGroupEditor extends Editor private java.util.Map<String, String[]> objectDescriptorSeqToMap(java.util.List<ObjectDescriptor> objects) { java.util.Map<String, String[]> result = new java.util.TreeMap<>(); + com.zeroc.Ice.Communicator communicator = _target.getCoordinator().getCommunicator(); for(ObjectDescriptor p : objects) { - result.put(com.zeroc.Ice.Util.identityToString(p.id), new String[]{p.type, p.proxyOptions}); + result.put(communicator.identityToString(p.id), new String[]{p.type, p.proxyOptions}); } return result; } @@ -433,12 +434,13 @@ class ReplicaGroupEditor extends Editor { String badIdentities = ""; java.util.LinkedList<ObjectDescriptor> result = new java.util.LinkedList<>(); + com.zeroc.Ice.Communicator communicator = _target.getCoordinator().getCommunicator(); for(java.util.Map.Entry<String, String[]> p : map.entrySet()) { try { - com.zeroc.Ice.Identity id = com.zeroc.Ice.Util.stringToIdentity(p.getKey()); + com.zeroc.Ice.Identity id = communicator.stringToIdentity(p.getKey()); String[] val = p.getValue(); result.add(new ObjectDescriptor(id, val[0], val[1])); } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/TreeNode.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/TreeNode.java index f8276f2dc2c..56dd18e634e 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/TreeNode.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Application/TreeNode.java @@ -140,11 +140,11 @@ public abstract class TreeNode extends TreeNodeBase for(ObjectDescriptor q : p.objects) { - hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id)); + hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id, com.zeroc.Ice.ToStringMode.Unicode)); } for(ObjectDescriptor q : p.allocatables) { - hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id)); + hiddenPropertyValues.add(com.zeroc.Ice.Util.identityToString(q.id, com.zeroc.Ice.ToStringMode.Unicode)); } } } @@ -261,7 +261,7 @@ public abstract class TreeNode extends TreeNodeBase for(ObjectDescriptor p : objects) { java.util.List<String[]> attributes = new java.util.LinkedList<>(); - String strId = com.zeroc.Ice.Util.identityToString(p.id); + String strId = com.zeroc.Ice.Util.identityToString(p.id, com.zeroc.Ice.ToStringMode.Unicode); attributes.add(createAttribute("identity", strId)); if(p.type.length() > 0) { diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Coordinator.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Coordinator.java index 8bbd0625ac1..c35d5e3608f 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Coordinator.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/Coordinator.java @@ -2014,7 +2014,7 @@ public class Coordinator masterRegistryId.name = "Registry"; cb.setRegistry(RegistryPrx.uncheckedCast(_communicator.stringToProxy( - "\"" + com.zeroc.Ice.Util.identityToString(masterRegistryId) + + "\"" + _communicator.identityToString(masterRegistryId) + "\""))); } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/Root.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/Root.java index 277e5c34a56..c0f646fa74f 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/Root.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/Root.java @@ -600,23 +600,23 @@ public class Root extends ListArrayTreeNode { for(ObjectInfo info : objects) { - _objects.put(com.zeroc.Ice.Util.identityToString(info.proxy.ice_getIdentity()), info); + _objects.put(info.proxy.ice_getCommunicator().identityToString(info.proxy.ice_getIdentity()), info); } } public void objectAdded(ObjectInfo info) { - _objects.put(com.zeroc.Ice.Util.identityToString(info.proxy.ice_getIdentity()), info); + _objects.put(info.proxy.ice_getCommunicator().identityToString(info.proxy.ice_getIdentity()), info); } public void objectUpdated(ObjectInfo info) { - _objects.put(com.zeroc.Ice.Util.identityToString(info.proxy.ice_getIdentity()), info); + _objects.put(info.proxy.ice_getCommunicator().identityToString(info.proxy.ice_getIdentity()), info); } public void objectRemoved(com.zeroc.Ice.Identity id) { - _objects.remove(com.zeroc.Ice.Util.identityToString(id)); + _objects.remove(_coordinator.getCommunicator().identityToString(id)); } // @@ -836,7 +836,7 @@ public class Root extends ListArrayTreeNode JOptionPane.ERROR_MESSAGE); } - String strIdentity = com.zeroc.Ice.Util.identityToString(proxy.ice_getIdentity()); + String strIdentity = _coordinator.getCommunicator().identityToString(proxy.ice_getIdentity()); final String prefix = "Adding well-known object '" + strIdentity + "'..."; final AdminPrx admin = _coordinator.getAdmin(); @@ -887,7 +887,7 @@ public class Root extends ListArrayTreeNode { com.zeroc.Ice.ObjectPrx proxy = _coordinator.getCommunicator().stringToProxy(strProxy); com.zeroc.Ice.Identity identity = proxy.ice_getIdentity(); - final String strIdentity = com.zeroc.Ice.Util.identityToString(identity); + final String strIdentity = _coordinator.getCommunicator().identityToString(identity); final String prefix = "Removing well-known object '" + strIdentity + "'..."; final String errorTitle = "Failed to remove object '" + strIdentity + "'"; diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/TableField.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/TableField.java index 77ac0980e60..8bb4a53393d 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/TableField.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/LiveDeployment/TableField.java @@ -77,7 +77,7 @@ public class TableField extends JTable { com.zeroc.Ice.Identity id = new com.zeroc.Ice.Identity(resolver.substitute(p.id.name), resolver.substitute(p.id.category)); - map.put(com.zeroc.Ice.Util.identityToString(id), resolver.substitute(p.type)); + map.put(com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.Unicode), resolver.substitute(p.type)); } setSortedMap(map); } diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/ObjectObserverI.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/ObjectObserverI.java index f68074429f7..7d80cf457fb 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/ObjectObserverI.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/ObjectObserverI.java @@ -71,7 +71,7 @@ class ObjectObserverI implements ObjectObserver { if(_trace) { - _coordinator.traceObserver("objectRemoved for object " + com.zeroc.Ice.Util.identityToString(id)); + _coordinator.traceObserver("objectRemoved for object " + _coordinator.getCommunicator().identityToString(id)); } SwingUtilities.invokeLater(() -> _coordinator.objectRemoved(id)); diff --git a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/SessionKeeper.java b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/SessionKeeper.java index 53d4f2a83ca..e6da2e4b8b6 100644 --- a/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/SessionKeeper.java +++ b/java/src/IceGridGUI/src/main/java/com/zeroc/IceGridGUI/SessionKeeper.java @@ -1114,7 +1114,7 @@ public class SessionKeeper { com.zeroc.Ice.LocatorPrx prx = com.zeroc.Ice.LocatorPrx.uncheckedCast( communicator.stringToProxy( - com.zeroc.Ice.Util.identityToString(locator.ice_getIdentity()) + + communicator.identityToString(locator.ice_getIdentity()) + ":" + e.toString())); if(_directDiscoveryEndpointModel.indexOf(prx) == -1) @@ -2226,7 +2226,7 @@ public class SessionKeeper id.name = "Locator"; id.category = _directInstanceName.getText(); StringBuilder endpoint = new StringBuilder(); - endpoint.append(com.zeroc.Ice.Util.identityToString(id)); + endpoint.append(_coordinator.getCommunicator().identityToString(id)); endpoint.append(":"); endpoint.append(_directCustomEndpointValue.getText()); _coordinator.getCommunicator().stringToProxy(endpoint.toString()); @@ -2283,7 +2283,7 @@ public class SessionKeeper id.name = "router"; id.category = _routedInstanceName.getText(); StringBuilder endpoint = new StringBuilder(); - endpoint.append(com.zeroc.Ice.Util.identityToString(id)); + endpoint.append(_coordinator.getCommunicator().identityToString(id)); endpoint.append(":"); endpoint.append(_routedCustomEndpointValue.getText()); _coordinator.getCommunicator().stringToProxy(endpoint.toString()); @@ -3125,7 +3125,7 @@ public class SessionKeeper id.name = "Locator"; id.category = _directInstanceName.getText(); StringBuilder endpoint = new StringBuilder(); - endpoint.append(com.zeroc.Ice.Util.identityToString(id)); + endpoint.append(_coordinator.getCommunicator().identityToString(id)); endpoint.append(":"); endpoint.append(_directCustomEndpointValue.getText()); return containsSecureEndpoints(endpoint.toString()); @@ -3143,7 +3143,7 @@ public class SessionKeeper id.name = "router"; id.category = _routedInstanceName.getText(); StringBuilder endpoint = new StringBuilder(); - endpoint.append(com.zeroc.Ice.Util.identityToString(id)); + endpoint.append(_coordinator.getCommunicator().identityToString(id)); endpoint.append(":"); endpoint.append(_routedCustomEndpointValue.getText()); return containsSecureEndpoints(endpoint.toString()); @@ -3335,7 +3335,7 @@ public class SessionKeeper id.name = inf.getDirect() ? "Locator" : "router"; id.category = inf.getInstanceName(); StringBuilder endpoint = new StringBuilder(); - endpoint.append(com.zeroc.Ice.Util.identityToString(id)); + endpoint.append(_coordinator.getCommunicator().identityToString(id)); endpoint.append(":"); endpoint.append(inf.getEndpoint()); ssl = containsSecureEndpoints(endpoint.toString()); diff --git a/java/test/src/main/java/test/Ice/location/AllTests.java b/java/test/src/main/java/test/Ice/location/AllTests.java index 164408efc27..e3fee0edb51 100644 --- a/java/test/src/main/java/test/Ice/location/AllTests.java +++ b/java/test/src/main/java/test/Ice/location/AllTests.java @@ -663,7 +663,7 @@ public class AllTests // Note the quotes are necessary here due to ":" in the // java generated UUID. HelloPrx helloPrx = HelloPrx.checkedCast( - communicator.stringToProxy("\"" + com.zeroc.Ice.Util.identityToString(id) + "\"")); + communicator.stringToProxy("\"" + communicator.identityToString(id) + "\"")); test(helloPrx.ice_getConnection() == null); adapter.deactivate(); diff --git a/java/test/src/main/java/test/Ice/proxy/AllTests.java b/java/test/src/main/java/test/Ice/proxy/AllTests.java index 633f48bc256..92caa297e39 100644 --- a/java/test/src/main/java/test/Ice/proxy/AllTests.java +++ b/java/test/src/main/java/test/Ice/proxy/AllTests.java @@ -91,7 +91,7 @@ public class AllTests b1 = communicator.stringToProxy("test\\40test"); test(b1.ice_getIdentity().name.equals("test test")); - // Test some octal and hex corner cases. + // Test some octal corner cases. b1 = communicator.stringToProxy("test\\4test"); test(b1.ice_getIdentity().name.equals("test\4test")); b1 = communicator.stringToProxy("test\\04test"); @@ -273,11 +273,77 @@ public class AllTests // Test for bug ICE-5543: escaped escapes in stringToIdentity // com.zeroc.Ice.Identity id = new com.zeroc.Ice.Identity("test", ",X2QNUAzSBcJ_e$AV;E\\"); - com.zeroc.Ice.Identity id2 = com.zeroc.Ice.Util.stringToIdentity(com.zeroc.Ice.Util.identityToString(id)); + com.zeroc.Ice.Identity id2 = com.zeroc.Ice.Util.stringToIdentity(communicator.identityToString(id)); test(id.equals(id2)); id = new com.zeroc.Ice.Identity("test", ",X2QNUAz\\SB\\/cJ_e$AV;E\\\\"); - id2 = com.zeroc.Ice.Util.stringToIdentity(com.zeroc.Ice.Util.identityToString(id)); + id2 = com.zeroc.Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.equals(id2)); + + id = new com.zeroc.Ice.Identity("/test", "cat/"); + String idStr = communicator.identityToString(id); + test(idStr.equals("cat\\//\\/test")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + try + { + // Illegal character < 32 + id = com.zeroc.Ice.Util.stringToIdentity("xx\01FooBar"); + test(false); + } + catch(com.zeroc.Ice.IdentityParseException e) + { + } + + try + { + // Illegal surrogate + id = com.zeroc.Ice.Util.stringToIdentity("xx\\ud911"); + test(false); + } + catch(com.zeroc.Ice.IdentityParseException e) + { + } + + // Testing bytes 127 (\x7F, \177) and € + id = new com.zeroc.Ice.Identity("test", "\177€"); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.Unicode); + test(idStr.equals("\\u007f€/test")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + test(com.zeroc.Ice.Util.identityToString(id).equals(idStr)); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.ASCII); + test(idStr.equals("\\u007f\\u20ac/test")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.Compat); + test(idStr.equals("\\177\\342\\202\\254/test")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + id2 = com.zeroc.Ice.Util.stringToIdentity(communicator.identityToString(id)); + test(id.equals(id2)); + + // More unicode character + id = new com.zeroc.Ice.Identity("banana \016-\ud83c\udf4c\u20ac\u00a2\u0024", "greek \ud800\udd6a"); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.Unicode); + test(idStr.equals("greek \ud800\udd6a/banana \\u000e-\ud83c\udf4c\u20ac\u00a2$")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.ASCII); + test(idStr.equals("greek \\U0001016a/banana \\u000e-\\U0001f34c\\u20ac\\u00a2$")); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = com.zeroc.Ice.Util.identityToString(id, com.zeroc.Ice.ToStringMode.Compat); + id2 = com.zeroc.Ice.Util.stringToIdentity(idStr); + test(idStr.equals("greek \\360\\220\\205\\252/banana \\016-\\360\\237\\215\\214\\342\\202\\254\\302\\242$")); test(id.equals(id2)); out.println("ok"); @@ -464,10 +530,6 @@ public class AllTests out.print("testing proxy methods... "); out.flush(); - test(com.zeroc.Ice.Util.identityToString( - base.ice_identity(com.zeroc.Ice.Util.stringToIdentity("other")).ice_getIdentity()).equals("other")); - test(com.zeroc.Ice.Util.identityToString( - base.ice_identity(com.zeroc.Ice.Util.stringToIdentity("other")).ice_getIdentity()).equals("other")); test(base.ice_facet("facet").ice_getFacet().equals("facet")); test(base.ice_adapterId("id").ice_getAdapterId().equals("id")); test(base.ice_twoway().ice_isTwoway()); diff --git a/java/test/src/main/java/test/Ice/proxy/run.py b/java/test/src/main/java/test/Ice/proxy/run.py index 78cfe699505..0d0598cb160 100755 --- a/java/test/src/main/java/test/Ice/proxy/run.py +++ b/java/test/src/main/java/test/Ice/proxy/run.py @@ -24,5 +24,5 @@ import TestUtil TestUtil.queueClientServerTest() TestUtil.queueClientServerTest(configName = "amd", localOnly = True, message = "Running test with AMD server.", server="test.Ice.proxy.AMDServer") -TestUtil.queueCollocatedTest() +TestUtil.queueCollocatedTest(additionalOptions = "--Ice.ToStringMode=Compat") TestUtil.runQueuedTests() diff --git a/js/src/Ice/Communicator.js b/js/src/Ice/Communicator.js index 4fd7a9d91ab..e4556285275 100644 --- a/js/src/Ice/Communicator.js +++ b/js/src/Ice/Communicator.js @@ -83,7 +83,7 @@ class Communicator identityToString(ident) { - return Ice.identityToString(ident); + return Ice.identityToString(ident, this._instance.toStringMode()); } createObjectAdapter(name) diff --git a/js/src/Ice/IdentityUtil.js b/js/src/Ice/IdentityUtil.js index 1d5b79a4a51..1cbfbc051d2 100644 --- a/js/src/Ice/IdentityUtil.js +++ b/js/src/Ice/IdentityUtil.js @@ -106,17 +106,19 @@ Ice.stringToIdentity = function(s) * * @param ident The object identity to convert. * +* @param toStringMode Specifies if and how non-printable ASCII characters are escaped in the result. +* * @return The string representation of the object identity. **/ -Ice.identityToString = function(ident) +Ice.identityToString = function(ident, toStringMode = Ice.ToStringMode.Unicode) { if(ident.category === null || ident.category.length === 0) { - return StringUtil.escapeString(ident.name, "/"); + return StringUtil.escapeString(ident.name, "/", toStringMode); } else { - return StringUtil.escapeString(ident.category, "/") + '/' + StringUtil.escapeString(ident.name, "/"); + return StringUtil.escapeString(ident.category, "/", toStringMode) + '/' + StringUtil.escapeString(ident.name, "/", toStringMode); } }; diff --git a/js/src/Ice/IncomingAsync.js b/js/src/Ice/IncomingAsync.js index 2ba22566f5d..995b81fd1f3 100644 --- a/js/src/Ice/IncomingAsync.js +++ b/js/src/Ice/IncomingAsync.js @@ -123,8 +123,8 @@ class IncomingAsync const s = []; s.push("dispatch exception:"); - s.push("\nidentity: " + Ice.identityToString(this._current.id)); - s.push("\nfacet: " + StringUtil.escapeString(this._current.facet, "")); + s.push("\nidentity: " + Ice.identityToString(this._current.id, this._instance.toStringMode())); + s.push("\nfacet: " + StringUtil.escapeString(this._current.facet, "", this._instance.toStringMode())); s.push("\noperation: " + this._current.operation); if(this._connection !== null) { diff --git a/js/src/Ice/Instance.js b/js/src/Ice/Instance.js index df3a67a8947..f521ec74499 100644 --- a/js/src/Ice/Instance.js +++ b/js/src/Ice/Instance.js @@ -36,7 +36,8 @@ Ice.__M.require(module, "../Ice/LocalException", "../Ice/Exception", "../Ice/ProcessLogger", - "../Ice/ACM" + "../Ice/ACM", + "../Ice/ToStringMode" ]); const IceSSL = Ice.__M.require(module, ["../Ice/EndpointInfo"]).IceSSL; @@ -80,6 +81,7 @@ class Instance this._messageSizeMax = 0; this._batchAutoFlushSize = 0; this._clientACM = null; + this._toStringMode = Ice.ToStringMode.Unicode; this._implicitContext = null; this._routerManager = null; this._locatorManager = null; @@ -247,6 +249,12 @@ class Instance return this._clientACM; } + toStringMode() + { + // this value is immutable + return this._toStringMode; + } + getImplicitContext() { return this._implicitContext; @@ -347,6 +355,21 @@ class Instance new ACMConfig(this._initData.properties, this._initData.logger, "Ice.ACM", new ACMConfig())); + + const toStringModeStr = this._initData.properties.getPropertyWithDefault("Ice.ToStringMode", "Unicode"); + if(toStringModeStr === "ASCII") + { + _toStringMode = Ice.ToStringMode.ASCII; + } + else if(toStringModeStr === "Compat") + { + _toStringMode = Ice.ToStringMode.Compat; + } + else if(toStringModeStr !== "Unicode") + { + throw new Ice.InitializationException("The value for Ice.ToStringMode must be Unicode, ASCII or Compat"); + } + this._implicitContext = ImplicitContextI.create(this._initData.properties.getProperty("Ice.ImplicitContext")); diff --git a/js/src/Ice/LocatorInfo.js b/js/src/Ice/LocatorInfo.js index deeed68660a..8219a62e0b5 100644 --- a/js/src/Ice/LocatorInfo.js +++ b/js/src/Ice/LocatorInfo.js @@ -198,7 +198,7 @@ class LocatorInfo else { s.push("object = "); - s.push(Ice.identityToString(ref.getIdentity())); + s.push(Ice.identityToString(ref.getIdentity(), ref.getInstance().toStringMode())); s.push("\n"); } @@ -241,13 +241,13 @@ class LocatorInfo const s = []; s.push("object not found\n"); s.push("object = "); - s.push(Ice.identityToString(ref.getIdentity())); + s.push(Ice.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.join("")); } const e = new Ice.NotRegisteredException(); e.kindOfObject = "object"; - e.id = Ice.identityToString(ref.getIdentity()); + e.id = Ice.identityToString(ref.getIdentity(), instance.toStringMode()); throw e; } else if(ex instanceof Ice.NotRegisteredException) @@ -269,7 +269,7 @@ class LocatorInfo else { s.push("object = "); - s.push(Ice.identityToString(ref.getIdentity())); + s.push(Ice.identityToString(ref.getIdentity(), instance.toStringMode())); s.push("\n"); } s.push("reason = " + ex.toString()); @@ -313,7 +313,7 @@ class LocatorInfo { s.push("object\n"); s.push("object = "); - s.push(Ice.identityToString(ref.getIdentity())); + s.push(Ice.identityToString(ref.getIdentity(), instance.toStringMode())); s.push("\n"); } instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.join("")); @@ -350,7 +350,7 @@ class LocatorInfo const s = []; s.push("searching for object by id\n"); s.push("object = "); - s.push(Ice.identityToString(ref.getIdentity())); + s.push(Ice.identityToString(ref.getIdentity(), instance.toStringMode())); instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.join("")); } diff --git a/js/src/Ice/ObjectAdapterI.js b/js/src/Ice/ObjectAdapterI.js index 4db04bf214a..07bdd31cea3 100644 --- a/js/src/Ice/ObjectAdapterI.js +++ b/js/src/Ice/ObjectAdapterI.js @@ -176,7 +176,7 @@ class ObjectAdapterI { throw new Ice.AlreadyRegisteredException( "object adapter with router", - Ice.identityToString(router.ice_getIdentity())); + Ice.identityToString(router.ice_getIdentity(), this._instance.toStringMode())); } // diff --git a/js/src/Ice/Operation.js b/js/src/Ice/Operation.js index 37e637bd388..85b70ee6fac 100644 --- a/js/src/Ice/Operation.js +++ b/js/src/Ice/Operation.js @@ -280,7 +280,7 @@ function __dispatchImpl(servant, op, incomingAsync, current) const method = servant[op.servantMethod]; if(method === undefined || typeof(method) !== "function") { - throw new Ice.UnknownException("servant for identity " + Ice.identityToString(current.id) + + throw new Ice.UnknownException("servant for identity " + current.adapter.getCommunicator().identityToString(current.id) + " does not define operation `" + op.servantMethod + "'"); } diff --git a/js/src/Ice/PropertyNames.js b/js/src/Ice/PropertyNames.js index fc1c7b8b9fd..0d1add2f012 100644 --- a/js/src/Ice/PropertyNames.js +++ b/js/src/Ice/PropertyNames.js @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 5 19:04:47 2016 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Fri Oct 14 20:53:43 2016 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -166,6 +166,7 @@ PropertyNames.IceProps = new Property("/^Ice\.ThreadPool\.Server\.ThreadIdleTime/", false, null), new Property("/^Ice\.ThreadPool\.Server\.ThreadPriority/", false, null), new Property("/^Ice\.ThreadPriority/", false, null), + new Property("/^Ice\.ToASCII/", false, null), new Property("/^Ice\.Trace\.Admin\.Properties/", false, null), new Property("/^Ice\.Trace\.Admin\.Logger/", false, null), new Property("/^Ice\.Trace\.Locator/", false, null), diff --git a/js/src/Ice/Reference.js b/js/src/Ice/Reference.js index 0bda489e771..21424413d29 100644 --- a/js/src/Ice/Reference.js +++ b/js/src/Ice/Reference.js @@ -1267,12 +1267,15 @@ class Reference // const s = []; + const toStringMode = this._instance.toStringMode(); + // // If the encoded identity string contains characters which // the reference parser uses as separators, then we enclose // the identity string in quotes. // - const id = Ice.identityToString(this._identity); + + const id = Ice.identityToString(this._identity, toStringMode); if(id.search(/[ :@]/) != -1) { s.push('"'); @@ -1292,7 +1295,7 @@ class Reference // the facet string in quotes. // s.push(" -f "); - const fs = StringUtil.escapeString(this._facet, ""); + const fs = StringUtil.escapeString(this._facet, "", toStringMode); if(fs.search(/[ :@]/) != -1) { s.push('"'); @@ -1967,7 +1970,7 @@ class RoutableReference extends Reference // the reference parser uses as separators, then we enclose // the adapter id string in quotes. // - const a = StringUtil.escapeString(this._adapterId, null); + const a = StringUtil.escapeString(this._adapterId, null, this._instance.toStringMode()); if(a.search(/[ :@]/) != -1) { s.push('"'); diff --git a/js/src/Ice/ServantManager.js b/js/src/Ice/ServantManager.js index d388b366f40..dd9d7628edc 100644 --- a/js/src/Ice/ServantManager.js +++ b/js/src/Ice/ServantManager.js @@ -55,11 +55,11 @@ class ServantManager if(m.has(facet)) { const ex = new Ice.AlreadyRegisteredException(); - ex.id = Ice.identityToString(ident); + ex.id = Ice.identityToString(ident, this._instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length > 0) { - ex.id += " -f " + StringUtil.escapeString(facet, ""); + ex.id += " -f " + StringUtil.escapeString(facet, "", this._instance.toStringMode()); } throw ex; } @@ -96,11 +96,11 @@ class ServantManager if(m === undefined || !m.has(facet)) { const ex = new Ice.NotRegisteredException(); - ex.id = Ice.identityToString(ident); + ex.id = Ice.identityToString(ident, this._instance.toStringMode()); ex.kindOfObject = "servant"; if(facet.length > 0) { - ex.id += " -f " + StringUtil.escapeString(facet, ""); + ex.id += " -f " + StringUtil.escapeString(facet, "", this._instance.toStringMode()); } throw ex; } @@ -141,7 +141,7 @@ class ServantManager if(m === undefined) { const ex = new Ice.NotRegisteredException(); - ex.id = Ice.identityToString(ident); + ex.id = Ice.identityToString(ident, this._instance.toStringMode()); ex.kindOfObject = "servant"; throw ex; } @@ -234,7 +234,7 @@ class ServantManager if(this._locatorMap.has(category)) { const ex = new Ice.AlreadyRegisteredException(); - ex.id = StringUtil.escapeString(category, ""); + ex.id = StringUtil.escapeString(category, "", this._instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } @@ -250,7 +250,7 @@ class ServantManager if(l === undefined) { const ex = new Ice.NotRegisteredException(); - ex.id = StringUtil.escapeString(category, ""); + ex.id = StringUtil.escapeString(category, "", this._instance.toStringMode()); ex.kindOfObject = "servant locator"; throw ex; } diff --git a/js/src/Ice/StringUtil.js b/js/src/Ice/StringUtil.js index 1673f4d745a..c23273e6ba8 100644 --- a/js/src/Ice/StringUtil.js +++ b/js/src/Ice/StringUtil.js @@ -7,7 +7,7 @@ // // ********************************************************************** -const Ice = require("../Ice/Debug").Ice; +const Ice = require("../Ice/Debug").Ice; const Debug = Ice.Debug; Ice.StringUtil = class @@ -49,11 +49,9 @@ Ice.StringUtil = class return -1; } // - // Add escape sequences (such as "\n", or "\007") to make a string - // readable in ASCII. Any characters that appear in special are - // prefixed with a backlash in the returned string. + // Add escape sequences (such as "\n", or "\123") to s // - static escapeString(s, special) + static escapeString(s, special, toStringMode) { special = special === undefined ? null : special; if(special !== null) @@ -68,26 +66,51 @@ Ice.StringUtil = class } let result = []; - for(let i = 0; i < s.length; ++i) + + if(toStringMode === Ice.ToStringMode.Compat) { - const c = s.charCodeAt(i); - if(c < 128) - { - encodeChar(c, result, special); - } - else if(c > 127 && c < 2048) + // Encode UTF-8 bytes + var bytes = unescape(encodeURIComponent(s)); + for(let i = 0; i < bytes.length; ++i) { - encodeChar((c >> 6) | 192, result, special); - encodeChar((c & 63) | 128, result, special); + const c = bytes.charCodeAt(i); + encodeChar(c, result, special, toStringMode); } - else + } + else + { + for(let i = 0; i < s.length; ++i) { - encodeChar((c >> 12) | 224, result, special); - encodeChar(((c >> 6) & 63) | 128, result, special); - encodeChar((c & 63) | 128, result, special); + const c = s.charCodeAt(i); + if(toStringMode === Ice.ToStringMode.Unicode || c < 0xD800 || c > 0xDFFF) + { + encodeChar(c, result, special, toStringMode); + } + else + { + Debug.assert(toStringMode === Ice.ToStringMode.ASCII && c >= 0xD800 && c <= 0xDFFF); + if(i + 1 === s.length) + { + throw new Error("High surrogate without low surrogate"); + } + else + { + const codePoint = s.codePointAt(i); + Debug.assert(codePoint > 0xFFFF); + i++; + + // append \Unnnnnnnn + result.push("\\U"); + const hex = codePoint.toString(16); + for(let j = hex.length; j < 8; j++) + { + result.push('0'); + } + result.push(hex); + } + } } } - return result.join(""); } // @@ -101,10 +124,26 @@ Ice.StringUtil = class Debug.assert(start >= 0 && start <= end && end <= s.length); - const arr = []; - decodeString(s, start, end, arr); - - return arr.join(""); + // Optimization for strings without escapes + let p = s.indexOf('\\', start); + if(p == -1 || p >= end) + { + p = start; + while(p < end) + { + checkChar(s, p++); + } + return s.substring(start, end); + } + else + { + const arr = []; + while(start < end) + { + start = decodeChar(s, start, end, arr); + } + return arr.join(""); + } } // // Split string helper; returns null for unmatched quotes @@ -217,15 +256,10 @@ Ice.StringUtil = class }; module.exports.Ice = Ice; -// -// Write the byte b as an escape sequence if it isn't a printable ASCII -// character and append the escape sequence to sb. Additional characters -// that should be escaped can be passed in special. If b is any of these -// characters, b is preceded by a backslash in sb. -// -function encodeChar(b, sb, special) + +function encodeChar(c, sb, special, toStringMode) { - switch(b) + switch(c) { case 92: // '\\' { @@ -269,44 +303,71 @@ function encodeChar(b, sb, special) } default: { - if(!(b >= 32 && b <= 126)) + var s = String.fromCharCode(c); + + if(special !== null && special.indexOf(s) !== -1) { sb.push('\\'); - const octal = b.toString(8); - // - // Add leading zeroes so that we avoid problems during - // decoding. For example, consider the encoded string - // \0013 (i.e., a character with value 1 followed by - // the character '3'). If the leading zeroes were omitted, - // the result would be incorrectly interpreted by the - // decoder as a single character with value 11. - // - for(let j = octal.length; j < 3; j++) - { - sb.push('0'); - } - sb.push(octal); + sb.push(s); } else { - const c = String.fromCharCode(b); - if(special !== null && special.indexOf(c) !== -1) + if(c < 32 || c > 126) { - sb.push('\\'); - sb.push(c); + if(toStringMode === Ice.ToStringMode.Compat) + { + // + // When ToStringMode=Compat, c is a UTF-8 byte + // + Debug.assert(c < 256); + sb.push('\\'); + const octal = c.toString(8); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(let j = octal.length; j < 3; j++) + { + sb.push('0'); + } + sb.push(octal); + } + else if(c < 32 || c == 127 || toStringMode === Ice.ToStringMode.ASCII) + { + // append \\unnnn + sb.push("\\u"); + const hex = c.toString(16); + for(let j = hex.length; j < 4; j++) + { + sb.push('0'); + } + sb.push(hex); + } + else + { + // keep as is + sb.push(s); + } } else { - sb.push(c); + // printable ASCII character + sb.push(s); } } + break; } } } + function checkChar(s, pos) { - const n = s.charCodeAt(pos); - if(!(n >= 32 && n <= 126)) + const c = s.charCodeAt(pos); + if(c < 32 || c === 127) { let msg; if(pos > 0) @@ -317,32 +378,25 @@ function checkChar(s, pos) { msg = "first character"; } - msg += " is not a printable ASCII character (ordinal " + n + ")"; + msg += " has invalid ordinal value" + c; throw new Error(msg); } - return n; + return s.charAt(pos) } - // -// Decode the character or escape sequence starting at start and return it. -// nextStart is set to the index of the first character following the decoded -// character or escape sequence. +// Decode the character or escape sequence starting at start and appends it to result; +// returns the index of the first character following the decoded character +// or escape sequence. // -function decodeChar(s, start, end, nextStart) +function decodeChar(s, start, end, result) { Debug.assert(start >= 0); + Debug.assert(start < end); Debug.assert(end <= s.length); - if(start >= end) - { - throw new Error("EOF while decoding string"); - } - - let c; - if(s.charAt(start) != '\\') { - c = checkChar(s, start++); + result.push(checkChar(s, start++)); } else { @@ -350,43 +404,94 @@ function decodeChar(s, start, end, nextStart) { throw new Error("trailing backslash"); } - switch(s.charAt(++start)) + + const c = s.charAt(++start); + + switch(c) { case '\\': case '\'': case '"': { - c = s.charCodeAt(start++); + ++start; + result.push(c); break; } case 'b': { ++start; - c = "\b".charCodeAt(0); + result.push("\b"); break; } case 'f': { ++start; - c = "\f".charCodeAt(0); + result.push("\f"); break; } case 'n': { ++start; - c = "\n".charCodeAt(0); + result.push("\n"); break; } case 'r': { ++start; - c = "\r".charCodeAt(0); + result.push("\r") break; } case 't': { ++start; - c = "\t".charCodeAt(0); + result.push("\t") + break; + } + case 'u': + case 'U': + { + let codePoint = 0; + const inBMP = (c === 'u'); + let size = inBMP ? 4 : 8; + ++start; + while(size > 0 && start < end) + { + let charVal = s.charCodeAt(start++); + if(charVal >= 0x30 && charVal <= 0x39) + { + charVal -= 0x30; + } + else if(charVal >= 0x61 && charVal <= 0x66) + { + charVal += 10 - 0x61; + } + else if(charVal >= 0x41 && charVal <= 0x46) + { + charVal += 10 - 0x41; + } + else + { + break; // while + } + codePoint = codePoint * 16 + charVal; + --size; + } + if(size > 0) + { + throw new Error("Invalid universal character name: too few hex digits"); + } + if(inBMP && codePoint >= 0xD800 && codePoint <= 0xDFFF) + { + throw new Error("A non-BMP character cannot be encoded with \\unnnn, use \\Unnnnnnnn instead"); + } + if(inBMP || codePoint <= 0xFFFF) + { + result.push(String.fromCharCode(codePoint)); + } + else + { + result.push(String.fromCodePoint(codePoint)); + } break; } case '0': @@ -398,65 +503,61 @@ function decodeChar(s, start, end, nextStart) case '6': case '7': { - const octalChars = "01234567"; - let val = 0; - for(let j = 0; j < 3 && start < end; ++j) + // UTF-8 byte sequence encoded with octal escapes + + let arr = []; + let done = false; + while(!done) { - const ch = s.charAt(start++); - if(octalChars.indexOf(ch) == -1) + let val = 0; + for(let j = 0; j < 3 && start < end; ++j) { - --start; - break; + let charVal = s.charCodeAt(start++) - '0'.charCodeAt(0); + if(charVal < 0 || charVal > 7) + { + --start; + if(j === 0) + { + // first character after escape is not 0-7: + done = true; + --start; // go back to the previous backslash + } + break; // for + } + val = val * 8 + charVal; + } + + if(!done) + { + if(val > 255) + { + throw new Error("octal value \\" + val.toString(8) + " (" + val + ") is out of range"); + } + arr.push(String.fromCharCode(val)); + + if((start + 1 < end) && s.charAt(start) === '\\') + { + start++; + // loop, read next octal escape sequence + } + else + { + done = true; + } } - val = val * 8 + parseInt(ch); - } - if(val > 255) - { - throw new Error("octal value \\" + val.toString(8) + " (" + val + ") is out of range"); } - c = val; + + // Decode UTF-8 arr into string + result.push(decodeURIComponent(escape(arr.join("")))); break; } default: { - c = checkChar(s, start++); + result.push(checkChar(s, start++)); break; } } } - nextStart.value = start; - return c; -} -// -// Remove escape sequences from s and append the result to sb. -// Return true if successful, false otherwise. -// -function decodeString(s, start, end, arr) -{ - let nextStart = { 'value': 0 }; - while(start < end) - { - const c = decodeChar(s, start, end, nextStart); - start = nextStart.value; - - if(c < 128) - { - arr.push(String.fromCharCode(c)); - } - else if(c > 191 && c < 224) - { - const c2 = decodeChar(s, start, end, nextStart); - start = nextStart.value; - arr.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63))); - } - else - { - const c2 = decodeChar(s, start, end, nextStart); - start = nextStart.value; - const c3 = decodeChar(s, start, end, nextStart); - start = nextStart.value; - arr.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); - } - } + return start; } diff --git a/js/src/Ice/ToStringMode.js b/js/src/Ice/ToStringMode.js new file mode 100644 index 00000000000..ed2112858dd --- /dev/null +++ b/js/src/Ice/ToStringMode.js @@ -0,0 +1,12 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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. +// +// ********************************************************************** + +const Ice = require("../Ice/EnumBase").Ice; +Ice.ToStringMode = Ice.Slice.defineEnum([['Unicode', 0], ['ASCII',1], ['Compat',2]]); +module.exports.Ice = Ice; diff --git a/js/src/Ice/TraceUtil.js b/js/src/Ice/TraceUtil.js index 3d8c2c93304..9d52c297d55 100644 --- a/js/src/Ice/TraceUtil.js +++ b/js/src/Ice/TraceUtil.js @@ -39,15 +39,21 @@ function traceSlicing(kind, typeId, slicingCat, logger) function printIdentityFacetOperation(s, stream) { + let toStringMode = Ice.ToStringMode.Unicode; + if(stream.instance() !== null) + { + toStringMode = stream.instance().toStringMode(); + } + const identity = new Identity(); identity.__read(stream); - s.push("\nidentity = " + Ice.identityToString(identity)); + s.push("\nidentity = " + Ice.identityToString(identity, toStringMode)); const facet = Ice.StringSeqHelper.read(stream); s.push("\nfacet = "); if(facet.length > 0) { - s.push(StringUtil.escapeString(facet[0], "")); + s.push(StringUtil.escapeString(facet[0], "", toStringMode)); } const operation = stream.readString(); diff --git a/js/test/Ice/proxy/Client.js b/js/test/Ice/proxy/Client.js index 61d7fe996cc..b25d8e2e452 100644 --- a/js/test/Ice/proxy/Client.js +++ b/js/test/Ice/proxy/Client.js @@ -321,9 +321,11 @@ } } + // // Test for bug ICE-5543: escaped escapes in stringToIdentity // + var id = new Ice.Identity("test", ",X2QNUAzSBcJ_e$AV;E\\"); var id2 = Ice.stringToIdentity(Ice.identityToString(id)); test(id.equals(id2)); @@ -332,6 +334,80 @@ id2 = Ice.stringToIdentity(Ice.identityToString(id)); test(id.equals(id2)); + id = new Ice.Identity("/test", "cat/"); + var idStr = Ice.identityToString(id); + test(idStr === "cat\\//\\/test"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + + try + { + // Illegal character < 32 + id = Ice.stringToIdentity("xx\x01FooBar"); + test(false); + } + catch(ex) + { + if(!(ex instanceof Ice.IdentityParseException)) + { + test(false); + } + } + try + { + // Illegal surrogate + id = Ice.stringToIdentity("xx\\ud911"); + test(false); + } + catch(ex) + { + if(!(ex instanceof Ice.IdentityParseException)) + { + test(false); + } + } + + // Testing bytes 127 (\x7F) and € + id = new Ice.Identity("test", "\x7F€"); + + idStr = Ice.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr === "\\u007f€/test"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + test(Ice.identityToString(id) === idStr); + + idStr = Ice.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr === "\\u007f\\u20ac/test"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.identityToString(id, Ice.ToStringMode.Compat); + test(idStr === "\\177\\342\\202\\254/test"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + + id2 = Ice.stringToIdentity(communicator.identityToString(id)); + test(id.equals(id2)); + + // More unicode characters + + id = new Ice.Identity("banana \x0e-\ud83c\udf4c\u20ac\u00a2\u0024", "greek \ud800\udd6a"); + + idStr = Ice.identityToString(id, Ice.ToStringMode.Unicode); + test(idStr === "greek \ud800\udd6a/banana \\u000e-\ud83c\udf4c\u20ac\u00a2$"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.identityToString(id, Ice.ToStringMode.ASCII); + test(idStr === "greek \\U0001016a/banana \\u000e-\\U0001f34c\\u20ac\\u00a2$"); + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + + idStr = Ice.identityToString(id, Ice.ToStringMode.Compat); + test(idStr === "greek \\360\\220\\205\\252/banana \\016-\\360\\237\\215\\214\\342\\202\\254\\302\\242$") + id2 = Ice.stringToIdentity(idStr); + test(id.equals(id2)); + out.writeLine("ok"); out.write("testing propertyToProxy... "); diff --git a/objective-c/include/objc/Ice/Initialize.h b/objective-c/include/objc/Ice/Initialize.h index 5dcaa28eb79..597e5ce079a 100644 --- a/objective-c/include/objc/Ice/Initialize.h +++ b/objective-c/include/objc/Ice/Initialize.h @@ -77,6 +77,7 @@ ICE_API @interface ICEUtil : NSObject +(NSArray*)argsToStringSeq:(int)argc argv:(char*[])argv; +(void)stringSeqToArgs:(NSArray*)args argc:(int*)argc argv:(char*[])argv; +(ICEIdentity*) stringToIdentity:(NSString*)str; ++(NSMutableString*) identityToString:(ICEIdentity*)ident toStringMode:(ICEToStringMode)toStringMode; +(NSMutableString*) identityToString:(ICEIdentity*)ident; @end diff --git a/objective-c/src/Ice/CommunicatorI.mm b/objective-c/src/Ice/CommunicatorI.mm index 3110c72e47d..39d1e3a929e 100644 --- a/objective-c/src/Ice/CommunicatorI.mm +++ b/objective-c/src/Ice/CommunicatorI.mm @@ -242,7 +242,17 @@ -(NSMutableString*) identityToString:(ICEIdentity*)ident { - return [ICEUtil identityToString:ident]; + NSException* nsex = nil; + try + { + return [toNSMutableString(COMMUNICATOR->identityToString([ident identity])) autorelease]; + } + catch(const std::exception& ex) + { + nsex = toObjCException(ex); + } + @throw nsex; + return nil; // Keep the compiler happy. } -(id<ICEObjectAdapter>) createObjectAdapter:(NSString*)name; diff --git a/objective-c/src/Ice/Initialize.mm b/objective-c/src/Ice/Initialize.mm index 0e23324738f..40f8ce180e7 100644 --- a/objective-c/src/Ice/Initialize.mm +++ b/objective-c/src/Ice/Initialize.mm @@ -554,12 +554,13 @@ private: return nil; // Keep the compiler happy. } -+(NSMutableString*) identityToString:(ICEIdentity*)ident ++(NSMutableString*) identityToString:(ICEIdentity*)ident toStringMode:(ICEToStringMode)toStringMode { NSException* nsex = nil; try { - return [toNSMutableString(Ice::identityToString([ident identity])) autorelease]; + return [toNSMutableString(Ice::identityToString([ident identity], + static_cast<Ice::ToStringMode>(toStringMode))) autorelease]; } catch(const std::exception& ex) { @@ -568,6 +569,12 @@ private: @throw nsex; return nil; // Keep the compiler happy. } + ++(NSMutableString*) identityToString:(ICEIdentity*)ident +{ + return [ICEUtil identityToString:ident toStringMode:ICEUnicode]; +} + @end @implementation ICEEncodingVersion(StringConv) diff --git a/objective-c/src/Ice/Proxy.mm b/objective-c/src/Ice/Proxy.mm index f269605b385..4c44532c3d8 100644 --- a/objective-c/src/Ice/Proxy.mm +++ b/objective-c/src/Ice/Proxy.mm @@ -780,7 +780,7 @@ BOOL _returnsData; marshal:marshal returnsData:NO completed:completed - response:TRUE + response:YES exception:exception sent:sent context:ctx]; @@ -800,7 +800,7 @@ BOOL _returnsData; mode:mode format:format marshal:marshal - returnsData:TRUE + returnsData:YES completed:completed response:response exception:exception diff --git a/objective-c/test/Ice/binding/AllTests.m b/objective-c/test/Ice/binding/AllTests.m index 92c61e93000..ee873ed5a65 100644 --- a/objective-c/test/Ice/binding/AllTests.m +++ b/objective-c/test/Ice/binding/AllTests.m @@ -137,7 +137,7 @@ createTestIntfPrx(NSArray* adapters) test = [a getTestIntf]; [endpoints addObjectsFromArray:getEndpoints(test)]; } - NSString* proxy = [ICEUtil identityToString:[test ice_getIdentity]]; + NSString* proxy = [[test ice_getCommunicator] identityToString:[test ice_getIdentity]]; for(NSString* e in endpoints) { proxy = [proxy stringByAppendingString:@":"]; diff --git a/objective-c/test/Ice/proxy/AllTests.m b/objective-c/test/Ice/proxy/AllTests.m index 5f595d46687..f7f6cc90acf 100644 --- a/objective-c/test/Ice/proxy/AllTests.m +++ b/objective-c/test/Ice/proxy/AllTests.m @@ -413,8 +413,31 @@ proxyAllTests(id<ICECommunicator> communicator) tprintf("testing proxy methods... "); test([[communicator identityToString:[[base ice_identity:[communicator stringToIdentity:@"other"]] ice_getIdentity]] isEqualToString:@"other"]); - test([[ICEUtil identityToString:[[base ice_identity:[ICEUtil stringToIdentity:@"other"]] ice_getIdentity]] - isEqualToString:@"other"]); + + // + // Verify that ToStringMode is passed correctly + // + ICEIdentity *ident = [ICEIdentity identity:@"test" category:@"\x7F\xE2\x82\xAC"]; + + NSString *idStr = [ICEUtil identityToString:ident toStringMode:ICEUnicode]; + test([idStr isEqualToString:@"\\u007f\xE2\x82\xAC/test"]); + ICEIdentity *id2 = [ICEUtil stringToIdentity:idStr]; + test([ident isEqual:id2]); + test([[ICEUtil identityToString:ident] isEqualToString:idStr]); + + idStr = [ICEUtil identityToString:ident toStringMode:ICEASCII]; + test([idStr isEqualToString:@"\\u007f\\u20ac/test"]); + id2 = [ICEUtil stringToIdentity:idStr]; + test([ident isEqual:id2]); + + idStr = [ICEUtil identityToString:ident toStringMode:ICECompat]; + test([idStr isEqualToString:@"\\177\\342\\202\\254/test"]); + id2 = [ICEUtil stringToIdentity:idStr]; + test([ident isEqual:id2]); + + id2 = [ICEUtil stringToIdentity:[communicator identityToString:ident]]; + test([ident isEqual:id2]); + test([[[base ice_facet:@"facet"] ice_getFacet] isEqualToString:@"facet"]); test([[[base ice_adapterId:@"id"] ice_getAdapterId] isEqualToString:@"id"]); test([[base ice_twoway] ice_isTwoway]); diff --git a/php/lib/Ice.php b/php/lib/Ice.php index fa996209da6..402f94de032 100644 --- a/php/lib/Ice.php +++ b/php/lib/Ice.php @@ -187,6 +187,7 @@ require_once 'Ice/Version.php'; require_once 'Ice/Instrumentation.php'; require_once 'Ice/Metrics.php'; require_once 'Ice/RemoteLogger.php'; +require_once 'Ice/Communicator.php'; $Ice_Protocol_1_0 = new Ice_ProtocolVersion(1, 0); $Ice_Encoding_1_0 = new Ice_EncodingVersion(1, 0); diff --git a/php/lib/Ice_ns.php b/php/lib/Ice_ns.php index 95bcf7d55d5..b21357c833f 100644 --- a/php/lib/Ice_ns.php +++ b/php/lib/Ice_ns.php @@ -195,6 +195,7 @@ require_once 'Ice/Version.php'; require_once 'Ice/Instrumentation.php'; require_once 'Ice/Metrics.php'; require_once 'Ice/RemoteLogger.php'; +require_once 'Ice/Communicator.php'; $Ice_Protocol_1_0 = new Ice\ProtocolVersion(1, 0); $Ice_Encoding_1_0 = new Ice\EncodingVersion(1, 0); diff --git a/php/src/php5/Communicator.cpp b/php/src/php5/Communicator.cpp index 8b03d75a694..d1a53a18e32 100644 --- a/php/src/php5/Communicator.cpp +++ b/php/src/php5/Communicator.cpp @@ -1365,7 +1365,9 @@ ZEND_FUNCTION(Ice_identityToString) assert(identityClass); zval* zv; - if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, identityClass) != SUCCESS) + long mode = 0; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O|l"), &zv, identityClass, &mode TSRMLS_CC) != SUCCESS) { RETURN_NULL(); } @@ -1377,7 +1379,7 @@ ZEND_FUNCTION(Ice_identityToString) try { - string str = Ice::identityToString(id); + string str = identityToString(id, static_cast<Ice::ToStringMode>(mode)); RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()), 1); } catch(const IceUtil::Exception& ex) diff --git a/php/src/php7/Communicator.cpp b/php/src/php7/Communicator.cpp index b7943d07907..4f8ffabd945 100644 --- a/php/src/php7/Communicator.cpp +++ b/php/src/php7/Communicator.cpp @@ -1368,7 +1368,9 @@ ZEND_FUNCTION(Ice_identityToString) assert(identityClass); zval* zv; - if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O"), &zv, identityClass) != SUCCESS) + long mode = 0; + + if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O|l"), &zv, identityClass, &mode) != SUCCESS) { RETURN_NULL(); } @@ -1380,7 +1382,7 @@ ZEND_FUNCTION(Ice_identityToString) try { - string str = Ice::identityToString(id); + string str = Ice::identityToString(id, static_cast<Ice::ToStringMode>(mode)); RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length())); } catch(const IceUtil::Exception& ex) diff --git a/php/test/Ice/proxy/Client.php b/php/test/Ice/proxy/Client.php index a80838fb44f..987a8c792a6 100644 --- a/php/test/Ice/proxy/Client.php +++ b/php/test/Ice/proxy/Client.php @@ -42,6 +42,18 @@ function allTests($communicator) $identityToString = $NS ? "Ice\\identityToString" : "Ice_identityToString"; $stringToIdentity = $NS ? "Ice\\stringToIdentity" : "Ice_stringToIdentity"; + $modeUnicode = $NS ? constant("Ice\\ToStringMode::Unicode") : constant("Ice_ToStringMode::Unicode"); + $modeASCII = $NS ? constant("Ice\\ToStringMode::ASCII") : constant("Ice_ToStringMode::ASCII"); + $modeCompat = $NS ? constant("Ice\\ToStringMode::Compat") : constant("Ice_ToStringMode::Compat"); + + if($NS) + { + echo "namespace ON\n"; + } + else + { + echo "namespace OFF\n"; + } echo "testing stringToProxy... "; flush(); @@ -439,7 +451,31 @@ function allTests($communicator) echo "testing proxy methods... "; flush(); test($communicator->identityToString($base->ice_identity($communicator->stringToIdentity("other"))->ice_getIdentity()) == "other"); - test($identityToString($base->ice_identity($stringToIdentity("other"))->ice_getIdentity()) == "other"); + + // + // Verify that ToStringMode is passed correctly + // + $ident = new Ice_Identity("test", "\x7F\xE2\x82\xAC"); + + $idStr = $identityToString($ident, $modeUnicode); + test($idStr == "\\u007f\xE2\x82\xAC/test"); + $ident2 = $stringToIdentity($idStr); + test($ident == $ident2); + test($identityToString($ident) == $idStr); + + $idStr = $identityToString($ident, $modeASCII); + test($idStr == "\\u007f\\u20ac/test"); + $ident2 = $stringToIdentity($idStr); + test($ident == $ident2); + + $idStr = $identityToString($ident, $modeCompat); + test($idStr == "\\177\\342\\202\\254/test"); + $ident2 = $stringToIdentity($idStr); + test($ident == $ident2); + + $ident2 = $stringToIdentity($communicator->identityToString($ident)); + test($ident == $ident2); + test($base->ice_facet("facet")->ice_getFacet() == "facet"); test($base->ice_adapterId("id")->ice_getAdapterId() == "id"); test($base->ice_twoway()->ice_isTwoway()); diff --git a/python/modules/IcePy/Communicator.cpp b/python/modules/IcePy/Communicator.cpp index 1549cd1043c..eb223c85853 100644 --- a/python/modules/IcePy/Communicator.cpp +++ b/python/modules/IcePy/Communicator.cpp @@ -1740,19 +1740,34 @@ IcePy::getCommunicatorWrapper(const Ice::CommunicatorPtr& communicator) extern "C" PyObject* -IcePy_identityToString(PyObject* /*self*/, PyObject* obj) +IcePy_identityToString(PyObject* /*self*/, PyObject* args) { + PyObject* identityType = lookupType("Ice.Identity"); + PyObject* obj; + PyObject* mode = 0; + if(!PyArg_ParseTuple(args, STRCAST("O!O"), identityType, &obj, &mode)) + { + return 0; + } + Ice::Identity id; if(!getIdentity(obj, id)) { return 0; } - + + Ice::ToStringMode toStringMode = Ice::Unicode; + if(mode != Py_None && PyObject_HasAttrString(mode, STRCAST("value"))) + { + PyObjectHandle modeValue = PyObject_GetAttrString(mode, STRCAST("value")); + toStringMode = static_cast<Ice::ToStringMode>(PyLong_AsLong(modeValue.get())); + } + string str; try { - str = Ice::identityToString(id); + str = identityToString(id, toStringMode); } catch(const Ice::Exception& ex) { diff --git a/python/modules/IcePy/Init.cpp b/python/modules/IcePy/Init.cpp index 88205ebc571..581e4f649c5 100644 --- a/python/modules/IcePy/Init.cpp +++ b/python/modules/IcePy/Init.cpp @@ -60,8 +60,8 @@ static PyMethodDef methods[] = PyDoc_STR(STRCAST("createProperties([args]) -> Ice.Properties")) }, { STRCAST("stringToIdentity"), reinterpret_cast<PyCFunction>(IcePy_stringToIdentity), METH_O, PyDoc_STR(STRCAST("stringToIdentity(string) -> Ice.Identity")) }, - { STRCAST("identityToString"), reinterpret_cast<PyCFunction>(IcePy_identityToString), METH_O, - PyDoc_STR(STRCAST("identityToString(Ice.Identity) -> string")) }, + { STRCAST("identityToString"), reinterpret_cast<PyCFunction>(IcePy_identityToString), METH_VARARGS, + PyDoc_STR(STRCAST("identityToString(Ice.Identity, Ice.ToStringMode) -> string")) }, { STRCAST("getProcessLogger"), reinterpret_cast<PyCFunction>(IcePy_getProcessLogger), METH_NOARGS, PyDoc_STR(STRCAST("getProcessLogger() -> Ice.Logger")) }, { STRCAST("setProcessLogger"), reinterpret_cast<PyCFunction>(IcePy_setProcessLogger), METH_VARARGS, diff --git a/python/modules/IcePy/Operation.cpp b/python/modules/IcePy/Operation.cpp index 3b59074a8e5..c8dad9a0c96 100644 --- a/python/modules/IcePy/Operation.cpp +++ b/python/modules/IcePy/Operation.cpp @@ -3349,7 +3349,7 @@ IcePy::TypedUpcall::dispatch(PyObject* servant, const pair<const Ice::Byte*, con if(!method.get()) { ostringstream ostr; - ostr << "servant for identity " << identityToString(current.id) + ostr << "servant for identity " << _communicator->identityToString(current.id) << " does not define operation `" << _op->dispatchName << "'"; string str = ostr.str(); PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); @@ -3712,7 +3712,7 @@ IcePy::BlobjectUpcall::dispatch(PyObject* servant, const pair<const Ice::Byte*, if(!method.get()) { ostringstream ostr; - ostr << "servant for identity " << identityToString(current.id) + ostr << "servant for identity " << communicator->identityToString(current.id) << " does not define operation `" << dispatchName << "'"; string str = ostr.str(); PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); diff --git a/python/python/Ice.py b/python/python/Ice.py index 162f626682d..7c06a1fec77 100644 --- a/python/python/Ice.py +++ b/python/python/Ice.py @@ -716,8 +716,8 @@ the list that were recognized by the Ice run time. # # Ice.identityToString # -def identityToString(id): - return IcePy.identityToString(id) +def identityToString(id, toStringMode=None): + return IcePy.identityToString(id, toStringMode) # # Ice.stringToIdentity diff --git a/python/test/Ice/location/AllTests.py b/python/test/Ice/location/AllTests.py index bf0a378b85f..91519152101 100644 --- a/python/test/Ice/location/AllTests.py +++ b/python/test/Ice/location/AllTests.py @@ -248,7 +248,7 @@ def allTests(communicator, ref): registry.addObject(adapter.add(HelloI(), id)); adapter.activate(); - helloPrx = Test.HelloPrx.checkedCast(communicator.stringToProxy(Ice.identityToString(id))); + helloPrx = Test.HelloPrx.checkedCast(communicator.stringToProxy(communicator.identityToString(id))); test(not helloPrx.ice_getConnection()); adapter.deactivate(); diff --git a/python/test/Ice/proxy/AllTests.py b/python/test/Ice/proxy/AllTests.py index bd889945639..6e04cc674fa 100644 --- a/python/test/Ice/proxy/AllTests.py +++ b/python/test/Ice/proxy/AllTests.py @@ -358,10 +358,35 @@ def allTests(communicator, collocated): sys.stdout.write("testing proxy methods... ") sys.stdout.flush() + + test(communicator.identityToString(base.ice_identity(communicator.stringToIdentity("other")).ice_getIdentity()) \ == "other") - test(Ice.identityToString(base.ice_identity(Ice.stringToIdentity("other")).ice_getIdentity()) == "other") - + + # + # Verify that ToStringMode is passed correctly + # + ident = Ice.Identity("test", "\x7F\xE2\x82\xAC") + + idStr = Ice.identityToString(ident, Ice.ToStringMode.Unicode) + test(idStr == "\\u007f\xE2\x82\xAC/test") + ident2 = Ice.stringToIdentity(idStr) + test(ident == ident2) + test(Ice.identityToString(ident) == idStr) + + idStr = Ice.identityToString(ident, Ice.ToStringMode.ASCII) + test(idStr == "\\u007f\\u20ac/test") + ident2 = Ice.stringToIdentity(idStr) + test(ident == ident2) + + idStr = Ice.identityToString(ident, Ice.ToStringMode.Compat) + test(idStr == "\\177\\342\\202\\254/test") + ident2 = Ice.stringToIdentity(idStr) + test(ident == ident2) + + ident2 = Ice.stringToIdentity(communicator.identityToString(ident)) + test(ident == ident2) + test(base.ice_facet("facet").ice_getFacet() == "facet") test(base.ice_adapterId("id").ice_getAdapterId() == "id") test(base.ice_twoway().ice_isTwoway()) diff --git a/ruby/ruby/Ice.rb b/ruby/ruby/Ice.rb index 88e1b9a744f..41d14b2ad7d 100644 --- a/ruby/ruby/Ice.rb +++ b/ruby/ruby/Ice.rb @@ -213,6 +213,7 @@ end # require 'Ice/BuiltinSequences.rb' require 'Ice/Current.rb' +require 'Ice/Communicator.rb' require 'Ice/EndpointTypes.rb' require 'Ice/LocalException.rb' require 'Ice/Locator.rb' diff --git a/ruby/src/IceRuby/Communicator.cpp b/ruby/src/IceRuby/Communicator.cpp index 3d90f420464..73fd483f8be 100644 --- a/ruby/src/IceRuby/Communicator.cpp +++ b/ruby/src/IceRuby/Communicator.cpp @@ -239,12 +239,27 @@ IceRuby_stringToIdentity(VALUE self, VALUE str) extern "C" VALUE -IceRuby_identityToString(VALUE self, VALUE id) +IceRuby_identityToString(int argc, VALUE* argv, VALUE self) { ICE_RUBY_TRY { - Ice::Identity ident = getIdentity(id); - string str = Ice::identityToString(ident); + if(argc < 1 || argc > 2) + { + throw RubyException(rb_eArgError, "wrong number of arguments"); + } + + Ice::Identity ident = getIdentity(argv[0]); + + + Ice::ToStringMode toStringMode = Ice::Unicode; + if(argc == 2) + { + volatile VALUE modeValue = callRuby(rb_funcall, argv[1], rb_intern("to_i"), 0); + assert(TYPE(modeValue) == T_FIXNUM); + toStringMode = static_cast<Ice::ToStringMode>(FIX2LONG(modeValue)); + } + + string str = Ice::identityToString(ident, toStringMode); return createString(str); } ICE_RUBY_CATCH @@ -602,7 +617,7 @@ void IceRuby::initCommunicator(VALUE iceModule) { rb_define_module_function(iceModule, "initialize", CAST_METHOD(IceRuby_initialize), -1); - rb_define_module_function(iceModule, "identityToString", CAST_METHOD(IceRuby_identityToString), 1); + rb_define_module_function(iceModule, "identityToString", CAST_METHOD(IceRuby_identityToString), -1); rb_define_module_function(iceModule, "stringToIdentity", CAST_METHOD(IceRuby_stringToIdentity), 1); _communicatorClass = rb_define_class_under(iceModule, "CommunicatorI", rb_cObject); diff --git a/ruby/src/IceRuby/Util.cpp b/ruby/src/IceRuby/Util.cpp index ef076d04bd8..7fa1222fb06 100644 --- a/ruby/src/IceRuby/Util.cpp +++ b/ruby/src/IceRuby/Util.cpp @@ -442,8 +442,8 @@ IceRuby::contextToHash(const Ice::Context& ctx) volatile VALUE result = callRuby(rb_hash_new); for(Ice::Context::const_iterator p = ctx.begin(); p != ctx.end(); ++p) { - volatile VALUE key = callRuby(rb_str_new, p->first.c_str(), static_cast<long>(p->first.size())); - volatile VALUE value = callRuby(rb_str_new, p->second.c_str(), static_cast<long>(p->second.size())); + volatile VALUE key = createString(p->first); + volatile VALUE value = createString(p->second); callRuby(rb_hash_aset, result, key, value); } return result; @@ -522,8 +522,8 @@ IceRuby::createIdentity(const Ice::Identity& id) assert(!NIL_P(cls)); volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls); - volatile VALUE name = callRuby(rb_str_new, id.name.c_str(), static_cast<long>(id.name.size())); - volatile VALUE category = callRuby(rb_str_new, id.category.c_str(), static_cast<long>(id.category.size())); + volatile VALUE name = createString(id.name); + volatile VALUE category = createString(id.category); callRuby(rb_iv_set, result, "@name", name); callRuby(rb_iv_set, result, "@category", category); return result; diff --git a/ruby/test/Ice/proxy/AllTests.rb b/ruby/test/Ice/proxy/AllTests.rb index cc15619ccc5..cecc44c2b7d 100644 --- a/ruby/test/Ice/proxy/AllTests.rb +++ b/ruby/test/Ice/proxy/AllTests.rb @@ -355,7 +355,31 @@ def allTests(communicator) print "testing proxy methods... " STDOUT.flush test(communicator.identityToString(base.ice_identity(communicator.stringToIdentity("other")).ice_getIdentity()) == "other") - test(Ice::identityToString(base.ice_identity(Ice::stringToIdentity("other")).ice_getIdentity()) == "other") + + # + # Verify that ToStringMode is passed correctly + # + ident = Ice::Identity.new("test", "\x7F\xE2\x82\xAC") + + idStr = Ice::identityToString(ident, Ice::ToStringMode::Unicode) + test(idStr == "\\u007f\xE2\x82\xAC/test") + ident2 = Ice::stringToIdentity(idStr) + test(ident == ident2) + test(Ice::identityToString(ident) == idStr) + + idStr = Ice::identityToString(ident, Ice::ToStringMode::ASCII) + test(idStr == "\\u007f\\u20ac/test") + ident2 = Ice::stringToIdentity(idStr) + test(ident == ident2) + + idStr = Ice::identityToString(ident, Ice::ToStringMode::Compat) + test(idStr == "\\177\\342\\202\\254/test") + ident2 = Ice::stringToIdentity(idStr) + test(ident == ident2) + + ident2 = Ice::stringToIdentity(communicator.identityToString(ident)) + test(ident == ident2) + test(base.ice_facet("facet").ice_getFacet() == "facet") test(base.ice_adapterId("id").ice_getAdapterId() == "id") test(base.ice_twoway().ice_isTwoway()) diff --git a/slice/Ice/Communicator.ice b/slice/Ice/Communicator.ice index 8914cf37a1a..3940e93691c 100644 --- a/slice/Ice/Communicator.ice +++ b/slice/Ice/Communicator.ice @@ -216,7 +216,7 @@ local interface Communicator * @see #stringToIdentity * **/ - ["cpp:const", "deprecate:identityToString() is deprecated, use the static identityToString() method instead."] + ["cpp:const"] string identityToString(Identity ident); /** @@ -583,4 +583,34 @@ local interface Communicator FacetMap findAllAdminFacets(); }; + +/** + * The output mode for xxxToString method such as identityToString and proxyToString. + * The actual encoding format for the string is the same for all modes: you + * don't need to specify an encoding format or mode when reading such a string. + * + **/ +local enum ToStringMode +{ + /** + * Characters > 127 are kept as-is in the resulting string. Non-printable ASCII + * characters <= 127 are encoded as \\t, \\n (etc.) or \\unnnn. + **/ + Unicode, + + /** + * Characters > 127 are encoded as universal character names in the resulting string: + * \\unnnn for BMP characters and \\Unnnnnnnn for non-BMP characters. Non-printable ASCII + * characters <= 127 are encoded as \\t, \\n (etc.) or \\unnnn. + **/ + ASCII, + + /** + * Characters > 127 are encoded as a sequence of UTF-8 bytes using octal escapes. + * characters <= 127 are encoded as \\t, \\n (etc.) or an octal escape. Use this mode + * to generate strings compatible with Ice 3.6 and earlier. + **/ + Compat +}; + }; |