AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.7.0" />

 HtmlParser

public sealed class HtmlParser
Represents the Tree construction as specified in 8.2.5 Tree construction, on the following page: http://www.w3.org/html/wg/drafts/html/master/syntax.html
using AngleSharp.DOM; using AngleSharp.DOM.Html; using AngleSharp.DOM.Mathml; using AngleSharp.DOM.Svg; using AngleSharp.Extensions; using AngleSharp.Html; using AngleSharp.Network; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AngleSharp.Parser.Html { [DebuggerStepThrough] public sealed class HtmlParser { private readonly HtmlTokenizer tokenizer; private readonly Document doc; private readonly List<Element> open; private readonly List<Element> formatting; private readonly Stack<HtmlTreeMode> templateMode; private readonly object sync; private HtmlTreeMode insert; private HtmlTreeMode originalInsert; private HTMLFormElement form; private bool frameset; private Element fragmentContext; private bool foster; private int nesting; private bool started; private HTMLScriptElement pendingParsingBlock; private Task<IDocument> task; public IDocument Result { get { Parse(); return doc; } } public bool IsAsync => task != null; public bool IsFragmentCase => fragmentContext != null; internal Element AdjustedCurrentNode { get { if (fragmentContext == null || open.Count != 1) return CurrentNode; return fragmentContext; } } internal Element CurrentNode { get { if (open.Count <= 0) return null; return open[open.Count - 1]; } } internal HTMLScriptElement PendingParsingBlock { get { return pendingParsingBlock; } set { pendingParsingBlock = value; } } public event EventHandler<ParseErrorEventArgs> ParseError { add { tokenizer.ErrorOccurred += value; } remove { tokenizer.ErrorOccurred -= value; } } public HtmlParser(string source, IConfiguration configuration = null) : this(new Document(new TextSource(source)) { Options = configuration }) { } public HtmlParser(Stream stream, IConfiguration configuration = null) : this(new Document(new TextSource(stream, configuration.DefaultEncoding())) { Options = configuration }) { } internal HtmlParser(Document document) { tokenizer = new HtmlTokenizer(document.Source); sync = new object(); started = false; doc = document; open = new List<Element>(); templateMode = new Stack<HtmlTreeMode>(); formatting = new List<Element>(); frameset = true; insert = HtmlTreeMode.Initial; } public Task<IDocument> ParseAsync() { return ParseAsync(CancellationToken.None); } public Task<IDocument> ParseAsync(CancellationToken cancelToken) { lock (sync) { if (!started) { started = true; task = KernelAsync(cancelToken); } } return task; } public IDocument Parse() { if (!started) { started = true; Kernel(); } return doc; } internal HtmlParser SwitchToFragment(Element context) { if (started) throw new InvalidOperationException("Fragment mode has to be activated before running the parser!"); string nodeName = context.NodeName; if (nodeName.IsOneOf(Tags.Title, Tags.Textarea)) tokenizer.State = HtmlParseMode.RCData; else if (nodeName.IsOneOf(Tags.Style, Tags.Xmp, Tags.Iframe, Tags.NoEmbed, Tags.NoFrames)) { tokenizer.State = HtmlParseMode.Rawtext; } else if (nodeName == Tags.Script) { tokenizer.State = HtmlParseMode.Script; } else if (nodeName == Tags.Plaintext) { tokenizer.State = HtmlParseMode.Plaintext; } else if (nodeName == Tags.NoScript && doc.Options.IsScripting) { tokenizer.State = HtmlParseMode.Rawtext; } HTMLHtmlElement hTMLHtmlElement = new HTMLHtmlElement(); hTMLHtmlElement.Owner = doc; HTMLHtmlElement hTMLHtmlElement2 = hTMLHtmlElement; doc.AddNode(hTMLHtmlElement2); open.Add(hTMLHtmlElement2); if (context is HTMLTemplateElement) templateMode.Push(HtmlTreeMode.InTemplate); Reset(context); fragmentContext = context; tokenizer.IsAcceptingCharacterData = !AdjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember); do { if (context is HTMLFormElement) { form = (HTMLFormElement)context; break; } context = (context.ParentElement as Element); } while (context != null); return this; } private void Reset(Node context = null) { bool flag = false; int num = open.Count - 1; while (true) { if (num < 0) return; Node node = open[num]; if (num == 0) { flag = true; node = (context ?? node); } string nodeName = node.NodeName; if (nodeName == Tags.Select) { insert = HtmlTreeMode.InSelect; return; } if (nodeName.IsOneOf(Tags.Th, Tags.Td)) { insert = (flag ? HtmlTreeMode.InBody : HtmlTreeMode.InCell); return; } if (nodeName == Tags.Tr) { insert = HtmlTreeMode.InRow; return; } if (nodeName.IsOneOf(Tags.Thead, Tags.Tfoot, Tags.Tbody)) { insert = HtmlTreeMode.InTableBody; return; } if (nodeName == Tags.Body) { insert = HtmlTreeMode.InBody; return; } if (nodeName == Tags.Table) { insert = HtmlTreeMode.InTable; return; } if (nodeName == Tags.Caption) { insert = HtmlTreeMode.InCaption; return; } if (nodeName == Tags.Colgroup) { insert = HtmlTreeMode.InColumnGroup; return; } if (nodeName == Tags.Template) { insert = templateMode.Peek(); return; } if (nodeName == Tags.Html) { insert = HtmlTreeMode.BeforeHead; return; } if (nodeName == Tags.Head) { insert = (flag ? HtmlTreeMode.InBody : HtmlTreeMode.InHead); return; } if (nodeName == Tags.Frameset) { insert = HtmlTreeMode.InFrameset; return; } if (flag) break; num--; } insert = HtmlTreeMode.InBody; } private void Consume(HtmlToken token) { Element adjustedCurrentNode = AdjustedCurrentNode; if (adjustedCurrentNode == null || token.IsEof || adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlTip) && token.IsHtmlCompatible) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.MathTip) && token.IsMathCompatible) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.MathMember) && token.IsSvg && adjustedCurrentNode.NodeName == Tags.AnnotationXml)) Home(token); else Foreign(token); } private void Home(HtmlToken token) { switch (insert) { case HtmlTreeMode.Initial: Initial(token); break; case HtmlTreeMode.BeforeHtml: BeforeHtml(token); break; case HtmlTreeMode.BeforeHead: BeforeHead(token); break; case HtmlTreeMode.InHead: InHead(token); break; case HtmlTreeMode.InHeadNoScript: InHeadNoScript(token); break; case HtmlTreeMode.AfterHead: AfterHead(token); break; case HtmlTreeMode.InBody: InBody(token); break; case HtmlTreeMode.Text: Text(token); break; case HtmlTreeMode.InTable: InTable(token); break; case HtmlTreeMode.InCaption: InCaption(token); break; case HtmlTreeMode.InColumnGroup: InColumnGroup(token); break; case HtmlTreeMode.InTableBody: InTableBody(token); break; case HtmlTreeMode.InRow: InRow(token); break; case HtmlTreeMode.InCell: InCell(token); break; case HtmlTreeMode.InSelect: InSelect(token); break; case HtmlTreeMode.InSelectInTable: InSelectInTable(token); break; case HtmlTreeMode.InTemplate: InTemplate(token); break; case HtmlTreeMode.AfterBody: AfterBody(token); break; case HtmlTreeMode.InFrameset: InFrameset(token); break; case HtmlTreeMode.AfterFrameset: AfterFrameset(token); break; case HtmlTreeMode.AfterAfterBody: AfterAfterBody(token); break; case HtmlTreeMode.AfterAfterFrameset: AfterAfterFrameset(token); break; } } private void Initial(HtmlToken token) { switch (token.Type) { case HtmlTokenType.DOCTYPE: { HtmlDoctypeToken htmlDoctypeToken = (HtmlDoctypeToken)token; if (!htmlDoctypeToken.IsValid) RaiseErrorOccurred(ErrorCode.DoctypeInvalid); AddDoctype(htmlDoctypeToken); if (htmlDoctypeToken.IsFullQuirks) doc.QuirksMode = QuirksMode.On; else if (htmlDoctypeToken.IsLimitedQuirks) { doc.QuirksMode = QuirksMode.Limited; } insert = HtmlTreeMode.BeforeHtml; return; } case HtmlTokenType.Character: token.TrimStart(); if (token.IsEmpty) return; break; case HtmlTokenType.Comment: doc.AddComment(token.Data); return; } if (!doc.Options.IsEmbedded) { RaiseErrorOccurred(ErrorCode.DoctypeMissing); doc.QuirksMode = QuirksMode.On; } insert = HtmlTreeMode.BeforeHtml; BeforeHtml(token); } private void BeforeHtml(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: token.TrimStart(); if (token.IsEmpty) return; break; case HtmlTokenType.Comment: doc.AddComment(token.Data); return; case HtmlTokenType.StartTag: if (!(token.Name != Tags.Html)) { AddRoot(token.AsTag()); insert = HtmlTreeMode.BeforeHead; return; } break; case HtmlTokenType.EndTag: if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br, Tags.Head)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; } BeforeHtml(HtmlToken.OpenTag(Tags.Html)); BeforeHead(token); } private void BeforeHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: token.TrimStart(); if (token.IsEmpty) return; break; case HtmlTokenType.StartTag: { string name = token.Name; if (name == Tags.Html) { InBody(token); return; } if (name == Tags.Head) { AddElement<HTMLHeadElement>(token.AsTag(), false); insert = HtmlTreeMode.InHead; return; } break; } case HtmlTokenType.EndTag: if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br, Tags.Head)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; } BeforeHead(HtmlToken.OpenTag(Tags.Head)); InHead(token); } private void InHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Html) { InBody(token); return; } if (name2 == Tags.Meta) { HTMLMetaElement hTMLMetaElement = AddElement<HTMLMetaElement>(token.AsTag(), true); CloseCurrentNode(); string attribute = hTMLMetaElement.GetAttribute(AttributeNames.Charset); if (attribute == null || !DocumentEncoding.IsSupported(attribute)) { attribute = hTMLMetaElement.GetAttribute(AttributeNames.HttpEquiv); if (attribute != null && attribute.Equals(HeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)) { attribute = (hTMLMetaElement.GetAttribute(AttributeNames.Content) ?? string.Empty); attribute = DocumentEncoding.Extract(attribute); if (DocumentEncoding.IsSupported(attribute)) SetCharset(attribute); } } else SetCharset(attribute); return; } if (name2.IsOneOf(Tags.Link, Tags.Base, Tags.BaseFont, Tags.Bgsound)) { AddElement(token.AsTag(), true); CloseCurrentNode(); return; } if (name2 == Tags.Title) { RCDataAlgorithm(token.AsTag()); return; } if (name2.IsOneOf(Tags.Style, Tags.NoFrames) || (doc.Options.IsScripting && name2 == Tags.NoScript)) { RawtextAlgorithm(token.AsTag()); return; } if (name2 == Tags.NoScript) { AddElement(token.AsTag(), false); insert = HtmlTreeMode.InHeadNoScript; return; } if (name2 == Tags.Script) { HTMLScriptElement hTMLScriptElement = AddElement<HTMLScriptElement>(token.AsTag(), false); hTMLScriptElement.IsParserInserted = true; hTMLScriptElement.IsAlreadyStarted = IsFragmentCase; tokenizer.State = HtmlParseMode.Script; originalInsert = insert; insert = HtmlTreeMode.Text; return; } if (name2 == Tags.Head) { RaiseErrorOccurred(ErrorCode.HeadTagMisplaced); return; } if (name2 == Tags.Template) { AddElement<HTMLTemplateElement>(token.AsTag(), false); formatting.AddScopeMarker(); frameset = false; insert = HtmlTreeMode.InTemplate; templateMode.Push(HtmlTreeMode.InTemplate); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.Head) { CloseCurrentNode(); insert = HtmlTreeMode.AfterHead; return; } if (name == Tags.Template) { if (TagCurrentlyOpen(Tags.Template)) { GenerateImpliedEndTags(); if (!(CurrentNode is HTMLTemplateElement)) RaiseErrorOccurred(ErrorCode.TagClosingMismatch); CloseTemplate(); } else RaiseErrorOccurred(ErrorCode.TagInappropriate); return; } if (!name.IsOneOf(Tags.Html, Tags.Body, Tags.Br)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; } } CloseCurrentNode(); insert = HtmlTreeMode.AfterHead; AfterHead(token); } private void InHeadNoScript(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: InHead(token); return; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2.IsOneOf(Tags.Style, Tags.Link, Tags.BaseFont, Tags.Meta, Tags.NoFrames, Tags.Bgsound)) { InHead(token); return; } if (name2 == Tags.Html) { InBody(token); return; } if (name2.IsOneOf(Tags.Head, Tags.NoScript)) { RaiseErrorOccurred(ErrorCode.TagInappropriate); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.NoScript) { CloseCurrentNode(); insert = HtmlTreeMode.InHead; return; } if (name != Tags.Br) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; } case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); CloseCurrentNode(); insert = HtmlTreeMode.InHead; InHead(token); } private void AfterHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name = token.Name; if (name == Tags.Html) { InBody(token); return; } if (name == Tags.Body) { AfterHeadStartTagBody(token.AsTag()); return; } if (name == Tags.Frameset) { AddElement<HTMLFrameSetElement>(token.AsTag(), false); insert = HtmlTreeMode.InFrameset; return; } if (name.IsOneOf(Tags.Link, Tags.Meta, Tags.Script, Tags.Style, Tags.Title) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound, Tags.NoFrames)) { RaiseErrorOccurred(ErrorCode.TagMustBeInHead); int count = open.Count; open.Add(doc.Head as Element); InHead(token); open.RemoveAt(count); return; } if (name == Tags.Head) { RaiseErrorOccurred(ErrorCode.HeadTagMisplaced); return; } break; } case HtmlTokenType.EndTag: if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; } AfterHeadStartTagBody(HtmlToken.OpenTag(Tags.Body)); frameset = true; Home(token); } private void InBodyStartTag(HtmlTagToken tag) { string name = tag.Name; if (name == Tags.Div) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement(tag, false); } else if (name == Tags.A) { for (int num = formatting.Count - 1; num >= 0; num--) { if (formatting[num] == null) break; if (formatting[num] is HTMLAnchorElement) { Element item = formatting[num]; RaiseErrorOccurred(ErrorCode.AnchorNested); HeisenbergAlgorithm(HtmlToken.CloseTag(Tags.A)); if (open.Contains(item)) open.Remove(item); if (formatting.Contains(item)) formatting.RemoveAt(num); break; } } ReconstructFormatting(); HTMLAnchorElement element = AddElement<HTMLAnchorElement>(tag, false); formatting.AddFormatting(element); } else if (name == Tags.Span) { ReconstructFormatting(); AddElement(tag, false); } else if (name == Tags.Li) { InBodyStartTagListItem(tag); } else if (name == Tags.Img) { InBodyStartTagBreakrow(tag); } else if (name.IsOneOf(Tags.Ul, Tags.P)) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement(tag, false); } else if (name == Tags.Script) { InHead(tag); } else if (name.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5)) { if (IsInButtonScope()) InBodyEndTagParagraph(); if (CurrentNode is HTMLHeadingElement) { RaiseErrorOccurred(ErrorCode.HeadingNested); CloseCurrentNode(); } AddElement(new HTMLHeadingElement(name) { Owner = doc }, tag, false); } else if (name == Tags.Input) { ReconstructFormatting(); AddElement<HTMLInputElement>(tag, true); CloseCurrentNode(); if (!tag.GetAttribute(AttributeNames.Type).Equals(AttributeNames.Hidden, StringComparison.OrdinalIgnoreCase)) frameset = false; } else if (name == Tags.Form) { if (form == null) { if (IsInButtonScope()) InBodyEndTagParagraph(); form = AddElement<HTMLFormElement>(tag, false); } else RaiseErrorOccurred(ErrorCode.FormAlreadyOpen); } else if (name.IsOneOf(Tags.Ol, Tags.Dl, Tags.Fieldset) || name.IsOneOf(Tags.Figcaption, Tags.Figure, Tags.Article, Tags.Aside, Tags.BlockQuote, Tags.Center) || name.IsOneOf(Tags.Address, Tags.Dialog, Tags.Dir, Tags.Summary, Tags.Details) || name.IsOneOf(Tags.Footer, Tags.Header, Tags.Nav, Tags.Section, Tags.Menu, Tags.Hgroup)) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement(tag, false); } else if (name.IsOneOf(Tags.B, Tags.Strong, Tags.Code, Tags.Em, Tags.U, Tags.I) || name.IsOneOf(Tags.Font, Tags.S, Tags.Small, Tags.Strike, Tags.Big, Tags.Tt)) { ReconstructFormatting(); HTMLElement element2 = HtmlElementFactory.Create(name, doc); AddElement(element2, tag, false); formatting.AddFormatting(element2); } else if (name.IsOneOf(Tags.Caption, Tags.Col, Tags.Colgroup) || name.IsOneOf(Tags.Frame, Tags.Head) || name.IsOneOf(Tags.Tbody, Tags.Td, Tags.Tfoot, Tags.Th, Tags.Thead, Tags.Tr)) { RaiseErrorOccurred(ErrorCode.TagCannotStartHere); } else if (name.IsOneOf(Tags.Style, Tags.Link) || name.IsOneOf(Tags.Meta, Tags.MenuItem, Tags.Title, Tags.NoFrames, Tags.Template) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound)) { InHead(tag); } else if (name.IsOneOf(Tags.Pre, Tags.Listing)) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement(new HTMLPreElement(name) { Owner = doc }, tag, false); frameset = false; PreventNewLine(); } else if (name == Tags.Button) { if (IsInScope<HTMLButtonElement>()) { RaiseErrorOccurred(ErrorCode.ButtonInScope); InBodyEndTagBlock(Tags.Button); InBody(tag); } else { ReconstructFormatting(); AddElement<HTMLButtonElement>(tag, false); frameset = false; } } else if (name == Tags.Table) { if (doc.QuirksMode == QuirksMode.Off && IsInButtonScope()) InBodyEndTagParagraph(); AddElement<HTMLTableElement>(tag, false); frameset = false; insert = HtmlTreeMode.InTable; } else if (name.IsOneOf(Tags.Br, Tags.Area, Tags.Embed, Tags.Keygen, Tags.Wbr)) { InBodyStartTagBreakrow(tag); } else if (name.IsOneOf(Tags.Param, Tags.Source, Tags.Track)) { AddElement(tag, true); CloseCurrentNode(); } else if (name == Tags.Hr) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement<HTMLHRElement>(tag, true); CloseCurrentNode(); frameset = false; } else if (name == Tags.Textarea) { AddElement<HTMLTextAreaElement>(tag, false); tokenizer.State = HtmlParseMode.RCData; originalInsert = insert; frameset = false; insert = HtmlTreeMode.Text; PreventNewLine(); } else if (name == Tags.Select) { ReconstructFormatting(); AddElement<HTMLSelectElement>(tag, false); frameset = false; switch (insert) { case HtmlTreeMode.InTable: case HtmlTreeMode.InCaption: case HtmlTreeMode.InRow: case HtmlTreeMode.InCell: insert = HtmlTreeMode.InSelectInTable; break; default: insert = HtmlTreeMode.InSelect; break; } } else if (name.IsOneOf(Tags.Optgroup, Tags.Option)) { if (CurrentNode is HTMLOptionElement) InBodyEndTagAnythingElse(HtmlToken.CloseTag(Tags.Option)); ReconstructFormatting(); AddElement(tag, false); } else if (name.IsOneOf(Tags.Dd, Tags.Dt)) { InBodyStartTagDefinitionItem(tag); } else if (name == Tags.Iframe) { frameset = false; RawtextAlgorithm(tag); } else if (name.IsOneOf(Tags.Applet, Tags.Marquee, Tags.Object)) { ReconstructFormatting(); AddElement(tag, false); formatting.AddScopeMarker(); frameset = false; } else if (name == Tags.Image) { RaiseErrorOccurred(ErrorCode.ImageTagNamedWrong); tag.Name = Tags.Img; InBodyStartTagBreakrow(tag); } else if (name == Tags.NoBr) { ReconstructFormatting(); if (IsInScope<HTMLNoNewlineElement>()) { RaiseErrorOccurred(ErrorCode.NobrInScope); HeisenbergAlgorithm(tag); ReconstructFormatting(); } HTMLElement element3 = HtmlElementFactory.Create(name, doc); AddElement(element3, tag, false); formatting.AddFormatting(element3); } else if (name == Tags.Xmp) { if (IsInButtonScope()) InBodyEndTagParagraph(); ReconstructFormatting(); frameset = false; RawtextAlgorithm(tag); } else if (name.IsOneOf(Tags.Rp, Tags.Rt)) { if (IsInScope<HTMLRubyElement>()) { GenerateImpliedEndTags(); if (!(CurrentNode is HTMLRubyElement)) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); } AddElement(tag, false); } else if (name == Tags.NoEmbed) { RawtextAlgorithm(tag); } else if (name == Tags.NoScript) { if (doc.Options.IsScripting) RawtextAlgorithm(tag); else { ReconstructFormatting(); AddElement(tag, false); } } else if (name == Tags.Math) { MathElement mathElement = new MathElement(name, NodeFlags.None); mathElement.Owner = doc; MathElement mathElement2 = mathElement; ReconstructFormatting(); for (int i = 0; i < tag.Attributes.Count; i++) { string key = tag.Attributes[i].Key; string value = tag.Attributes[i].Value; mathElement2.SetAdjustedAttribute(key.AdjustMathMLAttributeName(), value); } AddElement(mathElement2); if (tag.IsSelfClosing) open.Remove(mathElement2); } else if (name == Tags.Svg) { SVGElement sVGElement = new SVGElement(name, NodeFlags.None); sVGElement.Owner = doc; SVGElement sVGElement2 = sVGElement; ReconstructFormatting(); for (int j = 0; j < tag.Attributes.Count; j++) { string key2 = tag.Attributes[j].Key; string value2 = tag.Attributes[j].Value; sVGElement2.SetAdjustedAttribute(key2.AdjustSvgAttributeName(), value2); } AddElement(sVGElement2); if (tag.IsSelfClosing) open.Remove(sVGElement2); } else if (name == Tags.Plaintext) { if (IsInButtonScope()) InBodyEndTagParagraph(); AddElement(tag, false); tokenizer.State = HtmlParseMode.Plaintext; } else if (name == Tags.Frameset) { RaiseErrorOccurred(ErrorCode.FramesetMisplaced); if (open.Count != 1 && open[1] is HTMLBodyElement && frameset) { open[1].Parent.RemoveChild(open[1]); while (open.Count > 1) { CloseCurrentNode(); } AddElement<HTMLFrameSetElement>(tag, false); insert = HtmlTreeMode.InFrameset; } } else if (name == Tags.Html) { RaiseErrorOccurred(ErrorCode.HtmlTagMisplaced); if (templateMode.Count == 0) open[0].SetAttributes(tag.Attributes); } else if (name == Tags.Body) { RaiseErrorOccurred(ErrorCode.BodyTagMisplaced); if (templateMode.Count == 0 && open.Count > 1 && open[1] is HTMLBodyElement) { frameset = false; open[1].SetAttributes(tag.Attributes); } } else if (name == Tags.IsIndex) { RaiseErrorOccurred(ErrorCode.TagInappropriate); if (form == null) { InBody(HtmlToken.OpenTag(Tags.Form)); if (tag.GetAttribute(AttributeNames.Action) != string.Empty) form.SetAttribute(AttributeNames.Action, tag.GetAttribute(AttributeNames.Action)); InBody(HtmlToken.OpenTag(Tags.Hr)); InBody(HtmlToken.OpenTag(Tags.Label)); if (tag.GetAttribute(AttributeNames.Prompt) != string.Empty) AddCharacters(tag.GetAttribute(AttributeNames.Prompt)); else AddCharacters("This is a searchable index. Enter search keywords: "); HtmlTagToken htmlTagToken = HtmlToken.OpenTag(Tags.Input); htmlTagToken.AddAttribute(AttributeNames.Name, Tags.IsIndex); for (int k = 0; k < tag.Attributes.Count; k++) { if (!tag.Attributes[k].Key.IsOneOf(AttributeNames.Name, AttributeNames.Action, AttributeNames.Prompt)) htmlTagToken.AddAttribute(tag.Attributes[k].Key, tag.Attributes[k].Value); } InBody(htmlTagToken); InBody(HtmlToken.CloseTag(Tags.Label)); InBody(HtmlToken.OpenTag(Tags.Hr)); InBody(HtmlToken.CloseTag(Tags.Form)); } } else { ReconstructFormatting(); AddElement(tag, false); } } private void InBodyEndTag(HtmlTagToken tag) { string name = tag.Name; if (name == Tags.Div) InBodyEndTagBlock(name); else if (name == Tags.A) { HeisenbergAlgorithm(tag); } else if (name == Tags.Li) { if (IsInListItemScope()) { GenerateImpliedEndTagsExceptFor(name); if (!(CurrentNode is HTMLLIElement)) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo<HTMLLIElement>(); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.ListItemNotInScope); } else if (name == Tags.P) { InBodyEndTagParagraph(); } else if (name.IsOneOf(Tags.Ol, Tags.Ul, Tags.Dl, Tags.Fieldset, Tags.Button) || name.IsOneOf(Tags.Figcaption, Tags.Figure, Tags.Article, Tags.Aside, Tags.BlockQuote, Tags.Center) || name.IsOneOf(Tags.Address, Tags.Dialog, Tags.Dir, Tags.Summary, Tags.Details, Tags.Listing) || name.IsOneOf(Tags.Footer, Tags.Header, Tags.Nav, Tags.Section, Tags.Menu, Tags.Hgroup) || name.IsOneOf(Tags.Main, Tags.Pre)) { InBodyEndTagBlock(name); } else if (name.IsOneOf(Tags.B, Tags.Strong, Tags.Code) || name.IsOneOf(Tags.NoBr, Tags.Em, Tags.U, Tags.I) || name.IsOneOf(Tags.Font, Tags.S, Tags.Small, Tags.Strike, Tags.Big, Tags.Tt)) { HeisenbergAlgorithm(tag); } else if (name == Tags.Form) { HTMLFormElement hTMLFormElement = form; form = null; if (hTMLFormElement != null && IsInScope(hTMLFormElement.NodeName)) { GenerateImpliedEndTags(); if (CurrentNode != hTMLFormElement) RaiseErrorOccurred(ErrorCode.FormClosedWrong); open.Remove(hTMLFormElement); } else RaiseErrorOccurred(ErrorCode.FormNotInScope); } else if (name == Tags.Br) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); InBodyStartTagBreakrow(HtmlToken.OpenTag(Tags.Br)); } else if (name.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5)) { if (IsInScope<HTMLHeadingElement>()) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo<HTMLHeadingElement>(); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.HeadingNotInScope); } else if (name.IsOneOf(Tags.Dd, Tags.Dt)) { if (IsInScope(name)) { GenerateImpliedEndTagsExceptFor(name); if (CurrentNode.NodeName != name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(name); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.ListItemNotInScope); } else if (name.IsOneOf(Tags.Applet, Tags.Marquee, Tags.Object)) { if (IsInScope(name)) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(name); CloseCurrentNode(); formatting.ClearFormatting(); } else RaiseErrorOccurred(ErrorCode.ObjectNotInScope); } else if (name == Tags.Body) { InBodyEndTagBody(); } else if (name == Tags.Html) { if (InBodyEndTagBody()) AfterBody(tag); } else if (name == Tags.Template) { InHead(tag); } else { InBodyEndTagAnythingElse(tag); } } private void InBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: ReconstructFormatting(); AddCharacters(token.Data); if (token.HasContent) frameset = false; break; case HtmlTokenType.StartTag: InBodyStartTag(token.AsTag()); break; case HtmlTokenType.EndTag: InBodyEndTag(token.AsTag()); break; case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); break; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); break; case HtmlTokenType.EOF: CheckBodyOnClosing(); if (templateMode.Count != 0) InTemplate(token); else End(); break; } } private void Text(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Comment: break; case HtmlTokenType.Character: AddCharacters(token.Data); break; case HtmlTokenType.EndTag: if (token.Name != Tags.Script) { CloseCurrentNode(); insert = originalInsert; } else RunScript(CurrentNode as HTMLScriptElement); break; case HtmlTokenType.EOF: RaiseErrorOccurred(ErrorCode.EOF); CloseCurrentNode(); insert = originalInsert; Consume(token); break; } } private void InTable(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Caption) { ClearStackBackTo<HTMLTableElement>(); formatting.AddScopeMarker(); AddElement<HTMLTableCaptionElement>(token.AsTag(), false); insert = HtmlTreeMode.InCaption; } else if (name2 == Tags.Colgroup) { ClearStackBackTo<HTMLTableElement>(); AddElement<HTMLTableColgroupElement>(token.AsTag(), false); insert = HtmlTreeMode.InColumnGroup; } else if (name2 == Tags.Col) { InTable(HtmlToken.OpenTag(Tags.Colgroup)); InColumnGroup(token); } else if (name2.IsOneOf(Tags.Tbody, Tags.Thead, Tags.Tfoot)) { ClearStackBackTo<HTMLTableElement>(); HTMLTableSectionElement hTMLTableSectionElement = new HTMLTableSectionElement(name2); hTMLTableSectionElement.Owner = doc; HTMLTableSectionElement element = hTMLTableSectionElement; AddElement(element, token.AsTag(), false); insert = HtmlTreeMode.InTableBody; } else if (name2.IsOneOf(Tags.Td, Tags.Th, Tags.Tr)) { InTable(HtmlToken.OpenTag(Tags.Tbody)); InTableBody(token); } else if (name2 == Tags.Table) { RaiseErrorOccurred(ErrorCode.TableNesting); if (InTableEndTagTable()) Home(token); } else if (name2.IsOneOf(Tags.Script, Tags.Style, Tags.Template)) { InHead(token); } else if (name2 == Tags.Input) { HtmlTagToken htmlTagToken = token.AsTag(); if (htmlTagToken.GetAttribute(AttributeNames.Type).Equals(AttributeNames.Hidden, StringComparison.OrdinalIgnoreCase)) { RaiseErrorOccurred(ErrorCode.InputUnexpected); AddElement<HTMLInputElement>(htmlTagToken, true); CloseCurrentNode(); } else { RaiseErrorOccurred(ErrorCode.TokenNotPossible); InBodyWithFoster(token); } } else if (name2 == Tags.Form) { RaiseErrorOccurred(ErrorCode.FormInappropriate); if (form == null) { form = AddElement<HTMLFormElement>(token.AsTag(), false); CloseCurrentNode(); } } else { RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected); InBodyWithFoster(token); } return; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.Table) InTableEndTagTable(); else if (name == Tags.Template) { InHead(token); } else if (name.IsOneOf(Tags.Body, Tags.Colgroup, Tags.Col, Tags.Caption, Tags.Html) || name.IsOneOf(Tags.Tbody, Tags.Tr, Tags.Thead, Tags.Th, Tags.Tfoot, Tags.Td)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); } else { RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected); InBodyWithFoster(token); } return; } case HtmlTokenType.EOF: InBody(token); return; case HtmlTokenType.Character: if (CurrentNode.IsTableElement()) { InTableText(token); return; } break; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); InBodyWithFoster(token); } private void InTableText(HtmlToken token) { if (token.HasContent) { RaiseErrorOccurred(ErrorCode.TokenNotPossible); InBodyWithFoster(token); } else AddCharacters(token.Data); } private void InCaption(HtmlToken token) { switch (token.Type) { case HtmlTokenType.EndTag: { string name2 = token.Name; if (name2 == Tags.Caption) { InCaptionEndTagCaption(); return; } if (name2.IsOneOf(Tags.Body, Tags.Th, Tags.Colgroup, Tags.Html) || name2.IsOneOf(Tags.Tbody, Tags.Col, Tags.Tfoot, Tags.Td, Tags.Thead, Tags.Tr)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } if (name2 == Tags.Table) { RaiseErrorOccurred(ErrorCode.TableNesting); if (InCaptionEndTagCaption()) InTable(token); return; } break; } case HtmlTokenType.StartTag: { string name = token.Name; if (name.IsOneOf(Tags.Caption, Tags.Th, Tags.Colgroup) || name.IsOneOf(Tags.Tbody, Tags.Col, Tags.Tfoot, Tags.Td, Tags.Thead, Tags.Tr)) { RaiseErrorOccurred(ErrorCode.TagCannotStartHere); if (InCaptionEndTagCaption()) InTable(token); return; } break; } } InBody(token); } private void InColumnGroup(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); return; } case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Html) { InBody(token); return; } if (name2 == Tags.Col) { AddElement<HTMLTableColElement>(token.AsTag(), true); CloseCurrentNode(); return; } if (name2 == Tags.Template) { InHead(token); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.Colgroup) { InColumnGroupEndTagColgroup(); return; } if (name == Tags.Col) { RaiseErrorOccurred(ErrorCode.TagClosedWrong); return; } if (name == Tags.Template) { InHead(token); return; } break; } case HtmlTokenType.EOF: InBody(token); return; } if (InColumnGroupEndTagColgroup()) InTable(token); } private void InTableBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Tr) { ClearStackBackTo<HTMLTableSectionElement>(); AddElement<HTMLTableRowElement>(token.AsTag(), false); insert = HtmlTreeMode.InRow; return; } if (name2.IsTableCellElement()) { InTableBody(HtmlToken.OpenTag(Tags.Tr)); InRow(token); return; } if (name2.IsGeneralTableElement(false)) { InTableBodyCloseTable(token.AsTag()); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name.IsTableSectionElement()) { if (IsInTableScope(name)) { ClearStackBackTo<HTMLTableSectionElement>(); CloseCurrentNode(); insert = HtmlTreeMode.InTable; } else RaiseErrorOccurred(ErrorCode.TableSectionNotInScope); return; } if (name.IsSpecialTableElement(true)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } if (name == Tags.Table) { InTableBodyCloseTable(token.AsTag()); return; } break; } } InTable(token); } private void InRow(HtmlToken token) { switch (token.Type) { case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2.IsTableCellElement()) { ClearStackBackTo<HTMLTableRowElement>(); HTMLElement element = HtmlElementFactory.Create(name2, doc); AddElement(element, token.AsTag(), false); insert = HtmlTreeMode.InCell; formatting.AddScopeMarker(); return; } if (name2.IsGeneralTableElement(true)) { if (InRowEndTagTablerow()) InTableBody(token); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.Tr) { InRowEndTagTablerow(); return; } if (name == Tags.Table) { if (InRowEndTagTablerow()) InTableBody(token); return; } if (name.IsTableSectionElement()) { if (IsInTableScope(name)) { InRowEndTagTablerow(); InTableBody(token); } else RaiseErrorOccurred(ErrorCode.TableSectionNotInScope); return; } if (name.IsSpecialTableElement(false)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); return; } break; } } InTable(token); } private void InCell(HtmlToken token) { switch (token.Type) { case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2.IsTableCellElement() || name2.IsGeneralTableElement(true)) { if (IsInTableScope(Tags.Td) || IsInTableScope(Tags.Th)) { InCellEndTagCell(); Home(token); } else RaiseErrorOccurred(ErrorCode.TableCellNotInScope); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name.IsTableCellElement()) InCellEndTagCell(); else if (name.IsSpecialTableElement(false)) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); } else if (name.IsTableElement()) { if (IsInTableScope(name)) { InCellEndTagCell(); Home(token); } else RaiseErrorOccurred(ErrorCode.TableNotInScope); } else { InBody(token); } return; } } InBody(token); } private void InSelect(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: AddCharacters(token.Data); break; case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); break; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); break; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Html) InBody(token); else if (name2 == Tags.Option) { if (CurrentNode is HTMLOptionElement) InSelectEndTagOption(); AddElement<HTMLOptionElement>(token.AsTag(), false); } else if (name2 == Tags.Optgroup) { if (CurrentNode is HTMLOptionElement) InSelectEndTagOption(); if (CurrentNode is HTMLOptGroupElement) InSelectEndTagOptgroup(); AddElement<HTMLOptGroupElement>(token.AsTag(), false); } else if (name2 == Tags.Select) { RaiseErrorOccurred(ErrorCode.SelectNesting); InSelectEndTagSelect(); } else if (name2.IsOneOf(Tags.Input, Tags.Keygen, Tags.Textarea)) { RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected); if (IsInSelectScope(Tags.Select)) { InSelectEndTagSelect(); Home(token); } } else if (name2.IsOneOf(Tags.Template, Tags.Script)) { InHead(token); } else { RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected); } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name == Tags.Template) InHead(token); else if (name == Tags.Optgroup) { InSelectEndTagOptgroup(); } else if (name == Tags.Option) { InSelectEndTagOption(); } else if (name == Tags.Select) { if (IsInSelectScope(Tags.Select)) InSelectEndTagSelect(); else RaiseErrorOccurred(ErrorCode.SelectNotInScope); } else { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); } break; } case HtmlTokenType.EOF: InBody(token); break; default: RaiseErrorOccurred(ErrorCode.TokenNotPossible); break; } } private void InSelectInTable(HtmlToken token) { switch (token.Type) { case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2.IsTableCellElement() || name2.IsTableElement() || name2 == Tags.Caption) { RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected); InSelectEndTagSelect(); Home(token); return; } break; } case HtmlTokenType.EndTag: { string name = token.Name; if (name.IsTableCellElement() || name.IsTableElement() || name == Tags.Caption) { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); if (IsInTableScope(name)) { InSelectEndTagSelect(); Home(token); } return; } break; } } InSelect(token); } private void InTemplate(HtmlToken token) { switch (token.Type) { case HtmlTokenType.StartTag: { string name = token.Name; if (name.IsOneOf(Tags.Link, Tags.Meta, Tags.Script, Tags.Style) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound, Tags.NoFrames, Tags.Template, Tags.Title)) InHead(token); else if (name.IsOneOf(Tags.Caption, Tags.Colgroup, Tags.Tbody, Tags.Tfoot, Tags.Thead)) { TemplateStep(token, HtmlTreeMode.InTable); } else if (name == Tags.Col) { TemplateStep(token, HtmlTreeMode.InColumnGroup); } else if (name == Tags.Tr) { TemplateStep(token, HtmlTreeMode.InTableBody); } else if (name.IsOneOf(Tags.Td, Tags.Th)) { TemplateStep(token, HtmlTreeMode.InRow); } else { TemplateStep(token, HtmlTreeMode.InBody); } break; } case HtmlTokenType.EndTag: if (token.Name == Tags.Template) InHead(token); else RaiseErrorOccurred(ErrorCode.TagCannotEndHere); break; case HtmlTokenType.EOF: if (TagCurrentlyOpen(Tags.Template)) { RaiseErrorOccurred(ErrorCode.EOF); CloseTemplate(); Home(token); } else End(); break; default: InBody(token); break; } } private void AfterBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); ReconstructFormatting(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: open[0].AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: if (token.Name == Tags.Html) { InBody(token); return; } break; case HtmlTokenType.EndTag: if (token.Name == Tags.Html) { if (IsFragmentCase) RaiseErrorOccurred(ErrorCode.TagInvalidInFragmentMode); else insert = HtmlTreeMode.AfterAfterBody; return; } break; case HtmlTokenType.EOF: End(); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); insert = HtmlTreeMode.InBody; InBody(token); } private void InFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name = token.Name; if (name == Tags.Html) { InBody(token); return; } if (name == Tags.Frameset) { AddElement<HTMLFrameSetElement>(token.AsTag(), false); return; } if (name == Tags.Frame) { AddElement<HTMLFrameElement>(token.AsTag(), true); CloseCurrentNode(); return; } if (name == Tags.NoFrames) { InHead(token); return; } break; } case HtmlTokenType.EndTag: if (!(token.Name != Tags.Frameset)) { if (CurrentNode != open[0]) { CloseCurrentNode(); if (!IsFragmentCase && !(CurrentNode is HTMLFrameSetElement)) insert = HtmlTreeMode.AfterFrameset; } else RaiseErrorOccurred(ErrorCode.CurrentNodeIsRoot); return; } break; case HtmlTokenType.EOF: if (CurrentNode != doc.DocumentElement) RaiseErrorOccurred(ErrorCode.CurrentNodeIsNotRoot); End(); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); } private void AfterFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { string text = token.TrimStart(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); return; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); return; case HtmlTokenType.StartTag: { string name = token.Name; if (name == Tags.Html) { InBody(token); return; } if (name == Tags.NoFrames) { InHead(token); return; } break; } case HtmlTokenType.EndTag: if (!(token.Name != Tags.Html)) { insert = HtmlTreeMode.AfterAfterFrameset; return; } break; case HtmlTokenType.EOF: End(); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); } private void AfterAfterBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Comment: doc.AddComment(token.Data); return; case HtmlTokenType.Character: { string text = token.TrimStart(); ReconstructFormatting(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.DOCTYPE: InBody(token); return; case HtmlTokenType.StartTag: if (!(token.Name != Tags.Html)) { InBody(token); return; } break; case HtmlTokenType.EOF: End(); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); insert = HtmlTreeMode.InBody; InBody(token); } private void AfterAfterFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Comment: doc.AddComment(token.Data); return; case HtmlTokenType.Character: { string text = token.TrimStart(); ReconstructFormatting(); AddCharacters(text); if (token.IsEmpty) return; break; } case HtmlTokenType.DOCTYPE: InBody(token); return; case HtmlTokenType.StartTag: { string name = token.Name; if (name == Tags.Html) { InBody(token); return; } if (name == Tags.NoFrames) { InHead(token); return; } break; } case HtmlTokenType.EOF: End(); return; } RaiseErrorOccurred(ErrorCode.TokenNotPossible); } private void TemplateStep(HtmlToken token, HtmlTreeMode mode) { templateMode.Pop(); templateMode.Push(mode); insert = mode; Home(token); } private void CloseTemplate() { while (open.Count > 0) { Element currentNode = CurrentNode; CloseCurrentNode(); if (currentNode is HTMLTemplateElement) break; } formatting.ClearFormatting(); templateMode.Pop(); Reset(null); } private void InTableBodyCloseTable(HtmlTagToken tag) { if (IsInTableScope<HTMLTableSectionElement>()) { ClearStackBackTo<HTMLTableSectionElement>(); CloseCurrentNode(); insert = HtmlTreeMode.InTable; InTable(tag); } else RaiseErrorOccurred(ErrorCode.TableSectionNotInScope); } private void InSelectEndTagOption() { if (CurrentNode is HTMLOptionElement) CloseCurrentNode(); else RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); } private void InSelectEndTagOptgroup() { if (open.Count > 1 && open[open.Count - 1] is HTMLOptionElement && open[open.Count - 2] is HTMLOptGroupElement) CloseCurrentNode(); if (CurrentNode is HTMLOptGroupElement) CloseCurrentNode(); else RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); } private bool InColumnGroupEndTagColgroup() { if (CurrentNode.NodeName == Tags.Colgroup) { CloseCurrentNode(); insert = HtmlTreeMode.InTable; return true; } RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); return false; } private void AfterHeadStartTagBody(HtmlTagToken token) { AddElement<HTMLBodyElement>(token, false); frameset = false; insert = HtmlTreeMode.InBody; } private void RawtextAlgorithm(HtmlTagToken tag) { HTMLElement element = HtmlElementFactory.Create(tag.Name, doc); AddElement(element, tag, false); originalInsert = insert; insert = HtmlTreeMode.Text; tokenizer.State = HtmlParseMode.Rawtext; } private void RCDataAlgorithm(HtmlTagToken tag) { HTMLElement element = HtmlElementFactory.Create(tag.Name, doc); AddElement(element, tag, false); originalInsert = insert; insert = HtmlTreeMode.Text; tokenizer.State = HtmlParseMode.RCData; } private void InBodyStartTagListItem(HtmlTagToken tag) { int num = open.Count - 1; Element element = open[num]; frameset = false; while (true) { if (element is HTMLLIElement && element.NodeName == Tags.Li) { InBody(HtmlToken.CloseTag(element.NodeName)); break; } if (!(element is HTMLAddressElement) && !(element is HTMLDivElement) && !(element is HTMLParagraphElement) && element.Flags.HasFlag(NodeFlags.Special)) break; element = open[--num]; } if (IsInButtonScope()) InBodyEndTagParagraph(); HTMLElement element2 = HtmlElementFactory.Create(tag.Name, doc); AddElement(element2, tag, false); } private void InBodyStartTagDefinitionItem(HtmlTagToken tag) { frameset = false; int num = open.Count - 1; Element element = open[num]; while (true) { if (element is HTMLLIElement && (element.NodeName == Tags.Dd || element.NodeName == Tags.Dt)) { InBody(HtmlToken.CloseTag(element.NodeName)); break; } if (element.Flags.HasFlag(NodeFlags.Special) && !(element is HTMLAddressElement) && !(element is HTMLDivElement) && !(element is HTMLParagraphElement)) break; element = open[--num]; } if (IsInButtonScope()) InBodyEndTagParagraph(); HTMLElement element2 = HtmlElementFactory.Create(tag.Name, doc); AddElement(element2, tag, false); } private bool InBodyEndTagBlock(string tagName) { if (IsInScope(tagName)) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != tagName) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(tagName); CloseCurrentNode(); return true; } RaiseErrorOccurred(ErrorCode.BlockNotInScope); return false; } private void HeisenbergAlgorithm(HtmlTagToken tag) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Element element; Element element2; while (true) { if (num >= 8) return; element = null; element2 = null; num++; num4 = 0; num2 = 0; for (int num5 = formatting.Count - 1; num5 >= 0; num5--) { if (formatting[num5] == null) break; if (formatting[num5].NodeName == tag.Name) { num4 = num5; element = formatting[num5]; break; } } if (element == null) { InBodyEndTagAnythingElse(tag); return; } int num6 = open.IndexOf(element); if (num6 == -1) { RaiseErrorOccurred(ErrorCode.FormattingElementNotFound); formatting.Remove(element); return; } if (!IsInScope(element.NodeName)) { RaiseErrorOccurred(ErrorCode.ElementNotInScope); return; } if (num6 != open.Count - 1) RaiseErrorOccurred(ErrorCode.TagClosedWrong); num3 = num4; for (int i = num6 + 1; i < open.Count; i++) { if (open[i].Flags.HasFlag(NodeFlags.Special)) { num4 = i; element2 = open[i]; break; } } if (element2 == null) break; Element element3 = open[num6 - 1]; Element element4 = element2; Element element5 = element2; while (true) { num2++; element4 = open[--num4]; if (element4 == element) break; if (num2 > 3 && formatting.Contains(element4)) formatting.Remove(element4); if (!formatting.Contains(element4)) open.Remove(element4); else { Element element6 = CopyElement(element4); element3.AddNode(element6); open[num4] = element6; for (int j = 0; j != formatting.Count; j++) { if (formatting[j] == element4) { formatting[j] = element6; break; } } element4 = element6; if (element5 == element2) num3++; if (element5.Parent != null) element5.Parent.RemoveChild(element5); element4.AddNode(element5); element5 = element4; } } if (!element3.IsTableElement()) { if (element5.Parent != null) element5.Parent.RemoveChild(element5); element3.AddNode(element5); } else AddElementWithFoster(element5); Element element7 = CopyElement(element); while (element2.ChildNodes.Length > 0) { Node node = element2.ChildNodes[0]; element2.RemoveNode(0, node); element7.AddNode(node); } element2.AddNode(element7); formatting.Remove(element); formatting.Insert(num3, element7); open.Remove(element); open.Insert(open.IndexOf(element2) + 1, element7); } do { element2 = CurrentNode; CloseCurrentNode(); } while (element2 != element); formatting.Remove(element); } private Element CopyElement(Element element) { HTMLElement hTMLElement = HtmlElementFactory.Create(element.NodeName, doc); foreach (IAttr attribute in element.Attributes) { hTMLElement.AddAttribute(attribute.Name, attribute.Value); } return hTMLElement; } private void InBodyWithFoster(HtmlToken token) { foster = true; InBody(token); foster = false; } private void InBodyEndTagAnythingElse(HtmlTagToken tag) { int num = open.Count - 1; Element element = CurrentNode; while (true) { if (element.NodeName == tag.Name) { GenerateImpliedEndTagsExceptFor(tag.Name); if (element.NodeName == tag.Name) RaiseErrorOccurred(ErrorCode.TagClosedWrong); int num2 = open.Count - 1; while (num <= num2) { CloseCurrentNode(); num2--; } return; } if (element.Flags.HasFlag(NodeFlags.Special)) break; element = open[--num]; } RaiseErrorOccurred(ErrorCode.TagClosedWrong); } private bool InBodyEndTagBody() { if (IsInScope<HTMLBodyElement>()) { CheckBodyOnClosing(); insert = HtmlTreeMode.AfterBody; return true; } RaiseErrorOccurred(ErrorCode.BodyNotInScope); return false; } private void InBodyStartTagBreakrow(HtmlTagToken tag) { ReconstructFormatting(); HTMLElement element = HtmlElementFactory.Create(tag.Name, doc); AddElement(element, tag, false); CloseCurrentNode(); frameset = false; } private bool InBodyEndTagParagraph() { if (IsInButtonScope()) { GenerateImpliedEndTagsExceptFor(Tags.P); if (!(CurrentNode is HTMLParagraphElement)) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo<HTMLParagraphElement>(); CloseCurrentNode(); return true; } RaiseErrorOccurred(ErrorCode.ParagraphNotInScope); InBody(HtmlToken.OpenTag(Tags.P)); InBodyEndTagParagraph(); return false; } private bool InTableEndTagTable() { if (IsInTableScope<HTMLTableElement>()) { ClearStackBackTo<HTMLTableElement>(); CloseCurrentNode(); Reset(null); return true; } RaiseErrorOccurred(ErrorCode.TableNotInScope); return false; } private bool InRowEndTagTablerow() { if (IsInTableScope<HTMLTableRowElement>()) { ClearStackBackTo<HTMLTableRowElement>(); CloseCurrentNode(); insert = HtmlTreeMode.InTableBody; return true; } RaiseErrorOccurred(ErrorCode.TableRowNotInScope); return false; } private void InSelectEndTagSelect() { ClearStackBackTo<HTMLSelectElement>(); CloseCurrentNode(); Reset(null); } private bool InCaptionEndTagCaption() { if (IsInTableScope<HTMLTableCaptionElement>()) { GenerateImpliedEndTags(); if (!(CurrentNode is HTMLTableCaptionElement)) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo<HTMLTableCaptionElement>(); CloseCurrentNode(); formatting.ClearFormatting(); insert = HtmlTreeMode.InTable; return true; } RaiseErrorOccurred(ErrorCode.CaptionNotInScope); return false; } private bool InCellEndTagCell() { if (IsInTableScope<HTMLTableCellElement>()) { GenerateImpliedEndTags(); if (!(CurrentNode is HTMLTableCellElement)) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo<HTMLTableCellElement>(); CloseCurrentNode(); formatting.ClearFormatting(); insert = HtmlTreeMode.InRow; return true; } RaiseErrorOccurred(ErrorCode.TableCellNotInScope); return false; } private void Foreign(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: AddCharacters(token.Data.Replace('', '�')); if (token.HasContent) frameset = false; break; case HtmlTokenType.Comment: CurrentNode.AddComment(token.Data); break; case HtmlTokenType.DOCTYPE: RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); break; case HtmlTokenType.StartTag: { string name2 = token.Name; if (name2 == Tags.Font) { HtmlTagToken htmlTagToken = token.AsTag(); for (int i = 0; i != htmlTagToken.Attributes.Count; i++) { if (htmlTagToken.Attributes[i].Key.IsOneOf(AttributeNames.Color, AttributeNames.Face, AttributeNames.Size)) { ForeignNormalTag(token); return; } } ForeignSpecialTag(htmlTagToken); } else if (name2.IsOneOf(Tags.B, Tags.Big, Tags.BlockQuote, Tags.Body, Tags.Br, Tags.Center) || name2.IsOneOf(Tags.Code, Tags.Dd, Tags.Div, Tags.Dl, Tags.Dt, Tags.Em) || name2.IsOneOf(Tags.Embed, Tags.Head, Tags.Hr, Tags.I, Tags.Img, Tags.Li, Tags.Ul) || name2.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5) || name2.IsOneOf(Tags.Listing, Tags.Main, Tags.Menu, Tags.Meta, Tags.NoBr, Tags.Ol) || name2.IsOneOf(Tags.P, Tags.Pre, Tags.Ruby, Tags.S, Tags.Small, Tags.Span, Tags.Strike) || name2.IsOneOf(Tags.Strong, Tags.Sub, Tags.Sup, Tags.Table, Tags.Tt, Tags.U, Tags.Var)) { ForeignNormalTag(token); } else { ForeignSpecialTag(token.AsTag()); } break; } case HtmlTokenType.EndTag: { string name = token.Name; Element element = CurrentNode; HTMLScriptElement hTMLScriptElement = element as HTMLScriptElement; if (hTMLScriptElement == null) { if (element.NodeName != name) RaiseErrorOccurred(ErrorCode.TagClosingMismatch); int num = open.Count - 1; while (true) { if (num <= 0) return; if (element.NodeName.Equals(name, StringComparison.OrdinalIgnoreCase)) { open.RemoveRange(num + 1, open.Count - num - 1); CloseCurrentNode(); return; } element = open[num - 1]; if (element.Flags.HasFlag(NodeFlags.HtmlMember)) break; num--; } Home(token); } else RunScript(hTMLScriptElement); break; } } } private void ForeignSpecialTag(HtmlTagToken tag) { Element element = CreateForeignElementFrom(tag); if (element != null) { AddForeignElement(element); if (!tag.IsSelfClosing) { open.Add(element); tokenizer.IsAcceptingCharacterData = true; } else if (tag.Name == Tags.Script) { Foreign(HtmlToken.CloseTag(Tags.Script)); } } } private Element CreateForeignElementFrom(HtmlTagToken tag) { if (AdjustedCurrentNode.Flags.HasFlag(NodeFlags.MathMember)) { MathElement mathElement = MathElementFactory.Create(tag.Name, doc); for (int i = 0; i < tag.Attributes.Count; i++) { string key = tag.Attributes[i].Key; string value = tag.Attributes[i].Value; mathElement.SetAdjustedAttribute(key.AdjustMathMLAttributeName(), value); } return mathElement; } if (AdjustedCurrentNode.Flags.HasFlag(NodeFlags.SvgMember)) { SVGElement sVGElement = SvgElementFactory.Create(tag.Name.AdjustSvgTagName(), doc); for (int j = 0; j < tag.Attributes.Count; j++) { string key2 = tag.Attributes[j].Key; string value2 = tag.Attributes[j].Value; sVGElement.SetAdjustedAttribute(key2.AdjustSvgAttributeName(), value2); } return sVGElement; } return null; } private void ForeignNormalTag(HtmlToken token) { RaiseErrorOccurred(ErrorCode.TagCannotStartHere); do { CloseCurrentNode(); if (CurrentNode is MathAnnotationXmlElement) { string attribute = CurrentNode.GetAttribute(AttributeNames.Encoding); if (!string.IsNullOrEmpty(attribute) && (attribute.Equals(MimeTypes.Html, StringComparison.OrdinalIgnoreCase) || attribute.Equals(MimeTypes.ApplicationXHtml, StringComparison.OrdinalIgnoreCase))) break; } } while ((CurrentNode.Flags & (NodeFlags.HtmlMember | NodeFlags.HtmlTip | NodeFlags.MathTip)) == NodeFlags.None); Consume(token); } private bool IsInScope(string tagName) { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element.NodeName == tagName) return true; if (element.Flags.HasFlag(NodeFlags.Scoped)) return false; } return false; } private bool IsInScope<T>() { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element is T) return true; if (element.Flags.HasFlag(NodeFlags.Scoped)) return false; } return false; } private bool IsInListItemScope() { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element is HTMLLIElement) return true; if (element.Flags.HasFlag(NodeFlags.HtmlListScoped)) return false; } return false; } private bool IsInButtonScope() { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element is HTMLParagraphElement) return true; if (element.Flags.HasFlag(NodeFlags.Scoped) || element is HTMLButtonElement) return false; } return false; } private bool IsInTableScope<T>() { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element is T) return true; if (element.Flags.HasFlag(NodeFlags.HtmlTableScoped)) return false; } return false; } private bool IsInTableScope(string tagName) { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element.NodeName == tagName) return true; if (element.Flags.HasFlag(NodeFlags.HtmlTableScoped)) return false; } return false; } private bool IsInSelectScope(string tagName) { for (int num = open.Count - 1; num >= 0; num--) { Element element = open[num]; if (element.NodeName == tagName) return true; if (!element.Flags.HasFlag(NodeFlags.HtmlSelectScoped)) return false; } return false; } private void Kernel() { HtmlToken htmlToken; do { htmlToken = tokenizer.Get(); Consume(htmlToken); } while (htmlToken.Type != HtmlTokenType.EOF); } private async Task<IDocument> KernelAsync(CancellationToken cancelToken) { ITextSource source = doc.Source; HtmlToken token; do { if (source.Length - source.Index < 1024) await source.Prefetch(8192, cancelToken).ConfigureAwait(false); token = tokenizer.Get(); Consume(token); } while (token.Type != HtmlTokenType.EOF); return doc; } private void RunScript(HTMLScriptElement script) { if (script != null) { doc.PerformMicrotaskCheckpoint(); doc.ProvideStableState(); CloseCurrentNode(); insert = originalInsert; nesting++; script.Prepare(); nesting--; if (pendingParsingBlock != null && nesting == 0) { do { script = pendingParsingBlock; pendingParsingBlock = null; doc.WaitForReady(); nesting++; script.Run(); nesting--; tokenizer.ResetInsertionPoint(); } while (pendingParsingBlock != null); } } } private void CheckBodyOnClosing() { int num = 0; while (true) { if (num >= open.Count) return; if (!open[num].Flags.HasFlag(NodeFlags.ImplicitelyClosed)) break; num++; } RaiseErrorOccurred(ErrorCode.BodyClosedWrong); } private bool TagCurrentlyOpen(string tagName) { for (int i = 0; i < open.Count; i++) { if (open[i].NodeName == tagName) return true; } return false; } private void PreventNewLine() { HtmlToken htmlToken = tokenizer.Get(); if (htmlToken.Type == HtmlTokenType.Character) htmlToken.RemoveNewLine(); Home(htmlToken); } private void SetCharset(string charset) { Encoding encoding = DocumentEncoding.Resolve(charset); if (encoding != null) doc.Source.CurrentEncoding = encoding; } private void End() { while (open.Count != 0) { CloseCurrentNode(); } doc.CloseCurrent(); } private void AddDoctype(HtmlDoctypeToken doctypeToken) { doc.AddNode(new DocumentType(doctypeToken.Name ?? string.Empty) { Owner = doc, SystemIdentifier = doctypeToken.SystemIdentifier, PublicIdentifier = doctypeToken.PublicIdentifier }); } private void AddRoot(HtmlTagToken tag) { HTMLHtmlElement hTMLHtmlElement = new HTMLHtmlElement(); hTMLHtmlElement.Owner = doc; HTMLHtmlElement hTMLHtmlElement2 = hTMLHtmlElement; doc.AddNode(hTMLHtmlElement2); SetupElement(hTMLHtmlElement2, tag, false); open.Add(hTMLHtmlElement2); tokenizer.IsAcceptingCharacterData = false; hTMLHtmlElement2.ApplyManifest(); } private void CloseCurrentNode() { if (open.Count > 0) { open[open.Count - 1].Close(); open.RemoveAt(open.Count - 1); Element adjustedCurrentNode = AdjustedCurrentNode; tokenizer.IsAcceptingCharacterData = (adjustedCurrentNode != null && !adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember)); } } private void SetupElement(Element element, HtmlTagToken tag, bool acknowledgeSelfClosing) { if (tag.IsSelfClosing && !acknowledgeSelfClosing) RaiseErrorOccurred(ErrorCode.TagCannotBeSelfClosed); element.SetAttributes(tag.Attributes); } private Element AddElement(HtmlTagToken tag, bool acknowledgeSelfClosing = false) { HTMLElement hTMLElement = HtmlElementFactory.Create(tag.Name, doc); SetupElement(hTMLElement, tag, acknowledgeSelfClosing); AddElement(hTMLElement); return hTMLElement; } private TElement AddElement<TElement>(HtmlTagToken tag, bool acknowledgeSelfClosing = false) where TElement : Element, new { TElement val = new TElement(); val.Owner = doc; TElement val2 = val; SetupElement(val2, tag, acknowledgeSelfClosing); AddElement(val2); return val2; } private void AddElement(Element element, HtmlTagToken tag, bool acknowledgeSelfClosing = false) { SetupElement(element, tag, acknowledgeSelfClosing); AddElement(element); } private void AddElement(Element element) { Element currentNode = CurrentNode; if (foster && currentNode.IsTableElement()) AddElementWithFoster(element); else currentNode.AddNode(element); open.Add(element); tokenizer.IsAcceptingCharacterData = !element.Flags.HasFlag(NodeFlags.HtmlMember); } private void AddElementWithFoster(Element element) { bool flag = false; int num = open.Count; while (--num != 0) { if (open[num] is HTMLTemplateElement) { open[num].AddNode(element); return; } if (open[num] is HTMLTableElement) { flag = true; break; } } Node node = open[num].Parent ?? open[num + 1]; if (flag && open[num].Parent != null) { int num2 = 0; while (true) { if (num2 >= node.ChildNodes.Length) return; if (node.ChildNodes[num2] == open[num]) break; num2++; } node.InsertNode(num2, element); } else node.AddNode(element); } private void AddForeignElement(Element element) { element.NamespaceUri = AdjustedCurrentNode.NamespaceUri; CurrentNode.AddNode(element); } private void AddCharacters(string text) { if (!string.IsNullOrEmpty(text)) { Element currentNode = CurrentNode; if (foster && currentNode.IsTableElement()) AddCharactersWithFoster(text); else currentNode.AppendText(text); } } private void AddCharactersWithFoster(string text) { bool flag = false; int num = open.Count; while (--num != 0) { if (open[num] is HTMLTemplateElement) { open[num].AppendText(text); return; } if (open[num] is HTMLTableElement) { flag = true; break; } } Node node = open[num].Parent ?? open[num + 1]; if (flag && open[num].Parent != null) { int num2 = 0; while (true) { if (num2 >= node.ChildNodes.Length) return; if (node.ChildNodes[num2] == open[num]) break; num2++; } node.InsertText(num2, text); } else node.AppendText(text); } private void ClearStackBackTo(string tagName) { Element currentNode = CurrentNode; while (currentNode.NodeName != tagName && !(currentNode is HTMLHtmlElement) && !(currentNode is HTMLTemplateElement)) { CloseCurrentNode(); currentNode = CurrentNode; } } private void ClearStackBackTo<T>() { Element currentNode = CurrentNode; while (!(currentNode is T) && !(currentNode is HTMLHtmlElement) && !(currentNode is HTMLTemplateElement)) { CloseCurrentNode(); currentNode = CurrentNode; } } private void GenerateImpliedEndTagsExceptFor(string tagName) { Element currentNode = CurrentNode; while (currentNode.Flags.HasFlag(NodeFlags.ImpliedEnd) && currentNode.NodeName != tagName) { CloseCurrentNode(); currentNode = CurrentNode; } } private void GenerateImpliedEndTags() { while (CurrentNode.Flags.HasFlag(NodeFlags.ImpliedEnd)) { CloseCurrentNode(); } } private void ReconstructFormatting() { if (formatting.Count != 0) { int i = formatting.Count - 1; Element element = formatting[i]; if (element != null && !open.Contains(element)) { while (i > 0) { element = formatting[--i]; if (element == null || open.Contains(element)) { i++; break; } } for (; i < formatting.Count; i++) { Element element2 = CopyElement(formatting[i]); AddElement(element2); formatting[i] = element2; } } } } private void RaiseErrorOccurred(ErrorCode code) { tokenizer.RaiseErrorOccurred(code); } } }