URI.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Net / System / URI.cs / 1 / URI.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System { 
    using System.Configuration; 
    using System.Runtime.InteropServices;
    using System.Text; 
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.ComponentModel;
    using System.Security.Permissions; 
    using System.Threading;
    using Microsoft.Win32; 
    using System.Security; 
    using System.Net;
    using System.IO; 
    using System.Xml;
    [Serializable]
    [TypeConverter(typeof(UriTypeConverter))]
    public partial class Uri : ISerializable { 

        public static readonly string UriSchemeFile = UriParser.FileUri.SchemeName; 
        public static readonly string UriSchemeFtp = UriParser.FtpUri.SchemeName; 
        public static readonly string UriSchemeGopher = UriParser.GopherUri.SchemeName;
        public static readonly string UriSchemeHttp = UriParser.HttpUri.SchemeName; 
        public static readonly string UriSchemeHttps = UriParser.HttpsUri.SchemeName;
        public static readonly string UriSchemeMailto = UriParser.MailToUri.SchemeName;
        public static readonly string UriSchemeNews = UriParser.NewsUri.SchemeName;
        public static readonly string UriSchemeNntp = UriParser.NntpUri.SchemeName; 
        public static readonly string UriSchemeNetTcp = UriParser.NetTcpUri.SchemeName;
        public static readonly string UriSchemeNetPipe = UriParser.NetPipeUri.SchemeName; 
        public static readonly string SchemeDelimiter = "://"; 

 
        private const int c_Max16BitUtf8SequenceLength = 3+3+3+3; //each unicode byte takes 3 escaped chars
        private const int c_MaxUriBufferSize = 0xFFF0;
        private const int c_MaxUriSchemeName = 1024;
 
        // untouched user string unless string has unicode chars and iriparsing is enabled
        // or idn is on and we have unicode host or idn host 
        // In that case, this string is normalized, stripped of bidi chars, and validated 
        // with char limits
        private string      m_String; 

        // untouched user string if string has unicode with iri on or unicode/idn host with idn on
        private string      m_originalUnicodeString;
 
        private UriParser m_Syntax;   // This is a whole Uri syntax, not only the scheme name
        // temporarily stores dnssafe host when we have unicode/idn host and idn is on 
        private string m_DnsSafeHost = null; 

        private enum ParsingError { 
            // looks good
            None            = 0,

            // Could be only Relative 
            BadFormat           = 1,
            BadScheme           = 2, 
            BadAuthority        = 3, 
            EmptyUriString      = 4,
            LastRelativeUriOkErrIndex   = 4, 

            // Fatal
            SchemeLimit         = 5,
            SizeLimit           = 6, 
            MustRootedPath      = 7,
            LastFatalErrIndex           = 7, 
 
            // derived class controlled
            BadHostName         = 8, 
            NonEmptyHost        = 9,    //unix only
            BadPort             = 10,
            BadAuthorityTerminator=11,
 
            CannotCreateRelative = 12
        } 
 
        [Flags]
        private enum Flags : ulong { 
            Zero                = 0x00000000,

            SchemeNotCanonical     = 0x1,
            UserNotCanonical       = 0x2, 
            HostNotCanonical       = 0x4,
            PortNotCanonical       = 0x8, 
            PathNotCanonical       = 0x10, 
            QueryNotCanonical      = 0x20,
            FragmentNotCanonical   = 0x40, 
            CannotDisplayCanonical = 0x7F,

            E_UserNotCanonical      = 0x80,
            E_HostNotCanonical      = 0x100, 
            E_PortNotCanonical      = 0x200,
            E_PathNotCanonical      = 0x400, 
            E_QueryNotCanonical     = 0x800, 
            E_FragmentNotCanonical  = 0x1000,
            E_CannotDisplayCanonical = 0x1F80, 


            ShouldBeCompressed      = 0x2000,
            FirstSlashAbsent        = 0x4000, 
            BackslashInPath         = 0x8000,
 
            IndexMask           = 0x0000FFFF, 
            HostTypeMask        = 0x00070000,
            HostNotParsed   = 0x00000000, 
            IPv6HostType    = 0x00010000,
            IPv4HostType    = 0x00020000,
            DnsHostType     = 0x00030000,
#if !PLATFORM_UNIX 
            UncHostType     = 0x00040000,
#endif // !PLATFORM_UNIX 
            BasicHostType   = 0x00050000, 
            UnusedHostType  = 0x00060000,
            UnknownHostType = 0x00070000, 

            UserEscaped         = 0x00080000,
            AuthorityFound      = 0x00100000,
            HasUserInfo         = 0x00200000, 
            LoopbackHost        = 0x00400000,
            NotDefaultPort      = 0x00800000, 
 
            UserDrivenParsing   = 0x01000000,
            CanonicalDnsHost    = 0x02000000, 
            ErrorOrParsingRecursion = 0x04000000,   // Used to signal a default parser error and alsoe to confirm Port and Host values in case of a custom user Parser
#if !PLATFORM_UNIX
            DosPath             = 0x08000000,
            UncPath             = 0x10000000, 
#endif // !PLATFORM_UNIX
            ImplicitFile        = 0x20000000, 
            MinimalUriInfoSet   = 0x40000000, 
            AllUriInfoSet       = unchecked(0x80000000),
            IdnHost             = 0x100000000, 
            HasUnicode          = 0x200000000,
            HostUnicodeNormalized = 0x400000000,
            RestUnicodeNormalized = 0x800000000,
            UnicodeHost         = 0x1000000000, 
            IntranetUri         = 0x2000000000,
            UseOrigUncdStrOffset= 0x4000000000, 
            // Is this component Iri canonical 
            UserIriCanonical =          0x8000000000,
            PathIriCanonical =          0x10000000000, 
            QueryIriCanonical =         0x20000000000,
            FragmentIriCanonical =      0x40000000000,
            IriCanonical =              0x78000000000,
        } 

        private Flags       m_Flags; 
        private UriInfo     m_Info; 

        private class UriInfo { 
            public string   Host;
            public string   ScopeId;        //only IP v6 may need this
            public string   String;
            public Offset   Offset; 
            public string   DnsSafeHost;    // stores dns safe host when idn is on and we have unicode or idn host
            public MoreInfo MoreInfo;       //Multi-threading: This field must be always accessed through a _local_ stack copy of m_Info. 
        }; 

        [StructLayout(LayoutKind.Sequential, Pack=1)] 
        private struct Offset {
            public ushort  Scheme;
            public ushort  User;
            public ushort  Host; 
            public ushort  PortValue;
            public ushort  Path; 
            public ushort  Query; 
            public ushort  Fragment;
            public ushort  End; 
        };

        private class MoreInfo {
            public string   Path; 
            public string   Query;
            public string   Fragment; 
            public string   AbsoluteUri; 
            public int      Hash;
            public string   RemoteUrl; 
        };

        private bool IsImplicitFile {
            get {return (m_Flags & Flags.ImplicitFile) != 0;} 
        }
 
        private bool IsUncOrDosPath { 
#if !PLATFORM_UNIX
            get {return (m_Flags & (Flags.UncPath|Flags.DosPath)) != 0;} 
#else
            get {return false;}
#endif // !PLATFORM_UNIX
        } 

        private bool IsDosPath { 
#if !PLATFORM_UNIX 
            get {return (m_Flags & Flags.DosPath) != 0;}
#else 
            get {return false;}
#endif // !PLATFORM_UNIX
        }
 
        private bool IsUncPath {
#if !PLATFORM_UNIX 
            get {return (m_Flags & Flags.UncPath) != 0;} 
#else
            get {return false;} 
#endif // !PLATFORM_UNIX
        }

        private Flags HostType { 
            get {return m_Flags & Flags.HostTypeMask;}
        } 
 
        private UriParser Syntax {
            get { 
                return m_Syntax;
            }
        }
 
        private bool IsNotAbsoluteUri {
            get {return (object) m_Syntax == null;} 
        } 

        // 
        // Checks if Iri parsing is allowed by the syntax & by config
        //
        private bool m_iriParsing;
 
        //
        // Statically checks if Iri parsing is allowed by the syntax & by config 
        // 
        private static bool IriParsingStatic( UriParser syntax )
        { 
            return (s_IriParsing && (((syntax != null) && syntax.InFact(UriSyntaxFlags.AllowIriParsing)) ||
                   (syntax == null)));
        }
 
        //
        // Checks if Idn is allowed by the syntax & by config 
        // 
        private bool AllowIdn
        { 
            get { return    ((m_Syntax != null) && ((m_Syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) &&
                            ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet)
                                                                                && NotAny(Flags.IntranetUri)))); }
        } 

        // 
        // Checks statically if Idn is allowed by the syntax & by config 
        //
        private bool AllowIdnStatic(UriParser syntax, Flags flags) 
        {
            return ((syntax != null) && ((syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) &&
                   ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet)
                                                                            && StaticNotAny(flags, Flags.IntranetUri)))); 
        }
 
        // 
        // check if the scheme + host are in intranet or not
        // Used to determine of we apply idn or not 
        //
        private static IInternetSecurityManager s_ManagerRef = null;
        private static object s_IntranetLock = new object();
 
        private bool IsIntranet(string schemeHost)
        { 
            bool error = false; 
            int zone = -1;
            int E_FAIL = unchecked((int)0x80004005); 

            // MapUrlToZone call below fails on scheme length > 32 so we consider this
            // not be be intranet
            // 
            if (m_Syntax.SchemeName.Length > 32)
                return false; 
 
            if (s_ManagerRef == null){
                lock (s_IntranetLock){ 
                    if(s_ManagerRef == null)
                        s_ManagerRef = (IInternetSecurityManager)new InternetSecurityManager();
                }
            } 

            try{ 
                s_ManagerRef.MapUrlToZone(schemeHost.TrimStart(_WSchars), out zone, 0); 
            }
            catch (COMException ex){ 
                if (ex.ErrorCode == E_FAIL){    // E_FAIL
                    error = true;
                }
            } 

            if(zone == (int) SecurityZone.Intranet) 
                return true; 

            // Do dot check for intranet if zone is trusted or untrusted 
            // since an intranet zone may be in these zones as well
            if ((zone == (int)SecurityZone.Trusted) ||
                (zone == (int)SecurityZone.Untrusted) || error)
            { 
                // do dot check
                for (int i = 0; i < schemeHost.Length; ++i) 
                { 
                    if (schemeHost[i] == '.')
                        return false; 
                }
                return true;
            }
            return false; 
        }
 
        internal bool UserDrivenParsing 
        {
            get { 
                return (m_Flags & Flags.UserDrivenParsing) != 0;
            }
        }
        private void SetUserDrivenParsing() 
        {
            // we use = here to clear all parsing flags for a uri that we think is invalid. 
            m_Flags = Flags.UserDrivenParsing | (m_Flags & Flags.UserEscaped); 
        }
 
        private ushort SecuredPathIndex {
            get {
                // This is one more trouble with a Dos Path.
                // This property gets "safe" first path slash that is not the first if path = c:\ 
                if (IsDosPath) {
                    char ch = m_String[m_Info.Offset.Path]; 
                    return (ushort)((ch == '/' || ch == '\\')? 3 :2); 
                }
                return (ushort)0; 
            }
        }

        private bool NotAny(Flags flags) { 
            return (m_Flags & flags) == 0;
        } 
 
        private bool InFact(Flags flags) {
            return (m_Flags & flags) != 0; 
        }

        private static bool StaticNotAny(Flags allFlags, Flags checkFlags) {
            return (allFlags & checkFlags) == 0; 
        }
 
        private static bool StaticInFact(Flags allFlags, Flags checkFlags) { 
            return (allFlags & checkFlags) != 0;
        } 

        //
        //
        private UriInfo EnsureUriInfo() { 
            Flags cF = m_Flags;
            if ((m_Flags & Flags.MinimalUriInfoSet) == 0) { 
                CreateUriInfo(cF); 
            }
            return m_Info; 
        }
        //
        //
        private void EnsureParseRemaining() { 
            if ((m_Flags & Flags.AllUriInfoSet) == 0) {
                ParseRemaining(); 
            } 
        }
        // 
        //
        private void EnsureHostString(bool allowDnsOptimization) {
            EnsureUriInfo();
            if ((object)m_Info.Host == null) { 
                if (allowDnsOptimization && InFact(Flags.CanonicalDnsHost)) {
                    /* Optimization for a canonical DNS name 
                    *  ATTN: the host string won't be created, 
                    *  Hence ALL m_Info.Host callers first call EnsureHostString(false)
                    *  For example IsLoopBack property is one of such callers. 
                    */
                    return;
                }
                CreateHostString(); 
            }
        } 
 
        //
        // Uri(string) 
        //
        //  We expect to create a Uri from a display name - e.g. that was typed by
        //  a user, or that was copied & pasted from a document. That is, we do not
        //  expect already encoded URI to be supplied. 
        //
        public Uri(string uriString){ 
            if ((object)uriString == null) 
                throw new ArgumentNullException("uriString");
 
            CreateThis(uriString, false, UriKind.Absolute);
        }

 
        //
        // Uri(string, bool) 
        // 
        //  Uri constructor. Assumes that input string is canonically escaped
        // 
        [Obsolete("The constructor has been deprecated. Please use new Uri(string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")]
        public Uri(string uriString, bool dontEscape) {
            if ((object)uriString == null)
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, dontEscape, UriKind.Absolute); 
        } 

 
        //
        // Uri(string, UriKind);
        //
        public Uri(string uriString, UriKind uriKind) 
        {
            if ((object)uriString == null) 
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, false, uriKind); 
        }


        // 
        // Uri(Uri, string)
        // 
        //  Construct a new Uri from a base and relative URI. The relative URI may 
        //  also be an absolute URI, in which case the resultant URI is constructed
        //  entirely from it 
        //
        public Uri(Uri baseUri, string relativeUri){
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri"); 

            if (!baseUri.IsAbsoluteUri) 
                throw new ArgumentOutOfRangeException("baseUri"); 

            CreateUri(baseUri, relativeUri, false); 
        }

        //
        // Uri(Uri, string, bool) 
        //
        //  Uri combinatorial constructor. Do not perform character escaping if 
        //  DontEscape is true 
        //
        [Obsolete("The constructor has been deprecated. Please new Uri(Uri, string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")] 
        public Uri(Uri baseUri, string relativeUri, bool dontEscape){
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri");
 
            if (!baseUri.IsAbsoluteUri)
                throw new ArgumentOutOfRangeException("baseUri"); 
 
            CreateUri(baseUri, relativeUri, dontEscape);
        } 

        private void CreateUri(Uri baseUri, string relativeUri, bool dontEscape)
        {
            // Parse relativeUri and populate Uri internal data. 
            CreateThis(relativeUri, dontEscape, UriKind.RelativeOrAbsolute);
 
            UriFormatException e; 
            if (baseUri.Syntax.IsSimple)
            { 
                // Resolve Uris if possible OR get merged Uri String to re-parse below
                Uri uriResult = ResolveHelper(baseUri, this, ref relativeUri, ref dontEscape, out e);

                if (e != null) 
                    throw e;
 
                // If resolved into a Uri then we build from that Uri 
                if (uriResult != null)
                { 
                    if ((object)uriResult != (object)this)
                        CreateThisFromUri(uriResult);

                    return; 
                }
            } 
            else 
            {
                dontEscape = false; 
                relativeUri = baseUri.Syntax.InternalResolve(baseUri, this, out e);
                if (e != null)
                    throw e;
            } 

            m_Flags = Flags.Zero; 
            m_Info = null; 
            m_Syntax = null;
            // If not resolved, we reparse modified Uri string and populate Uri internal data. 
            CreateThis(relativeUri, dontEscape, UriKind.Absolute);
        }

        // 
        // Uri(Uri , Uri )
        // Note: a static Create() method should be used by users, not this .ctor 
        // 
        public Uri(Uri baseUri, Uri relativeUri)
        { 
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri");

            if (!baseUri.IsAbsoluteUri) 
                throw new ArgumentOutOfRangeException("baseUri");
 
            CreateThisFromUri(relativeUri); 

            string newUriString = null; 
            UriFormatException e;
            bool dontEscape;

            if (baseUri.Syntax.IsSimple) 
            {
                dontEscape = InFact(Flags.UserEscaped); 
                relativeUri = ResolveHelper(baseUri, this, ref newUriString, ref dontEscape, out e); 

                if (e != null) 
                    throw e;

                if (relativeUri != null)
                { 
                    if ((object)relativeUri != (object)this)
                        CreateThisFromUri(relativeUri); 
 
                    return;
                } 
            }
            else
            {
                dontEscape = false; 
                newUriString = baseUri.Syntax.InternalResolve(baseUri, this, out e);
                if (e != null) 
                    throw e; 
            }
 
            m_Flags = Flags.Zero;
            m_Info = null;
            m_Syntax = null;
            CreateThis(newUriString, dontEscape, UriKind.Absolute); 
        }
 
        // 
        // ISerializable constructor
        // 
        protected Uri(SerializationInfo serializationInfo, StreamingContext streamingContext)
        {
            string uriString = serializationInfo.GetString("AbsoluteUri");
 
            if (uriString.Length != 0)
            { 
                CreateThis(uriString, false, UriKind.Absolute); 
                return;
            } 

            uriString = serializationInfo.GetString("RelativeUri");
            if ((object)uriString == null)
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, false, UriKind.Relative); 
        } 
        //
        // This method is shared by base+relative Uris constructors and is only called from them. 
        // The assumptions:
        //  - baseUri is a valid absolute Uri
        //  - relative part is not null and not empty
        private unsafe static ParsingError GetCombinedString(Uri baseUri, string relativeStr, bool dontEscape, ref string result) 
        {
            // NB: This is not RFC2396 compliant although it is inline with w3c.org recommendations 
            // This parser will allow the relativeStr to be an absolute Uri with the different scheme 
            // In fact this is strict violation of RFC2396
            // 
            for (int i=0; i < relativeStr.Length; ++i)
            {
                if (relativeStr[i] == '/' || relativeStr[i] == '\\' || relativeStr[i] == '?' || relativeStr[i] == '#')
                { 
                    break;
                } 
                else if (relativeStr[i] == ':') 
                {
                    if (i < 2) 
                    {
                        // Note we don't support one-letter Uri schemes.
                        // Hence anything like x:sdsd is a relative path and be added to the baseUri Path
                        break; 
                    }
                    string scheme =  relativeStr.Substring(0, i); 
                    fixed (char* sptr = scheme) { 
                        UriParser syntax = null;
                        if (CheckSchemeSyntax(sptr, (ushort) scheme.Length, ref syntax) == ParsingError.None) { 
                            if (baseUri.Syntax == syntax) {
                                //Remove the scheme for backward Uri parsers compatibility
                                if (i+1 < relativeStr.Length) {
                                    relativeStr = relativeStr.Substring(i+1); 
                                }
                                else { 
                                    relativeStr = string.Empty; 
                                }
                            } 
                            else {
                                // This is the place where we switch the scheme.
                                // Return relative part as the result Uri.
                                result = relativeStr; 
                                return ParsingError.None;
                            } 
                        } 
                    }
                    break; 
                }
            }

            if (relativeStr.Length == 0) { 
                result = baseUri.OriginalString;
                return ParsingError.None; 
            } 

            result = CombineUri(baseUri, relativeStr, dontEscape? UriFormat.UriEscaped: UriFormat.SafeUnescaped); 
            return ParsingError.None;
        }
        //
        private static UriFormatException GetException(ParsingError err) 
        {
            switch (err) 
            { 
                case ParsingError.None:
                    return null; 
                // Could be OK for Relative Uri
                case ParsingError.BadFormat:
                    return System.Net.ExceptionHelper.BadFormatException;
                case ParsingError.BadScheme: 
                    return System.Net.ExceptionHelper.BadSchemeException;
                case ParsingError.BadAuthority: 
                    return System.Net.ExceptionHelper.BadAuthorityException; 
                case ParsingError.EmptyUriString:
                    return System.Net.ExceptionHelper.EmptyUriException; 
                // Fatal
                case ParsingError.SchemeLimit:
                    return System.Net.ExceptionHelper.SchemeLimitException;
                case ParsingError.SizeLimit: 
                    return System.Net.ExceptionHelper.SizeLimitException;
                case ParsingError.MustRootedPath: 
                    return System.Net.ExceptionHelper.MustRootedPathException; 
                // Derived class controllable
                case ParsingError.BadHostName: 
                    return System.Net.ExceptionHelper.BadHostNameException;
                case ParsingError.NonEmptyHost:
                    return System.Net.ExceptionHelper.BadFormatException;   //unix-only
                case ParsingError.BadPort: 
                    return System.Net.ExceptionHelper.BadPortException;
                case ParsingError.BadAuthorityTerminator: 
                    return System.Net.ExceptionHelper.BadAuthorityTerminatorException; 
                case ParsingError.CannotCreateRelative:
                    return System.Net.ExceptionHelper.CannotCreateRelativeException; 
                default:
                    break;
            }
            return System.Net.ExceptionHelper.BadFormatException; 
        }
        // 
        // ISerializable method 
        //
        ///  
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
        void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        {
            GetObjectData(serializationInfo, streamingContext); 
        }
 
        // 
        // FxCop: provide some way for derived classes to access GetObjectData even if the derived class
        // explicitly re-inherits ISerializable. 
        //
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
        protected void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 

            if (IsAbsoluteUri) 
                serializationInfo.AddValue("AbsoluteUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); 
            else
            { 
                serializationInfo.AddValue("AbsoluteUri", string.Empty);
                serializationInfo.AddValue("RelativeUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped));
            }
        } 

        // 
        // 
        //
        public string AbsolutePath { 
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                string path = PrivateAbsolutePath; 
                // 
                //
 

                if (IsDosPath && path[0] == '/') {
                    path =  path.Substring(1);
                } 
                return path;
            } 
        } 
        //
        private string PrivateAbsolutePath { 
            get {
                UriInfo info = EnsureUriInfo();
                if ((object) info.MoreInfo == null) {
                    info.MoreInfo = new MoreInfo(); 
                }
                string result = info.MoreInfo.Path; 
                if ((object) result == null) { 
                    result = GetParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
                    info.MoreInfo.Path = result; 
                }
                return result;
            }
        } 
        //
        // 
        // 
        public string AbsoluteUri {
            get { 
                if (m_Syntax == null){
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }
 
                UriInfo info = EnsureUriInfo();
                if ((object) info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo(); 
                }
                string result = info.MoreInfo.AbsoluteUri; 
                if ((object) result == null) {
                    result = GetParts(UriComponents.AbsoluteUri, UriFormat.UriEscaped);
                    info.MoreInfo.AbsoluteUri = result;
                } 
                return result;
            } 
        } 
        //
        // 
        // The result is of the form "hostname[:port]" Port is omitted if default
        //
        public string Authority {
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                } 

                // 
                return GetParts(UriComponents.Host | UriComponents.Port, UriFormat.UriEscaped);
            }
        }
        // 
        //
        //Gets a hostname part (special formatting for IPv6 form) 
        public string Host { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }

                return GetParts(UriComponents.Host, UriFormat.UriEscaped); 
            }
        } 
        // 
        //
        public UriHostNameType HostNameType { 
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (m_Syntax.IsSimple) 
                    EnsureUriInfo(); 
                else
                { 
                    // For a custom parser we request HostString creation to confirm HostType
                    EnsureHostString(false);
                }
 
                switch (HostType) {
                    case Flags.DnsHostType:   return UriHostNameType.Dns; 
                    case Flags.IPv4HostType:  return UriHostNameType.IPv4; 
                    case Flags.IPv6HostType:  return UriHostNameType.IPv6;
                    case Flags.BasicHostType: return UriHostNameType.Basic; 
#if !PLATFORM_UNIX
                    case Flags.UncHostType:   return UriHostNameType.Basic; //return (UriHostNameType)(UriHostNameType.Basic+10);
#endif // !PLATFORM_UNIX
                    case Flags.UnknownHostType: return UriHostNameType.Unknown; 
                    default:
                        break; 
                } 
                return UriHostNameType.Unknown;
            } 
        }
        //
        //
        public bool IsDefaultPort { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
                if (m_Syntax.IsSimple) 
                    EnsureUriInfo();
                else
                {
                    // For a custom parser we request HostString creation that will aso set the port 
                    EnsureHostString(false);
                } 
 
                return NotAny(Flags.NotDefaultPort);
            } 
        }
        //
        //
        public bool IsFile { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                return (object)m_Syntax.SchemeName == (object)UriSchemeFile;
            }
        }
        private static bool StaticIsFile(UriParser syntax) 
        {
            return syntax.InFact(UriSyntaxFlags.FileLikeUri); 
        } 
        //
        // 
        public bool IsLoopback {
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                EnsureHostString(false); 

                return InFact(Flags.LoopbackHost); 
            }
        }
        //
        // 
        public bool IsUnc {
            get { 
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
                return IsUncPath;
            }
        }
        // 
        // LocalPath
        // 
        //  Returns a 'local' version of the path. This is mainly for file: URI 
        //  such that DOS and UNC paths are returned with '/' converted back to
        //  '\', and any escape sequences converted 
        //
        //  The form of the returned path is in NOT Escaped
        //
        public string LocalPath { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
                return GetLocalPath(); 
            }
        }

        private static bool s_ConfigInitialized;                                     // Have the config values been 
                                                                                    // initalized from config file
        private static UriIdnScope s_IdnScope = UriIdnScope.None;                   // Value from config Uri section 
        private static bool s_IriParsing = false;                                   // Value from config Uri section 
        private static object s_initLock;
 
        internal static object InitializeLock {
            get {
                if (s_initLock == null) {
                    object o = new object(); 
                    Interlocked.CompareExchange(ref s_initLock, o, null);
                } 
                return s_initLock; 
            }
        } 

        //
        // Reads values from config uri section
        // 
        private static void InitializeUriConfig()
        { 
            if (!s_ConfigInitialized) { 
                lock(InitializeLock) {
                    if (!s_ConfigInitialized) { 

                        // Set this first to avoid possible recursion
                        // if GetConfig's callees use Uri methods.
                        s_ConfigInitialized = true; 

                        GetConfig(ref s_IdnScope, ref s_IriParsing); 
 
                    }
                } 
            }
        }

        // internal IDN config state with additional Invalid & NotFound states 
        private enum IdnScopeFromConfig {
            None = 0, 
            AllExceptIntranet, 
            All,
            Invalid = Int32.MaxValue - 1, 
            NotFound = Int32.MaxValue
        }

        // internal IRI config state with additional Invalid & NotFound states 
        private enum IriParsingFromConfig {
            False = 0, 
            True, 
            Invalid = Int32.MaxValue - 1,
            NotFound = Int32.MaxValue 
        }

        //
        // GetConfig - get the Uri config state 
        //
        // This function originally just used System.Config to get the 
        // new-to-Orcas Uri config section.  Unfortunately that created a 
        // circular dependency on System.Config that ultimately could cause
        // ConfigurationExceptions that didn't used to happen in Whidbey and 
        // thus break existing deployed applications.
        //
        // Now this function will determine if it is running in a client
        // application or a web scenario (ASP.NET).   If in a web scenario 
        // this code must still use System.Config to read config as the web
        // scenario has a hierarchy of config files that only System.Config 
        // can practically discover and pars.  If in a client scenario this 
        // code will now use System.Xml.XmlReader to parse machine and app
        // config files. 
        //
        // The default output of this function if it encounters invalid or
        // non-existent Uri config is the original Whidbey settings (no IDN
        // support and no IRI support). 
        //
        private static void GetConfig(ref UriIdnScope idnScope, ref bool iriParsing) { 
 
            // Get the app config path
 
            string appConfigFile = null;

            // Must Assert unrestricted FileIOPermission to get the app config path.
            new FileIOPermission(PermissionState.Unrestricted).Assert(); 
            try {
                appConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 
            } 
            finally {
                FileIOPermission.RevertAssert(); 
            }
            if (IsWebConfig(appConfigFile)) {
                // This is a web scenario.
                // It is safe and *necessary* to use System.Config. 
                try {
                   UriSectionInternal uriSection = UriSectionInternal.GetSection(); 
                   if (uriSection != null) { 
                       idnScope = uriSection.Idn;
                       iriParsing = uriSection.IriParsing; 
                   }
                }
                catch (ConfigurationException) {
                   // Simply ---- any ConfigurationException. 
                   // Throwing it would potentially break applications.
                   // Uri did not read config in previous releases. 
                } 

            } else { 
                // This is a client application scenario.
                // It is not safe to use System.Config for app compat reasons.

                // Already have the application config file path in scope. 
                // Get the path of the machine config file.
                string runtimeDir = null; 
 
                // Must Assert unrestricted FileIOPermission to get the machine config path.
                new FileIOPermission(PermissionState.Unrestricted).Assert(); 
                try {
                    runtimeDir = RuntimeEnvironment.GetRuntimeDirectory();
                }
                finally { 
                    FileIOPermission.RevertAssert();
                } 
                string machineConfigFile = Path.Combine(Path.Combine(runtimeDir, "Config"), "machine.config"); 

                IdnScopeFromConfig idnFromMachine, idnFromApp; 
                IriParsingFromConfig iriFromMachine, iriFromApp;

                // Attempt tp parse machine and app config files if they exist.
                ParseConfigFile(machineConfigFile, out idnFromMachine, out iriFromMachine); 
                ParseConfigFile(appConfigFile, out idnFromApp, out iriFromApp);
 
                // App config takes precedence over machine config 
                // only if found and valid.
                switch (idnFromApp) { 
                    case IdnScopeFromConfig.None:
                        idnScope = UriIdnScope.None;
                        break;
                    case IdnScopeFromConfig.AllExceptIntranet: 
                        idnScope = UriIdnScope.AllExceptIntranet;
                        break; 
                    case IdnScopeFromConfig.All: 
                        idnScope = UriIdnScope.All;
                        break; 
                    default: // invalid or notfound
                        switch (idnFromMachine) {
                            case IdnScopeFromConfig.None:
                                idnScope = UriIdnScope.None; 
                                break;
                            case IdnScopeFromConfig.AllExceptIntranet: 
                                idnScope = UriIdnScope.AllExceptIntranet; 
                                break;
                            case IdnScopeFromConfig.All: 
                                idnScope = UriIdnScope.All;
                                break;
                            default: // invalid or notfound
                                idnScope = UriIdnScope.None; 
                                break;
                        } 
                        break; 
                }
                switch (iriFromApp) { 
                    case IriParsingFromConfig.False:
                        iriParsing = false;
                        break;
                    case IriParsingFromConfig.True: 
                        iriParsing = true;
                        break; 
                    default: // invalid or notfound 
                        switch (iriFromMachine) {
                            case IriParsingFromConfig.False: 
                                iriParsing = false;
                                break;
                            case IriParsingFromConfig.True:
                                iriParsing = true; 
                                break;
                            default: // invalid or notfound 
                                iriParsing = false; 
                                break;
                        } 
                        break;
                }
            }
        } 

        // 
        // Determine if we are in a Web config scenario. 
        //
        private static bool IsWebConfig(string appConfigFile) { 
            // Existence of string object associated with .appVPath tells
            // us that this is an ASP.Net web scenario.
            string appVPath = AppDomain.CurrentDomain.GetData(".appVPath") as string;
            if (appVPath != null) { 
                return true;
            } 
            // If application config file path not null 
            // and begins with http:// or https://
            // then this is the No-Touch web deployment scenario. 
            if (appConfigFile != null) {
                if (appConfigFile.StartsWith("http://", true, CultureInfo.InvariantCulture) ||
                    appConfigFile.StartsWith("https://", true, CultureInfo.InvariantCulture)) {
                return true; 
                }
            } 
            return false; 
        }
 
        //
        // Attempt to parse out the IDN and IRI settings in an xml config file.
        //
        private static void ParseConfigFile( 
                                string file,
                                out IdnScopeFromConfig idnStateConfig, 
                                out IriParsingFromConfig iriParsingConfig) { 

            // Start with default NotFound values. 
            idnStateConfig = IdnScopeFromConfig.NotFound;
            iriParsingConfig = IriParsingFromConfig.NotFound;

            // Assert read permission for only this file. 
            new FileIOPermission(FileIOPermissionAccess.Read, file).Assert();
 
            try { 
                // Create a filestream to read the config file
                // We cannot allow XmlReader.Create to do it as it considers 
                // the input file string as a URI and calls our ctor
                // potentially creating endless recursion if the file string
                // requires us to read config.
                FileStream filestream = new FileStream(file, FileMode.Open, FileAccess.Read); 

                // Close the filestream when done. 
                using (filestream) { 
                    // Create an XML reader that ignores:
                    // - processing instructions 
                    // - comments
                    // - insignificant white space
                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.IgnoreComments = true; 
                    settings.IgnoreWhitespace = true;
                    settings.IgnoreProcessingInstructions = true; 
                    XmlReader reader = XmlReader.Create(filestream, settings); 

                    // Close the reader when done. 
                    using(reader) {

                        // Find configuration element - return if not found.
                        if (!reader.ReadToFollowing("configuration")) { 
                            return;
                        } 
                        // Find uri element - return if not found 
                        if (!reader.ReadToFollowing("uri")) {
                            return; 
                        }

                        // Loop reading nodes until we hit the uri EndElement
                        while (true) { 

                            // If an EndElement and is "uri" then stop reading 
                            if (reader.NodeType == XmlNodeType.EndElement) { 
                                if (ConfigStringEqual(reader.Name, "uri")) {
                                    break; 
                                }
                            }
                            // If an Element look for our two elements of interest:
                            // "idn" or "iriParsing" 
                            if (reader.NodeType == XmlNodeType.Element) {
                                string value; 
                                if (ConfigStringEqual(reader.Name, "idn")) { 
                                    // Try to get the "enabled" attribute value
                                    value = reader.GetAttribute("enabled"); 
                                    if (value != null) {
                                        // Look for "None" or "AllExceptIntranet" or "All"
                                        // Otherwise invalid
                                        if (ConfigStringEqual(value, "None")) { 
                                            idnStateConfig = IdnScopeFromConfig.None;
                                        } else if (ConfigStringEqual(value, "AllExceptIntranet")) { 
                                            idnStateConfig = IdnScopeFromConfig.AllExceptIntranet; 
                                        } else if (ConfigStringEqual(value, "All")) {
                                            idnStateConfig = IdnScopeFromConfig.All; 
                                        } else {
                                            idnStateConfig = IdnScopeFromConfig.Invalid;
                                        }
                                    } 
                                } else if (ConfigStringEqual(reader.Name, "iriParsing")) {
                                    // Try to get the "enabled" attribute value 
                                    value = reader.GetAttribute("enabled"); 
                                    if (value != null) {
                                        // Look for "false" or "true" 
                                        // Otherwise invalid
                                        if (ConfigStringEqual(value, "false")) {
                                            iriParsingConfig = IriParsingFromConfig.False;
                                        } else if (ConfigStringEqual(value, "true")) { 
                                            iriParsingConfig = IriParsingFromConfig.True;
                                        } else { 
                                            iriParsingConfig = IriParsingFromConfig.Invalid; 
                                        }
                                    } 
                                }
                            }
                            // Go to next node
                            if(!reader.Read()) break;  // break out of loop on eof 
                        }
                    } 
                } 
            }
 
            catch (Exception exception) {
                // Throw only "fatal" exceptions for backward compat
                if (NclUtilities.IsFatal(exception))
                    throw; 
            }
            finally { 
                // Revert read permission assert for this file. 
                FileIOPermission.RevertAssert();
            } 
        }

        // Simple function to do OrdinalIgnoreCase string comparisons
        private static bool ConfigStringEqual(string string1, string string2) { 
            if(String.Compare(string1, string2, StringComparison.OrdinalIgnoreCase) == 0) {
                return true; 
            } else { 
                return false;
            } 
        }

        private string GetLocalPath(){
            EnsureParseRemaining(); 

            //Other cases will get a Unix-style path 
            if (IsUncOrDosPath) 
            {
                EnsureHostString(false); 
                int start;

                // Do we have a valid local path right in m_string?
                if (NotAny(Flags.HostNotCanonical|Flags.PathNotCanonical|Flags.ShouldBeCompressed)) { 

                    start = IsUncPath? m_Info.Offset.Host-2 :m_Info.Offset.Path; 
 

                    string str = 
                        (IsImplicitFile && m_Info.Offset.Host == (IsDosPath?0:2) && m_Info.Offset.Query == m_Info.Offset.End)
                            ? m_String
                            : (IsDosPath && (m_String[start] == '/' || m_String[start] == '\\'))
                                ? m_String.Substring(start + 1, m_Info.Offset.Query - start - 1) 
                                : m_String.Substring(start, m_Info.Offset.Query - start);
 
                    // Should be a rare case, convert c|\ into c:\ 
                    if (IsDosPath && str[1] == '|') {
                        // Sadly, today there is no method for replacong just one occurrence 
                        str = str.Remove(1, 1);
                        str = str.Insert(1, ":");
                    }
 
                    // check for all back slashes (though may be string.Replace is smart?)
                    for (int i = 0; i < str.Length; ++i) { 
                        if (str[i] == '/') { 
                            str = str.Replace('/', '\\');
                            break; 
                        }
                    }

                    return str; 
                }
 
                // Not everything went well, going ---- 

                char[] result; 
                int count = 0;
                start = m_Info.Offset.Path;

                string host = m_Info.Host; 
                result = new char [host.Length + 3 + m_Info.Offset.Fragment - m_Info.Offset.Path ];
 
                if (IsUncPath) 
                {
                    result[0] = '\\'; 
                    result[1] = '\\';
                    count = 2;

                    UnescapeString( host, 0, host.Length, result, ref count, c_DummyChar, c_DummyChar, c_DummyChar, 
                                    UnescapeMode.CopyOnly, m_Syntax, false, false);
 
                } 
                else {
                    // Dos path 
                    if(m_String[start] == '/' ||  m_String[start] == '\\') {
                        // Skip leading slash for a DOS path
                        ++start;
                    } 
                }
 
 
                ushort pathStart = (ushort)count; //save for optional Compress() call
 
                UnescapeMode mode = (InFact(Flags.PathNotCanonical) && !IsImplicitFile) ? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll): UnescapeMode.CopyOnly;
                UnescapeString(m_String, start, m_Info.Offset.Query, result, ref count, c_DummyChar, c_DummyChar, c_DummyChar, mode, m_Syntax, true, false);

                // Possibly convert c|\ into c:\ 
                if (result[1] == '|')
                    result[1] = ':'; 
 
                if (InFact(Flags.ShouldBeCompressed)) {
                    // suspecting not compressed path 
                    // For a dos path we won't compress the "x:" part if found /../ sequences
                    result = Compress(result, (ushort)(IsDosPath? pathStart + 2: pathStart), ref count, m_Syntax);
                }
 
                // We don't know whether all slashes were the back ones
                // Plus going through Compress will turn them into / anyway 
                // Converting / back into \ 
                for (ushort i = 0; i < (ushort) count; ++i) {
                    if (result[i] == '/') { 
                        result[i] = '\\';
                    }
                }
 
                return new string(result, 0, count);
 
            } 
            else {
                // Return unescaped canonical path 
                // Note we cannot call GetParts here because it has circular dependancy on GelLocalPath method
                return GetUnescapedParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped);
            }
        } 

        // 
        // 
        //  Gets the escaped Uri.AbsolutePath and Uri.Query
        //  properties separated by a "?" character. 
        public string PathAndQuery {
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                string result = GetParts(UriComponents.PathAndQuery, UriFormat.UriEscaped); 
                //
                // 


                if (IsDosPath && result[0] == '/')
                { 
                    result = result.Substring(1);
                } 
                return result; 
            }
        } 
        //
        //
        //
        // 
        public int Port {
            get { 
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (m_Syntax.IsSimple)
                    EnsureUriInfo();
                else 
                {
                    // For a custom parser we request HostString creation that will aso set the port 
                    EnsureHostString(false); 
                }
 
                if (InFact(Flags.NotDefaultPort)) {
                    return (int)m_Info.Offset.PortValue;
                }
                return m_Syntax.DefaultPort; 
            }
        } 
        // 
        //
        // 
        //  Gets the escaped query.
        public string Query {
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
 
                UriInfo info = EnsureUriInfo();
                if ((object)info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo();
                }
                string result = info.MoreInfo.Query;
                if ((object)result == null) { 
                    result = GetParts(UriComponents.Query | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
                    info.MoreInfo.Query = result; 
                } 
                return result;
            } 
        }
        //
        //
        // 
        //    Gets the escaped fragment.
        public string Fragment { 
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }

                UriInfo info = EnsureUriInfo();
                if ((object)info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo();
                } 
                string result = info.MoreInfo.Fragment; 
                if ((object)result == null) {
                    result = GetParts(UriComponents.Fragment | UriComponents.KeepDelimiter, UriFormat.UriEscaped); 
                    info.MoreInfo.Fragment = result;
                }
                return result;
            } 
        }
 
        // 
        //  Gets the Scheme string of this Uri
        // 
        //
        public string Scheme {
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
 
                return m_Syntax.SchemeName;
            } 
        }

        //
        //  Was the original string switched from m_String to m_OriginalUnicodeString 
        //  Will happen when Iri is turned on and we have unicode chars or of idn is
        //  is on and we have an idn or unicode host. 
        // 
        private bool OriginalStringSwitched
        { 
            get{return ((m_iriParsing && InFact(Flags.HasUnicode)) ||
                        (AllowIdn && (InFact(Flags.IdnHost) || InFact(Flags.UnicodeHost))));}
        }
        // 
        //    Gets the exact string passed by a user.
        public String OriginalString { 
            get { 
                return OriginalStringSwitched ? m_originalUnicodeString : m_String;
            } 
        }

        //
        //    Gets the host string that is unescaped and if it's Ipv6 host, 
        //    then the returned string is suitable for DNS lookup.
        // 
        //    For Ipv6 this will strip [] and add ScopeId if was found in the original string 
        public string DnsSafeHost {
            get { 

                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))){ 
                    // return pre generated idn 
                    EnsureUriInfo();
                    return m_Info.DnsSafeHost; 
                }

                EnsureHostString(false);
 
                // Special case, will include ScopeID and strip [] around IPv6
                // This will also unescape the host string 
                string ret = m_Info.Host; 

                if (HostType == Flags.IPv6HostType) 
                {
                    ret = ret.Substring(1, ret.Length - 2);
                    if ((object)m_Info.ScopeId != null)
                    { 
                        ret += m_Info.ScopeId;
                    } 
                } 
                // We do not unescape anything but Basic host
                else if (HostType == Flags.BasicHostType && InFact(Flags.HostNotCanonical | Flags.E_HostNotCanonical)) 
                {
                    char[] dest = new char[ret.Length];
                    int count = 0;
                    UnescapeString(ret, 0, ret.Length, dest, ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false); 
                    ret = new string(dest, 0, count);
                } 
 
                return ret;
            } 
        }

        //
        //  Returns false if the string passed in the constructor cannot be parsed as 
        //  valid AbsoluteUri. This could be a relative Uri instead.
        // 
        public bool IsAbsoluteUri { 
            get {
                return m_Syntax != null; 
            }
        }

        // 
        //
        //  Gets an array of the segments that make up a URI. 
        public string[] Segments { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }

                //[....] codereview 
                //I did not optimize this method
 
                string[] segments = null; // used to be a class cached result 
                if (segments == null) {
 
                    string path = PrivateAbsolutePath;

                    if (path.Length == 0) {
                        segments = new string[0]; 
                    }
                    else { 
                        System.Collections.ArrayList pathSegments = new System.Collections.ArrayList(); 
                        int current = 0;
                        while (current < path.Length) { 
                            int next = path.IndexOf('/', current);
                            if (next == -1) {
                                next = path.Length - 1;
                            } 
                            pathSegments.Add(path.Substring(current, (next - current) + 1));
                            current = next + 1; 
                        } 
                        segments = (string[]) (pathSegments.ToArray(typeof(string)));
                    } 
                }
                return segments;
            }
        } 
        //
        // 
        //  Returns 'true' if the 'dontEscape' parameter was set to 'true ' when the Uri instance was created. 
        public bool UserEscaped {
            get { 
                return InFact(Flags.UserEscaped);
            }
        }
        // 
        //
        //  Gets the user name, password, and other user specific information associated 
        //  with the Uniform Resource Identifier (URI). 
        public string UserInfo {
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }
 
                return GetParts(UriComponents.UserInfo, UriFormat.UriEscaped);
            } 
        } 

        // 
        // CheckHostName
        //
        //  Determines whether a host name authority is a valid Host name according
        //  to DNS naming rules 
        //
        // Returns: 
        //  true if  is valid else false 
        //
        // Throws: 
        //  Nothing
        //
        public static UriHostNameType CheckHostName(string name) {
 
            if ((object)name == null || name.Length == 0 || name.Length > short.MaxValue) {
                return UriHostNameType.Unknown; 
            } 
            int end = name.Length;
            unsafe { 
                fixed (char* fixedName = name) {

                    if (name[0] == '[' && name[name.Length-1] == ']') {
                        // we require that _entire_ name is recognized as ipv6 address 
                        if (IPv6AddressHelper.IsValid(fixedName, 1, ref end) && end == name.Length) {
                            return UriHostNameType.IPv6; 
                        } 
                    }
                    end = name.Length; 
                    if (IPv4AddressHelper.IsValid(fixedName, 0 , ref end, false, false) && end == name.Length) {
                        return UriHostNameType.IPv4;
                    }
                    end = name.Length; 
                    bool dummyBool = false;
                    if (DomainNameHelper.IsValid(fixedName, 0, ref end, ref dummyBool, false) && end == name.Length) { 
                        return UriHostNameType.Dns; 
                    }
                } 

                //This checks the form without []
                end = name.Length+2;
                // we require that _entire_ name is recognized as ipv6 address 
                name = "["+name+"]";
                fixed (char* newFixedName = name) { 
                    if (IPv6AddressHelper.IsValid(newFixedName, 1, ref end) && end == name.Length) { 
                        return UriHostNameType.IPv6;
                    } 
                }
            }
            return UriHostNameType.Unknown;
        } 
        //
        // CheckSchemeName 
        // 
        //  Determines whether a string is a valid scheme name according to RFC 2396.
        //  Syntax is: 
        //      scheme = alpha *(alpha | digit | '+' | '-' | '.')
        //
        public static bool CheckSchemeName(string schemeName) {
            if (((object)schemeName == null) 
                || (schemeName.Length == 0)
                || !IsAsciiLetter(schemeName[0])) { 
                return false; 
            }
            for (int i = schemeName.Length - 1; i > 0; --i) { 
                if (!(IsAsciiLetterOrDigit(schemeName[i])
                    || (schemeName[i] == '+')
                    || (schemeName[i] == '-')
                    || (schemeName[i] == '.'))) { 
                    return false;
                } 
            } 
            return true;
        } 
        //
        // Returns:
        //  Number in the range 0..15
        // 
        // Throws:
        //  ArgumentException 
        // 
        public static int FromHex(char digit) {
            if (((digit >= '0') && (digit <= '9')) 
                || ((digit >= 'A') && (digit <= 'F'))
                || ((digit >= 'a') && (digit <= 'f'))) {
                return  (digit <= '9')
                    ? ((int)digit - (int)'0') 
                    : (((digit <= 'F')
                    ? ((int)digit - (int)'A') 
                    : ((int)digit - (int)'a')) 
                    + 10);
            } 
            throw new ArgumentException("digit");
        }
        //
        // GetHashCode 
        //
        //  Overrides default function (in Object class) 
        // 
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public override int GetHashCode() {
            if (IsNotAbsoluteUri)
            {
                return CalculateCaseInsensitiveHashCode(OriginalString); 
            }
 
            // Consider moving hash code storage from m_Info.MoreInfo to m_Info 
            UriInfo info = EnsureUriInfo();
            if ((object)info.MoreInfo == null) { 
                info.MoreInfo = new MoreInfo();
            }
            int tempHash = info.MoreInfo.Hash;
            if (tempHash == 0) { 
                string chkString = info.MoreInfo.RemoteUrl;
                if ((object) chkString == null) 
                    chkString = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); 
                tempHash = CalculateCaseInsensitiveHashCode(chkString);
                if (tempHash == 0) { 
                    tempHash = 0x1000000;   //making it not zero still large enough to be maped to zero by a hashtable
                }
                info.MoreInfo.Hash = tempHash;
            } 
            return tempHash;
        } 
 
        //
        // ToString 
        //
        // The better implementation would be just
        //
        private const UriFormat V1ToStringUnescape = (UriFormat)0x7FFF; 

        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public override string ToString() 
        {
            if (m_Syntax == null) { 
                return (m_iriParsing && InFact(Flags.HasUnicode)) ? m_String : OriginalString;
            }

            EnsureUriInfo(); 
            if ((object)m_Info.String == null)
            { 
 
                // V1.1 compat unless #353711 is appoved, otheriwse it should be just a call into GetParts() as shown below
                // m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); 

                if (Syntax.IsSimple)
                    m_Info.String = GetComponentsHelper(UriComponents.AbsoluteUri, V1ToStringUnescape);
                else 
                    m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
 
            } 
            return m_Info.String;
        } 

        //
        //
        //  A static shortcut to Uri.Equals 
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public static bool operator == (Uri uri1, Uri uri2) { 
            if ((object)uri1 == (object)uri2) {
                return true; 
            }
            if ((object)uri1 == null || (object)uri2 == null) {
                return false;
            } 
            return uri2.Equals(uri1);
        } 
 
        //
        // 
        //  A static shortcut to !Uri.Equals
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static bool operator != (Uri uri1, Uri uri2) { 
            if ((object)uri1 == (object)uri2) {
                return false; 
            } 

            if ((object)uri1 == null || (object)uri2 == null) { 
                return true;
            }

            return !uri2.Equals(uri1); 
        }
 
 

        // 
        // Equals
        //
        //  Overrides default function (in Object class)
        // 
        // Assumes:
        //   is an object of class Uri 
        // 
        // Returns:
        //  true if objects have the same value, else false 
        //
        // Throws:
        //  Nothing
        // 
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public override bool Equals(object comparand) { 
            if ((object) comparand == null) { 
                return false;
            } 

            if ((object)this == (object)comparand) {
                return true;
            } 

            Uri obj = comparand as Uri; 
 
            //
            // we allow comparisons of Uri and String objects only. If a string 
            // is passed, convert to Uri. This is inefficient, but allows us to
            // canonicalize the comparand, making comparison possible
            //
            if ((object)obj == null) { 
                string s = comparand as string;
 
                if ((object)s == null) 
                    return false;
 
                if (!TryCreate(s, UriKind.RelativeOrAbsolute, out obj))
                    return false;
            }
 
            // Since v1.0 two Uris are equal if everything but fragment and UserInfo does match
 
            // This check is for a case where we already fixed up the equal references 
            if ((object)this.m_String == (object)obj.m_String) {
                return true; 
            }

            if (IsAbsoluteUri != obj.IsAbsoluteUri)
                return false; 

            if (IsNotAbsoluteUri) 
                return OriginalString.Equals(obj.OriginalString); 

            if (NotAny(Flags.AllUriInfoSet) || obj.NotAny(Flags.AllUriInfoSet)) { 
                // Try raw compare for m_Strings as the last chance to keep the working set small
                if (!IsUncOrDosPath ) {
                    if (m_String.Length == obj.m_String.Length) {
                        unsafe { 
                            // Try case sensitive compare on m_Strings
                            fixed (char* pMe = m_String) { 
                                fixed (char* pShe = obj.m_String) { 
                                    // This will never go negative since m_String is checked to be a valid URI
                                    int i = (m_String.Length-1); 
                                    for ( ;i >= 0 ; --i) {
                                        if (*(pMe+i) != *(pShe+i)) {
                                            break;
                                        } 
                                    }
                                    if (i == -1) { 
                                        return true; 
                                    }
                                } 
                            }
                        }
                    }
                } 
                else if (String.Compare(m_String, obj.m_String, StringComparison.OrdinalIgnoreCase) == 0) {
                    return true; 
                } 
            }
 
            // Note that equality test will bring the working set of both
            // objects up to creation of m_Info.MoreInfo member
            EnsureUriInfo();
            obj.EnsureUriInfo(); 

            if (!UserDrivenParsing && !obj.UserDrivenParsing && Syntax.IsSimple && obj.Syntax.IsSimple) 
            { 
                // Optimization of canonical DNS names by avoiding host string creation.
                // Note there could be explicit ports specified that would invalidate path offsets 
                if (InFact(Flags.CanonicalDnsHost) && obj.InFact(Flags.CanonicalDnsHost)) {
                    ushort i1 = m_Info.Offset.Host;
                    ushort end1 = m_Info.Offset.Path;
 
                    ushort i2 = obj.m_Info.Offset.Host;
                    ushort end2 = obj.m_Info.Offset.Path; 
                    string str = obj.m_String; 
                    //Taking the shortest part
                    if (end1-i1 > end2-i2) { 
                        end1 = (ushort)(i1 + end2-i2);
                    }
                    // compare and break on ':' if found
                    while (i1 < end1) { 
                        if (m_String[i1] != str[i2]) {
                            return false; 
                        } 
                        if (str[i2] == ':') {
                            // The other must have ':' too to have equal host 
                            break;
                        }
                        ++i1;++i2;
                    } 

                    // The longest host must have ':' or be of the same size 
                    if (i1 < m_Info.Offset.Path && m_String[i1] != ':') { 
                        return false;
                    } 
                    if (i2 < end2 && str[i2] != ':') {
                        return false;
                    }
                    //hosts are equal! 
                }
                else { 
                    EnsureHostString(false); 
                    obj.EnsureHostString(false);
                    if (!m_Info.Host.Equals(obj.m_Info.Host)) { 
                        return false;
                    }
                }
 
                if (Port != obj.Port) {
                    return false; 
                } 
            }
 
            // see Whidbey#21590
            // We want to cache RemoteUrl to improve perf for Uri as a key.
            // We should consider reducing the overall working set by not caching some other properties mentioned in MoreInfo
 
            // Mutli-threading!
            UriInfo meInfo  = m_Info; 
            UriInfo sheInfo = obj.m_Info; 
            if ((object)meInfo.MoreInfo == null) {
                meInfo.MoreInfo = new MoreInfo(); 
            }
            if ((object)sheInfo.MoreInfo == null) {
                sheInfo.MoreInfo = new MoreInfo();
            } 

            // NB: To avoid a race condition when creating MoreInfo field 
            // "meInfo" and "sheInfo" shall remain as local copies. 
            string me = meInfo.MoreInfo.RemoteUrl;
            if ((object)me == null) { 
                me = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped);
                meInfo.MoreInfo.RemoteUrl = me;
            }
            string she = sheInfo.MoreInfo.RemoteUrl; 
            if ((object)she == null) {
                she = obj.GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); 
                sheInfo.MoreInfo.RemoteUrl = she; 
            }
 
            if (!IsUncOrDosPath ) {
                if (me.Length != she.Length) {
                    return false;
                } 
                unsafe {
                    // Try case sensitive compare on m_Strings 
                    fixed (char* pMe = me) { 
                        fixed (char* pShe = she) {
                            char *endMe  = pMe  + me.Length; 
                            char *endShe = pShe + me.Length;
                            while (endMe != pMe) {
                                if (*--endMe != *--endShe) {
                                    return false; 
                                }
                            } 
                            return true; 
                        }
                    } 
                }
            }

 
            // if IsUncOrDosPath is true then we ignore case in the path comparison
            // Get Unescaped form as most safe for the comparison 
            // Fragment AND UserInfo are ignored 
            //
            return (String.Compare(meInfo.MoreInfo.RemoteUrl, 
                                   sheInfo.MoreInfo.RemoteUrl,
                                   IsUncOrDosPath ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal ) == 0);
        }
        // 
        // GetLeftPart
        // 
        //  Returns part of the URI based on the parameters: 
        //
        // Inputs: 
        //    part
        //      Which part of the URI to return
        //
        // Returns: 
        //  The requested substring
        // 
        // Throws: 
        //  UriFormatException if URI type doesn't have host-port or authority parts
        // 
        public string GetLeftPart(UriPartial part) {
            if (IsNotAbsoluteUri) {
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
            } 

            EnsureUriInfo(); 
            const UriComponents NonPathPart = (UriComponents.Scheme | UriComponents.UserInfo | UriComponents.Host | UriComponents.Port); 

            switch (part) { 
                case UriPartial.Scheme:

                    return GetParts(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
 
                case UriPartial.Authority:
 
                    if (NotAny(Flags.AuthorityFound) || IsDosPath) { 

                        // 



                        // From V1.0 comments: 

                        // anything that didn't have "//" after the scheme name 
                        // (mailto: and news: e.g.) doesn't have an authority 
                        //
 
                        return String.Empty;
                    }
                    return GetParts(NonPathPart, UriFormat.UriEscaped);
 
                case UriPartial.Path:
                    return GetParts(NonPathPart | UriComponents.Path, UriFormat.UriEscaped); 
 
                case UriPartial.Query:
                    return GetParts(NonPathPart | UriComponents.Path | UriComponents.Query, UriFormat.UriEscaped); 

            }
            throw new ArgumentException("part");
        } 

        // 
        // 
        /// Transforms a character into its hexadecimal representation.
        public static string HexEscape(char character) { 
            if (character > '\xff') {
                throw new ArgumentOutOfRangeException("character");
            }
            char[] chars = new char[3]; 
            int pos = 0;
            EscapeAsciiChar(character, chars, ref pos); 
            return new string(chars); 
        }
 
        //
        // HexUnescape
        //
        //  Converts a substring of the form "%XX" to the single character represented 
        //  by the hexadecimal value XX. If the substring s[Index] does not conform to
        //  the hex encoding format then the character at s[Index] is returned 
        // 
        // Inputs:
        //    pattern 
        //      String from which to read the hexadecimal encoded substring
        //
        //    index
        //      Offset within  from which to start reading the hexadecimal 
        //      encoded substring
        // 
        // Outputs: 
        //    index
        //      Incremented to the next character position within the string. This 
        //      may be EOS if this was the last character/encoding within 
        //
        // Returns:
        //  Either the converted character if [] was hex encoded, or 
        //  the character at []
        // 
        // Throws: 
        //  ArgumentOutOfRangeException
        // 

        public static char HexUnescape(string pattern, ref int index) {
            if ((index < 0) || (index >= pattern.Length)) {
                throw new ArgumentOutOfRangeException("index"); 
            }
            if ((pattern[index] == '%') 
                && (pattern.Length - index >= 3)) { 
                char ret = EscapedAscii(pattern[index + 1], pattern[index + 2]);
                if (ret != c_DummyChar) { 
                    index += 3;
                    return ret;
                }
            } 
            return pattern[index++];
        } 
 
        //
        // IsHexDigit 
        //
        //  Determines whether a character is a valid hexadecimal digit in the range
        //  [0..9] | [A..F] | [a..f]
        // 
        // Inputs:
        //    character 
        //      Character to test 
        //
        // Returns: 
        //  true if  is a hexadecimal digit character
        //
        // Throws:
        //  Nothing 
        //
        public static bool IsHexDigit(char character) { 
            return ((character >= '0') && (character <= '9')) 
                || ((character >= 'A') && (character <= 'F'))
                || ((character >= 'a') && (character <= 'f')); 
        }

        //
        // IsHexEncoding 
        //
        //  Determines whether a substring has the URI hex encoding format of '%' 
        //  followed by 2 hexadecimal characters 
        //
        // Inputs: 
        //    pattern
        //      String to check
        //
        //    index 
        //      Offset in  at which to check substring for hex encoding
        // 
        // Assumes: 
        //  0 <=  < .Length
        // 
        // Returns:
        //  true if [] is hex encoded, else false
        //
        // Throws: 
        //  Nothing
        // 
        public static bool IsHexEncoding(string pattern, int index) { 
            if ((pattern.Length - index) < 3) {
                return false; 
            }
            if ((pattern[index] == '%') && EscapedAscii(pattern[index + 1], pattern[index + 1]) != c_DummyChar) {
                return true;
            } 
            return false;
        } 
 
        //
        // MakeRelative (toUri) 
        //
        //  Return a relative path which when applied to this Uri would create the
        //  resulting Uri 
        // 
        // Inputs:
        //    toUri 
        //      Uri to which we calculate the transformation from this Uri 
        //
        // Returns: 
        //  If the 2 Uri are common except for a relative path difference, then that
        //  difference, else the display name of this Uri
        //
        // Throws: 
        //  Nothing
        // 
        [Obsolete("The method has been deprecated. Please use MakeRelativeUri(Uri uri). http://go.microsoft.com/fwlink/?linkid=14202")] 
        public string MakeRelative(Uri toUri)
        { 
            if (IsNotAbsoluteUri || toUri.IsNotAbsoluteUri)
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));

            if ((Scheme == toUri.Scheme) && (Host == toUri.Host) && (Port == toUri.Port)) 
                return PathDifference(AbsolutePath, toUri.AbsolutePath, !IsUncOrDosPath);
 
            return toUri.ToString(); 
        }
        // 
        public Uri MakeRelativeUri(Uri uri)
        {
            if (IsNotAbsoluteUri || uri.IsNotAbsoluteUri)
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 

            // Note that the UserInfo part is ignored when computing a relative Uri. 
            if ((Scheme == uri.Scheme) && (Host == uri.Host) && (Port == uri.Port)) 
                return new Uri(
                            PathDifference(AbsolutePath, uri.AbsolutePath, !IsUncOrDosPath) + uri.GetParts(UriComponents.Query | UriComponents.Fragment, UriFormat.UriEscaped), 
                            UriKind.Relative
                            );

            return uri; 
        }
 
        // 
        // http://host/Path/Path/File?Query is the base of
        //      - http://host/Path/Path/File/ ...    (those "File" words may be different in semantic but anyway) 
        //      - http://host/Path/Path/#Fragment
        //      - http://host/Path/Path/?Query
        //      - http://host/Path/Path/MoreDir/ ...
        //      - http://host/Path/Path/OtherFile?Query 
        //      - http://host/Path/Path/Fl
        //      - http://host/Path/Path/ 
        // 
        //  It is not a base for
        //      - http://host/Path/Path         (that last "Path" is not considered as a directory) 
        //      - http://host/Path/Path?Query
        //      - http://host/Path/Path#Fragment
        //      - http://host/Path/Path2/
        //      - http://host/Path/Path2/MoreDir 
        //      - http://host/Path/File
        // 
        // ASSUMES that strings like http://host/Path/Path/MoreDir/../../  have been canonicalized before going to this method. 
        // ASSUMES that back slashes already have been converted if applicable.
        // 
        private static unsafe bool TestForSubPath(  char* pMe,  ushort meLength,
                                                    char* pShe, ushort sheLength,
                                                    bool ignoreCase) {
            ushort i = 0; 
            char chMe;
            char chShe; 
 
            bool AllSameBeforeSlash = true;
 
            for( ;i < meLength && i < sheLength; ++i)
            {
                chMe  = *(pMe+i);
                chShe = *(pShe+i); 

                if (chMe == '?' || chMe == '#') { 
                    // survived so far and pMe does not have any more path segments 
                    return true;
                } 

                // If pMe terminates a path segment, so must pShe
                if (chMe == '/') {
                    if (chShe != '/') { 
                        // comparison has falied
                        return false; 
                    } 
                    // plus the segments must be the same
                    if (!AllSameBeforeSlash) { 
                        // comparison has falied
                        return false;
                    }
                    //so far so good 
                    AllSameBeforeSlash = true;
                    continue; 
                } 

                // if pShe terminates then pMe must not have any more path segments 
                if (chShe == '?' || chShe == '#') {
                    break;
                }
 
                if (!ignoreCase) {
                    if (chMe != chShe) { 
                        AllSameBeforeSlash = false; 
                    }
                } 
                else {
                    if (Char.ToLower(chMe, CultureInfo.InvariantCulture) != Char.ToLower(chShe, CultureInfo.InvariantCulture)) {
                        AllSameBeforeSlash = false;
                    } 
                }
            } 
 
            // If me is longer then it must not have any more path segments
            for (; i < meLength; ++i) { 
                if ((chMe = *(pMe+i)) == '?' || chMe == '#') {
                    return true;
                }
                if (chMe == '/') { 
                    return false;
                } 
            } 
            //survived by getting to the end of pMe
            return true; 
        }
        // This is used by UriBuilder,

        internal unsafe static string InternalEscapeString(string rawString) { 
            if ((object)rawString == null)
                return String.Empty; 
 
            int position = 0;
            char[] dest = EscapeString(rawString, 0, rawString.Length, null, ref position, true, '?', '#', '%'); 
            if ((object)dest == null)
                return rawString;

            return new string(dest, 0, position); 
        }
 
        // 
        //  This method is called first to figure out the scheme or a simple file path
        //  Is called only at the .ctor time 
        //
        private static unsafe ParsingError ParseScheme(string uriString, ref Flags flags, ref UriParser syntax)
        {
            int length = uriString.Length; 
            if (length == 0)
                return ParsingError.EmptyUriString; 
 
            // we don;t work with >= 64k Uris
            if (length >= c_MaxUriBufferSize) 
                return ParsingError.SizeLimit;

            //STEP1: parse scheme, lookup this Uri Syntax or create one using UnknownV1SyntaxFlags uri syntax template
            fixed (char* pUriString = uriString) 
            {
                ParsingError err = ParsingError.None; 
                ushort idx = ParseSchemeCheckImplicitFile(pUriString, (ushort)length, ref err, ref flags, ref syntax); 

                if (err != ParsingError.None) 
                    return err;

                flags |= (Flags)idx;
             } 
             return ParsingError.None;
        } 
 
        //
        // A wrapper for ParseMinimal() called from a user parser 
        // It signals back that the call has been done
        // plus it communicates back a flag for an error if any
        //
        internal UriFormatException ParseMinimal() 
        {
            ParsingError result = PrivateParseMinimal(); 
            if (result == ParsingError.None) 
                return null;
 
            // Means the we think the Uri is invalid, bu that can be later overriden by a user parser
            m_Flags |= Flags.ErrorOrParsingRecursion;

            return GetException(result); 
        }
        // 
        // 
        //  This method tries to parse the minimal information needed to certify the valifity
        //  of a uri string 
        //
        //      scheme://userinfo@host:Port/Path?Query#Fragment
        //
        //  The method must be called only at the .ctor time 
        //
        //  Returns ParsingError.None if the Uri syntax is valid, an error otheriwse 
        // 
        private unsafe ParsingError PrivateParseMinimal()
        { 
            ushort idx = (ushort) (m_Flags & Flags.IndexMask);
            ushort length = (ushort) m_String.Length;
            string newHost = null;      // stores newly parsed host when original strings are being switched
 
            // Means a custom UriParser did call "base" InitializeAndValidate()
            m_Flags &= ~(Flags.IndexMask | Flags.UserDrivenParsing); 
 
            //STEP2: Parse up to the port
 
            fixed (char* pUriString =   ((m_iriParsing &&
                                        ((m_Flags & Flags.HasUnicode)!=0) &&
                                        ((m_Flags & Flags.HostUnicodeNormalized) == 0)) ? m_originalUnicodeString : m_String))
            { 
                // Cut trailing spaces in m_String
                if (length > idx && IsLWS(pUriString[length-1])) 
                { 
                    --length;
                    while (length != idx && IsLWS(pUriString[--length])) 
                        ;
                    ++length;
                }
 
                // [....] codereview:
                // Old Uri parser tries to figure out on a DosPath in all cases. 
                // Hence http://c:/ is treated as as DosPath without the host while it should be a host "c", port 80 
                //
                // This block is compatible with Old Uri parser in terms it will look for the DosPath if the scheme 
                // syntax allows both empty hostnames and DosPath
                //
#if !PLATFORM_UNIX
                if (m_Syntax.IsAllSet(UriSyntaxFlags.AllowEmptyHost|UriSyntaxFlags.AllowDOSPath) && NotAny(Flags.ImplicitFile) && (idx+1 < length)) { 

                    char c; 
                    ushort i = (ushort) idx; 

                    // V1 Compat: Allow _compression_ of > 3 slashes only for File scheme, see VsWhidbey 87448. 
                    // This will skip all slashes and if their number is 2+ it sets the AuthorityFound flag
                    for (; i < length; ++i) {
                        if (!((c=pUriString[i])== '\\' || c == '/'))
                            break; 
                    }
 
                    if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) || i-idx <= 3) { 
                        // if more than one slash after the scheme, the authority is present
                        if (i-idx >= 2) { 
                            m_Flags |= Flags.AuthorityFound;
                        }
                        // DOS-like path?
                        if (i+1 < (ushort) length  && ((c=pUriString[i+1]) == ':' || c == '|') && IsAsciiLetter(pUriString[i])) { 

                            if (i+2 >= (ushort) length || ((c=pUriString[i+2]) != '\\' && c != '/')) 
                            { 
                                // report an error but only for a file: scheme
                                if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri)) 
                                    return ParsingError.MustRootedPath;
                            }
                            else
                            { 
                                // This will set IsDosPath
                                m_Flags |= Flags.DosPath; 
 
                                if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) {
                                    // when DosPath found and Authority is required, set this flag even if Authority is empty 
                                    m_Flags |= Flags.AuthorityFound;
                                }
                                if (i != idx && i-idx != 2) {
                                    //This will remember that DosPath is rooted 
                                    idx = (ushort)(i-1);
                                } 
                                else { 
                                    idx = i;
                                } 
                            }
                        }
                        else if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) && (i-idx >= 2 && i-idx != 3 && i < length && pUriString[i] != '?' && pUriString[i] != '#'))
                        { 
                            // see VsWhidbey#226745 V1.0 did not support file:///, fixing it with minimal behavior change impact
                            // Only FILE scheme may have UNC Path flag set 
                            m_Flags |= Flags.UncPath; 
                            idx = i;
                        } 
                    }
                }
#endif // !PLATFORM_UNIX
                // 
                //STEP 1.5 decide on the Authority component
                // 
#if !PLATFORM_UNIX 
                if ((m_Flags & (Flags.UncPath|Flags.DosPath)) != 0) {
                } 
#else
                if ((m_Flags & Flags.ImplicitFile) != 0) {
                    // Already parsed up to the path
                } 
#endif // !PLATFORM_UNIX
                else if ((idx+2) <= length) { 
                    char first  = pUriString[idx]; 
                    char second = pUriString[idx+1];
 
                    if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) {
                        // (V1.0 compatiblity) This will allow http:\\ http:\/ http:/\
#if !PLATFORM_UNIX
                        if ((first == '/' || first == '\\') && (second == '/' || second == '\\')) 
#else
                        if (first == '/' && second == '/') 
#endif // !PLATFORM_UNIX 
                        {
                            m_Flags |= Flags.AuthorityFound; 
                            idx+=2;
                        }
                        else {
                            return ParsingError.BadAuthority; 
                        }
                    } 
                    else if (m_Syntax.InFact(UriSyntaxFlags.OptionalAuthority) && (InFact(Flags.AuthorityFound) || (first == '/' && second == '/'))) { 
                        m_Flags |= Flags.AuthorityFound;
                        idx+=2; 
                    }
                    else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) {
                        // There is no Authority component, save the Path index
                        // 
                        m_Flags |= ((Flags)idx | Flags.UnknownHostType);
                        return ParsingError.None; 
                    } 
                }
                else if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) { 
                    return ParsingError.BadAuthority;
                }
                else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) {
                    // There is no Authority component, save the Path index 
                    //
                    m_Flags |= ((Flags)idx | Flags.UnknownHostType); 
                    return ParsingError.None; 
                }
 
#if !PLATFORM_UNIX
                // The following sample taken from the original parser comments makes the whole story sad
                // vsmacros://c:\path\file
                // Note that two slashes say there must be an Authority but instead the path goes 
                // Fro V1 compat the next block allow this case but not for schemes like http
                if (InFact(Flags.DosPath)) { 
 
                    m_Flags |= (((m_Flags & Flags.AuthorityFound)!= 0)? Flags.BasicHostType :Flags.UnknownHostType);
                    m_Flags |= (Flags)idx; 
                    return ParsingError.None;
                }
#endif // !PLATFORM_UNIX
 
                //STEP 2: Check the syntax of authority expecting at least one character in it
                // 
                // Note here we do know that there is an authority in the string OR it's a DOS path 

                // We may find a userInfo and the port when parsing an authority 
                // Also we may find a registry based authority.
                // We must ensure that known schemes do use a server-based authority
            {
                ParsingError err = ParsingError.None; 
                idx = CheckAuthorityHelper(pUriString, idx, (ushort)length, ref err, ref m_Flags, m_Syntax, ref newHost);
                if (err != ParsingError.None) 
                    return err; 

                // This will disallow '\' as the host terminator for any scheme that is not implicitFile or cannot have a Dos Path 
                if ((idx < (ushort)length && pUriString[idx] == '\\') && NotAny(Flags.ImplicitFile) && m_Syntax.NotAny(UriSyntaxFlags.AllowDOSPath))
                    return ParsingError.BadAuthorityTerminator;

            } 

                // The Path (or Port) parsing index is reloaded on demand in CreateUriInfo when accessing a Uri property 
                m_Flags |= (Flags)idx; 

                // The rest of the string will be parsed on demand 
                // The Host/Authorty is all checked, the type is known but the host value string
                // is not created/canonicalized at this point.
            }
 
            if((s_IdnScope != UriIdnScope.None) || m_iriParsing)
                PrivateParseMinimalIri(newHost, idx); 
 
            return ParsingError.None;
        } 

        private void PrivateParseMinimalIri(string newHost, ushort idx)
        {
            // we have a new host! 
            if (newHost != null)
                m_String = newHost; 
 
            // conditions where we dont need to go to parseremaining, so we copy the rest of the
            // original string.. and switch offsets 
            if ((!m_iriParsing && AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))) ||
                (m_iriParsing && ((m_Flags & Flags.HasUnicode) == 0) && AllowIdn && ((m_Flags & Flags.IdnHost) != 0))){
                // update the start of path from the end of new string
                m_Flags &= ~(Flags.IndexMask); 
                m_Flags |= (Flags)m_String.Length;
 
                m_String += m_originalUnicodeString.Substring(idx, m_originalUnicodeString.Length - idx); 
            }
 
            // Indicate to createuriinfo that offset is in m_originalUnicodeString
            if (m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0)){
                // offset in Flags.IndexMask refers to m_originalUnicodeString
                m_Flags |= Flags.UseOrigUncdStrOffset; 
            }
        } 
 
        //
        // 
        // The method is called when we have to access m_Info members
        // This will create the m_Info based on the copied parser context
        // Under milti-threading ---- this method may do duplicated yet harmless work
        // 
        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)m_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 (IsLWS(m_String[idx])) { 
                    ++idx;
                    ++info.Offset.Scheme; 
                } 

#if !PLATFORM_UNIX 
                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) && (m_String[idx] == '/' || m_String[idx] == '\\')) {
                        ++idx; 
                    } 
                }
#endif // !PLATFORM_UNIX 
            }
            else {
                // This is NOT an ImplicitFile uri
                idx = (ushort)m_Syntax.SchemeName.Length; 

                while (m_String[idx++] != ':') { 
                    ++info.Offset.Scheme; 
                }
 
                if ((cF & Flags.AuthorityFound) != 0)
                {
                    if (m_String[idx] == '\\' || m_String[idx+1] == '\\')
                        notCanonicalScheme = true; 

                    idx+=2; 
#if !PLATFORM_UNIX 
                    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) && (m_String[idx] == '/' || m_String[idx] == '\\')) {
                            notCanonicalScheme = true;
                            ++idx; 
                        }
                    } 
#endif // !PLATFORM_UNIX 
                }
            } 

            // This is weird but some schemes (mailto) do not have Authority-based syntax, still they do have a port
            if (m_Syntax.DefaultPort != UriParser.NoDefaultPort)
                info.Offset.PortValue = (ushort)m_Syntax.DefaultPort; 

            //Here we set the indexes for already parsed components 
            if ((cF & Flags.HostTypeMask) == Flags.UnknownHostType 
#if !PLATFORM_UNIX
                || StaticInFact(cF, Flags.DosPath) 
#endif // !PLATFORM_UNIX
                ) {
                //there is no Authotity 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 (m_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_[....] 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)m_originalUnicodeString.Length;

            if (idx < info.Offset.End ){
                fixed (char* userString = UseOrigUnicodeStrOffset ? m_originalUnicodeString : m_String){ 
                    if (userString[idx] == ':'){
                        int port = 0; 
 
                        //Check on some noncanonical 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; 
/*********
            // The spinlock would be better than below lock but it's too late for Beta2, consider for RTM 
            // Also DON'T forget to check EnsureUriInfo method 
            int copyF = m_Flags;
            while ((copyF & Flags.MinimalUriInfoSet) == 0) 
            {
               if (copyF != (copyF = Interlocked.CompareExchange(ref m_Flags, cF | (copyF & ~Flags.IndexMask), copyF))
                   continue;
               m_Info  = info; 
            }
*********/ 
            info.DnsSafeHost = m_DnsSafeHost; 
            lock (m_String)
            { 
                if (( m_Flags & Flags.MinimalUriInfoSet) == 0)
                {
                    m_Info  = info;
                    m_Flags = (m_Flags & ~Flags.IndexMask) | cF; 
                }
            } 
 
        }
 
        //
        // This will create a Host string. The validity has been already checked
        //
        // Assuming: UriInfo memeber is already set at this point 
        private unsafe void CreateHostString() {
            // 
            // Mutlithrreading! 
            //
            if (!m_Syntax.IsSimple) 
            {
                lock (m_Info)
                {
                    // ATTN: Avoid possible recursion through CreateHostString->Syntax.GetComponents->Uri.GetComponentsHelper->CreateHostString 
                    if (NotAny(Flags.ErrorOrParsingRecursion))
                    { 
                        m_Flags |= Flags.ErrorOrParsingRecursion; 
                        // Need to get host string through the derived type
                        GetHostViaCustomSyntax(); 
                        m_Flags &= ~Flags.ErrorOrParsingRecursion;
                        return;
                    }
                } 
            }
            Flags flags = m_Flags; 
            string host = CreateHostStringHelper(m_String, m_Info.Offset.Host, m_Info.Offset.Path, ref flags, ref m_Info.ScopeId); 

            // now check on canonical host representation 
            if (host.Length != 0)
            {
                // An Authority may need escaping except when it's an inet server address
                // 
                // We do not escape UNC names and will get rid of this type when switching to IDN spec
                // 
                if (HostType == Flags.BasicHostType) { 
                    ushort idx = 0;
                    Check result; 
                    fixed (char* pHost = host) {
                        result = CheckCanonical(pHost, ref idx, (ushort)host.Length, c_DummyChar);
                    }
 
                    if ((result & Check.DisplayCanonical) == 0) {
                        // For implicit file the user string must be in perfect display format, 
                        // Hence, ignoring complains from CheckCanonical() 
                        if (NotAny(Flags.ImplicitFile) || (result & Check.ReservedFound) != 0) {
                            flags |= Flags.HostNotCanonical; 
                        }
                    }

                    if (InFact(Flags.ImplicitFile) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0) { 
                        // need to re-escape this host if any escaped sequence was found
                        result &= ~Check.EscapedCanonical; 
                    } 

                    if ((result & (Check.EscapedCanonical|Check.BackslashInPath)) != Check.EscapedCanonical) { 
                        // we will make a canonical host in m_Info.Host, but mark that m_String holds wrong data
                        flags |= Flags.E_HostNotCanonical;
                        if (NotAny(Flags.UserEscaped))
                        { 
                            int position = 0;
                            char[] dest = EscapeString(host, 0, host.Length, null, ref position, true, '?', '#', IsImplicitFile? c_DummyChar: '%'); 
                            if ((object)dest != null) 
                                host = new string(dest, 0, position);
                        } 
                        else {
                            //

                        } 
                    }
                } 
                else if (NotAny(Flags.CanonicalDnsHost)){ 
                    // Check to see if we can take the canonical host string out of m_String
                    if ((object)m_Info.ScopeId != null) { 
                        // IPv6 ScopeId is included when serializing a Uri
                        flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical);
                    }
                    else for (ushort i=0 ; i < host.Length; ++i) { 
                             if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || host[i] != m_String[m_Info.Offset.Host + i]) {
                                 flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical); 
                                 break; 
                             }
                         } 
                }
            }

            m_Info.Host = host; 
            lock (m_Info)
            { 
                m_Flags |= flags; 
            }
        } 
        //
        private static string CreateHostStringHelper(string str, ushort idx, ushort end, ref Flags flags, ref string scopeId)
        {
            bool loopback = false; 
            string host;
            switch (flags & Flags.HostTypeMask) { 
 
                case Flags.DnsHostType:
                    host = DomainNameHelper.ParseCanonicalName(str, idx, end, ref loopback); 
                    break;

                case Flags.IPv6HostType:
                    //[....] codereview 
                    // The helper will return [...] string that is not suited for Dns.Resolve()
                    host = IPv6AddressHelper.ParseCanonicalName(str, idx, ref loopback, ref scopeId); 
                    break; 

                case Flags.IPv4HostType: 
                    host = IPv4AddressHelper.ParseCanonicalName(str, idx, end, ref loopback);
                    break;

#if !PLATFORM_UNIX 
                case Flags.UncHostType:
                    host = UncNameHelper.ParseCanonicalName(str, idx, end, ref loopback); 
                    break; 
#endif // !PLATFORM_UNIX
 
                case Flags.BasicHostType:
#if !PLATFORM_UNIX
                    if (StaticInFact(flags, Flags.DosPath)) {
                        host = string.Empty; 
                    }
                    else 
#endif // !PLATFORM_UNIX 
                    {
                        // This is for a registry-based authority, not relevant for known schemes 
                        host = str.Substring(idx, end-idx);
                    }
                    // A empty host would count for a loopback
                    if (host.Length == 0) { 
                        loopback = true;
                    } 
                    //there will be no port 
                    break;
 
                case Flags.UnknownHostType:
                    //means the host is *not expected* for this uri type
                    host = string.Empty;
                    break; 

                default: //it's a bug 
                    throw GetException(ParsingError.BadHostName); 
            }
 
            if (loopback) {
                flags |= Flags.LoopbackHost;
            }
            return host; 
        }
        // 
        // Called under lock() 
        //
        private unsafe void GetHostViaCustomSyntax() 
        {
            // A multithreading check
            if (m_Info.Host != null)
                return; 

            string host = m_Syntax.InternalGetComponents(this, UriComponents.Host, UriFormat.UriEscaped); 
 
            // ATTN: Check on whether recursion has not happened
            if ((object)m_Info.Host == null) 
            {
                if (host.Length >= c_MaxUriBufferSize)
                    throw GetException(ParsingError.SizeLimit);
 
                ParsingError err = ParsingError.None;
                Flags flags = m_Flags & ~Flags.HostTypeMask; 
 
                fixed (char *pHost = host)
                { 
                    string newHost = null;
                    if (CheckAuthorityHelper(pHost, 0, (ushort)host.Length, ref err, ref flags, m_Syntax, ref newHost) != (ushort)host.Length)
                    {
                        // We cannot parse the entire host string 
                        flags &= ~Flags.HostTypeMask;
                        flags |= Flags.UnknownHostType; 
                    } 
                }
 
                if (err != ParsingError.None || (flags & Flags.HostTypeMask) == Flags.UnknownHostType)
                {
                    // Well, custom parser has returned a not known host type, take it as Basic then.
                    m_Flags = (m_Flags & ~Flags.HostTypeMask) | Flags.BasicHostType; 
                }
                else 
                { 
                    host = CreateHostStringHelper(host, 0, (ushort)host.Length, ref flags, ref m_Info.ScopeId);
                    for (ushort i=0 ; i < host.Length; ++i) { 
                             if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || host[i] != m_String[m_Info.Offset.Host + i]) {
                                 m_Flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical);
                                 break;
                             } 
                         }
                    m_Flags = (m_Flags & ~Flags.HostTypeMask) | (flags & Flags.HostTypeMask); 
                } 
            }
            // 
            // This is a chance for a custom parser to report a different port value
            //
            string portStr = m_Syntax.InternalGetComponents(this, UriComponents.StrongPort, UriFormat.UriEscaped);
            int port = 0; 
            if ((object)portStr == null || portStr.Length == 0)
            { 
                // It's like no port 
                m_Flags &= ~Flags.NotDefaultPort;
                m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); 
                m_Info.Offset.PortValue = 0;
            }
            else
            { 
                for (int idx=0; idx < portStr.Length; ++idx)
                { 
                    int val = portStr[idx] - '0'; 
                    if (val < 0 || val > 9 || (port = (port * 10 + val)) > 0xFFFF)
                        throw new UriFormatException(SR.GetString(SR.net_uri_PortOutOfRange, m_Syntax.GetType().FullName, portStr)); 
                }
                if (port != m_Info.Offset.PortValue)
                {
                    if (port == m_Syntax.DefaultPort) 
                        m_Flags &= ~Flags.NotDefaultPort;
                    else 
                        m_Flags |= Flags.NotDefaultPort; 

                    m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); 
                    m_Info.Offset.PortValue = (ushort) port;
                }
            }
            // This must be done as the last thing in this method 
            m_Info.Host = host;
        } 
        // 
        // An internal shortcut into Uri extenisiblity API
        // 
        internal string GetParts(UriComponents uriParts, UriFormat formatAs)
        {
            return GetComponents(uriParts, formatAs);
        } 

        // 
        // 
        //
        private string GetEscapedParts(UriComponents uriParts) { 
            // Which Uri parts are not escaped canonically ?
            // Notice that public UriPart and private Flags must me in [....] so below code can work
            //
            ushort  nonCanonical = (ushort)(((ushort)m_Flags & ((ushort)Flags.CannotDisplayCanonical<<7)) >> 6); 
            if (InFact(Flags.SchemeNotCanonical)) {
                nonCanonical |= (ushort)Flags.SchemeNotCanonical; 
            } 

            // We keep separate flags for some of path canonicalization facts 
            if ((uriParts & UriComponents.Path) != 0) {
                if (InFact(Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) {
                    nonCanonical |= (ushort)Flags.PathNotCanonical;
                } 
                else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') {
                    // A rare case of c|\ 
                    nonCanonical |= (ushort)Flags.PathNotCanonical; 
                }
            } 

            if (((ushort)uriParts & nonCanonical) == 0) {
                string ret = GetUriPartsFromUserString(uriParts);
                if ((object)ret != null) { 
                    return ret;
                } 
            } 

            return ReCreateParts(uriParts, nonCanonical, UriFormat.UriEscaped); 
        }

        private string GetUnescapedParts(UriComponents uriParts, UriFormat formatAs) {
            // Which Uri parts are not escaped canonically ? 
            // Notice that public UriComponents and private Uri.Flags must me in [....] so below code can work
            // 
            ushort  nonCanonical = (ushort)((ushort)m_Flags & (ushort)Flags.CannotDisplayCanonical); 

            // We keep separate flags for some of path canonicalization facts 
            if ((uriParts & UriComponents.Path) != 0) {
                if ((m_Flags & (Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) !=0) {
                    nonCanonical |= (ushort)Flags.PathNotCanonical;
                } 
                else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') {
                    // A rare case of c|\ 
                    nonCanonical |= (ushort)Flags.PathNotCanonical; 
                }
 
            }

            if (((ushort)uriParts & nonCanonical) == 0) {
                string ret = GetUriPartsFromUserString(uriParts); 
                if ((object)ret != null) {
                    return ret; 
                } 
            }
 
            return ReCreateParts(uriParts, nonCanonical, formatAs);
        }

        // 
        //
        // 
        private string ReCreateParts(UriComponents parts, ushort nonCanonical, UriFormat formatAs) 
        {
            // going hard core 
            EnsureHostString(false);
            string stemp = (parts & UriComponents.Host) == 0? string.Empty: m_Info.Host;
            // we reserve more space than required because a canonical Ipv6 Host
            // may take more characteres than in original m_String 
            // Also +3 is for :// and +1 is for absent first slash
            // Also we may escape every character, hence multiplying by 6 
            int count = (m_Info.Offset.End-m_Info.Offset.User) * (formatAs == UriFormat.UriEscaped?6:1); 
            char[] chars = new char[stemp.Length + count + m_Syntax.SchemeName.Length + 3 + 1];
            count = 0; 

            //Scheme and slashes
            if ((parts & UriComponents.Scheme) != 0) {
                m_Syntax.SchemeName.CopyTo(0, chars, count, m_Syntax.SchemeName.Length); 
                count += m_Syntax.SchemeName.Length;
                if (parts != UriComponents.Scheme) { 
                    chars[count++] = ':'; 
                    if (InFact(Flags.AuthorityFound)) {
                        chars[count++] = '/'; 
                        chars[count++] = '/';
                    }
                }
            } 

            //UserInfo 
            if ((parts & UriComponents.UserInfo) != 0 && InFact(Flags.HasUserInfo)) 
            {
                if ((nonCanonical & (ushort)UriComponents.UserInfo) != 0) { 
                    switch (formatAs) {
                        case UriFormat.UriEscaped:
                            if (NotAny(Flags.UserEscaped))
                            { 
                                chars = EscapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, true, '?', '#', '%');
                            } 
                            else { 
                                if (InFact(Flags.E_UserNotCanonical)) {
                                    // 

                                }
                                m_String.CopyTo(m_Info.Offset.User, chars, count, m_Info.Offset.Host - m_Info.Offset.User);
                                count += (m_Info.Offset.Host - m_Info.Offset.User); 
                            }
                            break; 
 
                        case UriFormat.SafeUnescaped:
                            chars = UnescapeString( m_String, m_Info.Offset.User, m_Info.Offset.Host-1, chars, ref count, '@', '/', '\\', 
                                                    InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape,
                                                    m_Syntax, false, false);
                            chars[count++] = '@';
                            break; 

                        case UriFormat.Unescaped: 
                            chars = UnescapeString( m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, c_DummyChar, 
                                                    c_DummyChar, c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll,
                                                    m_Syntax, false, false); 
                            break;

                        default: //V1ToStringUnescape
                            chars = UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, c_DummyChar, 
                                                    c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false);
                            break; 
                    } 
                }
                else { 
                    UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count,
                        c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false);
                }
                if (parts == UriComponents.UserInfo) 
                {
                    //strip '@' delimiter 
                    --count; 
                }
            } 

            // Host
            if ((parts & UriComponents.Host) != 0 && stemp.Length != 0)
            { 
                UnescapeMode mode;
                if (formatAs != UriFormat.UriEscaped && HostType == Flags.BasicHostType && (nonCanonical & (ushort)UriComponents.Host) != 0) { 
                    // only Basic host could be in the escaped form 
                    mode = formatAs == UriFormat.Unescaped? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll):
                                            (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape); 

                }
                else {
                    mode = UnescapeMode.CopyOnly; 
                }
                chars = UnescapeString(stemp, 0, stemp.Length, chars, ref count, '/', '?', '#', mode, m_Syntax, false, false); 
 

                // A fix up only for SerializationInfo and IpV6 host with a scopeID 
                if ((parts & UriComponents.SerializationInfoString) != 0 && HostType == Flags.IPv6HostType && (object)m_Info.ScopeId != null)
                {
                    m_Info.ScopeId.CopyTo(0, chars, count-1, m_Info.ScopeId.Length);
                    count += m_Info.ScopeId.Length; 
                    chars[count-1] = ']';
                } 
            } 

            //Port (always wants a ':' delimiter if got to this method) 
            if ((parts & UriComponents.Port) != 0)
            {
                if ((nonCanonical & (ushort)UriComponents.Port) == 0) {
                    //take it from m_String 
                    if (InFact(Flags.NotDefaultPort)) {
                        ushort start = m_Info.Offset.Path; 
                        while (m_String[--start] != ':') { 
                            ;
                        } 
                        m_String.CopyTo(start, chars, count, m_Info.Offset.Path - start);
                        count += (m_Info.Offset.Path - start);
                    }
                    else if ((parts & UriComponents.StrongPort) != 0 && m_Syntax.DefaultPort != UriParser.NoDefaultPort) { 
                        chars[count++]= ':';
                        stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); 
                        stemp.CopyTo(0, chars, count, stemp.Length); 
                        count += stemp.Length;
                    } 
                }
                else if (InFact(Flags.NotDefaultPort) || ((parts & UriComponents.StrongPort) != 0 && m_Syntax.DefaultPort != UriParser.NoDefaultPort)) {
                    // recreate string from port value
                    chars[count++]= ':'; 
                    stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture);
                    stemp.CopyTo(0, chars, count, stemp.Length); 
                    count += stemp.Length; 
                }
            } 

            ushort delimiterAwareIndex;

            //Path 
            if ((parts & UriComponents.Path) != 0)
            { 
                chars = GetCanonicalPath(chars, ref count, formatAs); 

                // (possibly strip the leading '/' delimiter) 
                if (parts == UriComponents.Path)
                {
                    if (InFact(Flags.AuthorityFound) && count !=0 && chars[0] == '/')
                    { 
                        delimiterAwareIndex = 1; --count;
                    } 
                    else 
                    {
                        delimiterAwareIndex = 0; 
                    }
                    return count == 0? string.Empty: new string(chars, delimiterAwareIndex, count);
                }
            } 

            //Query (possibly strip the '?' delimiter) 
            if ((parts & UriComponents.Query) != 0 && m_Info.Offset.Query < m_Info.Offset.Fragment) 
            {
                delimiterAwareIndex = (ushort)(m_Info.Offset.Query+1); 
                if(parts != UriComponents.Query)
                    chars[count++] = '?';   //see Fragment+1 below

                if ((nonCanonical & (ushort)UriComponents.Query) != 0) 
                {
                    switch (formatAs) 
                    { 
                    case UriFormat.UriEscaped:
                        //Can Assert IsImplicitfile == false 
                        if (NotAny(Flags.UserEscaped))
                            chars = EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, true,  '#', c_DummyChar, '%');
                        else
                        { 
                            //
 
 
                            UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count,
                                c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, true, false); 
                        }
                        break;

                    case V1ToStringUnescape: 

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, 
                                               m_Syntax, true, false);
                        break; 

                    case UriFormat.Unescaped:

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (UnescapeMode.Unescape| UnescapeMode.UnescapeAll), m_Syntax, true, false);
                        break; 
 
                    default: // UriFormat.SafeUnescaped
 
                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar,
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, true, false);
                        break;
                    } 
                }
                else 
                { 
                    UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar,
                                    UnescapeMode.CopyOnly, m_Syntax, true, false); 
                }
            }

            //Fragment (possibly strip the '#' delimiter) 
            if ((parts & UriComponents.Fragment) != 0 && m_Info.Offset.Fragment < m_Info.Offset.End)
            { 
                delimiterAwareIndex = (ushort)(m_Info.Offset.Fragment+1); 
                if(parts != UriComponents.Fragment)
                    chars[count++] = '#';   //see Fragment+1 below 

                if ((nonCanonical & (ushort)UriComponents.Fragment) != 0)
                {
                    switch (formatAs) { 
                    case UriFormat.UriEscaped:
                            if (NotAny(Flags.UserEscaped)) 
                                chars = EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, true, '#', c_DummyChar, '%'); 
                            else
                            { 
                                //


                                UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar, 
                                                UnescapeMode.CopyOnly, m_Syntax, false, false);
                            } 
                            break; 

                    case V1ToStringUnescape: 

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar,
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, m_Syntax, false, false);
                        break; 
                    case UriFormat.Unescaped:
 
                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               UnescapeMode.Unescape | UnescapeMode.UnescapeAll, m_Syntax, false, false);
                        break; 

                    default: // UriFormat.SafeUnescaped

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, false, false);
                        break; 
                    } 
                }
                else 
                {
                    UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar,
                                    UnescapeMode.CopyOnly, m_Syntax, false, false);
                } 
            }
 
            return new string(chars, 0, count); 
        }
 
        //
        // This method is called only if the user string has a canonical representation
        // of requested parts
        // 
        private string GetUriPartsFromUserString(UriComponents uriParts) {
 
            ushort delimiterAwareIdx; 

            switch (uriParts & ~UriComponents.KeepDelimiter) { 
                    // For FindServicePoint perf
                case UriComponents.Scheme | UriComponents.Host | UriComponents.Port:
                    if (!InFact(Flags.HasUserInfo))
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme); 

                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                         + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); 

                    // For HttpWebRequest.ConnectHostAndPort perf 
                case UriComponents.HostAndPort:  //Host|StrongPort

                    if (!InFact(Flags.HasUserInfo))
                        goto case UriComponents.StrongAuthority; 

                    if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort) 
                        return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); 

                    return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host) 
                        + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture);

                    // For an obvious common case perf
                case UriComponents.AbsoluteUri:     //Scheme|UserInfo|Host|Port|Path|Query|Fragment, 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length)
                        return m_String; 
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme);
 
                    // For Uri.Equals() and HttpWebRequest through a proxy perf
                case UriComponents.HttpRequestUrl:   //Scheme|Host|Port|Path|Query,
                    if (InFact(Flags.HasUserInfo)) {
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                            + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Fragment - m_Info.Offset.Host);
                    } 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) 
                        return m_String;
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme);

                    // For CombineUri() perf
                case UriComponents.SchemeAndServer|UriComponents.UserInfo: 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme);
 
                    // For Cache perf 
                case (UriComponents.AbsoluteUri & ~UriComponents.Fragment):
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) 
                        return m_String;

                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme);
 

                // Strip scheme delimiter if was not requested 
                case UriComponents.Scheme: 
                        if (uriParts != UriComponents.Scheme)
                            return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme); 

                        return m_Syntax.SchemeName;

                // KeepDelimiter makes no sense for this component 
                case UriComponents.Host:
                    ushort idx = m_Info.Offset.Path; 
                    if (InFact(Flags.NotDefaultPort|Flags.PortNotCanonical)) { 
                        //Means we do have ':' after the host
                        while (m_String[--idx] != ':') 
                            ;
                    }
                    return (idx - m_Info.Offset.Host == 0)? string.Empty: m_String.Substring(m_Info.Offset.Host, idx - m_Info.Offset.Host);
 
                case UriComponents.Path:
 
                    // Strip the leading '/' for a hierarchical URI if no delimiter was requested 
                    if (uriParts == UriComponents.Path && InFact(Flags.AuthorityFound) && m_Info.Offset.End > m_Info.Offset.Path &&  m_String[m_Info.Offset.Path] == '/')
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Path + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Path;

                    if (delimiterAwareIdx >= m_Info.Offset.Query) 
                        return string.Empty;
 
 
                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Query - delimiterAwareIdx);
 
                case UriComponents.Query:
                    // Strip the '?' if no delimiter was requested
                    if (uriParts == UriComponents.Query)
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Query + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Query; 
 
                    if (delimiterAwareIdx >= m_Info.Offset.Fragment)
                        return string.Empty; 

                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Fragment - delimiterAwareIdx);

                case UriComponents.Fragment: 
                    // Strip the '#' if no delimiter was requested
                    if (uriParts == UriComponents.Fragment) 
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Fragment + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Fragment; 

                    if (delimiterAwareIdx >= m_Info.Offset.End)
                        return string.Empty;
 
                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.End - delimiterAwareIdx);
 
                case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port: 
                    return (m_Info.Offset.Path - m_Info.Offset.User == 0)? string.Empty: m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User);
 
                case UriComponents.StrongAuthority:  //UserInfo|Host|StrongPort
                    if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort)
                        goto case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port;
 
                    return m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User)
                        + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); 
 
                case UriComponents.PathAndQuery:        //Path|Query,
                    return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.Fragment - m_Info.Offset.Path); 

                case UriComponents.HttpRequestUrl|UriComponents.Fragment: //Scheme|Host|Port|Path|Query|Fragment,
                    if (InFact(Flags.HasUserInfo)) {
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                            + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.End - m_Info.Offset.Host);
                    } 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length) 
                        return m_String;
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme);

                case UriComponents.PathAndQuery|UriComponents.Fragment:  //LocalUrl|Fragment
                    return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.End - m_Info.Offset.Path); 

                case UriComponents.UserInfo: 
                        // Strip the '@' if no delimiter was requested 

                    if (NotAny(Flags.HasUserInfo)) 
                        return string.Empty;

                    if (uriParts == UriComponents.UserInfo)
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Host - 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Host; 
 
                    if (m_Info.Offset.User >= delimiterAwareIdx)
                        return string.Empty; 

                    return m_String.Substring(m_Info.Offset.User, delimiterAwareIdx - m_Info.Offset.User);

                default: 
                    return null;
            } 
        } 

 
        //
        //This method does:
        //  - Creates m_Info member
        //  - checks all componenets up to path on their canonical representation 
        //  - continues parsing starting the path position
        //  - Sets the offsets of remaining components 
        //  - Sets the Canonicalization flags if applied 
        //  - Will NOT create MoreInfo members
        // 
        private unsafe void ParseRemaining() {

            // ensure we parsed up to the path
            EnsureUriInfo(); 

            Flags cF = Flags.Zero; 
 
            if (UserDrivenParsing)
                goto Done; 

            // Do we have to continue building Iri'zed string from original string
            bool buildIriStringFromPath = m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0) && ((m_Flags & Flags.RestUnicodeNormalized) == 0);
 
            ushort origIdx;     // stores index to switched original string
            ushort idx = m_Info.Offset.Scheme; 
            ushort length = (ushort)m_String.Length; 
            Check result = Check.None;
            UriSyntaxFlags syntaxFlags = m_Syntax.Flags;    // perf 

            // Multithreading!
            // m_Info.Offset values may be parsed twice but we lock only on m_Flags update.
 
            fixed (char* str = m_String){
                // Cut trailing spaces in m_String 
                if (length > idx && IsLWS(str[length - 1])) 
                {
                    --length; 
                    while (length != idx && IsLWS(str[--length]))
                        ;
                    ++length;
                } 

                if (IsImplicitFile){ 
                    cF |= Flags.SchemeNotCanonical; 
                }
                else { 
                    ushort i = 0;
                    ushort syntaxLength = (ushort)m_Syntax.SchemeName.Length;
                    for (; i < syntaxLength; ++i)
                    { 
                        if (m_Syntax.SchemeName[i] != str[idx + i])
                            cF |= Flags.SchemeNotCanonical; 
                    } 
                    // For an authority Uri only // after the scheme would be canonical
                    // (compatibility bug http:\\host) 
                    if (((m_Flags & Flags.AuthorityFound) != 0) && (idx + i + 3 >= length || str[idx + i + 1] != '/' || str[idx + i + 2] != '/')){
                        cF |= Flags.SchemeNotCanonical;
                    }
                } 

 
                //Check the form of the user info 
                if ((m_Flags & Flags.HasUserInfo) != 0){
                    idx = m_Info.Offset.User; 
                    result = CheckCanonical(str, ref idx, m_Info.Offset.Host, '@');
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.UserNotCanonical;
                    } 
                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){
                        cF |= Flags.E_UserNotCanonical; 
                    } 
                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath
                                                    | Check.FoundNonAscii | Check.NotIriCanonical)) 
                                                    == (Check.DisplayCanonical | Check.FoundNonAscii))){
                        cF |= Flags.UserIriCanonical;
                    }
                } 
            }
            // 
            // Delay canonical Host checking to avoid creation of a host string 
            // Will do that on demand.
            // 


            //
            //We have already checked on the port in EnsureUriInfo() that calls CreateUriInfo 
            //
 
            // 
            // Parsing the Path if any
            // 

            // For iri parsing if we found unicode the idx has offset into m_[....] string..
            // so restart parsing from there and make m_Info.Offset.Path as m_string.length
 
            idx = m_Info.Offset.Path;
            origIdx = m_Info.Offset.Path; 
 
            //Some uris do not have a query
            //    When '?' is passed as delimiter, then it's special case 
            //    so both '?' and '#' will work as delimiters
            if (buildIriStringFromPath){
                m_Info.Offset.Path = (ushort)m_String.Length;
                idx = m_Info.Offset.Path; 

                ushort offset = origIdx; 
                if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ 
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_DummyChar);
                } 
                else{
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length,
                   (m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL));
                } 

                // Correctly escape unescape 
                string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Path); 

                // Normalize path 
                try{
                    m_String += escapedPath.Normalize(NormalizationForm.FormC);
                }
                catch (ArgumentException){ 
                    UriFormatException e = GetException(ParsingError.BadFormat);
                    throw e; 
                } 

                length = (ushort)m_String.Length; 
            }

            fixed (char* str = m_String){
                if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ 
                    result = CheckCanonical(str, ref idx, length, c_DummyChar);
                } 
                else { 
                    result = CheckCanonical(str, ref idx, length, (((syntaxFlags & UriSyntaxFlags.MayHaveQuery) != 0) ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL));
                } 

                // ATTN:
                // This may render problems for unknown schemes, but in general for an authority based Uri
                // (that has slashes) a path should start with "/" 
                // This becomes more interesting knowning how a file uri is used in "file://c:/path"
                // It will be converted to file:///c:/path 
                // 
                // However, even more interesting is that vsmacros://c:\path will not add the third slash in the _canoical_ case
                // (vsmacros inventors have violated the RFC) 
                //
                // We use special syntax flag to check if the path is rooted, i.e. has a first slash
                //
                if (((m_Flags & Flags.AuthorityFound) != 0) && ((syntaxFlags & UriSyntaxFlags.PathIsRooted) != 0) 
                    && (m_Info.Offset.Path == length || (str[m_Info.Offset.Path] != '/' && str[m_Info.Offset.Path] != '\\'))){
                    cF |= Flags.FirstSlashAbsent; 
                } 
            }
            // Check the need for compression or backslashes conversion 
            // we included IsDosPath since it may come with other than FILE uri, for ex. scheme://C:\path
            // (This is very unfortunate that the original design has included that feature)
            bool nonCanonical = false;
            if (IsDosPath || (((m_Flags & Flags.AuthorityFound) != 0) && ((syntaxFlags & (UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.UnEscapeDotsAndSlashes)) != 0))) 
            {
                if (((syntaxFlags & (UriSyntaxFlags.UnEscapeDotsAndSlashes)) != 0) && (result & Check.DotSlashEscaped) != 0){ 
                    cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical); 
                    nonCanonical = true;
                } 

                if (((syntaxFlags & (UriSyntaxFlags.ConvertPathSlashes)) != 0) && (result & Check.BackslashInPath) != 0){
                    cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical);
                    nonCanonical = true; 
                }
 
                if (((syntaxFlags & (UriSyntaxFlags.CompressPath)) != 0) && ((cF & Flags.E_PathNotCanonical) != 0 || (result & Check.DotSlashAttn) != 0)) 
                    cF |= Flags.ShouldBeCompressed;
 
                if ((result & Check.BackslashInPath) != 0)
                    cF |= Flags.BackslashInPath;

            } 
            else if ((result & Check.BackslashInPath) != 0){
                // for a "generic" path '\' should be escaped 
                cF |= Flags.E_PathNotCanonical; 
                nonCanonical = true;
            } 

            if ((result & Check.DisplayCanonical) == 0){
                // For implicit file the user string is usually in perfect display format,
                // Hence, ignoring complains from CheckCanonical() 
                //
 
                if (((m_Flags & Flags.ImplicitFile) == 0) || ((m_Flags & Flags.UserEscaped) != 0) || (result & Check.ReservedFound) != 0){ 
                    //means it's found as escaped or has unescaped Reserved Characters
                    cF |= Flags.PathNotCanonical; 
                    nonCanonical = true;
                }
            }
 
            if (((m_Flags & Flags.ImplicitFile) != 0) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0){
                // need to escape reserved chars or re-escape '%' if an "escaped sequence" was found 
                result &= ~Check.EscapedCanonical; 
            }
 
            if ((result & Check.EscapedCanonical) == 0){
                //means it's found as not completely escaped
                cF |= Flags.E_PathNotCanonical;
            } 

            if (m_iriParsing && !nonCanonical & ((result & (Check.DisplayCanonical | Check.EscapedCanonical 
                            | Check.FoundNonAscii | Check.NotIriCanonical)) 
                            == (Check.DisplayCanonical | Check.FoundNonAscii))){
                cF |= Flags.PathIriCanonical; 
            }

            //
            //Now we've got to parse the Query if any. Note that Query requires the presence of '?' 
            //
           if (buildIriStringFromPath){ 
               ushort offset = origIdx; 

               if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '?'){ 
                   ++origIdx; // This is to exclude first '?' character from checking
                   FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, ((syntaxFlags &(UriSyntaxFlags.MayHaveFragment)) != 0) ? '#' : c_EOL);

                   // Correctly escape unescape 
                   string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Query);
 
                   // Normalize path 
                   try{
                       m_String += escapedPath.Normalize(NormalizationForm.FormC); 
                   }
                   catch (ArgumentException){
                       UriFormatException e = GetException(ParsingError.BadFormat);
                       throw e; 
                   }
 
                   length = (ushort)m_String.Length; 
               }
            } 

            m_Info.Offset.Query = idx;

            fixed (char* str = m_String){ 
                if (idx < length && str[idx] == '?'){
                    ++idx; // This is to exclude first '?' character from checking 
                    result = CheckCanonical(str, ref idx, length, ((syntaxFlags & (UriSyntaxFlags.MayHaveFragment)) != 0) ? '#' : c_EOL); 
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.QueryNotCanonical; 
                    }

                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){
                        cF |= Flags.E_QueryNotCanonical; 
                    }
 
                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath 
                                | Check.FoundNonAscii | Check.NotIriCanonical))
                                == (Check.DisplayCanonical | Check.FoundNonAscii))){ 
                        cF |= Flags.QueryIriCanonical;
                    }

                } 
            }
            // 
            //Now we've got to parse the Fragment if any. Note that Fragment requires the presense of '#' 
            //
            if (buildIriStringFromPath){ 
                ushort offset = origIdx;

                if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '#')
                { 
                    ++origIdx; // This is to exclude first '#' character from checking
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_EOL); 
 
                    // Correctly escape unescape
                    string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Fragment); 

                    // Normalize path
                    try{
                        m_String += escapedPath.Normalize(NormalizationForm.FormC); 
                    }
                    catch (ArgumentException){ 
                        UriFormatException e = GetException(ParsingError.BadFormat); 
                        throw e;
                    } 

                    length = (ushort)m_String.Length;
                }
            } 

            m_Info.Offset.Fragment = idx; 
 
            fixed (char* str = m_String){
                if (idx < length && str[idx] == '#'){ 
                    ++idx; // This is to exclude first '#' character from checking
                    result = CheckCanonical(str, ref idx, length, c_EOL);     //We don't using c_DummyChar since want to allow '?' and '#' as unescaped
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.FragmentNotCanonical; 
                    }
 
                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){ 
                        cF |= Flags.E_FragmentNotCanonical;
                    } 

                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath
                                | Check.FoundNonAscii | Check.NotIriCanonical))
                                == (Check.DisplayCanonical | Check.FoundNonAscii))){ 
                        cF |= Flags.FragmentIriCanonical;
                    } 
 
                }
            } 
                m_Info.Offset.End = idx;
        Done:

            cF |= Flags.AllUriInfoSet; 
            lock (m_Info)
            { 
                m_Flags |= cF; 
            }
            m_Flags |= Flags.RestUnicodeNormalized; 
        }

        //
        // 
        // verifies the syntax of the scheme part
        // Checks on implicit File: scheme due to simple Dos/Unc path passed 
        // returns the start of the next component  position 
        // throws UriFormatException if invalid scheme
        // 
        unsafe static private ushort ParseSchemeCheckImplicitFile(char *uriString, ushort length, ref ParsingError err, ref Flags flags, ref UriParser syntax) {

            ushort idx = 0;
 
            //skip whitespaces
            while(idx < length && IsLWS(uriString[idx])) { 
                ++idx; 
            }
 
            // sets the recognizer for well known registered schemes
            // file, ftp, http, https, uuid, etc
            // Note that we don't support one-letter schemes that will be put into a DOS path bucket
 
            //
            ushort end = idx; 
            while (end < length && uriString[end] != ':') { 
                ++end;
            } 

            // NB: On 64-bits we will use less optimized code from CheckSchemeSyntax()
            //
            if (IntPtr.Size == 4) { 
                // long = 4chars: The minimal size of a known scheme is 3 + ':'
                if (end != length && end >= idx+3 && CheckKnownSchemes((long*) (uriString + idx), (ushort)(end-idx), ref syntax)) { 
                    return (ushort)(end+1); 
                }
            } 

            //NB: A string must have at least 3 characters and at least 1 before ':'
            if (idx+2 >= length || end == idx) {
                err = ParsingError.BadFormat; 
                return 0;
            } 
 
            //Check for supported special cases like a DOS file path OR a UNC share path
            //NB: A string may not have ':' if this is a UNC path 
        {
            char c;
            if ((c=uriString[idx+1]) == ':' || c == '|') {
#if !PLATFORM_UNIX 
                //DOS-like path?
                if (IsAsciiLetter(uriString[idx])) { 
                    if((c=uriString[idx+2]) == '\\' || c== '/') { 
                        flags |= (Flags.DosPath|Flags.ImplicitFile|Flags.AuthorityFound);
                        syntax = UriParser.FileUri; 
                        return idx;
                    }
                    err = ParsingError.MustRootedPath;
                    return 0; 
                }
#endif // !PLATFORM_UNIX 
                if (c == ':') 
                    err = ParsingError.BadScheme;
                else 
                    err = ParsingError.BadFormat;
                return 0;
            }
#if !PLATFORM_UNIX 
            else if ((c=uriString[idx]) == '/' || c == '\\') {
                //UNC share ? 
                if ((c=uriString[idx+1]) == '\\' || c == '/') { 
                    flags |= (Flags.UncPath|Flags.ImplicitFile|Flags.AuthorityFound);
                    syntax = UriParser.FileUri; 
                    idx+=2;
                    // V1.1 compat this will simply eat any slashes prepended to a UNC path
                    while (idx < length && ((c=uriString[idx]) == '/' ||  c == '\\'))
                        ++idx; 

                    return idx; 
                } 
                err = ParsingError.BadFormat;
                return 0; 
            }
#else
            else if (uriString[idx] == '/') {
                // On UNIX an implicit file has the form / or scheme:/// 
                if (idx == 0 || uriString[idx-1] != ':' ) {
                    // No scheme present; implicit / starting at idx 
                    flags |= (Flags.ImplicitFile|Flags.AuthorityFound); 
                    syntax = UriParser.FileUri;
                    return idx; 
                } else if (uriString[idx+1] == '/' && uriString[idx+2] == '/') {
                    // scheme present; rooted path starts at idx + 2
                    flags |= (Flags.ImplicitFile|Flags.AuthorityFound);
                    syntax = UriParser.FileUri; 
                    idx+=2;
                    return idx; 
                } 
            }
            else if (uriString[idx] == '\\') { 
                err = ParsingError.BadFormat;
                return 0;
            }
#endif // !PLATFORM_UNIX 
        }
 
            if (end == length) { 
                err = ParsingError.BadFormat;
                return 0; 
            }

            // Here could be a possibly valid, and not well-known scheme
            // Finds the scheme delimiter 
            // we don;t work with the schemes names > c_MaxUriSchemeName (should be ~1k)
            if ((end-idx) > c_MaxUriSchemeName) { 
                err = ParsingError.SchemeLimit; 
                return 0;
            } 

            //Check the syntax, canonicalize  and avoid a GC call
            char* schemePtr = stackalloc char[end-idx];
            for (length = 0; idx < end; ++idx) { 
                schemePtr[length++] = uriString[idx];
            } 
            err = CheckSchemeSyntax(schemePtr, length, ref syntax); 
            if (err != ParsingError.None) {
                return 0; 
            }
            return (ushort)(end+1);
        }
        // 
        // Quickly parses well known schemes.
        // nChars does not include the last ':'. Assuming there is one at the end of passed buffer 
        unsafe static private bool CheckKnownSchemes(long *lptr, ushort nChars, ref UriParser syntax) { 
            //NOTE beware of too short input buffers!
 
            const long _HTTP_Mask0   = 'h'|('t'<<16)|((long)'t'<<32)|((long)'p'<<48);
            const char _HTTPS_Mask1  = 's';
            const long _FTP_Mask     = 'f'|('t'<<16)|((long)'p'<<32)|((long)':'<<48);
            const long _FILE_Mask0   = 'f'|('i'<<16)|((long)'l'<<32)|((long)'e'<<48); 
            const long _GOPHER_Mask0 = 'g'|('o'<<16)|((long)'p'<<32)|((long)'h'<<48);
            const int  _GOPHER_Mask1 = 'e'|('r'<<16); 
            const long _MAILTO_Mask0 = 'm'|('a'<<16)|((long)'i'<<32)|((long)'l'<<48); 
            const int  _MAILTO_Mask1 = 't'|('o'<<16);
            const long _NEWS_Mask0   = 'n'|('e'<<16)|((long)'w'<<32)|((long)'s'<<48); 
            const long _NNTP_Mask0   = 'n'|('n'<<16)|((long)'t'<<32)|((long)'p'<<48);
            const long _UUID_Mask0   = 'u'|('u'<<16)|((long)'i'<<32)|((long)'d'<<48);

            const long _TELNET_Mask0 = 't'|('e'<<16)|((long)'l'<<32)|((long)'n'<<48); 
            const int  _TELNET_Mask1 = 'e'|('t'<<16);
 
            const long _NETXXX_Mask0 = 'n'|('e'<<16)|((long)'t'<<32)|((long)'.'<<48); 
            const long _NETTCP_Mask1 = 't'|('c'<<16)|((long)'p'<<32)|((long)':'<<48);
            const long _NETPIPE_Mask1 = 'p'|('i'<<16)|((long)'p'<<32)|((long)'e'<<48); 

            const long _LDAP_Mask0   = 'l'|('d'<<16)|((long)'a'<<32)|((long)'p'<<48);

 
            const long _LOWERCASE_Mask = 0x0020002000200020L;
            const int  _INT_LOWERCASE_Mask = 0x00200020; 
 

            //Map to a known scheme if possible 
            //upgrade 4 letters to ASCII lower case, keep a false case to stay false
            switch (*lptr | _LOWERCASE_Mask) {
                case _HTTP_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.HttpUri;
                        return true; 
                    } 
                    if (nChars == 5 && ((*(char*)(lptr+1))|0x20) == _HTTPS_Mask1) {
                        syntax = UriParser.HttpsUri; 
                        return true;
                    }
                    break;
 
                case _FILE_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.FileUri; 
                        return true;
                    } 
                    break;
                case _FTP_Mask:
                    if (nChars == 3) {
                        syntax = UriParser.FtpUri; 
                        return true;
                    } 
                    break; 

                case _NEWS_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.NewsUri;
                        return true;
                    } 
                    break;
 
                case _NNTP_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.NntpUri; 
                        return true;
                    }
                    break;
 
                case _UUID_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.UuidUri; 
                        return true;
                    } 
                    break;

                case _GOPHER_Mask0:
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _GOPHER_Mask1) { 
                        syntax = UriParser.GopherUri;
                        return true; 
                    } 
                    break;
                case _MAILTO_Mask0: 
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _MAILTO_Mask1) {
                        syntax = UriParser.MailToUri;
                        return true;
                    } 
                    break;
 
                case _TELNET_Mask0: 
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _TELNET_Mask1) {
                        syntax = UriParser.TelnetUri; 
                        return true;
                    }
                    break;
 
                case _NETXXX_Mask0:
                    if (nChars == 8 && (*(lptr+1)|_LOWERCASE_Mask) == _NETPIPE_Mask1) { 
                        syntax = UriParser.NetPipeUri; 
                        return true;
                    } 
                    else if (nChars == 7 && (*(lptr+1)|_LOWERCASE_Mask) == _NETTCP_Mask1) {
                        syntax = UriParser.NetTcpUri;
                        return true;
                    } 
                    break;
 
                case _LDAP_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.LdapUri; 
                        return true;
                    }
                    break;
                default:    break; 
            }
            return false; 
        } 

        // 
        //
        // This will check whether a scheme string follows the rules
        //
        unsafe static private ParsingError CheckSchemeSyntax(char* ptr, ushort length, ref UriParser syntax) { 
            //First character must be an alpha
        { 
            char c = *ptr; 
            if (c >= 'a' && c <= 'z') {
                ; 
            } else if (c >= 'A' && c <= 'Z') {
                *ptr = (char)(c | 0x20);    //make it lowercase
            } else {
                return ParsingError.BadScheme; 
            }
        } 
 
            for (ushort i = 1; i < length; ++i) {
                char c = ptr[i]; 
                if (c >= 'a' && c <= 'z') {
                    ;
                } else if (c >= 'A' && c <= 'Z') {
                    ptr[i] = (char)(c | 0x20);    //make it lowercase 
                } else if (c >= '0' && c <= '9') {
                    ; 
                } else if (c == '+' || c == '-' || c == '.') { 
                    ;
                } else { 
                    return ParsingError.BadScheme;
                }
            }
            // A not well-known scheme, needs string creation 
            // Note it is already in the lower case as required.
            string str  =  new string(ptr, 0, length); 
            syntax = UriParser.FindOrFetchAsUnknownV1Syntax(str); 
            return ParsingError.None;
        } 
        //
        //
        // Checks the syntax of an authority component. It may also get a userInfo if present
        // Returns an error if no/mailformed authority found 
        // Does not NOT touch m_Info
        // Returns position of the Path component 
        // 
        // Must be called in the ctor only
        private unsafe ushort CheckAuthorityHelper( char* pString, ushort idx, ushort length, 
                                                    ref ParsingError err, ref Flags flags, UriParser syntax,
                                                    ref string newHost )
        {
            int end = length; 
            char ch;
            int startInput = idx; 
            ushort start = idx; 
            newHost = null;
            bool justNormalized = false; 
            bool iriParsing = (s_IriParsing && IriParsingStatic(syntax)); // perf
            bool hasUnicode = ((flags & Flags.HasUnicode) != 0); // perf
            bool hostNotUnicodeNormalized = ((flags & Flags.HostUnicodeNormalized) == 0); // perf
            UriSyntaxFlags syntaxFlags = syntax.Flags; 

            // need to build new Iri'zed string 
            if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                newHost = m_originalUnicodeString.Substring(0, startInput);
            } 

            //Special case is an empty authority
            if (idx == length || ((ch=pString[idx]) == '/' || (ch == '\\' && StaticIsFile(syntax)) || ch == '#' || ch == '?'))
            { 
                if (syntax.InFact(UriSyntaxFlags.AllowEmptyHost))
                { 
                    flags &= ~Flags.UncPath;    //UNC cannot have an empty hostname 
                    if (StaticInFact(flags, Flags.ImplicitFile))
                        err = ParsingError.BadHostName; 
                    else
                        flags |= Flags.BasicHostType;
                }
                else 
                    err = ParsingError.BadHostName;
 
                if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                    flags |= Flags.HostUnicodeNormalized;// no host
                } 

                 return idx;
            }
 
#if PLATFORM_UNIX
            if (StaticIsFile(syntax) && ch != '/') { 
                // On UNIX a file URL may only have an empty authority 
                err = ParsingError.NonEmptyHost;
                return idx; 
            }
#endif // PLATFORM_UNIX

            string userInfoString = null; 
            // Attempt to parse user info first
 
            if ((syntaxFlags & UriSyntaxFlags.MayHaveUserInfo) != 0) 
            {
                for (; start < end; ++start) 
                {
                    if (start == end - 1 || pString[start] == '?' || pString[start] == '#' || pString[start] == '\\' || pString[start] == '/')
                    {
                        start = idx; 
                        break;
                    } 
                    else if (pString[start] == '@') 
                    {
                        flags |= Flags.HasUserInfo; 

                        // Iri'ze userinfo
                        if (iriParsing || (s_IdnScope != UriIdnScope.None)){
                            if (iriParsing && hasUnicode && hostNotUnicodeNormalized){ 
                                // Normalize user info
                                userInfoString = EscapeUnescapeIri(pString, startInput, start + 1, UriComponents.UserInfo); 
                                try{ 
                                    userInfoString = userInfoString.Normalize(NormalizationForm.FormC);
                                } 
                                catch (ArgumentException){
                                    err = ParsingError.BadFormat;
                                    return idx;
                                } 

                                newHost += userInfoString; 
                            } 
                            else{
                                userInfoString = new string(pString, startInput, start - startInput + 1); 
                            }
                        }
                        ++start;
                        ch = pString[start]; 
                        break;
                    } 
                } 
            }
 
            // DNS name only optimization
            // Fo an overriden parsing the optimization is suppressed since hostname can be changed to anything
            bool dnsNotCanonical = ((syntaxFlags & UriSyntaxFlags.SimpleUserSyntax) == 0);
 
            if (ch == '[' && syntax.InFact(UriSyntaxFlags.AllowIPv6Host) && IPv6AddressHelper.IsValid(pString, (int)start+1, ref end))
            { 
                flags |= Flags.IPv6HostType; 

                // Force load config here if config not loaded earlier since we handle IsWellFormed differently 
                // for IPv6 if the iri parsing flag is on or off
                if (!s_ConfigInitialized) {
                    InitializeUriConfig();
                    m_iriParsing = (s_IriParsing && IriParsingStatic(syntax)); 
                }
 
                if (hasUnicode && iriParsing && hostNotUnicodeNormalized) { 
                    newHost += new string(pString, start, end - start);
                    flags |= Flags.HostUnicodeNormalized; 
                    justNormalized = true;
                }
            }
            else if ( ch <= '9' && ch >= '0' && syntax.InFact(UriSyntaxFlags.AllowIPv4Host) && 
                IPv4AddressHelper.IsValid(pString, (int) start, ref end, false, StaticNotAny(flags, Flags.ImplicitFile)))
            { 
                flags |= Flags.IPv4HostType; 

                if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                    newHost += new string(pString, start, end - start);
                    flags |= Flags.HostUnicodeNormalized;
                    justNormalized = true;
                } 
            }
            else if (((syntaxFlags & UriSyntaxFlags.AllowDnsHost)!= 0) && !iriParsing && 
           DomainNameHelper.IsValid(pString, start, ref end, ref dnsNotCanonical, StaticNotAny(flags, Flags.ImplicitFile))) 
            {
                // comes here if there are only ascii chars in host with original parsing and no Iri 

                flags |= Flags.DnsHostType;
                if (!dnsNotCanonical) {
                    flags |= Flags.CanonicalDnsHost; 
                }
 
                if ((s_IdnScope != UriIdnScope.None)){ 
                    // check if intranet
                    // 
                    if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end))){
                        flags |= Flags.IntranetUri;
                    }
                    if (AllowIdnStatic(syntax, flags)){ 
                        bool allAscii = true;
                        bool atLeastOneIdn = false; 
 
                        string idnValue = DomainNameHelper.UnicodeEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn);
 
                        // did we find at least one valid idn
                        if (atLeastOneIdn)
                        {
                            // need to switch string here since we didnt know before hand there there was an idn host 
                            if (StaticNotAny(flags, Flags.HasUnicode))
                                m_originalUnicodeString = m_String; // lazily switching strings 
                            flags |= Flags.IdnHost; 

                            // need to build string for this special scenario 
                            newHost = m_originalUnicodeString.Substring(0, startInput) + userInfoString + idnValue;
                            flags |= Flags.CanonicalDnsHost;
                            m_DnsSafeHost = new string(pString, start, end - start);
                            justNormalized = true; 
                        }
                        flags |= Flags.HostUnicodeNormalized; 
                    } 
                }
            } 
            else if ((iriParsing || (s_IdnScope != UriIdnScope.None)) && ((syntaxFlags & UriSyntaxFlags.AllowDnsHost) != 0) &&
                    ((iriParsing && hostNotUnicodeNormalized) || AllowIdnStatic(syntax, flags)) &&
                    DomainNameHelper.IsValidByIri(  pString, start, ref end, ref dnsNotCanonical,
                                                    StaticNotAny(flags, Flags.ImplicitFile))) 
            {
                CheckAuthorityHelperHandleDnsIri(pString, start, end, startInput, iriParsing, hasUnicode, syntax, userInfoString, 
                                                ref flags, ref justNormalized, ref newHost, ref err); 

            } 
#if !PLATFORM_UNIX
            else if ((s_IdnScope == UriIdnScope.None) && (!s_IriParsing) && ((syntaxFlags & UriSyntaxFlags.AllowUncHost) != 0))
            {
                // 
                // This must remain as the last check befor BasicHost type
                // 
                if (UncNameHelper.IsValid(pString, start, ref end, StaticNotAny(flags, Flags.ImplicitFile))) 
                {
                    if (end - start <= UncNameHelper.MaximumInternetNameLength) 
                        flags |= Flags.UncHostType;
                }
            }
#endif // !PLATFORM_UNIX 

            // The deal here is that we won't allow '\' host terminator except for the File scheme 
            // If we see '\' we try to make it a part of of a Basic host 
            if (end < length && pString[end] == '\\' && (flags & Flags.HostTypeMask) != Flags.HostNotParsed && !StaticIsFile(syntax))
            { 
                if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri))
                {
                    err = ParsingError.BadHostName;
                    flags |= Flags.UnknownHostType; 
                    return (ushort) end;
                } 
                flags &= ~Flags.HostTypeMask; 
            }
            // Here we have checked the syntax up to the end of host 
            // The only thing that can cause an exception is the port value
            // Spend some (duplicated) cycles on that.
            else if (end < length && pString[end] == ':')
            { 
                if (syntax.InFact(UriSyntaxFlags.MayHavePort))
                { 
                    int port = 0; 
                    int startPort = end;
                    for (idx = (ushort)(end+1); idx < length; ++idx) { 
                        ushort val = (ushort)((ushort)pString[idx] - (ushort)'0');
                        if ((val >= 0) && (val <= 9))
                        {
                            if ((port = (port * 10 + val)) > 0xFFFF) 
                                break;
                        } 
                        else if (val == unchecked((ushort)('/' - '0')) || val == (ushort)('?' - '0') || val == unchecked((ushort)('#' - '0'))) 
                        {
                            break; 
                        }
                        else
                        {
                            // The second check is to keep compatibility with V1 until the UriParser is registered 
                            if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost) && syntax.NotAny(UriSyntaxFlags.V1_UnknownUri))
                            { 
                                flags &= ~Flags.HostTypeMask; 
                                break;
                            } 
                            else
                            {
                                err = ParsingError.BadPort;
                                return idx; 
                            }
                        } 
                    } 
                    // check on 0-ffff range
                    if (port > 0xFFFF) 
                    {
                        if (syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost))
                        {
                            flags &= ~Flags.HostTypeMask; 
                        }
                        else 
                        { 
                            err = ParsingError.BadPort;
                            return idx; 
                        }
                    }

                    if (iriParsing && hasUnicode && justNormalized){ 
                        newHost += new string(pString, startPort, idx - startPort);
                    } 
                } 
                else
                { 
                    flags &= ~Flags.HostTypeMask;
                }

            } 

            // check on whether nothing has worked out 
            if ((flags & Flags.HostTypeMask) == Flags.HostNotParsed) 
            {
                //No user info for a Basic hostname 
                flags &= ~Flags.HasUserInfo;
                // Some schemes do not allow HostType = Basic (plus V1 almost never understands this cause of a bug)
                //
                if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost)) 
                {
                    flags |= Flags.BasicHostType; 
                    for (end = idx; end < length; ++end) { 
                        if (pString[end] == '/' || (pString[end] == '?' || pString[end] == '#')) {
                            break; 
                        }
                    }
                    CheckAuthorityHelperHandleAnyHostIri(pString, startInput, end, iriParsing, hasUnicode, syntax,
                                                            ref flags, ref newHost, ref err); 
                }
                else 
                { 
                    //
                    // ATTN V1 compat: V1 supports hostnames like ".." and ".", and so we do but only for unknown schemes. 
                    //                 (VsWhidbey#438821)
                    if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri))
                    {
                        // Can assert here that the host is not empty so we will set dotFound 
                        // at least once or fail before exiting the loop
                        bool dotFound = false; 
                        int startOtherHost = idx; 
                        for (end = idx; end < length; ++end)
                        { 
                            if (dotFound && (pString[end] == '/' || pString[end] == '?' || pString[end] == '#'))
                                break;
                            else if (end < (idx + 2) && pString[end] == '.')
                            { 
                                // allow one or two dots
                                dotFound = true; 
                            } 
                            else
                            { 
                                //failure
                                err = ParsingError.BadHostName;
                                flags |= Flags.UnknownHostType;
                                return idx; 
                            }
                        } 
                        //success 
                        flags |= Flags.BasicHostType;
 
                        if (iriParsing && hasUnicode
                            && StaticNotAny(flags, Flags.HostUnicodeNormalized)){
                            // Normalize any other host
                            String user = new string(pString, startOtherHost, startOtherHost - end); 
                            try
                            { 
                                newHost += user.Normalize(NormalizationForm.FormC); 
                            }
                            catch (ArgumentException){ 
                                err = ParsingError.BadFormat;
                                return idx;
                            }
 
                            flags |= Flags.HostUnicodeNormalized;
                        } 
                    } 
                    else if(syntax.InFact(UriSyntaxFlags.MustHaveAuthority))
                    { 
                        err = ParsingError.BadHostName;
                        flags |= Flags.UnknownHostType;
                        return idx;
                    } 
                }
            } 
            return (ushort) end; 
        }
 
        unsafe void CheckAuthorityHelperHandleDnsIri( char* pString, ushort start, int end, int startInput,
                                            bool iriParsing, bool hasUnicode, UriParser syntax, string userInfoString,
                                            ref Flags flags, ref bool justNormalized, ref string newHost, ref ParsingError err)
        { 
            // comes here only if host has unicode chars and iri is on or idn is allowed
 
            flags |= Flags.DnsHostType; 

            // check if intranet 
            //
            if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end)))
            {
                flags |= Flags.IntranetUri; 
            }
 
            if (AllowIdnStatic(syntax, flags)) 
            {
                bool allAscii = true; 
                bool atLeastOneIdn = false;

                string idnValue = DomainNameHelper.IdnEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn);
                string UniEquvlt = DomainNameHelper.UnicodeEquivalent(idnValue, pString, start, end); 

                if (!allAscii) 
                    flags |= Flags.UnicodeHost; // we have a unicode host 

                if (atLeastOneIdn) 
                    flags |= Flags.IdnHost;   // we have at least one valid idn label

                if (allAscii && atLeastOneIdn && StaticNotAny(flags, Flags.HasUnicode))
                { 
                    // original string location changed lazily
                    m_originalUnicodeString = m_String; 
                    newHost = m_originalUnicodeString.Substring(0, startInput) + 
                        (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null);
                    justNormalized = true; 
                }
                else if (!iriParsing && (StaticInFact(flags, Flags.UnicodeHost) || StaticInFact(flags, Flags.IdnHost)))
                {
                    // original string location changed lazily 
                    m_originalUnicodeString = m_String;
                    newHost = m_originalUnicodeString.Substring(0, startInput) + 
                        (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null); 
                    justNormalized = true;
                } 

                if (!(allAscii && !atLeastOneIdn))
                {
                    m_DnsSafeHost = idnValue; 
                    newHost += UniEquvlt;
                    justNormalized = true; 
                } 
                else if (allAscii && !atLeastOneIdn && iriParsing && hasUnicode)
                { 
                    newHost += UniEquvlt;
                    justNormalized = true;
                }
            } 
            else
            { 
                if (hasUnicode) 
                {
                    string temp = StripBidiControlCharacter(pString, start, end - start); 
                    try{
                        newHost += ((temp != null) ? temp.Normalize(NormalizationForm.FormC) : null);
                    }
                    catch (ArgumentException){ 
                        err = ParsingError.BadHostName;
                    } 
                    justNormalized = true; 
                }
            } 
            flags |= Flags.HostUnicodeNormalized;
        }

        unsafe void CheckAuthorityHelperHandleAnyHostIri(char* pString, int startInput, int end, 
                                            bool iriParsing, bool hasUnicode, UriParser syntax,
                                            ref Flags flags, ref string newHost, ref ParsingError err) 
        { 
            if (StaticNotAny(flags, Flags.HostUnicodeNormalized) && (AllowIdnStatic(syntax, flags) || (iriParsing && hasUnicode)))
            { 
                // Normalize any other host or do idn
                String user = new string(pString, startInput, end - startInput);

                if (AllowIdnStatic(syntax, flags)) 
                {
                    bool allAscii = true; 
                    bool atLeastOneIdn = false; 

                    string UniEquvlt = DomainNameHelper.UnicodeEquivalent(pString, startInput, end, ref allAscii, ref atLeastOneIdn); 

                    if (((allAscii && atLeastOneIdn) || !allAscii) && !(iriParsing && hasUnicode))
                    {
                        // original string location changed lazily 
                        m_originalUnicodeString = m_String;
                        newHost = m_originalUnicodeString.Substring(0, startInput); 
                        flags |= Flags.HasUnicode; 
                    }
                    if (atLeastOneIdn || !allAscii) 
                    {
                        newHost += UniEquvlt;
                        string bidiStrippedHost = null;
                        m_DnsSafeHost = DomainNameHelper.IdnEquivalent(pString, startInput, end, ref  allAscii, ref bidiStrippedHost); 
                        if (atLeastOneIdn)
                            flags |= Flags.IdnHost; 
                        if (!allAscii) 
                            flags |= Flags.UnicodeHost;
                    } 
                    else if (iriParsing && hasUnicode)
                    {
                        newHost += user;
 
                    }
                } 
                else 
                {
                    try{ 
                        newHost += user.Normalize(NormalizationForm.FormC);
                    }
                    catch (ArgumentException){
                        err = ParsingError.BadHostName; 
                    }
                } 
 
                flags |= Flags.HostUnicodeNormalized;
            } 
        }

        //
        // 
        // The method checks whether a string needs transformation before going to display or wire
        // 
        // Parameters: 
        // - escaped   true = treat all valid escape sequences as escaped sequences, false = escape all %
        // - delim     a character signalling the termination of the component being checked 
        //
        // When delim=='?', then '#' character is also considered as delimiter additionally to passed '?'.
        //
        // The method pays attention to the dots and slashes so to signal potential Path compression action needed. 
        // Even that is not required for other components, the cycles are still spent (little inefficiency)
        // 
 
        const char c_DummyChar = (char) 0xFFFF;     //An Invalid Unicode character used as a dummy char passed into the parameter
        const char c_EOL       = (char) 0xFFFE;     //An Invalid Unicode character used by CheckCanonical as "no delimiter condition" 
        [Flags]
        private enum Check {
            None            = 0x0,
            EscapedCanonical= 0x1, 
            DisplayCanonical= 0x2,
            DotSlashAttn    = 0x4, 
            DotSlashEscaped = 0x80, 
            BackslashInPath = 0x10,
            ReservedFound   = 0x20, 
            NotIriCanonical = 0x40,
            FoundNonAscii =    0x8
        }
 
        //
        // Finds the end of component 
        // 

        private unsafe void FindEndOfComponent(string input, ref ushort idx, ushort end, char delim) 
        {
            fixed (char* str = input)
            {
                FindEndOfComponent(str, ref idx, end, delim); 
            }
        } 
        private unsafe void FindEndOfComponent(char* str, ref ushort idx, ushort end, char delim) 
        {
            char c = c_DummyChar; 
            ushort i=idx;
            for (; i < end; ++i)
            {
                c = str[i]; 
                if (c == delim)
                { 
                    break; 
                }
                else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) 
                {
                    // this is a special case when deciding on Query/Fragment
                    break;
                } 
            }
            idx = i; 
        } 

        // 
        // Used by ParseRemaining as well by InternalIsWellFormedOriginalString
        //
        private unsafe Check CheckCanonical(char* str, ref ushort idx, ushort end, char delim) {
            Check res = Check.None; 
            bool needsEscaping = false;
            bool foundEscaping = false; 
 
            char c = c_DummyChar;
            ushort i=idx; 
            for (; i < end; ++i)
            {
                c = str[i];
                // Control chars usually should be escaped in any case 
                if (c <= '\x1F' || (c >= '\x7F' && c <= '\x9F'))
                { 
                    needsEscaping = true; 
                    foundEscaping = true;
                    res |= Check.ReservedFound; 
                }
                else if (c > 'z' && c != '~') {
                    if(m_iriParsing){
                        bool valid = false; 
                        res |= Check.FoundNonAscii;
 
                        if (Char.IsHighSurrogate(c)){ 
                            if ((i + 1) < end){
                                bool surrPair = false; 
                                valid = CheckIriUnicodeRange(c, str[i + 1], ref surrPair, true);
                            }
                        }
                        else{ 
                            valid = CheckIriUnicodeRange(c, true);
                        } 
                        if (!valid) res |= Check.NotIriCanonical; 
                    }
 
                    if (!needsEscaping) needsEscaping = true;
                }
                else if (c == delim) {
                    break; 
                }
                else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) { 
                    // this is a special case when deciding on Query/Fragment 
                    break;
                } 
                else if (c == '?') {
                    if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) && delim != c_EOL))
                    {
                        // VsWhidbey#87423 
                        // If found as reserved this char is not suitable for safe unescaped display
                        // Will need to escape it when both escaping and unescaping the string 
                        res |= Check.ReservedFound; 
                        foundEscaping = true;
                        needsEscaping = true; 
                    }
                }
                else if (c == '#') {
                    needsEscaping = true; 
                    if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) {
                        // VsWhidbey#87423, 122037 
                        // If found as reserved this char is not suitable for safe unescaped display 
                        // Will need to escape it when both escaping and unescaping the string
                        res |= Check.ReservedFound; 
                        foundEscaping = true;
                    }
                }
                else if (c == '/' || c == '\\') { 
                    if ((res & Check.BackslashInPath) == 0 && c == '\\') {
                        res |= Check.BackslashInPath; 
                    } 
                    if ((res & Check.DotSlashAttn) == 0 && i+1 != end && (str[i+1] == '/' || str[i+1] == '\\' )) {
                        res |= Check.DotSlashAttn; 
                    }
                }
                else if (c == '.') {
                    if ((res & Check.DotSlashAttn) == 0 && i+1 == end || str[i+1] == '.' || str[i+1] == '/' || str[i+1] == '\\' || str[i+1] == '?' || str[i+1] == '#') { 
                        res |= Check.DotSlashAttn;
                    } 
                } 
                else if (!needsEscaping && ((c <= '"' && c != '!') || (c >= '[' && c <= '^') || c == '>' || c == '<' || c == '`')) {
                    needsEscaping = true; 
                }
                else if (c == '%') {
                    if (!foundEscaping) foundEscaping = true;
                    //try unescape a byte hex escaping 
                    if (i+2 < end && (c = EscapedAscii(str[i+1], str[i+2])) != c_DummyChar)
                    { 
                        if (c == '.' || c == '/' || c == '\\') { 
                            res |= Check.DotSlashEscaped;
                        } 
                        i+=2;
                        continue;
                    }
                    // otherwise we follow to non escaped case 
                    if (!needsEscaping) {
                        needsEscaping = true; 
                    } 
                }
            } 

            if (foundEscaping) {
                if (!needsEscaping) {
                    res |= Check.EscapedCanonical; 
                }
            } 
            else { 
                res |= Check.DisplayCanonical;
                if (!needsEscaping) { 
                    res |= Check.EscapedCanonical;
                }
            }
            idx = i; 
            return res;
        } 
 
        //
        // Returns the escaped and canonicalized path string 
        // the passed array must be long enough to hold at least
        // canonical unescaped path representation (allocated by the caller)
        //
        private unsafe char[] GetCanonicalPath(char[] dest, ref int pos, UriFormat formatAs) 
        {
 
            if (InFact(Flags.FirstSlashAbsent)) 
                dest[pos++] = '/';
 
            if (m_Info.Offset.Path == m_Info.Offset.Query)
                return dest;

            int end = pos; 

            int dosPathIdx = SecuredPathIndex; 
 
            // Note that unescaping and then escapig back is not transitive hence not safe.
            // We are vulnerable due to the way the UserEscaped flag is processed (see NDPWhidbey#10612 bug). 
            // Try to unescape only needed chars.
            if (formatAs == UriFormat.UriEscaped)
            {
                if (InFact(Flags.ShouldBeCompressed)) 
                {
                    m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path); 
                    end += (m_Info.Offset.Query - m_Info.Offset.Path); 

                    // If the path was found as needed compression and contains escaped characters, unescape only interesting characters (safe) 

                    if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) && !IsImplicitFile)
                    {
                        fixed (char* pdest = dest) 
                            UnescapeOnly(pdest, pos, ref end, '.', '/', m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)? '\\': c_DummyChar) ;
                    } 
                } 
                else
                { 
                    //
                    if (InFact(Flags.E_PathNotCanonical) && NotAny(Flags.UserEscaped)) {
                        string str = m_String;
 
                        // Check on not canonical disk designation like C|\, should be rare, rare case
                        if (dosPathIdx != 0 && str[dosPathIdx + m_Info.Offset.Path -1] == '|') 
                        { 
                            str = str.Remove(dosPathIdx + m_Info.Offset.Path -1, 1);
                            str = str.Insert(dosPathIdx + m_Info.Offset.Path -1, ":"); 
                        }
                        dest = EscapeString(str, m_Info.Offset.Path, m_Info.Offset.Query, dest, ref end, true, '?', '#', IsImplicitFile? c_DummyChar: '%');
                    }
                    else { 
                        m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path);
                        end += (m_Info.Offset.Query - m_Info.Offset.Path); 
                    } 
                }
            } 
            else
            {
                m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path);
                end += (m_Info.Offset.Query - m_Info.Offset.Path); 

                if (InFact(Flags.ShouldBeCompressed)) 
                { 
                    // If the path was found as needed compression and contains escaped characters, unescape only interesting characters (safe)
 
                    if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) && !IsImplicitFile)
                    {
                        fixed (char* pdest = dest)
                            UnescapeOnly(pdest, pos, ref end, '.', '/', m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)? '\\': c_DummyChar) ; 
                    }
                } 
            } 

            // Here we already got output data as copied into dest array 
            // We just may need more processing of that data

            //
            // if this URI is using 'non-proprietary' disk drive designation, convert to MS-style 
            //
            // (path is already  >= 3 chars if recognized as a DOS-like) 
            // 
            if (dosPathIdx != 0 && dest[dosPathIdx + pos - 1] == '|')
                dest[dosPathIdx + pos - 1] = ':'; 

            if (InFact(Flags.ShouldBeCompressed))
            {
                // It will also convert back slashes if needed 
                dest = Compress(dest, (ushort)(pos + dosPathIdx), ref end, m_Syntax);
                if (dest[pos] == '\\') 
                    dest[pos] = '/'; 

                // Escape path if requested and found as not fully escaped 
                if (formatAs == UriFormat.UriEscaped && NotAny(Flags.UserEscaped) && InFact(Flags.E_PathNotCanonical)) {
                    //
                    string srcString = new string(dest, pos, end-pos);
                    dest = EscapeString(srcString ,  0, end-pos, dest, ref pos, true, '?', '#', IsImplicitFile? c_DummyChar: '%'); 
                    end = pos;
                } 
            } 
            else if (m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes) && InFact(Flags.BackslashInPath))
            { 
                for (int i = pos; i < end; ++i)
                    if (dest[i] == '\\') dest[i] = '/';
            }
 
            if (formatAs != UriFormat.UriEscaped && InFact(Flags.PathNotCanonical))
            { 
                UnescapeMode mode; 
                if (InFact(Flags.PathNotCanonical))
                { 
                    switch (formatAs)
                    {
                    case V1ToStringUnescape:
 
                        mode = (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag;
                        if (IsImplicitFile) 
                            mode &= ~UnescapeMode.Unescape; 
                        break;
 
                    case UriFormat.Unescaped:
                        mode = IsImplicitFile? UnescapeMode.CopyOnly : UnescapeMode.Unescape | UnescapeMode.UnescapeAll;
                        break;
 
                    default: // UriFormat.SafeUnescaped
 
                        mode = InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape; 
                        if (IsImplicitFile)
                            mode &= ~UnescapeMode.Unescape; 
                        break;
                    }
                }
                else { 
                    mode = UnescapeMode.CopyOnly;
                } 
 
                char[] dest1 = new char[dest.Length];
                Buffer.BlockCopy(dest, 0, dest1, 0, end<<1); 
                fixed (char *pdest = dest1)
                {
                    dest = UnescapeString(pdest, pos, end, dest, ref pos, '?', '#', c_DummyChar, mode, m_Syntax, false, false);
                } 
            }
            else 
            { 
                pos = end;
            } 

            return dest;
        }
 
        // works only with ASCII characters, used to partially unescape path before compressing
        private unsafe static void UnescapeOnly(char* pch, int start, ref int end, char ch1, char ch2, char ch3) { 
            if (end - start < 3) { 
                //no chance that something is escaped
                return; 
            }

            char *pend = pch + end-2;
            pch += start; 
            char *pnew = null;
 
            over: 

            // Just looking for a interested escaped char 
            if (pch >= pend)    goto done;
            if(*pch++ != '%')   goto over;

            char ch = EscapedAscii(*pch++, *pch++); 
            if (!(ch == ch1 || ch == ch2 || ch == ch3)) goto over;
 
            // Here we found something and now start copying the scanned chars 
            pnew = pch-2;
            *(pnew-1) = ch; 

            over_new:

            if (pch >= pend)                goto done; 
            if((*pnew++ = *pch++) != '%')   goto over_new;
 
            ch = EscapedAscii((*pnew++ = *pch++), (*pnew++ = *pch++)); 
            if (!(ch == ch1 || ch == ch2 || ch == ch3)) {
                goto over_new; 
            }

            pnew -= 2;
            *(pnew-1) = ch; 

            goto over_new; 
 
            done:
            pend+=2; 

            if (pnew == null) {
                //nothing was found
                return; 
            }
 
            //the tail may be already processed 
            if(pch == pend) {
                end -= (int) (pch-pnew); 
                return;
            }

            *pnew++ = *pch++; 
            if(pch == pend) {
                end -= (int) (pch-pnew); 
                return; 
            }
            *pnew++ = *pch++; 
            end -= (int) (pch-pnew);
        }
        //
        // 
        //
        // 
        // 
        private static char EscapedAscii(char digit, char next) {
            if (!(((digit >= '0') && (digit <= '9')) 
                || ((digit >= 'A') && (digit <= 'F'))
                || ((digit >= 'a') && (digit <= 'f')))) {
                return c_DummyChar;
            } 

            int res= (digit <= '9') 
                ? ((int)digit - (int)'0') 
                : (((digit <= 'F')
                ? ((int)digit - (int)'A') 
                : ((int)digit - (int)'a'))
                   + 10);

            if (!(((next >= '0') && (next <= '9')) 
                || ((next >= 'A') && (next <= 'F'))
                || ((next >= 'a') && (next <= 'f')))) { 
                return c_DummyChar; 
            }
 
            return  (char) ((res << 4) + ((next <= '9')
                    ? ((int)next - (int)'0')
                    : (((next <= 'F')
                        ? ((int)next - (int)'A') 
                        : ((int)next - (int)'a'))
                       + 10))); 
        } 

 
        //
        //
        // This will compress any "\" "/../" "/./" "///" "/..../" /XXX.../, etc found in the input
        // 
        // The passed syntax controls whether to use agressive compression or the one specified in RFC 2396
        // 
        // 
        private static char[] Compress(char[] dest, ushort start, ref int destLength, UriParser syntax)
        { 
            ushort  slashCount      = 0;
            ushort  lastSlash       = 0;
            ushort  dotCount        = 0;
            ushort  removeSegments  = 0; 

            unchecked { 
                //ushort i == -1 and start == -1 overflow is ok here 
                ushort  i = (ushort)((ushort)destLength - (ushort)1);
                start = (ushort)(start-1); 

                for (; i != start ; --i) {
                    char ch = dest[i];
                    if (ch == '\\' && syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)) { 
                        dest[i] = ch = '/';
                    } 
 
                    //
                    // compress multiple '/' for file URI 
                    //
                    if (ch == '/') {
                        ++slashCount;
                        /* 
                        QFE 4390 - remove the compression of multiple slashes to a single slash
                        if (slashCount > 1) { 
                            continue; 
                        }
 			*/ 
                    }
                    else {
                        if (slashCount > 1) {
                            /* 
                            QFE 4390 - remove the compression of multiple slashes to a single slash
                            if (syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) 
                            { 
                                // We saw > 1 slashes so remove all but the last one
                                // dest.Remove(i+1, slashCount -1); 
                                Buffer.BlockCopy(dest, (i + slashCount) << 1, dest, (i + 1) << 1, (destLength - (i + slashCount)) << 1);
                                destLength -= (slashCount - 1);
                            }
			    */ 
                            // else preserve repeated slashes
                            lastSlash = (ushort)(i + 1); 
                        } 
                        slashCount = 0;
                    } 

                    if (ch == '.') {
                        ++dotCount;
                        continue; 
                    }
                    else if (dotCount != 0) { 
 
                        bool skipSegment = syntax.NotAny(UriSyntaxFlags.CanonicalizeAsFilePath) && (dotCount > 2 || ch != '/' || i == start);
 
                        //
                        // Cases:
                        // /./ or /...[....]/   = remove this segment as invalid
                        // /../                 = remove this segment, mark next for removal 
                        // /....x               = DO NOT TOUCH, leave as is
                        // x.../                = remove trailing dots 
                        // 
                        if (!skipSegment && ch == '/') {
                            if (lastSlash == i+dotCount+1 || (lastSlash == 0 && i+dotCount+1 == destLength)) { 
                                //
                                //  /./ or  /...[....]/ or /. or  /...[....]
                                //  Remove this segment (note that /.../ is an invalid segment, remove it since
                                //  we should not throw at this parsing point. 
                                //
                                // just reusing a variable slot we perform //dest.Remove(i+1, dotCount + (lastSlash==0?0:1)); 
                                lastSlash = (ushort)(i + 1 + dotCount + (lastSlash==0?0:1)); 
                                Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1);
                                destLength -= (lastSlash-i-1); 

                                lastSlash = i;
                                if (dotCount == 2) {
                                    // 
                                    // We have 2 dots in between like /../ or /..,
                                    // Mark next segment for removal and remove this /../ or /.. 
                                    // 
                                    ++removeSegments;
                                } 
                                dotCount = 0;
                                continue;
                            }
                        } 
                        // Note if removeSegments!=0, then ignore and remove the whole segment later
                        else if (!skipSegment && removeSegments == 0 && (lastSlash == i+dotCount+1 || (lastSlash == 0 && i+dotCount+1 == destLength))) { 
                            // 
                            // x.../  or  x...
                            // remove trailing dots 
                            //
                            //
                            // just reusing a variable slot we perform //dest.Remove(i+1, dotCount);
                            dotCount = (ushort)(i + 1 + dotCount); 
                            Buffer.BlockCopy(dest, dotCount<<1, dest, (i+1)<<1, (destLength - dotCount)<<1);
                            destLength -= (dotCount-i-1); 
                            lastSlash = 0;  //the other dots in this segment will stay intact 
                            dotCount = 0;
                            continue; 
                        }
                        dotCount = 0;
                        //
                        // Here all other cases go such as 
                        // x.[..]y or /.[..]x or (/x.[...][/] && removeSegments !=0)
                    } 
 
                    //
                    // Now we may want to remove a segment because of previous /../ 
                    //
                    if (ch == '/') {
                        if (removeSegments  != 0) {
                            --removeSegments; 

                            // just reusing a variable slot we perform //dest.Remove(i+1, lastSlash - i); 
                            lastSlash = (ushort)(lastSlash + 1); 
                            Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1);
                            destLength -= (lastSlash-i-1); 
                        }
                    lastSlash = i;
                    }
                } 

               start = (ushort)((ushort)start + (ushort)1); 
            } //end of unchecked 

            if ((ushort)destLength > start && syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) 
            {
                if (slashCount > 1) {
		    /*
                    Buffer.BlockCopy(dest, lastSlash << 1, dest, start << 1, (destLength - lastSlash) << 1); 
                    destLength -= (slashCount - 1);
                    */ 
                    //QFE 4390 - Fall through for compat after not multiple slashes to a single slashl 
                }
                else if (removeSegments != 0 && dest[start] != '/') { 
                    //remove first not rooted segment
                    // dest.Remove(i+1, lastSlash - i);
                    lastSlash = (ushort)(lastSlash + 1);
                    Buffer.BlockCopy(dest, lastSlash<<1, dest, start<<1, (destLength - lastSlash)<<1); 
                    destLength -= lastSlash;
                } 
                else if (dotCount != 0) { 
                    // If final string starts with a segment looking like .[...]/ or .[...]
                    // then we remove this fisrt segment 
                    if (lastSlash == dotCount+1 || (lastSlash == 0 && dotCount + 1 == destLength)) {
                        //dest.Remove(0, dotCount + (lastSlash==0?0:1));
                        dotCount = (ushort)(dotCount + (lastSlash==0?0:1));
                        Buffer.BlockCopy(dest, dotCount<<1, dest, start<<1, (destLength - dotCount)<<1); 
                        destLength -= dotCount;
                    } 
                } 
            }
            return dest; 
        }
        //
        //
        // 
        //
        private static readonly char[] HexUpperChars = { 
                                   '0', '1', '2', '3', '4', '5', '6', '7', 
                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
                                   }; 

        //used by DigestClient
        internal static readonly char[] HexLowerChars = {
                                   '0', '1', '2', '3', '4', '5', '6', '7', 
                                   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
                                   }; 
 

        // 
        //
        //
        //
        private static void EscapeAsciiChar(char ch, char[] to, ref int pos) { 
            to[pos++] = '%';
            to[pos++] = HexUpperChars[(ch & 0xf0) >> 4]; 
            to[pos++] = HexUpperChars[ch & 0xf]; 
        }
 
        internal static int CalculateCaseInsensitiveHashCode(string text)
        {
            return StringComparer.InvariantCultureIgnoreCase.GetHashCode(text);
        } 
        //
        // CombineUri 
        // 
        //  Given 2 URI strings, combine them into a single resultant URI string
        // 
        // Inputs:
        //    basePart
        //      Base URI to combine with
        // 
        //    relativePart
        //      String expected to be relative URI 
        // 
        // Assumes:
        //   is in canonic form 
        //
        // Returns:
        //  Resulting combined URI string
        // 
        private static string CombineUri(Uri basePart, string relativePart, UriFormat uriFormat) {
           //NB: relativePart is ensured as not empty by the caller 
           //    Another assumption is that basePart is an AbsoluteUri 

           // This method was not optimized for efficiency 
           // Means a relative Uri ctor may be relatively slow plus it increases the footprint of the baseUri

           char c1 = relativePart[0];
 
#if !PLATFORM_UNIX
           //check a special case for the base as DOS path and a rooted relative string 
           if ( basePart.IsDosPath && 
               (c1 == '/' || c1 == '\\') &&
               (relativePart.Length == 1 || (relativePart[1] != '/' && relativePart[1] != '\\'))) 
           {
               // take relative part appended to the base string after the drive letter
               int idx = basePart.OriginalString.IndexOf(':');
               if (basePart.IsImplicitFile) { 
                   return basePart.OriginalString.Substring(0, idx+1 ) + relativePart;
               } 
               // The basePart has explicit scheme (could be not file:), take the DOS drive ':' position 
               idx = basePart.OriginalString.IndexOf(':', idx+1);
               return basePart.OriginalString.Substring(0, idx+1 ) + relativePart; 
           }
#endif // !PLATFORM_UNIX

           // Check special case for Unc or absolute path in relativePart when base is FILE 
           if (StaticIsFile(basePart.Syntax))
           { 
 
                if (c1 == '\\' || c1 == '/') {
 
                    if(relativePart.Length >= 2 && (relativePart[1] == '\\' || relativePart[1] == '/')) {
                        //Assuming relative is a Unc path and base is a file uri.
                        return basePart.IsImplicitFile? relativePart: "file:" + relativePart;
                    } 

                    // here we got an absolute path in relativePart, 
                    // For compatibility with V1.0 parser we restrict the compression scope to Unc Share, i.e. \\host\share\ 
                    if (basePart.IsUnc) {
                        string share = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped); 
                        for (int i = 1; i < share.Length; ++i) {
                            if (share[i] == '/') {
                                share = share.Substring(0, i);
                                break; 
                            }
                        } 
                        if (basePart.IsImplicitFile) { 
                            return  @"\\"
                                    + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped) 
                                    + share
                                    + relativePart;
                        }
                        return  "file://" 
                                + basePart.GetParts(UriComponents.Host, uriFormat)
                                + share 
                                + relativePart; 

                    } 
                    // It's not obvious but we've checked (for this relativePart format) that baseUti is nor UNC nor DOS path
                    //
                    // Means base is a Unix style path and, btw, IsImplicitFile cannot be the case either
                    return "file://" + relativePart; 
               }
           } 
 
           // If we are here we did not recognize absolute DOS/UNC path for a file: base uri
           // Note that DOS path may still happen in the relativePart and if so it may override the base uri scheme. 

           bool convBackSlashes =  basePart.Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes);

           string left = null; 

           // check for network or local absolute path 
           if (c1 == '/' || (c1 == '\\' && convBackSlashes)) { 
               if (relativePart.Length >= 2 && relativePart[1] == '/') {
                   // got an authority in relative path and the base scheme is not file (checked) 
                   return basePart.Scheme + ':' + relativePart;
               }

               // Got absolute relative path, and the base is nor FILE nor a DOS path (checked at the method start) 
               if (basePart.HostType == Flags.IPv6HostType) {
                   left =  basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat) 
                                    + '[' + basePart.DnsSafeHost + ']' 
                                    + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat);
               } 
               else {
                   left =  basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat);
               }
               //VsWhidbey#241426 
               if (convBackSlashes && c1 == '\\')
                   relativePart = '/' + relativePart.Substring(1); 
 
               return left + relativePart;
           } 

           // Here we got a relative path or just a query+[fragment]
           // Need to run path Compression because this is how relative Uri combining works
 
           // Take the base part path up to and including the last slash
           left = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, basePart.IsImplicitFile? UriFormat.Unescaped: uriFormat); 
           int length = left.Length; 
           char[] path = new char[length + relativePart.Length];
 
           if (length > 0) {
               left.CopyTo(0, path, 0, length);
               while(length > 0) {
                   if (path[--length] == '/') { 
                       ++length;
                       break; 
                   } 
               }
           } 

           //Append relative path to the result
           relativePart.CopyTo(0, path, length, relativePart.Length);
 
           // Split relative on path and extra (for compression)
           c1 = basePart.Syntax.InFact(UriSyntaxFlags.MayHaveQuery)? '?': c_DummyChar; 
 
           // The  implcit file check is to avoid a fragment in the implicit file combined uri.
           // The behavior change request is tracked vis VsWhidbey#261387 ans that was approved through VsWhidbey#266417. 
           char c2 = (!basePart.IsImplicitFile && basePart.Syntax.InFact(UriSyntaxFlags.MayHaveFragment))? '#': c_DummyChar;
           string extra = String.Empty;

           // assuming c_DummyChar may not happen in an unicode uri string 
           if (!(c1 == c_DummyChar && c2 == c_DummyChar)) {
               int i=0; 
               for (;i < relativePart.Length; ++i) { 
                   if (path[length + i] == c1 || path[length + i] == c2) {
                       break; 
                   }
               }
               if (i == 0) {
                   extra = relativePart; 
               }
               else if (i < relativePart.Length) { 
                   extra = relativePart.Substring(i); 
               }
               length += i; 
           }
           else {
               length += relativePart.Length;
           } 

           // Take the base part up to the path 
           if (basePart.HostType == Flags.IPv6HostType) { 
               if (basePart.IsImplicitFile) {
                   left =  @"\\[" + basePart.DnsSafeHost + ']'; 
               }
               else {
                   left =  basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat)
                           + '[' + basePart.DnsSafeHost + ']' 
                           + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat);
               } 
           } 
           else {
               if (basePart.IsImplicitFile) { 
#if !PLATFORM_UNIX
                   if (basePart.IsDosPath) {
                       // The FILE DOS path comes as /c:/path, we have to exclude first 3 chars from compression
                       path = Compress(path, 3, ref length, basePart.Syntax); 
                       return new string(path, 1, length-1) + extra;
                   } 
                   else { 
                       left =  @"\\" + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped);
                   } 
#else
                   left =  basePart.GetParts(UriComponents.Host, UriFormat.Unescaped);
#endif // !PLATFORM_UNIX
 
               }
               else { 
                   left =  basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat); 
               }
           } 
           //compress the path
           path = Compress(path, basePart.SecuredPathIndex, ref length, basePart.Syntax);
           return left + new string(path, 0, length) + extra;
        } 

        // 
        // PathDifference 
        //
        //  Performs the relative path calculation for MakeRelative() 
        //
        // Inputs:
        //    path1
        //    path2 
        //      Paths for which we calculate the difference
        // 
        //    compareCase 
        //      False if we consider characters that differ only in case to be
        //      equal 
        //
        // Returns:
        //  A string which is the relative path difference between  and
        //   such that if  and the calculated difference are used 
        //  as arguments to Combine(),  is returned
        // 
        // Throws: 
        //  Nothing
        // 
        private static string PathDifference(string path1, string path2, bool compareCase) {

            int i;
            int si = -1; 

            for (i = 0; (i < path1.Length) && (i < path2.Length); ++i) { 
                if ((path1[i] != path2[i]) && (compareCase || (Char.ToLower(path1[i], CultureInfo.InvariantCulture) != Char.ToLower(path2[i], CultureInfo.InvariantCulture)))) 
                {
                    break; 

                } else if (path1[i] == '/') {
                    si = i;
                } 
            }
 
            if (i == 0) { 
                return path2;
            } 
            if ((i == path1.Length) && (i == path2.Length)) {
                return String.Empty;
            }
 
            StringBuilder relPath = new StringBuilder();
 
            for (; i < path1.Length; ++i) { 
                if (path1[i] == '/') {
                    relPath.Append("../"); 
                }
            }
            return relPath.ToString() + path2.Substring(si + 1);
        } 

        //Used by Uribuilder 
        internal bool HasAuthority { 
            get {
                return InFact(Flags.AuthorityFound); 
            }
        }

        private static readonly char[] _WSchars = new char[] {' ', '\n', '\r', '\t'}; 
        private static bool IsLWS(char ch) {
 
            return (ch <= ' ') && (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); 
        }
 
        //Only consider ASCII characters
        private static bool IsAsciiLetter(char character) {

            return (character >= 'a' && character <= 'z') || 
                   (character >= 'A' && character <= 'Z');
        } 
 
        private static bool IsAsciiLetterOrDigit(char character) {
            return IsAsciiLetter(character) || (character >= '0' && character <= '9'); 
        }


        // 
        // Is this a gen delim char from RFC 3986
        // 
        internal static bool IsGenDelim(char ch) 
        {
            return (ch == ':' || ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@'); 
        }

        //
        // Is this a Bidirectional control char.. These get stripped 
        //
        internal static bool IsBidiControlCharacter(char ch) 
        { 
            return (ch == '\u200E' /*LRM*/ || ch == '\u200F' /*RLM*/ || ch == '\u202A' /*LRE*/ ||
                    ch == '\u202B' /*RLE*/ || ch == '\u202C' /*PDF*/ || ch == '\u202D' /*LRO*/ || 
                    ch == '\u202E' /*RLO*/);
        }

        // 
        // Strip Bidirectional control charcters from this string
        // 
        internal static unsafe string StripBidiControlCharacter(char* strToClean, int start, int length) 
        {
            if (length <= 0) return ""; 

            char [] cleanStr = new char[length];
            int count = 0;
            for (int i = 0; i < length; ++i){ 
                char c = strToClean[start + i];
                if (c < '\u200E' || c > '\u202E' || !IsBidiControlCharacter(c)){ 
                    cleanStr[count++] = c; 
                }
            } 
            return new string(cleanStr, 0, count);
        }

        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Parse() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to an unconstructed Uri instance. 
            // It does not make any sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Canonicalize() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to supressing of a path compression 
            // It does not make much sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Escape() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to the same effect as dontEscape=true. 
            // It does not make much sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        // 
        // Unescape
        // 
        //  Convert any escape sequences in . Escape sequences can be 
        //  hex encoded reserved characters (e.g. %40 == '@') or hex encoded
        //  UTF-8 sequences (e.g. %C4%D2 == 'Latin capital Ligature Ij') 
        //
        /// 
        [Obsolete("The method has been deprecated. Please use GetComponents() or static UnescapeDataString() to unescape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual string Unescape(string path) { 

            // [....] cr: This method is dangerous since it gives path unescaping control 
            // to the derived class without any permission demand. 
            // Should be deprecated and removed asap.
 
            char[] dest = new char[path.Length];
            int count = 0;
            dest = UnescapeString(path, 0, path.Length, dest, ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll, null, false, true);
            return new string(dest, 0, count); 
        }
 
        [Obsolete("The method has been deprecated. Please use GetComponents() or static EscapeUriString() to escape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")] 
        protected static string EscapeString(string str) {
 
            // [....] cr: This method just does not make sense sa protected
            // It should go public static asap

            if ((object)str == null) { 
                return string.Empty;
            } 
 
            int destStart = 0;
            char[] dest = EscapeString(str, 0, str.Length, null, ref destStart, true, '?', '#', '%'); 
            if ((object)dest == null)
                return str;
            return new string(dest, 0, destStart);
        } 

        // 
        // CheckSecurity 
        //
        //  Check for any invalid or problematic character sequences 
        //
        /// 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void CheckSecurity()  { 

            // [....] cr: This method just does not make sense 
            // Should be deprecated and removed asap. 

            if (Scheme == "telnet") { 

                //
                // remove everything after ';' for telnet
                // 

            } 
        } 

        // 
        // IsReservedCharacter
        //
        //  Determine whether a character is part of the reserved set
        // 
        // Returns:
        //  true if  is reserved else false 
        // 
        /// 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] 
        protected virtual bool IsReservedCharacter(char character) {

            // [....] cr: This method just does not make sense as virtual protected
            // It should go public static asap 

            return (character == ';') 
                || (character == '/') 
                || (character == ':')
                || (character == '@')   // OK FS char 
                || (character == '&')
                || (character == '=')
                || (character == '+')   // OK FS char
                || (character == '$')   // OK FS char 
                || (character == ',')
                ; 
        } 

        // 
        // IsExcludedCharacter
        //
        //  Determine if a character should be exluded from a URI and therefore be
        //  escaped 
        //
        // Returns: 
        //  true if  should be escaped else false 
        //
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected static bool IsExcludedCharacter(char character) {

            // [....] cr: This method just does not make sense sa protected 
            // It should go public static asap
 
            // 
            // the excluded characters...
            // 

            return (character <= 0x20)
                || (character >= 0x7f)
                || (character == '<') 
                || (character == '>')
                || (character == '#') 
                || (character == '%') 
                || (character == '"')
 
                //
                // the 'unwise' characters...
                //
 
                || (character == '{')
                || (character == '}') 
                || (character == '|') 
                || (character == '\\')
                || (character == '^') 
                || (character == '[')
                || (character == ']')
                || (character == '`')
                ; 
        }
 
        // 
        // IsBadFileSystemCharacter
        // 
        //  Determine whether a character would be an invalid character if used in
        //  a file system name. Note, this is really based on NTFS rules
        //
        // Returns: 
        //  true if  would be a treated as a bad file system character
        //  else false 
        // 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual bool IsBadFileSystemCharacter(char character) { 

            // [....] cr: This method just does not make sense sa protected virtual
            // It should go public static asap
 
            return (character < 0x20)
                || (character == ';') 
                || (character == '/') 
                || (character == '?')
                || (character == ':') 
                || (character == '&')
                || (character == '=')
                || (character == ',')
                || (character == '*') 
                || (character == '<')
                || (character == '>') 
                || (character == '"') 
                || (character == '|')
                || (character == '\\') 
                || (character == '^')
                ;
        }
 

    } // class Uri 
} // namespace System 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System { 
    using System.Configuration; 
    using System.Runtime.InteropServices;
    using System.Text; 
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.ComponentModel;
    using System.Security.Permissions; 
    using System.Threading;
    using Microsoft.Win32; 
    using System.Security; 
    using System.Net;
    using System.IO; 
    using System.Xml;
    [Serializable]
    [TypeConverter(typeof(UriTypeConverter))]
    public partial class Uri : ISerializable { 

        public static readonly string UriSchemeFile = UriParser.FileUri.SchemeName; 
        public static readonly string UriSchemeFtp = UriParser.FtpUri.SchemeName; 
        public static readonly string UriSchemeGopher = UriParser.GopherUri.SchemeName;
        public static readonly string UriSchemeHttp = UriParser.HttpUri.SchemeName; 
        public static readonly string UriSchemeHttps = UriParser.HttpsUri.SchemeName;
        public static readonly string UriSchemeMailto = UriParser.MailToUri.SchemeName;
        public static readonly string UriSchemeNews = UriParser.NewsUri.SchemeName;
        public static readonly string UriSchemeNntp = UriParser.NntpUri.SchemeName; 
        public static readonly string UriSchemeNetTcp = UriParser.NetTcpUri.SchemeName;
        public static readonly string UriSchemeNetPipe = UriParser.NetPipeUri.SchemeName; 
        public static readonly string SchemeDelimiter = "://"; 

 
        private const int c_Max16BitUtf8SequenceLength = 3+3+3+3; //each unicode byte takes 3 escaped chars
        private const int c_MaxUriBufferSize = 0xFFF0;
        private const int c_MaxUriSchemeName = 1024;
 
        // untouched user string unless string has unicode chars and iriparsing is enabled
        // or idn is on and we have unicode host or idn host 
        // In that case, this string is normalized, stripped of bidi chars, and validated 
        // with char limits
        private string      m_String; 

        // untouched user string if string has unicode with iri on or unicode/idn host with idn on
        private string      m_originalUnicodeString;
 
        private UriParser m_Syntax;   // This is a whole Uri syntax, not only the scheme name
        // temporarily stores dnssafe host when we have unicode/idn host and idn is on 
        private string m_DnsSafeHost = null; 

        private enum ParsingError { 
            // looks good
            None            = 0,

            // Could be only Relative 
            BadFormat           = 1,
            BadScheme           = 2, 
            BadAuthority        = 3, 
            EmptyUriString      = 4,
            LastRelativeUriOkErrIndex   = 4, 

            // Fatal
            SchemeLimit         = 5,
            SizeLimit           = 6, 
            MustRootedPath      = 7,
            LastFatalErrIndex           = 7, 
 
            // derived class controlled
            BadHostName         = 8, 
            NonEmptyHost        = 9,    //unix only
            BadPort             = 10,
            BadAuthorityTerminator=11,
 
            CannotCreateRelative = 12
        } 
 
        [Flags]
        private enum Flags : ulong { 
            Zero                = 0x00000000,

            SchemeNotCanonical     = 0x1,
            UserNotCanonical       = 0x2, 
            HostNotCanonical       = 0x4,
            PortNotCanonical       = 0x8, 
            PathNotCanonical       = 0x10, 
            QueryNotCanonical      = 0x20,
            FragmentNotCanonical   = 0x40, 
            CannotDisplayCanonical = 0x7F,

            E_UserNotCanonical      = 0x80,
            E_HostNotCanonical      = 0x100, 
            E_PortNotCanonical      = 0x200,
            E_PathNotCanonical      = 0x400, 
            E_QueryNotCanonical     = 0x800, 
            E_FragmentNotCanonical  = 0x1000,
            E_CannotDisplayCanonical = 0x1F80, 


            ShouldBeCompressed      = 0x2000,
            FirstSlashAbsent        = 0x4000, 
            BackslashInPath         = 0x8000,
 
            IndexMask           = 0x0000FFFF, 
            HostTypeMask        = 0x00070000,
            HostNotParsed   = 0x00000000, 
            IPv6HostType    = 0x00010000,
            IPv4HostType    = 0x00020000,
            DnsHostType     = 0x00030000,
#if !PLATFORM_UNIX 
            UncHostType     = 0x00040000,
#endif // !PLATFORM_UNIX 
            BasicHostType   = 0x00050000, 
            UnusedHostType  = 0x00060000,
            UnknownHostType = 0x00070000, 

            UserEscaped         = 0x00080000,
            AuthorityFound      = 0x00100000,
            HasUserInfo         = 0x00200000, 
            LoopbackHost        = 0x00400000,
            NotDefaultPort      = 0x00800000, 
 
            UserDrivenParsing   = 0x01000000,
            CanonicalDnsHost    = 0x02000000, 
            ErrorOrParsingRecursion = 0x04000000,   // Used to signal a default parser error and alsoe to confirm Port and Host values in case of a custom user Parser
#if !PLATFORM_UNIX
            DosPath             = 0x08000000,
            UncPath             = 0x10000000, 
#endif // !PLATFORM_UNIX
            ImplicitFile        = 0x20000000, 
            MinimalUriInfoSet   = 0x40000000, 
            AllUriInfoSet       = unchecked(0x80000000),
            IdnHost             = 0x100000000, 
            HasUnicode          = 0x200000000,
            HostUnicodeNormalized = 0x400000000,
            RestUnicodeNormalized = 0x800000000,
            UnicodeHost         = 0x1000000000, 
            IntranetUri         = 0x2000000000,
            UseOrigUncdStrOffset= 0x4000000000, 
            // Is this component Iri canonical 
            UserIriCanonical =          0x8000000000,
            PathIriCanonical =          0x10000000000, 
            QueryIriCanonical =         0x20000000000,
            FragmentIriCanonical =      0x40000000000,
            IriCanonical =              0x78000000000,
        } 

        private Flags       m_Flags; 
        private UriInfo     m_Info; 

        private class UriInfo { 
            public string   Host;
            public string   ScopeId;        //only IP v6 may need this
            public string   String;
            public Offset   Offset; 
            public string   DnsSafeHost;    // stores dns safe host when idn is on and we have unicode or idn host
            public MoreInfo MoreInfo;       //Multi-threading: This field must be always accessed through a _local_ stack copy of m_Info. 
        }; 

        [StructLayout(LayoutKind.Sequential, Pack=1)] 
        private struct Offset {
            public ushort  Scheme;
            public ushort  User;
            public ushort  Host; 
            public ushort  PortValue;
            public ushort  Path; 
            public ushort  Query; 
            public ushort  Fragment;
            public ushort  End; 
        };

        private class MoreInfo {
            public string   Path; 
            public string   Query;
            public string   Fragment; 
            public string   AbsoluteUri; 
            public int      Hash;
            public string   RemoteUrl; 
        };

        private bool IsImplicitFile {
            get {return (m_Flags & Flags.ImplicitFile) != 0;} 
        }
 
        private bool IsUncOrDosPath { 
#if !PLATFORM_UNIX
            get {return (m_Flags & (Flags.UncPath|Flags.DosPath)) != 0;} 
#else
            get {return false;}
#endif // !PLATFORM_UNIX
        } 

        private bool IsDosPath { 
#if !PLATFORM_UNIX 
            get {return (m_Flags & Flags.DosPath) != 0;}
#else 
            get {return false;}
#endif // !PLATFORM_UNIX
        }
 
        private bool IsUncPath {
#if !PLATFORM_UNIX 
            get {return (m_Flags & Flags.UncPath) != 0;} 
#else
            get {return false;} 
#endif // !PLATFORM_UNIX
        }

        private Flags HostType { 
            get {return m_Flags & Flags.HostTypeMask;}
        } 
 
        private UriParser Syntax {
            get { 
                return m_Syntax;
            }
        }
 
        private bool IsNotAbsoluteUri {
            get {return (object) m_Syntax == null;} 
        } 

        // 
        // Checks if Iri parsing is allowed by the syntax & by config
        //
        private bool m_iriParsing;
 
        //
        // Statically checks if Iri parsing is allowed by the syntax & by config 
        // 
        private static bool IriParsingStatic( UriParser syntax )
        { 
            return (s_IriParsing && (((syntax != null) && syntax.InFact(UriSyntaxFlags.AllowIriParsing)) ||
                   (syntax == null)));
        }
 
        //
        // Checks if Idn is allowed by the syntax & by config 
        // 
        private bool AllowIdn
        { 
            get { return    ((m_Syntax != null) && ((m_Syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) &&
                            ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet)
                                                                                && NotAny(Flags.IntranetUri)))); }
        } 

        // 
        // Checks statically if Idn is allowed by the syntax & by config 
        //
        private bool AllowIdnStatic(UriParser syntax, Flags flags) 
        {
            return ((syntax != null) && ((syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) &&
                   ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet)
                                                                            && StaticNotAny(flags, Flags.IntranetUri)))); 
        }
 
        // 
        // check if the scheme + host are in intranet or not
        // Used to determine of we apply idn or not 
        //
        private static IInternetSecurityManager s_ManagerRef = null;
        private static object s_IntranetLock = new object();
 
        private bool IsIntranet(string schemeHost)
        { 
            bool error = false; 
            int zone = -1;
            int E_FAIL = unchecked((int)0x80004005); 

            // MapUrlToZone call below fails on scheme length > 32 so we consider this
            // not be be intranet
            // 
            if (m_Syntax.SchemeName.Length > 32)
                return false; 
 
            if (s_ManagerRef == null){
                lock (s_IntranetLock){ 
                    if(s_ManagerRef == null)
                        s_ManagerRef = (IInternetSecurityManager)new InternetSecurityManager();
                }
            } 

            try{ 
                s_ManagerRef.MapUrlToZone(schemeHost.TrimStart(_WSchars), out zone, 0); 
            }
            catch (COMException ex){ 
                if (ex.ErrorCode == E_FAIL){    // E_FAIL
                    error = true;
                }
            } 

            if(zone == (int) SecurityZone.Intranet) 
                return true; 

            // Do dot check for intranet if zone is trusted or untrusted 
            // since an intranet zone may be in these zones as well
            if ((zone == (int)SecurityZone.Trusted) ||
                (zone == (int)SecurityZone.Untrusted) || error)
            { 
                // do dot check
                for (int i = 0; i < schemeHost.Length; ++i) 
                { 
                    if (schemeHost[i] == '.')
                        return false; 
                }
                return true;
            }
            return false; 
        }
 
        internal bool UserDrivenParsing 
        {
            get { 
                return (m_Flags & Flags.UserDrivenParsing) != 0;
            }
        }
        private void SetUserDrivenParsing() 
        {
            // we use = here to clear all parsing flags for a uri that we think is invalid. 
            m_Flags = Flags.UserDrivenParsing | (m_Flags & Flags.UserEscaped); 
        }
 
        private ushort SecuredPathIndex {
            get {
                // This is one more trouble with a Dos Path.
                // This property gets "safe" first path slash that is not the first if path = c:\ 
                if (IsDosPath) {
                    char ch = m_String[m_Info.Offset.Path]; 
                    return (ushort)((ch == '/' || ch == '\\')? 3 :2); 
                }
                return (ushort)0; 
            }
        }

        private bool NotAny(Flags flags) { 
            return (m_Flags & flags) == 0;
        } 
 
        private bool InFact(Flags flags) {
            return (m_Flags & flags) != 0; 
        }

        private static bool StaticNotAny(Flags allFlags, Flags checkFlags) {
            return (allFlags & checkFlags) == 0; 
        }
 
        private static bool StaticInFact(Flags allFlags, Flags checkFlags) { 
            return (allFlags & checkFlags) != 0;
        } 

        //
        //
        private UriInfo EnsureUriInfo() { 
            Flags cF = m_Flags;
            if ((m_Flags & Flags.MinimalUriInfoSet) == 0) { 
                CreateUriInfo(cF); 
            }
            return m_Info; 
        }
        //
        //
        private void EnsureParseRemaining() { 
            if ((m_Flags & Flags.AllUriInfoSet) == 0) {
                ParseRemaining(); 
            } 
        }
        // 
        //
        private void EnsureHostString(bool allowDnsOptimization) {
            EnsureUriInfo();
            if ((object)m_Info.Host == null) { 
                if (allowDnsOptimization && InFact(Flags.CanonicalDnsHost)) {
                    /* Optimization for a canonical DNS name 
                    *  ATTN: the host string won't be created, 
                    *  Hence ALL m_Info.Host callers first call EnsureHostString(false)
                    *  For example IsLoopBack property is one of such callers. 
                    */
                    return;
                }
                CreateHostString(); 
            }
        } 
 
        //
        // Uri(string) 
        //
        //  We expect to create a Uri from a display name - e.g. that was typed by
        //  a user, or that was copied & pasted from a document. That is, we do not
        //  expect already encoded URI to be supplied. 
        //
        public Uri(string uriString){ 
            if ((object)uriString == null) 
                throw new ArgumentNullException("uriString");
 
            CreateThis(uriString, false, UriKind.Absolute);
        }

 
        //
        // Uri(string, bool) 
        // 
        //  Uri constructor. Assumes that input string is canonically escaped
        // 
        [Obsolete("The constructor has been deprecated. Please use new Uri(string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")]
        public Uri(string uriString, bool dontEscape) {
            if ((object)uriString == null)
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, dontEscape, UriKind.Absolute); 
        } 

 
        //
        // Uri(string, UriKind);
        //
        public Uri(string uriString, UriKind uriKind) 
        {
            if ((object)uriString == null) 
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, false, uriKind); 
        }


        // 
        // Uri(Uri, string)
        // 
        //  Construct a new Uri from a base and relative URI. The relative URI may 
        //  also be an absolute URI, in which case the resultant URI is constructed
        //  entirely from it 
        //
        public Uri(Uri baseUri, string relativeUri){
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri"); 

            if (!baseUri.IsAbsoluteUri) 
                throw new ArgumentOutOfRangeException("baseUri"); 

            CreateUri(baseUri, relativeUri, false); 
        }

        //
        // Uri(Uri, string, bool) 
        //
        //  Uri combinatorial constructor. Do not perform character escaping if 
        //  DontEscape is true 
        //
        [Obsolete("The constructor has been deprecated. Please new Uri(Uri, string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")] 
        public Uri(Uri baseUri, string relativeUri, bool dontEscape){
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri");
 
            if (!baseUri.IsAbsoluteUri)
                throw new ArgumentOutOfRangeException("baseUri"); 
 
            CreateUri(baseUri, relativeUri, dontEscape);
        } 

        private void CreateUri(Uri baseUri, string relativeUri, bool dontEscape)
        {
            // Parse relativeUri and populate Uri internal data. 
            CreateThis(relativeUri, dontEscape, UriKind.RelativeOrAbsolute);
 
            UriFormatException e; 
            if (baseUri.Syntax.IsSimple)
            { 
                // Resolve Uris if possible OR get merged Uri String to re-parse below
                Uri uriResult = ResolveHelper(baseUri, this, ref relativeUri, ref dontEscape, out e);

                if (e != null) 
                    throw e;
 
                // If resolved into a Uri then we build from that Uri 
                if (uriResult != null)
                { 
                    if ((object)uriResult != (object)this)
                        CreateThisFromUri(uriResult);

                    return; 
                }
            } 
            else 
            {
                dontEscape = false; 
                relativeUri = baseUri.Syntax.InternalResolve(baseUri, this, out e);
                if (e != null)
                    throw e;
            } 

            m_Flags = Flags.Zero; 
            m_Info = null; 
            m_Syntax = null;
            // If not resolved, we reparse modified Uri string and populate Uri internal data. 
            CreateThis(relativeUri, dontEscape, UriKind.Absolute);
        }

        // 
        // Uri(Uri , Uri )
        // Note: a static Create() method should be used by users, not this .ctor 
        // 
        public Uri(Uri baseUri, Uri relativeUri)
        { 
            if ((object)baseUri == null)
                throw new ArgumentNullException("baseUri");

            if (!baseUri.IsAbsoluteUri) 
                throw new ArgumentOutOfRangeException("baseUri");
 
            CreateThisFromUri(relativeUri); 

            string newUriString = null; 
            UriFormatException e;
            bool dontEscape;

            if (baseUri.Syntax.IsSimple) 
            {
                dontEscape = InFact(Flags.UserEscaped); 
                relativeUri = ResolveHelper(baseUri, this, ref newUriString, ref dontEscape, out e); 

                if (e != null) 
                    throw e;

                if (relativeUri != null)
                { 
                    if ((object)relativeUri != (object)this)
                        CreateThisFromUri(relativeUri); 
 
                    return;
                } 
            }
            else
            {
                dontEscape = false; 
                newUriString = baseUri.Syntax.InternalResolve(baseUri, this, out e);
                if (e != null) 
                    throw e; 
            }
 
            m_Flags = Flags.Zero;
            m_Info = null;
            m_Syntax = null;
            CreateThis(newUriString, dontEscape, UriKind.Absolute); 
        }
 
        // 
        // ISerializable constructor
        // 
        protected Uri(SerializationInfo serializationInfo, StreamingContext streamingContext)
        {
            string uriString = serializationInfo.GetString("AbsoluteUri");
 
            if (uriString.Length != 0)
            { 
                CreateThis(uriString, false, UriKind.Absolute); 
                return;
            } 

            uriString = serializationInfo.GetString("RelativeUri");
            if ((object)uriString == null)
                throw new ArgumentNullException("uriString"); 

            CreateThis(uriString, false, UriKind.Relative); 
        } 
        //
        // This method is shared by base+relative Uris constructors and is only called from them. 
        // The assumptions:
        //  - baseUri is a valid absolute Uri
        //  - relative part is not null and not empty
        private unsafe static ParsingError GetCombinedString(Uri baseUri, string relativeStr, bool dontEscape, ref string result) 
        {
            // NB: This is not RFC2396 compliant although it is inline with w3c.org recommendations 
            // This parser will allow the relativeStr to be an absolute Uri with the different scheme 
            // In fact this is strict violation of RFC2396
            // 
            for (int i=0; i < relativeStr.Length; ++i)
            {
                if (relativeStr[i] == '/' || relativeStr[i] == '\\' || relativeStr[i] == '?' || relativeStr[i] == '#')
                { 
                    break;
                } 
                else if (relativeStr[i] == ':') 
                {
                    if (i < 2) 
                    {
                        // Note we don't support one-letter Uri schemes.
                        // Hence anything like x:sdsd is a relative path and be added to the baseUri Path
                        break; 
                    }
                    string scheme =  relativeStr.Substring(0, i); 
                    fixed (char* sptr = scheme) { 
                        UriParser syntax = null;
                        if (CheckSchemeSyntax(sptr, (ushort) scheme.Length, ref syntax) == ParsingError.None) { 
                            if (baseUri.Syntax == syntax) {
                                //Remove the scheme for backward Uri parsers compatibility
                                if (i+1 < relativeStr.Length) {
                                    relativeStr = relativeStr.Substring(i+1); 
                                }
                                else { 
                                    relativeStr = string.Empty; 
                                }
                            } 
                            else {
                                // This is the place where we switch the scheme.
                                // Return relative part as the result Uri.
                                result = relativeStr; 
                                return ParsingError.None;
                            } 
                        } 
                    }
                    break; 
                }
            }

            if (relativeStr.Length == 0) { 
                result = baseUri.OriginalString;
                return ParsingError.None; 
            } 

            result = CombineUri(baseUri, relativeStr, dontEscape? UriFormat.UriEscaped: UriFormat.SafeUnescaped); 
            return ParsingError.None;
        }
        //
        private static UriFormatException GetException(ParsingError err) 
        {
            switch (err) 
            { 
                case ParsingError.None:
                    return null; 
                // Could be OK for Relative Uri
                case ParsingError.BadFormat:
                    return System.Net.ExceptionHelper.BadFormatException;
                case ParsingError.BadScheme: 
                    return System.Net.ExceptionHelper.BadSchemeException;
                case ParsingError.BadAuthority: 
                    return System.Net.ExceptionHelper.BadAuthorityException; 
                case ParsingError.EmptyUriString:
                    return System.Net.ExceptionHelper.EmptyUriException; 
                // Fatal
                case ParsingError.SchemeLimit:
                    return System.Net.ExceptionHelper.SchemeLimitException;
                case ParsingError.SizeLimit: 
                    return System.Net.ExceptionHelper.SizeLimitException;
                case ParsingError.MustRootedPath: 
                    return System.Net.ExceptionHelper.MustRootedPathException; 
                // Derived class controllable
                case ParsingError.BadHostName: 
                    return System.Net.ExceptionHelper.BadHostNameException;
                case ParsingError.NonEmptyHost:
                    return System.Net.ExceptionHelper.BadFormatException;   //unix-only
                case ParsingError.BadPort: 
                    return System.Net.ExceptionHelper.BadPortException;
                case ParsingError.BadAuthorityTerminator: 
                    return System.Net.ExceptionHelper.BadAuthorityTerminatorException; 
                case ParsingError.CannotCreateRelative:
                    return System.Net.ExceptionHelper.CannotCreateRelativeException; 
                default:
                    break;
            }
            return System.Net.ExceptionHelper.BadFormatException; 
        }
        // 
        // ISerializable method 
        //
        ///  
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
        void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        {
            GetObjectData(serializationInfo, streamingContext); 
        }
 
        // 
        // FxCop: provide some way for derived classes to access GetObjectData even if the derived class
        // explicitly re-inherits ISerializable. 
        //
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
        protected void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 

            if (IsAbsoluteUri) 
                serializationInfo.AddValue("AbsoluteUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); 
            else
            { 
                serializationInfo.AddValue("AbsoluteUri", string.Empty);
                serializationInfo.AddValue("RelativeUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped));
            }
        } 

        // 
        // 
        //
        public string AbsolutePath { 
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                string path = PrivateAbsolutePath; 
                // 
                //
 

                if (IsDosPath && path[0] == '/') {
                    path =  path.Substring(1);
                } 
                return path;
            } 
        } 
        //
        private string PrivateAbsolutePath { 
            get {
                UriInfo info = EnsureUriInfo();
                if ((object) info.MoreInfo == null) {
                    info.MoreInfo = new MoreInfo(); 
                }
                string result = info.MoreInfo.Path; 
                if ((object) result == null) { 
                    result = GetParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
                    info.MoreInfo.Path = result; 
                }
                return result;
            }
        } 
        //
        // 
        // 
        public string AbsoluteUri {
            get { 
                if (m_Syntax == null){
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }
 
                UriInfo info = EnsureUriInfo();
                if ((object) info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo(); 
                }
                string result = info.MoreInfo.AbsoluteUri; 
                if ((object) result == null) {
                    result = GetParts(UriComponents.AbsoluteUri, UriFormat.UriEscaped);
                    info.MoreInfo.AbsoluteUri = result;
                } 
                return result;
            } 
        } 
        //
        // 
        // The result is of the form "hostname[:port]" Port is omitted if default
        //
        public string Authority {
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                } 

                // 
                return GetParts(UriComponents.Host | UriComponents.Port, UriFormat.UriEscaped);
            }
        }
        // 
        //
        //Gets a hostname part (special formatting for IPv6 form) 
        public string Host { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }

                return GetParts(UriComponents.Host, UriFormat.UriEscaped); 
            }
        } 
        // 
        //
        public UriHostNameType HostNameType { 
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (m_Syntax.IsSimple) 
                    EnsureUriInfo(); 
                else
                { 
                    // For a custom parser we request HostString creation to confirm HostType
                    EnsureHostString(false);
                }
 
                switch (HostType) {
                    case Flags.DnsHostType:   return UriHostNameType.Dns; 
                    case Flags.IPv4HostType:  return UriHostNameType.IPv4; 
                    case Flags.IPv6HostType:  return UriHostNameType.IPv6;
                    case Flags.BasicHostType: return UriHostNameType.Basic; 
#if !PLATFORM_UNIX
                    case Flags.UncHostType:   return UriHostNameType.Basic; //return (UriHostNameType)(UriHostNameType.Basic+10);
#endif // !PLATFORM_UNIX
                    case Flags.UnknownHostType: return UriHostNameType.Unknown; 
                    default:
                        break; 
                } 
                return UriHostNameType.Unknown;
            } 
        }
        //
        //
        public bool IsDefaultPort { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
                if (m_Syntax.IsSimple) 
                    EnsureUriInfo();
                else
                {
                    // For a custom parser we request HostString creation that will aso set the port 
                    EnsureHostString(false);
                } 
 
                return NotAny(Flags.NotDefaultPort);
            } 
        }
        //
        //
        public bool IsFile { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                return (object)m_Syntax.SchemeName == (object)UriSchemeFile;
            }
        }
        private static bool StaticIsFile(UriParser syntax) 
        {
            return syntax.InFact(UriSyntaxFlags.FileLikeUri); 
        } 
        //
        // 
        public bool IsLoopback {
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                EnsureHostString(false); 

                return InFact(Flags.LoopbackHost); 
            }
        }
        //
        // 
        public bool IsUnc {
            get { 
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
                return IsUncPath;
            }
        }
        // 
        // LocalPath
        // 
        //  Returns a 'local' version of the path. This is mainly for file: URI 
        //  such that DOS and UNC paths are returned with '/' converted back to
        //  '\', and any escape sequences converted 
        //
        //  The form of the returned path is in NOT Escaped
        //
        public string LocalPath { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
                return GetLocalPath(); 
            }
        }

        private static bool s_ConfigInitialized;                                     // Have the config values been 
                                                                                    // initalized from config file
        private static UriIdnScope s_IdnScope = UriIdnScope.None;                   // Value from config Uri section 
        private static bool s_IriParsing = false;                                   // Value from config Uri section 
        private static object s_initLock;
 
        internal static object InitializeLock {
            get {
                if (s_initLock == null) {
                    object o = new object(); 
                    Interlocked.CompareExchange(ref s_initLock, o, null);
                } 
                return s_initLock; 
            }
        } 

        //
        // Reads values from config uri section
        // 
        private static void InitializeUriConfig()
        { 
            if (!s_ConfigInitialized) { 
                lock(InitializeLock) {
                    if (!s_ConfigInitialized) { 

                        // Set this first to avoid possible recursion
                        // if GetConfig's callees use Uri methods.
                        s_ConfigInitialized = true; 

                        GetConfig(ref s_IdnScope, ref s_IriParsing); 
 
                    }
                } 
            }
        }

        // internal IDN config state with additional Invalid & NotFound states 
        private enum IdnScopeFromConfig {
            None = 0, 
            AllExceptIntranet, 
            All,
            Invalid = Int32.MaxValue - 1, 
            NotFound = Int32.MaxValue
        }

        // internal IRI config state with additional Invalid & NotFound states 
        private enum IriParsingFromConfig {
            False = 0, 
            True, 
            Invalid = Int32.MaxValue - 1,
            NotFound = Int32.MaxValue 
        }

        //
        // GetConfig - get the Uri config state 
        //
        // This function originally just used System.Config to get the 
        // new-to-Orcas Uri config section.  Unfortunately that created a 
        // circular dependency on System.Config that ultimately could cause
        // ConfigurationExceptions that didn't used to happen in Whidbey and 
        // thus break existing deployed applications.
        //
        // Now this function will determine if it is running in a client
        // application or a web scenario (ASP.NET).   If in a web scenario 
        // this code must still use System.Config to read config as the web
        // scenario has a hierarchy of config files that only System.Config 
        // can practically discover and pars.  If in a client scenario this 
        // code will now use System.Xml.XmlReader to parse machine and app
        // config files. 
        //
        // The default output of this function if it encounters invalid or
        // non-existent Uri config is the original Whidbey settings (no IDN
        // support and no IRI support). 
        //
        private static void GetConfig(ref UriIdnScope idnScope, ref bool iriParsing) { 
 
            // Get the app config path
 
            string appConfigFile = null;

            // Must Assert unrestricted FileIOPermission to get the app config path.
            new FileIOPermission(PermissionState.Unrestricted).Assert(); 
            try {
                appConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 
            } 
            finally {
                FileIOPermission.RevertAssert(); 
            }
            if (IsWebConfig(appConfigFile)) {
                // This is a web scenario.
                // It is safe and *necessary* to use System.Config. 
                try {
                   UriSectionInternal uriSection = UriSectionInternal.GetSection(); 
                   if (uriSection != null) { 
                       idnScope = uriSection.Idn;
                       iriParsing = uriSection.IriParsing; 
                   }
                }
                catch (ConfigurationException) {
                   // Simply ---- any ConfigurationException. 
                   // Throwing it would potentially break applications.
                   // Uri did not read config in previous releases. 
                } 

            } else { 
                // This is a client application scenario.
                // It is not safe to use System.Config for app compat reasons.

                // Already have the application config file path in scope. 
                // Get the path of the machine config file.
                string runtimeDir = null; 
 
                // Must Assert unrestricted FileIOPermission to get the machine config path.
                new FileIOPermission(PermissionState.Unrestricted).Assert(); 
                try {
                    runtimeDir = RuntimeEnvironment.GetRuntimeDirectory();
                }
                finally { 
                    FileIOPermission.RevertAssert();
                } 
                string machineConfigFile = Path.Combine(Path.Combine(runtimeDir, "Config"), "machine.config"); 

                IdnScopeFromConfig idnFromMachine, idnFromApp; 
                IriParsingFromConfig iriFromMachine, iriFromApp;

                // Attempt tp parse machine and app config files if they exist.
                ParseConfigFile(machineConfigFile, out idnFromMachine, out iriFromMachine); 
                ParseConfigFile(appConfigFile, out idnFromApp, out iriFromApp);
 
                // App config takes precedence over machine config 
                // only if found and valid.
                switch (idnFromApp) { 
                    case IdnScopeFromConfig.None:
                        idnScope = UriIdnScope.None;
                        break;
                    case IdnScopeFromConfig.AllExceptIntranet: 
                        idnScope = UriIdnScope.AllExceptIntranet;
                        break; 
                    case IdnScopeFromConfig.All: 
                        idnScope = UriIdnScope.All;
                        break; 
                    default: // invalid or notfound
                        switch (idnFromMachine) {
                            case IdnScopeFromConfig.None:
                                idnScope = UriIdnScope.None; 
                                break;
                            case IdnScopeFromConfig.AllExceptIntranet: 
                                idnScope = UriIdnScope.AllExceptIntranet; 
                                break;
                            case IdnScopeFromConfig.All: 
                                idnScope = UriIdnScope.All;
                                break;
                            default: // invalid or notfound
                                idnScope = UriIdnScope.None; 
                                break;
                        } 
                        break; 
                }
                switch (iriFromApp) { 
                    case IriParsingFromConfig.False:
                        iriParsing = false;
                        break;
                    case IriParsingFromConfig.True: 
                        iriParsing = true;
                        break; 
                    default: // invalid or notfound 
                        switch (iriFromMachine) {
                            case IriParsingFromConfig.False: 
                                iriParsing = false;
                                break;
                            case IriParsingFromConfig.True:
                                iriParsing = true; 
                                break;
                            default: // invalid or notfound 
                                iriParsing = false; 
                                break;
                        } 
                        break;
                }
            }
        } 

        // 
        // Determine if we are in a Web config scenario. 
        //
        private static bool IsWebConfig(string appConfigFile) { 
            // Existence of string object associated with .appVPath tells
            // us that this is an ASP.Net web scenario.
            string appVPath = AppDomain.CurrentDomain.GetData(".appVPath") as string;
            if (appVPath != null) { 
                return true;
            } 
            // If application config file path not null 
            // and begins with http:// or https://
            // then this is the No-Touch web deployment scenario. 
            if (appConfigFile != null) {
                if (appConfigFile.StartsWith("http://", true, CultureInfo.InvariantCulture) ||
                    appConfigFile.StartsWith("https://", true, CultureInfo.InvariantCulture)) {
                return true; 
                }
            } 
            return false; 
        }
 
        //
        // Attempt to parse out the IDN and IRI settings in an xml config file.
        //
        private static void ParseConfigFile( 
                                string file,
                                out IdnScopeFromConfig idnStateConfig, 
                                out IriParsingFromConfig iriParsingConfig) { 

            // Start with default NotFound values. 
            idnStateConfig = IdnScopeFromConfig.NotFound;
            iriParsingConfig = IriParsingFromConfig.NotFound;

            // Assert read permission for only this file. 
            new FileIOPermission(FileIOPermissionAccess.Read, file).Assert();
 
            try { 
                // Create a filestream to read the config file
                // We cannot allow XmlReader.Create to do it as it considers 
                // the input file string as a URI and calls our ctor
                // potentially creating endless recursion if the file string
                // requires us to read config.
                FileStream filestream = new FileStream(file, FileMode.Open, FileAccess.Read); 

                // Close the filestream when done. 
                using (filestream) { 
                    // Create an XML reader that ignores:
                    // - processing instructions 
                    // - comments
                    // - insignificant white space
                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.IgnoreComments = true; 
                    settings.IgnoreWhitespace = true;
                    settings.IgnoreProcessingInstructions = true; 
                    XmlReader reader = XmlReader.Create(filestream, settings); 

                    // Close the reader when done. 
                    using(reader) {

                        // Find configuration element - return if not found.
                        if (!reader.ReadToFollowing("configuration")) { 
                            return;
                        } 
                        // Find uri element - return if not found 
                        if (!reader.ReadToFollowing("uri")) {
                            return; 
                        }

                        // Loop reading nodes until we hit the uri EndElement
                        while (true) { 

                            // If an EndElement and is "uri" then stop reading 
                            if (reader.NodeType == XmlNodeType.EndElement) { 
                                if (ConfigStringEqual(reader.Name, "uri")) {
                                    break; 
                                }
                            }
                            // If an Element look for our two elements of interest:
                            // "idn" or "iriParsing" 
                            if (reader.NodeType == XmlNodeType.Element) {
                                string value; 
                                if (ConfigStringEqual(reader.Name, "idn")) { 
                                    // Try to get the "enabled" attribute value
                                    value = reader.GetAttribute("enabled"); 
                                    if (value != null) {
                                        // Look for "None" or "AllExceptIntranet" or "All"
                                        // Otherwise invalid
                                        if (ConfigStringEqual(value, "None")) { 
                                            idnStateConfig = IdnScopeFromConfig.None;
                                        } else if (ConfigStringEqual(value, "AllExceptIntranet")) { 
                                            idnStateConfig = IdnScopeFromConfig.AllExceptIntranet; 
                                        } else if (ConfigStringEqual(value, "All")) {
                                            idnStateConfig = IdnScopeFromConfig.All; 
                                        } else {
                                            idnStateConfig = IdnScopeFromConfig.Invalid;
                                        }
                                    } 
                                } else if (ConfigStringEqual(reader.Name, "iriParsing")) {
                                    // Try to get the "enabled" attribute value 
                                    value = reader.GetAttribute("enabled"); 
                                    if (value != null) {
                                        // Look for "false" or "true" 
                                        // Otherwise invalid
                                        if (ConfigStringEqual(value, "false")) {
                                            iriParsingConfig = IriParsingFromConfig.False;
                                        } else if (ConfigStringEqual(value, "true")) { 
                                            iriParsingConfig = IriParsingFromConfig.True;
                                        } else { 
                                            iriParsingConfig = IriParsingFromConfig.Invalid; 
                                        }
                                    } 
                                }
                            }
                            // Go to next node
                            if(!reader.Read()) break;  // break out of loop on eof 
                        }
                    } 
                } 
            }
 
            catch (Exception exception) {
                // Throw only "fatal" exceptions for backward compat
                if (NclUtilities.IsFatal(exception))
                    throw; 
            }
            finally { 
                // Revert read permission assert for this file. 
                FileIOPermission.RevertAssert();
            } 
        }

        // Simple function to do OrdinalIgnoreCase string comparisons
        private static bool ConfigStringEqual(string string1, string string2) { 
            if(String.Compare(string1, string2, StringComparison.OrdinalIgnoreCase) == 0) {
                return true; 
            } else { 
                return false;
            } 
        }

        private string GetLocalPath(){
            EnsureParseRemaining(); 

            //Other cases will get a Unix-style path 
            if (IsUncOrDosPath) 
            {
                EnsureHostString(false); 
                int start;

                // Do we have a valid local path right in m_string?
                if (NotAny(Flags.HostNotCanonical|Flags.PathNotCanonical|Flags.ShouldBeCompressed)) { 

                    start = IsUncPath? m_Info.Offset.Host-2 :m_Info.Offset.Path; 
 

                    string str = 
                        (IsImplicitFile && m_Info.Offset.Host == (IsDosPath?0:2) && m_Info.Offset.Query == m_Info.Offset.End)
                            ? m_String
                            : (IsDosPath && (m_String[start] == '/' || m_String[start] == '\\'))
                                ? m_String.Substring(start + 1, m_Info.Offset.Query - start - 1) 
                                : m_String.Substring(start, m_Info.Offset.Query - start);
 
                    // Should be a rare case, convert c|\ into c:\ 
                    if (IsDosPath && str[1] == '|') {
                        // Sadly, today there is no method for replacong just one occurrence 
                        str = str.Remove(1, 1);
                        str = str.Insert(1, ":");
                    }
 
                    // check for all back slashes (though may be string.Replace is smart?)
                    for (int i = 0; i < str.Length; ++i) { 
                        if (str[i] == '/') { 
                            str = str.Replace('/', '\\');
                            break; 
                        }
                    }

                    return str; 
                }
 
                // Not everything went well, going ---- 

                char[] result; 
                int count = 0;
                start = m_Info.Offset.Path;

                string host = m_Info.Host; 
                result = new char [host.Length + 3 + m_Info.Offset.Fragment - m_Info.Offset.Path ];
 
                if (IsUncPath) 
                {
                    result[0] = '\\'; 
                    result[1] = '\\';
                    count = 2;

                    UnescapeString( host, 0, host.Length, result, ref count, c_DummyChar, c_DummyChar, c_DummyChar, 
                                    UnescapeMode.CopyOnly, m_Syntax, false, false);
 
                } 
                else {
                    // Dos path 
                    if(m_String[start] == '/' ||  m_String[start] == '\\') {
                        // Skip leading slash for a DOS path
                        ++start;
                    } 
                }
 
 
                ushort pathStart = (ushort)count; //save for optional Compress() call
 
                UnescapeMode mode = (InFact(Flags.PathNotCanonical) && !IsImplicitFile) ? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll): UnescapeMode.CopyOnly;
                UnescapeString(m_String, start, m_Info.Offset.Query, result, ref count, c_DummyChar, c_DummyChar, c_DummyChar, mode, m_Syntax, true, false);

                // Possibly convert c|\ into c:\ 
                if (result[1] == '|')
                    result[1] = ':'; 
 
                if (InFact(Flags.ShouldBeCompressed)) {
                    // suspecting not compressed path 
                    // For a dos path we won't compress the "x:" part if found /../ sequences
                    result = Compress(result, (ushort)(IsDosPath? pathStart + 2: pathStart), ref count, m_Syntax);
                }
 
                // We don't know whether all slashes were the back ones
                // Plus going through Compress will turn them into / anyway 
                // Converting / back into \ 
                for (ushort i = 0; i < (ushort) count; ++i) {
                    if (result[i] == '/') { 
                        result[i] = '\\';
                    }
                }
 
                return new string(result, 0, count);
 
            } 
            else {
                // Return unescaped canonical path 
                // Note we cannot call GetParts here because it has circular dependancy on GelLocalPath method
                return GetUnescapedParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped);
            }
        } 

        // 
        // 
        //  Gets the escaped Uri.AbsolutePath and Uri.Query
        //  properties separated by a "?" character. 
        public string PathAndQuery {
            get {
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }
 
                string result = GetParts(UriComponents.PathAndQuery, UriFormat.UriEscaped); 
                //
                // 


                if (IsDosPath && result[0] == '/')
                { 
                    result = result.Substring(1);
                } 
                return result; 
            }
        } 
        //
        //
        //
        // 
        public int Port {
            get { 
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (m_Syntax.IsSimple)
                    EnsureUriInfo();
                else 
                {
                    // For a custom parser we request HostString creation that will aso set the port 
                    EnsureHostString(false); 
                }
 
                if (InFact(Flags.NotDefaultPort)) {
                    return (int)m_Info.Offset.PortValue;
                }
                return m_Syntax.DefaultPort; 
            }
        } 
        // 
        //
        // 
        //  Gets the escaped query.
        public string Query {
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
 
                UriInfo info = EnsureUriInfo();
                if ((object)info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo();
                }
                string result = info.MoreInfo.Query;
                if ((object)result == null) { 
                    result = GetParts(UriComponents.Query | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
                    info.MoreInfo.Query = result; 
                } 
                return result;
            } 
        }
        //
        //
        // 
        //    Gets the escaped fragment.
        public string Fragment { 
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 
                }

                UriInfo info = EnsureUriInfo();
                if ((object)info.MoreInfo == null) { 
                    info.MoreInfo = new MoreInfo();
                } 
                string result = info.MoreInfo.Fragment; 
                if ((object)result == null) {
                    result = GetParts(UriComponents.Fragment | UriComponents.KeepDelimiter, UriFormat.UriEscaped); 
                    info.MoreInfo.Fragment = result;
                }
                return result;
            } 
        }
 
        // 
        //  Gets the Scheme string of this Uri
        // 
        //
        public string Scheme {
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 
 
                return m_Syntax.SchemeName;
            } 
        }

        //
        //  Was the original string switched from m_String to m_OriginalUnicodeString 
        //  Will happen when Iri is turned on and we have unicode chars or of idn is
        //  is on and we have an idn or unicode host. 
        // 
        private bool OriginalStringSwitched
        { 
            get{return ((m_iriParsing && InFact(Flags.HasUnicode)) ||
                        (AllowIdn && (InFact(Flags.IdnHost) || InFact(Flags.UnicodeHost))));}
        }
        // 
        //    Gets the exact string passed by a user.
        public String OriginalString { 
            get { 
                return OriginalStringSwitched ? m_originalUnicodeString : m_String;
            } 
        }

        //
        //    Gets the host string that is unescaped and if it's Ipv6 host, 
        //    then the returned string is suitable for DNS lookup.
        // 
        //    For Ipv6 this will strip [] and add ScopeId if was found in the original string 
        public string DnsSafeHost {
            get { 

                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                } 

                if (AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))){ 
                    // return pre generated idn 
                    EnsureUriInfo();
                    return m_Info.DnsSafeHost; 
                }

                EnsureHostString(false);
 
                // Special case, will include ScopeID and strip [] around IPv6
                // This will also unescape the host string 
                string ret = m_Info.Host; 

                if (HostType == Flags.IPv6HostType) 
                {
                    ret = ret.Substring(1, ret.Length - 2);
                    if ((object)m_Info.ScopeId != null)
                    { 
                        ret += m_Info.ScopeId;
                    } 
                } 
                // We do not unescape anything but Basic host
                else if (HostType == Flags.BasicHostType && InFact(Flags.HostNotCanonical | Flags.E_HostNotCanonical)) 
                {
                    char[] dest = new char[ret.Length];
                    int count = 0;
                    UnescapeString(ret, 0, ret.Length, dest, ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false); 
                    ret = new string(dest, 0, count);
                } 
 
                return ret;
            } 
        }

        //
        //  Returns false if the string passed in the constructor cannot be parsed as 
        //  valid AbsoluteUri. This could be a relative Uri instead.
        // 
        public bool IsAbsoluteUri { 
            get {
                return m_Syntax != null; 
            }
        }

        // 
        //
        //  Gets an array of the segments that make up a URI. 
        public string[] Segments { 
            get {
                if (IsNotAbsoluteUri) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }

                //[....] codereview 
                //I did not optimize this method
 
                string[] segments = null; // used to be a class cached result 
                if (segments == null) {
 
                    string path = PrivateAbsolutePath;

                    if (path.Length == 0) {
                        segments = new string[0]; 
                    }
                    else { 
                        System.Collections.ArrayList pathSegments = new System.Collections.ArrayList(); 
                        int current = 0;
                        while (current < path.Length) { 
                            int next = path.IndexOf('/', current);
                            if (next == -1) {
                                next = path.Length - 1;
                            } 
                            pathSegments.Add(path.Substring(current, (next - current) + 1));
                            current = next + 1; 
                        } 
                        segments = (string[]) (pathSegments.ToArray(typeof(string)));
                    } 
                }
                return segments;
            }
        } 
        //
        // 
        //  Returns 'true' if the 'dontEscape' parameter was set to 'true ' when the Uri instance was created. 
        public bool UserEscaped {
            get { 
                return InFact(Flags.UserEscaped);
            }
        }
        // 
        //
        //  Gets the user name, password, and other user specific information associated 
        //  with the Uniform Resource Identifier (URI). 
        public string UserInfo {
            get { 
                if (IsNotAbsoluteUri) {
                    throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
                }
 
                return GetParts(UriComponents.UserInfo, UriFormat.UriEscaped);
            } 
        } 

        // 
        // CheckHostName
        //
        //  Determines whether a host name authority is a valid Host name according
        //  to DNS naming rules 
        //
        // Returns: 
        //  true if  is valid else false 
        //
        // Throws: 
        //  Nothing
        //
        public static UriHostNameType CheckHostName(string name) {
 
            if ((object)name == null || name.Length == 0 || name.Length > short.MaxValue) {
                return UriHostNameType.Unknown; 
            } 
            int end = name.Length;
            unsafe { 
                fixed (char* fixedName = name) {

                    if (name[0] == '[' && name[name.Length-1] == ']') {
                        // we require that _entire_ name is recognized as ipv6 address 
                        if (IPv6AddressHelper.IsValid(fixedName, 1, ref end) && end == name.Length) {
                            return UriHostNameType.IPv6; 
                        } 
                    }
                    end = name.Length; 
                    if (IPv4AddressHelper.IsValid(fixedName, 0 , ref end, false, false) && end == name.Length) {
                        return UriHostNameType.IPv4;
                    }
                    end = name.Length; 
                    bool dummyBool = false;
                    if (DomainNameHelper.IsValid(fixedName, 0, ref end, ref dummyBool, false) && end == name.Length) { 
                        return UriHostNameType.Dns; 
                    }
                } 

                //This checks the form without []
                end = name.Length+2;
                // we require that _entire_ name is recognized as ipv6 address 
                name = "["+name+"]";
                fixed (char* newFixedName = name) { 
                    if (IPv6AddressHelper.IsValid(newFixedName, 1, ref end) && end == name.Length) { 
                        return UriHostNameType.IPv6;
                    } 
                }
            }
            return UriHostNameType.Unknown;
        } 
        //
        // CheckSchemeName 
        // 
        //  Determines whether a string is a valid scheme name according to RFC 2396.
        //  Syntax is: 
        //      scheme = alpha *(alpha | digit | '+' | '-' | '.')
        //
        public static bool CheckSchemeName(string schemeName) {
            if (((object)schemeName == null) 
                || (schemeName.Length == 0)
                || !IsAsciiLetter(schemeName[0])) { 
                return false; 
            }
            for (int i = schemeName.Length - 1; i > 0; --i) { 
                if (!(IsAsciiLetterOrDigit(schemeName[i])
                    || (schemeName[i] == '+')
                    || (schemeName[i] == '-')
                    || (schemeName[i] == '.'))) { 
                    return false;
                } 
            } 
            return true;
        } 
        //
        // Returns:
        //  Number in the range 0..15
        // 
        // Throws:
        //  ArgumentException 
        // 
        public static int FromHex(char digit) {
            if (((digit >= '0') && (digit <= '9')) 
                || ((digit >= 'A') && (digit <= 'F'))
                || ((digit >= 'a') && (digit <= 'f'))) {
                return  (digit <= '9')
                    ? ((int)digit - (int)'0') 
                    : (((digit <= 'F')
                    ? ((int)digit - (int)'A') 
                    : ((int)digit - (int)'a')) 
                    + 10);
            } 
            throw new ArgumentException("digit");
        }
        //
        // GetHashCode 
        //
        //  Overrides default function (in Object class) 
        // 
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public override int GetHashCode() {
            if (IsNotAbsoluteUri)
            {
                return CalculateCaseInsensitiveHashCode(OriginalString); 
            }
 
            // Consider moving hash code storage from m_Info.MoreInfo to m_Info 
            UriInfo info = EnsureUriInfo();
            if ((object)info.MoreInfo == null) { 
                info.MoreInfo = new MoreInfo();
            }
            int tempHash = info.MoreInfo.Hash;
            if (tempHash == 0) { 
                string chkString = info.MoreInfo.RemoteUrl;
                if ((object) chkString == null) 
                    chkString = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); 
                tempHash = CalculateCaseInsensitiveHashCode(chkString);
                if (tempHash == 0) { 
                    tempHash = 0x1000000;   //making it not zero still large enough to be maped to zero by a hashtable
                }
                info.MoreInfo.Hash = tempHash;
            } 
            return tempHash;
        } 
 
        //
        // ToString 
        //
        // The better implementation would be just
        //
        private const UriFormat V1ToStringUnescape = (UriFormat)0x7FFF; 

        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public override string ToString() 
        {
            if (m_Syntax == null) { 
                return (m_iriParsing && InFact(Flags.HasUnicode)) ? m_String : OriginalString;
            }

            EnsureUriInfo(); 
            if ((object)m_Info.String == null)
            { 
 
                // V1.1 compat unless #353711 is appoved, otheriwse it should be just a call into GetParts() as shown below
                // m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); 

                if (Syntax.IsSimple)
                    m_Info.String = GetComponentsHelper(UriComponents.AbsoluteUri, V1ToStringUnescape);
                else 
                    m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
 
            } 
            return m_Info.String;
        } 

        //
        //
        //  A static shortcut to Uri.Equals 
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public static bool operator == (Uri uri1, Uri uri2) { 
            if ((object)uri1 == (object)uri2) {
                return true; 
            }
            if ((object)uri1 == null || (object)uri2 == null) {
                return false;
            } 
            return uri2.Equals(uri1);
        } 
 
        //
        // 
        //  A static shortcut to !Uri.Equals
        //
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static bool operator != (Uri uri1, Uri uri2) { 
            if ((object)uri1 == (object)uri2) {
                return false; 
            } 

            if ((object)uri1 == null || (object)uri2 == null) { 
                return true;
            }

            return !uri2.Equals(uri1); 
        }
 
 

        // 
        // Equals
        //
        //  Overrides default function (in Object class)
        // 
        // Assumes:
        //   is an object of class Uri 
        // 
        // Returns:
        //  true if objects have the same value, else false 
        //
        // Throws:
        //  Nothing
        // 
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public override bool Equals(object comparand) { 
            if ((object) comparand == null) { 
                return false;
            } 

            if ((object)this == (object)comparand) {
                return true;
            } 

            Uri obj = comparand as Uri; 
 
            //
            // we allow comparisons of Uri and String objects only. If a string 
            // is passed, convert to Uri. This is inefficient, but allows us to
            // canonicalize the comparand, making comparison possible
            //
            if ((object)obj == null) { 
                string s = comparand as string;
 
                if ((object)s == null) 
                    return false;
 
                if (!TryCreate(s, UriKind.RelativeOrAbsolute, out obj))
                    return false;
            }
 
            // Since v1.0 two Uris are equal if everything but fragment and UserInfo does match
 
            // This check is for a case where we already fixed up the equal references 
            if ((object)this.m_String == (object)obj.m_String) {
                return true; 
            }

            if (IsAbsoluteUri != obj.IsAbsoluteUri)
                return false; 

            if (IsNotAbsoluteUri) 
                return OriginalString.Equals(obj.OriginalString); 

            if (NotAny(Flags.AllUriInfoSet) || obj.NotAny(Flags.AllUriInfoSet)) { 
                // Try raw compare for m_Strings as the last chance to keep the working set small
                if (!IsUncOrDosPath ) {
                    if (m_String.Length == obj.m_String.Length) {
                        unsafe { 
                            // Try case sensitive compare on m_Strings
                            fixed (char* pMe = m_String) { 
                                fixed (char* pShe = obj.m_String) { 
                                    // This will never go negative since m_String is checked to be a valid URI
                                    int i = (m_String.Length-1); 
                                    for ( ;i >= 0 ; --i) {
                                        if (*(pMe+i) != *(pShe+i)) {
                                            break;
                                        } 
                                    }
                                    if (i == -1) { 
                                        return true; 
                                    }
                                } 
                            }
                        }
                    }
                } 
                else if (String.Compare(m_String, obj.m_String, StringComparison.OrdinalIgnoreCase) == 0) {
                    return true; 
                } 
            }
 
            // Note that equality test will bring the working set of both
            // objects up to creation of m_Info.MoreInfo member
            EnsureUriInfo();
            obj.EnsureUriInfo(); 

            if (!UserDrivenParsing && !obj.UserDrivenParsing && Syntax.IsSimple && obj.Syntax.IsSimple) 
            { 
                // Optimization of canonical DNS names by avoiding host string creation.
                // Note there could be explicit ports specified that would invalidate path offsets 
                if (InFact(Flags.CanonicalDnsHost) && obj.InFact(Flags.CanonicalDnsHost)) {
                    ushort i1 = m_Info.Offset.Host;
                    ushort end1 = m_Info.Offset.Path;
 
                    ushort i2 = obj.m_Info.Offset.Host;
                    ushort end2 = obj.m_Info.Offset.Path; 
                    string str = obj.m_String; 
                    //Taking the shortest part
                    if (end1-i1 > end2-i2) { 
                        end1 = (ushort)(i1 + end2-i2);
                    }
                    // compare and break on ':' if found
                    while (i1 < end1) { 
                        if (m_String[i1] != str[i2]) {
                            return false; 
                        } 
                        if (str[i2] == ':') {
                            // The other must have ':' too to have equal host 
                            break;
                        }
                        ++i1;++i2;
                    } 

                    // The longest host must have ':' or be of the same size 
                    if (i1 < m_Info.Offset.Path && m_String[i1] != ':') { 
                        return false;
                    } 
                    if (i2 < end2 && str[i2] != ':') {
                        return false;
                    }
                    //hosts are equal! 
                }
                else { 
                    EnsureHostString(false); 
                    obj.EnsureHostString(false);
                    if (!m_Info.Host.Equals(obj.m_Info.Host)) { 
                        return false;
                    }
                }
 
                if (Port != obj.Port) {
                    return false; 
                } 
            }
 
            // see Whidbey#21590
            // We want to cache RemoteUrl to improve perf for Uri as a key.
            // We should consider reducing the overall working set by not caching some other properties mentioned in MoreInfo
 
            // Mutli-threading!
            UriInfo meInfo  = m_Info; 
            UriInfo sheInfo = obj.m_Info; 
            if ((object)meInfo.MoreInfo == null) {
                meInfo.MoreInfo = new MoreInfo(); 
            }
            if ((object)sheInfo.MoreInfo == null) {
                sheInfo.MoreInfo = new MoreInfo();
            } 

            // NB: To avoid a race condition when creating MoreInfo field 
            // "meInfo" and "sheInfo" shall remain as local copies. 
            string me = meInfo.MoreInfo.RemoteUrl;
            if ((object)me == null) { 
                me = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped);
                meInfo.MoreInfo.RemoteUrl = me;
            }
            string she = sheInfo.MoreInfo.RemoteUrl; 
            if ((object)she == null) {
                she = obj.GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); 
                sheInfo.MoreInfo.RemoteUrl = she; 
            }
 
            if (!IsUncOrDosPath ) {
                if (me.Length != she.Length) {
                    return false;
                } 
                unsafe {
                    // Try case sensitive compare on m_Strings 
                    fixed (char* pMe = me) { 
                        fixed (char* pShe = she) {
                            char *endMe  = pMe  + me.Length; 
                            char *endShe = pShe + me.Length;
                            while (endMe != pMe) {
                                if (*--endMe != *--endShe) {
                                    return false; 
                                }
                            } 
                            return true; 
                        }
                    } 
                }
            }

 
            // if IsUncOrDosPath is true then we ignore case in the path comparison
            // Get Unescaped form as most safe for the comparison 
            // Fragment AND UserInfo are ignored 
            //
            return (String.Compare(meInfo.MoreInfo.RemoteUrl, 
                                   sheInfo.MoreInfo.RemoteUrl,
                                   IsUncOrDosPath ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal ) == 0);
        }
        // 
        // GetLeftPart
        // 
        //  Returns part of the URI based on the parameters: 
        //
        // Inputs: 
        //    part
        //      Which part of the URI to return
        //
        // Returns: 
        //  The requested substring
        // 
        // Throws: 
        //  UriFormatException if URI type doesn't have host-port or authority parts
        // 
        public string GetLeftPart(UriPartial part) {
            if (IsNotAbsoluteUri) {
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));
            } 

            EnsureUriInfo(); 
            const UriComponents NonPathPart = (UriComponents.Scheme | UriComponents.UserInfo | UriComponents.Host | UriComponents.Port); 

            switch (part) { 
                case UriPartial.Scheme:

                    return GetParts(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
 
                case UriPartial.Authority:
 
                    if (NotAny(Flags.AuthorityFound) || IsDosPath) { 

                        // 



                        // From V1.0 comments: 

                        // anything that didn't have "//" after the scheme name 
                        // (mailto: and news: e.g.) doesn't have an authority 
                        //
 
                        return String.Empty;
                    }
                    return GetParts(NonPathPart, UriFormat.UriEscaped);
 
                case UriPartial.Path:
                    return GetParts(NonPathPart | UriComponents.Path, UriFormat.UriEscaped); 
 
                case UriPartial.Query:
                    return GetParts(NonPathPart | UriComponents.Path | UriComponents.Query, UriFormat.UriEscaped); 

            }
            throw new ArgumentException("part");
        } 

        // 
        // 
        /// Transforms a character into its hexadecimal representation.
        public static string HexEscape(char character) { 
            if (character > '\xff') {
                throw new ArgumentOutOfRangeException("character");
            }
            char[] chars = new char[3]; 
            int pos = 0;
            EscapeAsciiChar(character, chars, ref pos); 
            return new string(chars); 
        }
 
        //
        // HexUnescape
        //
        //  Converts a substring of the form "%XX" to the single character represented 
        //  by the hexadecimal value XX. If the substring s[Index] does not conform to
        //  the hex encoding format then the character at s[Index] is returned 
        // 
        // Inputs:
        //    pattern 
        //      String from which to read the hexadecimal encoded substring
        //
        //    index
        //      Offset within  from which to start reading the hexadecimal 
        //      encoded substring
        // 
        // Outputs: 
        //    index
        //      Incremented to the next character position within the string. This 
        //      may be EOS if this was the last character/encoding within 
        //
        // Returns:
        //  Either the converted character if [] was hex encoded, or 
        //  the character at []
        // 
        // Throws: 
        //  ArgumentOutOfRangeException
        // 

        public static char HexUnescape(string pattern, ref int index) {
            if ((index < 0) || (index >= pattern.Length)) {
                throw new ArgumentOutOfRangeException("index"); 
            }
            if ((pattern[index] == '%') 
                && (pattern.Length - index >= 3)) { 
                char ret = EscapedAscii(pattern[index + 1], pattern[index + 2]);
                if (ret != c_DummyChar) { 
                    index += 3;
                    return ret;
                }
            } 
            return pattern[index++];
        } 
 
        //
        // IsHexDigit 
        //
        //  Determines whether a character is a valid hexadecimal digit in the range
        //  [0..9] | [A..F] | [a..f]
        // 
        // Inputs:
        //    character 
        //      Character to test 
        //
        // Returns: 
        //  true if  is a hexadecimal digit character
        //
        // Throws:
        //  Nothing 
        //
        public static bool IsHexDigit(char character) { 
            return ((character >= '0') && (character <= '9')) 
                || ((character >= 'A') && (character <= 'F'))
                || ((character >= 'a') && (character <= 'f')); 
        }

        //
        // IsHexEncoding 
        //
        //  Determines whether a substring has the URI hex encoding format of '%' 
        //  followed by 2 hexadecimal characters 
        //
        // Inputs: 
        //    pattern
        //      String to check
        //
        //    index 
        //      Offset in  at which to check substring for hex encoding
        // 
        // Assumes: 
        //  0 <=  < .Length
        // 
        // Returns:
        //  true if [] is hex encoded, else false
        //
        // Throws: 
        //  Nothing
        // 
        public static bool IsHexEncoding(string pattern, int index) { 
            if ((pattern.Length - index) < 3) {
                return false; 
            }
            if ((pattern[index] == '%') && EscapedAscii(pattern[index + 1], pattern[index + 1]) != c_DummyChar) {
                return true;
            } 
            return false;
        } 
 
        //
        // MakeRelative (toUri) 
        //
        //  Return a relative path which when applied to this Uri would create the
        //  resulting Uri 
        // 
        // Inputs:
        //    toUri 
        //      Uri to which we calculate the transformation from this Uri 
        //
        // Returns: 
        //  If the 2 Uri are common except for a relative path difference, then that
        //  difference, else the display name of this Uri
        //
        // Throws: 
        //  Nothing
        // 
        [Obsolete("The method has been deprecated. Please use MakeRelativeUri(Uri uri). http://go.microsoft.com/fwlink/?linkid=14202")] 
        public string MakeRelative(Uri toUri)
        { 
            if (IsNotAbsoluteUri || toUri.IsNotAbsoluteUri)
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute));

            if ((Scheme == toUri.Scheme) && (Host == toUri.Host) && (Port == toUri.Port)) 
                return PathDifference(AbsolutePath, toUri.AbsolutePath, !IsUncOrDosPath);
 
            return toUri.ToString(); 
        }
        // 
        public Uri MakeRelativeUri(Uri uri)
        {
            if (IsNotAbsoluteUri || uri.IsNotAbsoluteUri)
                throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); 

            // Note that the UserInfo part is ignored when computing a relative Uri. 
            if ((Scheme == uri.Scheme) && (Host == uri.Host) && (Port == uri.Port)) 
                return new Uri(
                            PathDifference(AbsolutePath, uri.AbsolutePath, !IsUncOrDosPath) + uri.GetParts(UriComponents.Query | UriComponents.Fragment, UriFormat.UriEscaped), 
                            UriKind.Relative
                            );

            return uri; 
        }
 
        // 
        // http://host/Path/Path/File?Query is the base of
        //      - http://host/Path/Path/File/ ...    (those "File" words may be different in semantic but anyway) 
        //      - http://host/Path/Path/#Fragment
        //      - http://host/Path/Path/?Query
        //      - http://host/Path/Path/MoreDir/ ...
        //      - http://host/Path/Path/OtherFile?Query 
        //      - http://host/Path/Path/Fl
        //      - http://host/Path/Path/ 
        // 
        //  It is not a base for
        //      - http://host/Path/Path         (that last "Path" is not considered as a directory) 
        //      - http://host/Path/Path?Query
        //      - http://host/Path/Path#Fragment
        //      - http://host/Path/Path2/
        //      - http://host/Path/Path2/MoreDir 
        //      - http://host/Path/File
        // 
        // ASSUMES that strings like http://host/Path/Path/MoreDir/../../  have been canonicalized before going to this method. 
        // ASSUMES that back slashes already have been converted if applicable.
        // 
        private static unsafe bool TestForSubPath(  char* pMe,  ushort meLength,
                                                    char* pShe, ushort sheLength,
                                                    bool ignoreCase) {
            ushort i = 0; 
            char chMe;
            char chShe; 
 
            bool AllSameBeforeSlash = true;
 
            for( ;i < meLength && i < sheLength; ++i)
            {
                chMe  = *(pMe+i);
                chShe = *(pShe+i); 

                if (chMe == '?' || chMe == '#') { 
                    // survived so far and pMe does not have any more path segments 
                    return true;
                } 

                // If pMe terminates a path segment, so must pShe
                if (chMe == '/') {
                    if (chShe != '/') { 
                        // comparison has falied
                        return false; 
                    } 
                    // plus the segments must be the same
                    if (!AllSameBeforeSlash) { 
                        // comparison has falied
                        return false;
                    }
                    //so far so good 
                    AllSameBeforeSlash = true;
                    continue; 
                } 

                // if pShe terminates then pMe must not have any more path segments 
                if (chShe == '?' || chShe == '#') {
                    break;
                }
 
                if (!ignoreCase) {
                    if (chMe != chShe) { 
                        AllSameBeforeSlash = false; 
                    }
                } 
                else {
                    if (Char.ToLower(chMe, CultureInfo.InvariantCulture) != Char.ToLower(chShe, CultureInfo.InvariantCulture)) {
                        AllSameBeforeSlash = false;
                    } 
                }
            } 
 
            // If me is longer then it must not have any more path segments
            for (; i < meLength; ++i) { 
                if ((chMe = *(pMe+i)) == '?' || chMe == '#') {
                    return true;
                }
                if (chMe == '/') { 
                    return false;
                } 
            } 
            //survived by getting to the end of pMe
            return true; 
        }
        // This is used by UriBuilder,

        internal unsafe static string InternalEscapeString(string rawString) { 
            if ((object)rawString == null)
                return String.Empty; 
 
            int position = 0;
            char[] dest = EscapeString(rawString, 0, rawString.Length, null, ref position, true, '?', '#', '%'); 
            if ((object)dest == null)
                return rawString;

            return new string(dest, 0, position); 
        }
 
        // 
        //  This method is called first to figure out the scheme or a simple file path
        //  Is called only at the .ctor time 
        //
        private static unsafe ParsingError ParseScheme(string uriString, ref Flags flags, ref UriParser syntax)
        {
            int length = uriString.Length; 
            if (length == 0)
                return ParsingError.EmptyUriString; 
 
            // we don;t work with >= 64k Uris
            if (length >= c_MaxUriBufferSize) 
                return ParsingError.SizeLimit;

            //STEP1: parse scheme, lookup this Uri Syntax or create one using UnknownV1SyntaxFlags uri syntax template
            fixed (char* pUriString = uriString) 
            {
                ParsingError err = ParsingError.None; 
                ushort idx = ParseSchemeCheckImplicitFile(pUriString, (ushort)length, ref err, ref flags, ref syntax); 

                if (err != ParsingError.None) 
                    return err;

                flags |= (Flags)idx;
             } 
             return ParsingError.None;
        } 
 
        //
        // A wrapper for ParseMinimal() called from a user parser 
        // It signals back that the call has been done
        // plus it communicates back a flag for an error if any
        //
        internal UriFormatException ParseMinimal() 
        {
            ParsingError result = PrivateParseMinimal(); 
            if (result == ParsingError.None) 
                return null;
 
            // Means the we think the Uri is invalid, bu that can be later overriden by a user parser
            m_Flags |= Flags.ErrorOrParsingRecursion;

            return GetException(result); 
        }
        // 
        // 
        //  This method tries to parse the minimal information needed to certify the valifity
        //  of a uri string 
        //
        //      scheme://userinfo@host:Port/Path?Query#Fragment
        //
        //  The method must be called only at the .ctor time 
        //
        //  Returns ParsingError.None if the Uri syntax is valid, an error otheriwse 
        // 
        private unsafe ParsingError PrivateParseMinimal()
        { 
            ushort idx = (ushort) (m_Flags & Flags.IndexMask);
            ushort length = (ushort) m_String.Length;
            string newHost = null;      // stores newly parsed host when original strings are being switched
 
            // Means a custom UriParser did call "base" InitializeAndValidate()
            m_Flags &= ~(Flags.IndexMask | Flags.UserDrivenParsing); 
 
            //STEP2: Parse up to the port
 
            fixed (char* pUriString =   ((m_iriParsing &&
                                        ((m_Flags & Flags.HasUnicode)!=0) &&
                                        ((m_Flags & Flags.HostUnicodeNormalized) == 0)) ? m_originalUnicodeString : m_String))
            { 
                // Cut trailing spaces in m_String
                if (length > idx && IsLWS(pUriString[length-1])) 
                { 
                    --length;
                    while (length != idx && IsLWS(pUriString[--length])) 
                        ;
                    ++length;
                }
 
                // [....] codereview:
                // Old Uri parser tries to figure out on a DosPath in all cases. 
                // Hence http://c:/ is treated as as DosPath without the host while it should be a host "c", port 80 
                //
                // This block is compatible with Old Uri parser in terms it will look for the DosPath if the scheme 
                // syntax allows both empty hostnames and DosPath
                //
#if !PLATFORM_UNIX
                if (m_Syntax.IsAllSet(UriSyntaxFlags.AllowEmptyHost|UriSyntaxFlags.AllowDOSPath) && NotAny(Flags.ImplicitFile) && (idx+1 < length)) { 

                    char c; 
                    ushort i = (ushort) idx; 

                    // V1 Compat: Allow _compression_ of > 3 slashes only for File scheme, see VsWhidbey 87448. 
                    // This will skip all slashes and if their number is 2+ it sets the AuthorityFound flag
                    for (; i < length; ++i) {
                        if (!((c=pUriString[i])== '\\' || c == '/'))
                            break; 
                    }
 
                    if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) || i-idx <= 3) { 
                        // if more than one slash after the scheme, the authority is present
                        if (i-idx >= 2) { 
                            m_Flags |= Flags.AuthorityFound;
                        }
                        // DOS-like path?
                        if (i+1 < (ushort) length  && ((c=pUriString[i+1]) == ':' || c == '|') && IsAsciiLetter(pUriString[i])) { 

                            if (i+2 >= (ushort) length || ((c=pUriString[i+2]) != '\\' && c != '/')) 
                            { 
                                // report an error but only for a file: scheme
                                if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri)) 
                                    return ParsingError.MustRootedPath;
                            }
                            else
                            { 
                                // This will set IsDosPath
                                m_Flags |= Flags.DosPath; 
 
                                if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) {
                                    // when DosPath found and Authority is required, set this flag even if Authority is empty 
                                    m_Flags |= Flags.AuthorityFound;
                                }
                                if (i != idx && i-idx != 2) {
                                    //This will remember that DosPath is rooted 
                                    idx = (ushort)(i-1);
                                } 
                                else { 
                                    idx = i;
                                } 
                            }
                        }
                        else if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) && (i-idx >= 2 && i-idx != 3 && i < length && pUriString[i] != '?' && pUriString[i] != '#'))
                        { 
                            // see VsWhidbey#226745 V1.0 did not support file:///, fixing it with minimal behavior change impact
                            // Only FILE scheme may have UNC Path flag set 
                            m_Flags |= Flags.UncPath; 
                            idx = i;
                        } 
                    }
                }
#endif // !PLATFORM_UNIX
                // 
                //STEP 1.5 decide on the Authority component
                // 
#if !PLATFORM_UNIX 
                if ((m_Flags & (Flags.UncPath|Flags.DosPath)) != 0) {
                } 
#else
                if ((m_Flags & Flags.ImplicitFile) != 0) {
                    // Already parsed up to the path
                } 
#endif // !PLATFORM_UNIX
                else if ((idx+2) <= length) { 
                    char first  = pUriString[idx]; 
                    char second = pUriString[idx+1];
 
                    if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) {
                        // (V1.0 compatiblity) This will allow http:\\ http:\/ http:/\
#if !PLATFORM_UNIX
                        if ((first == '/' || first == '\\') && (second == '/' || second == '\\')) 
#else
                        if (first == '/' && second == '/') 
#endif // !PLATFORM_UNIX 
                        {
                            m_Flags |= Flags.AuthorityFound; 
                            idx+=2;
                        }
                        else {
                            return ParsingError.BadAuthority; 
                        }
                    } 
                    else if (m_Syntax.InFact(UriSyntaxFlags.OptionalAuthority) && (InFact(Flags.AuthorityFound) || (first == '/' && second == '/'))) { 
                        m_Flags |= Flags.AuthorityFound;
                        idx+=2; 
                    }
                    else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) {
                        // There is no Authority component, save the Path index
                        // 
                        m_Flags |= ((Flags)idx | Flags.UnknownHostType);
                        return ParsingError.None; 
                    } 
                }
                else if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) { 
                    return ParsingError.BadAuthority;
                }
                else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) {
                    // There is no Authority component, save the Path index 
                    //
                    m_Flags |= ((Flags)idx | Flags.UnknownHostType); 
                    return ParsingError.None; 
                }
 
#if !PLATFORM_UNIX
                // The following sample taken from the original parser comments makes the whole story sad
                // vsmacros://c:\path\file
                // Note that two slashes say there must be an Authority but instead the path goes 
                // Fro V1 compat the next block allow this case but not for schemes like http
                if (InFact(Flags.DosPath)) { 
 
                    m_Flags |= (((m_Flags & Flags.AuthorityFound)!= 0)? Flags.BasicHostType :Flags.UnknownHostType);
                    m_Flags |= (Flags)idx; 
                    return ParsingError.None;
                }
#endif // !PLATFORM_UNIX
 
                //STEP 2: Check the syntax of authority expecting at least one character in it
                // 
                // Note here we do know that there is an authority in the string OR it's a DOS path 

                // We may find a userInfo and the port when parsing an authority 
                // Also we may find a registry based authority.
                // We must ensure that known schemes do use a server-based authority
            {
                ParsingError err = ParsingError.None; 
                idx = CheckAuthorityHelper(pUriString, idx, (ushort)length, ref err, ref m_Flags, m_Syntax, ref newHost);
                if (err != ParsingError.None) 
                    return err; 

                // This will disallow '\' as the host terminator for any scheme that is not implicitFile or cannot have a Dos Path 
                if ((idx < (ushort)length && pUriString[idx] == '\\') && NotAny(Flags.ImplicitFile) && m_Syntax.NotAny(UriSyntaxFlags.AllowDOSPath))
                    return ParsingError.BadAuthorityTerminator;

            } 

                // The Path (or Port) parsing index is reloaded on demand in CreateUriInfo when accessing a Uri property 
                m_Flags |= (Flags)idx; 

                // The rest of the string will be parsed on demand 
                // The Host/Authorty is all checked, the type is known but the host value string
                // is not created/canonicalized at this point.
            }
 
            if((s_IdnScope != UriIdnScope.None) || m_iriParsing)
                PrivateParseMinimalIri(newHost, idx); 
 
            return ParsingError.None;
        } 

        private void PrivateParseMinimalIri(string newHost, ushort idx)
        {
            // we have a new host! 
            if (newHost != null)
                m_String = newHost; 
 
            // conditions where we dont need to go to parseremaining, so we copy the rest of the
            // original string.. and switch offsets 
            if ((!m_iriParsing && AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))) ||
                (m_iriParsing && ((m_Flags & Flags.HasUnicode) == 0) && AllowIdn && ((m_Flags & Flags.IdnHost) != 0))){
                // update the start of path from the end of new string
                m_Flags &= ~(Flags.IndexMask); 
                m_Flags |= (Flags)m_String.Length;
 
                m_String += m_originalUnicodeString.Substring(idx, m_originalUnicodeString.Length - idx); 
            }
 
            // Indicate to createuriinfo that offset is in m_originalUnicodeString
            if (m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0)){
                // offset in Flags.IndexMask refers to m_originalUnicodeString
                m_Flags |= Flags.UseOrigUncdStrOffset; 
            }
        } 
 
        //
        // 
        // The method is called when we have to access m_Info members
        // This will create the m_Info based on the copied parser context
        // Under milti-threading ---- this method may do duplicated yet harmless work
        // 
        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)m_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 (IsLWS(m_String[idx])) { 
                    ++idx;
                    ++info.Offset.Scheme; 
                } 

#if !PLATFORM_UNIX 
                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) && (m_String[idx] == '/' || m_String[idx] == '\\')) {
                        ++idx; 
                    } 
                }
#endif // !PLATFORM_UNIX 
            }
            else {
                // This is NOT an ImplicitFile uri
                idx = (ushort)m_Syntax.SchemeName.Length; 

                while (m_String[idx++] != ':') { 
                    ++info.Offset.Scheme; 
                }
 
                if ((cF & Flags.AuthorityFound) != 0)
                {
                    if (m_String[idx] == '\\' || m_String[idx+1] == '\\')
                        notCanonicalScheme = true; 

                    idx+=2; 
#if !PLATFORM_UNIX 
                    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) && (m_String[idx] == '/' || m_String[idx] == '\\')) {
                            notCanonicalScheme = true;
                            ++idx; 
                        }
                    } 
#endif // !PLATFORM_UNIX 
                }
            } 

            // This is weird but some schemes (mailto) do not have Authority-based syntax, still they do have a port
            if (m_Syntax.DefaultPort != UriParser.NoDefaultPort)
                info.Offset.PortValue = (ushort)m_Syntax.DefaultPort; 

            //Here we set the indexes for already parsed components 
            if ((cF & Flags.HostTypeMask) == Flags.UnknownHostType 
#if !PLATFORM_UNIX
                || StaticInFact(cF, Flags.DosPath) 
#endif // !PLATFORM_UNIX
                ) {
                //there is no Authotity 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 (m_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_[....] 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)m_originalUnicodeString.Length;

            if (idx < info.Offset.End ){
                fixed (char* userString = UseOrigUnicodeStrOffset ? m_originalUnicodeString : m_String){ 
                    if (userString[idx] == ':'){
                        int port = 0; 
 
                        //Check on some noncanonical 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; 
/*********
            // The spinlock would be better than below lock but it's too late for Beta2, consider for RTM 
            // Also DON'T forget to check EnsureUriInfo method 
            int copyF = m_Flags;
            while ((copyF & Flags.MinimalUriInfoSet) == 0) 
            {
               if (copyF != (copyF = Interlocked.CompareExchange(ref m_Flags, cF | (copyF & ~Flags.IndexMask), copyF))
                   continue;
               m_Info  = info; 
            }
*********/ 
            info.DnsSafeHost = m_DnsSafeHost; 
            lock (m_String)
            { 
                if (( m_Flags & Flags.MinimalUriInfoSet) == 0)
                {
                    m_Info  = info;
                    m_Flags = (m_Flags & ~Flags.IndexMask) | cF; 
                }
            } 
 
        }
 
        //
        // This will create a Host string. The validity has been already checked
        //
        // Assuming: UriInfo memeber is already set at this point 
        private unsafe void CreateHostString() {
            // 
            // Mutlithrreading! 
            //
            if (!m_Syntax.IsSimple) 
            {
                lock (m_Info)
                {
                    // ATTN: Avoid possible recursion through CreateHostString->Syntax.GetComponents->Uri.GetComponentsHelper->CreateHostString 
                    if (NotAny(Flags.ErrorOrParsingRecursion))
                    { 
                        m_Flags |= Flags.ErrorOrParsingRecursion; 
                        // Need to get host string through the derived type
                        GetHostViaCustomSyntax(); 
                        m_Flags &= ~Flags.ErrorOrParsingRecursion;
                        return;
                    }
                } 
            }
            Flags flags = m_Flags; 
            string host = CreateHostStringHelper(m_String, m_Info.Offset.Host, m_Info.Offset.Path, ref flags, ref m_Info.ScopeId); 

            // now check on canonical host representation 
            if (host.Length != 0)
            {
                // An Authority may need escaping except when it's an inet server address
                // 
                // We do not escape UNC names and will get rid of this type when switching to IDN spec
                // 
                if (HostType == Flags.BasicHostType) { 
                    ushort idx = 0;
                    Check result; 
                    fixed (char* pHost = host) {
                        result = CheckCanonical(pHost, ref idx, (ushort)host.Length, c_DummyChar);
                    }
 
                    if ((result & Check.DisplayCanonical) == 0) {
                        // For implicit file the user string must be in perfect display format, 
                        // Hence, ignoring complains from CheckCanonical() 
                        if (NotAny(Flags.ImplicitFile) || (result & Check.ReservedFound) != 0) {
                            flags |= Flags.HostNotCanonical; 
                        }
                    }

                    if (InFact(Flags.ImplicitFile) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0) { 
                        // need to re-escape this host if any escaped sequence was found
                        result &= ~Check.EscapedCanonical; 
                    } 

                    if ((result & (Check.EscapedCanonical|Check.BackslashInPath)) != Check.EscapedCanonical) { 
                        // we will make a canonical host in m_Info.Host, but mark that m_String holds wrong data
                        flags |= Flags.E_HostNotCanonical;
                        if (NotAny(Flags.UserEscaped))
                        { 
                            int position = 0;
                            char[] dest = EscapeString(host, 0, host.Length, null, ref position, true, '?', '#', IsImplicitFile? c_DummyChar: '%'); 
                            if ((object)dest != null) 
                                host = new string(dest, 0, position);
                        } 
                        else {
                            //

                        } 
                    }
                } 
                else if (NotAny(Flags.CanonicalDnsHost)){ 
                    // Check to see if we can take the canonical host string out of m_String
                    if ((object)m_Info.ScopeId != null) { 
                        // IPv6 ScopeId is included when serializing a Uri
                        flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical);
                    }
                    else for (ushort i=0 ; i < host.Length; ++i) { 
                             if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || host[i] != m_String[m_Info.Offset.Host + i]) {
                                 flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical); 
                                 break; 
                             }
                         } 
                }
            }

            m_Info.Host = host; 
            lock (m_Info)
            { 
                m_Flags |= flags; 
            }
        } 
        //
        private static string CreateHostStringHelper(string str, ushort idx, ushort end, ref Flags flags, ref string scopeId)
        {
            bool loopback = false; 
            string host;
            switch (flags & Flags.HostTypeMask) { 
 
                case Flags.DnsHostType:
                    host = DomainNameHelper.ParseCanonicalName(str, idx, end, ref loopback); 
                    break;

                case Flags.IPv6HostType:
                    //[....] codereview 
                    // The helper will return [...] string that is not suited for Dns.Resolve()
                    host = IPv6AddressHelper.ParseCanonicalName(str, idx, ref loopback, ref scopeId); 
                    break; 

                case Flags.IPv4HostType: 
                    host = IPv4AddressHelper.ParseCanonicalName(str, idx, end, ref loopback);
                    break;

#if !PLATFORM_UNIX 
                case Flags.UncHostType:
                    host = UncNameHelper.ParseCanonicalName(str, idx, end, ref loopback); 
                    break; 
#endif // !PLATFORM_UNIX
 
                case Flags.BasicHostType:
#if !PLATFORM_UNIX
                    if (StaticInFact(flags, Flags.DosPath)) {
                        host = string.Empty; 
                    }
                    else 
#endif // !PLATFORM_UNIX 
                    {
                        // This is for a registry-based authority, not relevant for known schemes 
                        host = str.Substring(idx, end-idx);
                    }
                    // A empty host would count for a loopback
                    if (host.Length == 0) { 
                        loopback = true;
                    } 
                    //there will be no port 
                    break;
 
                case Flags.UnknownHostType:
                    //means the host is *not expected* for this uri type
                    host = string.Empty;
                    break; 

                default: //it's a bug 
                    throw GetException(ParsingError.BadHostName); 
            }
 
            if (loopback) {
                flags |= Flags.LoopbackHost;
            }
            return host; 
        }
        // 
        // Called under lock() 
        //
        private unsafe void GetHostViaCustomSyntax() 
        {
            // A multithreading check
            if (m_Info.Host != null)
                return; 

            string host = m_Syntax.InternalGetComponents(this, UriComponents.Host, UriFormat.UriEscaped); 
 
            // ATTN: Check on whether recursion has not happened
            if ((object)m_Info.Host == null) 
            {
                if (host.Length >= c_MaxUriBufferSize)
                    throw GetException(ParsingError.SizeLimit);
 
                ParsingError err = ParsingError.None;
                Flags flags = m_Flags & ~Flags.HostTypeMask; 
 
                fixed (char *pHost = host)
                { 
                    string newHost = null;
                    if (CheckAuthorityHelper(pHost, 0, (ushort)host.Length, ref err, ref flags, m_Syntax, ref newHost) != (ushort)host.Length)
                    {
                        // We cannot parse the entire host string 
                        flags &= ~Flags.HostTypeMask;
                        flags |= Flags.UnknownHostType; 
                    } 
                }
 
                if (err != ParsingError.None || (flags & Flags.HostTypeMask) == Flags.UnknownHostType)
                {
                    // Well, custom parser has returned a not known host type, take it as Basic then.
                    m_Flags = (m_Flags & ~Flags.HostTypeMask) | Flags.BasicHostType; 
                }
                else 
                { 
                    host = CreateHostStringHelper(host, 0, (ushort)host.Length, ref flags, ref m_Info.ScopeId);
                    for (ushort i=0 ; i < host.Length; ++i) { 
                             if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || host[i] != m_String[m_Info.Offset.Host + i]) {
                                 m_Flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical);
                                 break;
                             } 
                         }
                    m_Flags = (m_Flags & ~Flags.HostTypeMask) | (flags & Flags.HostTypeMask); 
                } 
            }
            // 
            // This is a chance for a custom parser to report a different port value
            //
            string portStr = m_Syntax.InternalGetComponents(this, UriComponents.StrongPort, UriFormat.UriEscaped);
            int port = 0; 
            if ((object)portStr == null || portStr.Length == 0)
            { 
                // It's like no port 
                m_Flags &= ~Flags.NotDefaultPort;
                m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); 
                m_Info.Offset.PortValue = 0;
            }
            else
            { 
                for (int idx=0; idx < portStr.Length; ++idx)
                { 
                    int val = portStr[idx] - '0'; 
                    if (val < 0 || val > 9 || (port = (port * 10 + val)) > 0xFFFF)
                        throw new UriFormatException(SR.GetString(SR.net_uri_PortOutOfRange, m_Syntax.GetType().FullName, portStr)); 
                }
                if (port != m_Info.Offset.PortValue)
                {
                    if (port == m_Syntax.DefaultPort) 
                        m_Flags &= ~Flags.NotDefaultPort;
                    else 
                        m_Flags |= Flags.NotDefaultPort; 

                    m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); 
                    m_Info.Offset.PortValue = (ushort) port;
                }
            }
            // This must be done as the last thing in this method 
            m_Info.Host = host;
        } 
        // 
        // An internal shortcut into Uri extenisiblity API
        // 
        internal string GetParts(UriComponents uriParts, UriFormat formatAs)
        {
            return GetComponents(uriParts, formatAs);
        } 

        // 
        // 
        //
        private string GetEscapedParts(UriComponents uriParts) { 
            // Which Uri parts are not escaped canonically ?
            // Notice that public UriPart and private Flags must me in [....] so below code can work
            //
            ushort  nonCanonical = (ushort)(((ushort)m_Flags & ((ushort)Flags.CannotDisplayCanonical<<7)) >> 6); 
            if (InFact(Flags.SchemeNotCanonical)) {
                nonCanonical |= (ushort)Flags.SchemeNotCanonical; 
            } 

            // We keep separate flags for some of path canonicalization facts 
            if ((uriParts & UriComponents.Path) != 0) {
                if (InFact(Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) {
                    nonCanonical |= (ushort)Flags.PathNotCanonical;
                } 
                else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') {
                    // A rare case of c|\ 
                    nonCanonical |= (ushort)Flags.PathNotCanonical; 
                }
            } 

            if (((ushort)uriParts & nonCanonical) == 0) {
                string ret = GetUriPartsFromUserString(uriParts);
                if ((object)ret != null) { 
                    return ret;
                } 
            } 

            return ReCreateParts(uriParts, nonCanonical, UriFormat.UriEscaped); 
        }

        private string GetUnescapedParts(UriComponents uriParts, UriFormat formatAs) {
            // Which Uri parts are not escaped canonically ? 
            // Notice that public UriComponents and private Uri.Flags must me in [....] so below code can work
            // 
            ushort  nonCanonical = (ushort)((ushort)m_Flags & (ushort)Flags.CannotDisplayCanonical); 

            // We keep separate flags for some of path canonicalization facts 
            if ((uriParts & UriComponents.Path) != 0) {
                if ((m_Flags & (Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) !=0) {
                    nonCanonical |= (ushort)Flags.PathNotCanonical;
                } 
                else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') {
                    // A rare case of c|\ 
                    nonCanonical |= (ushort)Flags.PathNotCanonical; 
                }
 
            }

            if (((ushort)uriParts & nonCanonical) == 0) {
                string ret = GetUriPartsFromUserString(uriParts); 
                if ((object)ret != null) {
                    return ret; 
                } 
            }
 
            return ReCreateParts(uriParts, nonCanonical, formatAs);
        }

        // 
        //
        // 
        private string ReCreateParts(UriComponents parts, ushort nonCanonical, UriFormat formatAs) 
        {
            // going hard core 
            EnsureHostString(false);
            string stemp = (parts & UriComponents.Host) == 0? string.Empty: m_Info.Host;
            // we reserve more space than required because a canonical Ipv6 Host
            // may take more characteres than in original m_String 
            // Also +3 is for :// and +1 is for absent first slash
            // Also we may escape every character, hence multiplying by 6 
            int count = (m_Info.Offset.End-m_Info.Offset.User) * (formatAs == UriFormat.UriEscaped?6:1); 
            char[] chars = new char[stemp.Length + count + m_Syntax.SchemeName.Length + 3 + 1];
            count = 0; 

            //Scheme and slashes
            if ((parts & UriComponents.Scheme) != 0) {
                m_Syntax.SchemeName.CopyTo(0, chars, count, m_Syntax.SchemeName.Length); 
                count += m_Syntax.SchemeName.Length;
                if (parts != UriComponents.Scheme) { 
                    chars[count++] = ':'; 
                    if (InFact(Flags.AuthorityFound)) {
                        chars[count++] = '/'; 
                        chars[count++] = '/';
                    }
                }
            } 

            //UserInfo 
            if ((parts & UriComponents.UserInfo) != 0 && InFact(Flags.HasUserInfo)) 
            {
                if ((nonCanonical & (ushort)UriComponents.UserInfo) != 0) { 
                    switch (formatAs) {
                        case UriFormat.UriEscaped:
                            if (NotAny(Flags.UserEscaped))
                            { 
                                chars = EscapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, true, '?', '#', '%');
                            } 
                            else { 
                                if (InFact(Flags.E_UserNotCanonical)) {
                                    // 

                                }
                                m_String.CopyTo(m_Info.Offset.User, chars, count, m_Info.Offset.Host - m_Info.Offset.User);
                                count += (m_Info.Offset.Host - m_Info.Offset.User); 
                            }
                            break; 
 
                        case UriFormat.SafeUnescaped:
                            chars = UnescapeString( m_String, m_Info.Offset.User, m_Info.Offset.Host-1, chars, ref count, '@', '/', '\\', 
                                                    InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape,
                                                    m_Syntax, false, false);
                            chars[count++] = '@';
                            break; 

                        case UriFormat.Unescaped: 
                            chars = UnescapeString( m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, c_DummyChar, 
                                                    c_DummyChar, c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll,
                                                    m_Syntax, false, false); 
                            break;

                        default: //V1ToStringUnescape
                            chars = UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, c_DummyChar, 
                                                    c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false);
                            break; 
                    } 
                }
                else { 
                    UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count,
                        c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false, false);
                }
                if (parts == UriComponents.UserInfo) 
                {
                    //strip '@' delimiter 
                    --count; 
                }
            } 

            // Host
            if ((parts & UriComponents.Host) != 0 && stemp.Length != 0)
            { 
                UnescapeMode mode;
                if (formatAs != UriFormat.UriEscaped && HostType == Flags.BasicHostType && (nonCanonical & (ushort)UriComponents.Host) != 0) { 
                    // only Basic host could be in the escaped form 
                    mode = formatAs == UriFormat.Unescaped? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll):
                                            (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape); 

                }
                else {
                    mode = UnescapeMode.CopyOnly; 
                }
                chars = UnescapeString(stemp, 0, stemp.Length, chars, ref count, '/', '?', '#', mode, m_Syntax, false, false); 
 

                // A fix up only for SerializationInfo and IpV6 host with a scopeID 
                if ((parts & UriComponents.SerializationInfoString) != 0 && HostType == Flags.IPv6HostType && (object)m_Info.ScopeId != null)
                {
                    m_Info.ScopeId.CopyTo(0, chars, count-1, m_Info.ScopeId.Length);
                    count += m_Info.ScopeId.Length; 
                    chars[count-1] = ']';
                } 
            } 

            //Port (always wants a ':' delimiter if got to this method) 
            if ((parts & UriComponents.Port) != 0)
            {
                if ((nonCanonical & (ushort)UriComponents.Port) == 0) {
                    //take it from m_String 
                    if (InFact(Flags.NotDefaultPort)) {
                        ushort start = m_Info.Offset.Path; 
                        while (m_String[--start] != ':') { 
                            ;
                        } 
                        m_String.CopyTo(start, chars, count, m_Info.Offset.Path - start);
                        count += (m_Info.Offset.Path - start);
                    }
                    else if ((parts & UriComponents.StrongPort) != 0 && m_Syntax.DefaultPort != UriParser.NoDefaultPort) { 
                        chars[count++]= ':';
                        stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); 
                        stemp.CopyTo(0, chars, count, stemp.Length); 
                        count += stemp.Length;
                    } 
                }
                else if (InFact(Flags.NotDefaultPort) || ((parts & UriComponents.StrongPort) != 0 && m_Syntax.DefaultPort != UriParser.NoDefaultPort)) {
                    // recreate string from port value
                    chars[count++]= ':'; 
                    stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture);
                    stemp.CopyTo(0, chars, count, stemp.Length); 
                    count += stemp.Length; 
                }
            } 

            ushort delimiterAwareIndex;

            //Path 
            if ((parts & UriComponents.Path) != 0)
            { 
                chars = GetCanonicalPath(chars, ref count, formatAs); 

                // (possibly strip the leading '/' delimiter) 
                if (parts == UriComponents.Path)
                {
                    if (InFact(Flags.AuthorityFound) && count !=0 && chars[0] == '/')
                    { 
                        delimiterAwareIndex = 1; --count;
                    } 
                    else 
                    {
                        delimiterAwareIndex = 0; 
                    }
                    return count == 0? string.Empty: new string(chars, delimiterAwareIndex, count);
                }
            } 

            //Query (possibly strip the '?' delimiter) 
            if ((parts & UriComponents.Query) != 0 && m_Info.Offset.Query < m_Info.Offset.Fragment) 
            {
                delimiterAwareIndex = (ushort)(m_Info.Offset.Query+1); 
                if(parts != UriComponents.Query)
                    chars[count++] = '?';   //see Fragment+1 below

                if ((nonCanonical & (ushort)UriComponents.Query) != 0) 
                {
                    switch (formatAs) 
                    { 
                    case UriFormat.UriEscaped:
                        //Can Assert IsImplicitfile == false 
                        if (NotAny(Flags.UserEscaped))
                            chars = EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, true,  '#', c_DummyChar, '%');
                        else
                        { 
                            //
 
 
                            UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count,
                                c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, true, false); 
                        }
                        break;

                    case V1ToStringUnescape: 

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, 
                                               m_Syntax, true, false);
                        break; 

                    case UriFormat.Unescaped:

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (UnescapeMode.Unescape| UnescapeMode.UnescapeAll), m_Syntax, true, false);
                        break; 
 
                    default: // UriFormat.SafeUnescaped
 
                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, '#', c_DummyChar, c_DummyChar,
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, true, false);
                        break;
                    } 
                }
                else 
                { 
                    UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar,
                                    UnescapeMode.CopyOnly, m_Syntax, true, false); 
                }
            }

            //Fragment (possibly strip the '#' delimiter) 
            if ((parts & UriComponents.Fragment) != 0 && m_Info.Offset.Fragment < m_Info.Offset.End)
            { 
                delimiterAwareIndex = (ushort)(m_Info.Offset.Fragment+1); 
                if(parts != UriComponents.Fragment)
                    chars[count++] = '#';   //see Fragment+1 below 

                if ((nonCanonical & (ushort)UriComponents.Fragment) != 0)
                {
                    switch (formatAs) { 
                    case UriFormat.UriEscaped:
                            if (NotAny(Flags.UserEscaped)) 
                                chars = EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, true, '#', c_DummyChar, '%'); 
                            else
                            { 
                                //


                                UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar, 
                                                UnescapeMode.CopyOnly, m_Syntax, false, false);
                            } 
                            break; 

                    case V1ToStringUnescape: 

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar,
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, m_Syntax, false, false);
                        break; 
                    case UriFormat.Unescaped:
 
                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               UnescapeMode.Unescape | UnescapeMode.UnescapeAll, m_Syntax, false, false);
                        break; 

                    default: // UriFormat.SafeUnescaped

                        chars = UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, '#', c_DummyChar, c_DummyChar, 
                                               (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, false, false);
                        break; 
                    } 
                }
                else 
                {
                    UnescapeString( m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, c_DummyChar, c_DummyChar, c_DummyChar,
                                    UnescapeMode.CopyOnly, m_Syntax, false, false);
                } 
            }
 
            return new string(chars, 0, count); 
        }
 
        //
        // This method is called only if the user string has a canonical representation
        // of requested parts
        // 
        private string GetUriPartsFromUserString(UriComponents uriParts) {
 
            ushort delimiterAwareIdx; 

            switch (uriParts & ~UriComponents.KeepDelimiter) { 
                    // For FindServicePoint perf
                case UriComponents.Scheme | UriComponents.Host | UriComponents.Port:
                    if (!InFact(Flags.HasUserInfo))
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme); 

                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                         + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); 

                    // For HttpWebRequest.ConnectHostAndPort perf 
                case UriComponents.HostAndPort:  //Host|StrongPort

                    if (!InFact(Flags.HasUserInfo))
                        goto case UriComponents.StrongAuthority; 

                    if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort) 
                        return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); 

                    return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host) 
                        + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture);

                    // For an obvious common case perf
                case UriComponents.AbsoluteUri:     //Scheme|UserInfo|Host|Port|Path|Query|Fragment, 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length)
                        return m_String; 
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme);
 
                    // For Uri.Equals() and HttpWebRequest through a proxy perf
                case UriComponents.HttpRequestUrl:   //Scheme|Host|Port|Path|Query,
                    if (InFact(Flags.HasUserInfo)) {
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                            + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Fragment - m_Info.Offset.Host);
                    } 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) 
                        return m_String;
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme);

                    // For CombineUri() perf
                case UriComponents.SchemeAndServer|UriComponents.UserInfo: 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme);
 
                    // For Cache perf 
                case (UriComponents.AbsoluteUri & ~UriComponents.Fragment):
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) 
                        return m_String;

                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme);
 

                // Strip scheme delimiter if was not requested 
                case UriComponents.Scheme: 
                        if (uriParts != UriComponents.Scheme)
                            return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme); 

                        return m_Syntax.SchemeName;

                // KeepDelimiter makes no sense for this component 
                case UriComponents.Host:
                    ushort idx = m_Info.Offset.Path; 
                    if (InFact(Flags.NotDefaultPort|Flags.PortNotCanonical)) { 
                        //Means we do have ':' after the host
                        while (m_String[--idx] != ':') 
                            ;
                    }
                    return (idx - m_Info.Offset.Host == 0)? string.Empty: m_String.Substring(m_Info.Offset.Host, idx - m_Info.Offset.Host);
 
                case UriComponents.Path:
 
                    // Strip the leading '/' for a hierarchical URI if no delimiter was requested 
                    if (uriParts == UriComponents.Path && InFact(Flags.AuthorityFound) && m_Info.Offset.End > m_Info.Offset.Path &&  m_String[m_Info.Offset.Path] == '/')
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Path + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Path;

                    if (delimiterAwareIdx >= m_Info.Offset.Query) 
                        return string.Empty;
 
 
                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Query - delimiterAwareIdx);
 
                case UriComponents.Query:
                    // Strip the '?' if no delimiter was requested
                    if (uriParts == UriComponents.Query)
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Query + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Query; 
 
                    if (delimiterAwareIdx >= m_Info.Offset.Fragment)
                        return string.Empty; 

                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Fragment - delimiterAwareIdx);

                case UriComponents.Fragment: 
                    // Strip the '#' if no delimiter was requested
                    if (uriParts == UriComponents.Fragment) 
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Fragment + 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Fragment; 

                    if (delimiterAwareIdx >= m_Info.Offset.End)
                        return string.Empty;
 
                    return m_String.Substring(delimiterAwareIdx, m_Info.Offset.End - delimiterAwareIdx);
 
                case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port: 
                    return (m_Info.Offset.Path - m_Info.Offset.User == 0)? string.Empty: m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User);
 
                case UriComponents.StrongAuthority:  //UserInfo|Host|StrongPort
                    if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort)
                        goto case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port;
 
                    return m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User)
                        + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); 
 
                case UriComponents.PathAndQuery:        //Path|Query,
                    return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.Fragment - m_Info.Offset.Path); 

                case UriComponents.HttpRequestUrl|UriComponents.Fragment: //Scheme|Host|Port|Path|Query|Fragment,
                    if (InFact(Flags.HasUserInfo)) {
                        return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) 
                            + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.End - m_Info.Offset.Host);
                    } 
                    if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length) 
                        return m_String;
 
                    return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme);

                case UriComponents.PathAndQuery|UriComponents.Fragment:  //LocalUrl|Fragment
                    return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.End - m_Info.Offset.Path); 

                case UriComponents.UserInfo: 
                        // Strip the '@' if no delimiter was requested 

                    if (NotAny(Flags.HasUserInfo)) 
                        return string.Empty;

                    if (uriParts == UriComponents.UserInfo)
                        delimiterAwareIdx = (ushort)(m_Info.Offset.Host - 1); 
                    else
                        delimiterAwareIdx = m_Info.Offset.Host; 
 
                    if (m_Info.Offset.User >= delimiterAwareIdx)
                        return string.Empty; 

                    return m_String.Substring(m_Info.Offset.User, delimiterAwareIdx - m_Info.Offset.User);

                default: 
                    return null;
            } 
        } 

 
        //
        //This method does:
        //  - Creates m_Info member
        //  - checks all componenets up to path on their canonical representation 
        //  - continues parsing starting the path position
        //  - Sets the offsets of remaining components 
        //  - Sets the Canonicalization flags if applied 
        //  - Will NOT create MoreInfo members
        // 
        private unsafe void ParseRemaining() {

            // ensure we parsed up to the path
            EnsureUriInfo(); 

            Flags cF = Flags.Zero; 
 
            if (UserDrivenParsing)
                goto Done; 

            // Do we have to continue building Iri'zed string from original string
            bool buildIriStringFromPath = m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0) && ((m_Flags & Flags.RestUnicodeNormalized) == 0);
 
            ushort origIdx;     // stores index to switched original string
            ushort idx = m_Info.Offset.Scheme; 
            ushort length = (ushort)m_String.Length; 
            Check result = Check.None;
            UriSyntaxFlags syntaxFlags = m_Syntax.Flags;    // perf 

            // Multithreading!
            // m_Info.Offset values may be parsed twice but we lock only on m_Flags update.
 
            fixed (char* str = m_String){
                // Cut trailing spaces in m_String 
                if (length > idx && IsLWS(str[length - 1])) 
                {
                    --length; 
                    while (length != idx && IsLWS(str[--length]))
                        ;
                    ++length;
                } 

                if (IsImplicitFile){ 
                    cF |= Flags.SchemeNotCanonical; 
                }
                else { 
                    ushort i = 0;
                    ushort syntaxLength = (ushort)m_Syntax.SchemeName.Length;
                    for (; i < syntaxLength; ++i)
                    { 
                        if (m_Syntax.SchemeName[i] != str[idx + i])
                            cF |= Flags.SchemeNotCanonical; 
                    } 
                    // For an authority Uri only // after the scheme would be canonical
                    // (compatibility bug http:\\host) 
                    if (((m_Flags & Flags.AuthorityFound) != 0) && (idx + i + 3 >= length || str[idx + i + 1] != '/' || str[idx + i + 2] != '/')){
                        cF |= Flags.SchemeNotCanonical;
                    }
                } 

 
                //Check the form of the user info 
                if ((m_Flags & Flags.HasUserInfo) != 0){
                    idx = m_Info.Offset.User; 
                    result = CheckCanonical(str, ref idx, m_Info.Offset.Host, '@');
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.UserNotCanonical;
                    } 
                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){
                        cF |= Flags.E_UserNotCanonical; 
                    } 
                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath
                                                    | Check.FoundNonAscii | Check.NotIriCanonical)) 
                                                    == (Check.DisplayCanonical | Check.FoundNonAscii))){
                        cF |= Flags.UserIriCanonical;
                    }
                } 
            }
            // 
            // Delay canonical Host checking to avoid creation of a host string 
            // Will do that on demand.
            // 


            //
            //We have already checked on the port in EnsureUriInfo() that calls CreateUriInfo 
            //
 
            // 
            // Parsing the Path if any
            // 

            // For iri parsing if we found unicode the idx has offset into m_[....] string..
            // so restart parsing from there and make m_Info.Offset.Path as m_string.length
 
            idx = m_Info.Offset.Path;
            origIdx = m_Info.Offset.Path; 
 
            //Some uris do not have a query
            //    When '?' is passed as delimiter, then it's special case 
            //    so both '?' and '#' will work as delimiters
            if (buildIriStringFromPath){
                m_Info.Offset.Path = (ushort)m_String.Length;
                idx = m_Info.Offset.Path; 

                ushort offset = origIdx; 
                if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ 
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_DummyChar);
                } 
                else{
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length,
                   (m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL));
                } 

                // Correctly escape unescape 
                string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Path); 

                // Normalize path 
                try{
                    m_String += escapedPath.Normalize(NormalizationForm.FormC);
                }
                catch (ArgumentException){ 
                    UriFormatException e = GetException(ParsingError.BadFormat);
                    throw e; 
                } 

                length = (ushort)m_String.Length; 
            }

            fixed (char* str = m_String){
                if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ 
                    result = CheckCanonical(str, ref idx, length, c_DummyChar);
                } 
                else { 
                    result = CheckCanonical(str, ref idx, length, (((syntaxFlags & UriSyntaxFlags.MayHaveQuery) != 0) ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL));
                } 

                // ATTN:
                // This may render problems for unknown schemes, but in general for an authority based Uri
                // (that has slashes) a path should start with "/" 
                // This becomes more interesting knowning how a file uri is used in "file://c:/path"
                // It will be converted to file:///c:/path 
                // 
                // However, even more interesting is that vsmacros://c:\path will not add the third slash in the _canoical_ case
                // (vsmacros inventors have violated the RFC) 
                //
                // We use special syntax flag to check if the path is rooted, i.e. has a first slash
                //
                if (((m_Flags & Flags.AuthorityFound) != 0) && ((syntaxFlags & UriSyntaxFlags.PathIsRooted) != 0) 
                    && (m_Info.Offset.Path == length || (str[m_Info.Offset.Path] != '/' && str[m_Info.Offset.Path] != '\\'))){
                    cF |= Flags.FirstSlashAbsent; 
                } 
            }
            // Check the need for compression or backslashes conversion 
            // we included IsDosPath since it may come with other than FILE uri, for ex. scheme://C:\path
            // (This is very unfortunate that the original design has included that feature)
            bool nonCanonical = false;
            if (IsDosPath || (((m_Flags & Flags.AuthorityFound) != 0) && ((syntaxFlags & (UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.UnEscapeDotsAndSlashes)) != 0))) 
            {
                if (((syntaxFlags & (UriSyntaxFlags.UnEscapeDotsAndSlashes)) != 0) && (result & Check.DotSlashEscaped) != 0){ 
                    cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical); 
                    nonCanonical = true;
                } 

                if (((syntaxFlags & (UriSyntaxFlags.ConvertPathSlashes)) != 0) && (result & Check.BackslashInPath) != 0){
                    cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical);
                    nonCanonical = true; 
                }
 
                if (((syntaxFlags & (UriSyntaxFlags.CompressPath)) != 0) && ((cF & Flags.E_PathNotCanonical) != 0 || (result & Check.DotSlashAttn) != 0)) 
                    cF |= Flags.ShouldBeCompressed;
 
                if ((result & Check.BackslashInPath) != 0)
                    cF |= Flags.BackslashInPath;

            } 
            else if ((result & Check.BackslashInPath) != 0){
                // for a "generic" path '\' should be escaped 
                cF |= Flags.E_PathNotCanonical; 
                nonCanonical = true;
            } 

            if ((result & Check.DisplayCanonical) == 0){
                // For implicit file the user string is usually in perfect display format,
                // Hence, ignoring complains from CheckCanonical() 
                //
 
                if (((m_Flags & Flags.ImplicitFile) == 0) || ((m_Flags & Flags.UserEscaped) != 0) || (result & Check.ReservedFound) != 0){ 
                    //means it's found as escaped or has unescaped Reserved Characters
                    cF |= Flags.PathNotCanonical; 
                    nonCanonical = true;
                }
            }
 
            if (((m_Flags & Flags.ImplicitFile) != 0) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0){
                // need to escape reserved chars or re-escape '%' if an "escaped sequence" was found 
                result &= ~Check.EscapedCanonical; 
            }
 
            if ((result & Check.EscapedCanonical) == 0){
                //means it's found as not completely escaped
                cF |= Flags.E_PathNotCanonical;
            } 

            if (m_iriParsing && !nonCanonical & ((result & (Check.DisplayCanonical | Check.EscapedCanonical 
                            | Check.FoundNonAscii | Check.NotIriCanonical)) 
                            == (Check.DisplayCanonical | Check.FoundNonAscii))){
                cF |= Flags.PathIriCanonical; 
            }

            //
            //Now we've got to parse the Query if any. Note that Query requires the presence of '?' 
            //
           if (buildIriStringFromPath){ 
               ushort offset = origIdx; 

               if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '?'){ 
                   ++origIdx; // This is to exclude first '?' character from checking
                   FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, ((syntaxFlags &(UriSyntaxFlags.MayHaveFragment)) != 0) ? '#' : c_EOL);

                   // Correctly escape unescape 
                   string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Query);
 
                   // Normalize path 
                   try{
                       m_String += escapedPath.Normalize(NormalizationForm.FormC); 
                   }
                   catch (ArgumentException){
                       UriFormatException e = GetException(ParsingError.BadFormat);
                       throw e; 
                   }
 
                   length = (ushort)m_String.Length; 
               }
            } 

            m_Info.Offset.Query = idx;

            fixed (char* str = m_String){ 
                if (idx < length && str[idx] == '?'){
                    ++idx; // This is to exclude first '?' character from checking 
                    result = CheckCanonical(str, ref idx, length, ((syntaxFlags & (UriSyntaxFlags.MayHaveFragment)) != 0) ? '#' : c_EOL); 
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.QueryNotCanonical; 
                    }

                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){
                        cF |= Flags.E_QueryNotCanonical; 
                    }
 
                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath 
                                | Check.FoundNonAscii | Check.NotIriCanonical))
                                == (Check.DisplayCanonical | Check.FoundNonAscii))){ 
                        cF |= Flags.QueryIriCanonical;
                    }

                } 
            }
            // 
            //Now we've got to parse the Fragment if any. Note that Fragment requires the presense of '#' 
            //
            if (buildIriStringFromPath){ 
                ushort offset = origIdx;

                if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '#')
                { 
                    ++origIdx; // This is to exclude first '#' character from checking
                    FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_EOL); 
 
                    // Correctly escape unescape
                    string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Fragment); 

                    // Normalize path
                    try{
                        m_String += escapedPath.Normalize(NormalizationForm.FormC); 
                    }
                    catch (ArgumentException){ 
                        UriFormatException e = GetException(ParsingError.BadFormat); 
                        throw e;
                    } 

                    length = (ushort)m_String.Length;
                }
            } 

            m_Info.Offset.Fragment = idx; 
 
            fixed (char* str = m_String){
                if (idx < length && str[idx] == '#'){ 
                    ++idx; // This is to exclude first '#' character from checking
                    result = CheckCanonical(str, ref idx, length, c_EOL);     //We don't using c_DummyChar since want to allow '?' and '#' as unescaped
                    if ((result & Check.DisplayCanonical) == 0){
                        cF |= Flags.FragmentNotCanonical; 
                    }
 
                    if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){ 
                        cF |= Flags.E_FragmentNotCanonical;
                    } 

                    if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath
                                | Check.FoundNonAscii | Check.NotIriCanonical))
                                == (Check.DisplayCanonical | Check.FoundNonAscii))){ 
                        cF |= Flags.FragmentIriCanonical;
                    } 
 
                }
            } 
                m_Info.Offset.End = idx;
        Done:

            cF |= Flags.AllUriInfoSet; 
            lock (m_Info)
            { 
                m_Flags |= cF; 
            }
            m_Flags |= Flags.RestUnicodeNormalized; 
        }

        //
        // 
        // verifies the syntax of the scheme part
        // Checks on implicit File: scheme due to simple Dos/Unc path passed 
        // returns the start of the next component  position 
        // throws UriFormatException if invalid scheme
        // 
        unsafe static private ushort ParseSchemeCheckImplicitFile(char *uriString, ushort length, ref ParsingError err, ref Flags flags, ref UriParser syntax) {

            ushort idx = 0;
 
            //skip whitespaces
            while(idx < length && IsLWS(uriString[idx])) { 
                ++idx; 
            }
 
            // sets the recognizer for well known registered schemes
            // file, ftp, http, https, uuid, etc
            // Note that we don't support one-letter schemes that will be put into a DOS path bucket
 
            //
            ushort end = idx; 
            while (end < length && uriString[end] != ':') { 
                ++end;
            } 

            // NB: On 64-bits we will use less optimized code from CheckSchemeSyntax()
            //
            if (IntPtr.Size == 4) { 
                // long = 4chars: The minimal size of a known scheme is 3 + ':'
                if (end != length && end >= idx+3 && CheckKnownSchemes((long*) (uriString + idx), (ushort)(end-idx), ref syntax)) { 
                    return (ushort)(end+1); 
                }
            } 

            //NB: A string must have at least 3 characters and at least 1 before ':'
            if (idx+2 >= length || end == idx) {
                err = ParsingError.BadFormat; 
                return 0;
            } 
 
            //Check for supported special cases like a DOS file path OR a UNC share path
            //NB: A string may not have ':' if this is a UNC path 
        {
            char c;
            if ((c=uriString[idx+1]) == ':' || c == '|') {
#if !PLATFORM_UNIX 
                //DOS-like path?
                if (IsAsciiLetter(uriString[idx])) { 
                    if((c=uriString[idx+2]) == '\\' || c== '/') { 
                        flags |= (Flags.DosPath|Flags.ImplicitFile|Flags.AuthorityFound);
                        syntax = UriParser.FileUri; 
                        return idx;
                    }
                    err = ParsingError.MustRootedPath;
                    return 0; 
                }
#endif // !PLATFORM_UNIX 
                if (c == ':') 
                    err = ParsingError.BadScheme;
                else 
                    err = ParsingError.BadFormat;
                return 0;
            }
#if !PLATFORM_UNIX 
            else if ((c=uriString[idx]) == '/' || c == '\\') {
                //UNC share ? 
                if ((c=uriString[idx+1]) == '\\' || c == '/') { 
                    flags |= (Flags.UncPath|Flags.ImplicitFile|Flags.AuthorityFound);
                    syntax = UriParser.FileUri; 
                    idx+=2;
                    // V1.1 compat this will simply eat any slashes prepended to a UNC path
                    while (idx < length && ((c=uriString[idx]) == '/' ||  c == '\\'))
                        ++idx; 

                    return idx; 
                } 
                err = ParsingError.BadFormat;
                return 0; 
            }
#else
            else if (uriString[idx] == '/') {
                // On UNIX an implicit file has the form / or scheme:/// 
                if (idx == 0 || uriString[idx-1] != ':' ) {
                    // No scheme present; implicit / starting at idx 
                    flags |= (Flags.ImplicitFile|Flags.AuthorityFound); 
                    syntax = UriParser.FileUri;
                    return idx; 
                } else if (uriString[idx+1] == '/' && uriString[idx+2] == '/') {
                    // scheme present; rooted path starts at idx + 2
                    flags |= (Flags.ImplicitFile|Flags.AuthorityFound);
                    syntax = UriParser.FileUri; 
                    idx+=2;
                    return idx; 
                } 
            }
            else if (uriString[idx] == '\\') { 
                err = ParsingError.BadFormat;
                return 0;
            }
#endif // !PLATFORM_UNIX 
        }
 
            if (end == length) { 
                err = ParsingError.BadFormat;
                return 0; 
            }

            // Here could be a possibly valid, and not well-known scheme
            // Finds the scheme delimiter 
            // we don;t work with the schemes names > c_MaxUriSchemeName (should be ~1k)
            if ((end-idx) > c_MaxUriSchemeName) { 
                err = ParsingError.SchemeLimit; 
                return 0;
            } 

            //Check the syntax, canonicalize  and avoid a GC call
            char* schemePtr = stackalloc char[end-idx];
            for (length = 0; idx < end; ++idx) { 
                schemePtr[length++] = uriString[idx];
            } 
            err = CheckSchemeSyntax(schemePtr, length, ref syntax); 
            if (err != ParsingError.None) {
                return 0; 
            }
            return (ushort)(end+1);
        }
        // 
        // Quickly parses well known schemes.
        // nChars does not include the last ':'. Assuming there is one at the end of passed buffer 
        unsafe static private bool CheckKnownSchemes(long *lptr, ushort nChars, ref UriParser syntax) { 
            //NOTE beware of too short input buffers!
 
            const long _HTTP_Mask0   = 'h'|('t'<<16)|((long)'t'<<32)|((long)'p'<<48);
            const char _HTTPS_Mask1  = 's';
            const long _FTP_Mask     = 'f'|('t'<<16)|((long)'p'<<32)|((long)':'<<48);
            const long _FILE_Mask0   = 'f'|('i'<<16)|((long)'l'<<32)|((long)'e'<<48); 
            const long _GOPHER_Mask0 = 'g'|('o'<<16)|((long)'p'<<32)|((long)'h'<<48);
            const int  _GOPHER_Mask1 = 'e'|('r'<<16); 
            const long _MAILTO_Mask0 = 'm'|('a'<<16)|((long)'i'<<32)|((long)'l'<<48); 
            const int  _MAILTO_Mask1 = 't'|('o'<<16);
            const long _NEWS_Mask0   = 'n'|('e'<<16)|((long)'w'<<32)|((long)'s'<<48); 
            const long _NNTP_Mask0   = 'n'|('n'<<16)|((long)'t'<<32)|((long)'p'<<48);
            const long _UUID_Mask0   = 'u'|('u'<<16)|((long)'i'<<32)|((long)'d'<<48);

            const long _TELNET_Mask0 = 't'|('e'<<16)|((long)'l'<<32)|((long)'n'<<48); 
            const int  _TELNET_Mask1 = 'e'|('t'<<16);
 
            const long _NETXXX_Mask0 = 'n'|('e'<<16)|((long)'t'<<32)|((long)'.'<<48); 
            const long _NETTCP_Mask1 = 't'|('c'<<16)|((long)'p'<<32)|((long)':'<<48);
            const long _NETPIPE_Mask1 = 'p'|('i'<<16)|((long)'p'<<32)|((long)'e'<<48); 

            const long _LDAP_Mask0   = 'l'|('d'<<16)|((long)'a'<<32)|((long)'p'<<48);

 
            const long _LOWERCASE_Mask = 0x0020002000200020L;
            const int  _INT_LOWERCASE_Mask = 0x00200020; 
 

            //Map to a known scheme if possible 
            //upgrade 4 letters to ASCII lower case, keep a false case to stay false
            switch (*lptr | _LOWERCASE_Mask) {
                case _HTTP_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.HttpUri;
                        return true; 
                    } 
                    if (nChars == 5 && ((*(char*)(lptr+1))|0x20) == _HTTPS_Mask1) {
                        syntax = UriParser.HttpsUri; 
                        return true;
                    }
                    break;
 
                case _FILE_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.FileUri; 
                        return true;
                    } 
                    break;
                case _FTP_Mask:
                    if (nChars == 3) {
                        syntax = UriParser.FtpUri; 
                        return true;
                    } 
                    break; 

                case _NEWS_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.NewsUri;
                        return true;
                    } 
                    break;
 
                case _NNTP_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.NntpUri; 
                        return true;
                    }
                    break;
 
                case _UUID_Mask0:
                    if (nChars == 4) { 
                        syntax = UriParser.UuidUri; 
                        return true;
                    } 
                    break;

                case _GOPHER_Mask0:
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _GOPHER_Mask1) { 
                        syntax = UriParser.GopherUri;
                        return true; 
                    } 
                    break;
                case _MAILTO_Mask0: 
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _MAILTO_Mask1) {
                        syntax = UriParser.MailToUri;
                        return true;
                    } 
                    break;
 
                case _TELNET_Mask0: 
                    if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _TELNET_Mask1) {
                        syntax = UriParser.TelnetUri; 
                        return true;
                    }
                    break;
 
                case _NETXXX_Mask0:
                    if (nChars == 8 && (*(lptr+1)|_LOWERCASE_Mask) == _NETPIPE_Mask1) { 
                        syntax = UriParser.NetPipeUri; 
                        return true;
                    } 
                    else if (nChars == 7 && (*(lptr+1)|_LOWERCASE_Mask) == _NETTCP_Mask1) {
                        syntax = UriParser.NetTcpUri;
                        return true;
                    } 
                    break;
 
                case _LDAP_Mask0: 
                    if (nChars == 4) {
                        syntax = UriParser.LdapUri; 
                        return true;
                    }
                    break;
                default:    break; 
            }
            return false; 
        } 

        // 
        //
        // This will check whether a scheme string follows the rules
        //
        unsafe static private ParsingError CheckSchemeSyntax(char* ptr, ushort length, ref UriParser syntax) { 
            //First character must be an alpha
        { 
            char c = *ptr; 
            if (c >= 'a' && c <= 'z') {
                ; 
            } else if (c >= 'A' && c <= 'Z') {
                *ptr = (char)(c | 0x20);    //make it lowercase
            } else {
                return ParsingError.BadScheme; 
            }
        } 
 
            for (ushort i = 1; i < length; ++i) {
                char c = ptr[i]; 
                if (c >= 'a' && c <= 'z') {
                    ;
                } else if (c >= 'A' && c <= 'Z') {
                    ptr[i] = (char)(c | 0x20);    //make it lowercase 
                } else if (c >= '0' && c <= '9') {
                    ; 
                } else if (c == '+' || c == '-' || c == '.') { 
                    ;
                } else { 
                    return ParsingError.BadScheme;
                }
            }
            // A not well-known scheme, needs string creation 
            // Note it is already in the lower case as required.
            string str  =  new string(ptr, 0, length); 
            syntax = UriParser.FindOrFetchAsUnknownV1Syntax(str); 
            return ParsingError.None;
        } 
        //
        //
        // Checks the syntax of an authority component. It may also get a userInfo if present
        // Returns an error if no/mailformed authority found 
        // Does not NOT touch m_Info
        // Returns position of the Path component 
        // 
        // Must be called in the ctor only
        private unsafe ushort CheckAuthorityHelper( char* pString, ushort idx, ushort length, 
                                                    ref ParsingError err, ref Flags flags, UriParser syntax,
                                                    ref string newHost )
        {
            int end = length; 
            char ch;
            int startInput = idx; 
            ushort start = idx; 
            newHost = null;
            bool justNormalized = false; 
            bool iriParsing = (s_IriParsing && IriParsingStatic(syntax)); // perf
            bool hasUnicode = ((flags & Flags.HasUnicode) != 0); // perf
            bool hostNotUnicodeNormalized = ((flags & Flags.HostUnicodeNormalized) == 0); // perf
            UriSyntaxFlags syntaxFlags = syntax.Flags; 

            // need to build new Iri'zed string 
            if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                newHost = m_originalUnicodeString.Substring(0, startInput);
            } 

            //Special case is an empty authority
            if (idx == length || ((ch=pString[idx]) == '/' || (ch == '\\' && StaticIsFile(syntax)) || ch == '#' || ch == '?'))
            { 
                if (syntax.InFact(UriSyntaxFlags.AllowEmptyHost))
                { 
                    flags &= ~Flags.UncPath;    //UNC cannot have an empty hostname 
                    if (StaticInFact(flags, Flags.ImplicitFile))
                        err = ParsingError.BadHostName; 
                    else
                        flags |= Flags.BasicHostType;
                }
                else 
                    err = ParsingError.BadHostName;
 
                if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                    flags |= Flags.HostUnicodeNormalized;// no host
                } 

                 return idx;
            }
 
#if PLATFORM_UNIX
            if (StaticIsFile(syntax) && ch != '/') { 
                // On UNIX a file URL may only have an empty authority 
                err = ParsingError.NonEmptyHost;
                return idx; 
            }
#endif // PLATFORM_UNIX

            string userInfoString = null; 
            // Attempt to parse user info first
 
            if ((syntaxFlags & UriSyntaxFlags.MayHaveUserInfo) != 0) 
            {
                for (; start < end; ++start) 
                {
                    if (start == end - 1 || pString[start] == '?' || pString[start] == '#' || pString[start] == '\\' || pString[start] == '/')
                    {
                        start = idx; 
                        break;
                    } 
                    else if (pString[start] == '@') 
                    {
                        flags |= Flags.HasUserInfo; 

                        // Iri'ze userinfo
                        if (iriParsing || (s_IdnScope != UriIdnScope.None)){
                            if (iriParsing && hasUnicode && hostNotUnicodeNormalized){ 
                                // Normalize user info
                                userInfoString = EscapeUnescapeIri(pString, startInput, start + 1, UriComponents.UserInfo); 
                                try{ 
                                    userInfoString = userInfoString.Normalize(NormalizationForm.FormC);
                                } 
                                catch (ArgumentException){
                                    err = ParsingError.BadFormat;
                                    return idx;
                                } 

                                newHost += userInfoString; 
                            } 
                            else{
                                userInfoString = new string(pString, startInput, start - startInput + 1); 
                            }
                        }
                        ++start;
                        ch = pString[start]; 
                        break;
                    } 
                } 
            }
 
            // DNS name only optimization
            // Fo an overriden parsing the optimization is suppressed since hostname can be changed to anything
            bool dnsNotCanonical = ((syntaxFlags & UriSyntaxFlags.SimpleUserSyntax) == 0);
 
            if (ch == '[' && syntax.InFact(UriSyntaxFlags.AllowIPv6Host) && IPv6AddressHelper.IsValid(pString, (int)start+1, ref end))
            { 
                flags |= Flags.IPv6HostType; 

                // Force load config here if config not loaded earlier since we handle IsWellFormed differently 
                // for IPv6 if the iri parsing flag is on or off
                if (!s_ConfigInitialized) {
                    InitializeUriConfig();
                    m_iriParsing = (s_IriParsing && IriParsingStatic(syntax)); 
                }
 
                if (hasUnicode && iriParsing && hostNotUnicodeNormalized) { 
                    newHost += new string(pString, start, end - start);
                    flags |= Flags.HostUnicodeNormalized; 
                    justNormalized = true;
                }
            }
            else if ( ch <= '9' && ch >= '0' && syntax.InFact(UriSyntaxFlags.AllowIPv4Host) && 
                IPv4AddressHelper.IsValid(pString, (int) start, ref end, false, StaticNotAny(flags, Flags.ImplicitFile)))
            { 
                flags |= Flags.IPv4HostType; 

                if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ 
                    newHost += new string(pString, start, end - start);
                    flags |= Flags.HostUnicodeNormalized;
                    justNormalized = true;
                } 
            }
            else if (((syntaxFlags & UriSyntaxFlags.AllowDnsHost)!= 0) && !iriParsing && 
           DomainNameHelper.IsValid(pString, start, ref end, ref dnsNotCanonical, StaticNotAny(flags, Flags.ImplicitFile))) 
            {
                // comes here if there are only ascii chars in host with original parsing and no Iri 

                flags |= Flags.DnsHostType;
                if (!dnsNotCanonical) {
                    flags |= Flags.CanonicalDnsHost; 
                }
 
                if ((s_IdnScope != UriIdnScope.None)){ 
                    // check if intranet
                    // 
                    if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end))){
                        flags |= Flags.IntranetUri;
                    }
                    if (AllowIdnStatic(syntax, flags)){ 
                        bool allAscii = true;
                        bool atLeastOneIdn = false; 
 
                        string idnValue = DomainNameHelper.UnicodeEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn);
 
                        // did we find at least one valid idn
                        if (atLeastOneIdn)
                        {
                            // need to switch string here since we didnt know before hand there there was an idn host 
                            if (StaticNotAny(flags, Flags.HasUnicode))
                                m_originalUnicodeString = m_String; // lazily switching strings 
                            flags |= Flags.IdnHost; 

                            // need to build string for this special scenario 
                            newHost = m_originalUnicodeString.Substring(0, startInput) + userInfoString + idnValue;
                            flags |= Flags.CanonicalDnsHost;
                            m_DnsSafeHost = new string(pString, start, end - start);
                            justNormalized = true; 
                        }
                        flags |= Flags.HostUnicodeNormalized; 
                    } 
                }
            } 
            else if ((iriParsing || (s_IdnScope != UriIdnScope.None)) && ((syntaxFlags & UriSyntaxFlags.AllowDnsHost) != 0) &&
                    ((iriParsing && hostNotUnicodeNormalized) || AllowIdnStatic(syntax, flags)) &&
                    DomainNameHelper.IsValidByIri(  pString, start, ref end, ref dnsNotCanonical,
                                                    StaticNotAny(flags, Flags.ImplicitFile))) 
            {
                CheckAuthorityHelperHandleDnsIri(pString, start, end, startInput, iriParsing, hasUnicode, syntax, userInfoString, 
                                                ref flags, ref justNormalized, ref newHost, ref err); 

            } 
#if !PLATFORM_UNIX
            else if ((s_IdnScope == UriIdnScope.None) && (!s_IriParsing) && ((syntaxFlags & UriSyntaxFlags.AllowUncHost) != 0))
            {
                // 
                // This must remain as the last check befor BasicHost type
                // 
                if (UncNameHelper.IsValid(pString, start, ref end, StaticNotAny(flags, Flags.ImplicitFile))) 
                {
                    if (end - start <= UncNameHelper.MaximumInternetNameLength) 
                        flags |= Flags.UncHostType;
                }
            }
#endif // !PLATFORM_UNIX 

            // The deal here is that we won't allow '\' host terminator except for the File scheme 
            // If we see '\' we try to make it a part of of a Basic host 
            if (end < length && pString[end] == '\\' && (flags & Flags.HostTypeMask) != Flags.HostNotParsed && !StaticIsFile(syntax))
            { 
                if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri))
                {
                    err = ParsingError.BadHostName;
                    flags |= Flags.UnknownHostType; 
                    return (ushort) end;
                } 
                flags &= ~Flags.HostTypeMask; 
            }
            // Here we have checked the syntax up to the end of host 
            // The only thing that can cause an exception is the port value
            // Spend some (duplicated) cycles on that.
            else if (end < length && pString[end] == ':')
            { 
                if (syntax.InFact(UriSyntaxFlags.MayHavePort))
                { 
                    int port = 0; 
                    int startPort = end;
                    for (idx = (ushort)(end+1); idx < length; ++idx) { 
                        ushort val = (ushort)((ushort)pString[idx] - (ushort)'0');
                        if ((val >= 0) && (val <= 9))
                        {
                            if ((port = (port * 10 + val)) > 0xFFFF) 
                                break;
                        } 
                        else if (val == unchecked((ushort)('/' - '0')) || val == (ushort)('?' - '0') || val == unchecked((ushort)('#' - '0'))) 
                        {
                            break; 
                        }
                        else
                        {
                            // The second check is to keep compatibility with V1 until the UriParser is registered 
                            if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost) && syntax.NotAny(UriSyntaxFlags.V1_UnknownUri))
                            { 
                                flags &= ~Flags.HostTypeMask; 
                                break;
                            } 
                            else
                            {
                                err = ParsingError.BadPort;
                                return idx; 
                            }
                        } 
                    } 
                    // check on 0-ffff range
                    if (port > 0xFFFF) 
                    {
                        if (syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost))
                        {
                            flags &= ~Flags.HostTypeMask; 
                        }
                        else 
                        { 
                            err = ParsingError.BadPort;
                            return idx; 
                        }
                    }

                    if (iriParsing && hasUnicode && justNormalized){ 
                        newHost += new string(pString, startPort, idx - startPort);
                    } 
                } 
                else
                { 
                    flags &= ~Flags.HostTypeMask;
                }

            } 

            // check on whether nothing has worked out 
            if ((flags & Flags.HostTypeMask) == Flags.HostNotParsed) 
            {
                //No user info for a Basic hostname 
                flags &= ~Flags.HasUserInfo;
                // Some schemes do not allow HostType = Basic (plus V1 almost never understands this cause of a bug)
                //
                if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost)) 
                {
                    flags |= Flags.BasicHostType; 
                    for (end = idx; end < length; ++end) { 
                        if (pString[end] == '/' || (pString[end] == '?' || pString[end] == '#')) {
                            break; 
                        }
                    }
                    CheckAuthorityHelperHandleAnyHostIri(pString, startInput, end, iriParsing, hasUnicode, syntax,
                                                            ref flags, ref newHost, ref err); 
                }
                else 
                { 
                    //
                    // ATTN V1 compat: V1 supports hostnames like ".." and ".", and so we do but only for unknown schemes. 
                    //                 (VsWhidbey#438821)
                    if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri))
                    {
                        // Can assert here that the host is not empty so we will set dotFound 
                        // at least once or fail before exiting the loop
                        bool dotFound = false; 
                        int startOtherHost = idx; 
                        for (end = idx; end < length; ++end)
                        { 
                            if (dotFound && (pString[end] == '/' || pString[end] == '?' || pString[end] == '#'))
                                break;
                            else if (end < (idx + 2) && pString[end] == '.')
                            { 
                                // allow one or two dots
                                dotFound = true; 
                            } 
                            else
                            { 
                                //failure
                                err = ParsingError.BadHostName;
                                flags |= Flags.UnknownHostType;
                                return idx; 
                            }
                        } 
                        //success 
                        flags |= Flags.BasicHostType;
 
                        if (iriParsing && hasUnicode
                            && StaticNotAny(flags, Flags.HostUnicodeNormalized)){
                            // Normalize any other host
                            String user = new string(pString, startOtherHost, startOtherHost - end); 
                            try
                            { 
                                newHost += user.Normalize(NormalizationForm.FormC); 
                            }
                            catch (ArgumentException){ 
                                err = ParsingError.BadFormat;
                                return idx;
                            }
 
                            flags |= Flags.HostUnicodeNormalized;
                        } 
                    } 
                    else if(syntax.InFact(UriSyntaxFlags.MustHaveAuthority))
                    { 
                        err = ParsingError.BadHostName;
                        flags |= Flags.UnknownHostType;
                        return idx;
                    } 
                }
            } 
            return (ushort) end; 
        }
 
        unsafe void CheckAuthorityHelperHandleDnsIri( char* pString, ushort start, int end, int startInput,
                                            bool iriParsing, bool hasUnicode, UriParser syntax, string userInfoString,
                                            ref Flags flags, ref bool justNormalized, ref string newHost, ref ParsingError err)
        { 
            // comes here only if host has unicode chars and iri is on or idn is allowed
 
            flags |= Flags.DnsHostType; 

            // check if intranet 
            //
            if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end)))
            {
                flags |= Flags.IntranetUri; 
            }
 
            if (AllowIdnStatic(syntax, flags)) 
            {
                bool allAscii = true; 
                bool atLeastOneIdn = false;

                string idnValue = DomainNameHelper.IdnEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn);
                string UniEquvlt = DomainNameHelper.UnicodeEquivalent(idnValue, pString, start, end); 

                if (!allAscii) 
                    flags |= Flags.UnicodeHost; // we have a unicode host 

                if (atLeastOneIdn) 
                    flags |= Flags.IdnHost;   // we have at least one valid idn label

                if (allAscii && atLeastOneIdn && StaticNotAny(flags, Flags.HasUnicode))
                { 
                    // original string location changed lazily
                    m_originalUnicodeString = m_String; 
                    newHost = m_originalUnicodeString.Substring(0, startInput) + 
                        (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null);
                    justNormalized = true; 
                }
                else if (!iriParsing && (StaticInFact(flags, Flags.UnicodeHost) || StaticInFact(flags, Flags.IdnHost)))
                {
                    // original string location changed lazily 
                    m_originalUnicodeString = m_String;
                    newHost = m_originalUnicodeString.Substring(0, startInput) + 
                        (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null); 
                    justNormalized = true;
                } 

                if (!(allAscii && !atLeastOneIdn))
                {
                    m_DnsSafeHost = idnValue; 
                    newHost += UniEquvlt;
                    justNormalized = true; 
                } 
                else if (allAscii && !atLeastOneIdn && iriParsing && hasUnicode)
                { 
                    newHost += UniEquvlt;
                    justNormalized = true;
                }
            } 
            else
            { 
                if (hasUnicode) 
                {
                    string temp = StripBidiControlCharacter(pString, start, end - start); 
                    try{
                        newHost += ((temp != null) ? temp.Normalize(NormalizationForm.FormC) : null);
                    }
                    catch (ArgumentException){ 
                        err = ParsingError.BadHostName;
                    } 
                    justNormalized = true; 
                }
            } 
            flags |= Flags.HostUnicodeNormalized;
        }

        unsafe void CheckAuthorityHelperHandleAnyHostIri(char* pString, int startInput, int end, 
                                            bool iriParsing, bool hasUnicode, UriParser syntax,
                                            ref Flags flags, ref string newHost, ref ParsingError err) 
        { 
            if (StaticNotAny(flags, Flags.HostUnicodeNormalized) && (AllowIdnStatic(syntax, flags) || (iriParsing && hasUnicode)))
            { 
                // Normalize any other host or do idn
                String user = new string(pString, startInput, end - startInput);

                if (AllowIdnStatic(syntax, flags)) 
                {
                    bool allAscii = true; 
                    bool atLeastOneIdn = false; 

                    string UniEquvlt = DomainNameHelper.UnicodeEquivalent(pString, startInput, end, ref allAscii, ref atLeastOneIdn); 

                    if (((allAscii && atLeastOneIdn) || !allAscii) && !(iriParsing && hasUnicode))
                    {
                        // original string location changed lazily 
                        m_originalUnicodeString = m_String;
                        newHost = m_originalUnicodeString.Substring(0, startInput); 
                        flags |= Flags.HasUnicode; 
                    }
                    if (atLeastOneIdn || !allAscii) 
                    {
                        newHost += UniEquvlt;
                        string bidiStrippedHost = null;
                        m_DnsSafeHost = DomainNameHelper.IdnEquivalent(pString, startInput, end, ref  allAscii, ref bidiStrippedHost); 
                        if (atLeastOneIdn)
                            flags |= Flags.IdnHost; 
                        if (!allAscii) 
                            flags |= Flags.UnicodeHost;
                    } 
                    else if (iriParsing && hasUnicode)
                    {
                        newHost += user;
 
                    }
                } 
                else 
                {
                    try{ 
                        newHost += user.Normalize(NormalizationForm.FormC);
                    }
                    catch (ArgumentException){
                        err = ParsingError.BadHostName; 
                    }
                } 
 
                flags |= Flags.HostUnicodeNormalized;
            } 
        }

        //
        // 
        // The method checks whether a string needs transformation before going to display or wire
        // 
        // Parameters: 
        // - escaped   true = treat all valid escape sequences as escaped sequences, false = escape all %
        // - delim     a character signalling the termination of the component being checked 
        //
        // When delim=='?', then '#' character is also considered as delimiter additionally to passed '?'.
        //
        // The method pays attention to the dots and slashes so to signal potential Path compression action needed. 
        // Even that is not required for other components, the cycles are still spent (little inefficiency)
        // 
 
        const char c_DummyChar = (char) 0xFFFF;     //An Invalid Unicode character used as a dummy char passed into the parameter
        const char c_EOL       = (char) 0xFFFE;     //An Invalid Unicode character used by CheckCanonical as "no delimiter condition" 
        [Flags]
        private enum Check {
            None            = 0x0,
            EscapedCanonical= 0x1, 
            DisplayCanonical= 0x2,
            DotSlashAttn    = 0x4, 
            DotSlashEscaped = 0x80, 
            BackslashInPath = 0x10,
            ReservedFound   = 0x20, 
            NotIriCanonical = 0x40,
            FoundNonAscii =    0x8
        }
 
        //
        // Finds the end of component 
        // 

        private unsafe void FindEndOfComponent(string input, ref ushort idx, ushort end, char delim) 
        {
            fixed (char* str = input)
            {
                FindEndOfComponent(str, ref idx, end, delim); 
            }
        } 
        private unsafe void FindEndOfComponent(char* str, ref ushort idx, ushort end, char delim) 
        {
            char c = c_DummyChar; 
            ushort i=idx;
            for (; i < end; ++i)
            {
                c = str[i]; 
                if (c == delim)
                { 
                    break; 
                }
                else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) 
                {
                    // this is a special case when deciding on Query/Fragment
                    break;
                } 
            }
            idx = i; 
        } 

        // 
        // Used by ParseRemaining as well by InternalIsWellFormedOriginalString
        //
        private unsafe Check CheckCanonical(char* str, ref ushort idx, ushort end, char delim) {
            Check res = Check.None; 
            bool needsEscaping = false;
            bool foundEscaping = false; 
 
            char c = c_DummyChar;
            ushort i=idx; 
            for (; i < end; ++i)
            {
                c = str[i];
                // Control chars usually should be escaped in any case 
                if (c <= '\x1F' || (c >= '\x7F' && c <= '\x9F'))
                { 
                    needsEscaping = true; 
                    foundEscaping = true;
                    res |= Check.ReservedFound; 
                }
                else if (c > 'z' && c != '~') {
                    if(m_iriParsing){
                        bool valid = false; 
                        res |= Check.FoundNonAscii;
 
                        if (Char.IsHighSurrogate(c)){ 
                            if ((i + 1) < end){
                                bool surrPair = false; 
                                valid = CheckIriUnicodeRange(c, str[i + 1], ref surrPair, true);
                            }
                        }
                        else{ 
                            valid = CheckIriUnicodeRange(c, true);
                        } 
                        if (!valid) res |= Check.NotIriCanonical; 
                    }
 
                    if (!needsEscaping) needsEscaping = true;
                }
                else if (c == delim) {
                    break; 
                }
                else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) { 
                    // this is a special case when deciding on Query/Fragment 
                    break;
                } 
                else if (c == '?') {
                    if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) && delim != c_EOL))
                    {
                        // VsWhidbey#87423 
                        // If found as reserved this char is not suitable for safe unescaped display
                        // Will need to escape it when both escaping and unescaping the string 
                        res |= Check.ReservedFound; 
                        foundEscaping = true;
                        needsEscaping = true; 
                    }
                }
                else if (c == '#') {
                    needsEscaping = true; 
                    if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) {
                        // VsWhidbey#87423, 122037 
                        // If found as reserved this char is not suitable for safe unescaped display 
                        // Will need to escape it when both escaping and unescaping the string
                        res |= Check.ReservedFound; 
                        foundEscaping = true;
                    }
                }
                else if (c == '/' || c == '\\') { 
                    if ((res & Check.BackslashInPath) == 0 && c == '\\') {
                        res |= Check.BackslashInPath; 
                    } 
                    if ((res & Check.DotSlashAttn) == 0 && i+1 != end && (str[i+1] == '/' || str[i+1] == '\\' )) {
                        res |= Check.DotSlashAttn; 
                    }
                }
                else if (c == '.') {
                    if ((res & Check.DotSlashAttn) == 0 && i+1 == end || str[i+1] == '.' || str[i+1] == '/' || str[i+1] == '\\' || str[i+1] == '?' || str[i+1] == '#') { 
                        res |= Check.DotSlashAttn;
                    } 
                } 
                else if (!needsEscaping && ((c <= '"' && c != '!') || (c >= '[' && c <= '^') || c == '>' || c == '<' || c == '`')) {
                    needsEscaping = true; 
                }
                else if (c == '%') {
                    if (!foundEscaping) foundEscaping = true;
                    //try unescape a byte hex escaping 
                    if (i+2 < end && (c = EscapedAscii(str[i+1], str[i+2])) != c_DummyChar)
                    { 
                        if (c == '.' || c == '/' || c == '\\') { 
                            res |= Check.DotSlashEscaped;
                        } 
                        i+=2;
                        continue;
                    }
                    // otherwise we follow to non escaped case 
                    if (!needsEscaping) {
                        needsEscaping = true; 
                    } 
                }
            } 

            if (foundEscaping) {
                if (!needsEscaping) {
                    res |= Check.EscapedCanonical; 
                }
            } 
            else { 
                res |= Check.DisplayCanonical;
                if (!needsEscaping) { 
                    res |= Check.EscapedCanonical;
                }
            }
            idx = i; 
            return res;
        } 
 
        //
        // Returns the escaped and canonicalized path string 
        // the passed array must be long enough to hold at least
        // canonical unescaped path representation (allocated by the caller)
        //
        private unsafe char[] GetCanonicalPath(char[] dest, ref int pos, UriFormat formatAs) 
        {
 
            if (InFact(Flags.FirstSlashAbsent)) 
                dest[pos++] = '/';
 
            if (m_Info.Offset.Path == m_Info.Offset.Query)
                return dest;

            int end = pos; 

            int dosPathIdx = SecuredPathIndex; 
 
            // Note that unescaping and then escapig back is not transitive hence not safe.
            // We are vulnerable due to the way the UserEscaped flag is processed (see NDPWhidbey#10612 bug). 
            // Try to unescape only needed chars.
            if (formatAs == UriFormat.UriEscaped)
            {
                if (InFact(Flags.ShouldBeCompressed)) 
                {
                    m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path); 
                    end += (m_Info.Offset.Query - m_Info.Offset.Path); 

                    // If the path was found as needed compression and contains escaped characters, unescape only interesting characters (safe) 

                    if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) && !IsImplicitFile)
                    {
                        fixed (char* pdest = dest) 
                            UnescapeOnly(pdest, pos, ref end, '.', '/', m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)? '\\': c_DummyChar) ;
                    } 
                } 
                else
                { 
                    //
                    if (InFact(Flags.E_PathNotCanonical) && NotAny(Flags.UserEscaped)) {
                        string str = m_String;
 
                        // Check on not canonical disk designation like C|\, should be rare, rare case
                        if (dosPathIdx != 0 && str[dosPathIdx + m_Info.Offset.Path -1] == '|') 
                        { 
                            str = str.Remove(dosPathIdx + m_Info.Offset.Path -1, 1);
                            str = str.Insert(dosPathIdx + m_Info.Offset.Path -1, ":"); 
                        }
                        dest = EscapeString(str, m_Info.Offset.Path, m_Info.Offset.Query, dest, ref end, true, '?', '#', IsImplicitFile? c_DummyChar: '%');
                    }
                    else { 
                        m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path);
                        end += (m_Info.Offset.Query - m_Info.Offset.Path); 
                    } 
                }
            } 
            else
            {
                m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path);
                end += (m_Info.Offset.Query - m_Info.Offset.Path); 

                if (InFact(Flags.ShouldBeCompressed)) 
                { 
                    // If the path was found as needed compression and contains escaped characters, unescape only interesting characters (safe)
 
                    if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) && !IsImplicitFile)
                    {
                        fixed (char* pdest = dest)
                            UnescapeOnly(pdest, pos, ref end, '.', '/', m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)? '\\': c_DummyChar) ; 
                    }
                } 
            } 

            // Here we already got output data as copied into dest array 
            // We just may need more processing of that data

            //
            // if this URI is using 'non-proprietary' disk drive designation, convert to MS-style 
            //
            // (path is already  >= 3 chars if recognized as a DOS-like) 
            // 
            if (dosPathIdx != 0 && dest[dosPathIdx + pos - 1] == '|')
                dest[dosPathIdx + pos - 1] = ':'; 

            if (InFact(Flags.ShouldBeCompressed))
            {
                // It will also convert back slashes if needed 
                dest = Compress(dest, (ushort)(pos + dosPathIdx), ref end, m_Syntax);
                if (dest[pos] == '\\') 
                    dest[pos] = '/'; 

                // Escape path if requested and found as not fully escaped 
                if (formatAs == UriFormat.UriEscaped && NotAny(Flags.UserEscaped) && InFact(Flags.E_PathNotCanonical)) {
                    //
                    string srcString = new string(dest, pos, end-pos);
                    dest = EscapeString(srcString ,  0, end-pos, dest, ref pos, true, '?', '#', IsImplicitFile? c_DummyChar: '%'); 
                    end = pos;
                } 
            } 
            else if (m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes) && InFact(Flags.BackslashInPath))
            { 
                for (int i = pos; i < end; ++i)
                    if (dest[i] == '\\') dest[i] = '/';
            }
 
            if (formatAs != UriFormat.UriEscaped && InFact(Flags.PathNotCanonical))
            { 
                UnescapeMode mode; 
                if (InFact(Flags.PathNotCanonical))
                { 
                    switch (formatAs)
                    {
                    case V1ToStringUnescape:
 
                        mode = (InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag;
                        if (IsImplicitFile) 
                            mode &= ~UnescapeMode.Unescape; 
                        break;
 
                    case UriFormat.Unescaped:
                        mode = IsImplicitFile? UnescapeMode.CopyOnly : UnescapeMode.Unescape | UnescapeMode.UnescapeAll;
                        break;
 
                    default: // UriFormat.SafeUnescaped
 
                        mode = InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape; 
                        if (IsImplicitFile)
                            mode &= ~UnescapeMode.Unescape; 
                        break;
                    }
                }
                else { 
                    mode = UnescapeMode.CopyOnly;
                } 
 
                char[] dest1 = new char[dest.Length];
                Buffer.BlockCopy(dest, 0, dest1, 0, end<<1); 
                fixed (char *pdest = dest1)
                {
                    dest = UnescapeString(pdest, pos, end, dest, ref pos, '?', '#', c_DummyChar, mode, m_Syntax, false, false);
                } 
            }
            else 
            { 
                pos = end;
            } 

            return dest;
        }
 
        // works only with ASCII characters, used to partially unescape path before compressing
        private unsafe static void UnescapeOnly(char* pch, int start, ref int end, char ch1, char ch2, char ch3) { 
            if (end - start < 3) { 
                //no chance that something is escaped
                return; 
            }

            char *pend = pch + end-2;
            pch += start; 
            char *pnew = null;
 
            over: 

            // Just looking for a interested escaped char 
            if (pch >= pend)    goto done;
            if(*pch++ != '%')   goto over;

            char ch = EscapedAscii(*pch++, *pch++); 
            if (!(ch == ch1 || ch == ch2 || ch == ch3)) goto over;
 
            // Here we found something and now start copying the scanned chars 
            pnew = pch-2;
            *(pnew-1) = ch; 

            over_new:

            if (pch >= pend)                goto done; 
            if((*pnew++ = *pch++) != '%')   goto over_new;
 
            ch = EscapedAscii((*pnew++ = *pch++), (*pnew++ = *pch++)); 
            if (!(ch == ch1 || ch == ch2 || ch == ch3)) {
                goto over_new; 
            }

            pnew -= 2;
            *(pnew-1) = ch; 

            goto over_new; 
 
            done:
            pend+=2; 

            if (pnew == null) {
                //nothing was found
                return; 
            }
 
            //the tail may be already processed 
            if(pch == pend) {
                end -= (int) (pch-pnew); 
                return;
            }

            *pnew++ = *pch++; 
            if(pch == pend) {
                end -= (int) (pch-pnew); 
                return; 
            }
            *pnew++ = *pch++; 
            end -= (int) (pch-pnew);
        }
        //
        // 
        //
        // 
        // 
        private static char EscapedAscii(char digit, char next) {
            if (!(((digit >= '0') && (digit <= '9')) 
                || ((digit >= 'A') && (digit <= 'F'))
                || ((digit >= 'a') && (digit <= 'f')))) {
                return c_DummyChar;
            } 

            int res= (digit <= '9') 
                ? ((int)digit - (int)'0') 
                : (((digit <= 'F')
                ? ((int)digit - (int)'A') 
                : ((int)digit - (int)'a'))
                   + 10);

            if (!(((next >= '0') && (next <= '9')) 
                || ((next >= 'A') && (next <= 'F'))
                || ((next >= 'a') && (next <= 'f')))) { 
                return c_DummyChar; 
            }
 
            return  (char) ((res << 4) + ((next <= '9')
                    ? ((int)next - (int)'0')
                    : (((next <= 'F')
                        ? ((int)next - (int)'A') 
                        : ((int)next - (int)'a'))
                       + 10))); 
        } 

 
        //
        //
        // This will compress any "\" "/../" "/./" "///" "/..../" /XXX.../, etc found in the input
        // 
        // The passed syntax controls whether to use agressive compression or the one specified in RFC 2396
        // 
        // 
        private static char[] Compress(char[] dest, ushort start, ref int destLength, UriParser syntax)
        { 
            ushort  slashCount      = 0;
            ushort  lastSlash       = 0;
            ushort  dotCount        = 0;
            ushort  removeSegments  = 0; 

            unchecked { 
                //ushort i == -1 and start == -1 overflow is ok here 
                ushort  i = (ushort)((ushort)destLength - (ushort)1);
                start = (ushort)(start-1); 

                for (; i != start ; --i) {
                    char ch = dest[i];
                    if (ch == '\\' && syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)) { 
                        dest[i] = ch = '/';
                    } 
 
                    //
                    // compress multiple '/' for file URI 
                    //
                    if (ch == '/') {
                        ++slashCount;
                        /* 
                        QFE 4390 - remove the compression of multiple slashes to a single slash
                        if (slashCount > 1) { 
                            continue; 
                        }
 			*/ 
                    }
                    else {
                        if (slashCount > 1) {
                            /* 
                            QFE 4390 - remove the compression of multiple slashes to a single slash
                            if (syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) 
                            { 
                                // We saw > 1 slashes so remove all but the last one
                                // dest.Remove(i+1, slashCount -1); 
                                Buffer.BlockCopy(dest, (i + slashCount) << 1, dest, (i + 1) << 1, (destLength - (i + slashCount)) << 1);
                                destLength -= (slashCount - 1);
                            }
			    */ 
                            // else preserve repeated slashes
                            lastSlash = (ushort)(i + 1); 
                        } 
                        slashCount = 0;
                    } 

                    if (ch == '.') {
                        ++dotCount;
                        continue; 
                    }
                    else if (dotCount != 0) { 
 
                        bool skipSegment = syntax.NotAny(UriSyntaxFlags.CanonicalizeAsFilePath) && (dotCount > 2 || ch != '/' || i == start);
 
                        //
                        // Cases:
                        // /./ or /...[....]/   = remove this segment as invalid
                        // /../                 = remove this segment, mark next for removal 
                        // /....x               = DO NOT TOUCH, leave as is
                        // x.../                = remove trailing dots 
                        // 
                        if (!skipSegment && ch == '/') {
                            if (lastSlash == i+dotCount+1 || (lastSlash == 0 && i+dotCount+1 == destLength)) { 
                                //
                                //  /./ or  /...[....]/ or /. or  /...[....]
                                //  Remove this segment (note that /.../ is an invalid segment, remove it since
                                //  we should not throw at this parsing point. 
                                //
                                // just reusing a variable slot we perform //dest.Remove(i+1, dotCount + (lastSlash==0?0:1)); 
                                lastSlash = (ushort)(i + 1 + dotCount + (lastSlash==0?0:1)); 
                                Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1);
                                destLength -= (lastSlash-i-1); 

                                lastSlash = i;
                                if (dotCount == 2) {
                                    // 
                                    // We have 2 dots in between like /../ or /..,
                                    // Mark next segment for removal and remove this /../ or /.. 
                                    // 
                                    ++removeSegments;
                                } 
                                dotCount = 0;
                                continue;
                            }
                        } 
                        // Note if removeSegments!=0, then ignore and remove the whole segment later
                        else if (!skipSegment && removeSegments == 0 && (lastSlash == i+dotCount+1 || (lastSlash == 0 && i+dotCount+1 == destLength))) { 
                            // 
                            // x.../  or  x...
                            // remove trailing dots 
                            //
                            //
                            // just reusing a variable slot we perform //dest.Remove(i+1, dotCount);
                            dotCount = (ushort)(i + 1 + dotCount); 
                            Buffer.BlockCopy(dest, dotCount<<1, dest, (i+1)<<1, (destLength - dotCount)<<1);
                            destLength -= (dotCount-i-1); 
                            lastSlash = 0;  //the other dots in this segment will stay intact 
                            dotCount = 0;
                            continue; 
                        }
                        dotCount = 0;
                        //
                        // Here all other cases go such as 
                        // x.[..]y or /.[..]x or (/x.[...][/] && removeSegments !=0)
                    } 
 
                    //
                    // Now we may want to remove a segment because of previous /../ 
                    //
                    if (ch == '/') {
                        if (removeSegments  != 0) {
                            --removeSegments; 

                            // just reusing a variable slot we perform //dest.Remove(i+1, lastSlash - i); 
                            lastSlash = (ushort)(lastSlash + 1); 
                            Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1);
                            destLength -= (lastSlash-i-1); 
                        }
                    lastSlash = i;
                    }
                } 

               start = (ushort)((ushort)start + (ushort)1); 
            } //end of unchecked 

            if ((ushort)destLength > start && syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) 
            {
                if (slashCount > 1) {
		    /*
                    Buffer.BlockCopy(dest, lastSlash << 1, dest, start << 1, (destLength - lastSlash) << 1); 
                    destLength -= (slashCount - 1);
                    */ 
                    //QFE 4390 - Fall through for compat after not multiple slashes to a single slashl 
                }
                else if (removeSegments != 0 && dest[start] != '/') { 
                    //remove first not rooted segment
                    // dest.Remove(i+1, lastSlash - i);
                    lastSlash = (ushort)(lastSlash + 1);
                    Buffer.BlockCopy(dest, lastSlash<<1, dest, start<<1, (destLength - lastSlash)<<1); 
                    destLength -= lastSlash;
                } 
                else if (dotCount != 0) { 
                    // If final string starts with a segment looking like .[...]/ or .[...]
                    // then we remove this fisrt segment 
                    if (lastSlash == dotCount+1 || (lastSlash == 0 && dotCount + 1 == destLength)) {
                        //dest.Remove(0, dotCount + (lastSlash==0?0:1));
                        dotCount = (ushort)(dotCount + (lastSlash==0?0:1));
                        Buffer.BlockCopy(dest, dotCount<<1, dest, start<<1, (destLength - dotCount)<<1); 
                        destLength -= dotCount;
                    } 
                } 
            }
            return dest; 
        }
        //
        //
        // 
        //
        private static readonly char[] HexUpperChars = { 
                                   '0', '1', '2', '3', '4', '5', '6', '7', 
                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
                                   }; 

        //used by DigestClient
        internal static readonly char[] HexLowerChars = {
                                   '0', '1', '2', '3', '4', '5', '6', '7', 
                                   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
                                   }; 
 

        // 
        //
        //
        //
        private static void EscapeAsciiChar(char ch, char[] to, ref int pos) { 
            to[pos++] = '%';
            to[pos++] = HexUpperChars[(ch & 0xf0) >> 4]; 
            to[pos++] = HexUpperChars[ch & 0xf]; 
        }
 
        internal static int CalculateCaseInsensitiveHashCode(string text)
        {
            return StringComparer.InvariantCultureIgnoreCase.GetHashCode(text);
        } 
        //
        // CombineUri 
        // 
        //  Given 2 URI strings, combine them into a single resultant URI string
        // 
        // Inputs:
        //    basePart
        //      Base URI to combine with
        // 
        //    relativePart
        //      String expected to be relative URI 
        // 
        // Assumes:
        //   is in canonic form 
        //
        // Returns:
        //  Resulting combined URI string
        // 
        private static string CombineUri(Uri basePart, string relativePart, UriFormat uriFormat) {
           //NB: relativePart is ensured as not empty by the caller 
           //    Another assumption is that basePart is an AbsoluteUri 

           // This method was not optimized for efficiency 
           // Means a relative Uri ctor may be relatively slow plus it increases the footprint of the baseUri

           char c1 = relativePart[0];
 
#if !PLATFORM_UNIX
           //check a special case for the base as DOS path and a rooted relative string 
           if ( basePart.IsDosPath && 
               (c1 == '/' || c1 == '\\') &&
               (relativePart.Length == 1 || (relativePart[1] != '/' && relativePart[1] != '\\'))) 
           {
               // take relative part appended to the base string after the drive letter
               int idx = basePart.OriginalString.IndexOf(':');
               if (basePart.IsImplicitFile) { 
                   return basePart.OriginalString.Substring(0, idx+1 ) + relativePart;
               } 
               // The basePart has explicit scheme (could be not file:), take the DOS drive ':' position 
               idx = basePart.OriginalString.IndexOf(':', idx+1);
               return basePart.OriginalString.Substring(0, idx+1 ) + relativePart; 
           }
#endif // !PLATFORM_UNIX

           // Check special case for Unc or absolute path in relativePart when base is FILE 
           if (StaticIsFile(basePart.Syntax))
           { 
 
                if (c1 == '\\' || c1 == '/') {
 
                    if(relativePart.Length >= 2 && (relativePart[1] == '\\' || relativePart[1] == '/')) {
                        //Assuming relative is a Unc path and base is a file uri.
                        return basePart.IsImplicitFile? relativePart: "file:" + relativePart;
                    } 

                    // here we got an absolute path in relativePart, 
                    // For compatibility with V1.0 parser we restrict the compression scope to Unc Share, i.e. \\host\share\ 
                    if (basePart.IsUnc) {
                        string share = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped); 
                        for (int i = 1; i < share.Length; ++i) {
                            if (share[i] == '/') {
                                share = share.Substring(0, i);
                                break; 
                            }
                        } 
                        if (basePart.IsImplicitFile) { 
                            return  @"\\"
                                    + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped) 
                                    + share
                                    + relativePart;
                        }
                        return  "file://" 
                                + basePart.GetParts(UriComponents.Host, uriFormat)
                                + share 
                                + relativePart; 

                    } 
                    // It's not obvious but we've checked (for this relativePart format) that baseUti is nor UNC nor DOS path
                    //
                    // Means base is a Unix style path and, btw, IsImplicitFile cannot be the case either
                    return "file://" + relativePart; 
               }
           } 
 
           // If we are here we did not recognize absolute DOS/UNC path for a file: base uri
           // Note that DOS path may still happen in the relativePart and if so it may override the base uri scheme. 

           bool convBackSlashes =  basePart.Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes);

           string left = null; 

           // check for network or local absolute path 
           if (c1 == '/' || (c1 == '\\' && convBackSlashes)) { 
               if (relativePart.Length >= 2 && relativePart[1] == '/') {
                   // got an authority in relative path and the base scheme is not file (checked) 
                   return basePart.Scheme + ':' + relativePart;
               }

               // Got absolute relative path, and the base is nor FILE nor a DOS path (checked at the method start) 
               if (basePart.HostType == Flags.IPv6HostType) {
                   left =  basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat) 
                                    + '[' + basePart.DnsSafeHost + ']' 
                                    + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat);
               } 
               else {
                   left =  basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat);
               }
               //VsWhidbey#241426 
               if (convBackSlashes && c1 == '\\')
                   relativePart = '/' + relativePart.Substring(1); 
 
               return left + relativePart;
           } 

           // Here we got a relative path or just a query+[fragment]
           // Need to run path Compression because this is how relative Uri combining works
 
           // Take the base part path up to and including the last slash
           left = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, basePart.IsImplicitFile? UriFormat.Unescaped: uriFormat); 
           int length = left.Length; 
           char[] path = new char[length + relativePart.Length];
 
           if (length > 0) {
               left.CopyTo(0, path, 0, length);
               while(length > 0) {
                   if (path[--length] == '/') { 
                       ++length;
                       break; 
                   } 
               }
           } 

           //Append relative path to the result
           relativePart.CopyTo(0, path, length, relativePart.Length);
 
           // Split relative on path and extra (for compression)
           c1 = basePart.Syntax.InFact(UriSyntaxFlags.MayHaveQuery)? '?': c_DummyChar; 
 
           // The  implcit file check is to avoid a fragment in the implicit file combined uri.
           // The behavior change request is tracked vis VsWhidbey#261387 ans that was approved through VsWhidbey#266417. 
           char c2 = (!basePart.IsImplicitFile && basePart.Syntax.InFact(UriSyntaxFlags.MayHaveFragment))? '#': c_DummyChar;
           string extra = String.Empty;

           // assuming c_DummyChar may not happen in an unicode uri string 
           if (!(c1 == c_DummyChar && c2 == c_DummyChar)) {
               int i=0; 
               for (;i < relativePart.Length; ++i) { 
                   if (path[length + i] == c1 || path[length + i] == c2) {
                       break; 
                   }
               }
               if (i == 0) {
                   extra = relativePart; 
               }
               else if (i < relativePart.Length) { 
                   extra = relativePart.Substring(i); 
               }
               length += i; 
           }
           else {
               length += relativePart.Length;
           } 

           // Take the base part up to the path 
           if (basePart.HostType == Flags.IPv6HostType) { 
               if (basePart.IsImplicitFile) {
                   left =  @"\\[" + basePart.DnsSafeHost + ']'; 
               }
               else {
                   left =  basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat)
                           + '[' + basePart.DnsSafeHost + ']' 
                           + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat);
               } 
           } 
           else {
               if (basePart.IsImplicitFile) { 
#if !PLATFORM_UNIX
                   if (basePart.IsDosPath) {
                       // The FILE DOS path comes as /c:/path, we have to exclude first 3 chars from compression
                       path = Compress(path, 3, ref length, basePart.Syntax); 
                       return new string(path, 1, length-1) + extra;
                   } 
                   else { 
                       left =  @"\\" + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped);
                   } 
#else
                   left =  basePart.GetParts(UriComponents.Host, UriFormat.Unescaped);
#endif // !PLATFORM_UNIX
 
               }
               else { 
                   left =  basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat); 
               }
           } 
           //compress the path
           path = Compress(path, basePart.SecuredPathIndex, ref length, basePart.Syntax);
           return left + new string(path, 0, length) + extra;
        } 

        // 
        // PathDifference 
        //
        //  Performs the relative path calculation for MakeRelative() 
        //
        // Inputs:
        //    path1
        //    path2 
        //      Paths for which we calculate the difference
        // 
        //    compareCase 
        //      False if we consider characters that differ only in case to be
        //      equal 
        //
        // Returns:
        //  A string which is the relative path difference between  and
        //   such that if  and the calculated difference are used 
        //  as arguments to Combine(),  is returned
        // 
        // Throws: 
        //  Nothing
        // 
        private static string PathDifference(string path1, string path2, bool compareCase) {

            int i;
            int si = -1; 

            for (i = 0; (i < path1.Length) && (i < path2.Length); ++i) { 
                if ((path1[i] != path2[i]) && (compareCase || (Char.ToLower(path1[i], CultureInfo.InvariantCulture) != Char.ToLower(path2[i], CultureInfo.InvariantCulture)))) 
                {
                    break; 

                } else if (path1[i] == '/') {
                    si = i;
                } 
            }
 
            if (i == 0) { 
                return path2;
            } 
            if ((i == path1.Length) && (i == path2.Length)) {
                return String.Empty;
            }
 
            StringBuilder relPath = new StringBuilder();
 
            for (; i < path1.Length; ++i) { 
                if (path1[i] == '/') {
                    relPath.Append("../"); 
                }
            }
            return relPath.ToString() + path2.Substring(si + 1);
        } 

        //Used by Uribuilder 
        internal bool HasAuthority { 
            get {
                return InFact(Flags.AuthorityFound); 
            }
        }

        private static readonly char[] _WSchars = new char[] {' ', '\n', '\r', '\t'}; 
        private static bool IsLWS(char ch) {
 
            return (ch <= ' ') && (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); 
        }
 
        //Only consider ASCII characters
        private static bool IsAsciiLetter(char character) {

            return (character >= 'a' && character <= 'z') || 
                   (character >= 'A' && character <= 'Z');
        } 
 
        private static bool IsAsciiLetterOrDigit(char character) {
            return IsAsciiLetter(character) || (character >= '0' && character <= '9'); 
        }


        // 
        // Is this a gen delim char from RFC 3986
        // 
        internal static bool IsGenDelim(char ch) 
        {
            return (ch == ':' || ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@'); 
        }

        //
        // Is this a Bidirectional control char.. These get stripped 
        //
        internal static bool IsBidiControlCharacter(char ch) 
        { 
            return (ch == '\u200E' /*LRM*/ || ch == '\u200F' /*RLM*/ || ch == '\u202A' /*LRE*/ ||
                    ch == '\u202B' /*RLE*/ || ch == '\u202C' /*PDF*/ || ch == '\u202D' /*LRO*/ || 
                    ch == '\u202E' /*RLO*/);
        }

        // 
        // Strip Bidirectional control charcters from this string
        // 
        internal static unsafe string StripBidiControlCharacter(char* strToClean, int start, int length) 
        {
            if (length <= 0) return ""; 

            char [] cleanStr = new char[length];
            int count = 0;
            for (int i = 0; i < length; ++i){ 
                char c = strToClean[start + i];
                if (c < '\u200E' || c > '\u202E' || !IsBidiControlCharacter(c)){ 
                    cleanStr[count++] = c; 
                }
            } 
            return new string(cleanStr, 0, count);
        }

        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Parse() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to an unconstructed Uri instance. 
            // It does not make any sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Canonicalize() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to supressing of a path compression 
            // It does not make much sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void Escape() 
        { 
            // [....] cr: In V1-Everett this method if suppressed by the derived class
            // would lead to the same effect as dontEscape=true. 
            // It does not make much sense and violates Fxcop on calling a virtual method in the ctor.
            // Should be deprecated and removed asap.
        }
        // 
        // Unescape
        // 
        //  Convert any escape sequences in . Escape sequences can be 
        //  hex encoded reserved characters (e.g. %40 == '@') or hex encoded
        //  UTF-8 sequences (e.g. %C4%D2 == 'Latin capital Ligature Ij') 
        //
        /// 
        [Obsolete("The method has been deprecated. Please use GetComponents() or static UnescapeDataString() to unescape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual string Unescape(string path) { 

            // [....] cr: This method is dangerous since it gives path unescaping control 
            // to the derived class without any permission demand. 
            // Should be deprecated and removed asap.
 
            char[] dest = new char[path.Length];
            int count = 0;
            dest = UnescapeString(path, 0, path.Length, dest, ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll, null, false, true);
            return new string(dest, 0, count); 
        }
 
        [Obsolete("The method has been deprecated. Please use GetComponents() or static EscapeUriString() to escape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")] 
        protected static string EscapeString(string str) {
 
            // [....] cr: This method just does not make sense sa protected
            // It should go public static asap

            if ((object)str == null) { 
                return string.Empty;
            } 
 
            int destStart = 0;
            char[] dest = EscapeString(str, 0, str.Length, null, ref destStart, true, '?', '#', '%'); 
            if ((object)dest == null)
                return str;
            return new string(dest, 0, destStart);
        } 

        // 
        // CheckSecurity 
        //
        //  Check for any invalid or problematic character sequences 
        //
        /// 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual void CheckSecurity()  { 

            // [....] cr: This method just does not make sense 
            // Should be deprecated and removed asap. 

            if (Scheme == "telnet") { 

                //
                // remove everything after ';' for telnet
                // 

            } 
        } 

        // 
        // IsReservedCharacter
        //
        //  Determine whether a character is part of the reserved set
        // 
        // Returns:
        //  true if  is reserved else false 
        // 
        /// 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] 
        protected virtual bool IsReservedCharacter(char character) {

            // [....] cr: This method just does not make sense as virtual protected
            // It should go public static asap 

            return (character == ';') 
                || (character == '/') 
                || (character == ':')
                || (character == '@')   // OK FS char 
                || (character == '&')
                || (character == '=')
                || (character == '+')   // OK FS char
                || (character == '$')   // OK FS char 
                || (character == ',')
                ; 
        } 

        // 
        // IsExcludedCharacter
        //
        //  Determine if a character should be exluded from a URI and therefore be
        //  escaped 
        //
        // Returns: 
        //  true if  should be escaped else false 
        //
        ///  
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected static bool IsExcludedCharacter(char character) {

            // [....] cr: This method just does not make sense sa protected 
            // It should go public static asap
 
            // 
            // the excluded characters...
            // 

            return (character <= 0x20)
                || (character >= 0x7f)
                || (character == '<') 
                || (character == '>')
                || (character == '#') 
                || (character == '%') 
                || (character == '"')
 
                //
                // the 'unwise' characters...
                //
 
                || (character == '{')
                || (character == '}') 
                || (character == '|') 
                || (character == '\\')
                || (character == '^') 
                || (character == '[')
                || (character == ']')
                || (character == '`')
                ; 
        }
 
        // 
        // IsBadFileSystemCharacter
        // 
        //  Determine whether a character would be an invalid character if used in
        //  a file system name. Note, this is really based on NTFS rules
        //
        // Returns: 
        //  true if  would be a treated as a bad file system character
        //  else false 
        // 
        [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")]
        protected virtual bool IsBadFileSystemCharacter(char character) { 

            // [....] cr: This method just does not make sense sa protected virtual
            // It should go public static asap
 
            return (character < 0x20)
                || (character == ';') 
                || (character == '/') 
                || (character == '?')
                || (character == ':') 
                || (character == '&')
                || (character == '=')
                || (character == ',')
                || (character == '*') 
                || (character == '<')
                || (character == '>') 
                || (character == '"') 
                || (character == '|')
                || (character == '\\') 
                || (character == '^')
                ;
        }
 

    } // class Uri 
} // namespace System 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK