| | | 1 | | // Copyright (c) ZeroC, Inc. |
| | | 2 | | |
| | | 3 | | #nullable enable |
| | | 4 | | |
| | | 5 | | namespace Ice; |
| | | 6 | | |
| | | 7 | | /// <summary> |
| | | 8 | | /// Utility methods for the Ice runtime. |
| | | 9 | | /// </summary> |
| | | 10 | | public sealed class Util |
| | | 11 | | { |
| | | 12 | | /// <summary> |
| | | 13 | | /// Creates a new empty property set. |
| | | 14 | | /// </summary> |
| | | 15 | | /// <returns>A new empty property set.</returns> |
| | | 16 | | /// <remarks>This method is provided for backwards compatibility. New code should call the |
| | | 17 | | /// <see cref="Properties()" /> constructor directly.</remarks> |
| | 0 | 18 | | public static Properties createProperties() => new(); |
| | | 19 | | |
| | | 20 | | /// <summary> |
| | | 21 | | /// Creates a property set initialized from command-line arguments and a default property set. |
| | | 22 | | /// </summary> |
| | | 23 | | /// <param name="args">The command-line arguments.</param> |
| | | 24 | | /// <param name="defaults">Default values for the new property set.</param> |
| | | 25 | | /// <returns>A new property set.</returns> |
| | | 26 | | /// <remarks>This method is provided for backwards compatibility. New code should call the |
| | | 27 | | /// <see cref="Properties(ref string[], Properties?)" /> constructor directly.</remarks> |
| | | 28 | | public static Properties createProperties(ref string[] args, Properties? defaults = null) => |
| | 0 | 29 | | new(ref args, defaults); |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Creates a new communicator. |
| | | 33 | | /// </summary> |
| | | 34 | | /// <param name="initData">Options for the new communicator.</param> |
| | | 35 | | /// <returns>The new communicator.</returns> |
| | | 36 | | /// <remarks>This method is provided for backwards compatibility. New code should call the |
| | | 37 | | /// <see cref="Communicator(InitializationData?)" /> constructor directly.</remarks> |
| | 0 | 38 | | public static Communicator initialize(InitializationData? initData = null) => new(initData); |
| | | 39 | | |
| | | 40 | | /// <summary> |
| | | 41 | | /// Creates a new communicator, using Ice properties parsed from command-line arguments. |
| | | 42 | | /// </summary> |
| | | 43 | | /// <param name="args">Command-line arguments.</param> |
| | | 44 | | /// <returns>The new communicator.</returns> |
| | | 45 | | /// <remarks>This method is provided for backwards compatibility. New code should call the |
| | | 46 | | /// <see cref="Communicator(ref string[])" /> constructor directly.</remarks> |
| | 0 | 47 | | public static Communicator initialize(ref string[] args) => new(ref args); |
| | | 48 | | |
| | | 49 | | /// <summary> |
| | | 50 | | /// Converts a string to an object identity. |
| | | 51 | | /// </summary> |
| | | 52 | | /// <param name="s">The string to convert.</param> |
| | | 53 | | /// <returns>The converted object identity.</returns> |
| | | 54 | | public static Identity stringToIdentity(string s) |
| | | 55 | | { |
| | 1 | 56 | | var ident = new Identity(); |
| | | 57 | | |
| | | 58 | | // |
| | | 59 | | // Find unescaped separator; note that the string may contain an escaped |
| | | 60 | | // backslash before the separator. |
| | | 61 | | // |
| | 1 | 62 | | int slash = -1, pos = 0; |
| | 1 | 63 | | while ((pos = s.IndexOf('/', pos)) != -1) |
| | | 64 | | { |
| | 1 | 65 | | int escapes = 0; |
| | 1 | 66 | | while (pos - escapes > 0 && s[pos - escapes - 1] == '\\') |
| | | 67 | | { |
| | 1 | 68 | | escapes++; |
| | | 69 | | } |
| | | 70 | | |
| | | 71 | | // |
| | | 72 | | // We ignore escaped escapes |
| | | 73 | | // |
| | 1 | 74 | | if (escapes % 2 == 0) |
| | | 75 | | { |
| | 1 | 76 | | if (slash == -1) |
| | | 77 | | { |
| | 1 | 78 | | slash = pos; |
| | | 79 | | } |
| | | 80 | | else |
| | | 81 | | { |
| | | 82 | | // |
| | | 83 | | // Extra unescaped slash found. |
| | | 84 | | // |
| | 0 | 85 | | throw new ParseException($"unescaped backslash in identity string '{s}'"); |
| | | 86 | | } |
| | | 87 | | } |
| | 1 | 88 | | pos++; |
| | | 89 | | } |
| | | 90 | | |
| | 1 | 91 | | if (slash == -1) |
| | | 92 | | { |
| | 1 | 93 | | ident.category = ""; |
| | | 94 | | try |
| | | 95 | | { |
| | 1 | 96 | | ident.name = Ice.UtilInternal.StringUtil.unescapeString(s, 0, s.Length, "/"); |
| | 1 | 97 | | } |
| | 1 | 98 | | catch (ArgumentException e) |
| | | 99 | | { |
| | 1 | 100 | | throw new ParseException($"invalid name in identity string '{s}'", e); |
| | | 101 | | } |
| | | 102 | | } |
| | | 103 | | else |
| | | 104 | | { |
| | | 105 | | try |
| | | 106 | | { |
| | 1 | 107 | | ident.category = Ice.UtilInternal.StringUtil.unescapeString(s, 0, slash, "/"); |
| | 1 | 108 | | } |
| | 0 | 109 | | catch (ArgumentException e) |
| | | 110 | | { |
| | 0 | 111 | | throw new ParseException($"invalid category in identity string '{s}'", e); |
| | | 112 | | } |
| | 1 | 113 | | if (slash + 1 < s.Length) |
| | | 114 | | { |
| | | 115 | | try |
| | | 116 | | { |
| | 1 | 117 | | ident.name = Ice.UtilInternal.StringUtil.unescapeString(s, slash + 1, s.Length, "/"); |
| | 1 | 118 | | } |
| | 0 | 119 | | catch (ArgumentException e) |
| | | 120 | | { |
| | 0 | 121 | | throw new ParseException($"invalid name in identity string '{s}'", e); |
| | | 122 | | } |
| | | 123 | | } |
| | | 124 | | else |
| | | 125 | | { |
| | 0 | 126 | | ident.name = ""; |
| | | 127 | | } |
| | | 128 | | } |
| | | 129 | | |
| | 1 | 130 | | return ident; |
| | | 131 | | } |
| | | 132 | | |
| | | 133 | | /// <summary> |
| | | 134 | | /// Converts an object identity to a string. |
| | | 135 | | /// </summary> |
| | | 136 | | /// <param name="ident">The object identity to convert.</param> |
| | | 137 | | /// <param name="toStringMode">Specifies if and how non-printable ASCII characters are escaped in the result.</param |
| | | 138 | | /// <returns>The string representation of the object identity.</returns> |
| | | 139 | | public static string identityToString(Identity ident, ToStringMode toStringMode = ToStringMode.Unicode) |
| | | 140 | | { |
| | 1 | 141 | | if (ident.category.Length == 0) |
| | | 142 | | { |
| | 1 | 143 | | return Ice.UtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); |
| | | 144 | | } |
| | | 145 | | else |
| | | 146 | | { |
| | 1 | 147 | | return Ice.UtilInternal.StringUtil.escapeString(ident.category, "/", toStringMode) + '/' + |
| | 1 | 148 | | Ice.UtilInternal.StringUtil.escapeString(ident.name, "/", toStringMode); |
| | | 149 | | } |
| | | 150 | | } |
| | | 151 | | |
| | | 152 | | /// <summary> |
| | | 153 | | /// This method is deprecated. Use System.Guid instead. |
| | | 154 | | /// </summary> |
| | | 155 | | /// <returns>A new UUID.</returns> |
| | | 156 | | [Obsolete("This method is deprecated. Use System.Guid instead.")] |
| | | 157 | | public static string generateUUID() => |
| | 0 | 158 | | Guid.NewGuid().ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture); |
| | | 159 | | |
| | | 160 | | /// <summary> |
| | | 161 | | /// Compares the object identities of two proxies. |
| | | 162 | | /// </summary> |
| | | 163 | | /// <param name="lhs">The first proxy to compare.</param> |
| | | 164 | | /// <param name="rhs">The second proxy to compare.</param> |
| | | 165 | | /// <returns>-1 if the identity in lhs compares less than the identity in rhs; 0 if the identities compare equal; |
| | | 166 | | /// 1, otherwise.</returns> |
| | | 167 | | public static int proxyIdentityCompare(ObjectPrx? lhs, ObjectPrx? rhs) |
| | | 168 | | { |
| | 1 | 169 | | if (lhs == null && rhs == null) |
| | | 170 | | { |
| | 0 | 171 | | return 0; |
| | | 172 | | } |
| | 1 | 173 | | else if (lhs == null && rhs != null) |
| | | 174 | | { |
| | 0 | 175 | | return -1; |
| | | 176 | | } |
| | 1 | 177 | | else if (lhs != null && rhs == null) |
| | | 178 | | { |
| | 0 | 179 | | return 1; |
| | | 180 | | } |
| | | 181 | | else |
| | | 182 | | { |
| | 1 | 183 | | Identity lhsIdentity = lhs!.ice_getIdentity(); |
| | 1 | 184 | | Identity rhsIdentity = rhs!.ice_getIdentity(); |
| | | 185 | | int n; |
| | 1 | 186 | | n = string.CompareOrdinal(lhsIdentity.name, rhsIdentity.name); |
| | 1 | 187 | | if (n != 0) |
| | | 188 | | { |
| | 0 | 189 | | return n; |
| | | 190 | | } |
| | 1 | 191 | | return string.CompareOrdinal(lhsIdentity.category, rhsIdentity.category); |
| | | 192 | | } |
| | | 193 | | } |
| | | 194 | | |
| | | 195 | | /// <summary> |
| | | 196 | | /// Compares the object identities and facets of two proxies. |
| | | 197 | | /// </summary> |
| | | 198 | | /// <param name="lhs">The first proxy to compare.</param> |
| | | 199 | | /// <param name="rhs">The second proxy to compare.</param> |
| | | 200 | | /// <returns>-1 if the identity and facet in lhs compare |
| | | 201 | | /// less than the identity and facet in rhs; 0 if the identities |
| | | 202 | | /// and facets compare equal; 1, otherwise.</returns> |
| | | 203 | | public static int proxyIdentityAndFacetCompare(ObjectPrx? lhs, ObjectPrx? rhs) |
| | | 204 | | { |
| | 1 | 205 | | if (lhs == null && rhs == null) |
| | | 206 | | { |
| | 0 | 207 | | return 0; |
| | | 208 | | } |
| | 1 | 209 | | else if (lhs == null && rhs != null) |
| | | 210 | | { |
| | 0 | 211 | | return -1; |
| | | 212 | | } |
| | 1 | 213 | | else if (lhs != null && rhs == null) |
| | | 214 | | { |
| | 0 | 215 | | return 1; |
| | | 216 | | } |
| | | 217 | | else |
| | | 218 | | { |
| | 1 | 219 | | Identity lhsIdentity = lhs!.ice_getIdentity(); |
| | 1 | 220 | | Identity rhsIdentity = rhs!.ice_getIdentity(); |
| | | 221 | | int n; |
| | 1 | 222 | | n = string.CompareOrdinal(lhsIdentity.name, rhsIdentity.name); |
| | 1 | 223 | | if (n != 0) |
| | | 224 | | { |
| | 1 | 225 | | return n; |
| | | 226 | | } |
| | 1 | 227 | | n = string.CompareOrdinal(lhsIdentity.category, rhsIdentity.category); |
| | 1 | 228 | | if (n != 0) |
| | | 229 | | { |
| | 0 | 230 | | return n; |
| | | 231 | | } |
| | | 232 | | |
| | 1 | 233 | | string lhsFacet = lhs.ice_getFacet(); |
| | 1 | 234 | | string rhsFacet = rhs.ice_getFacet(); |
| | 1 | 235 | | if (lhsFacet == null && rhsFacet == null) |
| | | 236 | | { |
| | 0 | 237 | | return 0; |
| | | 238 | | } |
| | 1 | 239 | | else if (lhsFacet == null) |
| | | 240 | | { |
| | 0 | 241 | | return -1; |
| | | 242 | | } |
| | 1 | 243 | | else if (rhsFacet == null) |
| | | 244 | | { |
| | 0 | 245 | | return 1; |
| | | 246 | | } |
| | | 247 | | else |
| | | 248 | | { |
| | 1 | 249 | | return string.CompareOrdinal(lhsFacet, rhsFacet); |
| | | 250 | | } |
| | | 251 | | } |
| | | 252 | | } |
| | | 253 | | |
| | | 254 | | /// <summary> |
| | | 255 | | /// Returns the process-wide logger. |
| | | 256 | | /// </summary> |
| | | 257 | | /// <returns>The process-wide logger.</returns> |
| | | 258 | | public static Logger getProcessLogger() |
| | | 259 | | { |
| | 1 | 260 | | lock (_processLoggerMutex) |
| | | 261 | | { |
| | 1 | 262 | | if (_processLogger is null) |
| | | 263 | | { |
| | 1 | 264 | | _processLogger = new ConsoleLoggerI(AppDomain.CurrentDomain.FriendlyName); |
| | 1 | 265 | | _ownProcessLogger = true; |
| | | 266 | | } |
| | 1 | 267 | | return _processLogger; |
| | | 268 | | } |
| | 1 | 269 | | } |
| | | 270 | | |
| | | 271 | | /// <summary> |
| | | 272 | | /// Changes the process-wide logger. |
| | | 273 | | /// </summary> |
| | | 274 | | /// <param name="logger">The new process-wide logger.</param> |
| | | 275 | | public static void setProcessLogger(Logger logger) |
| | | 276 | | { |
| | 0 | 277 | | lock (_processLoggerMutex) |
| | | 278 | | { |
| | 0 | 279 | | if (_ownProcessLogger) |
| | | 280 | | { |
| | 0 | 281 | | _processLogger!.Dispose(); |
| | | 282 | | } |
| | 0 | 283 | | _processLogger = logger; |
| | 0 | 284 | | _ownProcessLogger = false; |
| | 0 | 285 | | } |
| | 0 | 286 | | } |
| | | 287 | | |
| | | 288 | | /// <summary> |
| | | 289 | | /// Returns the Ice version in the form A.B.C, where A indicates the |
| | | 290 | | /// major version, B indicates the minor version, and C indicates the |
| | | 291 | | /// patch level. |
| | | 292 | | /// </summary> |
| | | 293 | | /// <returns>The Ice version.</returns> |
| | 0 | 294 | | public static string stringVersion() => "3.9.0-alpha.0"; // "A.B.C", with A=major, B=minor, C=patch |
| | | 295 | | |
| | | 296 | | /// <summary> |
| | | 297 | | /// Returns the Ice version as an integer in the form AABBCC, where AA |
| | | 298 | | /// indicates the major version, BB indicates the minor version, and CC |
| | | 299 | | /// indicates the patch level. For example, for Ice 3.9.1, the returned value is 30901. |
| | | 300 | | /// </summary> |
| | | 301 | | /// <returns>The Ice version.</returns> |
| | 1 | 302 | | public static int intVersion() => 30950; // AABBCC, with AA=major, BB=minor, CC=patch |
| | | 303 | | |
| | 1 | 304 | | public static readonly EncodingVersion Encoding_1_0 = new(1, 0); |
| | 1 | 305 | | public static readonly EncodingVersion Encoding_1_1 = new(1, 1); |
| | | 306 | | |
| | 1 | 307 | | private static readonly object _processLoggerMutex = new object(); |
| | | 308 | | private static Logger? _processLogger; |
| | | 309 | | private static bool _ownProcessLogger; |
| | | 310 | | } |