using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Cysharp.Text; using Microsoft.CodeAnalysis; using SmartFormat.Core.Extensions; using SmartFormat.Core.Formatting; using SmartFormat.Core.Output; using SmartFormat.Core.Parsing; using SmartFormat.Core.Settings; using SmartFormat.Extensions; using SmartFormat.Extensions.PersistentVariables; using SmartFormat.Pooling.ObjectPools; using SmartFormat.Pooling.SmartPools; using SmartFormat.Pooling.SpecializedPools; using SmartFormat.Utilities; using SmartFormat.ZString; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: InternalsVisibleTo("SmartFormat.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a1cdb8ba81e1a00f0f9509a8f0c896e0de0da6875652fffd44fb867e6b78fd78c31c6fdb07544b2ae53ed4b56daa90333d32ac14387f7f68d39165da8f99b8c294c1cee1bcc4bbcbe2dd73879824b53708837f425e2bf5c7d2cf868de9548c44871888bf9db5cb425064dda4b17134f8e3b52e1f686315a1832043c7b58fb0ac")] [assembly: InternalsVisibleTo("Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a1cdb8ba81e1a00f0f9509a8f0c896e0de0da6875652fffd44fb867e6b78fd78c31c6fdb07544b2ae53ed4b56daa90333d32ac14387f7f68d39165da8f99b8c294c1cee1bcc4bbcbe2dd73879824b53708837f425e2bf5c7d2cf868de9548c44871888bf9db5cb425064dda4b17134f8e3b52e1f686315a1832043c7b58fb0ac")] [assembly: AssemblyCompany("SmartFormat")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright 2011-2025 SmartFormat Project")] [assembly: AssemblyDescription("This package contains the core SmartFormat assemblies with core extensions built-in.\n\nSmartFormat is a lightweight text templating library written in C#.\nIt can format various data sources into a string with a minimal, intuitive syntax similar to string.Format.\nIt uses extensions to provide named placeholders, localization, pluralization, gender conjugation, and list and time formatting.\n ")] [assembly: AssemblyFileVersion("3.6.1")] [assembly: AssemblyInformationalVersion("3.6.1+ebf693558e4e511ae8542bdca527d55077296c4d")] [assembly: AssemblyProduct("SmartFormat")] [assembly: AssemblyTitle("SmartFormat")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/axuno/SmartFormat.git")] [assembly: AssemblyVersion("3.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SmartFormat { internal class Evaluator { internal readonly record struct FormatEventArgs(Format Format); internal readonly record struct OutputWrittenEventArgs(string WrittenValue); internal readonly record struct LiteralEventArgs(string Text); internal readonly record struct PlaceholderEventArgs(Placeholder Placeholder); internal readonly record struct SelectorValueEventArgs(Selector Selector, bool Success, Type? SourceType, object? Value); internal readonly record struct FormattingEventArgs(Selector Selector, object? Value, bool Success, Type? FormatterType); private readonly SmartFormatter _formatter; private readonly SmartSettings _settings; private readonly Registry _registry; internal EventHandler? OnFormat; internal EventHandler? OnLiteral; internal EventHandler? OnPlaceholder; internal EventHandler? OnSelectorValue; internal EventHandler? OnSelectorFailure; internal EventHandler? OnFormattingStart; internal EventHandler? OnOutputWritten; internal EventHandler? OnFormattingEnd; public event EventHandler? OnFormattingFailure; public Evaluator(SmartFormatter formatter) { _formatter = formatter; _settings = _formatter.Settings; _registry = _formatter.Registry; } public void WriteFormat(FormattingInfo formattingInfo) { Format format = formattingInfo.Format; OnFormat?.Invoke(this, new FormatEventArgs(format)); foreach (FormatItem item in format.Items) { if (item is LiteralText literalText) { OnLiteral?.Invoke(this, new LiteralEventArgs(literalText.ToString())); formattingInfo.Write(literalText.ToString().AsSpan()); continue; } Placeholder placeholder = (Placeholder)item; FormattingInfo formattingInfo2 = formattingInfo.CreateChild(placeholder); OnPlaceholder?.Invoke(this, new PlaceholderEventArgs(placeholder)); if (EvaluatePlaceholder(formattingInfo2)) { InvokeFormatters(formattingInfo2); } } } private bool EvaluatePlaceholder(FormattingInfo formattingInfo) { formattingInfo.Result = null; Placeholder placeholder = formattingInfo.Placeholder; try { EvaluateSelectors(formattingInfo); } catch (Exception innerException) { int startIndex = placeholder.Format?.StartIndex ?? placeholder.Selectors[placeholder.Selectors.Count - 1].EndIndex; FormatError(placeholder, innerException, startIndex, formattingInfo); return false; } return true; } public bool TryGetValue(FormattingInfo parentFormattingInfo, Placeholder placeholder, out object? result) { result = null; if (placeholder.Selectors.Count == 0) { result = parentFormattingInfo.CurrentValue; return true; } FormattingInfo formattingInfo = FormattingInfoPool.Instance.Get().Initialize(parentFormattingInfo, parentFormattingInfo.FormatDetails, placeholder, parentFormattingInfo.CurrentValue); parentFormattingInfo.Children.Add(formattingInfo); try { EvaluateSelectors(formattingInfo); result = formattingInfo.CurrentValue; return true; } catch { return false; } } private void EvaluateSelectors(FormattingInfo formattingInfo) { formattingInfo.Result = null; bool flag = true; foreach (Selector selector in formattingInfo.Placeholder.Selectors) { if (!SkipThisSelector(selector)) { formattingInfo.Selector = selector; (bool, Type) handled = _registry.InvokeSourceExtensions(formattingInfo); if (handled.Item1) { formattingInfo.CurrentValue = formattingInfo.Result; OnSelectorValue?.Invoke(this, new SelectorValueEventArgs(selector, handled.Item1, handled.Item2, formattingInfo.CurrentValue)); } else if (flag) { flag = false; HandleNestedScope(formattingInfo, selector, ref handled); OnSelectorValue?.Invoke(this, new SelectorValueEventArgs(selector, handled.Item1, handled.Item2, formattingInfo.CurrentValue)); } if (!handled.Item1) { OnSelectorFailure?.Invoke(this, new SelectorValueEventArgs(selector, handled.Item1, null, null)); throw formattingInfo.FormattingException("No source extension could handle the selector named \"" + selector.RawText + "\"", selector); } } } } private void HandleNestedScope(FormattingInfo formattingInfo, Selector selector, ref (bool Success, Type? SourceType) handled) { FormattingInfo formattingInfo2 = formattingInfo; while (!handled.Success && formattingInfo2.Parent != null) { formattingInfo2 = formattingInfo2.Parent; formattingInfo2.Selector = selector; formattingInfo2.Result = null; handled = _registry.InvokeSourceExtensions(formattingInfo2); if (handled.Success) { formattingInfo.CurrentValue = formattingInfo2.Result; } } } private bool SkipThisSelector(Selector selector) { if (selector.Length == 0) { return true; } if (selector.Operator.Length > 0 && selector.Operator[0] == _settings.Parser.AlignmentOperator) { return true; } return false; } private void InvokeFormatters(FormattingInfo formattingInfo) { if (formattingInfo.DisableFormattingExtensions) { return; } Placeholder placeholder = formattingInfo.Placeholder; try { OnFormattingStart?.Invoke(this, new FormattingEventArgs(formattingInfo.Selector, formattingInfo.CurrentValue, Success: true, null)); (bool, Type) tuple = _registry.InvokeFormatterExtensions(formattingInfo); OnFormattingEnd?.Invoke(this, new FormattingEventArgs(formattingInfo.Selector, formattingInfo.CurrentValue, tuple.Item1, tuple.Item2)); if (!tuple.Item1) { throw formattingInfo.FormattingException("No suitable Formatter could be found", formattingInfo.Format, formattingInfo.Selector?.SelectorIndex ?? (-1)); } } catch (Exception innerException) { int startIndex = placeholder.Format?.StartIndex ?? placeholder.Selectors[placeholder.Selectors.Count - 1].EndIndex; FormatError(placeholder, innerException, startIndex, formattingInfo); } } private void FormatError(FormatItem errorItem, Exception innerException, int startIndex, FormattingInfo formattingInfo) { FormattingErrorEventArgs formattingErrorEventArgs = new FormattingErrorEventArgs(errorItem.RawText, startIndex, _settings.Formatter.ErrorAction != FormatErrorAction.ThrowError); this.OnFormattingFailure?.Invoke(this, formattingErrorEventArgs); _formatter.FormatError(formattingErrorEventArgs); switch (_settings.Formatter.ErrorAction) { case FormatErrorAction.Ignore: break; case FormatErrorAction.ThrowError: throw (innerException as FormattingException) ?? new FormattingException(errorItem, innerException, startIndex); case FormatErrorAction.OutputErrorInResult: formattingInfo.FormatDetails.FormattingException = (innerException as FormattingException) ?? new FormattingException(errorItem, innerException, startIndex); formattingInfo.Write(innerException.Message); formattingInfo.FormatDetails.FormattingException = null; break; case FormatErrorAction.MaintainTokens: formattingInfo.Write(formattingInfo.Placeholder?.RawText ?? "'null'"); break; } } } public class FormattingErrorEventArgs : EventArgs { public string Placeholder { get; } public int ErrorIndex { get; } public bool IgnoreError { get; } internal FormattingErrorEventArgs(string rawText, int errorIndex, bool ignoreError) { Placeholder = rawText; ErrorIndex = errorIndex; IgnoreError = ignoreError; } } public static class Smart { private static SmartFormatter? _formatter; public static SmartFormatter Default { get { if (_formatter == null) { _formatter = CreateDefaultSmartFormat(); } return _formatter; } set { _formatter = value; } } public static string Format(string format, params object?[] args) { return Default.Format(format, args); } public static string Format(IFormatProvider provider, string format, params object?[] args) { return Default.Format(provider, format, args); } public static string Format(string format, object? arg0, object? arg1, object? arg2) { return Default.Format(format, arg0, arg1, arg2); } public static string Format(string format, object? arg0, object? arg1) { return Default.Format(format, arg0, arg1); } public static string Format(string format, object? arg0) { return Default.Format(format, arg0); } public static SmartFormatter CreateDefaultSmartFormat(SmartSettings? settings = null) { return new SmartFormatter(settings).AddExtensions(new StringSource(), new ListFormatter(), new DictionarySource(), new ValueTupleSource(), new ReflectionSource(), new DefaultSource(), new KeyValuePairSource()).AddExtensions(new PluralLocalizationFormatter(), new ConditionalFormatter(), new IsMatchFormatter(), new NullFormatter(), new ChooseFormatter(), new SubStringFormatter(), new DefaultFormatter()); } } public static class SmartExtensions { public static StringBuilder AppendSmart(this StringBuilder sb, string format, params object[] args) { StringOutput output = new StringOutput(sb); Smart.Default.FormatInto(output, format, args); return sb; } public static StringBuilder AppendLineSmart(this StringBuilder sb, string format, params object[] args) { sb.AppendSmart(format, args); sb.AppendLine(); return sb; } public static void WriteSmart(this TextWriter writer, string format, params object[] args) { TextWriterOutput output = new TextWriterOutput(writer); Smart.Default.FormatInto(output, format, args); } public static void WriteLineSmart(this TextWriter writer, string format, params object[] args) { writer.WriteSmart(format, args); writer.WriteLine(); } public static string FormatSmart(this string format, params object[] args) { return Smart.Format(format, args); } } public class SmartFormatter { internal List SourceExtensions => Registry.SourceExtensions; internal List FormatterExtensions => Registry.FormatterExtensions; public Parser Parser { get; } public SmartSettings Settings { get; } internal Registry Registry { get; } internal Evaluator Evaluator { get; } public event EventHandler? OnFormattingFailure; public SmartFormatter(SmartSettings? settings = null) { Settings = settings ?? new SmartSettings(); Parser = new Parser(Settings); Registry = new Registry(this); Evaluator = new Evaluator(this); } internal void FormatError(FormattingErrorEventArgs args) { this.OnFormattingFailure?.Invoke(this, args); } public IReadOnlyList GetSourceExtensions() { return Registry.GetSourceExtensions(); } public IReadOnlyList GetFormatterExtensions() { return Registry.GetFormatterExtensions(); } public SmartFormatter AddExtensions(params ISource[] sourceExtensions) { Registry.AddExtensions(sourceExtensions); return this; } public SmartFormatter AddExtensions(params IFormatter[] formatterExtensions) { Registry.AddExtensions(formatterExtensions); return this; } public SmartFormatter InsertExtension(int position, ISource sourceExtension) { Registry.InsertExtension(position, sourceExtension); return this; } public SmartFormatter InsertExtension(int position, IFormatter formatterExtension) { Registry.InsertExtension(position, formatterExtension); return this; } public T? GetSourceExtension() where T : class, ISource { return Registry.GetSourceExtension(); } public T? GetFormatterExtension() where T : class, IFormatter { return Registry.GetFormatterExtension(); } public bool RemoveSourceExtension() where T : class, ISource { return Registry.RemoveSourceExtension(); } public bool RemoveFormatterExtension() where T : class, IFormatter { return Registry.RemoveFormatterExtension(); } public string Format(string format, params object?[] args) { return Format((IFormatProvider?)null, format, (IList)args); } public string Format(string format, IList args) { return Format(null, format, args); } public string Format(IFormatProvider? provider, string format, params object?[] args) { return Format(provider, format, (IList)args); } public string Format(IFormatProvider? provider, string format, IList args) { Format format2 = Parser.ParseFormat(format); try { return Format(provider, format2, args); } finally { FormatPool.Instance.Return(format2); } } public string Format(Format formatParsed, params object?[] args) { return Format((IFormatProvider?)null, formatParsed, (IList)args); } public string Format(Format formatParsed, IList args) { return Format(null, formatParsed, args); } public string Format(IFormatProvider? provider, Format formatParsed, params object?[] args) { return Format(provider, formatParsed, (IList)args); } public string Format(IFormatProvider? provider, Format formatParsed, IList args) { using ZStringOutput zStringOutput = new ZStringOutput(ZStringBuilderUtilities.CalcCapacity(formatParsed)); FormatInto(zStringOutput, provider, formatParsed, args); return zStringOutput.ToString(); } public void Format(FormattingInfo formattingInfo) { Registry.ThrowIfNoExtensions(); Evaluator.WriteFormat(formattingInfo); } public void FormatInto(IOutput output, string format, params object?[] args) { FormatInto(output, format, (IList)args); } public void FormatInto(IOutput output, string format, IList args) { FormatInto(output, null, format, args); } public void FormatInto(IOutput output, IFormatProvider? provider, string format, IList args) { Format format2 = Parser.ParseFormat(format); try { FormatInto(output, provider, format2, args); } finally { FormatPool.Instance.Return(format2); } } public void FormatInto(IOutput output, IFormatProvider? provider, Format format, params object?[] args) { FormatInto(output, provider, format, (IList)args); } public void FormatInto(IOutput output, IFormatProvider? provider, Format formatParsed, IList args) { Registry.ThrowIfNoExtensions(); ExecuteFormattingAction(this, provider, formatParsed, args, output, Evaluator.WriteFormat); } private static void ExecuteFormattingAction(SmartFormatter formatter, IFormatProvider? provider, Format formatParsed, IList args, IOutput output, Action doWork) { object currentValue = ((args.Count > 0) ? args[0] : args); FormatDetails instance; using (FormatDetailsPool.Instance.Pool.Get(out instance)) { instance.Initialize(formatter, formatParsed, args, provider, output); FormattingInfo instance2; using (FormattingInfoPool.Instance.Pool.Get(out instance2)) { instance2.Initialize(instance, formatParsed, currentValue); doWork(instance2); } } } } } namespace SmartFormat.ZString { public struct ZCharArray : IDisposable { private static readonly ArrayPool Pool = ArrayPool.Create(10000000, 100); private char[]? _bufferArray; private int _currentLength; public const int DefaultBufferCapacity = 1000000; public const int MaxBufferCapacity = 10000000; internal Span Span { get { ThrowIfDisposed(); return _bufferArray.AsSpan(0, _currentLength); } } public int Length { get { ThrowIfDisposed(); return _currentLength; } } public int Capacity { get { ThrowIfDisposed(); return _bufferArray.Length; } } public bool IsDisposed => _bufferArray == null; public ZCharArray() : this(1000000) { } public ZCharArray(int length) { _bufferArray = Pool.Rent(length); _currentLength = 0; } public ReadOnlySpan GetSpan() { ThrowIfDisposed(); return _bufferArray.AsSpan(0, _currentLength); } public void Reset() { ThrowIfDisposed(); _currentLength = 0; } private void Grow(int length) { char[] array = Pool.Rent(length); Array.Copy(_bufferArray, array, Math.Min(_bufferArray.Length, length)); Pool.Return(_bufferArray); _bufferArray = array; } public void Write(Span data) { ThrowIfDisposed(); GrowBufferIfNeeded(data.Length); data.CopyTo(_bufferArray.AsSpan(_currentLength, data.Length)); _currentLength += data.Length; } public void Write(ReadOnlySpan data) { ThrowIfDisposed(); GrowBufferIfNeeded(data.Length); data.CopyTo(_bufferArray.AsSpan(_currentLength, data.Length)); _currentLength += data.Length; } public void Write(string data) { ThrowIfDisposed(); GrowBufferIfNeeded(data.Length); data.AsSpan().CopyTo(_bufferArray.AsSpan(_currentLength, data.Length)); _currentLength += data.Length; } public void Write(char c) { ThrowIfDisposed(); GrowBufferIfNeeded(1); _bufferArray[_currentLength++] = c; } public void Write(char c, int count) { ThrowIfDisposed(); GrowBufferIfNeeded(count); for (int i = 0; i < count; i++) { _bufferArray[_currentLength++] = c; } } public void Write(ISpanFormattable data, ReadOnlySpan format, IFormatProvider? provider = null) { ThrowIfDisposed(); int charsWritten; while (!data.TryFormat(_bufferArray.AsSpan(_currentLength), out charsWritten, format, provider)) { GrowBufferIfNeeded(1000); } _currentLength += charsWritten; } public void Write(IFormattable data, string format, IFormatProvider? provider = null) { ThrowIfDisposed(); ReadOnlySpan data2 = data.ToString(format, provider).AsSpan(); GrowBufferIfNeeded(data2.Length); Write(data2); } private void GrowBufferIfNeeded(int dataLength) { int num = _currentLength + dataLength; if (num > Capacity) { Grow(num * 2); } } private void ThrowIfDisposed() { if (IsDisposed) { throw new ObjectDisposedException("ZCharArray"); } } public override string ToString() { ThrowIfDisposed(); return new string(_bufferArray, 0, _currentLength); } public void Dispose() { if (!IsDisposed) { Pool.Return(_bufferArray); _bufferArray = null; } } } [ExcludeFromCodeCoverage] public class ZStringBuilder : IDisposable { private Utf16ValueStringBuilder _vsb; public int Length => ((Utf16ValueStringBuilder)(ref _vsb)).Length; public ZStringBuilder(bool disposeImmediately) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) _vsb = new Utf16ValueStringBuilder(disposeImmediately); } public ReadOnlySpan AsSpan() { return ((Utf16ValueStringBuilder)(ref _vsb)).AsSpan(); } public ReadOnlyMemory AsMemory() { return ((Utf16ValueStringBuilder)(ref _vsb)).AsMemory(); } public ArraySegment AsArraySegment() { return ((Utf16ValueStringBuilder)(ref _vsb)).AsArraySegment(); } public void Dispose() { ((Utf16ValueStringBuilder)(ref _vsb)).Dispose(); } public void Clear() { ((Utf16ValueStringBuilder)(ref _vsb)).Clear(); } public void TryGrow(int sizeHint) { ((Utf16ValueStringBuilder)(ref _vsb)).TryGrow(sizeHint); } public void Grow(int sizeHint) { ((Utf16ValueStringBuilder)(ref _vsb)).Grow(sizeHint); } public void AppendLine() { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(); } public void AppendLine(char value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(string value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(ReadOnlySpan value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(T value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(byte value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(byte value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(DateTime value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(DateTime value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(DateTimeOffset value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(DateTimeOffset value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(decimal value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(decimal value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(double value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(double value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(short value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(short value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(int value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(int value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(long value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(long value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(sbyte value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(sbyte value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(float value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(float value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(TimeSpan value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(TimeSpan value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(ushort value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(ushort value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(uint value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(uint value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(ulong value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(ulong value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void AppendLine(Guid value) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value); } public void AppendLine(Guid value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendLine(value, format); } public void Append(char value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(char value, int repeatCount) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, repeatCount); } public void Append(string value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(ReadOnlySpan value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(T value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(ZStringBuilder value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) ((Utf16ValueStringBuilder)(ref _vsb)).Append(value._vsb); } public void Append(byte value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(byte value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(DateTime value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(DateTime value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(DateTimeOffset value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(DateTimeOffset value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(decimal value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(decimal value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(double value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(double value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(short value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(short value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(int value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(int value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(long value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(long value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(sbyte value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(sbyte value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(float value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(float value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(TimeSpan value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(TimeSpan value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(ushort value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(ushort value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(uint value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(uint value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(ulong value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(ulong value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Append(Guid value) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value); } public void Append(Guid value, string format) { ((Utf16ValueStringBuilder)(ref _vsb)).Append(value, format); } public void Insert(int index, string value, int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Insert(index, value, count); } public void Insert(int index, string value) { ((Utf16ValueStringBuilder)(ref _vsb)).Insert(index, value); } public void Insert(int index, ReadOnlySpan value, int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Insert(index, value, count); } public void Replace(char oldChar, char newChar) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldChar, newChar); } public void Replace(char oldChar, char newChar, int startIndex, int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldChar, newChar, startIndex, count); } public void Replace(string oldValue, string newValue) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldValue, newValue); } public void Replace(ReadOnlySpan oldValue, ReadOnlySpan newValue) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldValue, newValue); } public void Replace(string oldValue, string newValue, int startIndex, int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldValue, newValue, startIndex, count); } public void Replace(ReadOnlySpan oldValue, ReadOnlySpan newValue, int startIndex, int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Replace(oldValue, newValue, startIndex, count); } public void ReplaceAt(char newChar, int replaceIndex) { ((Utf16ValueStringBuilder)(ref _vsb)).ReplaceAt(newChar, replaceIndex); } public void Remove(int startIndex, int length) { ((Utf16ValueStringBuilder)(ref _vsb)).Remove(startIndex, length); } public bool TryCopyTo(Span destination, out int charsWritten) { return ((Utf16ValueStringBuilder)(ref _vsb)).TryCopyTo(destination, ref charsWritten); } public override string ToString() { return ((object)(Utf16ValueStringBuilder)(ref _vsb)).ToString(); } public Memory GetMemory(int sizeHint) { return ((Utf16ValueStringBuilder)(ref _vsb)).GetMemory(sizeHint); } public Span GetSpan(int sizeHint) { return ((Utf16ValueStringBuilder)(ref _vsb)).GetSpan(sizeHint); } public void Advance(int count) { ((Utf16ValueStringBuilder)(ref _vsb)).Advance(count); } public void AppendFormat(ReadOnlySpan format, T1 arg1) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } public void AppendFormat(ReadOnlySpan format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } public void AppendFormat(string format, T1 arg1) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1); } public void AppendFormat(string format, T1 arg1, T2 arg2) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } public void AppendFormat(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } public void AppendJoin(char separator, params T[] values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, List values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, ReadOnlySpan values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, IEnumerable values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, ICollection values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, IList values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, IReadOnlyList values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(char separator, IReadOnlyCollection values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, params T[] values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, List values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, ReadOnlySpan values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, IEnumerable values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, ICollection values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, IList values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, IReadOnlyList values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } public void AppendJoin(string separator, IReadOnlyCollection values) { ((Utf16ValueStringBuilder)(ref _vsb)).AppendJoin(separator, values); } void IDisposable.Dispose() { ((Utf16ValueStringBuilder)(ref _vsb)).Dispose(); GC.SuppressFinalize(this); } } internal static class ZStringBuilderUtilities { internal const int DefaultBufferSize = 32768; internal static int CalcCapacity(Format format) { return format.Length + format.Items.Count * 8; } internal static ZStringBuilder CreateZStringBuilder() { return new ZStringBuilder(disposeImmediately: false); } internal static ZStringBuilder CreateZStringBuilder(Format format) { return CreateZStringBuilder(CalcCapacity(format)); } internal static ZStringBuilder CreateZStringBuilder(int capacity) { ZStringBuilder zStringBuilder = new ZStringBuilder(disposeImmediately: false); if (capacity > 32768) { zStringBuilder.Grow(capacity - 32768); } return zStringBuilder; } } [ExcludeFromCodeCoverage] public sealed class ZStringWriter : TextWriter { private readonly ZStringWriter _zw; private Encoding? _encoding; public override Encoding Encoding => _encoding ?? (_encoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false)); public ZStringWriter() : this(CultureInfo.CurrentCulture) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown _zw = new ZStringWriter((IFormatProvider)CultureInfo.CurrentCulture); } public ZStringWriter(IFormatProvider formatProvider) : base(formatProvider) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown _zw = new ZStringWriter(formatProvider); } public override void Close() { Dispose(disposing: true); } protected override void Dispose(bool disposing) { ((TextWriter)(object)_zw).Dispose(); base.Dispose(disposing); } public override void Write(char value) { ((TextWriter)(object)_zw).Write(value); } public override void Write(char[] buffer, int index, int count) { ((TextWriter)(object)_zw).Write(buffer, index, count); } public override void Write(string? value) { ((TextWriter)(object)_zw).Write(value ?? string.Empty); } public override void Write(bool value) { ((TextWriter)(object)_zw).Write(value); } public override void Write(decimal value) { ((TextWriter)(object)_zw).Write(value); } public override Task WriteAsync(char value) { return ((TextWriter)(object)_zw).WriteAsync(value); } public override Task WriteAsync(string? value) { return ((TextWriter)(object)_zw).WriteAsync(value ?? string.Empty); } public override Task WriteAsync(char[] buffer, int index, int count) { return ((TextWriter)(object)_zw).WriteAsync(buffer, index, count); } public override Task WriteLineAsync(char value) { return ((TextWriter)(object)_zw).WriteLineAsync(value); } public override Task WriteLineAsync(string? value) { return ((TextWriter)(object)_zw).WriteLineAsync(value ?? string.Empty); } public override Task WriteLineAsync(char[] buffer, int index, int count) { return ((TextWriter)(object)_zw).WriteLineAsync(buffer, index, count); } public override Task FlushAsync() { return ((TextWriter)(object)_zw).FlushAsync(); } public override string ToString() { return ((object)_zw).ToString(); } public override void Write(ReadOnlySpan buffer) { ((TextWriter)(object)_zw).Write(buffer); } public override void WriteLine(ReadOnlySpan buffer) { ((TextWriter)(object)_zw).WriteLine(buffer); } public override Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default(CancellationToken)) { return ((TextWriter)(object)_zw).WriteAsync(buffer, cancellationToken); } public override Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default(CancellationToken)) { return ((TextWriter)(object)_zw).WriteAsync(buffer, cancellationToken); } } } namespace SmartFormat.Utilities { public class FormatDelegate : IFormattable { private readonly Func? _getFormat1; private readonly Func? _getFormat2; public FormatDelegate(Func getFormat) { _getFormat1 = getFormat; } public FormatDelegate(Func getFormat) { _getFormat2 = getFormat; } string IFormattable.ToString(string? format, IFormatProvider? formatProvider) { if (_getFormat1 != null) { return _getFormat1(format); } if (_getFormat2 != null) { return _getFormat2(format, formatProvider); } return string.Empty; } } public interface ILocalizationProvider { string? GetString(string name); string? GetString(string name, string cultureName); string? GetString(string name, CultureInfo cultureInfo); } public class LocalizationProvider : ILocalizationProvider { internal readonly Dictionary Resources = new Dictionary(); public virtual CultureInfo? FallbackCulture { get; set; } public virtual bool ReturnNameIfNotFound { get; set; } public LocalizationProvider(bool isCaseSensitive = true, params ResourceManager[] resources) { foreach (ResourceManager resourceManager in resources) { DoAddResource(resourceManager, isCaseSensitive); } } public virtual void AddResource(ResourceManager resourceManager, bool isCaseSensitive = true) { DoAddResource(resourceManager, isCaseSensitive); } private void DoAddResource(ResourceManager resourceManager, bool isCaseSensitive = true) { if (!Resources.ContainsKey(resourceManager.BaseName)) { resourceManager.IgnoreCase = !isCaseSensitive; Resources.Add(resourceManager.BaseName, resourceManager); } } public virtual bool Remove(string resourceBaseName) { return Resources.Remove(resourceBaseName); } public virtual void Clear() { Resources.Clear(); } public virtual string? GetString(string name) { return GetString(name, (CultureInfo?)null); } public virtual string? GetString(string name, string cultureName) { return GetString(name, CultureInfo.GetCultureInfo(cultureName)); } public virtual string? GetString(string name, CultureInfo? cultureInfo) { foreach (ResourceManager value in Resources.Values) { string text = ((cultureInfo != null) ? value.GetString(name, cultureInfo) : value.GetString(name)); if (text == null && FallbackCulture != null) { text = value.GetString(name, FallbackCulture); } if (text != null) { return text; } } if (!ReturnNameIfNotFound) { return null; } return name; } } public static class PluralRules { public delegate int PluralRuleDelegate(decimal value, int pluralWordsCount); private static Dictionary DefaultLangToDelegate { get; } = new Dictionary { { "az", Singular }, { "bm", Singular }, { "bo", Singular }, { "dz", Singular }, { "fa", Singular }, { "hu", Singular }, { "id", Singular }, { "ig", Singular }, { "ii", Singular }, { "ja", Singular }, { "jv", Singular }, { "ka", Singular }, { "kde", Singular }, { "kea", Singular }, { "km", Singular }, { "kn", Singular }, { "ko", Singular }, { "ms", Singular }, { "my", Singular }, { "root", Singular }, { "sah", Singular }, { "ses", Singular }, { "sg", Singular }, { "th", Singular }, { "to", Singular }, { "vi", Singular }, { "wo", Singular }, { "yo", Singular }, { "zh", Singular }, { "af", DualOneOther }, { "bem", DualOneOther }, { "bg", DualOneOther }, { "bn", DualOneOther }, { "brx", DualOneOther }, { "ca", DualOneOther }, { "cgg", DualOneOther }, { "chr", DualOneOther }, { "da", DualOneOther }, { "de", DualOneOther }, { "dv", DualOneOther }, { "ee", DualOneOther }, { "el", DualOneOther }, { "en", DualOneOther }, { "eo", DualOneOther }, { "es", DualOneOther }, { "et", DualOneOther }, { "eu", DualOneOther }, { "fi", DualOneOther }, { "fo", DualOneOther }, { "fur", DualOneOther }, { "fy", DualOneOther }, { "gl", DualOneOther }, { "gsw", DualOneOther }, { "gu", DualOneOther }, { "ha", DualOneOther }, { "haw", DualOneOther }, { "he", DualOneOther }, { "is", DualOneOther }, { "it", DualOneOther }, { "kk", DualOneOther }, { "kl", DualOneOther }, { "ku", DualOneOther }, { "lb", DualOneOther }, { "lg", DualOneOther }, { "lo", DualOneOther }, { "mas", DualOneOther }, { "ml", DualOneOther }, { "mn", DualOneOther }, { "mr", DualOneOther }, { "nah", DualOneOther }, { "nb", DualOneOther }, { "ne", DualOneOther }, { "nl", DualOneOther }, { "nn", DualOneOther }, { "no", DualOneOther }, { "nyn", DualOneOther }, { "om", DualOneOther }, { "or", DualOneOther }, { "pa", DualOneOther }, { "pap", DualOneOther }, { "ps", DualOneOther }, { "pt", DualOneOther }, { "rm", DualOneOther }, { "saq", DualOneOther }, { "so", DualOneOther }, { "sq", DualOneOther }, { "ssy", DualOneOther }, { "sw", DualOneOther }, { "sv", DualOneOther }, { "syr", DualOneOther }, { "ta", DualOneOther }, { "te", DualOneOther }, { "tk", DualOneOther }, { "tr", DualOneOther }, { "ur", DualOneOther }, { "wae", DualOneOther }, { "xog", DualOneOther }, { "zu", DualOneOther }, { "ak", DualWithZero }, { "am", DualWithZero }, { "bh", DualWithZero }, { "fil", DualWithZero }, { "guw", DualWithZero }, { "hi", DualWithZero }, { "ln", DualWithZero }, { "mg", DualWithZero }, { "nso", DualWithZero }, { "ti", DualWithZero }, { "tl", DualWithZero }, { "wa", DualWithZero }, { "ff", DualFromZeroToTwo }, { "fr", DualFromZeroToTwo }, { "kab", DualFromZeroToTwo }, { "ga", TripleOneTwoOther }, { "iu", TripleOneTwoOther }, { "ksh", TripleOneTwoOther }, { "kw", TripleOneTwoOther }, { "se", TripleOneTwoOther }, { "sma", TripleOneTwoOther }, { "smi", TripleOneTwoOther }, { "smj", TripleOneTwoOther }, { "smn", TripleOneTwoOther }, { "sms", TripleOneTwoOther }, { "be", RussianSerboCroatian }, { "bs", RussianSerboCroatian }, { "hr", RussianSerboCroatian }, { "ru", RussianSerboCroatian }, { "sh", RussianSerboCroatian }, { "sr", RussianSerboCroatian }, { "uk", RussianSerboCroatian }, { "ar", Arabic }, { "br", Breton }, { "cs", Czech }, { "cy", Welsh }, { "gv", Manx }, { "lag", Langi }, { "lt", Lithuanian }, { "lv", Latvian }, { "mb", Macedonian }, { "mo", Moldavian }, { "mt", Maltese }, { "pl", Polish }, { "ro", Romanian }, { "shi", Tachelhit }, { "sk", Slovak }, { "sl", Slovenian }, { "tzm", CentralMoroccoTamazight } }; public static Dictionary IsoLangToDelegate { get; private set; } = new Dictionary(DefaultLangToDelegate); private static PluralRuleDelegate Singular => (decimal value, int pluralWordsCount) => 0; private static PluralRuleDelegate DualOneOther => (decimal value, int pluralWordsCount) => pluralWordsCount switch { 2 => (!(value == 1m)) ? 1 : 0, 3 => (!(value == 0m)) ? ((value == 1m) ? 1 : 2) : 0, 4 => (!(value < 0m)) ? ((value == 0m) ? 1 : ((value == 1m) ? 2 : 3)) : 0, _ => -1, }; private static PluralRuleDelegate DualWithZero => (decimal value, int pluralWordsCount) => (!(value == 0m) && !(value == 1m)) ? 1 : 0; private static PluralRuleDelegate DualFromZeroToTwo => delegate(decimal value, int pluralWordsCount) { switch (pluralWordsCount) { case 2: if (!(value >= 0m) || !(value < 2m)) { return 1; } return 0; case 3: return GetWordsCount3Value(value); case 4: return GetWordsCount4Value(value); default: return -1; } }; private static PluralRuleDelegate TripleOneTwoOther => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? ((value == 2m) ? 1 : 2) : 0; private static PluralRuleDelegate RussianSerboCroatian => (decimal value, int pluralWordsCount) => (!(value % 10m == 1m) || !(value % 100m != 11m)) ? (((value % 10m).BetweenWithoutFraction(2m, 4m) && !(value % 100m).BetweenWithoutFraction(12m, 14m)) ? 1 : 2) : 0; private static PluralRuleDelegate Arabic => (decimal value, int pluralWordsCount) => (!(value == 0m)) ? ((value == 1m) ? 1 : ((!(value == 2m)) ? ((!(value % 100m).BetweenWithoutFraction(3m, 10m)) ? ((!(value % 100m).BetweenWithoutFraction(11m, 99m)) ? 5 : 4) : 3) : 2)) : 0; private static PluralRuleDelegate Breton => delegate(decimal value, int pluralWordsCount) { if (value <= 1m) { if (value == 0m) { return 0; } if (value == 1m) { return 1; } } else { if (value == 2m) { return 2; } if (value == 3m) { return 3; } if (value == 6m) { return 4; } } return 5; }; private static PluralRuleDelegate Czech => (decimal value, int pluralWordsCount) => (!(value == 0m)) ? ((value == 1m) ? 1 : ((!value.BetweenWithoutFraction(2m, 4m)) ? ((!(value % 1m == 0m)) ? 4 : 3) : 2)) : 0; private static PluralRuleDelegate Welsh => delegate(decimal value, int pluralWordsCount) { if (value <= 1m) { if (value == 0m) { return 0; } if (value == 1m) { return 1; } } else { if (value == 2m) { return 2; } if (value == 3m) { return 3; } if (value == 6m) { return 4; } } return 5; }; private static PluralRuleDelegate Manx => (decimal value, int pluralWordsCount) => (!(value % 10m).BetweenWithoutFraction(1m, 2m) && !(value % 20m == 0m)) ? 1 : 0; private static PluralRuleDelegate Langi => delegate(decimal value, int pluralWordsCount) { if (value > 0m) { if (value < 2m) { return 1; } } else if (value == 0m) { return 0; } return 2; }; private static PluralRuleDelegate Lithuanian => (decimal value, int pluralWordsCount) => (!(value % 10m == 1m) || (value % 100m).BetweenWithoutFraction(11m, 19m)) ? (((value % 10m).BetweenWithoutFraction(2m, 9m) && !(value % 100m).BetweenWithoutFraction(11m, 19m)) ? 1 : 2) : 0; private static PluralRuleDelegate Latvian => (decimal value, int pluralWordsCount) => (!(value == 0m)) ? ((value % 10m == 1m && value % 100m != 11m) ? 1 : 2) : 0; private static PluralRuleDelegate Macedonian => (decimal value, int pluralWordsCount) => (!(value % 10m == 1m) || !(value != 11m)) ? 1 : 0; private static PluralRuleDelegate Moldavian => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? ((value == 0m || (value != 1m && (value % 100m).BetweenWithoutFraction(1m, 19m))) ? 1 : 2) : 0; private static PluralRuleDelegate Maltese => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? ((value == 0m || (value % 100m).BetweenWithoutFraction(2m, 10m)) ? 1 : ((!(value % 100m).BetweenWithoutFraction(11m, 19m)) ? 3 : 2)) : 0; private static PluralRuleDelegate Polish => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? (((value % 10m).BetweenWithoutFraction(2m, 4m) && !(value % 100m).BetweenWithoutFraction(12m, 14m)) ? 1 : ((!(value % 10m).BetweenWithoutFraction(0m, 1m) && !(value % 10m).BetweenWithoutFraction(5m, 9m) && !(value % 100m).BetweenWithoutFraction(12m, 14m)) ? 3 : 2)) : 0; private static PluralRuleDelegate Romanian => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? ((value == 0m || (value % 100m).BetweenWithoutFraction(1m, 19m)) ? 1 : 2) : 0; private static PluralRuleDelegate Tachelhit => (decimal value, int pluralWordsCount) => (!(value >= 0m) || !(value <= 1m)) ? (value.BetweenWithoutFraction(2m, 10m) ? 1 : 2) : 0; private static PluralRuleDelegate Slovak => (decimal value, int pluralWordsCount) => (!(value == 1m)) ? (value.BetweenWithoutFraction(2m, 4m) ? 1 : 2) : 0; private static PluralRuleDelegate Slovenian => (decimal value, int pluralWordsCount) => (!(value % 100m == 1m)) ? ((value % 100m == 2m) ? 1 : ((!(value % 100m).BetweenWithoutFraction(3m, 4m)) ? 3 : 2)) : 0; private static PluralRuleDelegate CentralMoroccoTamazight => (decimal value, int pluralWordsCount) => (!value.BetweenWithoutFraction(0m, 1m) && !value.BetweenWithoutFraction(11m, 99m)) ? 1 : 0; public static void RestoreDefault() { IsoLangToDelegate = new Dictionary(DefaultLangToDelegate); } private static int GetWordsCount3Value(decimal n) { if (n > 0m) { if (n < 2m) { return 1; } } else if (n == 0m) { return 0; } return 2; } private static int GetWordsCount4Value(decimal n) { if (!(n < 0m)) { if (n < 2m) { if (n == 0m) { return 1; } return 2; } return 3; } return 0; } public static PluralRuleDelegate GetPluralRule(string? twoLetterIsoLanguageName) { if (twoLetterIsoLanguageName != null && IsoLangToDelegate.TryGetValue(twoLetterIsoLanguageName, out PluralRuleDelegate value)) { return value; } throw new ArgumentException("IsoLangToDelegate not found for " + (twoLetterIsoLanguageName ?? "'null'"), "twoLetterIsoLanguageName"); } private static bool BetweenWithoutFraction(this decimal value, decimal min, decimal max) { if (value % 1m == 0m && value >= min) { return value <= max; } return false; } } public static class SystemTime { public static Func Now { get; private set; } = () => DateTime.Now; public static Func OffsetNow { get; private set; } = () => DateTimeOffset.Now; public static void SetDateTime(DateTime dateTimeNow) { Now = () => dateTimeNow; } public static void SetDateTimeOffset(DateTimeOffset dateTimeOffset) { OffsetNow = () => dateTimeOffset; } public static void ResetDateTime() { Now = () => DateTime.Now; OffsetNow = () => DateTimeOffset.Now; } } public static class TupleExtensions { [CompilerGenerated] private sealed class d__5 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object? <>2__current; private int <>l__initialThreadId; private object tuple; public object <>3__tuple; private IEnumerator <>7__wrap1; private IEnumerator <>7__wrap2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 2u) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = tuple.GetValueTupleItemObjects().GetEnumerator(); <>1__state = -3; goto IL_00fe; case 1: <>1__state = -4; goto IL_00a9; case 2: <>1__state = -3; goto IL_00fe; case 3: { <>1__state = -3; goto IL_00fe; } IL_00fe: if (<>7__wrap1.MoveNext()) { object current = <>7__wrap1.Current; if (current != null && current.IsValueTuple()) { <>7__wrap2 = current.GetValueTupleItemObjectsFlattened().GetEnumerator(); <>1__state = -4; goto IL_00a9; } if (current == null) { <>2__current = null; <>1__state = 2; return true; } <>2__current = current; <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; IL_00a9: if (<>7__wrap2.MoveNext()) { object current2 = <>7__wrap2.Current; <>2__current = current2; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap2 = null; goto IL_00fe; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally2() { <>1__state = -3; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__5 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__5(0); } d__.tuple = <>3__tuple; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly HashSet ValueTupleTypes = new HashSet(new Type[8] { typeof(ValueTuple<>), typeof(ValueTuple<, >), typeof(ValueTuple<, , >), typeof(ValueTuple<, , , >), typeof(ValueTuple<, , , , >), typeof(ValueTuple<, , , , , >), typeof(ValueTuple<, , , , , , >), typeof(ValueTuple<, , , , , , , >) }); public static bool IsValueTuple(this object obj) { return obj.GetType().IsValueTupleType(); } public static bool IsValueTupleType(this Type type) { if (type.GetTypeInfo().IsGenericType) { return ValueTupleTypes.Contains(type.GetGenericTypeDefinition()); } return false; } public static IEnumerable GetValueTupleItemObjects(this object tuple) { object tuple2 = tuple; return from f in tuple2.GetType().GetValueTupleItemFields() select f.GetValue(tuple2); } public static List GetValueTupleItemFields(this Type tupleType) { List list = new List(); int num = 1; FieldInfo runtimeField; while ((runtimeField = tupleType.GetRuntimeField($"Item{num}")) != null) { num++; list.Add(runtimeField); } return list; } [IteratorStateMachine(typeof(d__5))] public static IEnumerable GetValueTupleItemObjectsFlattened(this object tuple) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(-2) { <>3__tuple = tuple }; } } internal static class Validation { private static readonly char[] Valid = new char[3] { '|', ',', '~' }; public static char GetValidSplitCharOrThrow(char toCheck) { if (toCheck != Valid[0] && toCheck != Valid[1] && toCheck != Valid[2]) { throw new ArgumentException($"Only '{Valid[0]}', '{Valid[1]}' and '{Valid[2]}' are valid split chars."); } return toCheck; } } } namespace SmartFormat.Pooling { [Serializable] public class PoolingException : InvalidOperationException { public Type PoolType { get; } public PoolingException(string message, Type poolType) : base(message) { PoolType = poolType; } [Obsolete("This API supports obsolete formatter-based serialization. It will be removed in version 4.")] protected PoolingException(SerializationInfo info, StreamingContext context) : base(info, context) { PoolType = typeof(object); } } internal static class PoolRegistry { public static readonly ConcurrentDictionary Items = new ConcurrentDictionary(); public static T GetOrAdd(T pool) where T : class { return (T)Items.GetOrAdd(typeof(T), pool); } public static void TryRemove(T pool) where T : class { Items.TryRemove(typeof(T), out object _); } public static T? Get() where T : class { return (T)Items[typeof(T)]; } } } namespace SmartFormat.Pooling.SpecializedPools { internal class CollectionPool : SpecializedPoolAbstract where TCollection : class, ICollection, new() { private static readonly Lazy> Lazy = new Lazy>(() => new CollectionPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static CollectionPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); protected CollectionPool() { Policy.FunctionOnCreate = () => new TCollection(); Policy.ActionOnReturn = delegate(TCollection coll) { coll.Clear(); }; } } internal sealed class DictionaryPool : CollectionPool, KeyValuePair> where TKey : notnull { private static readonly Lazy> Lazy = new Lazy>(() => new DictionaryPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public new static DictionaryPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private DictionaryPool() { } } internal sealed class HashSetPool : CollectionPool, T> { private static readonly Lazy> Lazy = new Lazy>(() => new HashSetPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public new static HashSetPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private HashSetPool() { } } internal sealed class ListPool : CollectionPool, T> { private static readonly Lazy> Lazy = new Lazy>(() => new ListPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public new static ListPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private ListPool() { } } internal abstract class SpecializedPoolAbstract : IDisposable where T : class { private bool _isThreadSafeMode = SmartSettings.IsThreadSafeMode; protected readonly PoolPolicy Policy = new PoolPolicy(); internal ObjectPool Pool { get; set; } public bool IsThreadSafeMode => _isThreadSafeMode; protected SpecializedPoolAbstract() { Pool = LazyCreateObjectPool(); } internal void Reset(bool? isThreadSafeMode) { _isThreadSafeMode = isThreadSafeMode ?? SmartSettings.IsThreadSafeMode; PoolRegistry.TryRemove(this); Pool.Dispose(); Pool = LazyCreateObjectPool(); } private ObjectPool LazyCreateObjectPool() { if (!_isThreadSafeMode) { return new Lazy>(() => new ObjectPoolSingleThread(Policy), LazyThreadSafetyMode.None).Value; } return new Lazy>(() => new ObjectPoolConcurrent(Policy), LazyThreadSafetyMode.PublicationOnly).Value; } public virtual T Get() { if (!PoolSettings.IsPoolingEnabled) { return Policy.FunctionOnCreate(); } return Pool.Get(); } public virtual PooledObject Get(out T instance) { if (!PoolSettings.IsPoolingEnabled) { instance = Policy.FunctionOnCreate(); return new PooledObject(instance, Pool); } instance = Get(); return new PooledObject(instance, Pool); } public virtual void Return(T toReturn) { if (PoolSettings.IsPoolingEnabled) { Pool.Return(toReturn); } } public virtual void Clear() { Pool.Clear(); } protected virtual void Dispose(bool disposing) { if (disposing) { Reset(null); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } internal sealed class StringBuilderPool : SpecializedPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new StringBuilderPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public int DefaultStringBuilderCapacity { get; set; } = 1024; public static StringBuilderPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private StringBuilderPool() { Policy.FunctionOnCreate = () => new StringBuilder(DefaultStringBuilderCapacity); Policy.ActionOnReturn = delegate(StringBuilder sb) { sb.Clear(); sb.Capacity = DefaultStringBuilderCapacity; }; } } } namespace SmartFormat.Pooling.SmartPools { internal sealed class FormatDetailsPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new FormatDetailsPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static FormatDetailsPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private FormatDetailsPool() { Policy.FunctionOnCreate = () => new FormatDetails(); Policy.ActionOnReturn = delegate(FormatDetails fd) { fd.Clear(); }; } public override void Return(FormatDetails toReturn) { if (toReturn == InitializationObject.FormatDetails) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class FormatPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new FormatPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static FormatPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private FormatPool() { Policy.FunctionOnCreate = () => new Format(); Policy.ActionOnReturn = delegate(Format fmt) { fmt.ReturnToPool(); }; } public override void Return(Format toReturn) { if (toReturn == InitializationObject.Format) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class FormattingInfoPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new FormattingInfoPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static FormattingInfoPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private FormattingInfoPool() { Policy.FunctionOnCreate = () => new FormattingInfo(); Policy.ActionOnReturn = delegate(FormattingInfo fi) { fi.ReturnToPool(); }; } public override void Return(FormattingInfo toReturn) { if (toReturn == InitializationObject.FormattingInfo) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal static class InitializationObject { public static readonly IList ObjectList = new List(1); public static readonly List IntegerList = new List(1); public static readonly SmartSettings SmartSettings = new SmartSettings(); public static readonly SmartFormatter SmartFormatter = new SmartFormatter(SmartSettings); public static readonly Format Format = new Format().Initialize(SmartSettings, "init"); public static readonly LiteralText LiteralText = new LiteralText().Initialize(SmartSettings, Format, string.Empty, 0, 0); public static readonly Placeholder Placeholder = new Placeholder().Initialize(Format, 0, 0); public static readonly Selector Selector = new Selector().Initialize(SmartSettings, Placeholder, string.Empty, 0, 0, 0, 0); public static readonly IOutput Output = new NullOutput(); public static readonly FormatDetails FormatDetails = new FormatDetails().Initialize(SmartFormatter, Format, ObjectList, null, Output); public static readonly FormattingInfo FormattingInfo = new FormattingInfo().Initialize(FormatDetails, Format, null); public static readonly ParsingErrors ParsingErrors = new ParsingErrors().Initialize(Format); public static readonly SplitList SplitList = new SplitList().Initialize(Format, IntegerList); } internal sealed class LiteralTextPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new LiteralTextPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static LiteralTextPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private LiteralTextPool() { Policy.FunctionOnCreate = () => new LiteralText(); Policy.ActionOnReturn = delegate(LiteralText lt) { lt.Clear(); }; } public override void Return(LiteralText toReturn) { if (toReturn == InitializationObject.LiteralText) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class ParserStatePool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new ParserStatePool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static ParserStatePool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private ParserStatePool() { Policy.FunctionOnCreate = () => new ParserState(); Policy.ActionOnReturn = delegate(ParserState state) { state.Clear(); }; } } internal sealed class ParsingErrorsPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new ParsingErrorsPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static ParsingErrorsPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private ParsingErrorsPool() { Policy.FunctionOnCreate = () => new ParsingErrors(); Policy.ActionOnReturn = delegate(ParsingErrors pe) { pe.Clear(); }; } public override void Return(ParsingErrors toReturn) { if (toReturn == InitializationObject.ParsingErrors) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class PlaceholderPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new PlaceholderPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static PlaceholderPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private PlaceholderPool() { Policy.FunctionOnCreate = () => new Placeholder(); Policy.ActionOnReturn = delegate(Placeholder ph) { ph.ReturnToPool(); }; } public override void Return(Placeholder toReturn) { if (toReturn == InitializationObject.Placeholder) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class SelectorPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new SelectorPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static SelectorPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private SelectorPool() { Policy.FunctionOnCreate = () => new Selector(); Policy.ActionOnReturn = delegate(Selector selector) { selector.Clear(); }; } public override void Return(Selector toReturn) { if (toReturn == InitializationObject.Selector) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal abstract class SmartPoolAbstract : SpecializedPoolAbstract where T : class { public override T Get() { return base.Get(); } public override PooledObject Get(out T instance) { return base.Get(out instance); } } internal sealed class SplitListPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new SplitListPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static SplitListPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private SplitListPool() { Policy.FunctionOnCreate = () => new SplitList(); Policy.ActionOnReturn = delegate(SplitList sl) { sl.Clear(); }; } public override void Return(SplitList toReturn) { if (toReturn == InitializationObject.SplitList) { throw new PoolingException("InitializationObjects cannot be returned to the pool.", GetType()); } base.Return(toReturn); } } internal sealed class StringOutputPool : SmartPoolAbstract { private static readonly Lazy Lazy = new Lazy(() => new StringOutputPool(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static StringOutputPool Instance => PoolRegistry.GetOrAdd(Lazy.Value); private StringOutputPool() { Policy.FunctionOnCreate = () => new StringOutput(); Policy.ActionOnReturn = delegate(StringOutput so) { so.Clear(); }; } } } namespace SmartFormat.Pooling.ObjectPools { internal interface IObjectPool : IDisposable, IPoolCounters where T : class { IReadOnlyList PoolItems { get; } T Get(); PooledObject Get(out T instance); void Return(T element); void Clear(); } internal interface IPoolCounters { int CountAll { get; } int CountActive { get; } int CountInactive { get; } } internal class LinkedPool : ObjectPool where T : class { internal class LinkedPoolItem { internal LinkedPoolItem? PoolNext; internal T? Value; } [CompilerGenerated] private sealed class d__17 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private LinkedPoolItem <>2__current; private int <>l__initialThreadId; public LinkedPool <>4__this; private LinkedPoolItem 5__2; LinkedPool.LinkedPoolItem IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__17(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; LinkedPool linkedPool = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_005a; } <>1__state = -1; 5__2 = linkedPool.PoolFirst; goto IL_006b; IL_005a: 5__2 = 5__2.PoolNext; goto IL_006b; IL_006b: if (5__2 != null) { if (5__2.Value != null) { <>2__current = 5__2; <>1__state = 1; return true; } goto IL_005a; } 5__2 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__17 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__17(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } internal LinkedPoolItem? PoolFirst; internal LinkedPoolItem? NextAvailableListItem; private int _countAll; private int _countInactive; public override bool IsThreadSafeMode => false; public override int CountAll => _countAll; public override IReadOnlyList PoolItems => (from i in GetAllPoolItems() where i.Value != null select i.Value).ToList().AsReadOnly(); public override int CountInactive => _countInactive; public LinkedPool(PoolPolicy poolPolicy) : base(poolPolicy) { } public override T Get() { if (!PoolSettings.IsPoolingEnabled) { return base.PoolPolicy.FunctionOnCreate(); } T result; if (PoolFirst == null) { result = base.PoolPolicy.FunctionOnCreate(); _countAll++; return result; } LinkedPoolItem poolFirst = PoolFirst; result = poolFirst.Value; PoolFirst = poolFirst.PoolNext; poolFirst.PoolNext = NextAvailableListItem; NextAvailableListItem = poolFirst; NextAvailableListItem.Value = null; _countInactive--; base.PoolPolicy.ActionOnGet?.Invoke(result); return result; } public override void Return(T element) { if (!PoolSettings.IsPoolingEnabled) { return; } for (LinkedPoolItem linkedPoolItem = PoolFirst; linkedPoolItem != null; linkedPoolItem = linkedPoolItem.PoolNext) { if (PoolSettings.CheckReturnedObjectsExistInPool && linkedPoolItem.Value == element) { throw new PoolingException("Trying to return an object that has already been returned to the pool.", GetType()); } } base.PoolPolicy.ActionOnReturn?.Invoke(element); if (CountInactive < base.PoolPolicy.MaximumPoolSize) { LinkedPoolItem linkedPoolItem2 = NextAvailableListItem; if (linkedPoolItem2 == null) { linkedPoolItem2 = new LinkedPoolItem(); } else { NextAvailableListItem = linkedPoolItem2.PoolNext; } linkedPoolItem2.Value = element; linkedPoolItem2.PoolNext = PoolFirst; PoolFirst = linkedPoolItem2; _countInactive++; } else { base.PoolPolicy.ActionOnDestroy?.Invoke(element); } } public override void Clear() { if (base.PoolPolicy.ActionOnDestroy != null) { foreach (T item in from item in GetAllPoolItems() select item.Value) { if (item != null) { base.PoolPolicy.ActionOnDestroy(item); } } } PoolFirst = null; NextAvailableListItem = null; _countInactive = 0; _countAll = 0; } [IteratorStateMachine(typeof(LinkedPool<>.d__17))] private IEnumerable GetAllPoolItems() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__17(-2) { <>4__this = this }; } } internal abstract class ObjectPool : IObjectPool, IDisposable, IPoolCounters where T : class { public abstract bool IsThreadSafeMode { get; } [Obsolete("Use PoolSettings.IsPoolingEnabled instead.")] public bool IsPoolingEnabled { get { return PoolSettings.IsPoolingEnabled; } internal set { PoolSettings.IsPoolingEnabled = value; } } protected PoolPolicy PoolPolicy { get; } public abstract int CountAll { get; } public abstract IReadOnlyList PoolItems { get; } public int CountActive => CountAll - CountInactive; public abstract int CountInactive { get; } protected ObjectPool(PoolPolicy poolPolicy) { PoolPolicy = poolPolicy; } public abstract T Get(); public PooledObject Get(out T instance) { instance = Get(); return new PooledObject(instance, this); } public abstract void Return(T element); public abstract void Clear(); protected virtual void Dispose(bool disposing) { if (disposing) { Clear(); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } internal class ObjectPoolConcurrent : ObjectPool where T : class { private readonly ConcurrentStack _stack; private int _countAll; public override bool IsThreadSafeMode => true; public override int CountAll => _countAll; public override IReadOnlyList PoolItems => _stack.ToList().AsReadOnly(); public override int CountInactive => _stack.Count; public ObjectPoolConcurrent(PoolPolicy poolPolicy) : base(poolPolicy) { _stack = new ConcurrentStack(); } public override T Get() { if (!PoolSettings.IsPoolingEnabled) { return base.PoolPolicy.FunctionOnCreate(); } if (!_stack.TryPop(out var result)) { result = base.PoolPolicy.FunctionOnCreate(); Interlocked.Increment(ref _countAll); return result; } base.PoolPolicy.ActionOnGet?.Invoke(result); return result; } public override void Return(T element) { if (PoolSettings.IsPoolingEnabled) { if (PoolSettings.CheckReturnedObjectsExistInPool && !_stack.IsEmpty && _stack.Contains(element)) { throw new PoolingException($"Trying to return an object of type '{element.GetType()}', that has already been returned to the pool.", GetType()); } base.PoolPolicy.ActionOnReturn?.Invoke(element); if (CountInactive < base.PoolPolicy.MaximumPoolSize) { _stack.Push(element); } else { base.PoolPolicy.ActionOnDestroy?.Invoke(element); } } } public override void Clear() { if (base.PoolPolicy.ActionOnDestroy != null) { foreach (T item in _stack) { base.PoolPolicy.ActionOnDestroy(item); } } _stack.Clear(); _countAll = 0; } } internal class ObjectPoolSingleThread : ObjectPool where T : class { private readonly Stack _stack; private int _countAll; public override bool IsThreadSafeMode => false; public override int CountAll => _countAll; public override IReadOnlyList PoolItems => _stack.ToList().AsReadOnly(); public override int CountInactive => _stack.Count; public ObjectPoolSingleThread(PoolPolicy poolPolicy) : base(poolPolicy) { _stack = new Stack(poolPolicy.InitialPoolSize); } public override T Get() { if (!PoolSettings.IsPoolingEnabled) { return base.PoolPolicy.FunctionOnCreate(); } T result; if (_stack.Count == 0) { result = base.PoolPolicy.FunctionOnCreate(); _countAll++; return result; } try { result = _stack.Pop(); } catch { result = base.PoolPolicy.FunctionOnCreate(); Interlocked.Increment(ref _countAll); return result; } base.PoolPolicy.ActionOnGet?.Invoke(result); return result; } public override void Return(T element) { if (PoolSettings.IsPoolingEnabled) { if (PoolSettings.CheckReturnedObjectsExistInPool && _stack.Count > 0 && _stack.Contains(element)) { throw new PoolingException($"Trying to return an object of type '{element.GetType()}', that has already been returned to the pool.", GetType()); } base.PoolPolicy.ActionOnReturn?.Invoke(element); if (CountInactive < base.PoolPolicy.MaximumPoolSize) { _stack.Push(element); } else { base.PoolPolicy.ActionOnDestroy?.Invoke(element); } } } public override void Clear() { if (base.PoolPolicy.ActionOnDestroy != null) { foreach (T item in _stack) { base.PoolPolicy.ActionOnDestroy(item); } } _stack.Clear(); _countAll = 0; } } internal readonly struct PooledObject : IDisposable where T : class { private readonly T _value; private readonly IObjectPool _pool; internal PooledObject(T value, IObjectPool pool) { _value = value; _pool = pool; } void IDisposable.Dispose() { _pool.Return(_value); } } internal class PoolPolicy where T : class { private uint _maximumPoolSize = 10000u; public uint MaximumPoolSize { get { return _maximumPoolSize; } set { if (value == 0) { throw new PoolingException("Policy for MaximumPoolSize size must be greater than 0", typeof(T)); } _maximumPoolSize = value; } } public int InitialPoolSize { get; set; } = 10; public Func FunctionOnCreate { get; set; } = delegate { throw new PoolingException("'FunctionOnCreate' is not set in PoolPolicy.", typeof(T)); }; public Action? ActionOnDestroy { get; set; } public Action? ActionOnGet { get; set; } public Action? ActionOnReturn { get; set; } } } namespace SmartFormat.Extensions { public class ChooseFormatter : IFormatter { private CultureInfo? _cultureInfo; private char _splitChar = '|'; public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[2] { "choose", "c" }; public string Name { get; set; } = "choose"; public bool CanAutoDetect { get; set; } public CaseSensitivityType CaseSensitivity { get; set; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { string[] chooseOptions = formattingInfo.FormatterOptions.Split(SplitChar); IList list = formattingInfo.Format?.Split(SplitChar); if (list == null || list.Count < 2) { if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' requires at least 2 format options."); } _cultureInfo = (formattingInfo.FormatDetails.Provider as CultureInfo) ?? CultureInfo.CurrentUICulture; Format format = DetermineChosenFormat(formattingInfo, list, chooseOptions); formattingInfo.FormatAsChild(format, formattingInfo.CurrentValue); return true; } private Format DetermineChosenFormat(IFormattingInfo formattingInfo, IList choiceFormats, string[] chooseOptions) { string currentValueString; int num = GetChosenIndex(formattingInfo, chooseOptions, out currentValueString); if (choiceFormats.Count < chooseOptions.Length) { throw formattingInfo.FormattingException("You must specify at least " + chooseOptions.Length + " choices"); } if (choiceFormats.Count > chooseOptions.Length + 1) { throw formattingInfo.FormattingException("You cannot specify more than " + (chooseOptions.Length + 1) + " choices"); } if (num == -1 && choiceFormats.Count == chooseOptions.Length) { throw formattingInfo.FormattingException("\"" + currentValueString + "\" is not a valid choice, and a \"default\" choice was not supplied"); } if (num == -1) { num = choiceFormats.Count - 1; } return choiceFormats[num]; } private int GetChosenIndex(IFormattingInfo formattingInfo, string[] chooseOptions, out string currentValueString) { IFormattingInfo formattingInfo2 = formattingInfo; object currentValue = formattingInfo2.CurrentValue; string valAsString; if (currentValue != null) { if (currentValue is bool flag) { valAsString = (currentValueString = flag.ToString()); return Array.FindIndex(chooseOptions, (string t) => t.Equals(valAsString, StringComparison.OrdinalIgnoreCase)); } valAsString = (currentValueString = formattingInfo2.CurrentValue.ToString()); return Array.FindIndex(chooseOptions, (string t) => AreEqual(t, valAsString, formattingInfo2.FormatDetails.Settings.CaseSensitivity)); } valAsString = (currentValueString = "null"); return Array.FindIndex(chooseOptions, (string t) => t.Equals(valAsString, StringComparison.OrdinalIgnoreCase)); } private bool AreEqual(string s1, string s2, CaseSensitivityType caseSensitivityFromSettings) { CultureInfo cultureInfo = _cultureInfo; if (((caseSensitivityFromSettings == CaseSensitivity) ? caseSensitivityFromSettings : CaseSensitivity) != 0) { return cultureInfo.CompareInfo.Compare(s1, s2, CompareOptions.IgnoreCase) == 0; } return cultureInfo.CompareInfo.Compare(s1, s2, CompareOptions.None) == 0; } } public class ConditionalFormatter : IFormatter { private static readonly Regex _complexConditionPattern = new Regex("^ (?: ([&/]?) ([<>=!]=?) ([0-9.-]+) )+ \\?", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace, TimeSpan.FromMilliseconds(500.0)); private char _splitChar = '|'; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[3] { "conditional", "cond", string.Empty }; public string Name { get; set; } = "cond"; public bool CanAutoDetect { get; set; } = true; public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { Format format = formattingInfo.Format; object currentValue = formattingInfo.CurrentValue; IList list2; if (format == null) { IList list = new List(0); list2 = list; } else { list2 = format.Split(SplitChar); } IList list3 = list2; if (format == null || list3.Count == 1) { if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' requires at least 2 format parameters."); } bool flag = currentValue is IConvertible; if (flag) { bool flag2 = ((currentValue is DateTime || currentValue is string || currentValue is bool) ? true : false); flag = !flag2; } bool flag3 = flag; decimal num = (flag3 ? Convert.ToDecimal(currentValue) : 0m); int num2; if (flag3) { num2 = -1; while (num2++ < list3.Count) { if (!TryEvaluateCondition(list3[num2], num, out bool conditionResult, out Format outputItem)) { if (num2 == 0) { break; } conditionResult = true; } if (conditionResult) { formattingInfo.FormatAsChild(outputItem, currentValue); return true; } } } int count = list3.Count; if (flag3) { num2 = ((!(num < 0m)) ? Math.Min((int)Math.Floor(num), count - 1) : (count - 1)); } else { object obj = currentValue; if (!(obj is bool flag4)) { if (!(obj is DateTime dateTime)) { if (!(obj is DateTimeOffset dateTimeOffset)) { if (!(obj is TimeSpan timeSpan)) { num2 = (((!(obj is string value)) ? (currentValue == null) : string.IsNullOrEmpty(value)) ? 1 : 0); } else if (count == 3 && timeSpan == TimeSpan.Zero) { num2 = 1; } else { TimeSpan timeSpan2 = timeSpan; num2 = ((timeSpan2.CompareTo(TimeSpan.Zero) > 0) ? (count - 1) : 0); } } else if (count == 3 && dateTimeOffset.UtcDateTime.Date == SystemTime.OffsetNow().UtcDateTime.Date) { num2 = 1; } else { DateTimeOffset dateTimeOffset2 = dateTimeOffset; num2 = ((!(dateTimeOffset2.UtcDateTime <= SystemTime.OffsetNow().UtcDateTime)) ? (count - 1) : 0); } } else if (count == 3 && dateTime.ToUniversalTime().Date == SystemTime.Now().ToUniversalTime().Date) { num2 = 1; } else { DateTime dateTime2 = dateTime; num2 = ((!(dateTime2.ToUniversalTime() <= SystemTime.Now().ToUniversalTime())) ? (count - 1) : 0); } } else { num2 = ((!flag4) ? 1 : 0); } } Format format2 = list3[num2]; formattingInfo.FormatAsChild(format2, currentValue); return true; } private static bool TryEvaluateCondition(Format parameter, decimal value, out bool conditionResult, out Format outputItem) { conditionResult = false; Match match = _complexConditionPattern.Match(parameter.BaseString, parameter.StartIndex, parameter.EndIndex - parameter.StartIndex); if (!match.Success) { outputItem = parameter; return false; } CaptureCollection captures = match.Groups[1].Captures; CaptureCollection captures2 = match.Groups[2].Captures; CaptureCollection captures3 = match.Groups[3].Captures; int num = 0; while (num < captures.Count) { decimal num2 = decimal.Parse(captures3[num].Value, CultureInfo.InvariantCulture); bool flag = false; string value2 = captures2[num].Value; if (value2 != null) { int length = value2.Length; if (length == 1) { switch (value2[0]) { case '>': flag = value > num2; goto IL_019b; case '<': flag = value < num2; goto IL_019b; case '=': break; case '!': goto IL_0191; default: goto IL_019b; } goto IL_016d; } if (length == 2) { switch (value2[0]) { case '=': break; case '<': if (value2 == "<=") { flag = value <= num2; } goto IL_019b; case '>': if (value2 == ">=") { flag = value >= num2; } goto IL_019b; case '!': goto IL_0145; default: goto IL_019b; } if (value2 == "==") { goto IL_016d; } } } goto IL_019b; IL_0145: if (value2 == "!=") { goto IL_0191; } goto IL_019b; IL_019b: if (num == 0) { conditionResult = flag; } else if (captures[num].Value == "/") { conditionResult |= flag; } else { conditionResult &= flag; } num++; continue; IL_0191: flag = value != num2; goto IL_019b; IL_016d: flag = value == num2; goto IL_019b; } int start = match.Index + match.Length - parameter.StartIndex; outputItem = parameter.Substring(start); return true; } } public class CustomPluralRuleProvider : IFormatProvider { private readonly PluralRules.PluralRuleDelegate _pluralRule; public CustomPluralRuleProvider(PluralRules.PluralRuleDelegate pluralRule) { _pluralRule = pluralRule; } public object? GetFormat(Type? formatType) { if (!(formatType == typeof(CustomPluralRuleProvider))) { return null; } return this; } public PluralRules.PluralRuleDelegate GetPluralRule() { return _pluralRule; } } public class DefaultFormatter : IFormatter { internal const int StackAllocCharBufferSize = 512; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[3] { "default", "d", string.Empty }; public string Name { get; set; } = "d"; public bool CanAutoDetect { get; set; } = true; public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { Format format = formattingInfo.Format; object currentValue = formattingInfo.CurrentValue; if (format != null && format.HasNested) { formattingInfo.FormatAsChild(format, currentValue); return true; } IFormatProvider provider = formattingInfo.FormatDetails.Provider; if (provider?.GetFormat(typeof(ICustomFormatter)) is ICustomFormatter customFormatter) { string format2 = format?.GetLiteralText(); formattingInfo.Write(customFormatter.Format(format2, currentValue, provider).AsSpan()); return true; } if (currentValue is ISpanFormattable spanFormattable) { ReadOnlySpan format3 = format?.AsSpan() ?? ((ReadOnlySpan)Span.Empty); Span destination = stackalloc char[512]; if (spanFormattable.TryFormat(destination, out var charsWritten, format3, provider)) { formattingInfo.Write(destination.Slice(0, charsWritten)); return true; } using ZCharArray zCharArray = new ZCharArray(2000000); zCharArray.Write(spanFormattable, format3, provider); formattingInfo.Write(zCharArray.GetSpan()); return true; } if (currentValue is IFormattable formattable) { string text = format?.ToString(); formattingInfo.Write(formattable.ToString(text, provider).AsSpan()); return true; } ReadOnlySpan text2 = currentValue?.ToString().AsSpan() ?? ((ReadOnlySpan)Span.Empty); formattingInfo.Write(text2); return true; } } public class DefaultSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { string selectorText = selectorInfo.SelectorText; FormatDetails formatDetails = selectorInfo.FormatDetails; if (int.TryParse(selectorText, out var result) && selectorInfo.SelectorIndex == 0 && result < formatDetails.OriginalArgs.Count && selectorInfo.SelectorOperator == string.Empty) { selectorInfo.Result = formatDetails.OriginalArgs[result]; return true; } return false; } } public class DictionarySource : Source { protected internal readonly IDictionary RoDictionaryTypeCache = new Dictionary(); public bool IsIReadOnlyDictionarySupported { get; set; } public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { object currentValue = selectorInfo.CurrentValue; if (TrySetResultForNullableOperator(selectorInfo)) { return true; } if (currentValue == null) { return false; } string selectorText = selectorInfo.SelectorText; StringComparison caseSensitivityComparison = selectorInfo.FormatDetails.Settings.GetCaseSensitivityComparison(); if (TryGetIDictionaryValue(currentValue, selectorText, caseSensitivityComparison, out object value)) { selectorInfo.Result = value; return true; } if (TryGetGenericDictionaryValue(currentValue, selectorText, caseSensitivityComparison, out value)) { selectorInfo.Result = value; return true; } if (IsIReadOnlyDictionarySupported && TryGetReadOnlyDictionaryValue(currentValue, selectorText, caseSensitivityComparison, out value)) { selectorInfo.Result = value; return true; } return false; } private static bool TryGetIDictionaryValue(object current, string selectorText, StringComparison comparison, out object? value) { if (current is IDictionary dictionary) { foreach (DictionaryEntry item in dictionary) { if (((item.Key as string) ?? item.Key.ToString()).Equals(selectorText, comparison)) { value = item.Value; return true; } } } value = null; return false; } private static bool TryGetGenericDictionaryValue(object current, string selectorText, StringComparison comparison, out object? value) { if (current is IDictionary dictionary) { foreach (KeyValuePair item in dictionary) { if (item.Key.Equals(selectorText, comparison)) { value = item.Value; return true; } } } value = null; return false; } private bool TryGetReadOnlyDictionaryValue(object obj, string key, StringComparison comparison, out object? value) { value = null; if (!TryGetDictionaryProperties(obj.GetType(), out (PropertyInfo, PropertyInfo)? propertyTuple)) { return false; } foreach (object item in (IEnumerable)propertyTuple.Value.Item1.GetValue(obj)) { if (item.ToString().Equals(key, comparison)) { value = propertyTuple.Value.Item2.GetValue(obj, new object[1] { item }); return true; } } return false; } private bool TryGetDictionaryProperties(Type type, out (PropertyInfo KeyProperty, PropertyInfo ItemProperty)? propertyTuple) { if (RoDictionaryTypeCache.TryGetValue(type, out propertyTuple)) { return propertyTuple.HasValue; } if (!IsIReadOnlyDictionary(type)) { RoDictionaryTypeCache[type] = null; return false; } propertyTuple = (type.GetProperty("Keys"), type.GetProperty("Item")); RoDictionaryTypeCache[type] = propertyTuple; return true; } private static bool IsIReadOnlyDictionary(Type type) { Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { if (type2 == typeof(IReadOnlyDictionary<, >) || (type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<, >))) { return true; } } return false; } } public class GlobalVariablesSource : PersistentVariablesSource { private readonly IDictionary _globalGroupLookup = (SmartSettings.IsThreadSafeMode ? ((IDictionary)new ConcurrentDictionary()) : ((IDictionary)new Dictionary())); private static Lazy _lazySource = new Lazy(() => new GlobalVariablesSource(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); public static GlobalVariablesSource Instance => _lazySource.Value; private GlobalVariablesSource() { GroupLookup = _globalGroupLookup; } public static void Reset() { _lazySource = new Lazy(() => new GlobalVariablesSource(), SmartSettings.IsThreadSafeMode ? LazyThreadSafetyMode.PublicationOnly : LazyThreadSafetyMode.None); } } public class IsMatchFormatter : IFormatter, IInitializer { private char _splitChar = '|'; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[1] { "ismatch" }; public string Name { get; set; } = "ismatch"; public bool CanAutoDetect { get; set; } public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } public RegexOptions RegexOptions { get; set; } public string PlaceholderNameForMatches { get; set; } = "m"; public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { if (formattingInfo.CurrentValue == null) { return false; } string formatterOptions = formattingInfo.FormatterOptions; IList list = formattingInfo.Format?.Split(SplitChar); if (list == null || list.Count != 2) { if (list != null && list.Count == 0) { return true; } if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' requires at least 2 format options."); } Match match = new Regex(formatterOptions, RegexOptions, TimeSpan.FromMilliseconds(500.0)).Match(formattingInfo.CurrentValue.ToString()); if (!match.Success) { if (list.Count == 2) { formattingInfo.FormatAsChild(list[1], formattingInfo.CurrentValue); } return true; } List value = (from Group grp in match.Groups select grp.Value).ToList(); foreach (FormatItem item in list[0].Items) { if (item is Placeholder placeholder) { KeyValuePair keyValuePair = new KeyValuePair(PlaceholderNameForMatches, value); Format(formattingInfo, placeholder, keyValuePair); continue; } LiteralText literalText = (LiteralText)item; using Format format = formattingInfo.Format?.Substring(literalText.StartIndex - formattingInfo.Format.StartIndex, literalText.Length); if (format != null) { formattingInfo.FormatAsChild(format, formattingInfo.CurrentValue); } } return true; } private void Format(IFormattingInfo formattingInfo, Placeholder placeholder, object matchingGroupValues) { using Format format = formattingInfo.Format?.Substring(placeholder.StartIndex - formattingInfo.Format.StartIndex, placeholder.Length); if (format != null) { if (placeholder.Selectors.Count > 0 && placeholder.Selectors[0]?.RawText == PlaceholderNameForMatches) { formattingInfo.FormatAsChild(format, matchingGroupValues); } else { formattingInfo.FormatAsChild(format, formattingInfo.CurrentValue); } } } public void Initialize(SmartFormatter smartFormatter) { if (smartFormatter.GetSourceExtension() == null) { smartFormatter.AddExtensions(new KeyValuePairSource()); } } } public class KeyValuePairSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (TrySetResultForNullableOperator(selectorInfo)) { return true; } object currentValue = selectorInfo.CurrentValue; if (currentValue != null) { if (currentValue is KeyValuePair keyValuePair && keyValuePair.Key == selectorInfo.SelectorText) { selectorInfo.Result = keyValuePair.Value; return true; } return false; } return false; } } public class ListFormatter : IFormatter, ISource, IInitializer { private SmartSettings _smartSettings = new SmartSettings(); private bool _isInitialized; private char _splitChar = '|'; private static readonly AsyncLocal _collectionIndexThreadSafe = new AsyncLocal(); private static int _collectionIndexSingleThread = -1; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[3] { "list", "l", string.Empty }; public string Name { get; set; } = "list"; public bool CanAutoDetect { get; set; } = true; public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } internal static bool IsThreadSafeMode { get; set; } = SmartSettings.IsThreadSafeMode; private static int CollectionIndex { get { if (!IsThreadSafeMode) { return _collectionIndexSingleThread; } return _collectionIndexThreadSafe.Value.GetValueOrDefault(-1); } set { if (IsThreadSafeMode) { _collectionIndexThreadSafe.Value = value; } else { _collectionIndexSingleThread = value; } } } public bool TryEvaluateSelector(ISelectorInfo selectorInfo) { object currentValue = selectorInfo.CurrentValue; string selectorText = selectorInfo.SelectorText; bool flag = currentValue is IEnumerable && selectorText.Equals("index", StringComparison.OrdinalIgnoreCase); if (flag && selectorInfo.SelectorIndex == 0) { selectorInfo.Result = CollectionIndex; return true; } if (!(currentValue is IList list)) { return false; } if ((selectorInfo.SelectorIndex != 0 || selectorInfo.SelectorOperator.Length != 0) && int.TryParse(selectorText, out var result) && result < list.Count) { selectorInfo.Result = list[result]; return true; } if (flag && 0 <= CollectionIndex && CollectionIndex < list.Count) { selectorInfo.Result = list[CollectionIndex]; return true; } return false; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { Format format = formattingInfo.Format; object currentValue = formattingInfo.CurrentValue; if (currentValue == null && HasNullableOperator(formattingInfo)) { formattingInfo.Write(string.Empty); return true; } SplitList instance; bool flag; using (SplitListPool.Instance.Get(out instance)) { IList list2; if (format == null) { IList list = instance; list2 = list; } else { list2 = format.Split(SplitChar, 4); } SplitList splitList = (SplitList)list2; IEnumerable enumerable = default(IEnumerable); int num; if (format != null && splitList.Count >= 2) { enumerable = currentValue as IEnumerable; num = ((enumerable == null) ? 1 : 0); } else { num = 1; } flag = (byte)num != 0; if (!flag) { bool flag2 = ((enumerable is string || enumerable is IFormattable) ? true : false); flag = flag2; } if (flag) { if (!string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' requires an IEnumerable argument and at least 2 format parameters."); } splitList.Clear(); flag = false; } else { Format format2 = splitList[0]; if (!format2.HasNested) { Format format3 = FormatPool.Instance.Get().Initialize(_smartSettings, format2.BaseString, format2.StartIndex, format2.EndIndex); format2.ParentPlaceholder = formattingInfo.Placeholder; Placeholder placeholder = PlaceholderPool.Instance.Get().Initialize(format3, format2.StartIndex, 0); placeholder.Format = format2; placeholder.EndIndex = format2.EndIndex; placeholder.Alignment = formattingInfo.Alignment; format3.Items.Add(placeholder); format2 = format3; } List instance2; using (ListPool.Instance.Get(out instance2)) { ICollection collection = enumerable as ICollection; if (collection == null) { instance2 = ListPool.Instance.Get(); foreach (object item in enumerable) { instance2.Add(item); } collection = instance2; } int collectionIndex = CollectionIndex; CollectionIndex = -1; FormatItems(collection, splitList, format2, formattingInfo); CollectionIndex = collectionIndex; splitList.Clear(); flag = true; } } } return flag; } private static void FormatItems(ICollection items, SplitList parameters, Format itemFormat, IFormattingInfo formattingInfo) { Format format = formattingInfo.Format; FormattingInfo instance; using (FormattingInfoPool.Instance.Get(out instance)) { instance.Initialize((FormattingInfo)formattingInfo, formattingInfo.FormatDetails, format, null); instance.Alignment = 0; Format format2 = parameters[1]; Format format3 = ((parameters.Count >= 3) ? parameters[2] : format2); Format spacer = ((parameters.Count >= 4) ? parameters[3] : format3); FormattingInfo formattingInfo2 = formattingInfo as FormattingInfo; do { formattingInfo2 = formattingInfo2?.Parent; } while (formattingInfo2?.Parent != null); object value = formattingInfo2?.CurrentValue; foreach (object item in items) { CollectionIndex++; if (format2 != null && CollectionIndex != 0) { if (CollectionIndex < items.Count - 1) { WriteSpacer(instance, format2, value); } else if (CollectionIndex == 1) { WriteSpacer(instance, spacer, value); } else { WriteSpacer(instance, format3, value); } } formattingInfo.FormatAsChild(itemFormat, item); } } } private static void WriteSpacer(FormattingInfo formattingInfo, Format spacer, object? value) { if (spacer.HasNested) { formattingInfo.FormatAsChild(spacer, value); } else { formattingInfo.Write(spacer.GetLiteralText()); } } private bool HasNullableOperator(IFormattingInfo formattingInfo) { if (formattingInfo.Placeholder != null) { foreach (Selector selector in formattingInfo.Placeholder.Selectors) { if (selector.OperatorLength > 0 && selector.BaseString[selector.OperatorStartIndex] == _smartSettings.Parser.NullableOperator) { return true; } } } return false; } public void Initialize(SmartFormatter smartFormatter) { if (!_isInitialized) { _smartSettings = smartFormatter.Settings; _isInitialized = true; } } } public class LocalizationFormatter : IFormatter, IInitializer { private SmartFormatter? _formatter; internal IDictionary? LocalizedFormatCache; internal ILocalizationProvider? LocalizationProvider; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[2] { "localize", "L" }; public string Name { get; set; } = "L"; public bool CanAutoDetect { get { return false; } set { if (value) { throw new ArgumentException("LocalizationFormatter cannot handle auto-detection"); } } } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { if (formattingInfo.Format != null) { Format? format = formattingInfo.Format; if (format == null || format.Length != 0) { if (LocalizationProvider == null) { throw new LocalizationFormattingException(formattingInfo.Format, new NullReferenceException("The ILocalizationProvider must not be null."), 0); } CultureInfo cultureInfo = GetCultureInfo(formattingInfo); formattingInfo.FormatDetails.Provider = cultureInfo; string @string = LocalizationProvider.GetString(formattingInfo.Format.RawText, cultureInfo); if (@string == null && formattingInfo.Format.HasNested) { using ZStringOutput zStringOutput = new ZStringOutput(ZStringBuilderUtilities.CalcCapacity(formattingInfo.Format)); FormatDetails formatDetails = FormatDetailsPool.Instance.Get().Initialize(_formatter, formattingInfo.Format, InitializationObject.ObjectList, null, zStringOutput); FormattingInfo formattingInfo2 = FormattingInfoPool.Instance.Get().Initialize(formatDetails, formattingInfo.Format, formattingInfo.CurrentValue); _formatter.Format(formattingInfo2); @string = LocalizationProvider.GetString(zStringOutput.ToString(), cultureInfo); } if (@string == null) { throw new LocalizationFormattingException(formattingInfo.Format, "No localized string found for '" + formattingInfo.Format.RawText + "'", formattingInfo.Format.StartIndex); } if (LocalizedFormatCache.TryGetValue(@string, out Format value)) { formattingInfo.FormatAsChild(value, formattingInfo.CurrentValue); return true; } Format format2 = _formatter.Parser.ParseFormat(@string); LocalizedFormatCache.Add(@string, format2); formattingInfo.FormatAsChild(format2, formattingInfo.CurrentValue); return true; } } throw new LocalizationFormattingException(formattingInfo.Format, new ArgumentException("'Format' for localization must not be null or empty.", "formattingInfo"), 0); } public void Initialize(SmartFormatter smartFormatter) { _formatter = smartFormatter; LocalizationProvider = _formatter.Settings.Localization.LocalizationProvider; IEqualityComparer caseSensitivityComparer = _formatter.Settings.GetCaseSensitivityComparer(); LocalizedFormatCache = new Dictionary(caseSensitivityComparer); } private static CultureInfo GetCultureInfo(IFormattingInfo formattingInfo) { string text = formattingInfo.FormatterOptions.Trim(); if (text == string.Empty) { if (formattingInfo.FormatDetails.Provider is CultureInfo result) { return result; } return CultureInfo.CurrentUICulture; } try { return CultureInfo.GetCultureInfo(text); } catch (Exception formatException) { throw new LocalizationFormattingException(formattingInfo.Format, formatException, 0); } } } [Serializable] public class LocalizationFormattingException : FormattingException { public LocalizationFormattingException(FormatItem? errorItem, Exception formatException, int index) : base(errorItem, formatException, index) { } public LocalizationFormattingException(FormatItem? errorItem, string issue, int index) : base(errorItem, issue, index) { } [Obsolete("This API supports obsolete formatter-based serialization. It will be removed in version 4.")] protected LocalizationFormattingException(SerializationInfo info, StreamingContext context) : base(info, context) { } } public class NullFormatter : IFormatter { private char _splitChar = '|'; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[1] { "isnull" }; public string Name { get; set; } = "isnull"; public bool CanAutoDetect { get; set; } public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { object currentValue = formattingInfo.CurrentValue; ReadOnlySpan readOnlySpan = formattingInfo.FormatterOptions.AsSpan().Trim(); IList list = formattingInfo.Format?.Split(SplitChar); if (readOnlySpan.Length != 0) { if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' does not allow choose options"); } bool flag = list == null; if (!flag) { int count = list.Count; bool flag2 = ((count < 1 || count > 2) ? true : false); flag = flag2; } if (flag) { if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' must have 1 or 2 format options"); } if (currentValue == null) { formattingInfo.FormatAsChild(list[0], currentValue); return true; } if (list.Count > 1) { formattingInfo.FormatAsChild(list[1], currentValue); return true; } formattingInfo.Write(ReadOnlySpan.Empty); return true; } } public class PersistentVariablesSource : Source, IDictionary, ICollection>, IEnumerable>, IEnumerable { protected internal class NameGroupPair { public string Name { get; } public VariablesGroup Group { get; } public NameGroupPair(string name, VariablesGroup group) { Name = name; Group = group; } } protected IDictionary GroupLookup = (SmartSettings.IsThreadSafeMode ? ((IDictionary)new ConcurrentDictionary()) : ((IDictionary)new Dictionary())); public int Count => GroupLookup.Values.Count; public bool IsReadOnly => false; public ICollection Keys => GroupLookup.Keys; public ICollection Values => GroupLookup.Values.Select((NameGroupPair k) => k.Group).ToList(); public VariablesGroup this[string name] { get { return GroupLookup[name].Group; } set { Add(name, value); } } public bool TryGetValue(string name, out VariablesGroup value) { if (GroupLookup.TryGetValue(name, out NameGroupPair value2)) { value = value2.Group; return true; } value = null; return false; } public void Add(string name, VariablesGroup group) { if (string.IsNullOrEmpty(name)) { throw new ArgumentException("Name must not be null or empty.", "name"); } NameGroupPair value = new NameGroupPair(name, group); GroupLookup[name] = value; } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public bool Remove(string name) { return GroupLookup.Remove(name); } public bool Remove(KeyValuePair item) { return Remove(item.Key); } public void Clear() { GroupLookup.Clear(); } public bool ContainsKey(string name) { return GroupLookup.ContainsKey(name); } public bool Contains(KeyValuePair item) { if (TryGetValue(item.Key, out VariablesGroup value)) { return value == item.Value; } return false; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (KeyValuePair item in GroupLookup) { array[arrayIndex++] = new KeyValuePair(item.Key, item.Value.Group); } } public PersistentVariablesSource Clone() { PersistentVariablesSource persistentVariablesSource = new PersistentVariablesSource(); foreach (KeyValuePair item in GroupLookup) { persistentVariablesSource.Add(item.Key, item.Value.Group); } return persistentVariablesSource; } IEnumerator> IEnumerable>.GetEnumerator() { return GroupLookup.Select, KeyValuePair>((KeyValuePair v) => new KeyValuePair(v.Key, v.Value.Group)).GetEnumerator(); } public IEnumerator GetEnumerator() { return GroupLookup.Select, KeyValuePair>((KeyValuePair v) => new KeyValuePair(v.Key, v.Value.Group)).GetEnumerator(); } public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { object currentValue = selectorInfo.CurrentValue; if (currentValue != null) { if (currentValue is IVariablesGroup variablesGroup && TryEvaluateGroup(selectorInfo, variablesGroup)) { return true; } } else if (TrySetResultForNullableOperator(selectorInfo)) { return true; } if (TryGetValue(selectorInfo.SelectorText, out VariablesGroup value)) { selectorInfo.Result = value; return true; } return false; } private static bool TryEvaluateGroup(ISelectorInfo selectorInfo, IVariablesGroup variablesGroup) { if (!variablesGroup.TryGetValue(selectorInfo.SelectorText, out IVariable value)) { return false; } selectorInfo.Result = value.GetValue(); return true; } } public class PluralLocalizationFormatter : IFormatter { private char _splitChar = '|'; [Obsolete("This property is not supported any more. Changed process to get or set the default culture.", true)] public string DefaultTwoLetterISOLanguageName { get; set; } = "en"; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[3] { "plural", "p", string.Empty }; public string Name { get; set; } = "plural"; public bool CanAutoDetect { get; set; } = true; public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } public PluralLocalizationFormatter() { } [Obsolete("This constructor is not required. Changed process to determine the default culture.", true)] public PluralLocalizationFormatter(string defaultTwoLetterIsoLanguageName) { DefaultTwoLetterISOLanguageName = defaultTwoLetterIsoLanguageName; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { Format format = formattingInfo.Format; object currentValue = formattingInfo.CurrentValue; if (format == null) { return false; } IList list = format.Split(SplitChar); bool flag = string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName); if (flag && list.Count <= 1) { return false; } object obj = currentValue; decimal value; if (obj is IConvertible convertible) { IConvertible convertible2 = convertible; bool flag2 = ((convertible2 is bool || convertible2 is string) ? true : false); if (!flag2 && TryGetDecimalValue(convertible2, null, out value)) { goto IL_0124; } } if (obj is IEnumerable source) { value = source.Count(); goto IL_0124; } if (flag) { return false; } throw new FormattingException(format, $"Formatter named '{formattingInfo.Placeholder?.FormatterName}' can format numbers and IEnumerables, but the argument was of type '{currentValue?.GetType().ToString() ?? "null"}'", 0); IL_0124: int num = GetPluralRule(formattingInfo)(pluralWordsCount: list.Count, value: value); if (num < 0 || list.Count <= num) { throw new FormattingException(format, "Invalid number of plural parameters in PluralLocalizationFormatter", list.Count - 1); } Format format2 = list[num]; formattingInfo.FormatAsChild(format2, currentValue); return true; } private static bool TryGetDecimalValue(IConvertible convertible, IFormatProvider? provider, out decimal value) { try { value = convertible.ToDecimal(provider); return true; } catch { value = default(decimal); return false; } } private static PluralRules.PluralRuleDelegate GetPluralRule(IFormattingInfo formattingInfo) { CultureInfo cultureInfo = GetCultureInfo(formattingInfo); if (formattingInfo.FormatterOptions.Trim().Length != 0) { return PluralRules.GetPluralRule(cultureInfo.TwoLetterISOLanguageName); } CustomPluralRuleProvider customPluralRuleProvider = (CustomPluralRuleProvider)(formattingInfo.FormatDetails.Provider?.GetFormat(typeof(CustomPluralRuleProvider))); if (customPluralRuleProvider != null) { return customPluralRuleProvider.GetPluralRule(); } return PluralRules.GetPluralRule(cultureInfo.TwoLetterISOLanguageName); } private static CultureInfo GetCultureInfo(IFormattingInfo formattingInfo) { string text = formattingInfo.FormatterOptions.Trim(); CultureInfo cultureInfo2; if (text == string.Empty) { cultureInfo2 = ((!(formattingInfo.FormatDetails.Provider is CultureInfo cultureInfo)) ? CultureInfo.CurrentUICulture : cultureInfo); if (cultureInfo2.Equals(CultureInfo.InvariantCulture)) { cultureInfo2 = CultureInfo.GetCultureInfo("en"); } } else { try { cultureInfo2 = CultureInfo.GetCultureInfo(text); } catch (Exception formatException) { throw new FormattingException(formattingInfo.Format, formatException, 0); } } return cultureInfo2; } } public class ReflectionSource : Source { private static readonly object[] Empty = Array.Empty(); private static int _maxCacheSize = 500; public const int DefaultCacheSize = 500; protected internal static readonly IDictionary<(Type, string?), (FieldInfo? field, MethodInfo? method)> TypeCache; public static int MaxCacheSize { get { return _maxCacheSize; } set { _maxCacheSize = ((value > 0) ? value : 500); } } public bool IsTypeCacheEnabled { get; set; } = true; public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { object currentValue = selectorInfo.CurrentValue; if (TrySetResultForNullableOperator(selectorInfo)) { return true; } if ((currentValue == null || currentValue is string) ? true : false) { return false; } string selectorText = selectorInfo.SelectorText; Type type = currentValue.GetType(); if (IsTypeCacheEnabled && TypeCache.TryGetValue((type, selectorText), out (FieldInfo, MethodInfo) value)) { if (value.Item1 != null) { selectorInfo.Result = value.Item1.GetValue(currentValue); return true; } if (value.Item2 != null) { selectorInfo.Result = value.Item2.Invoke(currentValue, Empty); return true; } return false; } if (EvaluateMembers(selectorInfo, selectorText, currentValue, type)) { return true; } AddToCache(type, selectorText, null, null, IsTypeCacheEnabled); return false; } private bool EvaluateMembers(ISelectorInfo selectorInfo, string selector, object current, Type sourceType) { string selector2 = selector; StringComparison comparison = selectorInfo.FormatDetails.Settings.GetCaseSensitivityComparison(); foreach (MemberInfo item in from m in sourceType.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public) where string.Equals(m.Name, selector2, comparison) select m) { switch (item.MemberType) { case MemberTypes.Field: { FieldInfo fieldInfo = item as FieldInfo; selectorInfo.Result = fieldInfo?.GetValue(current); AddToCache(sourceType, selector2, fieldInfo, null, IsTypeCacheEnabled); return true; } case MemberTypes.Method: case MemberTypes.Property: { if (TryGetMethodInfo(item, out MethodInfo method) && ((object)method == null || method.GetParameters().Length == 0) && !(method?.ReturnType == typeof(void))) { AddToCache(sourceType, selector2, null, method, IsTypeCacheEnabled); selectorInfo.Result = method?.Invoke(current, Array.Empty()); return true; } break; } } } return false; } private static void AddToCache(Type sourceType, string selector, FieldInfo? field, MethodInfo? method, bool isCacheEnabled) { if (isCacheEnabled) { while (TypeCache.Count > 0 && TypeCache.Count >= MaxCacheSize) { TypeCache.Remove(TypeCache.First()); } TypeCache[(sourceType, selector)] = (field, method); } } private static bool TryGetMethodInfo(MemberInfo member, out MethodInfo? method) { if (member.MemberType == MemberTypes.Property) { if (member is PropertyInfo propertyInfo && propertyInfo.CanRead) { method = propertyInfo.GetGetMethod(); return true; } method = null; return false; } method = member as MethodInfo; return true; } static ReflectionSource() { IDictionary<(Type, string), (FieldInfo, MethodInfo)> typeCache; if (!SmartSettings.IsThreadSafeMode) { IDictionary<(Type, string), (FieldInfo, MethodInfo)> dictionary = new Dictionary<(Type, string), (FieldInfo, MethodInfo)>(MaxCacheSize, EqualityComparer<(Type, string)>.Default); typeCache = dictionary; } else { IDictionary<(Type, string), (FieldInfo, MethodInfo)> dictionary = new ConcurrentDictionary<(Type, string), (FieldInfo, MethodInfo)>(EqualityComparer<(Type, string)>.Default); typeCache = dictionary; } TypeCache = typeCache; } } public class StringSource : Source { private CultureInfo _cultureInfo = CultureInfo.CurrentUICulture; protected Dictionary> SelectorMethods { get; private set; } public StringSource() { SelectorMethods = new Dictionary>(); } public override void Initialize(SmartFormatter smartFormatter) { base.Initialize(smartFormatter); IEqualityComparer caseSensitivityComparer = smartFormatter.Settings.GetCaseSensitivityComparer(); SelectorMethods = new Dictionary>(caseSensitivityComparer); AddMethods(); } private void AddMethods() { SelectorMethods.Add("Length", Length); SelectorMethods.Add("ToUpper", ToUpper); SelectorMethods.Add("ToUpperInvariant", ToUpperInvariant); SelectorMethods.Add("ToLower", ToLower); SelectorMethods.Add("ToLowerInvariant", ToLowerInvariant); SelectorMethods.Add("Trim", Trim); SelectorMethods.Add("TrimStart", TrimStart); SelectorMethods.Add("TrimEnd", TrimEnd); SelectorMethods.Add("ToCharArray", ToCharArray); SelectorMethods.Add("Capitalize", Capitalize); SelectorMethods.Add("CapitalizeWords", CapitalizeWords); SelectorMethods.Add("ToBase64", ToBase64); SelectorMethods.Add("FromBase64", FromBase64); } public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (TrySetResultForNullableOperator(selectorInfo)) { return true; } if (!(selectorInfo.CurrentValue is string arg)) { return false; } string selectorText = selectorInfo.SelectorText; _cultureInfo = GetCulture(selectorInfo.FormatDetails); if (!SelectorMethods.TryGetValue(selectorText, out Func value)) { return false; } if (selectorInfo.FormatDetails.Settings.CaseSensitivity == CaseSensitivityType.CaseSensitive && value.Method.Name != selectorText) { return false; } return value(selectorInfo, arg); } private static bool Length(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.Length; return true; } private bool ToUpper(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.ToUpper(_cultureInfo); return true; } private static bool ToUpperInvariant(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.ToUpperInvariant(); return true; } private bool ToLower(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.ToLower(_cultureInfo); return true; } private static bool ToLowerInvariant(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.ToLowerInvariant(); return true; } private static bool Trim(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.Trim(); return true; } private static bool TrimStart(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.TrimStart(); return true; } private static bool TrimEnd(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.TrimEnd(); return true; } private static bool ToCharArray(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = currentValue.ToCharArray(); return true; } private bool Capitalize(ISelectorInfo selectorInfo, string currentValue) { if (currentValue.Length < 1 || char.IsUpper(currentValue[0])) { selectorInfo.Result = currentValue; return true; } if (currentValue.Length < 2) { selectorInfo.Result = char.ToUpper(currentValue[0], _cultureInfo); return true; } selectorInfo.Result = char.ToUpper(currentValue[0], _cultureInfo) + currentValue.Substring(1); return true; } private bool CapitalizeWords(ISelectorInfo selectorInfo, string currentValue) { if (string.IsNullOrEmpty(currentValue)) { selectorInfo.Result = currentValue; return true; } char[] array = currentValue.ToCharArray(); bool flag = true; for (int i = 0; i < array.Length; i++) { char c = array[i]; if (char.IsWhiteSpace(c)) { flag = true; } else if (flag && char.IsLetter(c)) { array[i] = char.ToUpper(c, _cultureInfo); flag = false; } } selectorInfo.Result = new string(array); return true; } private static bool ToBase64(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = Convert.ToBase64String(Encoding.UTF8.GetBytes(currentValue)); return true; } private static bool FromBase64(ISelectorInfo selectorInfo, string currentValue) { selectorInfo.Result = Encoding.UTF8.GetString(Convert.FromBase64String(currentValue)); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static CultureInfo GetCulture(FormatDetails formatDetails) { if (formatDetails.Provider is CultureInfo result) { return result; } return CultureInfo.CurrentUICulture; } } public class SubStringFormatter : IFormatter { public enum SubStringOutOfRangeBehavior { ReturnEmptyString, ReturnStartIndexToEndOfString, ThrowException } private char _splitChar = ','; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[1] { "substr" }; public string Name { get; set; } = "substr"; public bool CanAutoDetect { get; set; } public char SplitChar { get { return _splitChar; } set { _splitChar = Validation.GetValidSplitCharOrThrow(value); } } public string NullDisplayString { get; set; } = string.Empty; public SubStringOutOfRangeBehavior OutOfRangeBehavior { get; set; } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { string[] array = formattingInfo.FormatterOptions.Split(SplitChar); object currentValue = formattingInfo.CurrentValue; bool flag = ((currentValue is string || currentValue == null) ? true : false); if (!flag || (array.Length == 1 && array[0].Length == 0)) { if (string.IsNullOrEmpty(formattingInfo.Placeholder?.FormatterName)) { return false; } throw new FormatException("Formatter named '" + formattingInfo.Placeholder?.FormatterName + "' requires at least 1 formatter option and a string? argument."); } string text = formattingInfo.CurrentValue?.ToString(); ReadOnlySpan text2 = ((text == null) ? ReadOnlySpan.Empty : GetSubstring(text.AsSpan(), array)); Format format = formattingInfo.Format; if (format != null && format.Length > 0) { if (!format.HasNested) { throw new FormattingException(formattingInfo.Format, "The format requires a nested placeholder", format.StartIndex); } formattingInfo.FormatAsChild(format, (text == null) ? null : text2.ToString()); return true; } if (text == null) { formattingInfo.Write(NullDisplayString); return true; } formattingInfo.Write(text2); return true; } private ReadOnlySpan GetSubstring(ReadOnlySpan currentValue, string[] parameters) { var (num, num2) = GetStartAndLength(currentValue, parameters); switch (OutOfRangeBehavior) { case SubStringOutOfRangeBehavior.ReturnEmptyString: if (num + num2 > currentValue.Length) { num2 = 0; } break; case SubStringOutOfRangeBehavior.ReturnStartIndexToEndOfString: if (num + num2 > currentValue.Length) { num2 = currentValue.Length - num; } break; } if (parameters.Length <= 1) { return currentValue.Slice(num); } return currentValue.Slice(num, num2); } private static (int startPos, int length) GetStartAndLength(ReadOnlySpan currentValue, string[] parameters) { int num = int.Parse(parameters[0]); int num2 = ((parameters.Length > 1) ? int.Parse(parameters[1]) : 0); if (num < 0) { num = currentValue.Length + num; } if (num > currentValue.Length) { num = currentValue.Length; } if (num2 < 0) { num2 = currentValue.Length - num + num2; } return (num, num2); } } public class TemplateFormatter : IFormatter, IInitializer { private SmartFormatter? _formatter; private Dictionary? _templates; private readonly bool _canHandleAutoDetection; [Obsolete("Use property \"Name\" instead", true)] public string[] Names { get; set; } = new string[2] { "template", "t" }; public string Name { get; set; } = "t"; public bool CanAutoDetect { get { return _canHandleAutoDetection; } set { if (value) { throw new ArgumentException("TemplateFormatter cannot handle auto-detection"); } } } public bool TryEvaluateFormat(IFormattingInfo formattingInfo) { string text = formattingInfo.FormatterOptions; if (text == string.Empty) { Format format = formattingInfo.Format; if (format != null && format.HasNested) { return false; } text = formattingInfo.Format?.RawText; } if (!_templates.TryGetValue(text, out Format value)) { throw new FormatException($"Formatter named '{formattingInfo.Placeholder?.FormatterName}' found no registered template named '{text}'"); } formattingInfo.FormatAsChild(value, formattingInfo.CurrentValue); return true; } public void Register(string templateName, string template) { Format value = _formatter.Parser.ParseFormat(template); _templates.Add(templateName, value); } public bool Remove(string templateName) { return _templates.Remove(templateName); } public void Clear() { _templates.Clear(); } public void Initialize(SmartFormatter smartFormatter) { _formatter = smartFormatter; IEqualityComparer caseSensitivityComparer = _formatter.Settings.GetCaseSensitivityComparer(); _templates = new Dictionary(caseSensitivityComparer); } } public class ValueTupleSource : Source { public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) { if (!(selectorInfo is FormattingInfo formattingInfo)) { return false; } if (formattingInfo.CurrentValue == null || !formattingInfo.CurrentValue.IsValueTuple()) { return false; } object currentValue = formattingInfo.CurrentValue; foreach (object item in formattingInfo.CurrentValue.GetValueTupleItemObjectsFlattened()) { formattingInfo.CurrentValue = item; foreach (ISource sourceExtension in selectorInfo.FormatDetails.Formatter.SourceExtensions) { if (sourceExtension.TryEvaluateSelector(formattingInfo)) { formattingInfo.CurrentValue = currentValue; return true; } } } formattingInfo.CurrentValue = currentValue; return false; } } public static class WellKnownExtensionTypes { private static HashSet<(Type ExtensionType, bool IsSingleton)>? _formatterTypes; private static HashSet<(Type ExtensionType, bool IsSingleton)>? _sourceTypes; public static Dictionary Sources { get; } = new Dictionary(StringComparer.Ordinal) { { "SmartFormat.Extensions.GlobalVariablesSource", 1000 }, { "SmartFormat.Extensions.PersistentVariablesSource", 2000 }, { "SmartFormat.Extensions.StringSource", 3000 }, { "SmartFormat.Extensions.ListFormatter", 4000 }, { "SmartFormat.Extensions.DictionarySource", 5000 }, { "SmartFormat.Extensions.ValueTupleSource", 6000 }, { "SmartFormat.Extensions.SystemTextJsonSource", 7000 }, { "SmartFormat.Extensions.NewtonsoftJsonSource", 8000 }, { "SmartFormat.Extensions.XmlSource", 9000 }, { "SmartFormat.Extensions.ReflectionSource", 10000 }, { "SmartFormat.Extensions.KeyValuePairSource", 11000 }, { "SmartFormat.Extensions.DefaultSource", 12000 } }; public static Dictionary Formatters { get; } = new Dictionary(StringComparer.Ordinal) { { "SmartFormat.Extensions.ListFormatter", 1000 }, { "SmartFormat.Extensions.PluralLocalizationFormatter", 2000 }, { "SmartFormat.Extensions.ConditionalFormatter", 3000 }, { "SmartFormat.Extensions.TimeFormatter", 4000 }, { "SmartFormat.Extensions.XElementFormatter", 5000 }, { "SmartFormat.Extensions.IsMatchFormatter", 6000 }, { "SmartFormat.Extensions.NullFormatter", 7000 }, { "SmartFormat.Extensions.LocalizationFormatter", 8000 }, { "SmartFormat.Extensions.TemplateFormatter", 9000 }, { "SmartFormat.Extensions.ChooseFormatter", 10000 }, { "SmartFormat.Extensions.SubStringFormatter", 11000 }, { "SmartFormat.Extensions.DefaultFormatter", 12000 } }; internal static int GetIndexToInsert(IList currentExtensions, T extensionToInsert) where T : class { if (!currentExtensions.Any()) { return 0; } Dictionary dictionary = (typeof(T).IsAssignableFrom(typeof(ISource)) ? Sources : Formatters); if (!dictionary.TryGetValue(extensionToInsert.GetType().FullName, out var value)) { return currentExtensions.Count; } for (int num = currentExtensions.Count - 1; num >= 0; num--) { if (dictionary.TryGetValue(currentExtensions[num].GetType().FullName, out var value2) && value2 <= value) { return num + 1; } } return 0; } internal static HashSet<(Type ExtensionType, bool IsSingleton)> GetReferencedExtensions() { if (typeof(T).IsAssignableFrom(typeof(IFormatter))) { if (_formatterTypes == null) { _formatterTypes = FetchReferencedExtensions(Assembly.GetCallingAssembly()); } return _formatterTypes; } if (typeof(T).IsAssignableFrom(typeof(ISource))) { if (_sourceTypes == null) { _sourceTypes = FetchReferencedExtensions(Assembly.GetCallingAssembly()); } return _sourceTypes; } throw new InvalidOperationException("The Type argument must be 'IFormatter' or 'ISource'."); } private static HashSet<(Type ExtensionType, bool IsSingleton)> FetchReferencedExtensions(Assembly callingAssembly) { HashSet<(Type ExtensionType, bool IsSingleton)> allExtensionTypes = new HashSet<(Type, bool)>(); AssemblyName[] referencedAssemblies = callingAssembly.GetReferencedAssemblies(); for (int i = 0; i < referencedAssemblies.Length; i++) { Type[] types = Assembly.Load(referencedAssemblies[i]).GetTypes(); types.Where(TransientCondition).ToList().ForEach(delegate(Type t) { allExtensionTypes.Add((t, false)); }); types.Where(SingletonCondition).ToList().ForEach(delegate(Type t) { allExtensionTypes.Add((t, true)); }); } return allExtensionTypes; static bool SingletonCondition(Type t) { if (typeof(T).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass) { return t.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public) != null; } return false; } static bool TransientCondition(Type t) { if (typeof(T).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass) { return t.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null) != null; } return false; } } internal static T CreateInstanceForType((Type ExtensionType, bool IsSingleton) wellKnown) { if (wellKnown.IsSingleton) { return (T)wellKnown.ExtensionType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public).GetValue(wellKnown); } return (T)Activator.CreateInstance(Type.GetType(wellKnown.ExtensionType.AssemblyQualifiedName)); } } } namespace SmartFormat.Extensions.PersistentVariables { public class Variable : IVariable { public T? Value { get; set; } public Variable(T? value) { Value = value; } public object? GetValue() { return Value; } public override string ToString() { T value = Value; return ((value != null) ? value.ToString() : null) ?? string.Empty; } } public class FloatVariable : Variable { public FloatVariable(float? value) : base(value) { } } public class StringVariable : Variable { public StringVariable(string? value) : base(value) { } } public class IntVariable : Variable { public IntVariable(int? value) : base(value) { } } public class BoolVariable : Variable { public BoolVariable(bool? value) : base(value) { } } public class ObjectVariable : Variable { public ObjectVariable(object? value) : base(value) { } } public interface IVariablesGroup { bool TryGetValue(string name, out IVariable value); } public interface IVariable { object? GetValue(); } internal class NameVariablePair { public string Name { get; } public IVariable Variable { get; } public NameVariablePair(string name, IVariable variable) { Name = name; Variable = variable; } public override string ToString() { return $"'{Name}' - '{Variable.GetValue()?.GetType()}' - '{Variable.GetValue()}'"; } } public class VariablesGroup : IVariablesGroup, IVariable, IDictionary, ICollection>, IEnumerable>, IEnumerable { private readonly IDictionary _variableLookup = (SmartSettings.IsThreadSafeMode ? ((IDictionary)new ConcurrentDictionary()) : ((IDictionary)new Dictionary())); public int Count => _variableLookup.Count; public ICollection Keys => _variableLookup.Keys; public ICollection Values => _variableLookup.Values.Select((NameVariablePair s) => s.Variable).ToList(); public bool IsReadOnly => false; public IVariable this[string name] { get { return _variableLookup[name].Variable; } set { Add(name, value); } } public object GetValue() { return this; } public bool TryGetValue(string name, out IVariable value) { if (_variableLookup.TryGetValue(name, out NameVariablePair value2)) { value = value2.Variable; return true; } value = null; return false; } public void Add(string name, IVariable variable) { if (string.IsNullOrEmpty(name)) { throw new ArgumentException("Name must not be null or empty.", "name"); } NameVariablePair value = new NameVariablePair(name, variable); _variableLookup.Add(name, value); } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public bool Remove(string name) { return _variableLookup.Remove(name); } public bool Remove(KeyValuePair item) { return Remove(item.Key); } public bool ContainsKey(string name) { return _variableLookup.ContainsKey(name); } public bool Contains(KeyValuePair item) { if (TryGetValue(item.Key, out IVariable value)) { return value == item.Value; } return false; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (KeyValuePair item in _variableLookup) { array[arrayIndex++] = new KeyValuePair(item.Key, item.Value.Variable); } } public VariablesGroup Clone() { VariablesGroup variablesGroup = new VariablesGroup(); foreach (KeyValuePair item in _variableLookup) { variablesGroup.Add(item.Key, item.Value.Variable); } return variablesGroup; } IEnumerator> IEnumerable>.GetEnumerator() { return _variableLookup.Select, KeyValuePair>((KeyValuePair v) => new KeyValuePair(v.Key, v.Value.Variable)).GetEnumerator(); } public IEnumerator GetEnumerator() { return _variableLookup.Select, KeyValuePair>((KeyValuePair v) => new KeyValuePair(v.Key, v.Value.Variable)).GetEnumerator(); } public void Clear() { _variableLookup.Clear(); } } } namespace SmartFormat.Core.Settings { public enum CaseSensitivityType { CaseSensitive, CaseInsensitive } [Obsolete("Use 'ParseErrorAction' or 'FormatErrorAction' instead.", true)] public enum ErrorAction { ThrowError, OutputErrorInResult, Ignore, MaintainTokens } public enum FormatErrorAction { ThrowError, OutputErrorInResult, Ignore, MaintainTokens } public class FormatterSettings { public FormatErrorAction ErrorAction { get; set; } public char AlignmentFillCharacter { get; set; } = ' '; } public class Localization { public ILocalizationProvider? LocalizationProvider { get; set; } } public enum ParseErrorAction { ThrowError, OutputErrorInResult, Ignore, MaintainTokens } public class ParserSettings { private readonly List _alphanumericSelectorChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-".ToList(); private readonly List _customSelectorChars = new List(); private readonly List _customOperatorChars = new List(); public ParseErrorAction ErrorAction { get; set; } public bool ConvertCharacterStringLiterals { get; set; } = true; public bool ParseInputAsHtml { get; set; } internal char CharLiteralEscapeChar { get; set; } = '\\'; internal char FormatterNameSeparator { get; } = ':'; internal char AlignmentOperator { get; } = ','; internal char SelectorOperator { get; } = '.'; internal char NullableOperator { get; } = '?'; internal char PlaceholderBeginChar { get; } = '{'; internal char PlaceholderEndChar { get; } = '}'; internal char FormatterOptionsBeginChar { get; } = '('; internal char FormatterOptionsEndChar { get; } = ')'; internal char ListIndexBeginChar { get; } = '['; internal char ListIndexEndChar { get; } = ']'; internal List SelectorChars() { return _alphanumericSelectorChars; } internal List CustomSelectorChars() { return _customSelectorChars; } internal List DisallowedSelectorChars() { List list = new List(); list.Add(CharLiteralEscapeChar); list.Add(FormatterNameSeparator); list.Add(AlignmentOperator); list.Add(SelectorOperator); list.Add(PlaceholderBeginChar); list.Add(PlaceholderEndChar); list.Add(FormatterOptionsBeginChar); list.Add(FormatterOptionsEndChar); list.AddRange(OperatorChars()); return list; } internal List CustomOperatorChars() { return _customOperatorChars; } public void AddCustomSelectorChars(IList characters) { foreach (char character in characters) { if (DisallowedSelectorChars().Contains(character) || _customOperatorChars.Contains(character)) { throw new ArgumentException($"Cannot add '{character}' as a custom selector character. It is disallowed or in use as an operator."); } if (!_customSelectorChars.Contains(character) && !_alphanumericSelectorChars.Contains(character)) { _customSelectorChars.Add(character); } } } public void AddCustomOperatorChars(IList characters) { foreach (char c in characters) { if ((from _ in DisallowedSelectorChars() where OperatorChars().TrueForAll((char ch) => ch != c) select _).Contains(c) || SelectorChars().Contains(c) || CustomSelectorChars().Contains(c)) { throw new ArgumentException($"Cannot add '{c}' as a custom operator character. It is disallowed or in use as a selector."); } if (!OperatorChars().Contains(c) && !CustomOperatorChars().Contains(c)) { _customOperatorChars.Add(c); } } } internal List OperatorChars() { return new List { SelectorOperator, NullableOperator, AlignmentOperator, ListIndexBeginChar, ListIndexEndChar }; } internal List FormatOptionsTerminatorChars() { return new List { FormatterNameSeparator, FormatterOptionsBeginChar, FormatterOptionsEndChar, PlaceholderBeginChar, PlaceholderEndChar }; } } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct PoolSettings { public static bool IsPoolingEnabled { get; set; } = true; public static bool CheckReturnedObjectsExistInPool { get; set; } = false; } public class SmartSettings { public static bool IsThreadSafeMode { get; set; } = true; public bool StringFormatCompatibility { get; set; } [Obsolete("Use 'SmartSettings.Formatter.ErrorAction' instead.", true)] public ErrorAction FormatErrorAction { get { return (ErrorAction)Formatter.ErrorAction; } set { Formatter.ErrorAction = (FormatErrorAction)value; } } [Obsolete("Use 'SmartSettings.Parser.ErrorAction' instead.", true)] public ErrorAction ParseErrorAction { get { return (ErrorAction)Parser.ErrorAction; } set { Parser.ErrorAction = (ParseErrorAction)value; } } public CaseSensitivityType CaseSensitivity { get; set; } [Obsolete("Use SmartSettings.Parser.ConvertCharacterStringLiterals instead", true)] public bool ConvertCharacterStringLiterals { get { return Parser.ConvertCharacterStringLiterals; } set { Parser.ConvertCharacterStringLiterals = value; } } public ParserSettings Parser { get; set; } = new ParserSettings(); public FormatterSettings Formatter { get; set; } = new FormatterSettings(); public Localization Localization { get; set; } = new Localization(); public PoolSettings Pooling { get; set; } public IEqualityComparer GetCaseSensitivityComparer() { if (CaseSensitivity != 0) { return StringComparer.OrdinalIgnoreCase; } return StringComparer.Ordinal; } public StringComparison GetCaseSensitivityComparison() { if (CaseSensitivity != 0) { return StringComparison.OrdinalIgnoreCase; } return StringComparison.Ordinal; } } } namespace SmartFormat.Core.Parsing { public static class EscapedLiteral { [CompilerGenerated] private sealed class <>c__DisplayClass6_0 { public char c; internal bool b__0(KeyValuePair kv) { return kv.Value == c; } internal bool b__1(KeyValuePair kv) { return kv.Value == c; } internal bool b__2(KeyValuePair kv) { return kv.Value == c; } } [CompilerGenerated] private sealed class d__6 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private char <>2__current; private int <>l__initialThreadId; private int startIndex; public int <>3__startIndex; private int length; public int <>3__length; private string input; public string <>3__input; private char escapeSequenceStart; public char <>3__escapeSequenceStart; private <>c__DisplayClass6_0 <>8__1; private bool includeFormatterOptionChars; public bool <>3__includeFormatterOptionChars; private int 5__2; private int 5__3; char IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = startIndex + length; 5__3 = startIndex; break; case 1: <>1__state = -1; <>2__current = GeneralLookupTable.First((KeyValuePair kv) => kv.Value == <>8__1.c).Key; <>1__state = 2; return true; case 2: <>1__state = -1; goto IL_0201; case 3: <>1__state = -1; <>2__current = CharLiteralLookupTable.First((KeyValuePair kv) => kv.Value == <>8__1.c).Key; <>1__state = 4; return true; case 4: <>1__state = -1; goto IL_0201; case 5: <>1__state = -1; <>2__current = FormatterOptionsLookupTable.First((KeyValuePair kv) => kv.Value == <>8__1.c).Key; <>1__state = 6; return true; case 6: <>1__state = -1; goto IL_0201; case 7: { <>1__state = -1; <>8__1 = null; goto IL_0201; } IL_0201: 5__3++; break; } if (5__3 < 5__2) { <>8__1 = new <>c__DisplayClass6_0(); <>8__1.c = input[5__3]; if (GeneralLookupTable.ContainsValue(<>8__1.c)) { <>2__current = escapeSequenceStart; <>1__state = 1; return true; } if (CharLiteralLookupTable.ContainsValue(<>8__1.c)) { <>2__current = escapeSequenceStart; <>1__state = 3; return true; } if (includeFormatterOptionChars && FormatterOptionsLookupTable.ContainsValue(<>8__1.c)) { <>2__current = escapeSequenceStart; <>1__state = 5; return true; } <>2__current = <>8__1.c; <>1__state = 7; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__6 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__6(0); } d__.escapeSequenceStart = <>3__escapeSequenceStart; d__.input = <>3__input; d__.startIndex = <>3__startIndex; d__.length = <>3__length; d__.includeFormatterOptionChars = <>3__includeFormatterOptionChars; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly Dictionary GeneralLookupTable = new Dictionary { { '\\', '\\' }, { '{', '{' }, { '}', '}' }, { ':', ':' } }; private static readonly Dictionary CharLiteralLookupTable = new Dictionary { { '0', '\0' }, { 'a', '\a' }, { 'b', '\b' }, { 'f', '\f' }, { 'n', '\n' }, { 'r', '\r' }, { 't', '\t' }, { 'v', '\v' } }; private static readonly Dictionary FormatterOptionsLookupTable = new Dictionary { { '(', '(' }, { ')', ')' } }; public static bool TryGetChar(char input, out char result, bool includeFormatterOptionChars, bool includeCharacterLiterals = true) { if (!GeneralLookupTable.TryGetValue(input, out result) && (!includeCharacterLiterals || !CharLiteralLookupTable.TryGetValue(input, out result))) { if (includeFormatterOptionChars) { return FormatterOptionsLookupTable.TryGetValue(input, out result); } return false; } return true; } private static char GetUnicode(ReadOnlySpan input, int startIndex) { ReadOnlySpan s = ((input.Length - startIndex >= 4) ? input.Slice(startIndex, 4) : input.Slice(startIndex)); if (int.TryParse(s, NumberStyles.HexNumber, null, out var result)) { return (char)result; } throw new ArgumentException("Unrecognized escape sequence in literal: \"\\u" + s.ToString() + "\""); } public static ReadOnlySpan UnEscapeCharLiterals(char escapingSequenceStart, ReadOnlySpan input, bool includeFormatterOptionChars, bool includeCharacterLiterals, Span resultBuffer) { int length = input.Length; int length2 = 0; int num = 0; while (num < length) { if (num + 1 < length) { int num2 = num + 1; if (input[num] == escapingSequenceStart) { if (input[num2] == 'u') { resultBuffer[length2++] = GetUnicode(input, num2 + 1); num += 6; continue; } if (!TryGetChar(input[num2], out var result, includeFormatterOptionChars, includeCharacterLiterals)) { throw new ArgumentException($"Unrecognized escape sequence \"{input[num]}{input[num2]}\" in literal."); } resultBuffer[length2++] = result; num += 2; } else { resultBuffer[length2++] = input[num]; num++; } continue; } resultBuffer[length2++] = input[num]; return resultBuffer.Slice(0, length2); } return resultBuffer.Slice(0, length2); } [IteratorStateMachine(typeof(d__6))] public static IEnumerable EscapeCharLiterals(char escapeSequenceStart, string input, int startIndex, int length, bool includeFormatterOptionChars, bool includeCharLiterals = true) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(-2) { <>3__escapeSequenceStart = escapeSequenceStart, <>3__input = input, <>3__startIndex = startIndex, <>3__length = length, <>3__includeFormatterOptionChars = includeFormatterOptionChars }; } } public sealed class Format : FormatItem, IDisposable { private string? _toStringCache; private string? _literalTextCache; private char _splitCacheChar; private IList? _splitCache; private readonly List _listOfSplitLists = new List(); public Placeholder? ParentPlaceholder { get; internal set; } public List Items { get; } = new List(); public bool HasNested => Items.Exists((FormatItem i) => i is Placeholder); public Format Initialize(SmartSettings smartSettings, string baseString) { base.Initialize(smartSettings, null, baseString, 0, baseString.Length); ParentPlaceholder = null; return this; } public Format Initialize(SmartSettings smartSettings, Placeholder parent, int startIndex) { base.Initialize(smartSettings, parent, parent.BaseString, startIndex, parent.EndIndex); ParentPlaceholder = parent; return this; } public Format Initialize(SmartSettings smartSettings, string baseString, int startIndex, int endIndex) { base.Initialize(smartSettings, null, baseString, startIndex, endIndex); ParentPlaceholder = null; return this; } [Obsolete("Use the overload without 'hasNested' instead.")] public Format Initialize(SmartSettings smartSettings, string baseString, int startIndex, int endIndex, bool hasNested) { Initialize(smartSettings, baseString, startIndex, endIndex); return this; } public void ReturnToPool() { Clear(); ParentPlaceholder = null; foreach (FormatItem item in Items) { if (this == item.ParentFormatItem) { ReturnFormatItemToPool(item); } } Items.Clear(); foreach (SplitList listOfSplitList in _listOfSplitLists) { SplitListPool.Instance.Return(listOfSplitList); } _listOfSplitLists.Clear(); _splitCache = null; _toStringCache = null; _literalTextCache = null; } public Format Substring(int start) { return Substring(start, base.Length - start); } public Format Substring(int start, int length) { start = base.StartIndex + start; int num = start + length; ValidateArguments(start, length); if (start == base.StartIndex && num == base.EndIndex) { return this; } Format format = FormatPool.Instance.Get().Initialize(base.SmartSettings, base.BaseString, start, num); foreach (FormatItem item2 in Items) { if (item2.EndIndex > start) { if (num <= item2.StartIndex) { break; } FormatItem item = item2; if (item2 is LiteralText && (start > item2.StartIndex || item2.EndIndex > num)) { item = LiteralTextPool.Instance.Get().Initialize(format.SmartSettings, format, format.BaseString, Math.Max(start, item2.StartIndex), Math.Min(num, item2.EndIndex)); } format.Items.Add(item); } } return format; } private void ValidateArguments(int start, int length) { int num = start + length; if (start < base.StartIndex || start > base.EndIndex) { throw new ArgumentOutOfRangeException("start"); } if (num > base.EndIndex) { throw new ArgumentOutOfRangeException("length"); } } public int IndexOf(char search) { return IndexOf(search, 0); } public int IndexOf(char search, int start) { start = base.StartIndex + start; foreach (FormatItem item in Items) { if (item.EndIndex >= start && item is LiteralText literalText) { if (start < literalText.StartIndex) { start = literalText.StartIndex; } int num = literalText.BaseString.IndexOf(search, start, literalText.EndIndex - start); if (num != -1) { return num - base.StartIndex; } } } return -1; } private List FindAll(char search, int maxCount) { List list = ListPool.Instance.Get(); int start = 0; while (maxCount != 0) { start = IndexOf(search, start); if (start == -1) { break; } list.Add(start); start++; maxCount--; } return list; } public IList Split(char search) { if (_splitCache == null || _splitCacheChar != search) { _splitCacheChar = search; _splitCache = Split(search, -1); } return _splitCache; } public IList Split(char search, int maxCount) { List splits = FindAll(search, maxCount); SplitList splitList = SplitListPool.Instance.Get().Initialize(this, splits); _listOfSplitLists.Add(splitList); return splitList; } public string GetLiteralText() { if (_literalTextCache != null) { return _literalTextCache; } ZCharArray zCharArray = new ZCharArray(base.Length); foreach (FormatItem item in Items) { if (item is LiteralText literalText) { zCharArray.Write(literalText.AsSpan()); } } _literalTextCache = zCharArray.GetSpan().ToString(); return _literalTextCache; } public override string ToString() { if (_toStringCache != null) { return _toStringCache; } ZCharArray zCharArray = new ZCharArray(base.BaseString.Length); foreach (FormatItem item in Items) { zCharArray.Write(item.AsSpan()); } _toStringCache = zCharArray.GetSpan().ToString(); return _toStringCache; } private static void ReturnFormatItemToPool(FormatItem formatItem) { if (!(formatItem is LiteralText toReturn)) { if (!(formatItem is Format toReturn2)) { if (!(formatItem is Placeholder toReturn3)) { if (!(formatItem is Selector toReturn4)) { throw new ArgumentException($"Unhandled type '{formatItem.GetType()}'", "formatItem"); } SelectorPool.Instance.Return(toReturn4); } else { PlaceholderPool.Instance.Return(toReturn3); } } else { FormatPool.Instance.Return(toReturn2); } } else { LiteralTextPool.Instance.Return(toReturn); } } private void Dispose(bool disposing) { if (disposing) { FormatPool.Instance.Return(this); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } ~Format() { Dispose(disposing: false); } } public abstract class FormatItem { private string? _toStringCache; public string BaseString { get; protected set; } = string.Empty; public int EndIndex { get; set; } public int StartIndex { get; set; } public int Length => EndIndex - StartIndex; public SmartSettings SmartSettings { get; protected set; } = InitializationObject.SmartSettings; public FormatItem? ParentFormatItem { get; private set; } public string RawText => ToString(); protected virtual void Initialize(SmartSettings smartSettings, FormatItem? parent, string baseString, int startIndex, int endIndex) { ParentFormatItem = parent; SmartSettings = smartSettings; BaseString = baseString; StartIndex = startIndex; EndIndex = endIndex; } public virtual void Clear() { _toStringCache = null; BaseString = string.Empty; EndIndex = 0; StartIndex = 0; SmartSettings = InitializationObject.SmartSettings; ParentFormatItem = null; } public override string ToString() { return _toStringCache ?? (_toStringCache = AsSpan().ToString()); } public virtual ReadOnlySpan AsSpan() { if (EndIndex > StartIndex) { return BaseString.AsSpan(StartIndex, Length); } return ReadOnlySpan.Empty; } } public class LiteralText : FormatItem { private string? _toStringCache; public new LiteralText Initialize(SmartSettings smartSettings, FormatItem parent, string baseString, int startIndex, int endIndex) { base.Initialize(smartSettings, parent, baseString, startIndex, endIndex); return this; } public override string ToString() { if (_toStringCache != null) { return _toStringCache; } if (base.Length == 0) { _toStringCache = string.Empty; } _toStringCache = AsSpan().ToString(); return _toStringCache; } public override ReadOnlySpan AsSpan() { if (base.Length == 0) { return ReadOnlySpan.Empty; } ReadOnlySpan readOnlySpan = base.BaseString.AsSpan(base.StartIndex, base.Length); if (base.SmartSettings.Parser.ConvertCharacterStringLiterals) { if (readOnlySpan[0] == base.SmartSettings.Parser.CharLiteralEscapeChar) { return EscapedLiteral.UnEscapeCharLiterals(base.SmartSettings.Parser.CharLiteralEscapeChar, readOnlySpan, includeFormatterOptionChars: false, includeCharacterLiterals: true, new char[1]); } } else if (readOnlySpan.Length == 2 && readOnlySpan[0] == readOnlySpan[1] && readOnlySpan[0] == base.SmartSettings.Parser.CharLiteralEscapeChar) { return readOnlySpan.Slice(1); } return readOnlySpan; } public override void Clear() { base.Clear(); _toStringCache = null; } } public class Parser { private enum ParseContext { LiteralText, SelectorHeader } public enum ParsingError { TooManyClosingBraces = 1, TrailingOperatorsInSelector, InvalidCharactersInSelector, MissingClosingBrace } public class ParsingErrorText { private readonly Dictionary _errors = new Dictionary { { ParsingError.TooManyClosingBraces, "Format string has too many closing braces" }, { ParsingError.TrailingOperatorsInSelector, "There are illegal trailing operators in the selector" }, { ParsingError.InvalidCharactersInSelector, "Invalid character in the selector" }, { ParsingError.MissingClosingBrace, "Format string is missing a closing brace" } }; public string this[ParsingError parsingErrorKey] => _errors[parsingErrorKey]; internal ParsingErrorText() { } } private const int PositionUndefined = -1; private readonly ParsingErrorText _parsingErrorText = new ParsingErrorText(); private readonly List _operatorChars; private readonly List _customOperatorChars; private readonly ParserSettings _parserSettings; private readonly List _validSelectorChars; private readonly List _formatOptionsTerminatorChars; public SmartSettings Settings { get; } public event EventHandler? OnParsingFailure; public Parser(SmartSettings? smartSettings = null) { Settings = smartSettings ?? new SmartSettings(); _parserSettings = Settings.Parser; _operatorChars = _parserSettings.OperatorChars(); _customOperatorChars = _parserSettings.CustomOperatorChars(); _formatOptionsTerminatorChars = _parserSettings.FormatOptionsTerminatorChars(); _validSelectorChars = new List(); _validSelectorChars.AddRange(_parserSettings.SelectorChars()); _validSelectorChars.AddRange(_parserSettings.OperatorChars()); _validSelectorChars.AddRange(_parserSettings.CustomSelectorChars()); } [Obsolete("Alphanumeric selectors are always enabled", true)] public void AddAlphanumericSelectors() { } [Obsolete("Use 'Settings.Parser.AddCustomSelectorChars' instead.", true)] public void AddAdditionalSelectorChars(string chars) { _parserSettings.AddCustomSelectorChars(chars.ToCharArray()); } [Obsolete("Use 'Settings.Parser.AddCustomOperatorChars' instead.", true)] public void AddOperators(string chars) { _parserSettings.AddCustomOperatorChars(chars.ToCharArray()); } [Obsolete("Use 'Settings.StringFormatCompatibility' instead.", true)] public void UseAlternativeEscapeChar(char alternativeEscapeChar = '\\') { if (alternativeEscapeChar != _parserSettings.CharLiteralEscapeChar) { throw new ArgumentException("Cannot set an escape character other than '\\'", "alternativeEscapeChar"); } Settings.StringFormatCompatibility = false; } [Obsolete("Use 'Settings.StringFormatCompatibility' instead.", true)] public void UseBraceEscaping() { throw new NotSupportedException("Init-only property Settings.StringFormatCompatibility can only be set in an object initializer"); } [Obsolete("This feature has been removed", true)] public void UseAlternativeBraces(char opening, char closing) { throw new NotSupportedException("This feature has been removed"); } public Format ParseFormat(string inputFormat) { ParserState instance; using (ParserStatePool.Instance.Get(out instance)) { instance.Initialize(inputFormat, FormatPool.Instance.Get().Initialize(Settings, inputFormat)); ParserState.IndexContainer index = instance.Index; ParsingErrors parsingErrors = ParsingErrorsPool.Instance.Get().Initialize(instance.ResultFormat); ParseContext currentContext = ParseContext.LiteralText; Placeholder currentPlaceholder = null; int nestedDepth = 0; index.Current = 0; while (index.Current < instance.InputFormat.Length) { char inputChar = instance.InputFormat[index.Current]; switch (currentContext) { case ParseContext.SelectorHeader: ProcessSelector(inputChar, instance, parsingErrors, ref currentContext, ref currentPlaceholder, ref nestedDepth); break; case ParseContext.LiteralText: ProcessLiteralText(inputChar, instance, parsingErrors, ref currentContext, ref currentPlaceholder, ref nestedDepth); break; } index.Current++; } FinalizeParsing(instance, parsingErrors, currentPlaceholder); if (parsingErrors.HasIssues) { this.OnParsingFailure?.Invoke(this, new ParsingErrorEventArgs(parsingErrors, Settings.Parser.ErrorAction == ParseErrorAction.ThrowError)); return HandleParsingErrors(parsingErrors, instance.ResultFormat); } ParsingErrorsPool.Instance.Return(parsingErrors); return instance.ResultFormat; } } private void ProcessLiteralText(char inputChar, ParserState state, ParsingErrors parsingErrors, ref ParseContext currentContext, ref Placeholder? currentPlaceholder, ref int nestedDepth) { if (_parserSettings.ParseInputAsHtml && inputChar == '<') { ParseHtmlTags(state); } else if (inputChar == _parserSettings.PlaceholderBeginChar) { AddLiteralCharsParsedBefore(state); if (!EscapeLikeStringFormat(_parserSettings.PlaceholderBeginChar, state)) { CreateNewPlaceholder(ref nestedDepth, state, out currentPlaceholder); currentContext = ParseContext.SelectorHeader; } } else if (inputChar == _parserSettings.PlaceholderEndChar) { AddLiteralCharsParsedBefore(state); if (!EscapeLikeStringFormat(_parserSettings.PlaceholderEndChar, state) && !HasProcessedTooManyClosingBraces(parsingErrors, state)) { FinishPlaceholderFormat(ref nestedDepth, state); } } else if (inputChar == _parserSettings.CharLiteralEscapeChar && (_parserSettings.ConvertCharacterStringLiterals || !Settings.StringFormatCompatibility)) { ParseAlternativeEscaping(state); } else if (state.Index.NamedFormatterStart != -1) { ParseNamedFormatter(state); } } private void ProcessSelector(char inputChar, ParserState state, ParsingErrors parsingErrors, ref ParseContext currentContext, ref Placeholder? currentPlaceholder, ref int nestedDepth) { if (currentPlaceholder == null) { throw new InvalidOperationException("Invalid parser context: ProcessSelector called with a null currentPlaceholder."); } if (_operatorChars.Contains(inputChar) || _customOperatorChars.Contains(inputChar)) { if (state.Index.Current != state.Index.LastEnd) { currentPlaceholder.AddSelector(SelectorPool.Instance.Get().Initialize(Settings, currentPlaceholder, state.InputFormat, state.Index.LastEnd, state.Index.Current, state.Index.Operator, state.Index.Selector)); state.Index.Selector++; state.Index.Operator = state.Index.Current; } state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 1); } else if (inputChar == _parserSettings.FormatterNameSeparator) { AddLastSelector(ref currentPlaceholder, state, parsingErrors); Format format = FormatPool.Instance.Get().Initialize(Settings, currentPlaceholder, state.Index.Current + 1); currentPlaceholder.Format = format; state.ResultFormat = format; currentPlaceholder = null; state.Index.NamedFormatterStart = (Settings.StringFormatCompatibility ? (-1) : state.Index.LastEnd); state.Index.NamedFormatterOptionsStart = -1; state.Index.NamedFormatterOptionsEnd = -1; currentContext = ParseContext.LiteralText; } else if (inputChar == _parserSettings.PlaceholderEndChar) { AddLastSelector(ref currentPlaceholder, state, parsingErrors); nestedDepth--; currentPlaceholder.EndIndex = state.Index.SafeAdd(state.Index.Current, 1); currentPlaceholder = null; currentContext = ParseContext.LiteralText; } else if (!_validSelectorChars.Contains(inputChar)) { parsingErrors.AddIssue(state.ResultFormat, $"'0x{Convert.ToUInt32(inputChar):X}': " + _parsingErrorText[ParsingError.InvalidCharactersInSelector], state.Index.Current, state.Index.SafeAdd(state.Index.Current, 1)); } } private void FinalizeParsing(ParserState state, ParsingErrors parsingErrors, Placeholder? currentPlaceholder) { if (state.ResultFormat.ParentPlaceholder != null || currentPlaceholder != null) { parsingErrors.AddIssue(state.ResultFormat, _parsingErrorText[ParsingError.MissingClosingBrace], state.InputFormat.Length, state.InputFormat.Length); state.ResultFormat.EndIndex = state.InputFormat.Length; } else if (state.Index.LastEnd != state.InputFormat.Length) { state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.LastEnd, state.InputFormat.Length)); } while (state.ResultFormat.ParentPlaceholder != null) { state.ResultFormat = state.ResultFormat.ParentPlaceholder.Parent; state.ResultFormat.EndIndex = state.InputFormat.Length; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddLiteralCharsParsedBefore(ParserState state) { if (state.Index.Current != state.Index.LastEnd) { state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.LastEnd, state.Index.Current)); } state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HasProcessedTooManyClosingBraces(ParsingErrors parsingErrors, ParserState state) { if (state.ResultFormat.ParentPlaceholder != null) { return false; } state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.Current, state.Index.Current + 1)); parsingErrors.AddIssue(state.ResultFormat, _parsingErrorText[ParsingError.TooManyClosingBraces], state.Index.Current, state.Index.Current + 1); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool EscapeLikeStringFormat(char brace, ParserState state) { if (!Settings.StringFormatCompatibility) { return false; } if (state.Index.LastEnd < state.InputFormat.Length && state.InputFormat[state.Index.LastEnd] == brace) { state.Index.Current = state.Index.SafeAdd(state.Index.Current, 1); return true; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void CreateNewPlaceholder(ref int nestedDepth, ParserState state, out Placeholder newPlaceholder) { nestedDepth++; newPlaceholder = PlaceholderPool.Instance.Get().Initialize(state.ResultFormat, state.Index.Current, nestedDepth); state.ResultFormat.Items.Add(newPlaceholder); state.Index.Operator = state.Index.SafeAdd(state.Index.Current, 1); state.Index.Selector = 0; state.Index.NamedFormatterStart = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void FinishPlaceholderFormat(ref int nestedDepth, ParserState state) { nestedDepth--; state.ResultFormat.EndIndex = state.Index.Current; state.ResultFormat.ParentPlaceholder.EndIndex = state.Index.SafeAdd(state.Index.Current, 1); state.ResultFormat = state.ResultFormat.ParentPlaceholder.Parent; state.Index.NamedFormatterStart = (state.Index.NamedFormatterOptionsStart = (state.Index.NamedFormatterOptionsEnd = -1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ParseAlternativeEscaping(ParserState state) { int num = state.Index.SafeAdd(state.Index.Current, 1); if (num >= state.InputFormat.Length) { throw new ArgumentException("Unrecognized escape sequence at the end of the literal"); } if (state.InputFormat[num] == _parserSettings.PlaceholderBeginChar || state.InputFormat[num] == _parserSettings.PlaceholderEndChar) { if (state.Index.Current != state.Index.LastEnd) { state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.LastEnd, state.Index.Current)); } state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 1); state.Index.Current++; return; } if (state.Index.Current != state.Index.LastEnd) { state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.LastEnd, state.Index.Current)); } if (state.InputFormat[num] == 'u') { state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 6); } else { state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 2); } state.ResultFormat.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, state.ResultFormat, state.InputFormat, state.Index.Current, state.Index.LastEnd)); state.Index.Current = state.Index.SafeAdd(state.Index.Current, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool ParseNamedFormatter(ParserState state) { char c = state.InputFormat[state.Index.Current]; if (c == _parserSettings.FormatterOptionsBeginChar) { if (state.Index.NamedFormatterStart == state.Index.Current) { state.Index.NamedFormatterStart = -1; return false; } ParseFormatOptions(state); } else if (c == _parserSettings.FormatterOptionsEndChar || c == _parserSettings.FormatterNameSeparator) { if (c == _parserSettings.FormatterOptionsEndChar) { bool num = state.Index.NamedFormatterOptionsStart != -1; int num2 = state.Index.SafeAdd(state.Index.Current, 1); bool flag = num2 < state.InputFormat.Length && (state.InputFormat[num2] == _parserSettings.FormatterNameSeparator || state.InputFormat[num2] == _parserSettings.PlaceholderEndChar); if (!num || !flag) { state.Index.NamedFormatterStart = -1; return false; } state.Index.NamedFormatterOptionsEnd = state.Index.Current; if (state.InputFormat[num2] == _parserSettings.FormatterNameSeparator) { state.Index.Current++; } } bool num3 = state.Index.NamedFormatterStart == state.Index.Current; bool flag2 = state.Index.NamedFormatterOptionsStart != -1 && state.Index.NamedFormatterOptionsEnd == -1; if (num3 || flag2) { state.Index.NamedFormatterStart = -1; return false; } state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 1); Placeholder parentPlaceholder = state.ResultFormat.ParentPlaceholder; if (state.Index.NamedFormatterOptionsStart == -1) { if (parentPlaceholder != null) { parentPlaceholder.FormatterNameStartIndex = state.Index.NamedFormatterStart; parentPlaceholder.FormatterNameLength = state.Index.Current - state.Index.NamedFormatterStart; } } else if (parentPlaceholder != null) { parentPlaceholder.FormatterNameStartIndex = state.Index.NamedFormatterStart; parentPlaceholder.FormatterNameLength = state.Index.NamedFormatterOptionsStart - state.Index.NamedFormatterStart; parentPlaceholder.FormatterOptionsStartIndex = state.Index.NamedFormatterOptionsStart + 1; parentPlaceholder.FormatterOptionsLength = state.Index.NamedFormatterOptionsEnd - (state.Index.NamedFormatterOptionsStart + 1); } state.ResultFormat.StartIndex = state.Index.LastEnd; state.Index.NamedFormatterStart = -1; } return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddLastSelector(ref Placeholder currentPlaceholder, ParserState state, ParsingErrors parsingErrors) { if (state.Index.Current != state.Index.LastEnd || (currentPlaceholder.Selectors.Count > 0 && currentPlaceholder.Selectors[currentPlaceholder.Selectors.Count - 1].Length > 0 && state.Index.Current - state.Index.Operator == 1 && (state.InputFormat[state.Index.Operator] == _parserSettings.ListIndexEndChar || state.InputFormat[state.Index.Operator] == _parserSettings.NullableOperator))) { currentPlaceholder.AddSelector(SelectorPool.Instance.Get().Initialize(Settings, currentPlaceholder, state.InputFormat, state.Index.LastEnd, state.Index.Current, state.Index.Operator, state.Index.Selector)); } else if (state.Index.Operator != state.Index.Current) { parsingErrors.AddIssue(state.ResultFormat, $"'0x{Convert.ToInt32(state.InputFormat[state.Index.Operator]):X}': " + _parsingErrorText[ParsingError.TrailingOperatorsInSelector], state.Index.Operator, state.Index.Current); } state.Index.LastEnd = state.Index.SafeAdd(state.Index.Current, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ParseFormatOptions(ParserState state) { state.Index.NamedFormatterOptionsStart = state.Index.Current; char item = state.InputFormat[state.Index.SafeAdd(state.Index.Current, 1)]; if (_formatOptionsTerminatorChars.Contains(item)) { return; } while (++state.Index.Current < state.Index.ObjectLength) { item = state.InputFormat[state.Index.SafeAdd(state.Index.Current, 1)]; if (state.InputFormat[state.Index.Current] == _parserSettings.CharLiteralEscapeChar && (_formatOptionsTerminatorChars.Contains(item) || EscapedLiteral.TryGetChar(item, out var _, includeFormatterOptionChars: true, includeCharacterLiterals: false))) { state.Index.Current = state.Index.SafeAdd(state.Index.Current, 1); if (_formatOptionsTerminatorChars.Contains(state.InputFormat[state.Index.SafeAdd(state.Index.Current, 1)])) { break; } } else if (_formatOptionsTerminatorChars.Contains(state.InputFormat[state.Index.Current + 1])) { break; } } } private static void ParseHtmlTags(ParserState state) { ReadOnlySpan readOnlySpan = "script".AsSpan(); ReadOnlySpan readOnlySpan2 = "style".AsSpan(); state.Index.Current++; ReadOnlySpan readOnlySpan3 = ReadOnlySpan.Empty; if (state.InputFormat.AsSpan(state.Index.Current).StartsWith(readOnlySpan, StringComparison.InvariantCultureIgnoreCase)) { readOnlySpan3 = readOnlySpan; state.Index.Current += readOnlySpan3.Length; } if (state.InputFormat.AsSpan(state.Index.Current).StartsWith(readOnlySpan2, StringComparison.InvariantCultureIgnoreCase)) { readOnlySpan3 = readOnlySpan2; state.Index.Current += readOnlySpan3.Length; } if (readOnlySpan3 == ReadOnlySpan.Empty) { return; } bool flag = false; char c = '"'; while (state.Index.Current < state.InputFormat.Length) { if (!flag) { if (state.InputFormat[state.Index.Current] == '\'' || state.InputFormat[state.Index.Current] == '"') { flag = !flag; c = state.InputFormat[state.Index.Current]; state.Index.Current++; continue; } if (IsSelfClosingTag(state, readOnlySpan3)) { state.Index.Current++; break; } if (IsBeginOfClosingTag(state, readOnlySpan3)) { state.Index.Current = state.Index.SafeAdd(state.Index.Current, 2 + readOnlySpan3.Length); if (state.Index.Current < state.InputFormat.Length && state.InputFormat[state.Index.Current] == '>') { break; } } if (state.InputFormat.Length <= state.Index.Current) { break; } state.Index.Current++; } else if (state.InputFormat[state.Index.Current] == c) { flag = !flag; state.Index.Current++; } else { state.Index.Current++; } } } private static bool IsSelfClosingTag(ParserState state, ReadOnlySpan currentTagName) { if (state.InputFormat[state.Index.Current] == '/' && state.InputFormat[state.Index.Current + 1] == '>') { return state.InputFormat.AsSpan(state.Index.Current - 1 - currentTagName.Length).StartsWith(currentTagName, StringComparison.InvariantCultureIgnoreCase); } return false; } private static bool IsBeginOfClosingTag(ParserState state, ReadOnlySpan currentTagName) { if (state.InputFormat[state.Index.Current] == '<' && state.InputFormat[state.Index.Current + 1] == '/' && currentTagName != ReadOnlySpan.Empty) { return state.InputFormat.AsSpan(state.Index.Current + 2).StartsWith(currentTagName, StringComparison.InvariantCultureIgnoreCase); } return false; } private Format HandleParsingErrors(ParsingErrors parsingErrors, Format currentResult) { Format currentResult2 = currentResult; switch (Settings.Parser.ErrorAction) { case ParseErrorAction.ThrowError: throw parsingErrors; case ParseErrorAction.MaintainTokens: { int i; for (i = 0; i < currentResult2.Items.Count; i++) { if (currentResult2.Items[i] is Placeholder placeholder2 && parsingErrors.Issues.Exists((ParsingErrors.ParsingIssue errItem) => errItem.Index >= currentResult2.Items[i].StartIndex && errItem.Index <= currentResult2.Items[i].EndIndex)) { Format format3 = placeholder2.Format ?? FormatPool.Instance.Get().Initialize(Settings, placeholder2.BaseString); currentResult2.Items[i] = LiteralTextPool.Instance.Get().Initialize(Settings, format3, format3.BaseString, placeholder2.StartIndex, placeholder2.EndIndex); } } return currentResult2; } case ParseErrorAction.Ignore: { int j; for (j = 0; j < currentResult2.Items.Count; j++) { if (currentResult2.Items[j] is Placeholder placeholder && parsingErrors.Issues.Exists((ParsingErrors.ParsingIssue errItem) => errItem.Index >= currentResult2.Items[j].StartIndex && errItem.Index <= currentResult2.Items[j].EndIndex)) { Format format2 = placeholder.Format ?? FormatPool.Instance.Get().Initialize(Settings, placeholder.BaseString); currentResult2.Items[j] = LiteralTextPool.Instance.Get().Initialize(Settings, format2, format2.BaseString, placeholder.StartIndex, placeholder.StartIndex); } } return currentResult2; } case ParseErrorAction.OutputErrorInResult: { Format format = FormatPool.Instance.Get().Initialize(Settings, parsingErrors.Message, 0, parsingErrors.Message.Length); format.Items.Add(LiteralTextPool.Instance.Get().Initialize(Settings, format, parsingErrors.Message, 0, parsingErrors.Message.Length)); return format; } default: throw new ArgumentException("Illegal type for ParsingErrors", parsingErrors); } } } internal sealed class ParserState { internal sealed record IndexContainer { internal const int PositionUndefined = -1; public int ObjectLength; public int Current; public int LastEnd; public int NamedFormatterStart; public int NamedFormatterOptionsStart; public int NamedFormatterOptionsEnd; public int Operator; public int Selector; public IndexContainer() { Reset(); } public int SafeAdd(int index, int add) { index += add; if (index >= ObjectLength) { return ObjectLength; } return index; } public void Reset() { ObjectLength = 0; Current = -1; LastEnd = 0; NamedFormatterStart = -1; NamedFormatterOptionsStart = -1; NamedFormatterOptionsEnd = -1; Operator = -1; Selector = -1; } [CompilerGenerated] private IndexContainer(IndexContainer original) { ObjectLength = original.ObjectLength; Current = original.Current; LastEnd = original.LastEnd; NamedFormatterStart = original.NamedFormatterStart; NamedFormatterOptionsStart = original.NamedFormatterOptionsStart; NamedFormatterOptionsEnd = original.NamedFormatterOptionsEnd; Operator = original.Operator; Selector = original.Selector; } } public IndexContainer Index; public string InputFormat; public Format ResultFormat; public ParserState() { Index = new IndexContainer(); InputFormat = string.Empty; ResultFormat = null; } public ParserState Initialize(string inputFormat, Format resultFormat) { Index.Reset(); Index.ObjectLength = inputFormat.Length; InputFormat = inputFormat; ResultFormat = resultFormat; return this; } public void Clear() { Index.Reset(); InputFormat = string.Empty; ResultFormat = null; } } public class ParsingErrorEventArgs : EventArgs { public ParsingErrors Errors { get; internal set; } public bool ThrowsException { get; internal set; } internal ParsingErrorEventArgs(ParsingErrors errors, bool throwsException) { Errors = errors; ThrowsException = throwsException; } } [Serializable] public class ParsingErrors : Exception { public class ParsingIssue { public int Index { get; } public int Length { get; } public string Issue { get; } public ParsingIssue(string issue, int index, int length) { Issue = issue; Index = index; Length = length; } } private Format _result = InitializationObject.Format; public List Issues { get; } = new List(); public bool HasIssues => Issues.Count > 0; public string MessageShort => $"The format string has {Issues.Count} issue{((Issues.Count == 1) ? string.Empty : "s")}: {string.Join(", ", Issues.Select((ParsingIssue i) => i.Issue).ToArray())}"; public override string Message { get { StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (ParsingIssue issue in Issues) { stringBuilder.Append(new string('-', issue.Index - num)); if (issue.Length > 0) { stringBuilder.Append(new string('^', Math.Max(issue.Length, 1))); num = issue.Index + issue.Length; } else { stringBuilder.Append('^'); num = issue.Index + 1; } } return $"The format string has {Issues.Count} issue{((Issues.Count == 1) ? string.Empty : "s")}:\n{string.Join(", ", Issues.Select((ParsingIssue i) => i.Issue).ToArray())}\nIn: \"{_result.BaseString}\"\nAt: {stringBuilder} "; } } public ParsingErrors() { } public ParsingErrors Initialize(Format result) { _result = result; return this; } public void Clear() { Issues.Clear(); } [Obsolete("This API supports obsolete formatter-based serialization. It will be removed in version 4.")] protected ParsingErrors(SerializationInfo info, StreamingContext context) : base(info, context) { } public void AddIssue(Format parent, string issue, int startIndex, int endIndex) { Issues.Add(new ParsingIssue(issue, startIndex, endIndex - startIndex)); } } public class Placeholder : FormatItem { private string? _formatterNameCache; private string? _formatterOptionsCache; private string? _formatterOptionsRawCache; private string? _toStringCache; private readonly List _selectors = new List(); public Format Parent => (Format)base.ParentFormatItem; public int NestedDepth { get; set; } internal List Selectors => _selectors; public int Alignment { get; internal set; } internal int FormatterNameStartIndex { get; set; } internal int FormatterNameLength { get; set; } internal int FormatterOptionsStartIndex { get; set; } internal int FormatterOptionsLength { get; set; } public string FormatterName => _formatterNameCache ?? (_formatterNameCache = base.BaseString.Substring(FormatterNameStartIndex, FormatterNameLength)); public string FormatterOptions { get { if (_formatterOptionsCache != null) { return _formatterOptionsCache; } if (base.Length == 0) { _formatterOptionsCache = string.Empty; } ArrayPool shared = ArrayPool.Shared; char[] array = shared.Rent(base.Length); try { _formatterOptionsCache = EscapedLiteral.UnEscapeCharLiterals(base.SmartSettings.Parser.CharLiteralEscapeChar, base.BaseString.AsSpan(FormatterOptionsStartIndex, FormatterOptionsLength), includeFormatterOptionChars: true, base.SmartSettings.Parser.ConvertCharacterStringLiterals, array).ToString(); } finally { shared.Return(array); } return _formatterOptionsCache; } } public string FormatterOptionsRaw => _formatterOptionsRawCache ?? (_formatterOptionsRawCache = base.BaseString.Substring(FormatterOptionsStartIndex, FormatterOptionsLength)); public Format? Format { get; set; } public Placeholder Initialize(Format parent, int startIndex, int nestedDepth) { base.Initialize(parent.SmartSettings, parent, parent.BaseString, startIndex, parent.EndIndex); if (parent.ParentPlaceholder != null) { Alignment = parent.ParentPlaceholder.Alignment; } NestedDepth = nestedDepth; FormatterNameStartIndex = startIndex; FormatterNameLength = 0; FormatterOptionsStartIndex = startIndex; FormatterOptionsLength = 0; return this; } public override void Clear() { base.Clear(); _formatterNameCache = null; _formatterOptionsCache = null; _formatterOptionsRawCache = null; _toStringCache = null; NestedDepth = 0; Alignment = 0; FormatterNameStartIndex = 0; FormatterNameLength = 0; FormatterOptionsStartIndex = 0; FormatterOptionsLength = 0; } public void ReturnToPool() { Clear(); if (Format != null) { FormatPool.Instance.Return(Format); Format = null; } foreach (Selector selector in Selectors) { selector.Clear(); SelectorPool.Instance.Return(selector); } Selectors.Clear(); } public IReadOnlyList GetSelectors() { return _selectors.AsReadOnly(); } internal void AddSelector(Selector selector) { if (selector.OperatorLength > 0 && selector.Operator[0] == base.SmartSettings.Parser.AlignmentOperator && int.TryParse(selector.RawText, out var result)) { Alignment = result; } _selectors.Add(selector); } public override string ToString() { if (_toStringCache != null) { return _toStringCache; } using ZCharArray zCharArray = new ZCharArray(base.Length + 2); zCharArray.Write(base.SmartSettings.Parser.PlaceholderBeginChar); foreach (Selector selector in Selectors) { if (selector.Operator.Length <= 0 || selector.Operator[0] != base.SmartSettings.Parser.AlignmentOperator) { ReadOnlySpan data = selector.BaseString.AsSpan(selector.OperatorStartIndex, selector.EndIndex - selector.OperatorStartIndex); zCharArray.Write(data); } } if (Alignment != 0) { zCharArray.Write(base.SmartSettings.Parser.AlignmentOperator); zCharArray.Write(Alignment.ToString()); } if (FormatterName != string.Empty) { zCharArray.Write(base.SmartSettings.Parser.FormatterNameSeparator); zCharArray.Write(FormatterName); if (FormatterOptions != string.Empty) { zCharArray.Write(base.SmartSettings.Parser.FormatterOptionsBeginChar); zCharArray.Write(FormatterOptions); zCharArray.Write(base.SmartSettings.Parser.FormatterOptionsEndChar); } } if (Format != null) { zCharArray.Write(base.SmartSettings.Parser.FormatterNameSeparator); zCharArray.Write(Format.AsSpan()); } zCharArray.Write(base.SmartSettings.Parser.PlaceholderEndChar); _toStringCache = new string(zCharArray.GetSpan()); return _toStringCache; } } public class Selector : FormatItem { private string? _operatorCache; internal int OperatorStartIndex { get; private set; } internal int OperatorLength => base.StartIndex - OperatorStartIndex; public int SelectorIndex { get; private set; } public string Operator => _operatorCache ?? (_operatorCache = base.BaseString.Substring(OperatorStartIndex, OperatorLength)); public Selector Initialize(SmartSettings settings, FormatItem parent, string baseString, int startIndex, int endIndex, int operatorStartIndex, int selectorIndex) { base.Initialize(settings, parent, baseString, startIndex, endIndex); SelectorIndex = selectorIndex; OperatorStartIndex = operatorStartIndex; return this; } public override void Clear() { base.Clear(); SelectorIndex = 0; OperatorStartIndex = 0; _operatorCache = null; } } internal class SplitList : IList, ICollection, IEnumerable, IEnumerable { private Format _format = InitializationObject.Format; private List _splits = InitializationObject.IntegerList; private readonly List _formatCache = new List(); public Format this[int index] { get { if (index > _splits.Count) { throw new ArgumentOutOfRangeException("index"); } if (_splits.Count == 0) { return _format; } if (_formatCache[index] != null) { return _formatCache[index]; } if (index == 0) { Format format = _format.Substring(0, _splits[0]); _formatCache[index] = format; return format; } if (index == _splits.Count) { Format format2 = _format.Substring(_splits[index - 1] + 1); _formatCache[index] = format2; return format2; } int num = _splits[index - 1] + 1; Format format3 = _format.Substring(num, _splits[index] - num); _formatCache[index] = format3; return format3; } set { throw new NotSupportedException(); } } public int Count => _splits.Count + 1; public bool IsReadOnly => true; public SplitList Initialize(Format format, List splits) { _format = format; _splits = splits; for (int i = 0; i < Count; i++) { _formatCache.Add(null); } return this; } public void Clear() { _format = InitializationObject.Format; _splits = InitializationObject.IntegerList; for (int i = 0; i < _formatCache.Count; i++) { if (_formatCache[i] != null) { FormatPool.Instance.Return(_formatCache[i]); } } _formatCache.Clear(); } public void CopyTo(Format[] array, int arrayIndex) { int num = _splits.Count + 1; for (int i = 0; i < num; i++) { array[arrayIndex + i] = this[i]; } } public int IndexOf(Format item) { throw new NotSupportedException(); } public void Insert(int index, Format item) { throw new NotSupportedException(); } public void RemoveAt(int index) { throw new NotSupportedException(); } public void Add(Format item) { throw new NotSupportedException(); } public bool Contains(Format item) { throw new NotSupportedException(); } public bool Remove(Format item) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotSupportedException(); } } } namespace SmartFormat.Core.Output { public interface IOutput { void Write(string text, IFormattingInfo? formattingInfo = null); void Write(ReadOnlySpan text, IFormattingInfo? formattingInfo = null); void Write(ZStringBuilder stringBuilder, IFormattingInfo? formattingInfo = null); } public class NullOutput : IOutput { public void Write(string text, IFormattingInfo? formattingInfo = null) { } public void Write(ReadOnlySpan text, IFormattingInfo? formattingInfo = null) { } public void Write(ZStringBuilder stringBuilder, IFormattingInfo? formattingInfo = null) { } public override string ToString() { return string.Empty; } } public class StringOutput : IOutput { internal StringBuilder Output { get; } public StringOutput() { Output = new StringBuilder(); } public StringOutput(int capacity) { Output = new StringBuilder(capacity); } public StringOutput(StringBuilder output) { Output = output; } public void Write(string text, IFormattingInfo? formattingInfo = null) { Output.Append(text); } public void Write(ReadOnlySpan text, IFormattingInfo? formattingInfo = null) { Output.Append(text); } public void Write(ZStringBuilder stringBuilder, IFormattingInfo? formattingInfo = null) { Output.Append(stringBuilder.AsSpan()); } public void Clear() { Output.Clear(); } public override string ToString() { return Output.ToString(); } } public class TextWriterOutput : IOutput { public TextWriter Output { get; } public TextWriterOutput(TextWriter output) { Output = output; } public void Write(string text, IFormattingInfo? formattingInfo = null) { Output.Write(text); } public void Write(ReadOnlySpan text, IFormattingInfo? formattingInfo = null) { Output.Write(text); } public void Write(ZStringBuilder stringBuilder, IFormattingInfo? formattingInfo = null) { Output.Write(stringBuilder.AsSpan()); } } public class ZStringOutput : IOutput, IDisposable { internal ZStringBuilder Output { get; } public ZStringOutput() { Output = ZStringBuilderUtilities.CreateZStringBuilder(); } public ZStringOutput(int capacity) { Output = ZStringBuilderUtilities.CreateZStringBuilder(capacity); } public ZStringOutput(ZStringBuilder stringBuilder) { Output = stringBuilder; } public void Write(string text, IFormattingInfo? formattingInfo = null) { Output.Append(text); } public void Write(ReadOnlySpan text, IFormattingInfo? formattingInfo = null) { Output.Append(text); } public void Write(ZStringBuilder stringBuilder, IFormattingInfo? formattingInfo = null) { Output.Append(stringBuilder); } public void Clear() { Output.Clear(); } public override string ToString() { return Output.ToString(); } protected virtual void Dispose(bool disposing) { if (disposing) { Output.Dispose(); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } } namespace SmartFormat.Core.Formatting { public class FormatDetails { public SmartFormatter Formatter { get; private set; } public Format OriginalFormat { get; private set; } public IList OriginalArgs { get; private set; } public IFormatProvider? Provider { get; internal set; } public IOutput Output { get; private set; } public FormattingException? FormattingException { get; set; } public SmartSettings Settings => Formatter.Settings; public FormatDetails() { Formatter = InitializationObject.SmartFormatter; OriginalFormat = InitializationObject.Format; OriginalArgs = InitializationObject.ObjectList; Output = InitializationObject.Output; Provider = null; FormattingException = null; } public FormatDetails Initialize(SmartFormatter formatter, Format originalFormat, IList originalArgs, IFormatProvider? provider, IOutput output) { Formatter = formatter; OriginalFormat = originalFormat; OriginalArgs = originalArgs; Provider = provider; Output = output; FormattingException = null; return this; } internal void Clear() { Formatter = InitializationObject.SmartFormatter; OriginalFormat = InitializationObject.Format; OriginalArgs = InitializationObject.ObjectList; Output = InitializationObject.Output; Provider = null; FormattingException = null; } } [Serializable] public class FormattingException : Exception { public string? Format { get; } public FormatItem? ErrorItem { get; } public string Issue { get; } public int Index { get; } public override string Message => $"Error parsing format string: {Issue} at {Index}\n{Format}\n{new string('-', Index) + "^"}"; public FormattingException(FormatItem? errorItem, Exception formatException, int index) : base(formatException.Message, formatException) { Format = errorItem?.BaseString; ErrorItem = errorItem; Issue = formatException.Message; Index = index; } public FormattingException(FormatItem? errorItem, string issue, int index) { Format = errorItem?.BaseString; ErrorItem = errorItem; Issue = issue; Index = index; } [Obsolete("This API supports obsolete formatter-based serialization. It will be removed in version 4.")] protected FormattingException(SerializationInfo info, StreamingContext context) : base(info, context) { Issue = string.Empty; } } public class FormattingInfo : IFormattingInfo, ISelectorInfo, IFormattingExtensionsToggle { public FormattingInfo? Parent { get; private set; } public Selector? Selector { get; internal set; } public FormatDetails FormatDetails { get; private set; } public object? CurrentValue { get; set; } public Placeholder? Placeholder { get; internal set; } public int Alignment { get; set; } public string FormatterOptions => Placeholder?.FormatterOptions ?? string.Empty; public Format? Format { get; private set; } internal List Children { get; } = new List(); public string SelectorText => Selector?.RawText ?? string.Empty; public int SelectorIndex => Selector?.SelectorIndex ?? (-1); public string SelectorOperator => Selector?.Operator ?? string.Empty; public object? Result { get; set; } public bool DisableFormattingExtensions { get; set; } public FormattingInfo() { FormatDetails = InitializationObject.FormatDetails; } public FormattingInfo Initialize(FormatDetails formatDetails, Format format, object? currentValue) { return Initialize(null, formatDetails, format, currentValue); } public FormattingInfo Initialize(FormattingInfo? parent, FormatDetails formatDetails, Format format, object? currentValue) { Parent = parent; CurrentValue = currentValue; FormatDetails = formatDetails; Format = format; DisableFormattingExtensions = false; if (parent != null) { Alignment = parent.Alignment; } else if (format.ParentPlaceholder != null) { Alignment = format.ParentPlaceholder.Alignment; } return this; } public FormattingInfo Initialize(FormattingInfo? parent, FormatDetails formatDetails, Placeholder placeholder, object? currentValue) { Parent = parent; FormatDetails = formatDetails; Placeholder = placeholder; Format = placeholder.Format; DisableFormattingExtensions = false; CurrentValue = currentValue; Alignment = placeholder.Alignment; return this; } public void ReturnToPool() { Parent = null; FormatDetails = InitializationObject.FormatDetails; Placeholder = null; Selector = null; Alignment = 0; Format = null; DisableFormattingExtensions = false; CurrentValue = null; foreach (FormattingInfo child in Children) { FormattingInfoPool.Instance.Return(child); } Children.Clear(); } public void Write(string text) { Write(text.AsSpan()); } public void Write(ReadOnlySpan text) { if (Alignment == 0) { FormatDetails.Output.Write(text); FormatDetails.Formatter.Evaluator.OnOutputWritten?.Invoke(this, new Evaluator.OutputWrittenEventArgs(text.ToString())); return; } ZCharArray zCharArray = new ZCharArray(text.Length + Math.Abs(Alignment)); int num = Alignment - text.Length; if (num > 0) { zCharArray.Write(FormatDetails.Settings.Formatter.AlignmentFillCharacter, num); } zCharArray.Write(text); num = -Alignment - text.Length; if (num > 0) { zCharArray.Write(FormatDetails.Settings.Formatter.AlignmentFillCharacter, num); } FormatDetails.Output.Write(zCharArray.GetSpan()); FormatDetails.Formatter.Evaluator.OnOutputWritten?.Invoke(this, new Evaluator.OutputWrittenEventArgs(zCharArray.ToString())); } public void FormatAsChild(Format format, object? value) { FormatDetails.Formatter.Evaluator.WriteFormat(CreateChild(format, value)); } public ZCharArray FormatAsSpan(IFormatProvider? provider, Format format, object? current) { using ZStringOutput zStringOutput = new ZStringOutput(); ExecuteFormattingAction(provider, format, current, zStringOutput, FormatDetails.Formatter.Evaluator.WriteFormat); ZCharArray result = new ZCharArray(zStringOutput.Output.Length); result.Write(zStringOutput.Output.AsSpan()); return result; } public ZCharArray FormatAsSpan(IFormatProvider? provider, Placeholder placeholder, object? current) { Format instance; using (FormatPool.Instance.Get(out instance)) { instance.Initialize(FormatDetails.Settings, placeholder.BaseString); instance.Items.Add(placeholder); return FormatAsSpan(provider, instance, current); } } public bool TryGetValue(Placeholder placeholder, out object? result) { return FormatDetails.Formatter.Evaluator.TryGetValue(this, placeholder, out result); } public FormattingException FormattingException(string issue, FormatItem? problemItem = null, int startIndex = -1) { if (problemItem == null) { problemItem = Format; } if (startIndex == -1) { startIndex = problemItem?.StartIndex ?? (-1); } return new FormattingException(problemItem, issue, startIndex); } private FormattingInfo CreateChild(Format format, object? currentValue) { FormattingInfo formattingInfo = FormattingInfoPool.Instance.Get().Initialize(this, FormatDetails, format, currentValue); Children.Add(formattingInfo); return formattingInfo; } public FormattingInfo CreateChild(Placeholder placeholder) { FormattingInfo formattingInfo = FormattingInfoPool.Instance.Get().Initialize(this, FormatDetails, placeholder, CurrentValue); Children.Add(formattingInfo); return formattingInfo; } internal void ExecuteFormattingAction(IFormatProvider? provider, Format formatParsed, object? current, IOutput output, Action doWork) { SmartFormatter formatter = FormatDetails.Formatter; FormatDetails instance; using (FormatDetailsPool.Instance.Pool.Get(out instance)) { instance.Initialize(formatter, formatParsed, instance.OriginalArgs, provider, output); FormattingInfo instance2; using (FormattingInfoPool.Instance.Pool.Get(out instance2)) { instance2.Initialize(instance, formatParsed, current); doWork(instance2); } } } } } namespace SmartFormat.Core.Extensions { public interface IFormattingExtensionsToggle { bool DisableFormattingExtensions { get; set; } } public interface ISource { bool TryEvaluateSelector(ISelectorInfo selectorInfo); } internal class Registry { private readonly List _sourceExtensions = new List(); private readonly List _formatterExtensions = new List(); private readonly SmartFormatter _formatter; internal List SourceExtensions => _sourceExtensions; internal List FormatterExtensions => _formatterExtensions; public SmartSettings Settings { get; } public Registry(SmartFormatter formatter) { Settings = formatter.Settings; _formatter = formatter; } public IReadOnlyList GetSourceExtensions() { return _sourceExtensions.AsReadOnly(); } public IReadOnlyList GetFormatterExtensions() { return _formatterExtensions.AsReadOnly(); } public Registry AddExtensions(params ISource[] sourceExtensions) { foreach (ISource source in sourceExtensions) { int indexToInsert = WellKnownExtensionTypes.GetIndexToInsert(SourceExtensions, source); InsertExtension(indexToInsert, source); IFormatter formatter = source as IFormatter; if (formatter != null && FormatterExtensions.TrueForAll((IFormatter fx) => fx.GetType() != formatter.GetType())) { AddExtensions(formatter); } } return this; } public Registry AddExtensions(params IFormatter[] formatterExtensions) { foreach (IFormatter formatter in formatterExtensions) { int indexToInsert = WellKnownExtensionTypes.GetIndexToInsert(FormatterExtensions, formatter); InsertExtension(indexToInsert, formatter); ISource source = formatter as ISource; if (source != null && SourceExtensions.TrueForAll((ISource sx) => sx.GetType() != source.GetType())) { AddExtensions(source); } } return this; } public Registry InsertExtension(int position, ISource sourceExtension) { ISource sourceExtension2 = sourceExtension; if (_sourceExtensions.Exists((ISource sx) => sx.GetType() == sourceExtension2.GetType())) { return this; } if (sourceExtension2 is IInitializer initializer) { initializer.Initialize(_formatter); } _sourceExtensions.Insert(position, sourceExtension2); return this; } public Registry InsertExtension(int position, IFormatter formatterExtension) { IFormatter formatterExtension2 = formatterExtension; if (_formatterExtensions.Exists((IFormatter sx) => sx.GetType() == formatterExtension2.GetType())) { return this; } if (_formatterExtensions.Exists((IFormatter fx) => fx.Name.Equals(formatterExtension2.Name))) { throw new ArgumentException("Formatter '" + formatterExtension2.GetType().Name + "' uses existing name.", "formatterExtension"); } if (formatterExtension2 is IInitializer initializer) { initializer.Initialize(_formatter); } _formatterExtensions.Insert(position, formatterExtension2); return this; } public T? GetSourceExtension() where T : class, ISource { return _sourceExtensions.OfType().FirstOrDefault(); } public T? GetFormatterExtension() where T : class, IFormatter { return _formatterExtensions.OfType().FirstOrDefault(); } public bool RemoveSourceExtension() where T : class, ISource { T val = _sourceExtensions.OfType().FirstOrDefault(); if (val != null) { return _sourceExtensions.Remove(val); } return false; } public bool RemoveFormatterExtension() where T : class, IFormatter { T val = _formatterExtensions.OfType().FirstOrDefault(); if (val != null) { return _formatterExtensions.Remove(val); } return false; } public void ThrowIfNoExtensions() { if (_sourceExtensions.Count == 0) { throw new InvalidOperationException("No source extensions are available. Please add at least one source extension, such as the DefaultSource."); } if (_formatterExtensions.Count == 0) { throw new InvalidOperationException("No formatter extensions are available. Please add at least one formatter extension, such as the DefaultFormatter."); } } internal (bool Success, Type? SourceType) InvokeSourceExtensions(ISelectorInfo selectorInfo) { foreach (ISource sourceExtension in _sourceExtensions) { if (sourceExtension.TryEvaluateSelector(selectorInfo)) { return (true, sourceExtension.GetType()); } } return (false, null); } internal (bool Success, Type? FormatterType) InvokeFormatterExtensions(FormattingInfo formattingInfo) { if (formattingInfo.Placeholder == null) { throw new ArgumentException("The property formattingInfo.Placeholder must not be null.", "formattingInfo"); } if (Settings.StringFormatCompatibility) { IFormatter formatter = _formatterExtensions.First((IFormatter fe) => fe is DefaultFormatter); return (formatter.TryEvaluateFormat(formattingInfo), formatter.GetType()); } string formatterName = formattingInfo.Placeholder.FormatterName; StringComparison caseSensitivityComparison = Settings.GetCaseSensitivityComparison(); if (formatterName != string.Empty) { IFormatter formatter2 = null; foreach (IFormatter formatterExtension in _formatterExtensions) { if (formatterExtension.Name.Equals(formatterName, caseSensitivityComparison)) { formatter2 = formatterExtension; break; } } if (formatter2 != null) { return (formatter2.TryEvaluateFormat(formattingInfo), formatter2.GetType()); } return (false, null); } foreach (IFormatter formatterExtension2 in _formatterExtensions) { if (formatterExtension2.CanAutoDetect && formatterExtension2.TryEvaluateFormat(formattingInfo)) { return (true, formatterExtension2.GetType()); } } return (false, null); } } public abstract class Source : ISource, IInitializer { protected SmartFormatter? _formatter; protected SmartSettings? _smartSettings; public abstract bool TryEvaluateSelector(ISelectorInfo selectorInfo); public virtual void Initialize(SmartFormatter smartFormatter) { _formatter = smartFormatter; _smartSettings = smartFormatter.Settings; } private bool HasNullableOperator(ISelectorInfo selectorInfo) { if (_smartSettings != null && selectorInfo.Placeholder != null) { foreach (Selector selector in selectorInfo.Placeholder.Selectors) { if (selector.OperatorLength > 1 && selector.BaseString[selector.OperatorStartIndex] == _smartSettings.Parser.NullableOperator) { return true; } } } return false; } protected virtual bool TrySetResultForNullableOperator(ISelectorInfo selectorInfo) { if (HasNullableOperator(selectorInfo) && selectorInfo.CurrentValue == null) { selectorInfo.Result = null; return true; } return false; } } public interface IFormatter { string Name { get; set; } bool CanAutoDetect { get; set; } bool TryEvaluateFormat(IFormattingInfo formattingInfo); } public interface IFormattingInfo { object? CurrentValue { get; } Format? Format { get; } [EditorBrowsable(EditorBrowsableState.Advanced)] Placeholder? Placeholder { get; } int Alignment { get; } string FormatterOptions { get; } [EditorBrowsable(EditorBrowsableState.Advanced)] FormatDetails FormatDetails { get; } void Write(string text); void Write(ReadOnlySpan text); void FormatAsChild(Format format, object? value); FormattingException FormattingException(string issue, FormatItem? problemItem = null, int startIndex = -1); } public interface IInitializer { void Initialize(SmartFormatter smartFormatter); } public interface ISelectorInfo { object? CurrentValue { get; } string SelectorText { get; } int SelectorIndex { get; } string SelectorOperator { get; } object? Result { get; set; } [EditorBrowsable(EditorBrowsableState.Advanced)] Placeholder? Placeholder { get; } [EditorBrowsable(EditorBrowsableState.Advanced)] FormatDetails FormatDetails { get; } } }