/// <summary>
        /// Attempts to parse a markdown link e.g. "[](http://www.reddit.com)".
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The location to start parsing. </param>
        /// <param name="maxEnd"> The location to stop parsing. </param>
        /// <returns> A parsed markdown link, or <c>null</c> if this is not a markdown link. </returns>
        internal static 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 && ParseHelpers.IsMarkdownWhiteSpace(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 && ParseHelpers.IsMarkdownWhiteSpace(markdown[linkOpen]))
                {
                    linkOpen++;
                }

                // Find the ')' character.
                pos = linkOpen;
                int linkClose       = -1;
                var openParenthesis = 0;
                while (pos < maxEnd)
                {
                    if (markdown[pos] == ')')
                    {
                        if (openParenthesis == 0)
                        {
                            linkClose = pos;
                            break;
                        }
                        else
                        {
                            openParenthesis--;
                        }
                    }

                    if (markdown[pos] == '(')
                    {
                        openParenthesis++;
                    }

                    pos++;
                }

                if (pos >= maxEnd)
                {
                    return(null);
                }

                int end = linkClose + 1;

                // Skip whitespace backwards.
                while (linkClose > linkOpen && ParseHelpers.IsMarkdownWhiteSpace(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 (!url.IsEmail())
                {
                    if (!Common.IsUrlValid(url))
                    {
                        return(null);
                    }
                }
                else
                {
                    tooltip = url = string.Format("mailto:{0}", url);
                }

                // 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 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 InlineParseResult(result, start, linkClose + 1));
            }

            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Attempts to parse an image e.g. "![Toolkit logo](https://raw.githubusercontent.com/Microsoft/UWPCommunityToolkit/master/Microsoft.Toolkit.Uwp.SampleApp/Assets/ToolkitLogo.png)".
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The location to start parsing. </param>
        /// <param name="end"> The location to stop parsing. </param>
        /// <returns> A parsed markdown image, or <c>null</c> if this is not a markdown image. </returns>
        internal static InlineParseResult Parse(string markdown, int start, int end)
        {
            // Expect a '!' character.
            if (start >= end || markdown[start] != '!')
            {
                return(null);
            }

            int pos = start + 1;

            // Then a '[' character
            if (pos >= end || markdown[pos] != '[')
            {
                return(null);
            }

            pos++;

            // Find the ']' character
            while (pos < end)
            {
                if (markdown[pos] == ']')
                {
                    break;
                }

                pos++;
            }

            if (pos == end)
            {
                return(null);
            }

            // Extract the alt.
            string tooltip = markdown.Substring(start + 2, pos - (start + 2));

            // Expect the '(' character.
            pos++;
            if (pos == end || markdown[pos] != '(')
            {
                return(null);
            }

            // Skip whitespace
            pos++;
            while (pos < end && ParseHelpers.IsMarkdownWhiteSpace(markdown[pos]))
            {
                pos++;
            }

            if (pos == end)
            {
                return(null);
            }

            // Extract the URL.
            int urlStart = pos;

            while (pos < end && markdown[pos] != ')')
            {
                pos++;
            }

            var imageDimensionsPos = markdown.IndexOf(" =", urlStart, pos - urlStart, StringComparison.Ordinal);

            var url = imageDimensionsPos > 0
                ? TextRunInline.ResolveEscapeSequences(markdown, urlStart, imageDimensionsPos)
                : TextRunInline.ResolveEscapeSequences(markdown, urlStart, pos);

            int imageWidth  = 0;
            int imageHeight = 0;

            if (imageDimensionsPos > 0)
            {
                // trying to find 'x' which separates image width and height
                var dimensionsSepatorPos = markdown.IndexOf("x", imageDimensionsPos + 2, pos - imageDimensionsPos - 1, StringComparison.Ordinal);

                // didn't find separator, trying to parse value as imageWidth
                if (dimensionsSepatorPos == -1)
                {
                    var imageWidthStr = markdown.Substring(imageDimensionsPos + 2, pos - imageDimensionsPos - 2);

                    int.TryParse(imageWidthStr, out imageWidth);
                }
                else
                {
                    var dimensions = markdown.Substring(imageDimensionsPos + 2, pos - imageDimensionsPos - 2).Split('x');

                    // got width and height
                    if (dimensions.Length == 2)
                    {
                        int.TryParse(dimensions[0], out imageWidth);
                        int.TryParse(dimensions[1], out imageHeight);
                    }
                }
            }

            // We found something!
            var result = new ImageInline
            {
                Tooltip     = tooltip,
                Url         = url,
                Text        = markdown.Substring(start, pos + 1 - start),
                ImageWidth  = imageWidth,
                ImageHeight = imageHeight
            };

            return(new InlineParseResult(result, start, pos + 1));
        }