Decompiled source of WhatGotChanged v1.0.0

WhatGotChanged.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using WhatGotChanged.Source;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("WhatGotChanged")]
[assembly: AssemblyDescription("Auto-generates changelogs by comparing installed mods against previous Thunderstore versions")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WhatGotChanged")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d4e5f6a7-b8c9-0123-4567-89abcdef0123")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WhatGotChanged
{
	[BepInPlugin("IAmOnTheInternetAndItIsScary.WhatGotChanged", "WhatGotChanged", "1.0.0")]
	public class WhatGotChangedPlugin : BaseUnityPlugin
	{
		internal const string ModName = "WhatGotChanged";

		internal const string ModGUID = "IAmOnTheInternetAndItIsScary.WhatGotChanged";

		internal const string ModVersion = "1.0.0";

		public void Awake()
		{
			try
			{
				ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "TrackTeams", "", "Filter by Thunderstore team/owner names (comma-separated). Tracks ALL mods published by these teams.");
				ConfigEntry<string> val2 = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "TrackMods", "", "Filter by specific Thunderstore mod names (comma-separated). Use the exact name as it appears on Thunderstore.");
				ConfigEntry<ChangelogWriter.DetailLevel> val3 = ((BaseUnityPlugin)this).Config.Bind<ChangelogWriter.DetailLevel>("Output", "DetailLevel", ChangelogWriter.DetailLevel.Simple, "Detail level for changelogs.\nsimple   — counts per class (e.g. \"3 methods changed, 1 added\")\ndetailed — lists every change by name\nfull     — actual C# code diffs");
				ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
				Scanner.Run(((BaseUnityPlugin)this).Logger, val.Value, val2.Value, val3.Value);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Fatal error: " + ex.Message));
				((BaseUnityPlugin)this).Logger.LogError((object)ex.StackTrace);
			}
		}
	}
}
namespace WhatGotChanged.Source
{
	public static class Scanner
	{
		public static void Run(ManualLogSource log, string trackTeams, string trackMods, ChangelogWriter.DetailLevel detailLevel)
		{
			log.LogInfo((object)"=== WhatGotChanged? ===");
			if (string.IsNullOrEmpty(trackTeams) && string.IsNullOrEmpty(trackMods))
			{
				log.LogInfo((object)"No mods configured — edit config to add TrackTeams or TrackMods");
				return;
			}
			List<ThunderstoreApi.PackageInfo> list = ThunderstoreApi.FetchPackageList(log);
			if (list == null || list.Count == 0)
			{
				log.LogWarning((object)"Could not fetch Thunderstore data — are you offline?");
				return;
			}
			Dictionary<string, string> dictionary = ModDiscovery.GatherCandidates(log, trackTeams, trackMods, list);
			if (dictionary.Count == 0)
			{
				log.LogInfo((object)"No installed mods matched configured filters");
				return;
			}
			Dictionary<string, ThunderstoreApi.PackageInfo> dictionary2 = new Dictionary<string, ThunderstoreApi.PackageInfo>(StringComparer.OrdinalIgnoreCase);
			foreach (ThunderstoreApi.PackageInfo item in list)
			{
				string key = item.Owner + "/" + item.Name;
				if (!dictionary2.ContainsKey(key))
				{
					dictionary2[key] = item;
				}
			}
			log.LogInfo((object)$"Scanning {dictionary.Count} package(s)...");
			string text = Path.Combine(Paths.ConfigPath, "WhatGotChanged");
			Directory.CreateDirectory(text);
			int num = 0;
			foreach (KeyValuePair<string, string> item2 in dictionary)
			{
				string key2 = item2.Key;
				string value = item2.Value;
				ThunderstoreApi.PackageInfo packageInfo = dictionary2[key2];
				if (packageInfo.Versions.Count < 2)
				{
					log.LogInfo((object)("  " + packageInfo.Name + " — only 1 version, nothing to compare"));
					continue;
				}
				ThunderstoreApi.VersionInfo versionInfo = packageInfo.Versions[0];
				ThunderstoreApi.VersionInfo versionInfo2 = packageInfo.Versions[1];
				string text2 = Path.Combine(text, packageInfo.Name + "-" + versionInfo.VersionNumber + ".md");
				if (File.Exists(text2))
				{
					log.LogInfo((object)("  " + packageInfo.Name + " v" + versionInfo.VersionNumber + " — changelog already exists, skipping"));
					continue;
				}
				bool flag = value != versionInfo.VersionNumber;
				if (flag)
				{
					log.LogInfo((object)("  " + packageInfo.Name + ": UPDATE AVAILABLE v" + value + " -> v" + versionInfo.VersionNumber));
				}
				log.LogInfo((object)("  " + packageInfo.Name + ": comparing v" + versionInfo2.VersionNumber + " -> v" + versionInfo.VersionNumber));
				string text3 = ThunderstoreApi.FetchDecompiledSource(packageInfo.Owner, packageInfo.Name, versionInfo2.VersionNumber, log);
				string text4 = ThunderstoreApi.FetchDecompiledSource(packageInfo.Owner, packageInfo.Name, versionInfo.VersionNumber, log);
				if (text3 == null && text4 == null)
				{
					log.LogInfo((object)"    Decompiled source not available for either version, skipping");
					continue;
				}
				if (text3 == null)
				{
					log.LogInfo((object)("    Decompiled source not available for v" + versionInfo2.VersionNumber + ", skipping"));
					continue;
				}
				if (text4 == null)
				{
					log.LogInfo((object)("    Decompiled source not available for v" + versionInfo.VersionNumber + ", skipping"));
					continue;
				}
				SourceDiffer.DiffResult diffResult = SourceDiffer.Diff(text3, text4, log);
				if (diffResult.Changes.Count > 0)
				{
					log.LogInfo((object)$"    {diffResult.Changes.Count} change(s) detected");
				}
				else
				{
					log.LogInfo((object)"    No code changes — metadata/asset update only");
				}
				ChangelogWriter.WriteChangelog(text2, packageInfo.Name, versionInfo2.VersionNumber, versionInfo.VersionNumber, value, flag, diffResult, detailLevel);
				num++;
			}
			if (num > 0)
			{
				log.LogInfo((object)"Changelogs: BepInEx/config/WhatGotChanged/");
			}
			log.LogInfo((object)"=== Scan Complete ===");
		}
	}
	public static class ModDiscovery
	{
		private class InstalledPlugin
		{
			public string GUID;

