internal static Common.InlineParseResult Parse(string markdown, int start, int maxEnd)
{
// Expect a '[' character.
if (start == maxEnd || markdown[start] != '[')
return null;
// Find the ']' character, keeping in mind that [test [0-9]](http://www.test.com) is allowed.
int linkTextOpen = start + 1;
int pos = linkTextOpen;
int linkTextClose;
int openSquareBracketCount = 0;
while (true)
{
linkTextClose = markdown.IndexOfAny(new char[] { '[', ']' }, pos, maxEnd - pos);
if (linkTextClose == -1)
return null;
if (markdown[linkTextClose] == '[')
openSquareBracketCount++;
else if (openSquareBracketCount > 0)
openSquareBracketCount--;
else
break;
pos = linkTextClose + 1;
}
// Skip whitespace.
pos = linkTextClose + 1;
while (pos < maxEnd && Common.IsWhiteSpace(markdown[pos]))
pos++;
if (pos == maxEnd)
return null;
// Expect the '(' character or the '[' character.
int linkOpen = pos;
if (markdown[pos] == '(')
{
// Skip whitespace.
linkOpen++;
while (linkOpen < maxEnd && Common.IsWhiteSpace(markdown[linkOpen]))
linkOpen++;
// Find the ')' character.
pos = linkOpen;
int linkClose = -1;
while (pos < maxEnd)
{
linkClose = Common.IndexOf(markdown, ')', pos, maxEnd);
if (linkClose == -1)
return null;
if (markdown[linkClose - 1] != '\\')
break;
pos = linkClose + 1;
}
if (pos >= maxEnd)
return null;
int end = linkClose + 1;
// Skip whitespace backwards.
while (linkClose > linkOpen && Common.IsWhiteSpace(markdown[linkClose - 1]))
linkClose--;
// If there is no text whatsoever, then this is not a valid link.
if (linkOpen == linkClose)
return null;
// Check if there is tooltip text.
string url;
string tooltip = null;
bool lastUrlCharIsDoubleQuote = markdown[linkClose - 1] == '"';
int tooltipStart = Common.IndexOf(markdown, " \"", linkOpen, linkClose - 1);
if (tooltipStart == linkOpen)
return null;
if (lastUrlCharIsDoubleQuote && tooltipStart != -1)
{
// Extract the URL (resolving any escape sequences).
url = TextRunInline.ResolveEscapeSequences(markdown, linkOpen, tooltipStart).TrimEnd(' ', '\t', '\r', '\n');
tooltip = markdown.Substring(tooltipStart + 2, (linkClose - 1) - (tooltipStart + 2));
}
else
{
// Extract the URL (resolving any escape sequences).
url = TextRunInline.ResolveEscapeSequences(markdown, linkOpen, linkClose);
}
// Check the URL is okay.
if (!IsUrlValid(url))
return null;
// We found a regular stand-alone link.
var result = new MarkdownLinkInline();
result.Inlines = Common.ParseInlineChildren(markdown, linkTextOpen, linkTextClose, ignoreLinks: true);
result.Url = url.Replace(" ", "%20");
result.Tooltip = tooltip;
return new Common.InlineParseResult(result, start, end);
}
else if (markdown[pos] == '[')
{
// Find the ']' character.
int linkClose = Common.IndexOf(markdown, ']', pos + 1, maxEnd);
if (linkClose == -1)
return null;
// We found a reference-style link.
var result = new MarkdownLinkInline();
result.Inlines = Common.ParseInlineChildren(markdown, linkTextOpen, linkTextClose, ignoreLinks: true);
result.ReferenceId = markdown.Substring(linkOpen + 1, linkClose - (linkOpen + 1));
if (result.ReferenceId == string.Empty)
result.ReferenceId = markdown.Substring(linkTextOpen, linkTextClose - linkTextOpen);
return new Common.InlineParseResult(result, start, linkClose + 1);
}
return null;
}