DefaultJavaScriptEncoder
using System.Runtime.CompilerServices;
using System.Text.Internal;
using System.Text.Unicode;
namespace System.Text.Encodings.Web
{
internal sealed class DefaultJavaScriptEncoder : JavaScriptEncoder
{
private readonly AllowedCharactersBitmap _allowedCharacters;
private readonly int[] _asciiNeedsEscaping = new int[128];
private static readonly char[] s_b = new char[2] {
'\\',
'b'
};
private static readonly char[] s_t = new char[2] {
'\\',
't'
};
private static readonly char[] s_n = new char[2] {
'\\',
'n'
};
private static readonly char[] s_f = new char[2] {
'\\',
'f'
};
private static readonly char[] s_r = new char[2] {
'\\',
'r'
};
private static readonly char[] s_back = new char[2] {
'\\',
'\\'
};
public override int MaxOutputCharactersPerInputCharacter => 12;
public DefaultJavaScriptEncoder(TextEncoderSettings filter)
{
if (filter == null)
throw new ArgumentNullException("filter");
_allowedCharacters = filter.GetAllowedCharacters();
_allowedCharacters.ForbidUndefinedCharacters();
DefaultHtmlEncoder.ForbidHtmlCharacters(_allowedCharacters);
_allowedCharacters.ForbidCharacter('\\');
_allowedCharacters.ForbidCharacter('`');
for (int i = 0; i < _asciiNeedsEscaping.Length; i++) {
_asciiNeedsEscaping[i] = (WillEncode(i) ? 1 : (-1));
}
}
public DefaultJavaScriptEncoder(params UnicodeRange[] allowedRanges)
: this(new TextEncoderSettings(allowedRanges))
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool WillEncode(int unicodeScalar)
{
if (UnicodeHelpers.IsSupplementaryCodePoint(unicodeScalar))
return true;
return !_allowedCharacters.IsUnicodeScalarAllowed(unicodeScalar);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe override int FindFirstCharacterToEncode(char* text, int textLength)
{
if (text == null)
throw new ArgumentNullException("text");
return _allowedCharacters.FindFirstCharacterToEncode(text, textLength);
}
public unsafe override int FindFirstCharacterToEncodeUtf8(ReadOnlySpan<byte> utf8Text)
{
fixed (byte* ptr = &utf8Text.GetPinnableReference()) {
int num = 0;
while (true) {
if (num >= utf8Text.Length) {
num = -1;
break;
}
if (System.Text.UnicodeUtility.IsAsciiCodePoint(ptr[num])) {
if (DoesAsciiNeedEncoding(ptr[num]) == 1)
break;
num++;
} else {
if (UnicodeHelpers.DecodeScalarValueFromUtf8(utf8Text.Slice(num), out uint result, out int bytesConsumed) != 0 || WillEncode((int)result))
break;
num += bytesConsumed;
}
}
return num;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int DoesAsciiNeedEncoding(byte value)
{
return _asciiNeedsEscaping[value];
}
public unsafe override bool TryEncodeUnicodeScalar(int unicodeScalar, char* buffer, int bufferLength, out int numberOfCharactersWritten)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (!WillEncode(unicodeScalar))
return TextEncoder.TryWriteScalarAsChar(unicodeScalar, buffer, bufferLength, out numberOfCharactersWritten);
char[] source;
switch (unicodeScalar) {
case 8:
source = s_b;
break;
case 9:
source = s_t;
break;
case 10:
source = s_n;
break;
case 12:
source = s_f;
break;
case 13:
source = s_r;
break;
case 92:
source = s_back;
break;
default:
return JavaScriptEncoderHelper.TryWriteEncodedScalarAsNumericEntity(unicodeScalar, buffer, bufferLength, out numberOfCharactersWritten);
}
return TextEncoder.TryCopyCharacters(source, buffer, bufferLength, out numberOfCharactersWritten);
}
}
}