public bool IsTagReallySafe(HtmlTag tag)
        {
            switch (tag.name)
            {
                case "B":
                case "UL":
                case "LI":
                case "I":
                    return tag.attributes.Count == 0;

                case "A":
                case "a":
                    return tag.closing && tag.attributes.Count == 0;
            }

            return false;
        }
        internal void RenderLink(Markdown m, StringBuilder b, string link_text)
        {
            if (url.StartsWith("mailto:"))
            {
                b.Append("<a href=\"");
                Utils.HtmlRandomize(b, url);
                b.Append('\"');
                if (!String.IsNullOrEmpty(title))
                {
                    b.Append(" title=\"");
                    Utils.SmartHtmlEncodeAmpsAndAngles(b, title);
                    b.Append('\"');
                }
                b.Append('>');
                Utils.HtmlRandomize(b, link_text);
                b.Append("</a>");
            }
            else
            {
                HtmlTag tag = new HtmlTag("a");

                // encode url
                StringBuilder sb = m.GetStringBuilder();
                Utils.SmartHtmlEncodeAmpsAndAngles(sb, url);
                tag.attributes["href"] = sb.ToString();

                // encode title
                if (!String.IsNullOrEmpty(title ))
                {
                    sb.Length = 0;
                    Utils.SmartHtmlEncodeAmpsAndAngles(sb, title);
                    tag.attributes["title"] = sb.ToString();
                }

                // Do user processing
                m.OnPrepareLink(tag);

                // Render the opening tag
                tag.RenderOpening(b);

                b.Append(link_text);	  // Link text already escaped by SpanFormatter
                b.Append("</a>");
            }
        }
        internal void RenderImg(Markdown m, StringBuilder b, string alt_text)
        {
            HtmlTag tag = new HtmlTag("img");

            // encode url
            StringBuilder sb = m.GetStringBuilder();
            Utils.SmartHtmlEncodeAmpsAndAngles(sb, url);
            tag.attributes["src"] = sb.ToString();

            // encode alt text
            if (!String.IsNullOrEmpty(alt_text))
            {
                sb.Length = 0;
                Utils.SmartHtmlEncodeAmpsAndAngles(sb, alt_text);
                tag.attributes["alt"] = sb.ToString();
            }

            // encode title
            if (!String.IsNullOrEmpty(title))
            {
                sb.Length = 0;
                Utils.SmartHtmlEncodeAmpsAndAngles(sb, title);
                tag.attributes["title"] = sb.ToString();
            }

            tag.closed = true;

            m.OnPrepareImage(tag, m.RenderingTitledImage);

            tag.RenderOpening(b);
        }
