internal static TextRunInline Parse(string markdown, int start, int end)
{
// Handle escape sequences and entities.
// Note: this code is designed to be as fast as possible in the case where there are no
// escape sequences and no entities (expected to be the common case).
StringBuilder result = null;
int textPos = start;
int searchPos = start;
while (searchPos < end)
{
// Look for the next backslash.
int sequenceStartIndex = markdown.IndexOfAny(new char[] { '\\', '&' }, searchPos, end - searchPos);
if (sequenceStartIndex == -1)
break;
searchPos = sequenceStartIndex + 1;
char decodedChar;
if (markdown[sequenceStartIndex] == '\\')
{
// This is an escape sequence, with one more character expected.
if (sequenceStartIndex >= end - 1)
break;
// Check if the character after the backslash can be escaped.
decodedChar = markdown[sequenceStartIndex + 1];
if (Array.IndexOf(escapeCharacters, decodedChar) < 0)
{
// This character cannot be escaped.
continue;
}
// This here's an escape sequence!
if (result == null)
result = new StringBuilder(end - start);
result.Append(markdown.Substring(textPos, sequenceStartIndex - textPos));
result.Append(decodedChar);
searchPos = textPos = sequenceStartIndex + 2;
}
else if (markdown[sequenceStartIndex] == '&')
{
// This is an entity e.g. " ".
// Look for the semicolon.
int semicolonIndex = markdown.IndexOf(';', sequenceStartIndex + 1, end - (sequenceStartIndex + 1));
if (semicolonIndex == -1) // Unterminated entity.
continue;
// Okay, we have an entity, but is it one we recognise?
string entityName = markdown.Substring(sequenceStartIndex + 1, semicolonIndex - (sequenceStartIndex + 1));
if (entities.ContainsKey(entityName) == false) // Unrecognised entity.
continue;
// This here's an escape sequence!
if (result == null)
result = new StringBuilder(end - start);
result.Append(markdown.Substring(textPos, sequenceStartIndex - textPos));
result.Append((char)entities[entityName]);
searchPos = textPos = semicolonIndex + 1;
}
}
if (result != null)
{
result.Append(markdown.Substring(textPos, end - textPos));
return new TextRunInline { Text = result.ToString() };
}
return new TextRunInline { Text = markdown.Substring(start, end - start) };
}