XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using AngleSharp.Xml.Parser;
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using Jint.Native;
using Jint.Runtime.Interop;

namespace XFESystem.Browser;

public sealed partial class DomBridge
{
    private readonly Dictionary<IDocument, string> parsedDocuments = new(ReferenceEqualityComparer.Instance);
    private readonly HashSet<IElement> inertParsedScripts = new(ReferenceEqualityComparer.Instance);
    private long parsedCharacters;
    internal bool IsInertParsedScript(IElement script) => inertParsedScripts.Contains(script);
    private JsValue CloneDomNode(INode original, bool deep)
    {
        var clone = original.Clone(deep); var result = Created(clone);
        var sources = SelfAndDescendants(original).Where(element => element.LocalName == "script");
        var copies = SelfAndDescendants(clone).Where(element => element.LocalName == "script");
        foreach (var pair in sources.Zip(copies)) if (inertParsedScripts.Contains(pair.First)) inertParsedScripts.Add(pair.Second);
        return result;
    }
    private void InstallDomParserCallback() => engine.SetValue("__xfeParseDom", new ClrFunction(engine, "parseFromString", (_, args) =>
    {
        string source = LimitedText(Value(args, 0)), mime = Argument(args, 1);
        if (mime is not ("text/html" or "text/xml" or "application/xml" or "application/xhtml+xml" or "image/svg+xml"))
            throw AdjacentError("TypeError", "Unsupported DOMParser MIME type.", 0);
        if (parsedDocuments.Count >= 32 || parsedCharacters + source.Length > limits.MaximumHtmlCharacters)
            throw new BrowserLimitException("DOMParser exceeds the page's detached-document budget.");
        IDocument parsed;
        if (mime == "text/html") parsed = new HtmlParser().ParseDocument(source);
        else
        {
            try
            {
                RejectXmlDeclarations(source);
                int nodes = 0;
                parsed = new XmlParser(new XmlParserOptions { IsSuppressingErrors = false, OnCreated = (_, _) =>
                {
                    if (++nodes > limits.MaximumDomNodes) throw new BrowserLimitException("XML parsing exceeds its node budget.");
                } }).ParseDocument(source);
            }
            catch (Exception error) when (error is XmlParseException or FormatException)
            {
                parsed = new HtmlParser().ParseDocument("");
                foreach (var child in parsed.ChildNodes.ToArray()) parsed.RemoveChild(child);
                var element = parsed.CreateElement("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
                element.TextContent = "XML parsing failed."; parsed.AppendChild(element);
            }
        }
        ValidateDocument(parsed, limits);
        if (parsedDocuments.Sum(pair => pair.Key.All.Count()) + parsed.All.Count() > limits.MaximumDomNodes)
            throw new BrowserLimitException("DOMParser exceeds the page's detached node budget.");
        parsedCharacters += source.Length; parsedDocuments.Add(parsed, mime);
        foreach (var script in parsed.QuerySelectorAll("script")) inertParsedScripts.Add(script);
        return Wrap(parsed);
    }));
    private static void RejectXmlDeclarations(string source)
    {
        // DOMParser never loads external entities or accepts document type
        // declarations. Skip inert comment/CDATA text before rejecting markup.
        for (int at = 0; (at = source.IndexOf("<!", at, StringComparison.Ordinal)) >= 0;)
        {
            string terminator;
            if (source.AsSpan(at).StartsWith("<!--", StringComparison.Ordinal)) terminator = "-->";
            else if (source.AsSpan(at).StartsWith("<![CDATA[", StringComparison.Ordinal)) terminator = "]]>";
            else throw new FormatException("XML declarations are unsupported.");
            int end = source.IndexOf(terminator, at + 2, StringComparison.Ordinal);
            if (end < 0) throw new FormatException("Unclosed XML comment/CDATA.");
            at = end + terminator.Length;
        }
    }
}