Example #1
0
 /// <summary>
 /// The push attribute name start.
 /// </summary>
 /// <param name="index">The index.</param>
 private void PushAttributeNameStart(int index)
 {
     this.currentattribute = this.CreateAttribute();
     this.currentattribute.NameStartIndex = index;
     this.currentattribute.Line = this.line;
     this.currentattribute.LinePosition = this.lineposition;
     this.currentattribute.StreamPosition = index;
 }
Example #2
0
        /// <summary>
        /// The write attribute.
        /// </summary>
        /// <param name="outText">
        /// The out text.
        /// </param>
        /// <param name="att">
        /// The att.
        /// </param>
        internal void WriteAttribute(TextWriter outText, HtmlAttribute att)
        {
            string name;
            string quote = att.QuoteType == AttributeValueQuote.DoubleQuote ? "\"" : "'";
            if (this.OwnerDocument.OptionOutputAsXml)
            {
                name = this.OwnerDocument.OptionOutputUpperCase ? att.XmlName.ToUpper() : att.XmlName;
                if (this.OwnerDocument.OptionOutputOriginalCase)
                {
                    name = att.OriginalName;
                }

                outText.Write(" " + name + "=" + quote + HtmlDocument.HtmlEncode(att.XmlValue) + quote);
            }
            else
            {
                name = this.OwnerDocument.OptionOutputUpperCase ? att.Name.ToUpper() : att.Name;

                if (att.Name.Length >= 4)
                {
                    if ((att.Name[0] == '<') && (att.Name[1] == '%') && (att.Name[att.Name.Length - 1] == '>')
                        && (att.Name[att.Name.Length - 2] == '%'))
                    {
                        outText.Write(" " + name);
                        return;
                    }
                }

                if (this.OwnerDocument.OptionOutputOptimizeAttributeValues)
                {
                    if (att.Value.IndexOfAny(new[] { (char)10, (char)13, (char)9, ' ' }) < 0)
                    {
                        outText.Write(" " + name + "=" + att.Value);
                    }
                    else
                    {
                        outText.Write(" " + name + "=" + quote + att.Value + quote);
                    }
                }
                else
                {
                    outText.Write(" " + name + "=" + quote + att.Value + quote);
                }
            }
        }
