/************************************************************************* * ModernUO * * Copyright 2019-2026 - ModernUO Development Team * * Email: hi@modernuo.com * * File: Html.cs * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ using System; using System.Buffers; using System.Runtime.CompilerServices; using Server.Buffers; using Server.Text; namespace Server; public enum TextAlignment : byte { Left = 0, Center = 1, Right = 2 } public static class Html { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this string input) => Center(input.AsSpan()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this ReadOnlySpan input) => $"
{input}
"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(ref RawInterpolatedStringHandler input) { var str = input.Text.Center(); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this string input, int color) => Center(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this string input, ReadOnlySpan color) => Center(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this ReadOnlySpan input, int color) => $"
{input}
"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(this ReadOnlySpan input, ReadOnlySpan color) => $"
{input}
"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(ref RawInterpolatedStringHandler input, int color) { var str = input.Text.Center(color); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Center(ref RawInterpolatedStringHandler input, ReadOnlySpan color) { var str = input.Text.Center(color); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(this string input, int color) => Color(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(this string input, ReadOnlySpan color) => Color(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(this ReadOnlySpan input, int color) => $"{input}"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(this ReadOnlySpan input, ReadOnlySpan color) => $"{input}"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(ref RawInterpolatedStringHandler input, int color) { var str = input.Text.Color(color); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Color(ref RawInterpolatedStringHandler input, ReadOnlySpan color) { var str = input.Text.Color(color); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this string input) => Right(input.AsSpan()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this ReadOnlySpan input) => $"{input}"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(ref RawInterpolatedStringHandler input) { var str = input.Text.Right(); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this string input, int color) => Right(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this string input, ReadOnlySpan color) => Right(input.AsSpan(), color); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this ReadOnlySpan input, int color) => $"{input}"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(this ReadOnlySpan input, ReadOnlySpan color) => $"{input}"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(ref RawInterpolatedStringHandler input, int color) { var str = input.Text.Right(color); input.Clear(); return str; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string Right(ref RawInterpolatedStringHandler input, ReadOnlySpan color) { var str = input.Text.Right(color); input.Clear(); return str; } private static readonly SearchValues _htmlSearchValues = SearchValues.Create('<', '>', '&', '"', '\''); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string EscapeHtml(this string input) { if (string.IsNullOrEmpty(input)) { return input ?? ""; } return EscapeHtml(input.AsSpan()); } public static string EscapeHtml(this ReadOnlySpan input) { if (input.IsEmpty) { return string.Empty; } var indexOfAny = input.IndexOfAny(_htmlSearchValues); if (indexOfAny < 0) { return input.ToString(); } using var builder = ValueStringBuilder.Create(input.Length * 2); var lastIndex = 0; while (indexOfAny >= 0) { if (indexOfAny > lastIndex) { builder.Append(input[lastIndex..indexOfAny]); } var c = input[indexOfAny]; var replacement = c switch { '&' => "&", '<' => "<", '>' => ">", '"' => """, '\'' => "'" }; builder.Append(replacement); lastIndex = indexOfAny + 1; indexOfAny = input[lastIndex..].IndexOfAny(_htmlSearchValues); if (indexOfAny < 0) { break; } indexOfAny += lastIndex; } if (lastIndex < input.Length) { builder.Append(input[lastIndex..]); } var result = builder.ToString(); builder.Dispose(); return result; } public static string Build( ReadOnlySpan text, ReadOnlySpan color = default, int size = -1, byte fontStyle = 0, TextAlignment align = TextAlignment.Left ) { var arr = STArrayPool.Shared.Rent(BuildCharCount(text, color)); var bytesWritten = Build(text, arr.AsSpan(), color, size, fontStyle, align); var result = arr.AsSpan(0, bytesWritten).ToString(); STArrayPool.Shared.Return(arr); return result; } public static int BuildCharCount(ReadOnlySpan text, ReadOnlySpan color) => 61 + text.Length + color.Length; public static int Build( ReadOnlySpan text, Span dest, ReadOnlySpan color = default, int size = -1, byte fontStyle = 0, TextAlignment align = TextAlignment.Left ) { using var builder = new ValueStringBuilder(dest); if (align == TextAlignment.Right) { builder.Append(""); } else if (align == TextAlignment.Center) { builder.Append("
"); } if (color.Length > 0 || size > -1 || fontStyle > 0) { builder.Append(" 0) { builder.Append($" COLOR={color}"); } if (size > -1) { builder.Append($" SIZE={size}"); } if (fontStyle > 0) { builder.Append($" STYLE={fontStyle}"); } builder.Append($">{text}"); } else { builder.Append(text); } if (align == TextAlignment.Right) { builder.Append(""); } else if (align == TextAlignment.Center) { builder.Append("
"); } return builder.Length; } }