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 (_iriParsing)
{
bool valid = false;
res |= Check.FoundNonAscii;
if (char.IsHighSurrogate(c))
{
if ((i + 1) < end)
{
bool surrPair = false;
valid = IriHelper.CheckIriUnicodeRange(c, str[i + 1], ref surrPair, true);
}
}
else
{
valid = IriHelper.CheckIriUnicodeRange(c, true);
}
if (!valid) res |= Check.NotIriCanonical;
}
if (!needsEscaping) needsEscaping = true;
}
else if (c == delim)
{
break;
}
else if (delim == '?' && c == '#' && (_syntax != null && _syntax.InFact(UriSyntaxFlags.MayHaveFragment)))
{
// this is a special case when deciding on Query/Fragment
break;
}
else if (c == '?')
{
if (IsImplicitFile || (_syntax != null && !_syntax.InFact(UriSyntaxFlags.MayHaveQuery)
&& delim != c_EOL))
{
// 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 || (_syntax != null && !_syntax.InFact(UriSyntaxFlags.MayHaveFragment)))
{
// 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 = UriHelper.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;
}