private unsafe void CreateHostString()
{
if (!_syntax.IsSimple)
{
lock (_info)
{
// ATTN: Avoid possible recursion through
// CreateHostString->Syntax.GetComponents->Uri.GetComponentsHelper->CreateHostString
if (NotAny(Flags.ErrorOrParsingRecursion))
{
_flags |= Flags.ErrorOrParsingRecursion;
// Need to get host string through the derived type
GetHostViaCustomSyntax();
_flags &= ~Flags.ErrorOrParsingRecursion;
return;
}
}
}
Flags flags = _flags;
string host = CreateHostStringHelper(_string, _info.Offset.Host, _info.Offset.Path, ref flags, ref _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
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 = UriHelper.EscapeString(host, 0, host.Length, null, ref position, true, '?',
'#', IsImplicitFile ? c_DummyChar : '%');
if ((object)dest != null)
host = new string(dest, 0, position);
}
else
{
// We should throw here but currently just accept user input known as invalid
}
}
}
else if (NotAny(Flags.CanonicalDnsHost))
{
// Check to see if we can take the canonical host string out of m_String
if ((object)_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 ((_info.Offset.Host + i) >= _info.Offset.End ||
host[i] != _string[_info.Offset.Host + i])
{
flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical);
break;
}
}
}
}
}
_info.Host = host;
lock (_info)
{
_flags |= flags;
}
}