namespace XFESystem.Documents;
public static class WebsiteAssets
{
public const string BaseUri = "https://xfe-resources.invalid/Documents/";
public static IReadOnlyList<string> StyleNames { get; } = Array.AsReadOnly(new[]
{ "CodeStyle.css", "MarkdownStyle.css", "Log.css", "Terminal.css", "Katex.min.css" });
public static IReadOnlyList<string> 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<string, string> Values = Load();
private static IReadOnlyDictionary<string, string> Load()
{
const string prefix = "Documents/Website/";
const int maximumEntries = 512, maximumResourceBytes = 8_388_608, maximumCharacters = 16_777_216;
var values = new Dictionary<string, string>(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<string, string>(values);
}
}
public static int PrewarmTextResources() => ImmutableTextResources.Values.Count;
/// <summary>Original website URL paths routed to immutable embedded bytes.</summary>
public static IReadOnlyList<WebsiteWebResource> 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));
}
}
namespace XFESystem.Documents;
public static class WebsiteAssets
{
public const string BaseUri = "https://xfe-resources.invalid/Documents/";
public static IReadOnlyList<string> StyleNames { get; } = Array.AsReadOnly(new[]
{ "CodeStyle.css", "MarkdownStyle.css", "Log.css", "Terminal.css", "Katex.min.css" });
public static IReadOnlyList<string> 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<string, string> Values = Load();
private static IReadOnlyDictionary<string, string> Load()
{
const string prefix = "Documents/Website/";
const int maximumEntries = 512, maximumResourceBytes = 8_388_608, maximumCharacters = 16_777_216;
var values = new Dictionary<string, string>(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<string, string>(values);
}
}
public static int PrewarmTextResources() => ImmutableTextResources.Values.Count;
/// <summary>Original website URL paths routed to immutable embedded bytes.</summary>
public static IReadOnlyList<WebsiteWebResource> 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));
}
}