diff --git a/OpenDreamClient/Interface/Html/HtmlParser.cs b/OpenDreamClient/Interface/Html/HtmlParser.cs index 8d3b2904df..6be483a5ca 100644 --- a/OpenDreamClient/Interface/Html/HtmlParser.cs +++ b/OpenDreamClient/Interface/Html/HtmlParser.cs @@ -1,6 +1,8 @@ -using System.Text; -using OpenDreamShared.Dream; +using OpenDreamShared.Dream; using Robust.Shared.Utility; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; namespace OpenDreamClient.Interface.Html; @@ -11,6 +13,9 @@ public static class HtmlParser { private static readonly ISawmill Sawmill; private static readonly HashSet WarnedAttributes = new(); + private static Regex? _attributeMatchRegex; + private static Regex AttributeMatchRegex => _attributeMatchRegex ??= new Regex(@"[^ =]+(?:=(?:\w+|""[^""]*""|'[^']*'))?"); + static HtmlParser() { Sawmill = IoCManager.Resolve().GetSawmill("opendream.html_parser"); } @@ -33,6 +38,11 @@ void PushCurrentText() { currentText.Clear(); } + void SkipComment() { + while ((i - 2 < 0 || (text[i - 2] != '-' || text[i - 1] != '-' || text[i] != '>')) && text.Length > 2) + i++; + } + for (i = 0; i < text.Length; i++) { char c = text[i]; @@ -67,7 +77,10 @@ void PushCurrentText() { } string insideTag = currentText.ToString(); - string[] attributes = insideTag.Split(' ', StringSplitOptions.RemoveEmptyEntries); + string[] attributes = AttributeMatchRegex.Matches(insideTag) + .Where(x => x.Length > 0) + .Select(x => x.Value) + .ToArray(); string tagType = attributes[0].ToLowerInvariant(); currentText.Clear(); @@ -98,6 +111,12 @@ void PushCurrentText() { appendTo.Pop(); tags.Pop(); } else { + // If a comment contained other HTML tags, we need to make sure those also + // get skipped. + if (tagType == "!--") { + SkipComment(); + continue; + } if (!isSelfClosing) { tags.Push(tagType); } @@ -123,7 +142,7 @@ void PushCurrentText() { if (insideEntity.StartsWith('#')) { if (int.TryParse(insideEntity.Substring(1), out int result)) { - currentText.Append((char) result); + currentText.Append((char)result); } } else { switch (insideEntity) {