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;
        }
    }
}