DefaultUrlEncoder
using System.Buffers;
using System.Text.Unicode;
namespace System.Text.Encodings.Web
{
internal sealed class DefaultUrlEncoder : UrlEncoder
{
private sealed class EscaperImplementation : ScalarEscaperBase
{
internal static readonly EscaperImplementation Singleton = new EscaperImplementation();
private EscaperImplementation()
{
}
internal override int EncodeUtf8(System.Text.Rune value, Span<byte> destination)
{
uint utf8RepresentationForScalarValue = (uint)UnicodeHelpers.GetUtf8RepresentationForScalarValue((uint)value.Value);
if (SpanUtility.IsValidIndex(destination, 2)) {
destination[0] = 37;
System.HexConverter.ToBytesBuffer((byte)utf8RepresentationForScalarValue, destination, 1, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 3;
if (SpanUtility.IsValidIndex(destination, 5)) {
destination[3] = 37;
System.HexConverter.ToBytesBuffer((byte)utf8RepresentationForScalarValue, destination, 4, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 6;
if (SpanUtility.IsValidIndex(destination, 8)) {
destination[6] = 37;
System.HexConverter.ToBytesBuffer((byte)utf8RepresentationForScalarValue, destination, 7, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 9;
if (SpanUtility.IsValidIndex(destination, 11)) {
destination[9] = 37;
System.HexConverter.ToBytesBuffer((byte)utf8RepresentationForScalarValue, destination, 10, System.HexConverter.Casing.Upper);
return 12;
}
}
}
}
return -1;
}
internal override int EncodeUtf16(System.Text.Rune value, Span<char> destination)
{
uint utf8RepresentationForScalarValue = (uint)UnicodeHelpers.GetUtf8RepresentationForScalarValue((uint)value.Value);
if (SpanUtility.IsValidIndex(destination, 2)) {
destination[0] = '%';
System.HexConverter.ToCharsBuffer((byte)utf8RepresentationForScalarValue, destination, 1, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 3;
if (SpanUtility.IsValidIndex(destination, 5)) {
destination[3] = '%';
System.HexConverter.ToCharsBuffer((byte)utf8RepresentationForScalarValue, destination, 4, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 6;
if (SpanUtility.IsValidIndex(destination, 8)) {
destination[6] = '%';
System.HexConverter.ToCharsBuffer((byte)utf8RepresentationForScalarValue, destination, 7, System.HexConverter.Casing.Upper);
if ((utf8RepresentationForScalarValue >>= 8) == 0)
return 9;
if (SpanUtility.IsValidIndex(destination, 11)) {
destination[9] = '%';
System.HexConverter.ToCharsBuffer((byte)utf8RepresentationForScalarValue, destination, 10, System.HexConverter.Casing.Upper);
return 12;
}
}
}
}
return -1;
}
}
internal static readonly DefaultUrlEncoder BasicLatinSingleton = new DefaultUrlEncoder(new TextEncoderSettings(UnicodeRanges.BasicLatin));
private readonly OptimizedInboxTextEncoder _innerEncoder;
public override int MaxOutputCharactersPerInputCharacter => 9;
internal unsafe DefaultUrlEncoder(TextEncoderSettings settings)
{
if (settings == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.settings);
ScalarEscaperBase singleton = EscaperImplementation.Singleton;
ref AllowedBmpCodePointsBitmap allowedCodePointsBitmap = ref settings.GetAllowedCodePointsBitmap();
byte* intPtr = stackalloc byte[62];
*(short*)intPtr = 32;
*(short*)(intPtr + 2) = 35;
*(short*)(intPtr + 2 * 2) = 37;
*(short*)(intPtr + 3 * 2) = 47;
*(short*)(intPtr + 4 * 2) = 58;
*(short*)(intPtr + 5 * 2) = 61;
*(short*)(intPtr + 6 * 2) = 63;
*(short*)(intPtr + 7 * 2) = 91;
*(short*)(intPtr + 8 * 2) = 92;
*(short*)(intPtr + 9 * 2) = 93;
*(short*)(intPtr + 10 * 2) = 94;
*(short*)(intPtr + 11 * 2) = 96;
*(short*)(intPtr + 12 * 2) = 123;
*(short*)(intPtr + 13 * 2) = 124;
*(short*)(intPtr + 14 * 2) = 125;
*(short*)(intPtr + 15 * 2) = -16;
*(short*)(intPtr + 16 * 2) = -15;
*(short*)(intPtr + 17 * 2) = -14;
*(short*)(intPtr + 18 * 2) = -13;
*(short*)(intPtr + 19 * 2) = -12;
*(short*)(intPtr + 20 * 2) = -11;
*(short*)(intPtr + 21 * 2) = -10;
*(short*)(intPtr + 22 * 2) = -9;
*(short*)(intPtr + 23 * 2) = -8;
*(short*)(intPtr + 24 * 2) = -7;
*(short*)(intPtr + 25 * 2) = -6;
*(short*)(intPtr + 26 * 2) = -5;
*(short*)(intPtr + 27 * 2) = -4;
*(short*)(intPtr + 28 * 2) = -3;
*(short*)(intPtr + 29 * 2) = -2;
*(short*)(intPtr + 30 * 2) = -1;
Span<char> span = new Span<char>(intPtr, 31);
_innerEncoder = new OptimizedInboxTextEncoder(singleton, ref allowedCodePointsBitmap, true, span);
}
private protected override OperationStatus EncodeCore(ReadOnlySpan<char> source, Span<char> destination, out int charsConsumed, out int charsWritten, bool isFinalBlock)
{
return _innerEncoder.Encode(source, destination, out charsConsumed, out charsWritten, isFinalBlock);
}
private protected override OperationStatus EncodeUtf8Core(ReadOnlySpan<byte> utf8Source, Span<byte> utf8Destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock)
{
return _innerEncoder.EncodeUtf8(utf8Source, utf8Destination, out bytesConsumed, out bytesWritten, isFinalBlock);
}
private protected override int FindFirstCharacterToEncode(ReadOnlySpan<char> text)
{
return _innerEncoder.GetIndexOfFirstCharToEncode(text);
}
public unsafe override int FindFirstCharacterToEncode(char* text, int textLength)
{
return _innerEncoder.FindFirstCharacterToEncode(text, textLength);
}
public override int FindFirstCharacterToEncodeUtf8(ReadOnlySpan<byte> utf8Text)
{
return _innerEncoder.GetIndexOfFirstByteToEncode(utf8Text);
}
public unsafe override bool TryEncodeUnicodeScalar(int unicodeScalar, char* buffer, int bufferLength, out int numberOfCharactersWritten)
{
return _innerEncoder.TryEncodeUnicodeScalar(unicodeScalar, buffer, bufferLength, out numberOfCharactersWritten);
}
public override bool WillEncode(int unicodeScalar)
{
return !_innerEncoder.IsScalarValueAllowed(new System.Text.Rune(unicodeScalar));
}
}
}