System.Uri.Uri.Merge C# (CSharp) Method

Merge() private method

private Merge ( Uri baseUri, string relativeUri ) : void
baseUri Uri
relativeUri string
return void
		private void Merge (Uri baseUri, string relativeUri)
		{
#if NET_2_0
			if (baseUri == null)
				throw new ArgumentNullException ("baseUri");
			if (!baseUri.IsAbsoluteUri)
				throw new ArgumentOutOfRangeException ("baseUri");
			if (relativeUri == null)
				relativeUri = String.Empty;
#else
			if (baseUri == null)
				throw new NullReferenceException ("baseUri");
#endif
			// 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;
#if NET_2_0
				ParseUri (UriKind.Absolute);
#else
				Parse ();
#endif
				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] == '/') {
						source = relativeUri;
#if NET_2_0
						ParseUri (UriKind.Absolute);
#else
						Parse ();
#endif
						return;
					}
					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 == String.Empty) {
				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.
			pos = relativeUri.IndexOf ('#');
			if (pos != -1) {
				if (userEscaped)
					fragment = relativeUri.Substring (pos);
				else
					fragment = "#" + EscapeString (relativeUri.Substring (pos+1));
				relativeUri = relativeUri.Substring (0, pos);
			}

			// 6 query
			pos = relativeUri.IndexOf ('?');
			if (pos != -1) {
				query = relativeUri.Substring (pos);
				if (!userEscaped)
					query = EscapeString (query);
				relativeUri = relativeUri.Substring (0, pos);
			}

			if (relativeUri.Length > 0 && relativeUri [0] == '/') {
				if (relativeUri.Length > 1 && relativeUri [1] == '/') {
					source = scheme + ':' + relativeUri;
#if NET_2_0
					ParseUri (UriKind.Absolute);
#else
					Parse ();
#endif
					return;
				} else {
					path = relativeUri;
					if (!userEscaped)
						path = EscapeString (path);
					return;
				}
			}
			
			// par 5.2 step 6 a)
			path = baseUri.path;
#if NET_4_0
			if (relativeUri.Length > 0) {
#else
			if (relativeUri.Length > 0 || query.Length > 0) {
#endif
				pos = path.LastIndexOf ('/');
				if (pos >= 0) 
					path = path.Substring (0, pos + 1);
			}

			if(relativeUri.Length == 0)
				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);
			}
			
			if (!userEscaped)
				path = EscapeString (path);
		}		
		
		// Properties
		
		public string AbsolutePath { 
			get {
#if NET_2_0
				EnsureAbsoluteUri ();
				switch (Scheme) {
				case "mailto":
				case "file":
					// faster (mailto) and special (file) cases
					return path;
				default:
					if (path.Length == 0) {
						string start = Scheme + SchemeDelimiter;
						if (path.StartsWith (start))
							return "/";
						else
							return String.Empty;
					}
					return path;
				}
#else
				return path;
#endif
			}
		}