			public string Name;

			public string Version;
		}

		public static Dictionary<string, string> GatherCandidates(ManualLogSource log, string trackTeams, string trackMods, List<ThunderstoreApi.PackageInfo> allPackages)
		{
			HashSet<string> hashSet = ParseList(trackTeams);
			HashSet<string> hashSet2 = ParseList(trackMods);
			Dictionary<string, InstalledPlugin> plugins = BuildInstalledPluginMap();
			Dictionary<string, ThunderstoreApi.PackageInfo> dictionary = new Dictionary<string, ThunderstoreApi.PackageInfo>(StringComparer.OrdinalIgnoreCase);
			foreach (ThunderstoreApi.PackageInfo allPackage in allPackages)
			{
				if (hashSet.Contains(allPackage.Owner) || hashSet2.Contains(allPackage.Name))
				{
					dictionary[allPackage.Owner + "/" + allPackage.Name] = allPackage;
				}
			}
			log.LogInfo((object)$"Config matched {dictionary.Count} package(s) on Thunderstore");
			Dictionary<string, string> dictionary2 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (KeyValuePair<string, ThunderstoreApi.PackageInfo> item in dictionary)
			{
				string key = item.Key;
				ThunderstoreApi.PackageInfo value = item.Value;
				string text = FindDirect(value.Owner, value.Name, plugins);
				if (text != null)
				{
					dictionary2[key] = text;
					num++;
					log.LogInfo((object)("  " + key + " v" + text + " — found via direct match"));
					continue;
				}
				text = FindViaCfgFiles(value.Name);
				if (text != null)
				{
					dictionary2[key] = text;
					num2++;
					log.LogInfo((object)("  " + key + " v" + text + " — found via cfg scan"));
					continue;
				}
				text = FindViaChainloader(value.Owner, value.Name, plugins);
				if (text != null)
				{
					dictionary2[key] = text;
					num3++;
					log.LogInfo((object)("  " + key + " v" + text + " — found via chainloader scan"));
				}
				else
				{
					log.LogInfo((object)("  " + key + " — not installed, skipping"));
				}
			}
			log.LogInfo((object)$"Total installed: {num} direct, {num2} from cfg scan, {num3} from chainloader");
			return dictionary2;
		}

		private static Dictionary<string, InstalledPlugin> BuildInstalledPluginMap()
		{
			Dictionary<string, InstalledPlugin> dictionary = new Dictionary<string, InstalledPlugin>(StringComparer.OrdinalIgnoreCase);
			if (Chainloader.PluginInfos == null)
			{
				return dictionary;
			}
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				BepInPlugin metadata = pluginInfo.Value.Metadata;
				dictionary[metadata.GUID] = new InstalledPlugin
				{
					GUID = metadata.GUID,
					Name = metadata.Name,
					Version = metadata.Version.ToString()
				};
			}
			return dictionary;
		}

		private static string FindDirect(string owner, string mod, Dictionary<string, InstalledPlugin> plugins)
		{
			string[] array = new string[2]
			{
				owner + "." + mod,
				"com." + owner + "." + mod
			};
			string[] array2 = array;
			foreach (string key in array2)
			{
				if (plugins.TryGetValue(key, out var value))
				{
					return value.Version;
				}
			}
			foreach (InstalledPlugin value2 in plugins.Values)
			{
				if (!value2.Name.Equals(mod, StringComparison.OrdinalIgnoreCase) || value2.GUID.IndexOf(owner, StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				return value2.Version;
			}
			return null;
		}

		private static string FindViaCfgFiles(string mod)
		{
			string configPath = Paths.ConfigPath;
			if (!Directory.Exists(configPath))
			{
				return null;
			}
			string value = mod.ToLowerInvariant();
			string[] files = Directory.GetFiles(configPath, "*.cfg");
			foreach (string path in files)
			{
				string text = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
				if (text.Contains(value))
				{
					return "unknown";
				}
			}
			return null;
		}

		private static string FindViaChainloader(string owner, string mod, Dictionary<string, InstalledPlugin> plugins)
		{
			if (plugins.Count == 0)
			{
				return null;
			}
			string text = mod.ToLowerInvariant();
			string value = owner.ToLowerInvariant();
			InstalledPlugin installedPlugin = null;
			foreach (InstalledPlugin value2 in plugins.Values)
			{
				string text2 = value2.GUID.ToLowerInvariant();
				string text3 = value2.Name.ToLowerInvariant();
				if (text2.Contains(text) || text3 == text)
				{
					if (text2.Contains(value))
					{
						return value2.Version;
					}
					if (installedPlugin == null)
					{
						installedPlugin = value2;
					}
				}
			}
			return installedPlugin?.Version;
		}

		private static HashSet<string> ParseList(string csv)
		{
			return new HashSet<string>(from s in csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim(), StringComparer.OrdinalIgnoreCase);
		}
	}
	public static class ThunderstoreApi
	{
		public class PackageInfo
		{
			[JsonProperty("name")]
			public string Name { get; set; } = "";


			[JsonProperty("owner")]
			public string Owner { get; set; } = "";


			[JsonProperty("versions")]
			public List<VersionInfo> Versions { get; set; } = new List<VersionInfo>();

		}

		public class VersionInfo
		{
			[JsonProperty("version_number")]
			public string VersionNumber { get; set; } = "";

		}

		public class DecompilationResponse
		{
			[JsonProperty("decompilations")]
			public List<DecompilationEntry> Decompilations { get; set; } = new List<DecompilationEntry>();

		}

		public class DecompilationEntry
		{
			[JsonProperty("url")]
			public string Url { get; set; } = "";

		}

		private const string PackageListUrl = "https://thunderstore.io/c/valheim/api/v1/package/";

		private const string DecompilationUrl = "https://thunderstore.io/api/cyberstorm/package/{0}/{1}/v/{2}/source/";

		private const string UserAgent = "WhatGotChanged/1.0";

		private const int Timeout = 30000;

		public static List<PackageInfo> FetchPackageList(ManualLogSource log)
		{
			try
			{
				log.LogInfo((object)"Fetching Thunderstore package list...");
				HttpWebRequest httpWebRequest = CreateRequest("https://thunderstore.io/c/valheim/api/v1/package/");
				using HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
				using StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
				return JsonConvert.DeserializeObject<List<PackageInfo>>(streamReader.ReadToEnd());
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Thunderstore fetch failed: " + ex.Message));
				return null;
			}
		}

		public static string FetchDecompiledSource(string owner, string packageName, string version, ManualLogSource log)
		{
			try
			{
				HttpWebRequest httpWebRequest = CreateRequest($"https://thunderstore.io/api/cyberstorm/package/{owner}/{packageName}/v/{version}/source/");
				DecompilationResponse decompilationResponse;
				using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse())
				{
					using StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
					decompilationResponse = JsonConvert.DeserializeObject<DecompilationResponse>(streamReader.ReadToEnd());
				}
				if (decompilationResponse?.Decompilations == null || decompilationResponse.Decompilations.Count == 0)
				{
					return null;
				}
				string url = decompilationResponse.Decompilations[0].Url;
				if (string.IsNullOrEmpty(url))
				{
					return null;
				}
				HttpWebRequest httpWebRequest2 = CreateRequest(url);
				using HttpWebResponse httpWebResponse2 = (HttpWebResponse)httpWebRequest2.GetResponse();
				using StreamReader streamReader2 = new StreamReader(httpWebResponse2.GetResponseStream());
				return streamReader2.ReadToEnd();
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("    Fetch failed for " + owner + "/" + packageName + " v" + version + ": " + ex.Message));
				return null;
			}
		}