Example #3
0
        /// <summary>
        /// The parse.
        /// </summary>
        private void Parse()
        {
            int lastquote = 0;

            this.LastNodes = new Dictionary<string, HtmlNode>();
            this.currentchar = 0;
            this.fullcomment = false;
            this.parseerrors = new List<HtmlParseError>();
            this.line = 1;
            this.lineposition = 1;
            this.maxlineposition = 1;

            this.state = ParseState.Text;
            this.oldstate = this.state;
            this.documentnode.InnerLength = this.Text.Length;
            this.documentnode.OuterLength = this.Text.Length;
            this.RemainderOffset = this.Text.Length;

            this.lastparentnode = this.documentnode;
            this.currentnode = this.CreateNode(HtmlNodeType.Text, 0);
            this.currentattribute = null;

            this.cuurrentindex = 0;
            this.PushNodeStart(HtmlNodeType.Text, 0);
            while (this.cuurrentindex < this.Text.Length)
            {
                this.currentchar = this.Text[this.cuurrentindex];
                this.IncrementPosition();

                switch (this.state)
                {
                    case ParseState.Text:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        break;

                    case ParseState.WhichTag:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (this.currentchar == '/')
                        {
                            this.PushNodeNameStart(false, this.cuurrentindex);
                        }
                        else
                        {
                            this.PushNodeNameStart(true, this.cuurrentindex - 1);
                            this.DecrementPosition();
                        }

                        this.state = ParseState.Tag;
                        break;

                    case ParseState.Tag:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            this.PushNodeNameEnd(this.cuurrentindex - 1);
                            if (this.state != ParseState.Tag)
                            {
                                continue;
                            }

                            this.state = ParseState.BetweenAttributes;
                            continue;
                        }

                        if (this.currentchar == '/')
                        {
                            this.PushNodeNameEnd(this.cuurrentindex - 1);
                            if (this.state != ParseState.Tag)
                            {
                                continue;
                            }

                            this.state = ParseState.EmptyTag;
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            this.PushNodeNameEnd(this.cuurrentindex - 1);
                            if (this.state != ParseState.Tag)
                            {
                                continue;
                            }

                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.Tag)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                        }

                        break;

                    case ParseState.BetweenAttributes:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            continue;
                        }

                        if ((this.currentchar == '/') || (this.currentchar == '?'))
                        {
                            this.state = ParseState.EmptyTag;
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.BetweenAttributes)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        this.PushAttributeNameStart(this.cuurrentindex - 1);
                        this.state = ParseState.AttributeName;
                        break;

                    case ParseState.EmptyTag:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            if (!this.PushNodeEnd(this.cuurrentindex, true))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.EmptyTag)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        this.state = ParseState.BetweenAttributes;
                        break;

                    case ParseState.AttributeName:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            this.PushAttributeNameEnd(this.cuurrentindex - 1);
                            this.state = ParseState.AttributeBeforeEquals;
                            continue;
                        }

                        if (this.currentchar == '=')
                        {
                            this.PushAttributeNameEnd(this.cuurrentindex - 1);
                            this.state = ParseState.AttributeAfterEquals;
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            this.PushAttributeNameEnd(this.cuurrentindex - 1);
                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.AttributeName)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        break;

                    case ParseState.AttributeBeforeEquals:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.AttributeBeforeEquals)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        if (this.currentchar == '=')
                        {
                            this.state = ParseState.AttributeAfterEquals;
                            continue;
                        }

                        // no equals, no whitespace, it's a new attrribute starting
                        this.state = ParseState.BetweenAttributes;
                        this.DecrementPosition();
                        break;

                    case ParseState.AttributeAfterEquals:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            continue;
                        }

                        if ((this.currentchar == '\'') || (this.currentchar == '"'))
                        {
                            this.state = ParseState.QuotedAttributeValue;
                            this.PushAttributeValueStart(this.cuurrentindex, this.currentchar);
                            lastquote = this.currentchar;
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.AttributeAfterEquals)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        this.PushAttributeValueStart(this.cuurrentindex - 1);
                        this.state = ParseState.AttributeValue;
                        break;

                    case ParseState.AttributeValue:
                        if (this.NewCheck())
                        {
                            continue;
                        }

                        if (IsWhiteSpace(this.currentchar))
                        {
                            this.PushAttributeValueEnd(this.cuurrentindex - 1);
                            this.state = ParseState.BetweenAttributes;
                            continue;
                        }

                        if (this.currentchar == '>')
                        {
                            this.PushAttributeValueEnd(this.cuurrentindex - 1);
                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            if (this.state != ParseState.AttributeValue)
                            {
                                continue;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        break;

                    case ParseState.QuotedAttributeValue:
                        if (this.currentchar == lastquote)
                        {
                            this.PushAttributeValueEnd(this.cuurrentindex - 1);
                            this.state = ParseState.BetweenAttributes;
                            continue;
                        }

                        if (this.currentchar == '<')
                        {
                            if (this.cuurrentindex < this.Text.Length)
                            {
                                if (this.Text[this.cuurrentindex] == '%')
                                {
                                    this.oldstate = this.state;
                                    this.state = ParseState.ServerSideCode;
                                    continue;
                                }
                            }
                        }

                        break;

                    case ParseState.Comment:
                        if (this.currentchar == '>')
                        {
                            if (this.fullcomment)
                            {
                                if ((this.Text[this.cuurrentindex - 2] != '-') || (this.Text[this.cuurrentindex - 3] != '-'))
                                {
                                    continue;
                                }
                            }

                            if (!this.PushNodeEnd(this.cuurrentindex, false))
                            {
                                // stop parsing
                                this.cuurrentindex = this.Text.Length;
                                break;
                            }

                            this.state = ParseState.Text;
                            this.PushNodeStart(HtmlNodeType.Text, this.cuurrentindex);
                            continue;
                        }

                        break;

                    case ParseState.ServerSideCode:
                        if (this.currentchar == '%')
                        {
                            if (this.cuurrentindex < this.Text.Length)
                            {
                                if (this.Text[this.cuurrentindex] == '>')
                                {
                                    switch (this.oldstate)
                                    {
                                        case ParseState.AttributeAfterEquals:
                                            this.state = ParseState.AttributeValue;
                                            break;

                                        case ParseState.BetweenAttributes:
                                            this.PushAttributeNameEnd(this.cuurrentindex + 1);
                                            this.state = ParseState.BetweenAttributes;
                                            break;

                                        default:
                                            this.state = this.oldstate;
                                            break;
                                    }

                                    this.IncrementPosition();
                                }
                            }
                        }

                        break;

                    case ParseState.PcData:

                        // look for </tag + 1 char

                        // check buffer end
                        if ((this.currentnode.NameLength + 3) <= (this.Text.Length - (this.cuurrentindex - 1)))
                        {
                            if (string.Compare(
                                this.Text.Substring(this.cuurrentindex - 1, this.currentnode.NameLength + 2),
                                "</" + this.currentnode.NodeName,
                                StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                int c = this.Text[this.cuurrentindex - 1 + 2 + this.currentnode.NodeName.Length];
                                if ((c == '>') || IsWhiteSpace(c))
                                {
                                    // add the script as a text node
                                    HtmlNode script = this.CreateNode(
                                        HtmlNodeType.Text,
                                        this.currentnode.OuterStartIndex + this.currentnode.OuterLength);
                                    script.OuterLength = this.cuurrentindex - 1 - script.OuterStartIndex;
                                    this.currentnode.AppendChild(script);

                                    this.PushNodeStart(HtmlNodeType.Element, this.cuurrentindex - 1);
                                    this.PushNodeNameStart(false, this.cuurrentindex - 1 + 2);
                                    this.state = ParseState.Tag;
                                    this.IncrementPosition();
                                }
                            }
                        }

                        break;
                }
            }

            // finish the current work
            if (this.currentnode.NameStartIndex > 0)
            {
                this.PushNodeNameEnd(this.cuurrentindex);
            }

            this.PushNodeEnd(this.cuurrentindex, false);

            // we don't need this anymore
            this.LastNodes.Clear();
        }