namespace XFESystem.Documents; public static class WebsiteAssets { public const string BaseUri = "https://xfe-resources.invalid/Documents/"; public static IReadOnlyList StyleNames { get; } = Array.AsReadOnly(new[] { "CodeStyle.css", "MarkdownStyle.css", "Log.css", "Terminal.css", "Katex.min.css" }); public static IReadOnlyList ScriptNames { get; } = Array.AsReadOnly(new[] { "Highlight.min.js", "Xaml.js", "CSharp.js", "Bash.js", "PowerShell.js", "Dos.js", "Log.js", "PlainText.js", "Katex.min.js", "AutoRender.min.js", "CodeBlockTools.js", "DocUtils.js" }); public static Stream Open(string name) { ValidateName(name); return typeof(WebsiteAssets).Assembly.GetManifestResourceStream("Documents/Website/" + name) ?? throw new FileNotFoundException("The requested bundled document resource does not exist.", name); } public static string ReadText(string name) { ValidateName(name); if (ImmutableTextResources.Values.TryGetValue(name, out var text)) return text; // Keep the legacy decoding behavior for unusual callers of ReadText on // binary assets, without retaining decoded font garbage for the boot. using var reader = new StreamReader(Open(name)); return reader.ReadToEnd(); } // Decode each finite embedded resource once, before native heap fragmentation // makes multi-megabyte strings difficult to allocate. Static initialization // publishes the completed read-only catalog atomically across threads; reads // never mutate it, evict entries, hold an engine lock or decode again. private static class ImmutableTextResources { internal static readonly IReadOnlyDictionary Values = Load(); private static IReadOnlyDictionary Load() { const string prefix = "Documents/Website/"; const int maximumEntries = 512, maximumResourceBytes = 8_388_608, maximumCharacters = 16_777_216; var values = new Dictionary(StringComparer.Ordinal); long characters = 0; foreach (string resource in typeof(WebsiteAssets).Assembly.GetManifestResourceNames().OrderBy(name => name, StringComparer.Ordinal)) { if (!resource.StartsWith(prefix, StringComparison.Ordinal)) continue; string extension = Path.GetExtension(resource).ToLowerInvariant(); if (extension is not (".js" or ".css" or ".json" or ".md" or ".txt" or ".html" or ".htm")) continue; if (values.Count == maximumEntries) throw new InvalidDataException("The bundled document text catalog exceeds its entry limit."); using var stream = typeof(WebsiteAssets).Assembly.GetManifestResourceStream(resource)!; if (stream.Length > maximumResourceBytes) throw new InvalidDataException("A bundled document resource exceeds its byte limit."); // Keep the original ReadText UTF-8/BOM semantics exactly. Open // remains the byte-exact API, including for binary font assets. using var reader = new StreamReader(stream); string text = reader.ReadToEnd(); if (text.Length > maximumCharacters - characters) throw new InvalidDataException("The bundled document text catalog exceeds its character limit."); values.Add(resource[prefix.Length..], text); characters += text.Length; } return new System.Collections.ObjectModel.ReadOnlyDictionary(values); } } public static int PrewarmTextResources() => ImmutableTextResources.Values.Count; /// Original website URL paths routed to immutable embedded bytes. public static IReadOnlyList WebResources => WebsiteWebResourceCatalog.Resources; public static bool TryOpenWebPath(string path, out Stream? stream, out string contentType) { stream = null; contentType = string.Empty; if (string.IsNullOrEmpty(path) || path.Contains('\\') || path.Contains('?') || path.Contains('#') || path.Split('/').Skip(1).Any(segment => segment is "" or "." or "..")) return false; foreach (var resource in WebResources) { if (!string.Equals(path, resource.UrlPath, StringComparison.Ordinal)) continue; stream = Open(resource.AssetName); contentType = resource.ContentType; return true; } return false; } public static bool TryReadWebText(string path, out string text, out string contentType) { text = contentType = string.Empty; if (string.IsNullOrEmpty(path) || path.Contains('\\') || path.Contains('?') || path.Contains('#') || path.Split('/').Skip(1).Any(segment => segment is "" or "." or "..")) return false; foreach (var resource in WebResources) { if (!string.Equals(path, resource.UrlPath, StringComparison.Ordinal)) continue; text = ReadText(resource.AssetName); contentType = resource.ContentType; return true; } return false; } private static void ValidateName(string name) { ArgumentException.ThrowIfNullOrWhiteSpace(name); if (name.Contains('\\') || name.StartsWith('/') || name.Split('/').Any(segment => segment is "" or "." or "..")) throw new ArgumentException("Invalid resource name.", nameof(name)); } }