		private static HttpWebRequest CreateRequest(string url)
		{
			HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url);
			httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
			httpWebRequest.Timeout = 30000;
			httpWebRequest.UserAgent = "WhatGotChanged/1.0";
			return httpWebRequest;
		}
	}
	public static class SourceDiffer
	{
		public enum ChangeKind
		{
			Added,
			Removed,
			Modified
		}

		public enum ChangeType
		{
			Type,
			Method,
			Field,
			Property
		}

		public class Change
		{
			public ChangeKind Kind;

			public ChangeType Type;

			public string ClassName;

			public string MemberName;

			public string NewBody;

			public string OldBody;

			public Change(ChangeKind kind, ChangeType type, string className, string memberName, string newBody, string oldBody = "")
			{
				Kind = kind;
				Type = type;
				ClassName = className;
				MemberName = memberName;
				NewBody = newBody;
				OldBody = oldBody;
			}
		}

		public class DiffResult
		{
			public List<Change> Changes = new List<Change>();
		}

		private class ParsedClass
		{
			public Dictionary<string, string> Methods = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

			public List<string> Fields = new List<string>();

			public List<string> Properties = new List<string>();
		}

		private static readonly string[] AccessModifiers = new string[13]
		{
			"public", "private", "protected", "internal", "static", "abstract", "sealed", "partial", "readonly", "new",
			"override", "virtual", "unsafe"
		};

		private static readonly string[] TypeKeywords = new string[4] { "class", "struct", "interface", "enum" };

		private static readonly HashSet<string> ReservedWords = new HashSet<string> { "class", "struct", "interface", "enum", "namespace", "return", "using", "get", "set" };

		public static DiffResult Diff(string oldSource, string newSource, ManualLogSource log = null)
		{
			DiffResult diffResult = new DiffResult();
			Dictionary<string, ParsedClass> dictionary = ParseSource(oldSource);
			Dictionary<string, ParsedClass> dictionary2 = ParseSource(newSource);
			if (log != null)
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				foreach (ParsedClass value2 in dictionary.Values)
				{
					num += value2.Methods.Count;
					num3 += value2.Fields.Count + value2.Properties.Count;
				}
				foreach (ParsedClass value3 in dictionary2.Values)
				{
					num2 += value3.Methods.Count;
					num4 += value3.Fields.Count + value3.Properties.Count;
				}
				log.LogInfo((object)$"    Parsed: {dictionary.Count}/{dictionary2.Count} classes, {num}/{num2} methods, {num3}/{num4} fields+props");
			}
			foreach (KeyValuePair<string, ParsedClass> item in dictionary2)
			{
				if (!dictionary.ContainsKey(item.Key))
				{
					diffResult.Changes.Add(new Change(ChangeKind.Added, ChangeType.Type, item.Key, "", ""));
				}
			}
			foreach (KeyValuePair<string, ParsedClass> item2 in dictionary)
			{
				if (!dictionary2.ContainsKey(item2.Key))
				{
					diffResult.Changes.Add(new Change(ChangeKind.Removed, ChangeType.Type, item2.Key, "", ""));
				}
			}
			foreach (KeyValuePair<string, ParsedClass> item3 in dictionary2)
			{
				if (dictionary.TryGetValue(item3.Key, out var value))
				{
					DiffMembers(item3.Key, value, item3.Value, diffResult);
				}
			}
			return diffResult;
		}

		private static void DiffMembers(string className, ParsedClass oldClass, ParsedClass newClass, DiffResult result)
		{
			string className2 = (className.Contains(".") ? className.Substring(className.LastIndexOf('.') + 1) : className);
			foreach (KeyValuePair<string, string> method in newClass.Methods)
			{
				if (!oldClass.Methods.ContainsKey(method.Key))
				{
					result.Changes.Add(new Change(ChangeKind.Added, ChangeType.Method, className2, method.Key, method.Value));
				}
			}
			foreach (KeyValuePair<string, string> method2 in oldClass.Methods)
			{
				if (!newClass.Methods.ContainsKey(method2.Key))
				{
					result.Changes.Add(new Change(ChangeKind.Removed, ChangeType.Method, className2, method2.Key, method2.Value));
				}
			}
			foreach (KeyValuePair<string, string> method3 in newClass.Methods)
			{
				if (oldClass.Methods.TryGetValue(method3.Key, out var value) && value != method3.Value)
				{
					result.Changes.Add(new Change(ChangeKind.Modified, ChangeType.Method, className2, method3.Key, method3.Value, value));
				}
			}
			DiffStringSet(oldClass.Fields, newClass.Fields, ChangeType.Field, className2, result);
			DiffStringSet(oldClass.Properties, newClass.Properties, ChangeType.Property, className2, result);
		}

		private static void DiffStringSet(List<string> oldItems, List<string> newItems, ChangeType type, string className, DiffResult result)
		{
			HashSet<string> hashSet = new HashSet<string>(oldItems, StringComparer.OrdinalIgnoreCase);
			HashSet<string> hashSet2 = new HashSet<string>(newItems, StringComparer.OrdinalIgnoreCase);
			foreach (string item in hashSet2.Except(hashSet))
			{
				result.Changes.Add(new Change(ChangeKind.Added, type, className, item, ""));
			}
			foreach (string item2 in hashSet.Except(hashSet2))
			{
				result.Changes.Add(new Change(ChangeKind.Removed, type, className, item2, ""));
			}
		}

		private static Dictionary<string, ParsedClass> ParseSource(string source)
		{
			Dictionary<string, ParsedClass> dictionary = new Dictionary<string, ParsedClass>(StringComparer.OrdinalIgnoreCase);
			string[] array = source.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			string text = "";
			string text2 = "";
			ParsedClass parsedClass = null;
			int num = 0;
			int num2 = -1;
			int num3 = -1;
			bool flag = false;
			List<string> list = new List<string>();
			string key = "";
			foreach (string text3 in array)
			{
				string text4 = text3.Trim();
				if (text4.StartsWith("namespace "))
				{
					text = text4.Substring("namespace ".Length).TrimEnd('{', ' ', '\t');
				}
				int num4 = text4.Count((char c) => c == '{');
				int num5 = text4.Count((char c) => c == '}');
				int num6 = num + num4 - num5;
				if (flag && num4 > 0)
				{
					num2 = num + 1;
					flag = false;
				}
				if ((parsedClass == null || num < num2) && IsTypeDeclaration(text4, out var name))
				{
					string text5 = (string.IsNullOrEmpty(text) ? name : (text + "." + name));
					if (parsedClass != null && num >= num2)
					{
						text5 = text2 + "." + name;
					}
					text2 = text5;
					parsedClass = new ParsedClass();
					if (num4 > 0)
					{
						num2 = num + 1;
					}
					else
					{
						flag = true;
					}
					if (!dictionary.ContainsKey(text5))
					{
						dictionary[text5] = parsedClass;
					}
				}
				if (parsedClass != null && num >= num2 && num2 > 0 && !flag)
				{
					string signature;
					string signature2;
					string signature3;
					if (text4 == "{" || text4 == "}")
					{
						if (num3 >= 0)
						{
							list.Add(text3);
							if (num6 <= num3)
							{
								parsedClass.Methods[key] = string.Join("\n", list);
								num3 = -1;
								list.Clear();
							}
						}
					}
					else if (num3 >= 0)
					{
						list.Add(text3);
						if (num6 <= num3)
						{
							parsedClass.Methods[key] = string.Join("\n", list);
							num3 = -1;
							list.Clear();
						}
					}
					else if (IsMethodDeclaration(text4, out signature))
					{
						key = signature;
						list.Clear();
						list.Add(text3);
						if (text4.Contains("=>") || (num4 > 0 && num5 > 0 && num4 == num5))
						{
							parsedClass.Methods[signature] = text3;
							list.Clear();
						}
						else
						{
							num3 = num;
						}
					}
					else if (IsFieldDeclaration(text4, out signature2))
					{
						parsedClass.Fields.Add(signature2);
					}
					else if (IsPropertyDeclaration(text4, out signature3))
					{
						parsedClass.Properties.Add(signature3);
					}
				}
				num = num6;
				if (parsedClass != null && num < num2)
				{
					parsedClass = null;
					num2 = -1;
				}
			}
			return dictionary;
		}

		private static bool IsTypeDeclaration(string line, out string name)
		{
			name = "";
			string input = line;
			string[] accessModifiers = AccessModifiers;
			foreach (string text in accessModifiers)
			{
				input = Regex.Replace(input, "\\b" + text + "\\b", "").Trim();
			}
			string[] typeKeywords = TypeKeywords;
			foreach (string text2 in typeKeywords)
			{
				Match match = Regex.Match(input, "\\b" + text2 + "\\s+(\\w+)");
				if (match.Success)
				{
					name = match.Groups[1].Value;
					return true;
				}
			}
			return false;
		}

		private static bool IsMethodDeclaration(string line, out string signature)
		{
			signature = "";
			if (line.StartsWith("[") || line.StartsWith("//") || line.StartsWith("/*") || line.Contains(" event "))
			{
				return false;
			}
			Match match = Regex.Match(line, "(?:(?:public|private|protected|internal|static|virtual|override|abstract|sealed|async|new|extern|unsafe)\\s+)*(\\w[\\w<>\\[\\],\\s\\?]*)\\s+(\\w+)\\s*\\(([^)]*)\\)");
			if (match.Success)
			{
				string item = match.Groups[1].Value.Trim();
				if (ReservedWords.Contains(item))
				{
					return false;
				}
				signature = match.Groups[2].Value.Trim() + "(" + SimplifyParams(match.Groups[3].Value.Trim()) + ")";
				return true;
			}
			match = Regex.Match(line, "(?:(?:public|private|protected|internal|static)\\s+)+(\\w+)\\s*\\(([^)]*)\\)\\s*(?::|{)");
			if (match.Success)
			{
				signature = match.Groups[1].Value.Trim() + "(" + SimplifyParams(match.Groups[2].Value.Trim()) + ")";
				return true;
			}
			return false;
		}

		private static string SimplifyParams(string parameters)
		{
			if (string.IsNullOrWhiteSpace(parameters))
			{
				return "";
			}
			return string.Join(", ", from p in parameters.Split(new char[1] { ',' })
				select p.Trim().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries) into t
				where t.Length >= 1
				select t[0]);
		}

		private static bool IsFieldDeclaration(string line, out string signature)
		{
			signature = "";
			if (line.Contains("(") || line.Contains("=>") || line.StartsWith("[") || line.StartsWith("//") || line.Contains(" event "))
			{
				return false;
			}
			Match match = Regex.Match(line, "(?:(?:public|private|protected|internal|static|readonly|const|volatile|new|unsafe)\\s+)*(\\w[\\w<>\\[\\],\\?\\s]*)\\s+(\\w+)\\s*[;=]");
			if (!match.Success)
			{
				return false;
			}
			string text = match.Groups[1].Value.Trim();
			if (ReservedWords.Contains(text))
			{
				return false;
			}
			signature = text + " " + match.Groups[2].Value.Trim();
			return true;
		}

		private static bool IsPropertyDeclaration(string line, out string signature)
		{
			signature = "";
			Match match = Regex.Match(line, "(?:(?:public|private|protected|internal|static|virtual|override|abstract|new|unsafe)\\s+)*(\\w[\\w<>\\[\\],\\?\\s]*)\\s+(\\w+)\\s*\\{");
			if (!match.Success || (!line.Contains("get") && !line.Contains("set")))
			{
				return false;
			}
			string text = match.Groups[1].Value.Trim();
			if (ReservedWords.Contains(text))
			{
				return false;
			}
			signature = text + " " + match.Groups[2].Value.Trim();
			return true;
		}
	}
	public static class ChangelogWriter
	{
		public enum DetailLevel
		{
			Simple,
			Detailed,
			Full
		}

		public static void WriteChangelog(string outputPath, string modName, string oldVersion, string newVersion, string installedVersion, bool hasUpdate, SourceDiffer.DiffResult diff, DetailLevel level)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# " + modName);
			stringBuilder.AppendLine("`v" + oldVersion + "` → `v" + newVersion + "`");
			stringBuilder.AppendLine();
			if (hasUpdate && !string.IsNullOrEmpty(installedVersion))
			{
				stringBuilder.AppendLine("> ⚠ **Update available:** you have `v" + installedVersion + "`, latest is `v" + newVersion + "`");
				stringBuilder.AppendLine();
			}
			stringBuilder.AppendLine($"*Generated {DateTime.Now:yyyy-MM-dd HH:mm}*");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("---");
			stringBuilder.AppendLine();
			if (diff.Changes.Count == 0)
			{
				stringBuilder.AppendLine("No code changes — metadata/asset update only.");
				stringBuilder.AppendLine();
			}
			else
			{
				switch (level)
				{
				case DetailLevel.Simple:
					WriteSimple(stringBuilder, diff);
					break;
				case DetailLevel.Detailed:
					WriteDetailed(stringBuilder, diff);
					break;
				case DetailLevel.Full:
					WriteFull(stringBuilder, diff);
					break;
				}
			}
			File.WriteAllText(outputPath, stringBuilder.ToString());
		}

		private static IEnumerable<IGrouping<string, SourceDiffer.Change>> GroupByClass(SourceDiffer.DiffResult diff)
		{
			return from c in diff.Changes
				group c by c.ClassName into g
				orderby g.Key
				select g;
		}

		private static void WriteSimple(StringBuilder sb, SourceDiffer.DiffResult diff)
		{
			foreach (IGrouping<string, SourceDiffer.Change> item in GroupByClass(diff))
			{
				IGrouping<string, SourceDiffer.Change> group = item;
				SourceDiffer.Change change = group.FirstOrDefault((SourceDiffer.Change c) => c.Type == SourceDiffer.ChangeType.Type);
				if (change != null)
				{
					sb.AppendLine("- **" + group.Key + "**: " + ((change.Kind == SourceDiffer.ChangeKind.Added) ? "new" : "removed") + " type");
					continue;
				}
				List<string> parts = new List<string>();
				Count(SourceDiffer.ChangeType.Method, SourceDiffer.ChangeKind.Added, "method(s) added");
				Count(SourceDiffer.ChangeType.Method, SourceDiffer.ChangeKind.Modified, "method(s) changed");
				Count(SourceDiffer.ChangeType.Method, SourceDiffer.ChangeKind.Removed, "method(s) removed");
				Count(SourceDiffer.ChangeType.Field, SourceDiffer.ChangeKind.Added, "field(s) added");
				Count(SourceDiffer.ChangeType.Field, SourceDiffer.ChangeKind.Removed, "field(s) removed");
				Count(SourceDiffer.ChangeType.Property, SourceDiffer.ChangeKind.Added, "property(s) added");
				Count(SourceDiffer.ChangeType.Property, SourceDiffer.ChangeKind.Removed, "property(s) removed");
				if (parts.Count > 0)
				{
					sb.AppendLine("- **" + group.Key + "**: " + string.Join(", ", parts));
				}
				void Count(SourceDiffer.ChangeType type, SourceDiffer.ChangeKind kind, string label)
				{
					int num = group.Count((SourceDiffer.Change c) => c.Type == type && c.Kind == kind);
					if (num > 0)
					{
						parts.Add($"{num} {label}");
					}
				}
			}
			sb.AppendLine();
		}

		private static void WriteDetailed(StringBuilder sb, SourceDiffer.DiffResult diff)
		{
			foreach (IGrouping<string, SourceDiffer.Change> item in GroupByClass(diff))
			{
				sb.AppendLine("### " + item.Key);
				sb.AppendLine();
				foreach (SourceDiffer.Change item2 in item.Where((SourceDiffer.Change c) => c.Kind == SourceDiffer.ChangeKind.Added))
				{
					sb.AppendLine("- + `" + FormatMember(item2) + "`");
				}
				foreach (SourceDiffer.Change item3 in item.Where((SourceDiffer.Change c) => c.Kind == SourceDiffer.ChangeKind.Removed))
				{
					sb.AppendLine("- - `" + FormatMember(item3) + "`");
				}
				foreach (SourceDiffer.Change item4 in item.Where((SourceDiffer.Change c) => c.Kind == SourceDiffer.ChangeKind.Modified))
				{
					sb.AppendLine("- ~ `" + FormatMember(item4) + "`");
				}
				sb.AppendLine();
			}
		}

		private static void WriteFull(StringBuilder sb, SourceDiffer.DiffResult diff)
		{
			foreach (IGrouping<string, SourceDiffer.Change> item in GroupByClass(diff))
			{
				sb.AppendLine("### " + item.Key);
				sb.AppendLine();
				foreach (SourceDiffer.Change item2 in item)
				{
					sb.AppendLine("**" + KindSymbol(item2.Kind) + " " + FormatMember(item2) + "**");
					if (item2.Type == SourceDiffer.ChangeType.Method)
					{
						if (item2.Kind == SourceDiffer.ChangeKind.Modified)
						{
							WriteLineDiff(sb, item2.OldBody, item2.NewBody);
						}
						else
						{
							string text = ((item2.Kind == SourceDiffer.ChangeKind.Added) ? item2.NewBody : item2.OldBody);
							if (!string.IsNullOrEmpty(text))
							{
								string text2 = ((item2.Kind == SourceDiffer.ChangeKind.Added) ? "+" : "-");
								sb.AppendLine("```csharp");
								string[] array = text.Split(new char[1] { '\n' });
								foreach (string text3 in array)
								{
									sb.AppendLine(text2 + " " + text3);
								}
								sb.AppendLine("```");
							}
						}
					}
					sb.AppendLine();
				}
			}
		}

		private static void WriteLineDiff(StringBuilder sb, string oldBody, string newBody)
		{
			string[] array = oldBody.Split(new char[1] { '\n' });
			string[] array2 = newBody.Split(new char[1] { '\n' });
			int num = array.Length;
			int num2 = array2.Length;
			int[,] array3 = new int[num + 1, num2 + 1];
			for (int num3 = num - 1; num3 >= 0; num3--)
			{
				for (int num4 = num2 - 1; num4 >= 0; num4--)
				{
					array3[num3, num4] = ((array[num3].Trim() == array2[num4].Trim()) ? (array3[num3 + 1, num4 + 1] + 1) : Math.Max(array3[num3 + 1, num4], array3[num3, num4 + 1]));
				}
			}
			sb.AppendLine("```diff");
			int num5 = 0;
			int num6 = 0;
			while (num5 < num || num6 < num2)
			{
				if (num5 < num && num6 < num2 && array[num5].Trim() == array2[num6].Trim())
				{
					sb.AppendLine("  " + array2[num6]);
					num5++;
					num6++;
				}
				else if (num6 < num2 && (num5 >= num || array3[num5, num6 + 1] >= array3[num5 + 1, num6]))
				{
					sb.AppendLine("+ " + array2[num6]);
					num6++;
				}
				else if (num5 < num)
				{
					sb.AppendLine("- " + array[num5]);
					num5++;
				}
			}
			sb.AppendLine("```");
		}

		private static string KindSymbol(SourceDiffer.ChangeKind kind)
		{
			return kind switch
			{
				SourceDiffer.ChangeKind.Added => "+", 
				SourceDiffer.ChangeKind.Removed => "-", 
				_ => "~", 
			};
		}

		private static string FormatMember(SourceDiffer.Change change)
		{
			return change.Type.ToString().ToLower() + ": " + change.MemberName;
		}
	}
}
[CompilerGenerated]
internal sealed class <b0c506eb-6090-4c98-a5fc-7e64dce1d243><PrivateImplementationDetails>
{
	[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 6)]
	internal struct __StaticArrayInitTypeSize=6
	{
	}

	internal static readonly __StaticArrayInitTypeSize=6 515E2C3AE1FA25341D4979E6610F37196C07BB55D83828D69D8FCD2331395EE0/* Not supported: data(7B 00 20 00 09 00) */;
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	internal class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
}
namespace Newtonsoft.Json
{
	internal enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	internal enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	internal enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	internal enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	internal class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = Volatile.Read(ref _mask);
			int num4 = num & num3;
			for (Entry entry = _entries[num4]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			Volatile.Write(ref _mask, num);
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	internal enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	internal enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	internal enum FloatParseHandling
	{
		Double,
		Decimal
	}
	internal enum Formatting
	{
		None,
		Indented
	}
	internal interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	internal interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	internal sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	internal static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				if (nullable)
				{
					return Null;
				}
				return "0.0";
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (StringUtils.IndexOf(text, '.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DBNull => Null, 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	internal abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	internal abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	internal class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	internal class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	internal class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	internal sealed class JsonIgnoreAttribute : Attribute
	{
	}
	internal abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			if (type != JsonContainerType.Array)
			{
				return type == JsonContainerType.Constructor;
			}
			return true;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!StringUtils.EndsWith(message, '.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}

		public JsonPropertyAttribute(string propertyName)
		{
			PropertyName = propertyName;
		}
	}
	internal abstract class JsonReader : IDisposable
	{
		protected internal enum State
		{
			Start,
			Complete,
			Property,
			ObjectStart,
			Object,
			ArrayStart,
			Array,
			Closed,
			PostValue,
			ConstructorStart,
			Constructor,
			Error,
			Finished
		}

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

		public virtual char QuoteChar
		{
			get
			{
				return _quoteChar;
			}
			protected internal set
			{
				_quoteChar = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling;
			}
			set
			{
				if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling;
			}
			set
			{
				if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateParseHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling;
			}
			set
			{
				if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_floatParseHandling = value;
			}
		}

		public string? DateFormatString
		{
			get
			{
				return _dateFormatString;
			}
			set
			{
				_dateFormatString = value;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
			}
		}

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

		public virtual Type? ValueType => _value?.GetType();

		public virtual int Depth
		{
			get
			{
				int num = _stack?.Count ?? 0;
				if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
				{
					return num;
				}
				return num + 1;
			}
		}

		public virtual string Path
		{
			get
			{
				if (_currentPosition.Type == JsonContainerType.None)
				{
					return string.Empty;
				}
				JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null);
				return JsonPosition.BuildPath(_stack, currentPosition);
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? CultureInfo.InvariantCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
		}

		public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TokenType == JsonToken.PropertyName)
			{
				await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth)
				{
				}
			}
		}

		internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
		{
			if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
			{
				throw CreateUnexpectedEndException();
			}
		}

		public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
		}

