<PackageReference Include="System.Text.Encodings.Web" Version="4.7.2" />

TextEncoder

public abstract class TextEncoder
The base class of web encoders.
using System.Buffers; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.Unicode; namespace System.Text.Encodings.Web { public abstract class TextEncoder { private const int EncodeStartingOutputBufferSize = 1024; private byte[][] _asciiEscape = new byte[128][]; private static readonly byte[] s_noEscape = Array.Empty<byte>(); [EditorBrowsable(EditorBrowsableState.Never)] public abstract int MaxOutputCharactersPerInputCharacter { get; } [CLSCompliant(false)] [EditorBrowsable(EditorBrowsableState.Never)] public unsafe abstract bool TryEncodeUnicodeScalar(int unicodeScalar, char* buffer, int bufferLength, out int numberOfCharactersWritten); [CLSCompliant(false)] [EditorBrowsable(EditorBrowsableState.Never)] public unsafe abstract int FindFirstCharacterToEncode(char* text, int textLength); [EditorBrowsable(EditorBrowsableState.Never)] public abstract bool WillEncode(int unicodeScalar); public unsafe virtual string Encode(string value) { if (value == null) throw new ArgumentNullException("value"); int num = FindFirstCharacterToEncode(MemoryExtensions.AsSpan(value)); if (num < 0) return value; ReadOnlySpan<char> source = MemoryExtensions.AsSpan(value, num); Span<char> initialBuffer = new Span<char>(stackalloc byte[2048], 1024); System.Text.ValueStringBuilder valueStringBuilder = new System.Text.ValueStringBuilder(initialBuffer); valueStringBuilder.Append(MemoryExtensions.AsSpan(value, 0, num)); int val = Math.Max(MaxOutputCharactersPerInputCharacter, 1024); do { Span<char> destination = valueStringBuilder.AppendSpan(Math.Max(source.Length, val)); Encode(source, destination, out int charsConsumed, out int charsWritten, true); if (charsWritten == 0 || (uint)charsWritten > (uint)destination.Length) ThrowArgumentException_MaxOutputCharsPerInputChar(); source = source.Slice(charsConsumed); valueStringBuilder.Length -= destination.Length - charsWritten; } while (!source.IsEmpty); return valueStringBuilder.ToString(); } public void Encode(TextWriter output, string value) { Encode(output, value, 0, value.Length); } public virtual void Encode(TextWriter output, string value, int startIndex, int characterCount) { if (value == null) throw new ArgumentNullException("value"); if (output == null) throw new ArgumentNullException("output"); ValidateRanges(startIndex, characterCount, value.Length); int num = FindFirstCharacterToEncode(MemoryExtensions.AsSpan(value, startIndex, characterCount)); if (num < 0) num = characterCount; output.WritePartialString(value, startIndex, num); if (num != characterCount) Encode(output, MemoryExtensions.AsSpan(value, startIndex + num, characterCount - num)); } public virtual void Encode(TextWriter output, char[] value, int startIndex, int characterCount) { if (value == null) throw new ArgumentNullException("value"); if (output == null) throw new ArgumentNullException("output"); ValidateRanges(startIndex, characterCount, value.Length); int num = FindFirstCharacterToEncode(MemoryExtensions.AsSpan(value, startIndex, characterCount)); if (num < 0) num = characterCount; output.Write(value, startIndex, num); if (num != characterCount) Encode(output, MemoryExtensions.AsSpan(value, startIndex + num, characterCount - num)); } public unsafe virtual OperationStatus EncodeUtf8(ReadOnlySpan<byte> utf8Source, Span<byte> utf8Destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true) { int length = utf8Source.Length; int length2 = utf8Destination.Length; char* ptr = stackalloc char[24]; byte* ptr2 = stackalloc byte[72]; int bytesConsumed2 = 0; int num = 0; OperationStatus operationStatus = OperationStatus.Done; while (!utf8Source.IsEmpty) { uint result; ReadOnlySpan<byte> readOnlySpan; do { result = utf8Source[num]; if (System.Text.UnicodeUtility.IsAsciiCodePoint(result)) { byte[] asciiEncoding = GetAsciiEncoding((byte)result); if (asciiEncoding == s_noEscape) { if (++num > utf8Destination.Length) { num--; operationStatus = OperationStatus.DestinationTooSmall; break; } } else { if (asciiEncoding == null) { operationStatus = OperationStatus.Done; bytesConsumed2 = 1; break; } if (num > 0) { readOnlySpan = utf8Source.Slice(0, num); readOnlySpan.CopyTo(utf8Destination); utf8Source = utf8Source.Slice(num); utf8Destination = utf8Destination.Slice(num); num = 0; } readOnlySpan = asciiEncoding; if (!readOnlySpan.TryCopyTo(utf8Destination)) { operationStatus = OperationStatus.DestinationTooSmall; break; } utf8Destination = utf8Destination.Slice(asciiEncoding.Length); utf8Source = utf8Source.Slice(1); } } else { operationStatus = UnicodeHelpers.DecodeScalarValueFromUtf8(utf8Source.Slice(num), out result, out bytesConsumed2); if (operationStatus != 0) break; if (WillEncode((int)result)) break; num += bytesConsumed2; if (num > utf8Destination.Length) { num -= bytesConsumed2; operationStatus = OperationStatus.DestinationTooSmall; break; } } } while (num < utf8Source.Length); if (num > 0) { readOnlySpan = utf8Source.Slice(0, num); readOnlySpan.CopyTo(utf8Destination); utf8Source = utf8Source.Slice(num); utf8Destination = utf8Destination.Slice(num); num = 0; } if (utf8Source.IsEmpty) break; int bytes; switch (operationStatus) { case OperationStatus.NeedMoreData: if (!isFinalBlock) { bytesConsumed = length - utf8Source.Length; bytesWritten = length2 - utf8Destination.Length; return OperationStatus.NeedMoreData; } goto default; default: { if (!TryEncodeUnicodeScalar((int)result, ptr, 24, out int numberOfCharactersWritten)) { bytesConsumed = length - utf8Source.Length; bytesWritten = length2 - utf8Destination.Length; return OperationStatus.InvalidData; } bytes = Encoding.UTF8.GetBytes(ptr, numberOfCharactersWritten, ptr2, 72); ReadOnlySpan<byte> readOnlySpan2 = new ReadOnlySpan<byte>(ptr2, bytes); if (System.Text.UnicodeUtility.IsAsciiCodePoint(result)) _asciiEscape[result] = readOnlySpan2.ToArray(); if (readOnlySpan2.TryCopyTo(utf8Destination)) break; goto case OperationStatus.DestinationTooSmall; } case OperationStatus.DestinationTooSmall: bytesConsumed = length - utf8Source.Length; bytesWritten = length2 - utf8Destination.Length; return OperationStatus.DestinationTooSmall; } utf8Destination = utf8Destination.Slice(bytes); utf8Source = utf8Source.Slice(bytesConsumed2); } bytesConsumed = length; bytesWritten = length2 - utf8Destination.Length; return OperationStatus.Done; } internal static OperationStatus EncodeUtf8Shim(TextEncoder encoder, ReadOnlySpan<byte> utf8Source, Span<byte> utf8Destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { return encoder.EncodeUtf8(utf8Source, utf8Destination, out bytesConsumed, out bytesWritten, isFinalBlock); } public virtual OperationStatus Encode(ReadOnlySpan<char> source, Span<char> destination, out int charsConsumed, out int charsWritten, bool isFinalBlock = true) { if (source.IsEmpty) { charsConsumed = 0; charsWritten = 0; return OperationStatus.Done; } ReadOnlySpan<char> text = source; if (destination.Length < source.Length) text = source.Slice(0, destination.Length); int num = FindFirstCharacterToEncode(text); if (num < 0) num = text.Length; source.Slice(0, num).CopyTo(destination); if (num == source.Length) { charsConsumed = source.Length; charsWritten = source.Length; return OperationStatus.Done; } int charsConsumed2; int charsWritten2; OperationStatus result = <Encode>g__EncodeCore|14_0(source.Slice(num), destination.Slice(num), out charsConsumed2, out charsWritten2, isFinalBlock); charsConsumed = num + charsConsumed2; charsWritten = num + charsWritten2; return result; } private void Encode(TextWriter output, ReadOnlySpan<char> value) { int val = Math.Max(MaxOutputCharactersPerInputCharacter, 1024); char[] array = ArrayPool<char>.Shared.Rent(Math.Max(value.Length, val)); Span<char> destination = array; do { Encode(value, destination, out int charsConsumed, out int charsWritten, true); if (charsWritten == 0 || (uint)charsWritten > (uint)destination.Length) ThrowArgumentException_MaxOutputCharsPerInputChar(); output.Write(array, 0, charsWritten); value = value.Slice(charsConsumed); } while (!value.IsEmpty); ArrayPool<char>.Shared.Return(array, false); } private unsafe int FindFirstCharacterToEncode(ReadOnlySpan<char> text) { fixed (char* text2 = &MemoryMarshal.GetReference(text)) { return FindFirstCharacterToEncode(text2, text.Length); } } [EditorBrowsable(EditorBrowsableState.Never)] public virtual int FindFirstCharacterToEncodeUtf8(ReadOnlySpan<byte> utf8Text) { int length = utf8Text.Length; int num = 0; while (num < utf8Text.Length) { byte value = utf8Text[num]; if (System.Text.UnicodeUtility.IsAsciiCodePoint(value)) { if (GetAsciiEncoding(value) != s_noEscape) return length - utf8Text.Length + num; num++; } else { if (num > 0) utf8Text = utf8Text.Slice(num); if (UnicodeHelpers.DecodeScalarValueFromUtf8(utf8Text, out uint result, out int bytesConsumed) != 0 || WillEncode((int)result)) return length - utf8Text.Length; num = bytesConsumed; } } return -1; } internal static int FindFirstCharacterToEncodeUtf8Shim(TextEncoder encoder, ReadOnlySpan<byte> utf8Text) { return encoder.FindFirstCharacterToEncodeUtf8(utf8Text); } internal unsafe static bool TryCopyCharacters(char[] source, char* destination, int destinationLength, out int numberOfCharactersWritten) { if (destinationLength < source.Length) { numberOfCharactersWritten = 0; return false; } for (int i = 0; i < source.Length; i++) { destination[i] = source[i]; } numberOfCharactersWritten = source.Length; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal unsafe static bool TryWriteScalarAsChar(int unicodeScalar, char* destination, int destinationLength, out int numberOfCharactersWritten) { if (destinationLength < 1) { numberOfCharactersWritten = 0; return false; } *destination = (char)unicodeScalar; numberOfCharactersWritten = 1; return true; } private static void ValidateRanges(int startIndex, int characterCount, int actualInputLength) { if (startIndex < 0 || startIndex > actualInputLength) throw new ArgumentOutOfRangeException("startIndex"); if (characterCount < 0 || characterCount > actualInputLength - startIndex) throw new ArgumentOutOfRangeException("characterCount"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte[] GetAsciiEncoding(byte value) { byte[] array = _asciiEscape[value]; if (array == null && !WillEncode(value)) { array = s_noEscape; _asciiEscape[value] = array; } return array; } private static void ThrowArgumentException_MaxOutputCharsPerInputChar() { throw new ArgumentException("Argument encoder does not implement MaxOutputCharsPerInputChar correctly."); } } }