/System/System/Uri.cs
C# | 2543 lines | 2186 code | 167 blank | 190 comment | 459 complexity | 02dff9ea78601b7faea675060a1ee586 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
-
- using System.ComponentModel;
- using System.IO;
- using System.Net;
- //using System.Runtime.Serialization;
- using System.Text;
- using System.Collections;
- using System.Collections.Generic;
- using System.Globalization;
-
- //
- // Disable warnings on Obsolete methods being used
- //
- #pragma warning disable 612
-
- namespace System
- {
-
- //[Serializable]
- // [TypeConverter(typeof(UriTypeConverter))]
- public class Uri //: ISerializable
- {
- // NOTES:
- // o scheme excludes the scheme delimiter
- // o port is -1 to indicate no port is defined
- // o path is empty or starts with / when scheme delimiter == "://"
- // o query is empty or starts with ? char, escaped.
- // o fragment is empty or starts with # char, unescaped.
- // o all class variables are in escaped format when they are escapable,
- // except cachedToString.
- // o UNC is supported, as starts with "\\" for windows,
- // or "//" with unix.
-
- private bool isUnixFilePath;
- private string source;
- private string scheme = String.Empty;
- private string host = String.Empty;
- private int port = -1;
- private string path = String.Empty;
- private string query = String.Empty;
- private string fragment = String.Empty;
- private string userinfo;
- private bool isUnc;
- private bool isOpaquePart;
- private bool isAbsoluteUri = true;
- private long scope_id;
-
- private List<string> segments;
-
- private bool userEscaped;
- private string cachedAbsoluteUri;
- private string cachedToString;
- private string cachedLocalPath;
- private int cachedHashCode;
-
- private static readonly string hexUpperChars = "0123456789ABCDEF";
- private static readonly string[] Empty = new string[0];
- private static bool isWin32 = (Path.DirectorySeparatorChar == '\\');
-
-
- // Fields
-
- public static readonly string SchemeDelimiter = "://";
- public static readonly string UriSchemeFile = "file";
- public static readonly string UriSchemeFtp = "ftp";
- public static readonly string UriSchemeGopher = "gopher";
- public static readonly string UriSchemeHttp = "http";
- public static readonly string UriSchemeHttps = "https";
- public static readonly string UriSchemeMailto = "mailto";
- public static readonly string UriSchemeNews = "news";
- public static readonly string UriSchemeNntp = "nntp";
- public static readonly string UriSchemeNetPipe = "net.pipe";
- public static readonly string UriSchemeNetTcp = "net.tcp";
-
- // Constructors
-
- #if MOONLIGHT
- public Uri (string uriString) : this (uriString, UriKind.Absolute)
- {
- }
- #else
- public Uri(string uriString)
- : this(uriString, false)
- {
- }
- #endif
- //protected Uri(SerializationInfo serializationInfo, StreamingContext streamingContext)
- //{
- // string uri = serializationInfo.GetString("AbsoluteUri");
- // if (uri.Length > 0)
- // {
- // source = uri;
- // ParseUri(UriKind.Absolute);
- // }
- // else
- // {
- // uri = serializationInfo.GetString("RelativeUri");
- // if (uri.Length > 0)
- // {
- // source = uri;
- // ParseUri(UriKind.Relative);
- // }
- // else
- // {
- // throw new ArgumentException("Uri string was null or empty.");
- // }
- // }
- //}
-
- public Uri(string uriString, UriKind uriKind)
- {
- source = uriString;
- ParseUri(uriKind);
-
- switch (uriKind)
- {
- case UriKind.Absolute:
- if (!IsAbsoluteUri)
- throw new UriFormatException("Invalid URI: The format of the URI could not be "
- + "determined.");
- break;
- case UriKind.Relative:
- if (IsAbsoluteUri)
- throw new UriFormatException("Invalid URI: The format of the URI could not be "
- + "determined because the parameter 'uriString' represents an absolute URI.");
- break;
- case UriKind.RelativeOrAbsolute:
- break;
- default:
- string msg = String.Format("Invalid UriKind value '{0}'.", uriKind);
- throw new ArgumentException(msg);
- }
- }
-
- //
- // An exception-less constructor, returns success
- // condition on the out parameter `success'.
- //
- Uri(string uriString, UriKind uriKind, out bool success)
- {
- if (uriString == null)
- {
- success = false;
- return;
- }
-
- if (uriKind != UriKind.RelativeOrAbsolute &&
- uriKind != UriKind.Absolute &&
- uriKind != UriKind.Relative)
- {
- string msg = String.Format("Invalid UriKind value '{0}'.", uriKind);
- throw new ArgumentException(msg);
- }
-
- source = uriString;
- if (ParseNoExceptions(uriKind, uriString) != null)
- success = false;
- else
- {
- success = true;
-
- switch (uriKind)
- {
- case UriKind.Absolute:
- if (!IsAbsoluteUri)
- success = false;
- break;
- case UriKind.Relative:
- if (IsAbsoluteUri)
- success = false;
- break;
- case UriKind.RelativeOrAbsolute:
- break;
- default:
- success = false;
- break;
- }
- }
- }
-
- public Uri(Uri baseUri, Uri relativeUri)
- {
- Merge(baseUri, relativeUri == null ? String.Empty : relativeUri.OriginalString);
- // FIXME: this should call UriParser.Resolve
- }
-
- // note: doc says that dontEscape is always false but tests show otherwise
- //[Obsolete]
- public Uri(string uriString, bool dontEscape)
- {
- userEscaped = dontEscape;
- source = uriString;
- ParseUri(UriKind.Absolute);
- if (!isAbsoluteUri)
- throw new UriFormatException("Invalid URI: The format of the URI could not be "
- + "determined: " + uriString);
- }
-
- public Uri(Uri baseUri, string relativeUri)
- {
- Merge(baseUri, relativeUri);
- // FIXME: this should call UriParser.Resolve
- }
-
- [Obsolete("dontEscape is always false")]
- public Uri(Uri baseUri, string relativeUri, bool dontEscape)
- {
- userEscaped = dontEscape;
- Merge(baseUri, relativeUri);
- }
-
- private void Merge(Uri baseUri, string relativeUri)
- {
- if (baseUri == null)
- throw new ArgumentNullException("baseUri");
- if (!baseUri.IsAbsoluteUri)
- throw new ArgumentOutOfRangeException("baseUri");
- if (relativeUri == null)
- relativeUri = String.Empty;
-
- // See RFC 2396 Par 5.2 and Appendix C
-
- // Check Windows UNC (for // it is scheme/host separator)
- if (relativeUri.Length >= 2 && relativeUri[0] == '\\' && relativeUri[1] == '\\')
- {
- source = relativeUri;
- ParseUri(UriKind.Absolute);
- return;
- }
-
- int pos = relativeUri.IndexOf(':');
- if (pos != -1)
- {
-
- int pos2 = relativeUri.IndexOfAny(new char[] { '/', '\\', '?' });
-
- // pos2 < 0 ... e.g. mailto
- // pos2 > pos ... to block ':' in query part
- if (pos2 > pos || pos2 < 0)
- {
- // in some cases, it is equivanent to new Uri (relativeUri, dontEscape):
- // 1) when the URI scheme in the
- // relative path is different from that
- // of the baseUri, or
- // 2) the URI scheme is non-standard
- // ones (non-standard URIs are always
- // treated as absolute here), or
- // 3) the relative URI path is absolute.
- if (String.CompareOrdinal(baseUri.Scheme, 0, relativeUri, 0, pos) != 0 ||
- !IsPredefinedScheme(baseUri.Scheme) ||
- (relativeUri.Length > pos + 1 && relativeUri[pos + 1] == '/'))
- {
- Uri tmp = null;
- if (Uri.TryCreate(relativeUri, UriKind.Absolute, out tmp))
- {
- source = relativeUri;
- ParseUri(UriKind.Absolute);
- return;
- }
- else if (pos == 1)
- {
- // special case as this looks like a windows path
- string msg = ParseAsWindowsAbsoluteFilePath(relativeUri);
- if (msg != null)
- throw new UriFormatException(msg);
- }
- // otherwise continue with 'full' relativeUri
- }
- else
- relativeUri = relativeUri.Substring(pos + 1);
- }
- }
-
- this.scheme = baseUri.scheme;
- this.host = baseUri.host;
- this.port = baseUri.port;
- this.userinfo = baseUri.userinfo;
- this.isUnc = baseUri.isUnc;
- this.isUnixFilePath = baseUri.isUnixFilePath;
- this.isOpaquePart = baseUri.isOpaquePart;
-
- if (relativeUri.Length == 0)
- {
- this.path = baseUri.path;
- this.query = baseUri.query;
- this.fragment = baseUri.fragment;
- return;
- }
-
- // 8 fragment
- // Note that in relative constructor, file URI cannot handle '#' as a filename character, but just regarded as a fragment identifier.
- string original_fragment = String.Empty;
- pos = relativeUri.IndexOf('#');
- if (pos != -1)
- {
- original_fragment = relativeUri.Substring(pos);
- if (userEscaped)
- fragment = original_fragment;
- else
- fragment = "#" + EscapeString(relativeUri.Substring(pos + 1));
- relativeUri = pos == 0 ? String.Empty : relativeUri.Substring(0, pos);
- }
-
- bool consider_query = false;
-
- // 6 query
- pos = relativeUri.IndexOf('?');
- if (pos != -1)
- {
- query = relativeUri.Substring(pos);
- if (!userEscaped)
- query = EscapeString(query);
- #if !NET_4_0 && !MOONLIGHT && !MOBILE
- consider_query = query.Length > 0;
- #endif
- relativeUri = pos == 0 ? String.Empty : relativeUri.Substring(0, pos);
- }
- else if (relativeUri.Length == 0)
- {
- // if there is no relative path then we keep the Query and Fragment from the absolute
- query = baseUri.query;
- }
-
- if (relativeUri.Length > 0 && relativeUri[0] == '/')
- {
- if (relativeUri.Length > 1 && relativeUri[1] == '/')
- {
- source = scheme + ':' + relativeUri;
- ParseUri(UriKind.Absolute);
- return;
- }
- else
- {
- path = relativeUri;
- if (!userEscaped)
- path = EscapeString(path);
- return;
- }
- }
-
- // par 5.2 step 6 a)
- path = baseUri.path;
- if ((relativeUri.Length > 0) || consider_query)
- {
- pos = path.LastIndexOf('/');
- if (pos >= 0)
- path = path.Substring(0, pos + 1);
- }
-
- if (relativeUri.Length == 0)
- {
- // when merging URI the OriginalString is not quite original
- source = GetLeftPart(UriPartial.Authority) + query + original_fragment;
- return;
- }
-
- // 6 b)
- path += relativeUri;
-
- // 6 c)
- int startIndex = 0;
- while (true)
- {
- pos = path.IndexOf("./", startIndex);
- if (pos == -1)
- break;
- if (pos == 0)
- path = path.Remove(0, 2);
- else if (path[pos - 1] != '.')
- path = path.Remove(pos, 2);
- else
- startIndex = pos + 1;
- }
-
- // 6 d)
- if (path.Length > 1 &&
- path[path.Length - 1] == '.' &&
- path[path.Length - 2] == '/')
- path = path.Remove(path.Length - 1, 1);
-
- // 6 e)
- startIndex = 0;
- while (true)
- {
- pos = path.IndexOf("/../", startIndex);
- if (pos == -1)
- break;
- if (pos == 0)
- {
- startIndex = 3;
- continue;
- }
- int pos2 = path.LastIndexOf('/', pos - 1);
- if (pos2 == -1)
- {
- startIndex = pos + 1;
- }
- else
- {
- if (path.Substring(pos2 + 1, pos - pos2 - 1) != "..")
- path = path.Remove(pos2 + 1, pos - pos2 + 3);
- else
- startIndex = pos + 1;
- }
- }
-
- // 6 f)
- if (path.Length > 3 && path.EndsWith("/.."))
- {
- pos = path.LastIndexOf('/', path.Length - 4);
- if (pos != -1)
- if (path.Substring(pos + 1, path.Length - pos - 4) != "..")
- path = path.Remove(pos + 1, path.Length - pos - 1);
- }
-
- // 6 g)
- while (path.StartsWith("/../"/*, StringComparison.Ordinal*/))
- path = path.Substring(3);
-
- if (!userEscaped)
- path = EscapeString(path);
-
- // when merging URI the OriginalString is not quite original
- source = GetLeftPart(UriPartial.Authority) + path + query + original_fragment;
- }
-
- // Properties
-
- public string AbsolutePath
- {
- get
- {
- EnsureAbsoluteUri();
- if (scheme == "mailto" || scheme == "file")
- // faster (mailto) and special (file) cases
- return path;
-
- if (path.Length == 0)
- {
- string start = scheme + SchemeDelimiter;
- if (path.StartsWith(start/*, StringComparison.Ordinal*/))
- return "/";
- else
- return String.Empty;
- }
- return path;
- }
- }
-
- public string AbsoluteUri
- {
- get
- {
- EnsureAbsoluteUri();
- if (cachedAbsoluteUri == null)
- {
- cachedAbsoluteUri = GetLeftPart(UriPartial.Path);
- if (query.Length > 0)
- cachedAbsoluteUri += query;
- if (fragment.Length > 0)
- cachedAbsoluteUri += fragment;
- }
- return cachedAbsoluteUri;
- }
- }
-
- public string Authority
- {
- get
- {
- EnsureAbsoluteUri();
- return (GetDefaultPort(Scheme) == port)
- ? host : host + ":" + port;
- }
- }
-
- public string Fragment
- {
- get
- {
- EnsureAbsoluteUri();
- return fragment;
- }
- }
-
- public string Host
- {
- get
- {
- EnsureAbsoluteUri();
- return host;
- }
- }
-
- public UriHostNameType HostNameType
- {
- get
- {
- EnsureAbsoluteUri();
- UriHostNameType ret = CheckHostName(Host);
- if (ret != UriHostNameType.Unknown)
- return ret;
-
- if (scheme == "mailto")
- return UriHostNameType.Basic;
- return (IsFile) ? UriHostNameType.Basic : ret;
- }
- }
-
- public bool IsDefaultPort
- {
- get
- {
- EnsureAbsoluteUri();
- return GetDefaultPort(Scheme) == port;
- }
- }
-
- public bool IsFile
- {
- get
- {
- EnsureAbsoluteUri();
- return (Scheme == UriSchemeFile);
- }
- }
-
- public bool IsLoopback
- {
- get
- {
- EnsureAbsoluteUri();
-
- if (Host.Length == 0)
- {
- return IsFile;
- }
-
- if (host == "loopback" || host == "localhost")
- return true;
-
- IPAddress result;
- if (IPAddress.TryParse(host, out result))
- if (IPAddress.Loopback.Equals(result))
- return true;
-
- /*IPv6Address result6;
- if (IPv6Address.TryParse(host, out result6))
- {
- if (IPv6Address.IsLoopback(result6))
- return true;
- }*/
-
- return false;
- }
- }
-
- public bool IsUnc
- {
- // rule: This should be true only if
- // - uri string starts from "\\", or
- // - uri string starts from "//" (Samba way)
- get
- {
- EnsureAbsoluteUri();
- return isUnc;
- }
- }
-
- private bool IsLocalIdenticalToAbsolutePath()
- {
- if (IsFile)
- return false;
-
- if ((scheme == Uri.UriSchemeNews) || (scheme == Uri.UriSchemeNntp) || (scheme == Uri.UriSchemeFtp))
- return false;
-
- return IsWellFormedOriginalString();
- }
-
- public string LocalPath
- {
- get
- {
- EnsureAbsoluteUri();
- if (cachedLocalPath != null)
- return cachedLocalPath;
-
- if (IsLocalIdenticalToAbsolutePath())
- {
- cachedLocalPath = Unescape(AbsolutePath);
- return cachedLocalPath;
- }
-
- if (!IsUnc)
- {
- string p = Unescape(path);
- bool windows = (path.Length > 3 && path[1] == ':' &&
- (path[2] == '\\' || path[2] == '/'));
-
- if (windows)
- cachedLocalPath = p.Replace('/', '\\');
- else
- cachedLocalPath = p;
- }
- else
- {
- // support *nix and W32 styles
- if (path.Length > 1 && path[1] == ':')
- cachedLocalPath = Unescape(path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
-
- // LAMESPEC: ok, now we cannot determine
- // if such URI like "file://foo/bar" is
- // Windows UNC or unix file path, so
- // they should be handled differently.
- else if (System.IO.Path.DirectorySeparatorChar == '\\')
- {
- string h = host;
- if (path.Length > 0)
- {
- if ((path.Length > 1) || (path[0] != '/'))
- {
- h += path.Replace('/', '\\');
- }
- }
- cachedLocalPath = "\\\\" + Unescape(h);
- }
- else
- cachedLocalPath = Unescape(path);
- }
- if (cachedLocalPath.Length == 0)
- cachedLocalPath = Path.DirectorySeparatorChar.ToString();
- return cachedLocalPath;
- }
- }
-
- public string PathAndQuery
- {
- get
- {
- EnsureAbsoluteUri();
- return path + Query;
- }
- }
-
- public int Port
- {
- get
- {
- EnsureAbsoluteUri();
- return port;
- }
- }
-
- public string Query
- {
- get
- {
- EnsureAbsoluteUri();
- return query;
- }
- }
-
- public string Scheme
- {
- get
- {
- EnsureAbsoluteUri();
- return scheme;
- }
- }
-
- public string[] Segments
- {
- get
- {
- EnsureAbsoluteUri();
-
- // return a (pre-allocated) empty array
- if (path.Length == 0)
- return Empty;
- // do not return the original array (since items can be changed)
- if (segments != null)
- return segments.ToArray();
-
- List<string> list = new List<string>();
- StringBuilder current = new StringBuilder();
- for (int i = 0; i < path.Length; i++)
- {
- switch (path[i])
- {
- case '/':
- case '\\':
- current.Append(path[i]);
- list.Add(current.ToString());
- current.Length = 0;
- break;
- case '%':
- if ((i < path.Length - 2) && (path[i + 1] == '5' && path[i + 2] == 'C'))
- {
- current.Append("%5C");
- list.Add(current.ToString());
- current.Length = 0;
- i += 2;
- }
- else
- {
- current.Append('%');
- }
- break;
- default:
- current.Append(path[i]);
- break;
- }
- }
-
- if (current.Length > 0)
- list.Add(current.ToString());
-
- if (IsFile && (list.Count > 0))
- {
- string first = list[0];
- if ((first.Length > 1) && (first[1] == ':'))
- {
- list.Insert(0, "/");
- }
- }
- segments = list;
- return segments.ToArray();
- }
- }
-
- public bool UserEscaped
- {
- get { return userEscaped; }
- }
-
- public string UserInfo
- {
- get
- {
- EnsureAbsoluteUri();
- return userinfo == null ? String.Empty : userinfo;
- }
- }
-
- public string DnsSafeHost
- {
- get
- {
- EnsureAbsoluteUri();
- string host = Host;
- /*if (HostNameType == UriHostNameType.IPv6)
- {
- host = Host.Substring(1, Host.Length - 2);
- if (scope_id != 0)
- host += "%" + scope_id.ToString();
- }*/
- return Unescape(host);
- }
- }
-
- #if NET_2_0
- public
- #else
- internal
- #endif
- bool IsAbsoluteUri
- {
- get { return isAbsoluteUri; }
- }
-
- // LAMESPEC: source field is supplied in such case that this
- // property makes sense. For such case that source field is
- // not supplied (i.e. .ctor(Uri, string), this property
- // makes no sense. To avoid silly regression it just returns
- // ToString() value now. See bug #78374.
- public string OriginalString
- {
- get { return source != null ? source : ToString(); }
- }
-
- // Methods
-
- public static UriHostNameType CheckHostName(string name)
- {
- if (name == null || name.Length == 0)
- return UriHostNameType.Unknown;
-
- if (IsIPv4Address(name))
- return UriHostNameType.IPv4;
-
- if (IsDomainAddress(name))
- return UriHostNameType.Dns;
-
- //IPv6Address addr;
- //if (IPv6Address.TryParse(name, out addr))
- // return UriHostNameType.IPv6;
-
- return UriHostNameType.Unknown;
- }
-
- internal static bool IsIPv4Address(string name)
- {
- string[] captures = name.Split(new char[] { '.' });
- if (captures.Length != 4)
- return false;
-
- for (int i = 0; i < 4; i++)
- {
- int length;
-
- length = captures[i].Length;
- if (length == 0)
- return false;
- uint number;
- if (!UInt32.TryParse(captures[i], out number))
- return false;
- if (number > 255)
- return false;
- }
- return true;
- }
-
- internal static bool IsDomainAddress(string name)
- {
- int len = name.Length;
-
- int count = 0;
- for (int i = 0; i < len; i++)
- {
- char c = name[i];
- if (count == 0)
- {
- if (!Char.IsLetterOrDigit(c))
- return false;
- }
- else if (c == '.')
- {
- // www..host.com is bad
- if (i + 1 < len && name[i + 1] == '.')
- return false;
- count = 0;
- }
- else if (!Char.IsLetterOrDigit(c) && c != '-' && c != '_')
- {
- return false;
- }
- if (++count == 64)
- return false;
- }
-
- return true;
- }
- #if !NET_2_1
-
- // [Obsolete("This method does nothing, it has been obsoleted")]
- protected virtual void Canonicalize()
- {
- //
- // This is flagged in the Microsoft documentation as used
- // internally, no longer in use, and Obsolete.
- //
- }
-
- // [MonoTODO("Find out what this should do")]
- //[Obsolete]
- protected virtual void CheckSecurity()
- {
- }
-
- #endif // NET_2_1
-
- // defined in RFC3986 as = ALPHA *( ALPHA / DIGIT / "+" / "-" / ".")
- public static bool CheckSchemeName(string schemeName)
- {
- if (schemeName == null || schemeName.Length == 0)
- return false;
-
- if (!IsAlpha(schemeName[0]))
- return false;
-
- int len = schemeName.Length;
- for (int i = 1; i < len; i++)
- {
- char c = schemeName[i];
- if (!Char.IsDigit(c) && !IsAlpha(c) && c != '.' && c != '+' && c != '-')
- return false;
- }
-
- return true;
- }
-
- private static bool IsAlpha(char c)
- {
- // as defined in rfc2234
- // %x41-5A / %x61-7A (A-Z / a-z)
- int i = (int)c;
- return (((i >= 0x41) && (i <= 0x5A)) || ((i >= 0x61) && (i <= 0x7A)));
- }
-
- public override bool Equals(object comparant)
- {
- if (comparant == null)
- return false;
-
- Uri uri = comparant as Uri;
- if ((object)uri == null)
- {
- string s = comparant as String;
- if (s == null)
- return false;
- uri = new Uri(s);
- }
-
- return InternalEquals(uri);
- }
-
- // Assumes: uri != null
- bool InternalEquals(Uri uri)
- {
- if (this.isAbsoluteUri != uri.isAbsoluteUri)
- return false;
- if (!this.isAbsoluteUri)
- return this.source == uri.source;
-
- CultureInfo inv = CultureInfo.InvariantCulture;
- return this.scheme.ToLower(inv) == uri.scheme.ToLower(inv)
- && this.host.ToLower(inv) == uri.host.ToLower(inv)
- && this.port == uri.port
- && this.query == uri.query
- && this.path == uri.path;
- }
-
- public static bool operator ==(Uri u1, Uri u2)
- {
- return object.Equals(u1, u2);
- }
-
- public static bool operator !=(Uri u1, Uri u2)
- {
- return !(u1 == u2);
- }
-
- public override int GetHashCode()
- {
- if (cachedHashCode == 0)
- {
- CultureInfo inv = CultureInfo.InvariantCulture;
- if (isAbsoluteUri)
- {
- cachedHashCode = scheme.ToLower(inv).GetHashCode()
- ^ host.ToLower(inv).GetHashCode()
- ^ port
- ^ query.GetHashCode()
- ^ path.GetHashCode();
- }
- else
- {
- cachedHashCode = source.GetHashCode();
- }
- }
- return cachedHashCode;
- }
-
- public string GetLeftPart(UriPartial part)
- {
- EnsureAbsoluteUri();
- int defaultPort;
- switch (part)
- {
- case UriPartial.Scheme:
- return scheme + GetOpaqueWiseSchemeDelimiter();
- case UriPartial.Authority:
- if ((scheme == Uri.UriSchemeMailto) || (scheme == Uri.UriSchemeNews))
- return String.Empty;
-
- StringBuilder s = new StringBuilder();
- s.Append(scheme);
- s.Append(GetOpaqueWiseSchemeDelimiter());
- if (path.Length > 1 && path[1] == ':' && (Uri.UriSchemeFile == scheme))
- s.Append('/'); // win32 file
- if (userinfo != null)
- s.Append(userinfo).Append('@');
- s.Append(host);
- defaultPort = GetDefaultPort(scheme);
- if ((port != -1) && (port != defaultPort))
- s.Append(':').Append(port);
- return s.ToString();
- case UriPartial.Path:
- StringBuilder sb = new StringBuilder();
- sb.Append(scheme);
- sb.Append(GetOpaqueWiseSchemeDelimiter());
- if (path.Length > 1 && path[1] == ':' && (Uri.UriSchemeFile == scheme))
- sb.Append('/'); // win32 file
- if (userinfo != null)
- sb.Append(userinfo).Append('@');
- sb.Append(host);
- defaultPort = GetDefaultPort(scheme);
- if ((port != -1) && (port != defaultPort))
- sb.Append(':').Append(port);
-
- if (path.Length > 0)
- {
- if (scheme == "mailto" || scheme == "news")
- sb.Append(path);
- else
- sb.Append(Reduce(path, CompactEscaped(scheme)));
- }
- return sb.ToString();
- }
- return null;
- }
-
- public static int FromHex(char digit)
- {
- if ('0' <= digit && digit <= '9')
- {
- return (int)(digit - '0');
- }
-
- if ('a' <= digit && digit <= 'f')
- return (int)(digit - 'a' + 10);
-
- if ('A' <= digit && digit <= 'F')
- return (int)(digit - 'A' + 10);
-
- throw new ArgumentException("digit");
- }
-
- public static string HexEscape(char character)
- {
- if (character > 255)
- {
- throw new ArgumentOutOfRangeException("character");
- }
-
- return "%" + hexUpperChars[((character & 0xf0) >> 4)]
- + hexUpperChars[((character & 0x0f))];
- }
-
- public static char HexUnescape(string pattern, ref int index)
- {
- if (pattern == null)
- throw new ArgumentException("pattern");
-
- if (index < 0 || index >= pattern.Length)
- throw new ArgumentOutOfRangeException("index");
-
- if (!IsHexEncoding(pattern, index))
- return pattern[index++];
-
- index++;
- int msb = FromHex(pattern[index++]);
- int lsb = FromHex(pattern[index++]);
- return (char)((msb << 4) | lsb);
- }
-
- public static bool IsHexDigit(char digit)
- {
- return (('0' <= digit && digit <= '9') ||
- ('a' <= digit && digit <= 'f') ||
- ('A' <= digit && digit <= 'F'));
- }
-
- public static bool IsHexEncoding(string pattern, int index)
- {
- if ((index + 3) > pattern.Length)
- return false;
-
- return ((pattern[index++] == '%') &&
- IsHexDigit(pattern[index++]) &&
- IsHexDigit(pattern[index]));
- }
-
- //
- // Implemented by copying most of the MakeRelative code
- //
- public Uri MakeRelativeUri(Uri uri)
- {
- #if NET_4_0 || MOONLIGHT || MOBILE
- if (uri == null)
- throw new ArgumentNullException ("uri");
- #endif
- if (Host != uri.Host || Scheme != uri.Scheme)
- return uri;
-
- string result = String.Empty;
- if (this.path != uri.path)
- {
- string[] segments = this.Segments;
- string[] segments2 = uri.Segments;
-
- int k = 0;
- int max = Math.Min(segments.Length, segments2.Length);
- for (; k < max; k++)
- if (segments[k] != segments2[k])
- break;
-
- for (int i = k + 1; i < segments.Length; i++)
- result += "../";
- for (int i = k; i < segments2.Length; i++)
- result += segments2[i];
-
- }
- uri.AppendQueryAndFragment(ref result);
-
- return new Uri(result, UriKind.Relative);
- }
-
- [Obsolete("Use MakeRelativeUri(Uri uri) instead.")]
- public string MakeRelative(Uri toUri)
- {
- if ((this.Scheme != toUri.Scheme) ||
- (this.Authority != toUri.Authority))
- return toUri.ToString();
-
- string result = String.Empty;
- if (this.path != toUri.path)
- {
- string[] segments = this.Segments;
- string[] segments2 = toUri.Segments;
- int k = 0;
- int max = Math.Min(segments.Length, segments2.Length);
- for (; k < max; k++)
- if (segments[k] != segments2[k])
- break;
-
- for (int i = k + 1; i < segments.Length; i++)
- result += "../";
- for (int i = k; i < segments2.Length; i++)
- result += segments2[i];
- }
-
- // Important: MakeRelative does not append fragment or query.
-
- return result;
- }
-
- void AppendQueryAndFragment(ref string result)
- {
- if (query.Length > 0)
- {
- string q = query[0] == '?' ? '?' + Unescape(query.Substring(1), true, false) : Unescape(query, false);
- result += q;
- }
- if (fragment.Length > 0)
- result += Unescape(fragment, true, false);
- }
-
- public override string ToString()
- {
- if (cachedToString != null)
- return cachedToString;
-
- if (isAbsoluteUri)
- {
- cachedToString = Unescape(GetLeftPart(UriPartial.Path), true);
- AppendQueryAndFragment(ref cachedToString);
- }
- else
- {
- // Everything is contained in path in this case.
- cachedToString = path;
- }
-
- return cachedToString;
- }
-
- //protected void GetObjectData(SerializationInfo info, StreamingContext context)
- //{
- // if (this.isAbsoluteUri)
- // {
- // info.AddValue("AbsoluteUri", this.AbsoluteUri);
- // }
- // else
- // {
- // info.AddValue("AbsoluteUri", String.Empty);
- // info.AddValue("RelativeUri", this.OriginalString);
- // }
- //}
-
- //void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
- //{
- // GetObjectData(info, context);
- //}
-
-
- // Internal Methods
-
- //[Obsolete]
- protected virtual void Escape()
- {
- path = EscapeString(path);
- }
-
- #if MOONLIGHT
- static string EscapeString (string str)
- #else
- //[Obsolete]
- protected static string EscapeString(string str)
- #endif
- {
- return EscapeString(str, Uri.EscapeCommonHexBrackets);
- }
-
- private const string EscapeCommon = "<>%\"{}|\\^`";
- private const string EscapeReserved = ";/?:@&=+$,";
- private const string EscapeFragment = "#";
- private const string EscapeBrackets = "[]";
-
- private const string EscapeNews = EscapeCommon + EscapeBrackets + "?";
- private const string EscapeCommonHex = EscapeCommon + EscapeFragment;
- private const string EscapeCommonBrackets = EscapeCommon + EscapeBrackets;
- internal const string EscapeCommonHexBrackets = EscapeCommon + EscapeFragment + EscapeBrackets;
- internal const string EscapeCommonHexBracketsQuery = EscapeCommonHexBrackets + "?";
-
- internal static string EscapeString(string str, string escape)
- {
- return EscapeString(str, escape, true);
- }
-
- internal static string EscapeString(string str, string escape, bool nonAsciiEscape)
- {
- if (String.IsNullOrEmpty(str))
- return String.Empty;
-
- StringBuilder s = new StringBuilder();
- int len = str.Length;
- for (int i = 0; i < len; i++)
- {
- // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
- // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
- // control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
- // space = <US-ASCII coded character 20 hexadecimal>
- // delims = "<" | ">" | "#" | "%" | <">
- // unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
-
- // check for escape code already placed in str,
- // i.e. for encoding that follows the pattern
- // "%hexhex" in a string, where "hex" is a digit from 0-9
- // or a letter from A-F (case-insensitive).
- if (IsHexEncoding(str, i))
- {
- // if ,yes , copy it as is
- s.Append(str.Substring(i, 3));
- i += 2;
- continue;
- }
-
- char c = str[i];
- bool outside_limited_ascii = ((c <= 0x20) || (c >= 0x7f));
- bool needs_escape = (escape.IndexOf(c) != -1);
- if (nonAsciiEscape && outside_limited_ascii)
- {
- byte[] data = Encoding.UTF8.GetBytes(new char[] { c });
- int length = data.Length;
- for (int j = 0; j < length; j++)
- {
- c = (char)data[j];
- if (needs_escape || nonAsciiEscape)
- s.Append(HexEscape(c));
- else
- s.Append(c);
- }
- }
- else if (needs_escape)
- {
- s.Append(HexEscape(c));
- }
- else
- {
- s.Append(c);
- }
- }
-
- return s.ToString();
- }
-
- // On .NET 1.x, this method is called from .ctor(). When overriden, we
- // can avoid the "absolute uri" constraints of the .ctor() by
- // overriding with custom code.
- [Obsolete("The method has been deprecated. It is not used by the system.")]
- protected virtual void Parse()
- {
- }
-
- private void ParseUri(UriKind kind)
- {
- Parse(kind, source);
-
- if (userEscaped)
- return;
-
- // non-ascii characters are not escaped for the host name
- host = EscapeString(host, EscapeCommonHex, false);
- if (host.Length > 1 && host[0] != '[' && host[host.Length - 1] != ']')
- {
- // host name present (but not an IPv6 address)
- host = host.ToLower(CultureInfo.InvariantCulture);
- }
-
- if (isAbsoluteUri && (path.Length > 0))
- path = EscapeString(path);
- }
-
- #if MOONLIGHT
- string Unescape (string str)
- #else
- //[Obsolete]
- protected virtual string Unescape(string str)
- #endif
- {
- return Unescape(str, false, false);
- }
-
- internal static string Unescape(string str, bool excludeSpecial)
- {
- return Unescape(str, excludeSpecial, excludeSpecial);
- }
-
- internal static string Unescape(string str, bool excludeSpecial, bool excludeBackslash)
- {
- if (String.IsNullOrEmpty(str))
- return String.Empty;
-
- StringBuilder s = new StringBuilder();
- int len = str.Length;
- for (int i = 0; i < len; i++)
- {
- char c = str[i];
- if (c == '%')
- {
- char surrogate;
- char x = HexUnescapeMultiByte(str, ref i, out surrogate);
- if (excludeSpecial && x == '#')
- s.Append("%23");
- else if (excludeSpecial && x == '%')
- s.Append("%25");
- else if (excludeSpecial && x == '?')
- s.Append("%3F");
- else if (excludeBackslash && x == '\\')
- s.Append("%5C");
- else
- {
- s.Append(x);
- if (surrogate != char.MinValue)
- s.Append(surrogate);
- }
- i--;
- }
- else
- s.Append(c);
- }
- return s.ToString();
- }
-
-
- // Private Methods
-
- private void ParseAsWindowsUNC(string uriString)
- {
- scheme = UriSchemeFile;
- port = -1;
- fragment = String.Empty;
- query = String.Empty;
- isUnc = true;
-
- uriString = uriString.TrimStart(new char[] { '\\' });
- int pos = uriString.IndexOf('\\');
- if (pos > 0)
- {
- path = uriString.Substring(pos);
- host = uriString.Substring(0, pos);
- }
- else
- { // "\\\\server"
- host = uriString;
- path = String.Empty;
- }
- path = path.Replace("\\", "/");
- }
-
- //
- // Returns null on success, string with error on failure
- //
- private string ParseAsWindowsAbsoluteFilePath(string uriString)
- {
- if (uriString.Length > 2 && uriString[2] != '\\' && uriString[2] != '/')
- return "Relative file path is not allowed.";
- scheme = UriSchemeFile;
- host = String.Empty;
- port = -1;
- path = uriString.Replace("\\", "/");
- fragment = String.Empty;
- query = String.Empty;
-
- return null;
- }
-
- private void ParseAsUnixAbsoluteFilePath(string uriString)
- {
- isUnixFilePath = true;
- scheme = UriSchemeFile;
- port = -1;
- fragment = String.Empty;
- query = String.Empty;
- host = String.Empty;
- path = null;
-
- if (uriString.Length >= 2 && uriString[0] == '/' && uriString[1] == '/')
- {
- uriString = uriString.TrimStart(new char[] { '/' });
- // Now we don't regard //foo/bar as "foo" host.
- /*
- int pos = uriString.IndexOf ('/');
- if (pos > 0) {
- path = '/' + uriString.Substring (pos + 1);
- host = uriString.Substring (0, pos);
- } else { // "///server"
- host = uriString;
- path = String.Empty;
- }
- */
- path = '/' + uriString;
- }
- if (path == null)
- path = uriString;
- }
-
- //
- // This parse method will throw exceptions on failure
- //
- private void Parse(UriKind kind, string uriString)
- {
- if (uriString == null)
- throw new ArgumentNullException("uriString");
-
- string s = ParseNoExceptions(kind, uriString);
- if (s != null)
- throw new UriFormatException(s);
- }
-
- private bool SupportsQuery()
- {
- return ((scheme != Uri.UriSchemeNntp) && (scheme != Uri.UriSchemeFtp) && (scheme != Uri.UriSchemeFile));
- }
-
- //
- // This parse method will not throw exceptions on failure
- //
- // Returns null on success, or a description of the error in the parsing
- //
- private string ParseNoExceptions(UriKind kind, string uriString)
- {
- //
- // From RFC 2396 :
- //
- // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- // 12 3 4 5 6 7 8 9
- //
-
- uriString = uriString.Trim();
- int len = uriString.Length;
-
- if (len == 0)
- {
- if (kind == UriKind.Relative || kind == UriKind.RelativeOrAbsolute)
- {
- isAbsoluteUri = false;
- return null;
- }
- }
-
- if (len <= 1 && (kind == UriKind.Absolute))
- return "Absolute URI is too short";
-
- int pos = 0;
-
- // 1, 2
- // Identify Windows path, unix path, or standard URI.
- if (uriString[0] == '/' && Path.DirectorySeparatorChar == '/')
- {
- //Unix Path
- ParseAsUnixAbsoluteFilePath(uriString);
- #if MOONLIGH…
Large files files are truncated, but you can click here to view the full file