		public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes());
		}

		internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
		{
			List<byte> buffer = new List<byte>();
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(buffer));
			byte[] array = buffer.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
		}

		public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
		}

		public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
		}

		public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Task.FromResult(ReadAsDouble());
		}

		public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
		}

		public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString());
		}

		internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
		{
			bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (flag)
			{
				flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			return flag;
		}

		internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType = TokenType;
			if (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				return MoveToContentFromNonContentAsync(cancellationToken);
			}
			return AsyncUtils.True;
		}

		private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType;
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					return false;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment);
			return true;
		}

		internal JsonPosition GetPosition(int depth)
		{
			if (_stack != null && depth < _stack.Count)
			{
				return _stack[depth];
			}
			return _currentPosition;
		}

		protected JsonReader()
		{
			_currentState = State.Start;
			_dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
			_dateParseHandling = DateParseHandling.DateTime;
			_floatParseHandling = FloatParseHandling.Double;
			_maxDepth = 64;
			CloseInput = true;
		}

		private void Push(JsonContainerType value)
		{
			UpdateScopeWithFinishedValue();
			if (_currentPosition.Type == JsonContainerType.None)
			{
				_currentPosition = new JsonPosition(value);
				return;
			}
			if (_stack == null)
			{
				_stack = new List<JsonPosition>();
			}
			_stack.Add(_currentPosition);
			_currentPosition = new JsonPosition(value);
			if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth)
			{
				return;
			}
			_hasExceededMaxDepth = true;
			throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
		}

		private JsonContainerType Pop()
		{
			JsonPosition currentPosition;
			if (_stack != null && _stack.Count > 0)
			{
				currentPosition = _currentPosition;
				_currentPosition = _stack[_stack.Count - 1];
				_stack.RemoveAt(_stack.Count - 1);
			}
			else
			{
				currentPosition = _currentPosition;
				_currentPosition = default(JsonPosition);
			}
			if (_maxDepth.HasValue && Depth <= _maxDepth)
			{
				_hasExceededMaxDepth = false;
			}
			return currentPosition.Type;
		}

		private JsonContainerType Peek()
		{
			return _currentPosition.Type;
		}

		public abstract bool Read();

		public virtual int? ReadAsInt32()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is int)
				{
					return (int)value;
				}
				int num;
				if (value is BigInteger bigInteger)
				{
					num = (int)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToInt32(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Integer, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadInt32String(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal int? ReadInt32String(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (int.TryParse(s, NumberStyles.Integer, Culture, out var result))
			{
				SetToken(JsonToken.Integer, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual string? ReadAsString()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.String:
				return (string)Value;
			default:
				if (JsonTokenUtils.IsPrimitiveToken(contentToken))
				{
					object value = Value;
					if (value != null)
					{
						string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture));
						SetToken(JsonToken.String, text, updateIndex: false);
						return text;
					}
				}
				throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		public virtual byte[]? ReadAsBytes()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.StartObject:
			{
				ReadIntoWrappedTypeObject();
				byte[] array2 = ReadAsBytes();
				ReaderReadAndAssert();
				if (TokenType != JsonToken.EndObject)
				{
					throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
				}
				SetToken(JsonToken.Bytes, array2, updateIndex: false);
				return array2;
			}
			case JsonToken.String:
			{
				string text = (string)Value;
				Guid g;
				byte[] array3 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, array3, updateIndex: false);
				return array3;
			}
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Bytes:
				if (Value is Guid guid)
				{
					byte[] array = guid.ToByteArray();
					SetToken(JsonToken.Bytes, array, updateIndex: false);
					return array;
				}
				return (byte[])Value;
			case JsonToken.StartArray:
				return ReadArrayIntoByteArray();
			default:
				throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal byte[] ReadArrayIntoByteArray()
		{
			List<byte> list = new List<byte>();
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(list));
			byte[] array = list.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
		{
			switch (TokenType)
			{
			case JsonToken.None:
				throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
			case JsonToken.Integer:
				buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
				return false;
			case JsonToken.EndArray:
				return true;
			case JsonToken.Comment:
				return false;
			default:
				throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		public virtual double? ReadAsDouble()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is double)
				{
					return (double)value;
				}
				double num = ((!(value is BigInteger bigInteger)) ? Convert.ToDouble(value, CultureInfo.InvariantCulture) : ((double)bigInteger));
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDoubleString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal double? ReadDoubleString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual bool? ReadAsBoolean()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				bool flag = ((!(Value is BigInteger bigInteger)) ? Convert.ToBoolean(Value, CultureInfo.InvariantCulture) : (bigInteger != 0L));
				SetToken(JsonToken.Boolean, flag, updateIndex: false);
				return flag;
			}
			case JsonToken.String:
				return ReadBooleanString((string)Value);
			case JsonToken.Boolean:
				return (bool)Value;
			default:
				throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal bool? ReadBooleanString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (bool.TryParse(s, out var result))
			{
				SetToken(JsonToken.Boolean, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual decimal? ReadAsDecimal()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is decimal)
				{
					return (decimal)value;
				}
				decimal num;
				if (value is BigInteger bigInteger)
				{
					num = (decimal)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDecimalString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal decimal? ReadDecimalString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success)
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTime? ReadAsDateTime()
		{
			switch (GetContentToken())
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTimeOffset dateTimeOffset)
				{
					SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false);
				}
				return (DateTime)Value;
			case JsonToken.String:
				return ReadDateTimeString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		internal DateTime? ReadDateTimeString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTimeOffset? ReadAsDateTimeOffset()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTime dateTime)
				{
					SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false);
				}
				return (DateTimeOffset)Value;
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadDateTimeOffsetString(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		internal void ReaderReadAndAssert()
		{
			if (!Read())
			{
				throw CreateUnexpectedEndException();
			}
		}

		internal JsonReaderException CreateUnexpectedEndException()
		{
			return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
		}

		internal void ReadIntoWrappedTypeObject()
		{
			ReaderReadAndAssert();
			if (Value != null && Value.ToString() == "$type")
			{
				ReaderReadAndAssert();
				if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
				{
					ReaderReadAndAssert();
					if (Value.ToString() == "$value")
					{
						return;
					}
				}
			}
			throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
		}

		public void Skip()
		{
			if (TokenType == JsonToken.PropertyName)
			{
				Read();
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (Read() && depth < Depth)
				{
				}
			}
		}

		protected void SetToken(JsonToken newToken)
		{
			SetToken(newToken, null, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value)
		{
			SetToken(newToken, value, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
		{
			_tokenType = newToken;
			_value = value;
			switch (newToken)
			{
			case JsonToken.StartObject:
				_currentState = State.ObjectStart;
				Push(JsonContainerType.Object);
				break;
			case JsonToken.StartArray:
				_currentState = State.ArrayStart;
				Push(JsonContainerType.Array);
				break;
			case JsonToken.StartConstructor:
				_currentState = State.ConstructorStart;
				Push(JsonContainerType.Constructor);
				break;
			case JsonToken.EndObject:
				ValidateEnd(JsonToken.EndObject);
				break;
			case JsonToken.EndArray:
				ValidateEnd(JsonToken.EndArray);
				break;
			case JsonToken.EndConstructor:
				ValidateEnd(JsonToken.EndConstructor);
				break;
			case JsonToken.PropertyName:
				_currentState = State.Property;
				_currentPosition.PropertyName = (string)value;
				break;
			case JsonToken.Raw:
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Null:
			case JsonToken.Undefined:
			case JsonToken.Date:
			case JsonToken.Bytes:
				SetPostValueState(updateIndex);
				break;
			case JsonToken.Comment:
				break;
			}
		}

		internal void SetPostValueState(bool updateIndex)
		{
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
			if (updateIndex)
			{
				UpdateScopeWithFinishedValue();
			}
		}

		private void UpdateScopeWithFinishedValue()
		{
			if (_currentPosition.HasIndex)
			{
				_currentPosition.Position++;
			}
		}

		private void ValidateEnd(JsonToken endToken)
		{
			JsonContainerType jsonContainerType = Pop();
			if (GetTypeForCloseToken(endToken) != jsonContainerType)
			{
				throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType));
			}
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
		}

		protected void SetStateBasedOnCurrent()
		{
			JsonContainerType jsonContainerType = Peek();
			switch (jsonContainerType)
			{
			case JsonContainerType.Object:
				_currentState = State.Object;
				break;
			case JsonContainerType.Array:
				_currentState = State.Array;
				break;
			case JsonContainerType.Constructor:
				_currentState = State.Constructor;
				break;
			case JsonContainerType.None:
				SetFinished();
				break;
			default:
				throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType));
			}
		}

		private void SetFinished()
		{
			_currentState = ((!SupportMultipleContent) ? State.Finished : State.Start);
		}

		private JsonContainerType GetTypeForCloseToken(JsonToken token)
		{
			return token switch
			{
				JsonToken.EndObject => JsonContainerType.Object, 
				JsonToken.EndArray => JsonContainerType.Array, 
				JsonToken.EndConstructor => JsonContainerType.Constructor, 
				_ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), 
			};
		}

		void IDisposable.Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_currentState != State.Closed && disposing)
			{
				Close();
			}
		}

		public virtual void Close()
		{
			_currentState = State.Closed;
			_tokenType = JsonToken.None;
			_value = null;
		}

		internal void ReadAndAssert()
		{
			if (!Read())
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
		{
			if (!ReadForType(contract, hasConverter))
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal bool ReadForType(JsonContract? contract, bool hasConverter)
		{
			if (hasConverter)
			{
				return Read();
			}
			switch (contract?.InternalReadType ?? ReadType.Read)
			{
			case ReadType.Read:
				return ReadAndMoveToContent();
			case ReadType.ReadAsInt32:
				ReadAsInt32();
				break;
			case ReadType.ReadAsInt64:
			{
				bool result = ReadAndMoveToContent();
				if (TokenType == JsonToken.Undefined)
				{
					throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
				}
				return result;
			}
			case ReadType.ReadAsDecimal:
				ReadAsDecimal();
				break;
			case ReadType.ReadAsDouble:
				ReadAsDouble();
				break;
			case ReadType.ReadAsBytes:
				ReadAsBytes();
				break;
			case ReadType.ReadAsBoolean:
				ReadAsBoolean();
				break;
			case ReadType.ReadAsString:
				ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				ReadAsDateTime();
				break;
			case ReadType.ReadAsDateTimeOffset:
				ReadAsDateTimeOffset();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			return TokenType != JsonToken.None;
		}

		internal bool ReadAndMoveToContent()
		{
			if (Read())
			{
				return MoveToContent();
			}
			return false;
		}

		internal bool MoveToContent()
		{
			JsonToken tokenType = TokenType;
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				if (!Read())
				{
					return false;
				}
				tokenType = TokenType;
			}
			return true;
		}

		private JsonToken GetContentToken()
		{
			JsonToken tokenType;
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
					return JsonToken.None;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.Comment);
			return tokenType;
		}
	}
	[Serializable]
	internal class JsonReaderException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

		public JsonReaderException(string message)
			: base(message)
		{
		}

		public JsonReaderException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonReaderException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonReaderException(message, path, lineNumber, linePosition, ex);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	internal sealed class JsonRequiredAttribute : Attribute
	{
	}
	[Serializable]
	internal class JsonSerializationException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

		public JsonSerializationException(string message)
			: base(message)
		{
		}

		public JsonSerializationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonSerializationException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonSerializationException Create