JavaScriptUtils
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Newtonsoft.Json.Utilities
{
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(string s, bool[] charEscapeFlags)
{
if (s == null)
return false;
foreach (char c in s) {
if (c >= charEscapeFlags.Length || charEscapeFlags[c])
return true;
}
return false;
}
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool<char> bufferPool, ref char[] writeBuffer)
{
if (appendDelimiters)
writer.Write(delimiter);
if (!string.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, "!");
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(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 bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, 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, 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;
return false;
}
integer = (long)reader.Value;
return true;
}
}
}