JavaScriptUtils
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Newtonsoft.Json.Utilities
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal static class JavaScriptUtils
{
internal static readonly bool[] SingleQuoteCharEscapeFlags;
internal static readonly bool[] DoubleQuoteCharEscapeFlags;
internal static readonly bool[] HtmlCharEscapeFlags;
private const int UnicodeTextLength = 6;
private const string EscapedUnicodeText = "!";
static JavaScriptUtils()
{
SingleQuoteCharEscapeFlags = new bool[128];
DoubleQuoteCharEscapeFlags = new bool[128];
HtmlCharEscapeFlags = new bool[128];
IList<char> list = new List<char> {
'\n',
'\r',
'\t',
'\\',
'',
'\b'
};
for (int i = 0; i < 32; i++) {
list.Add((char)i);
}
foreach (char item in list.Union(new char[1] {
'\''
})) {
SingleQuoteCharEscapeFlags[item] = true;
}
foreach (char item2 in list.Union(new char[1] {
'"'
})) {
DoubleQuoteCharEscapeFlags[item2] = true;
}
foreach (char item3 in list.Union(new char[5] {
'"',
'\'',
'<',
'>',
'&'
})) {
HtmlCharEscapeFlags[item3] = true;
}
}
public static bool[] GetCharEscapeFlags(StringEscapeHandling stringEscapeHandling, char quoteChar)
{
if (stringEscapeHandling == StringEscapeHandling.EscapeHtml)
return HtmlCharEscapeFlags;
if (quoteChar == '"')
return DoubleQuoteCharEscapeFlags;
return SingleQuoteCharEscapeFlags;
}
public static bool ShouldEscapeJavaScriptString([System.Runtime.CompilerServices.Nullable(2)] string s, bool[] charEscapeFlags)
{
if (s == null)
return false;
foreach (char c in s) {
if (c >= charEscapeFlags.Length || charEscapeFlags[c])
return true;
}
return false;
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static void WriteEscapedJavaScriptString([System.Runtime.CompilerServices.Nullable(1)] TextWriter writer, string s, char delimiter, bool appendDelimiters, [System.Runtime.CompilerServices.Nullable(1)] bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool<char> bufferPool, ref char[] writeBuffer)
{
if (appendDelimiters)
writer.Write(delimiter);
if (!StringUtils.IsNullOrEmpty(s)) {
int num = FirstCharToEscape(s, charEscapeFlags, stringEscapeHandling);
switch (num) {
case -1:
writer.Write(s);
break;
default:
if (writeBuffer == null || writeBuffer.Length < num)
writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, num, writeBuffer);
s.CopyTo(0, writeBuffer, 0, num);
writer.Write(writeBuffer, 0, num);
goto case 0;
case 0: {
int num2;
for (int i = num; i < s.Length; i++) {
char c = s[i];
if (c >= charEscapeFlags.Length || charEscapeFlags[c]) {
string text;
switch (c) {
case '\t':
text = "\\t";
break;
case '\n':
text = "\\n";
break;
case '\r':
text = "\\r";
break;
case '':
text = "\\f";
break;
case '\b':
text = "\\b";
break;
case '\\':
text = "\\\\";
break;
case '
':
text = "\\u0085";
break;
case '
':
text = "\\u2028";
break;
case '
':
text = "\\u2029";
break;
default:
if (c < charEscapeFlags.Length || stringEscapeHandling == StringEscapeHandling.EscapeNonAscii) {
if (c == '\'' && stringEscapeHandling != StringEscapeHandling.EscapeHtml)
text = "\\'";
else if (c == '"' && stringEscapeHandling != StringEscapeHandling.EscapeHtml) {
text = "\\\"";
} else {
if (writeBuffer == null || writeBuffer.Length < 6)
writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, 6, writeBuffer);
StringUtils.ToCharAsUnicode(c, writeBuffer);
text = "!";
}
} else
text = null;
break;
}
if (text != null) {
bool flag = string.Equals(text, "!", StringComparison.Ordinal);
if (i > num) {
num2 = i - num + (flag ? 6 : 0);
int num3 = flag ? 6 : 0;
if (writeBuffer == null || writeBuffer.Length < num2) {
char[] array = BufferUtils.RentBuffer(bufferPool, num2);
if (flag)
Array.Copy(writeBuffer, array, 6);
BufferUtils.ReturnBuffer(bufferPool, writeBuffer);
writeBuffer = array;
}
s.CopyTo(num, writeBuffer, num3, num2 - num3);
writer.Write(writeBuffer, num3, num2 - num3);
}
num = i + 1;
if (!flag)
writer.Write(text);
else
writer.Write(writeBuffer, 0, 6);
}
}
}
num2 = s.Length - num;
if (num2 > 0) {
if (writeBuffer == null || writeBuffer.Length < num2)
writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, num2, writeBuffer);
s.CopyTo(num, writeBuffer, 0, num2);
writer.Write(writeBuffer, 0, num2);
}
break;
}
}
}
if (appendDelimiters)
writer.Write(delimiter);
}
public static string ToEscapedJavaScriptString([System.Runtime.CompilerServices.Nullable(2)] string value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling)
{
bool[] charEscapeFlags = GetCharEscapeFlags(stringEscapeHandling, delimiter);
using (StringWriter stringWriter = StringUtils.CreateStringWriter(value?.Length ?? 16)) {
char[] writeBuffer = null;
WriteEscapedJavaScriptString(stringWriter, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, null, ref writeBuffer);
return stringWriter.ToString();
}
}
private static int FirstCharToEscape(string s, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling)
{
for (int i = 0; i != s.Length; i++) {
char c = s[i];
if (c < charEscapeFlags.Length) {
if (charEscapeFlags[c])
return i;
} else {
if (stringEscapeHandling == StringEscapeHandling.EscapeNonAscii)
return i;
if (c == '
' || c == '
' || c == '
')
return i;
}
}
return -1;
}
public static Task WriteEscapedJavaScriptStringAsync(TextWriter writer, string s, char delimiter, bool appendDelimiters, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
return cancellationToken.FromCanceled();
if (appendDelimiters)
return WriteEscapedJavaScriptStringWithDelimitersAsync(writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
if (StringUtils.IsNullOrEmpty(s))
return cancellationToken.CancelIfRequestedAsync() ?? AsyncUtils.CompletedTask;
return WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
}
private static Task WriteEscapedJavaScriptStringWithDelimitersAsync(TextWriter writer, string s, char delimiter, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken)
{
Task task = writer.WriteAsync(delimiter, cancellationToken);
if (!task.IsCompletedSucessfully())
return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
if (!StringUtils.IsNullOrEmpty(s)) {
task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
if (task.IsCompletedSucessfully())
return writer.WriteAsync(delimiter, cancellationToken);
}
return WriteCharAsync(task, writer, delimiter, cancellationToken);
}
[AsyncStateMachine(typeof(<WriteEscapedJavaScriptStringWithDelimitersAsync>d__13))]
private static Task WriteEscapedJavaScriptStringWithDelimitersAsync(Task task, TextWriter writer, string s, char delimiter, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken)
{
<WriteEscapedJavaScriptStringWithDelimitersAsync>d__13 stateMachine = default(<WriteEscapedJavaScriptStringWithDelimitersAsync>d__13);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.task = task;
stateMachine.writer = writer;
stateMachine.s = s;
stateMachine.delimiter = delimiter;
stateMachine.charEscapeFlags = charEscapeFlags;
stateMachine.stringEscapeHandling = stringEscapeHandling;
stateMachine.client = client;
stateMachine.writeBuffer = writeBuffer;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(<WriteCharAsync>d__14))]
public static Task WriteCharAsync(Task task, TextWriter writer, char c, CancellationToken cancellationToken)
{
<WriteCharAsync>d__14 stateMachine = default(<WriteCharAsync>d__14);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.task = task;
stateMachine.writer = writer;
stateMachine.c = c;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
private static Task WriteEscapedJavaScriptStringWithoutDelimitersAsync(TextWriter writer, string s, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken)
{
int num = FirstCharToEscape(s, charEscapeFlags, stringEscapeHandling);
if (num != -1)
return WriteDefinitelyEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, num, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken);
return writer.WriteAsync(s, cancellationToken);
}
[AsyncStateMachine(typeof(<WriteDefinitelyEscapedJavaScriptStringWithoutDelimitersAsync>d__16))]
private static Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimitersAsync(TextWriter writer, string s, int lastWritePosition, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken)
{
<WriteDefinitelyEscapedJavaScriptStringWithoutDelimitersAsync>d__16 stateMachine = default(<WriteDefinitelyEscapedJavaScriptStringWithoutDelimitersAsync>d__16);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.writer = writer;
stateMachine.s = s;
stateMachine.lastWritePosition = lastWritePosition;
stateMachine.charEscapeFlags = charEscapeFlags;
stateMachine.stringEscapeHandling = stringEscapeHandling;
stateMachine.client = client;
stateMachine.writeBuffer = writeBuffer;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, [System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out string errorMessage)
{
dateTime = default(DateTime);
errorMessage = null;
if (!TryGetDateConstructorValue(reader, out long? integer, out errorMessage) || !integer.HasValue) {
errorMessage = (errorMessage ?? "Date constructor has no arguments.");
return false;
}
if (!TryGetDateConstructorValue(reader, out long? integer2, out errorMessage))
return false;
if (integer2.HasValue) {
List<long> list = new List<long> {
integer.Value,
integer2.Value
};
while (true) {
if (!TryGetDateConstructorValue(reader, out long? integer3, out errorMessage))
return false;
if (!integer3.HasValue)
break;
list.Add(integer3.Value);
}
if (list.Count > 7) {
errorMessage = "Unexpected number of arguments when reading date constructor.";
return false;
}
while (list.Count < 7) {
list.Add(0);
}
dateTime = new DateTime((int)list[0], (int)list[1] + 1, (int)((list[2] == 0) ? 1 : list[2]), (int)list[3], (int)list[4], (int)list[5], (int)list[6]);
} else
dateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(integer.Value);
return true;
}
private static bool TryGetDateConstructorValue(JsonReader reader, out long? integer, [System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.NotNullWhen(false)] out string errorMessage)
{
integer = null;
errorMessage = null;
if (!reader.Read()) {
errorMessage = "Unexpected end when reading date constructor.";
return false;
}
if (reader.TokenType == JsonToken.EndConstructor)
return true;
if (reader.TokenType != JsonToken.Integer) {
errorMessage = "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType.ToString();
return false;
}
integer = (long)reader.Value;
return true;
}
}
}