Beispiel #4
0
        private static HtmlTag ParseHelper(StringScanner p)
        {
            // Does it look like a tag?
            if (p.current != '<')
                return null;

            // Skip '<'
            p.SkipForward(1);

            // Is it a comment?
            if (p.SkipString("!--"))
            {
                p.Mark();

                if (p.Find("-->"))
                {
                    var t = new HtmlTag("!");
                    t.m_attributes.Add("content", p.Extract());
                    t.m_closed = true;
                    p.SkipForward(3);
                    return t;
                }
            }

            // Is it a closing tag eg: </div>
            bool bClosing = p.SkipChar('/');

            // Get the tag name
            string tagName=null;
            if (!p.SkipIdentifier(ref tagName))
                return null;

            // Probably a tag, create the HtmlTag object now
            HtmlTag tag = new HtmlTag(tagName);
            tag.m_closing = bClosing;

            // If it's a closing tag, no attributes
            if (bClosing)
            {
                if (p.current != '>')
                    return null;

                p.SkipForward(1);
                return tag;
            }

            while (!p.eof)
            {
                // Skip whitespace
                p.SkipWhitespace();

                // Check for closed tag eg: <hr />
                if (p.SkipString("/>"))
                {
                    tag.m_closed=true;
                    return tag;
                }

                // End of tag?
                if (p.SkipChar('>'))
                {
                    return tag;
                }

                // attribute name
                string attributeName = null;
                if (!p.SkipIdentifier(ref attributeName))
                    return null;

                // Skip whitespace
                p.SkipWhitespace();

                // Skip equal sign
                if (p.SkipChar('='))
                {
                    // Skip whitespace
                    p.SkipWhitespace();

                    // Optional quotes
                    if (p.SkipChar('\"'))
                    {
                        // Scan the value
                        p.Mark();
                        if (!p.Find('\"'))
                            return null;

                        // Store the value
                        tag.m_attributes.Add(attributeName, p.Extract());

                        // Skip closing quote
                        p.SkipForward(1);
                    }
                    else
                    {
                        // Scan the value
                        p.Mark();
                        while (!p.eof && !char.IsWhiteSpace(p.current) && p.current != '>' && p.current != '/')
                            p.SkipForward(1);

                        if (!p.eof)
                        {
                            // Store the value
                            tag.m_attributes.Add(attributeName, p.Extract());
                        }
                    }
                }
                else
                {
                    tag.m_attributes.Add(attributeName, "");
                }
            }

            return null;
        }
        // Override to modify the attributes of a link
        public virtual void OnPrepareLink(HtmlTag tag)
        {
            if (PrepareLink != null)
            {
                if (PrepareLink(tag))
                    return;
            }

            string url = tag.attributes["href"];

            // IsUrlFullyQualified analyzer
            bool? isUrlFullyQualified_cache = null;
            Func<bool> fncIsUrlFullyQualified = () => {
                if (!isUrlFullyQualified_cache.HasValue) isUrlFullyQualified_cache = Utils.IsUrlFullyQualified(url);
                return isUrlFullyQualified_cache.Value;
            };

            // No follow?
            if (this.NoFollowLinks && fncIsUrlFullyQualified()) {
                tag.attributes["rel"] = "nofollow";
            }

            // New window?
            if ( (NewWindowForExternalLinks && fncIsUrlFullyQualified()) ||
                 (NewWindowForLocalLinks && !fncIsUrlFullyQualified()) )
            {
                tag.attributes["target"] = "_blank";
            }

            // Qualify url
            tag.attributes["href"] = OnQualifyUrl(url);
        }
        // Override to modify the attributes of an image
        public virtual void OnPrepareImage(HtmlTag tag, bool TitledImage)
        {
            if (PrepareImage != null)
            {
                if (PrepareImage(tag, TitledImage))
                    return;
            }

            // Try to determine width and height
            int width, height;
            if (OnGetImageSize(tag.attributes["src"], TitledImage, out width, out height))
            {
                tag.attributes["width"] = width.ToString();
                tag.attributes["height"] = height.ToString();
            }

            // Now qualify the url
            tag.attributes["src"] = OnQualifyUrl(tag.attributes["src"]);
        }
        internal bool ProcessMarkdownEnabledHtml(Block b, HtmlTag openingTag, MarkdownInHtmlMode mode)
        {
            // Current position is just after the opening tag

            // Scan until we find matching closing tag
            int inner_pos = position;
            int depth = 1;
            bool bHasUnsafeContent = false;
            while (!eof)
            {
                // Find next angle bracket
                if (!Find('<'))
                    break;

                // Is it a html tag?
                int tagpos = position;
                HtmlTag tag = HtmlTag.Parse(this);
                if (tag == null)
                {
                    // Nope, skip it
                    SkipForward(1);
                    continue;
                }

                // In markdown off mode, we need to check for unsafe tags
                if (m_markdown.SafeMode && mode == MarkdownInHtmlMode.Off && !bHasUnsafeContent)
                {
                    if (!tag.IsSafe())
                        bHasUnsafeContent = true;
                }

                // Ignore self closing tags
                if (tag.closed)
                    continue;

                // Same tag?
                if (tag.name == openingTag.name)
                {
                    if (tag.closing)
                    {
                        depth--;
                        if (depth == 0)
                        {
                            // End of tag?
                            SkipLinespace();
                            SkipEol();

                            b.blockType = BlockType.HtmlTag;
                            b.data = openingTag;
                            b.contentEnd = position;

                            switch (mode)
                            {
                                case MarkdownInHtmlMode.Span:
                                {
                                    Block span = this.CreateBlock();
                                    span.buf = input;
                                    span.blockType = BlockType.span;
                                    span.contentStart = inner_pos;
                                    span.contentLen = tagpos - inner_pos;

                                    b.children = new List<Block>();
                                    b.children.Add(span);
                                    break;
                                }

                                case MarkdownInHtmlMode.Block:
                                case MarkdownInHtmlMode.Deep:
                                {
                                    // Scan the internal content
                                    var bp = new BlockProcessor(m_markdown, mode == MarkdownInHtmlMode.Deep);
                                    b.children = bp.ScanLines(input, inner_pos, tagpos - inner_pos);
                                    break;
                                }

                                case MarkdownInHtmlMode.Off:
                                {
                                    if (bHasUnsafeContent)
                                    {
                                        b.blockType = BlockType.unsafe_html;
                                        b.contentEnd = position;
                                    }
                                    else
                                    {
                                        Block span = this.CreateBlock();
                                        span.buf = input;
                                        span.blockType = BlockType.html;
                                        span.contentStart = inner_pos;
                                        span.contentLen = tagpos - inner_pos;

                                        b.children = new List<Block>();
                                        b.children.Add(span);
                                    }
                                    break;
                                }
                            }

                            return true;
                        }
                    }
                    else
                    {
                        depth++;
                    }
                }
            }

            // Missing closing tag(s).
            return false;
        }
        internal MarkdownInHtmlMode GetMarkdownMode(HtmlTag tag)
        {
            // Get the markdown attribute
            string strMarkdownMode;
            if (!m_markdown.ExtraMode || !tag.attributes.TryGetValue("markdown", out strMarkdownMode))
            {
                if (m_bMarkdownInHtml)
                    return MarkdownInHtmlMode.Deep;
                else
                    return MarkdownInHtmlMode.NA;
            }

            // Remove it
            tag.attributes.Remove("markdown");

            // Parse mode
            if (strMarkdownMode == "1")
                return (tag.Flags & HtmlTagFlags.ContentAsSpan)!=0 ? MarkdownInHtmlMode.Span : MarkdownInHtmlMode.Block;

            if (strMarkdownMode == "block")
                return MarkdownInHtmlMode.Block;

            if (strMarkdownMode == "deep")
                return MarkdownInHtmlMode.Deep;

            if (strMarkdownMode == "span")
                return MarkdownInHtmlMode.Span;

            return MarkdownInHtmlMode.Off;
        }