System.Uri.CreateUriInfo C# (CSharp) Method

CreateUriInfo() private method

private CreateUriInfo ( Flags cF ) : void
cF Flags
return void
        private unsafe void CreateUriInfo(Flags cF)
        {
            UriInfo info = new UriInfo();

            // This will be revisited in ParseRemaining but for now just have it at least m_String.Length
            info.Offset.End = (ushort)_string.Length;

            if (UserDrivenParsing)
                goto Done;

            ushort idx;
            bool notCanonicalScheme = false;

            // The m_String may have leading spaces, figure that out
            // plus it will set idx value for next steps
            if ((cF & Flags.ImplicitFile) != 0)
            {
                idx = (ushort)0;
                while (UriHelper.IsLWS(_string[idx]))
                {
                    ++idx;
                    ++info.Offset.Scheme;
                }

                if (StaticInFact(cF, Flags.UncPath))
                {
                    // For implicit file AND Unc only
                    idx += 2;
                    //skip any other slashes (compatibility with V1.0 parser)
                    while (idx < (ushort)(cF & Flags.IndexMask) && (_string[idx] == '/' || _string[idx] == '\\'))
                    {
                        ++idx;
                    }
                }
            }
            else
            {
                // This is NOT an ImplicitFile uri
                idx = (ushort)_syntax.SchemeName.Length;

                while (_string[idx++] != ':')
                {
                    ++info.Offset.Scheme;
                }

                if ((cF & Flags.AuthorityFound) != 0)
                {
                    if (_string[idx] == '\\' || _string[idx + 1] == '\\')
                        notCanonicalScheme = true;

                    idx += 2;
                    if ((cF & (Flags.UncPath | Flags.DosPath)) != 0)
                    {
                        // Skip slashes if it was allowed during ctor time
                        // NB: Today this is only allowed if a Unc or DosPath was found after the scheme
                        while (idx < (ushort)(cF & Flags.IndexMask) && (_string[idx] == '/' || _string[idx] == '\\'))
                        {
                            notCanonicalScheme = true;
                            ++idx;
                        }
                    }
                }
            }

            // Some schemes (mailto) do not have Authority-based syntax, still they do have a port
            if (_syntax.DefaultPort != UriParser.NoDefaultPort)
                info.Offset.PortValue = (ushort)_syntax.DefaultPort;

            //Here we set the indexes for already parsed components
            if ((cF & Flags.HostTypeMask) == Flags.UnknownHostType
                || StaticInFact(cF, Flags.DosPath)
                )
            {
                //there is no Authority component defined
                info.Offset.User = (ushort)(cF & Flags.IndexMask);
                info.Offset.Host = info.Offset.User;
                info.Offset.Path = info.Offset.User;
                cF &= ~Flags.IndexMask;
                if (notCanonicalScheme)
                {
                    cF |= Flags.SchemeNotCanonical;
                }
                goto Done;
            }

            info.Offset.User = idx;

            //Basic Host Type does not have userinfo and port
            if (HostType == Flags.BasicHostType)
            {
                info.Offset.Host = idx;
                info.Offset.Path = (ushort)(cF & Flags.IndexMask);
                cF &= ~Flags.IndexMask;
                goto Done;
            }

            if ((cF & Flags.HasUserInfo) != 0)
            {
                // we previously found a userinfo, get it again
                while (_string[idx] != '@')
                {
                    ++idx;
                }
                ++idx;
                info.Offset.Host = idx;
            }
            else
            {
                info.Offset.Host = idx;
            }

            //Now reload the end of the parsed host

            idx = (ushort)(cF & Flags.IndexMask);

            //From now on we do not need IndexMask bits, and reuse the space for X_NotCanonical flags
            //clear them now
            cF &= ~Flags.IndexMask;

            // If this is not canonical, don't count on user input to be good
            if (notCanonicalScheme)
            {
                cF |= Flags.SchemeNotCanonical;
            }

            //Guessing this is a path start
            info.Offset.Path = idx;

            // parse Port if any. The new spec allows a port after ':' to be empty (assuming default?)
            bool notEmpty = false;
            // Note we already checked on general port syntax in ParseMinimal()

            // If iri parsing is on with unicode chars then the end of parsed host
            // points to m_orig string and not m_String

            bool UseOrigUnicodeStrOffset = ((cF & Flags.UseOrigUncdStrOffset) != 0);
            // This should happen only once. Reset it
            cF &= ~Flags.UseOrigUncdStrOffset;

            if (UseOrigUnicodeStrOffset)
                info.Offset.End = (ushort)_originalUnicodeString.Length;

            if (idx < info.Offset.End)
            {
                fixed (char* userString = UseOrigUnicodeStrOffset ? _originalUnicodeString : _string)
                {
                    if (userString[idx] == ':')
                    {
                        int port = 0;

                        //Check on some non-canonical cases http://host:0324/, http://host:03, http://host:0, etc
                        if (++idx < info.Offset.End)
                        {
                            port = (ushort)(userString[idx] - '0');
                            if (!(port == unchecked((ushort)('/' - '0')) || port == (ushort)('?' - '0') ||
                                port == unchecked((ushort)('#' - '0'))))
                            {
                                notEmpty = true;
                                if (port == 0)
                                {
                                    cF |= (Flags.PortNotCanonical | Flags.E_PortNotCanonical);
                                }
                                for (++idx; idx < info.Offset.End; ++idx)
                                {
                                    ushort val = (ushort)((ushort)userString[idx] - (ushort)'0');
                                    if (val == unchecked((ushort)('/' - '0')) || val == (ushort)('?' - '0') ||
                                        val == unchecked((ushort)('#' - '0')))
                                    {
                                        break;
                                    }
                                    port = (port * 10 + val);
                                }
                            }
                        }
                        if (notEmpty && info.Offset.PortValue != (ushort)port)
                        {
                            info.Offset.PortValue = (ushort)port;
                            cF |= Flags.NotDefaultPort;
                        }
                        else
                        {
                            //This will tell that we do have a ':' but the port value does
                            //not follow to canonical rules
                            cF |= (Flags.PortNotCanonical | Flags.E_PortNotCanonical);
                        }
                        info.Offset.Path = (ushort)idx;
                    }
                }
            }

        Done:
            cF |= Flags.MinimalUriInfoSet;
            info.DnsSafeHost = _dnsSafeHost;
            lock (_string)
            {
                if ((_flags & Flags.MinimalUriInfoSet) == 0)
                {
                    _info = info;
                    _flags = (_flags & ~Flags.IndexMask) | cF;
                }
            }
        }