public Endpoint ReadEndpoint(InputStream istr)
        {
            lock (this)
            {
                var type = (EndpointType)istr.ReadShort();

                IEndpointFactory?factory = GetEndpointFactory(type);
                Endpoint?        e       = null;

                (Encoding encoding, int size) = istr.StartEndpointEncapsulation();
                if (factory != null)
                {
                    e = factory.Read(istr);
                }

                // If the factory failed to read the endpoint, return an opaque endpoint. This can
                // occur if for example the factory delegates to another factory and this factory
                // isn't available. In this case, the factory needs to make sure the stream position
                // is preserved for reading the opaque endpoint.
                if (e == null)
                {
                    byte[] data = new byte[size];
                    size = istr.ReadSpan(data);
                    if (size < data.Length)
                    {
                        throw new InvalidDataException(@$ "not enough bytes available reading opaque endpoint, requested {
                            data.Length} bytes, but there was only {size} bytes remaining");
                    }
                    e = new OpaqueEndpoint(type, encoding, data);
                }
                istr.EndEndpointEncapsulation();

                return(e);
            }
        public Endpoint?CreateEndpoint(string endpointString, bool oaEndpoint)
        {
            string[]? args = IceUtilInternal.StringUtil.SplitString(endpointString, " \t\r\n");
            if (args == null)
            {
                throw new FormatException($"mismatched quote in endpoint `{endpointString}'");
            }

            if (args.Length == 0)
            {
                throw new FormatException("no non-whitespace character in endpoint string");
            }

            string transport = args[0];

            if (transport == "default")
            {
                transport = DefaultTransport;
            }

            var options = new Dictionary <string, string?>();

            // Parse args into options (and skip transport at args[0])
            for (int n = 1; n < args.Length; ++n)
            {
                // Any option with < 2 characters or that does not start with - is illegal
                string option = args[n];
                if (option.Length < 2 || option[0] != '-')
                {
                    throw new FormatException($"invalid option `{option}' in endpoint `{endpointString}'");
                }

                // Extract the argument given to the current option, if any
                string?argument = null;
                if (n + 1 < args.Length && args[n + 1][0] != '-')
                {
                    argument = args[++n];
                }

                try
                {
                    options.Add(option, argument);
                }
                catch (ArgumentException)
                {
                    throw new FormatException($"duplicate option `{option}' in endpoint `{endpointString}'");
                }
            }

            IEndpointFactory?factory = null;

            lock (this)
            {
                for (int i = 0; i < _endpointFactories.Count; i++)
                {
                    IEndpointFactory f = _endpointFactories[i];
                    if (f.Transport() == transport)
                    {
                        factory = f;
                    }
                }
            }

            if (factory != null)
            {
                Endpoint?e = factory.Create(endpointString, options, oaEndpoint);
                if (options.Count > 0)
                {
                    throw new FormatException(
                              $"unrecognized option(s) `{ToString(options)}' in endpoint `{endpointString}'");
                }
                return(e);
            }

            //
            // If the stringified endpoint is opaque, create an unknown endpoint,
            // then see whether the type matches one of the known endpoints.
            //
            if (transport == "opaque")
            {
                Endpoint ue = new OpaqueEndpoint(endpointString, options);
                if (options.Count > 0)
                {
                    throw new FormatException(
                              $"unrecognized option(s) `{ToString(options)}' in endpoint `{endpointString}'");
                }
                factory = GetEndpointFactory(ue.Type);
                if (factory != null)
                {
                    //
                    // Make a temporary stream, write the opaque endpoint data into the stream,
                    // and ask the factory to read the endpoint data from that stream to create
                    // the actual endpoint.
                    //
                    var ostr = new OutputStream(Ice1Definitions.Encoding, new List <ArraySegment <byte> >());
                    ostr.WriteShort((short)ue.Type);
                    ue.IceWrite(ostr);
                    // TODO avoid copy OutputStream buffers
                    var iss = new InputStream(this, ostr.ToArray());
                    iss.Pos = 0;
                    iss.ReadShort(); // type
                    iss.StartEndpointEncapsulation();
                    Endpoint?e = factory.Read(iss);
                    iss.EndEndpointEncapsulation();
                    return(e);
                }
                return(ue); // Endpoint is opaque, but we don't have a factory for its type.
            }

            return(null);
        }
        public Endpoint?CreateEndpoint(string endpointString, bool oaEndpoint)
        {
            string[]? args = IceUtilInternal.StringUtil.SplitString(endpointString, " \t\r\n");
            if (args == null)
            {
                throw new FormatException($"mismatched quote in endpoint `{endpointString}'");
            }

            if (args.Length == 0)
            {
                throw new FormatException("no non-whitespace character in endpoint string");
            }

            string transport = args[0];

            if (transport == "default")
            {
                transport = DefaultTransport;
            }

            var options = new Dictionary <string, string?>();

            // Parse args into options (and skip transport at args[0])
            for (int n = 1; n < args.Length; ++n)
            {
                // Any option with < 2 characters or that does not start with - is illegal
                string option = args[n];
                if (option.Length < 2 || option[0] != '-')
                {
                    throw new FormatException($"invalid option `{option}' in endpoint `{endpointString}'");
                }

                // Extract the argument given to the current option, if any
                string?argument = null;
                if (n + 1 < args.Length && args[n + 1][0] != '-')
                {
                    argument = args[++n];
                }

                try
                {
                    options.Add(option, argument);
                }
                catch (ArgumentException)
                {
                    throw new FormatException($"duplicate option `{option}' in endpoint `{endpointString}'");
                }
            }

            IEndpointFactory?factory = null;

            lock (this)
            {
                for (int i = 0; i < _endpointFactories.Count; i++)
                {
                    IEndpointFactory f = _endpointFactories[i];
                    if (f.Transport() == transport)
                    {
                        factory = f;
                    }
                }
            }

            if (factory != null)
            {
                Endpoint endpoint = factory.Create(endpointString, options, oaEndpoint);
                if (options.Count > 0)
                {
                    throw new FormatException(
                              $"unrecognized option(s) `{ToString(options)}' in endpoint `{endpointString}'");
                }
                return(endpoint);
            }

            //
            // If the stringified endpoint is opaque, create an unknown endpoint,
            // then see whether the type matches one of the known endpoints.
            //
            if (transport == "opaque")
            {
                var opaqueEndpoint = new OpaqueEndpoint(endpointString, options);
                if (options.Count > 0)
                {
                    throw new FormatException(
                              $"unrecognized option(s) `{ToString(options)}' in endpoint `{endpointString}'");
                }

                if (opaqueEndpoint.Encoding.IsSupported && GetEndpointFactory(opaqueEndpoint.Type) != null)
                {
                    // We may be able to unmarshal this endpoint, so we first marshal it into a byte buffer and then
                    // unmarshal it from this buffer.
                    var bufferList = new List <ArraySegment <byte> >
                    {
                        // 8 = size of short + size of encapsulation header
                        new byte[8 + opaqueEndpoint.Bytes.Length]
                    };

                    var ostr = new OutputStream(Ice1Definitions.Encoding, bufferList);
                    ostr.WriteEndpoint(opaqueEndpoint);
                    OutputStream.Position tail = ostr.Save();
                    Debug.Assert(bufferList.Count == 1);
                    Debug.Assert(tail.Segment == 0 && tail.Offset == 8 + opaqueEndpoint.Bytes.Length);

                    return(new InputStream(this, bufferList[0]).ReadEndpoint());
                }
                else
                {
                    return(opaqueEndpoint);
                }
            }

            return(null);
        }