//
// Resolves into either baseUri or relativeUri according to conditions OR if not possible it uses newUriString
// to return combined URI strings from both Uris
// otherwise if e != null on output the operation has failed
//
internal static Uri ResolveHelper(Uri baseUri, Uri relativeUri, ref string newUriString, ref bool userEscaped,
out UriFormatException e)
{
Debug.Assert(!baseUri.IsNotAbsoluteUri && !baseUri.UserDrivenParsing, "Uri::ResolveHelper()|baseUri is not Absolute or is controlled by User Parser.");
e = null;
string relativeStr = string.Empty;
if ((object)relativeUri != null)
{
if (relativeUri.IsAbsoluteUri)
{
return(relativeUri);
}
relativeStr = relativeUri.OriginalString;
userEscaped = relativeUri.UserEscaped;
}
else
{
relativeStr = string.Empty;
}
// Here we can assert that passed "relativeUri" is indeed a relative one
if (relativeStr.Length > 0 && (IsLWS(relativeStr[0]) || IsLWS(relativeStr[relativeStr.Length - 1])))
{
relativeStr = relativeStr.Trim(s_WSchars);
}
if (relativeStr.Length == 0)
{
newUriString = baseUri.GetParts(UriComponents.AbsoluteUri,
baseUri.UserEscaped ? UriFormat.UriEscaped : UriFormat.SafeUnescaped);
return(null);
}
// Check for a simple fragment in relative part
if (relativeStr[0] == '#' && !baseUri.IsImplicitFile && baseUri.Syntax.InFact(UriSyntaxFlags.MayHaveFragment))
{
newUriString = baseUri.GetParts(UriComponents.AbsoluteUri & ~UriComponents.Fragment,
UriFormat.UriEscaped) + relativeStr;
return(null);
}
// Check for a simple query in relative part
if (relativeStr[0] == '?' && !baseUri.IsImplicitFile && baseUri.Syntax.InFact(UriSyntaxFlags.MayHaveQuery))
{
newUriString = baseUri.GetParts(UriComponents.AbsoluteUri & ~UriComponents.Query & ~UriComponents.Fragment,
UriFormat.UriEscaped) + relativeStr;
return(null);
}
// Check on the DOS path in the relative Uri (a special case)
if (relativeStr.Length >= 3 &&
(relativeStr[1] == ':' || relativeStr[1] == '|') &&
IsAsciiLetter(relativeStr[0]) &&
(relativeStr[2] == '\\' || relativeStr[2] == '/'))
{
if (baseUri.IsImplicitFile)
{
// It could have file:/// prepended to the result but we want to keep it as *Implicit* File Uri
newUriString = relativeStr;
return(null);
}
else if (baseUri.Syntax.InFact(UriSyntaxFlags.AllowDOSPath))
{
// The scheme is not changed just the path gets replaced
string prefix;
if (baseUri.InFact(Flags.AuthorityFound))
{
prefix = baseUri.Syntax.InFact(UriSyntaxFlags.PathIsRooted) ? ":///" : "://";
}
else
{
prefix = baseUri.Syntax.InFact(UriSyntaxFlags.PathIsRooted) ? ":/" : ":";
}
newUriString = baseUri.Scheme + prefix + relativeStr;
return(null);
}
// If we are here then input like "http://host/path/" + "C:\x" will produce the result http://host/path/c:/x
}
ParsingError err = GetCombinedString(baseUri, relativeStr, userEscaped, ref newUriString);
if (err != ParsingError.None)
{
e = GetException(err);
return(null);
}
if ((object)newUriString == (object)baseUri._string)
{
return(baseUri);
}
return(null);
}