Decompiled source of DiscordConnector v2.3.2
plugins/DiscordConnector.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Timers; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DiscordConnector.Config; using DiscordConnector.Leaderboards; using DiscordConnector.Records; using HarmonyLib; using LiteDB; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Valheim Discord Connector (games.nwest.valheim.discordconnector)")] [assembly: AssemblyProduct("Valheim Discord Connector")] [assembly: AssemblyCopyright("© 2024 Nicholas Westerhausen Repository at github: nwesterhausen/valheim-discordconnector")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.3.2.0")] [module: UnverifiableCode] [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.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; } } [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 DiscordConnector { internal class ConfigWatcher { private static Regex watchedConfigFilesRegex = new Regex("discordconnector?[\\w\\-]*\\.cfg$"); private static Regex configExtensionMatcherRegex = new Regex("discordconnector-(\\w+)\\.cfg$"); private static DateTime lastChangeDetected; private static int DEBOUNCE_SECONDS = 10; private static Dictionary<string, string> _fileHashDictionary; public ConfigWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(); fileSystemWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite; fileSystemWatcher.Changed += OnChanged; fileSystemWatcher.Error += OnError; fileSystemWatcher.Path = Plugin.StaticConfig.configPath; fileSystemWatcher.Filter = "discordconnector*.cfg"; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.EnableRaisingEvents = true; Plugin.StaticLogger.LogInfo("File watcher loaded and watching for changes to configs."); _fileHashDictionary = new Dictionary<string, string>(); PopulateHashDictionary(); lastChangeDetected = DateTime.Now; } private void PopulateHashDictionary() { Task.Run(delegate { foreach (string item in from file in Directory.EnumerateFiles(Plugin.StaticConfig.configPath) where watchedConfigFilesRegex.IsMatch(file) select file) { string key = ConfigExtensionFromFilename(item); _fileHashDictionary.Add(key, Hashing.GetMD5Checksum(item)); } Plugin.StaticLogger.LogDebug("Initialization of file hash dictionary completed."); Plugin.StaticLogger.LogDebug(string.Join(Environment.NewLine, _fileHashDictionary)); }); } private static string ConfigExtensionFromFilename(string filename) { string result = "main"; Match match = configExtensionMatcherRegex.Match(filename); if (match.Success && match.Groups.Count > 1) { result = match.Groups[1].Value; } return result; } private static void OnChanged(object sender, FileSystemEventArgs e) { if (e.ChangeType == WatcherChangeTypes.Changed) { string text = ConfigExtensionFromFilename(e.FullPath); Plugin.StaticLogger.LogDebug("Detected change of " + text + " config file"); string mD5Checksum = Hashing.GetMD5Checksum(e.FullPath); if (!_fileHashDictionary.ContainsKey(text)) { Plugin.StaticLogger.LogWarning("Unexpectedly encountered unhashed config file!"); Plugin.StaticLogger.LogDebug("Added " + text + " config to config hash dictionary."); _fileHashDictionary.Add(text, mD5Checksum); } else if (string.Equals(_fileHashDictionary[text], mD5Checksum)) { Plugin.StaticLogger.LogDebug("Changes to file were determined to be inconsequential."); } else if (lastChangeDetected.AddSeconds(DEBOUNCE_SECONDS) > DateTime.Now) { Plugin.StaticLogger.LogDebug("Skipping config reload, within DEBOUNCE timing."); } else { Plugin.StaticConfig.ReloadConfig(text); lastChangeDetected = DateTime.Now; } } } private static void OnError(object sender, ErrorEventArgs e) { Plugin.StaticLogger.LogError(e.GetException().ToString()); } } internal class PluginConfig { private MainConfig mainConfig; private MessagesConfig messagesConfig; private TogglesConfig togglesConfig; private VariableConfig variableConfig; private LeaderBoardConfig leaderBoardConfig; private ExtraWebhookConfig extraWebhookConfig; public readonly string configPath; private const string ConfigJsonFilename = "config-dump.json"; internal static string[] ConfigExtensions = new string[6] { "messages", "variables", "leaderBoard", "toggles", "extraWebhooks", "main" }; public bool LaunchMessageEnabled => togglesConfig.LaunchMessageEnabled; public bool LoadedMessageEnabled => togglesConfig.LoadedMessageEnabled; public bool StopMessageEnabled => togglesConfig.StopMessageEnabled; public bool ShutdownMessageEnabled => togglesConfig.ShutdownMessageEnabled; public bool WorldSaveMessageEnabled => togglesConfig.WorldSaveMessageEnabled; public bool ChatShoutEnabled => togglesConfig.ChatShoutEnabled; public bool ChatPingEnabled => togglesConfig.ChatPingEnabled; public bool PlayerJoinMessageEnabled => togglesConfig.PlayerJoinMessageEnabled; public bool PlayerDeathMessageEnabled => togglesConfig.PlayerDeathMessageEnabled; public bool PlayerLeaveMessageEnabled => togglesConfig.PlayerLeaveMessageEnabled; public bool EventStartMessageEnabled => togglesConfig.EventStartMessageEnabled; public bool EventStopMessageEnabled => togglesConfig.EventStopMessageEnabled; public bool EventPausedMessageEnabled => togglesConfig.EventPausedMessageEnabled; public bool EventResumedMessageEnabled => togglesConfig.EventResumedMessageEnabled; public bool ChatShoutAllCaps => togglesConfig.ChatShoutAllCaps; public bool NewDayNumberEnabled => togglesConfig.NewDayNumberEnabled; public bool StatsDeathEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsDeathEnabled; } return false; } } public bool StatsJoinEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsJoinEnabled; } return false; } } public bool StatsLeaveEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsLeaveEnabled; } return false; } } public bool StatsPingEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsPingEnabled; } return false; } } public bool StatsShoutEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsShoutEnabled; } return false; } } public bool ChatPingPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.ChatPingPosEnabled; } return false; } } public bool ChatShoutPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.ChatShoutPosEnabled; } return false; } } public bool PlayerJoinPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerJoinPosEnabled; } return false; } } public bool PlayerDeathPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerDeathPosEnabled; } return false; } } public bool PlayerLeavePosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerLeavePosEnabled; } return false; } } public bool EventStartPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventStartPosEnabled; } return false; } } public bool EventStopPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventStopPosEnabled; } return false; } } public bool EventPausedPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventPausedPosEnabled; } return false; } } public bool EventResumedPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventResumedPosEnabled; } return false; } } public string DefaultWebhookUsernameOverride => mainConfig.DefaultWebhookUsernameOverride; public WebhookEntry PrimaryWebhook => mainConfig.PrimaryWebhook; public WebhookEntry SecondaryWebhook => mainConfig.SecondaryWebhook; public bool CollectStatsEnabled => mainConfig.CollectStatsEnabled; public bool DiscordEmbedsEnabled => mainConfig.DiscordEmbedsEnabled; public bool SendPositionsEnabled => mainConfig.SendPositionsEnabled; public bool AnnouncePlayerFirsts => mainConfig.AnnouncePlayerFirsts; public MainConfig.RetrievalDiscernmentMethods RecordRetrievalDiscernmentMethod => mainConfig.RecordRetrievalDiscernmentMethod; public List<string> MutedPlayers => mainConfig.MutedPlayers; public Regex MutedPlayersRegex => mainConfig.MutedPlayersRegex; public bool AllowNonPlayerShoutLogging => mainConfig.AllowNonPlayerShoutLogging; public bool AllowMentionsHereEveryone => mainConfig.AllowMentionsHereEveryone; public bool AllowMentionsAnyRole => mainConfig.AllowMentionsAnyRole; public bool AllowMentionsAnyUser => mainConfig.AllowMentionsAnyUser; public List<string> AllowedRoleMentions => mainConfig.AllowedRoleMentions; public List<string> AllowedUserMentions => mainConfig.AllowedUserMentions; public string LaunchMessage => messagesConfig.LaunchMessage; public string LoadedMessage => messagesConfig.LoadedMessage; public string StopMessage => messagesConfig.StopMessage; public string ShutdownMessage => messagesConfig.ShutdownMessage; public string SaveMessage => messagesConfig.SaveMessage; public string NewDayMessage => messagesConfig.NewDayMessage; public string JoinMessage => messagesConfig.JoinMessage; public string LeaveMessage => messagesConfig.LeaveMessage; public string DeathMessage => messagesConfig.DeathMessage; public string PingMessage => messagesConfig.PingMessage; public string ShoutMessage => messagesConfig.ShoutMessage; public string PlayerFirstDeathMessage => messagesConfig.PlayerFirstDeathMessage; public string PlayerFirstJoinMessage => messagesConfig.PlayerFirstJoinMessage; public string PlayerFirstLeaveMessage => messagesConfig.PlayerFirstLeaveMessage; public string PlayerFirstPingMessage => messagesConfig.PlayerFirstPingMessage; public string PlayerFirstShoutMessage => messagesConfig.PlayerFirstShoutMessage; public bool AnnouncePlayerFirstDeathEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstDeathEnabled; } return false; } } public bool AnnouncePlayerFirstJoinEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstJoinEnabled; } return false; } } public bool AnnouncePlayerFirstLeaveEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstLeaveEnabled; } return false; } } public bool AnnouncePlayerFirstPingEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstPingEnabled; } return false; } } public bool AnnouncePlayerFirstShoutEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstShoutEnabled; } return false; } } public string EventStartMessage => messagesConfig.EventStartMessage; public string EventStopMessage => messagesConfig.EventStopMessage; public string EventPausedMessage => messagesConfig.EventPausedMessage; public string EventResumedMessage => messagesConfig.EventResumedMessage; public string UserVariable => variableConfig.UserVariable; public string UserVariable1 => variableConfig.UserVariable1; public string UserVariable2 => variableConfig.UserVariable2; public string UserVariable3 => variableConfig.UserVariable3; public string UserVariable4 => variableConfig.UserVariable4; public string UserVariable5 => variableConfig.UserVariable5; public string UserVariable6 => variableConfig.UserVariable6; public string UserVariable7 => variableConfig.UserVariable7; public string UserVariable8 => variableConfig.UserVariable8; public string UserVariable9 => variableConfig.UserVariable9; public string PosVarFormat => variableConfig.PosVarFormat; public string AppendedPosFormat => variableConfig.AppendedPosFormat; public bool DebugEveryPlayerPosCheck => togglesConfig.DebugEveryPlayerPosCheck; public bool DebugEveryEventCheck => togglesConfig.DebugEveryEventCheck; public bool DebugEveryEventChange => togglesConfig.DebugEveryEventChange; public bool DebugHttpRequestResponse => togglesConfig.DebugHttpRequestResponse; public bool DebugDatabaseMethods => togglesConfig.DebugDatabaseMethods; public string LeaderBoardTopPlayerHeading => messagesConfig.LeaderBoardTopPlayerHeading; public string LeaderBoardBottomPlayersHeading => messagesConfig.LeaderBoardBottomPlayersHeading; public string LeaderBoardHighestHeading => messagesConfig.LeaderBoardHighestHeading; public string LeaderBoardLowestHeading => messagesConfig.LeaderBoardLowestHeading; public LeaderBoardConfigReference[] LeaderBoards => leaderBoardConfig.LeaderBoards; public ActivePlayersAnnouncementConfigValues ActivePlayersAnnouncement => leaderBoardConfig.ActivePlayersAnnouncement; public List<WebhookEntry> ExtraWebhooks => extraWebhookConfig.GetWebhookEntries(); internal void migrateConfigIfNeeded() { if (!Directory.Exists(configPath)) { Directory.CreateDirectory(configPath); } string[] configExtensions = ConfigExtensions; foreach (string text in configExtensions) { string text2 = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector-" + text + ".cfg"); string text3 = Path.Combine(configPath, "discordconnector-" + text + ".cfg"); if (text.Equals("main")) { text2 = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector.cfg"); text3 = Path.Combine(configPath, "discordconnector.cfg"); } if (File.Exists(text2)) { if (File.Exists(text3)) { Plugin.StaticLogger.LogWarning("Expected to be moving " + text + " config from pre-2.1.0 location to new config location, but already exists!"); } else { File.Move(text2, text3); } } } } public PluginConfig(ConfigFile config) { //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown configPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector"); migrateConfigIfNeeded(); string path = "discordconnector.cfg"; string path2 = "discordconnector-" + MessagesConfig.ConfigExtension + ".cfg"; string path3 = "discordconnector-" + TogglesConfig.ConfigExtension + ".cfg"; string path4 = "discordconnector-" + VariableConfig.ConfigExtension + ".cfg"; string path5 = "discordconnector-" + LeaderBoardConfig.ConfigExtension + ".cfg"; string path6 = "discordconnector-" + ExtraWebhookConfig.ConfigExtension + ".cfg"; string text = Path.Combine(configPath, path); string text2 = Path.Combine(configPath, path2); string text3 = Path.Combine(configPath, path3); string text4 = Path.Combine(configPath, path4); string text5 = Path.Combine(configPath, path5); string text6 = Path.Combine(configPath, path6); Plugin.StaticLogger.LogDebug("Main config: " + text); Plugin.StaticLogger.LogDebug("Messages config: " + text2); Plugin.StaticLogger.LogDebug("Toggles config: " + text3); Plugin.StaticLogger.LogDebug("Variable config: " + text4); Plugin.StaticLogger.LogDebug("Leader board config: " + text5); Plugin.StaticLogger.LogDebug("Extra Webhook config: " + text6); mainConfig = new MainConfig(new ConfigFile(text, true)); messagesConfig = new MessagesConfig(new ConfigFile(text2, true)); togglesConfig = new TogglesConfig(new ConfigFile(text3, true)); variableConfig = new VariableConfig(new ConfigFile(text4, true)); leaderBoardConfig = new LeaderBoardConfig(new ConfigFile(text5, true)); extraWebhookConfig = new ExtraWebhookConfig(new ConfigFile(text6, true)); Plugin.StaticLogger.LogDebug("Configuration Loaded"); Plugin.StaticLogger.LogDebug("Muted Players Regex pattern ('a^' is default for no matches): " + mainConfig.MutedPlayersRegex.ToString()); DumpConfigAsJson(); } public void ReloadConfig() { mainConfig.ReloadConfig(); messagesConfig.ReloadConfig(); togglesConfig.ReloadConfig(); variableConfig.ReloadConfig(); leaderBoardConfig.ReloadConfig(); extraWebhookConfig.ReloadConfig(); } public void ReloadConfig(string configExt) { switch (configExt) { case "main": mainConfig.ReloadConfig(); break; case "messages": messagesConfig.ReloadConfig(); break; case "toggles": togglesConfig.ReloadConfig(); break; case "variables": variableConfig.ReloadConfig(); break; case "leaderBoard": leaderBoardConfig.ReloadConfig(); break; case "extraWebhooks": extraWebhookConfig.ReloadConfig(); break; } } public void DumpConfigAsJson() { string jsonString = "{"; jsonString = jsonString + "\"Config.Main\":" + mainConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Messages\":" + messagesConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Toggles\":" + togglesConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Variables\":" + variableConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.LeaderBoard\":" + leaderBoardConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.ExtraWebhooks\":" + extraWebhookConfig.ConfigAsJson(); jsonString += "}"; Task.Run(delegate { File.WriteAllText(Path.Combine(configPath, "config-dump.json"), jsonString); Plugin.StaticLogger.LogDebug("Dumped configuration files to config-dump.json"); }); } } internal class DiscordApi { public static void SendMessage(Webhook.Event ev, string message, Vector3 pos) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (Plugin.StaticConfig.DiscordEmbedsEnabled) { SendMessageWithFields(ev, message, new List<Tuple<string, string>>(1) { Tuple.Create("Coordinates", MessageTransformer.FormatVector3AsPos(pos)) }); } else { SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos)); } } public static void SendMessage(Webhook.Event ev, string message) { DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook(); discordExecuteWebhook.content = message; discordExecuteWebhook.SendFor(ev); } public static void SendMessageWithFields(Webhook.Event ev, string content = null, List<Tuple<string, string>> fields = null) { if (string.IsNullOrEmpty(content) && fields == null) { content = "Uh-oh! An unexpectedly empty message was sent!"; } DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook { content = content }; if (fields != null) { discordExecuteWebhook.embeds = new List<DiscordEmbed>(); List<DiscordField> list = new List<DiscordField>(); new List<string>(); foreach (Tuple<string, string> field in fields) { list.Add(new DiscordField { name = field.Item1, value = field.Item2 }); } discordExecuteWebhook.embeds.Add(new DiscordEmbed { fields = list }); } discordExecuteWebhook.SendFor(ev); } public static void SendSerializedJson(Webhook.Event ev, string serializedJson) { Plugin.StaticLogger.LogDebug($"Finding webhooks for event: (event: {ev})"); if (ev == Webhook.Event.Other) { Plugin.StaticLogger.LogInfo("Dispatching webhook for 3rd party plugin (configured as 'Other' in WebHook config)"); } if ((string.IsNullOrEmpty(Plugin.StaticConfig.PrimaryWebhook.Url) && string.IsNullOrEmpty(Plugin.StaticConfig.SecondaryWebhook.Url)) || string.IsNullOrEmpty(serializedJson)) { return; } byte[] bytes = Encoding.UTF8.GetBytes(serializedJson); if (Plugin.StaticConfig.PrimaryWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook"); DispatchRequest(Plugin.StaticConfig.PrimaryWebhook, bytes); } if (Plugin.StaticConfig.SecondaryWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook"); DispatchRequest(Plugin.StaticConfig.SecondaryWebhook, bytes); } foreach (WebhookEntry extraWebhook in Plugin.StaticConfig.ExtraWebhooks) { if (extraWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to Extra Webhook: {extraWebhook.Url}"); DispatchRequest(extraWebhook, bytes); } } } public static void SendSerializedJson(WebhookEntry webhook, string serializedJson) { Plugin.StaticLogger.LogDebug("Trying webhook with payload: " + serializedJson); if (!string.IsNullOrEmpty(webhook.Url) && !string.IsNullOrEmpty(serializedJson)) { byte[] bytes = Encoding.UTF8.GetBytes(serializedJson); DispatchRequest(webhook, bytes); } } private static void DispatchRequest(WebhookEntry webhook, byte[] byteArray) { if (string.IsNullOrEmpty(webhook.Url)) { Plugin.StaticLogger.LogDebug("Dispatch attempted with empty webhook - ignoring"); return; } string requestId = GuidHelper.GenerateShortHexGuid(); Plugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: sending {byteArray.Length} bytes to Discord"); WebRequest request = WebRequest.Create(webhook.Url); request.Method = "POST"; request.ContentType = "application/json"; request.ContentLength = byteArray.Length; Task.Run(delegate { try { using (Stream stream = request.GetRequestStream()) { stream.Write(byteArray, 0, byteArray.Length); } bool flag = true; WebResponse webResponse = null; try { webResponse = request.GetResponse(); if (Plugin.StaticConfig.DebugHttpRequestResponse) { if (webResponse is HttpWebResponse httpWebResponse) { if (httpWebResponse.StatusCode == HttpStatusCode.NoContent) { flag = false; } Plugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: Response Code: {httpWebResponse.StatusCode}"); } else { Plugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response was not an HttpWebResponse"); } } } catch (WebException arg) { Plugin.StaticLogger.LogError($"DispatchRequest.{requestId}: Error getting web response: {arg}"); return; } if (flag) { using Stream stream2 = webResponse.GetResponseStream(); if (stream2 == null) { Plugin.StaticLogger.LogError("DispatchRequest." + requestId + ": Response stream is null"); return; } using StreamReader streamReader = new StreamReader(stream2); string text = streamReader.ReadToEnd(); if (Plugin.StaticConfig.DebugHttpRequestResponse) { if (text.Length > 0) { Plugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response from server: " + text); } else { Plugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Empty response from server (normal)"); } } } webResponse.Close(); } catch (Exception arg2) { Plugin.StaticLogger.LogWarning($"Error dispatching webhook: {arg2}"); } }).ConfigureAwait(continueOnCapturedContext: false); } public static void SendMessage(string message, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) SendMessage(Webhook.Event.Other, message, pos); } public static void SendMessage(string message) { SendMessage(Webhook.Event.Other, message); } public static void SendMessageWithFields(string content = null, List<Tuple<string, string>> fields = null) { SendMessageWithFields(Webhook.Event.Other, content, fields); } private static void SendSerializedJson(string serializedJson) { SendSerializedJson(Webhook.Event.Other, serializedJson); } } internal class DiscordExecuteWebhook { public string? content { get; set; } public string? username { get; set; } public string? avatar_url { get; set; } public List<DiscordEmbed>? embeds { get; set; } public AllowedMentions? allowed_mentions { get; set; } public DiscordExecuteWebhook() { allowed_mentions = new AllowedMentions(); ResetOverrides(); } public void SetUsername(string username) { this.username = username; } public void SetAvatarUrl(string avatar_url) { this.avatar_url = avatar_url; } public bool IsValid() { if (string.IsNullOrEmpty(content)) { return embeds != null; } return true; } public void ResetOverrides() { username = null; avatar_url = null; if (!string.IsNullOrEmpty(Plugin.StaticConfig.DefaultWebhookUsernameOverride)) { SetUsername(Plugin.StaticConfig.DefaultWebhookUsernameOverride); } } public void SendFor(Webhook.Event ev) { if (!IsValid()) { Plugin.StaticLogger.LogWarning($"Attempted to send an invalid DiscordExecuteWebhook object:\n{this}"); return; } try { if (Plugin.StaticConfig.PrimaryWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook"); WebhookEntry primaryWebhook = Plugin.StaticConfig.PrimaryWebhook; ResetOverrides(); if (primaryWebhook.HasUsernameOverride()) { SetUsername(primaryWebhook.UsernameOverride); } if (primaryWebhook.HasAvatarOverride()) { SetAvatarUrl(primaryWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(primaryWebhook, JsonConvert.SerializeObject((object)this)); } if (Plugin.StaticConfig.SecondaryWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook"); WebhookEntry secondaryWebhook = Plugin.StaticConfig.SecondaryWebhook; ResetOverrides(); if (secondaryWebhook.HasUsernameOverride()) { SetUsername(secondaryWebhook.UsernameOverride); } if (secondaryWebhook.HasAvatarOverride()) { SetAvatarUrl(secondaryWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(secondaryWebhook, JsonConvert.SerializeObject((object)this)); } if (Plugin.StaticConfig.ExtraWebhooks == null) { return; } foreach (WebhookEntry extraWebhook in Plugin.StaticConfig.ExtraWebhooks) { if (extraWebhook.HasEvent(ev)) { Plugin.StaticLogger.LogDebug($"Sending {ev} message to an Extra Webhook"); ResetOverrides(); if (extraWebhook.HasUsernameOverride()) { SetUsername(extraWebhook.UsernameOverride); } if (extraWebhook.HasAvatarOverride()) { SetAvatarUrl(extraWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(extraWebhook, JsonConvert.SerializeObject((object)this)); } } } catch (Exception arg) { Plugin.StaticLogger.LogWarning($"Error serializing payload: {arg}"); } } } internal class AllowedMentions { public List<string> parse { get; set; } public List<string> roles { get; set; } public List<string> users { get; set; } public bool replied_user { get; set; } public AllowedMentions() { parse = new List<string>(); roles = new List<string>(); users = new List<string>(); replied_user = false; if (Plugin.StaticConfig.AllowMentionsHereEveryone) { AllowEveryone(); } if (Plugin.StaticConfig.AllowMentionsAnyRole) { AllowAnyRoles(); } if (Plugin.StaticConfig.AllowMentionsAnyUser) { AllowAnyUsers(); } if (Plugin.StaticConfig.AllowedRoleMentions.Count > 0) { AllowRoles(Plugin.StaticConfig.AllowedRoleMentions); } if (Plugin.StaticConfig.AllowedUserMentions.Count > 0) { AllowUsers(Plugin.StaticConfig.AllowedUserMentions); } } public void AllowEveryone() { if (!parse.Contains("everyone")) { parse.Add("everyone"); } } public void AllowHere() { if (!parse.Contains("everyone")) { parse.Add("everyone"); } } public void AllowRole(string role_id) { if (!roles.Contains(role_id)) { roles.Add(role_id); } } public void AllowRoles(List<string> role_ids) { foreach (string role_id in role_ids) { AllowRole(role_id); } } public void DisallowRole(string role_id) { if (roles.Contains(role_id)) { roles.Remove(role_id); } } public void AllowUser(string user_id) { if (!users.Contains(user_id)) { users.Add(user_id); } } public void AllowUsers(List<string> user_ids) { foreach (string user_id in user_ids) { AllowUser(user_id); } } public void DisallowUser(string user_id) { if (users.Contains(user_id)) { users.Remove(user_id); } } public void AllowAnyRoles() { if (!parse.Contains("roles")) { parse.Add("roles"); } } public void AllowAnyUsers() { if (!parse.Contains("users")) { parse.Add("users"); } } public void DisallowAnyRoles() { if (parse.Contains("roles")) { parse.Remove("roles"); } } public void DisallowAnyUsers() { if (parse.Contains("users")) { parse.Remove("users"); } } } internal class DiscordEmbed { public string? title { get; set; } public string? description { get; set; } public List<DiscordField>? fields { get; set; } } internal class DiscordField { public string name { get; set; } public string value { get; set; } public bool? inline { get; set; } } internal class EventWatcher { private static class Status { public static bool HaveActiveEvent => RandEventSystem.HaveActiveEvent(); public static RandomEvent Event { get { if (!HaveActiveEvent) { return null; } return RandEventSystem.instance.GetCurrentRandomEvent(); } } public static string Name { get { if (!HaveActiveEvent) { return ""; } return Event.m_name; } } public static float Duration { get { if (!HaveActiveEvent) { return 0f; } return Event.m_duration; } } public static float Elapsed { get { if (!HaveActiveEvent) { return 0f; } return Event.m_time; } } public static bool IsRunning { get { if (!HaveActiveEvent) { return false; } return RandEventSystem.instance.IsAnyPlayerInEventArea(Event); } } public static Vector3 Pos { get { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!HaveActiveEvent) { return new Vector3(0f, 0f, 0f); } return Event.m_pos; } } public static string EndMessage { get { if (!HaveActiveEvent) { return ""; } return Localization.instance.Localize(Event.m_endMessage); } } public static string StartMessage { get { if (!HaveActiveEvent) { return ""; } return Localization.instance.Localize(Event.m_startMessage); } } public static string[] InvolvedPlayersList() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); if (!HaveActiveEvent) { return list.ToArray(); } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { if (!player.m_publicPosition) { if (Plugin.StaticConfig.DebugEveryPlayerPosCheck) { Plugin.StaticLogger.LogDebug("Unable to check location for " + player.m_name + " because their location is not public."); } } else if (RandEventSystem.instance.IsInsideRandomEventArea(Event, player.m_position)) { list.Add(player.m_name); if (Plugin.StaticConfig.DebugEveryPlayerPosCheck) { Plugin.StaticLogger.LogDebug($"{player.m_name} is at {player.m_position}"); } } } return list.ToArray(); } } private bool WasRunning; private bool HadActiveEvent; private float PreviousElapsed; private string PreviousEventStartMessage; private string PreviousEventEndMessage; private Vector3 PreviousEventPos; private Timer randEventTimer; public EventWatcher() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) WasRunning = false; HadActiveEvent = false; PreviousElapsed = 0f; PreviousEventStartMessage = ""; PreviousEventEndMessage = ""; PreviousEventPos = default(Vector3); randEventTimer = new Timer(); randEventTimer.Elapsed += CheckRandomEvent; randEventTimer.Interval = 1000.0; } public void Activate() { randEventTimer.Start(); } public void Dispose() { randEventTimer.Stop(); } public void CheckRandomEvent(object sender, ElapsedEventArgs elapsedEventArgs) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) if (Status.HaveActiveEvent) { string message = $"Currently an event: {Status.HaveActiveEvent}. {Status.StartMessage} | {Status.EndMessage}" + Environment.NewLine + $"Event: {Status.Name} at {Status.Pos}. Status.IsRunning: {Status.IsRunning}. {Status.Elapsed} of {Status.Duration} seconds completed." + Environment.NewLine + $"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Involved Players: " + string.Join(",", Status.InvolvedPlayersList()); if (Plugin.StaticConfig.DebugEveryEventCheck) { Plugin.StaticLogger.LogDebug(message); } if (Status.IsRunning) { if (!HadActiveEvent) { TriggerEventStart(); if (Plugin.StaticConfig.DebugEveryEventChange) { Plugin.StaticLogger.LogDebug(message); } } if (HadActiveEvent && !WasRunning) { TriggerEventResumed(); if (Plugin.StaticConfig.DebugEveryEventChange) { Plugin.StaticLogger.LogDebug(message); } } } else if (!HadActiveEvent || (HadActiveEvent && WasRunning)) { TriggerEventPaused(); if (Plugin.StaticConfig.DebugEveryEventChange) { Plugin.StaticLogger.LogDebug(message); } } if (Status.Pos != Vector3.zero) { PreviousEventStartMessage = Status.StartMessage; PreviousEventEndMessage = Status.EndMessage; PreviousEventPos = Status.Pos; } } else { if (Plugin.StaticConfig.DebugEveryEventCheck) { Plugin.StaticLogger.LogDebug($"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Event check ran, no current events (or world isn't loaded yet)."); } if (HadActiveEvent) { TriggerEventStop(); if (Plugin.StaticConfig.DebugEveryEventChange) { Plugin.StaticLogger.LogDebug("Event stopped!"); } } } HadActiveEvent = Status.HaveActiveEvent; WasRunning = Status.IsRunning; PreviousElapsed = Status.Elapsed; } internal void TriggerEventStart() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (Plugin.StaticConfig.EventStartMessageEnabled) { string text = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage); if (!Plugin.StaticConfig.EventStartPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventStart, text); return; } if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventStart, text, Status.Pos); return; } text = MessageTransformer.FormatEventStartMessage(Plugin.StaticConfig.EventResumedMessage, Status.EndMessage, Status.StartMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventStart, text); } } internal void TriggerEventPaused() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (Plugin.StaticConfig.EventPausedMessageEnabled) { string text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage); if (!Plugin.StaticConfig.EventPausedPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventPaused, text); return; } if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventPaused, text, Status.Pos); return; } text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventPaused, text); } } internal void TriggerEventResumed() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (Plugin.StaticConfig.EventResumedMessageEnabled) { string text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage); if (!Plugin.StaticConfig.EventResumedPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventResumed, text); return; } if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventResumed, text, Status.Pos); return; } text = MessageTransformer.FormatEventMessage(Plugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventResumed, text); } } internal void TriggerEventStop() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (Plugin.StaticConfig.EventStopMessageEnabled) { string text = MessageTransformer.FormatEventEndMessage(Plugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage); if (!Plugin.StaticConfig.EventStopPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventStop, text); return; } if (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventStop, text, PreviousEventPos); return; } text = MessageTransformer.FormatEventEndMessage(Plugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage, PreviousEventPos); DiscordApi.SendMessage(Webhook.Event.EventStop, text); } } } internal static class Handlers { public static HashSet<string> joinedPlayers = new HashSet<string>(); public static void Join(ZNetPeer peer) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { Plugin.StaticLogger.LogDebug("Handler:Join - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerJoin; string text = peer.m_socket.GetHostName() ?? ""; if (!joinedPlayers.Add(text)) { Plugin.StaticLogger.LogDebug(text + " already exists in list of joined players."); if (((ZDOID)(ref peer.m_characterID)).ID != 0) { Death(peer); } return; } Plugin.StaticLogger.LogDebug($"Added player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) to joined player list."); string text2 = ""; if (Plugin.StaticConfig.AnnouncePlayerFirstJoinEnabled && Plugin.StaticDatabase.CountOfRecordsByName("join", peer.m_playerName) == 0) { text2 = Plugin.StaticConfig.PlayerFirstJoinMessage; ev = Webhook.Event.PlayerFirstJoin; } else if (Plugin.StaticConfig.PlayerJoinMessageEnabled) { text2 = Plugin.StaticConfig.JoinMessage; } if (Plugin.StaticConfig.StatsJoinEnabled) { Plugin.StaticDatabase.InsertSimpleStatRecord("join", peer.m_playerName, text, peer.m_refPos); } if (!string.IsNullOrEmpty(text2)) { FinalizeFormattingAndSend(peer, text, text2, Plugin.StaticConfig.PlayerJoinPosEnabled, ev); } } public static void Leave(ZNetPeer peer) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { Plugin.StaticLogger.LogDebug("Handler:Leave - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerLeave; string text = peer.m_socket.GetHostName() ?? ""; if (!joinedPlayers.Remove(text)) { Plugin.StaticLogger.LogDebug(text + " did not exist in the list of joined players!"); return; } Plugin.StaticLogger.LogDebug($"Removed player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) from joined player list."); string text2 = ""; if (Plugin.StaticConfig.AnnouncePlayerFirstLeaveEnabled && Plugin.StaticDatabase.CountOfRecordsByName("leave", peer.m_playerName) == 0) { text2 = Plugin.StaticConfig.PlayerFirstLeaveMessage; ev = Webhook.Event.PlayerFirstLeave; } else if (Plugin.StaticConfig.PlayerLeaveMessageEnabled) { text2 = Plugin.StaticConfig.LeaveMessage; } if (Plugin.StaticConfig.StatsLeaveEnabled) { Plugin.StaticDatabase.InsertSimpleStatRecord("leave", peer.m_playerName, text, peer.m_refPos); } if (!string.IsNullOrEmpty(text2)) { FinalizeFormattingAndSend(peer, text, text2, Plugin.StaticConfig.PlayerLeavePosEnabled, ev); } } public static void Death(ZNetPeer peer) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { Plugin.StaticLogger.LogDebug("Handler:Death - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerDeath; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text = ""; if (Plugin.StaticConfig.AnnouncePlayerFirstDeathEnabled && Plugin.StaticDatabase.CountOfRecordsByName("death", peer.m_playerName) == 0) { text = Plugin.StaticConfig.PlayerFirstDeathMessage; ev = Webhook.Event.PlayerFirstDeath; } else if (Plugin.StaticConfig.PlayerDeathMessageEnabled) { text = Plugin.StaticConfig.DeathMessage; } if (Plugin.StaticConfig.StatsDeathEnabled) { Plugin.StaticDatabase.InsertSimpleStatRecord("death", peer.m_playerName, playerHostName, peer.m_refPos); } if (!string.IsNullOrEmpty(text)) { FinalizeFormattingAndSend(peer, playerHostName, text, Plugin.StaticConfig.PlayerDeathPosEnabled, ev); } } public static void Ping(ZNetPeer peer, Vector3 pos) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { Plugin.StaticLogger.LogDebug("Handler:Ping - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerPing; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text = ""; if (Plugin.StaticConfig.AnnouncePlayerFirstPingEnabled && Plugin.StaticDatabase.CountOfRecordsByName("ping", peer.m_playerName) == 0) { text = Plugin.StaticConfig.PlayerFirstPingMessage; ev = Webhook.Event.PlayerFirstPing; } else if (Plugin.StaticConfig.ChatPingEnabled) { text = Plugin.StaticConfig.PingMessage; } if (Plugin.StaticConfig.StatsPingEnabled) { Plugin.StaticDatabase.InsertSimpleStatRecord("ping", peer.m_playerName, playerHostName, pos); } if (!string.IsNullOrEmpty(text)) { FinalizeFormattingAndSend(peer, playerHostName, text, Plugin.StaticConfig.ChatPingPosEnabled, pos, ev); } } public static void Shout(ZNetPeer peer, Vector3 pos, string text) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { Plugin.StaticLogger.LogDebug("Handler:Shout - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerShout; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text2 = ""; if (Plugin.StaticConfig.AnnouncePlayerFirstShoutEnabled && Plugin.StaticDatabase.CountOfRecordsByName("shout", peer.m_playerName) == 0) { text2 = Plugin.StaticConfig.PlayerFirstShoutMessage; ev = Webhook.Event.PlayerFirstShout; } else if (Plugin.StaticConfig.ChatShoutEnabled) { text2 = Plugin.StaticConfig.ShoutMessage; } if (Plugin.StaticConfig.StatsShoutEnabled) { Plugin.StaticDatabase.InsertSimpleStatRecord("shout", peer.m_playerName, playerHostName, pos); } if (!string.IsNullOrEmpty(text2)) { if (Plugin.StaticConfig.ChatShoutAllCaps) { text = text.ToUpper(); } FinalizeFormattingAndSend(peer, playerHostName, text2, Plugin.StaticConfig.ChatShoutPosEnabled, pos, text, ev); } } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Webhook.Event ev) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) FinalizeFormattingAndSend(peer, playerHostName, preFormattedMessage, posEnabled, peer.m_refPos, ev); } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, Webhook.Event ev) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) bool subtractOne = ev == Webhook.Event.PlayerLeave || ev == Webhook.Event.PlayerFirstLeave; string text; if (preFormattedMessage.Contains("%POS%")) { if (!posEnabled) { preFormattedMessage.Replace("%POS%", ""); } text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, pos, subtractOne); } else { text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, subtractOne); } if (posEnabled && (Plugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%"))) { DiscordApi.SendMessage(ev, text, pos); } else { DiscordApi.SendMessage(ev, text); } } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, string text, Webhook.Event ev) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) string text2; if (preFormattedMessage.Contains("%POS%")) { if (!posEnabled) { preFormattedMessage.Replace("%POS%", ""); } text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text, pos); } else { text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text); } if (posEnabled && (Plugin.StaticConfig.DiscordEmbedsEnabled || !text2.Contains("%POS%"))) { DiscordApi.SendMessage(ev, text2, pos); } else { DiscordApi.SendMessage(ev, text2); } } internal static void NonPlayerChat(Type type, string user, string text) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if (Plugin.StaticConfig.AllowNonPlayerShoutLogging) { if ((int)type != 2) { Plugin.StaticLogger.LogDebug("Ignored ping/join/leave from non-player " + user); return; } string playerId = ""; Plugin.StaticLogger.LogDebug("Sending shout from '" + user + "' to discord: '" + text + "'"); if (Plugin.StaticConfig.ChatShoutEnabled) { string playerName = MessageTransformer.CleanCaretFormatting(user); string text2 = MessageTransformer.FormatPlayerMessage(Plugin.StaticConfig.ShoutMessage, playerName, playerId, text); if (text2.Contains("%POS%")) { text2.Replace("%POS%", ""); } DiscordApi.SendMessage(Webhook.Event.PlayerShout, text2); } } else { Plugin.StaticLogger.LogInfo("Ignored shout from " + user + " because they aren't a real player"); } } } internal class LeaderbBoard { private Base leaderBoard1; private Base leaderBoard2; private Base leaderBoard3; private Base leaderBoard4; private Base leaderBoard5; public static readonly int MAX_LEADER_BOARD_SIZE = 16; public Base LeaderBoard1 => leaderBoard1; public Base LeaderBoard2 => leaderBoard2; public Base LeaderBoard3 => leaderBoard3; public Base LeaderBoard4 => leaderBoard4; public Base LeaderBoard5 => leaderBoard5; public LeaderbBoard() { leaderBoard1 = new Composer(0); leaderBoard2 = new Composer(1); leaderBoard3 = new Composer(2); leaderBoard4 = new Composer(3); leaderBoard5 = new Composer(4); } public static string RankedCountResultToString(List<CountResult> rankings) { string text = ""; for (int i = 0; i < rankings.Count; i++) { text += $"{i + 1}: {rankings[i].Name}: {rankings[i].Count}{Environment.NewLine}"; } return text; } private static string ToReadableString(TimeSpan span) { string text = string.Format("{0}{1}{2}{3}", (span.Duration().Days > 0) ? string.Format("{0:0} day{1}, ", span.Days, (span.Days == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Hours > 0) ? string.Format("{0:0} hour{1}, ", span.Hours, (span.Hours == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Minutes > 0) ? string.Format("{0:0} minute{1}, ", span.Minutes, (span.Minutes == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Seconds > 0) ? string.Format("{0:0} second{1}", span.Seconds, (span.Seconds == 1) ? string.Empty : "s") : string.Empty); if (text.EndsWith(", ")) { text = text.Substring(0, text.Length - 2); } if (string.IsNullOrEmpty(text)) { text = "0 seconds"; } return text; } public static string RankedSecondsToString(List<CountResult> rankings) { string text = ""; for (int i = 0; i < rankings.Count; i++) { string text2 = ToReadableString(TimeSpan.FromSeconds(rankings[i].Count)); text += $"{i + 1}: {rankings[i].Name}: {text2}{Environment.NewLine}"; } return text; } } internal class VDCLogger { private static ManualLogSource _logger; private static string _logFilePath; private bool _logDebugMessages; private static readonly string LOG_NAME = "vdc.log"; public VDCLogger(ManualLogSource logger) { _logger = logger; _logFilePath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector", LOG_NAME); InitializeLogFile(); _logger.LogInfo((object)"Logger initialized."); } internal void SetLogLevel(bool logDebugMessages) { _logDebugMessages = logDebugMessages; } private void InitializeLogFile() { if (File.Exists(_logFilePath)) { string text = _logFilePath + ".old"; File.Move(_logFilePath, text); _logger.LogInfo((object)("Existing log file moved to " + text)); } } private async Task LogToFileAsync(string severity, string message) { try { using StreamWriter writer = new StreamWriter(_logFilePath, append: true); await writer.WriteLineAsync($"{DateTime.Now} [{severity}]: {message}"); } catch (Exception ex) { _logger.LogError((object)("Error writing to log file: " + ex.Message)); } } public async Task LogDebugAsync(string message) { await LogToFileAsync("DEBUG", message); if (_logDebugMessages) { _logger.LogInfo((object)message); } } public async Task LogInfoAsync(string message) { await LogToFileAsync("INFO", message); _logger.LogInfo((object)message); } public async Task LogWarningAsync(string message) { await LogToFileAsync("WARNING", message); _logger.LogWarning((object)message); } public async Task LogErrorAsync(string message) { await LogToFileAsync("ERROR", message); _logger.LogError((object)message); } public async Task LogFatalAsync(string message) { await LogToFileAsync("FATAL", message); _logger.LogFatal((object)message); } public void LogDebug(string message) { LogDebugAsync(message).GetAwaiter().GetResult(); } public void LogInfo(string message) { LogInfoAsync(message).GetAwaiter().GetResult(); } public void LogWarning(string message) { LogWarningAsync(message).GetAwaiter().GetResult(); } public void LogError(string message) { LogErrorAsync(message).GetAwaiter().GetResult(); } public void LogFatal(string message) { LogFatalAsync(message).GetAwaiter().GetResult(); } } internal static class MessageTransformer { private const string PUBLIC_IP = "%PUBLICIP%"; private const string VAR = "%VAR1%"; private const string VAR_1 = "%VAR2%"; private const string VAR_2 = "%VAR3%"; private const string VAR_3 = "%VAR4%"; private const string VAR_4 = "%VAR5%"; private const string VAR_5 = "%VAR6%"; private const string VAR_6 = "%VAR7%"; private const string VAR_7 = "%VAR8%"; private const string VAR_8 = "%VAR9%"; private const string VAR_9 = "%VAR10%"; private const string PLAYER_NAME = "%PLAYER_NAME%"; private const string PLAYER_STEAMID = "%PLAYER_STEAMID%"; private const string PLAYER_ID = "%PLAYER_ID%"; private const string SHOUT = "%SHOUT%"; private const string POS = "%POS%"; private const string EVENT_START_MSG = "%EVENT_START_MSG%"; private const string EVENT_END_MSG = "%EVENT_END_MSG%"; private const string EVENT_MSG = "%EVENT_MSG%"; private const string EVENT_PLAYERS = "%PLAYERS%"; private const string N = "%N%"; private const string WORLD_NAME = "%WORLD_NAME%"; private const string DAY_NUMBER = "%DAY_NUMBER%"; private const string NUM_PLAYERS = "%NUM_PLAYERS%"; private const string JOIN_CODE = "%JOIN_CODE%"; private const string TIMESTAMP = "%TIMESTAMP%"; private const string TIMESINCE = "%TIMESINCE%"; private const string UNIX_TIMESTAMP = "%UNIX_TIMESTAMP%"; private static readonly Regex OpenCaretRegex = new Regex("<[\\w=]+>"); private static readonly Regex CloseCaretRegex = new Regex("</[\\w]+>"); private static string ReplaceVariables(string rawMessage, bool subtractOne = false) { return ReplaceDynamicVariables(rawMessage.Replace("%VAR1%", Plugin.StaticConfig.UserVariable).Replace("%VAR2%", Plugin.StaticConfig.UserVariable1).Replace("%VAR3%", Plugin.StaticConfig.UserVariable2) .Replace("%VAR4%", Plugin.StaticConfig.UserVariable3) .Replace("%VAR5%", Plugin.StaticConfig.UserVariable4) .Replace("%VAR6%", Plugin.StaticConfig.UserVariable5) .Replace("%VAR7%", Plugin.StaticConfig.UserVariable6) .Replace("%VAR8%", Plugin.StaticConfig.UserVariable7) .Replace("%VAR9%", Plugin.StaticConfig.UserVariable8) .Replace("%VAR10%", Plugin.StaticConfig.UserVariable9), subtractOne); } private static string ReplaceDynamicVariables(string rawMessage, bool subtractOne = false) { return ReplaceUnixTimestamp(ReplaceTimesince(ReplaceTimestamp(ReplaceJoinCode(ReplaceNumPlayers(ReplaceDayNumber(ReplaceWorldName(ReplacePublicIp(rawMessage))), subtractOne))))); } private static string ReplaceTimestamp(string rawMessage) { return rawMessage.Replace("%TIMESTAMP%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}>"); } private static string ReplaceTimesince(string rawMessage) { return rawMessage.Replace("%TIMESINCE%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}:R>"); } private static string ReplaceUnixTimestamp(string rawMessage) { return rawMessage.Replace("%UNIX_TIMESTAMP%", ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString()); } private static string ReplaceJoinCode(string rawMessage) { return rawMessage.Replace("%JOIN_CODE%", ZPlayFabMatchmaking.JoinCode); } private static string ReplaceDayNumber(string rawMessage) { return rawMessage.Replace("%DAY_NUMBER%", ((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetCurrentDay().ToString() : "%DAY_NUMBER%"); } private static string ReplaceNumPlayers(string rawMessage, bool subtractOne = false) { if (subtractOne) { return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? (ZNet.instance.GetNrOfPlayers() - 1).ToString() : "%NUM_PLAYERS%"); } return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetNrOfPlayers().ToString() : "%NUM_PLAYERS%"); } private static string ReplacePublicIp(string rawMessage) { return rawMessage.Replace("%PUBLICIP%", Plugin.PublicIpAddress); } private static string ReplaceWorldName(string rawMessage) { return rawMessage.Replace("%WORLD_NAME%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "%WORLD_NAME%"); } public static string FormatServerMessage(string rawMessage) { return ReplaceVariables(rawMessage); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, bool subtractOne = false) { return ReplaceVariables(rawMessage, subtractOne).Replace("%PLAYER_STEAMID%", playerId).Replace("%PLAYER_ID%", playerId).Replace("%PLAYER_NAME%", playerName); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, Vector3 pos, bool subtractOne = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%POS%", $"{pos}"); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, string shout, bool subtractOne = false) { return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%SHOUT%", shout); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerSteamId, string shout, Vector3 pos, bool subtractOne = false) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatPlayerMessage(rawMessage, playerName, playerSteamId, pos, subtractOne).Replace("%SHOUT%", shout); } public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return ReplaceVariables(rawMessage).Replace("%EVENT_START_MSG%", eventStartMsg).Replace("%EVENT_END_MSG%", eventEndMsg); } public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%POS%", $"{pos}"); } public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventStartMsg); } public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventEndMsg); } public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventStartMsg); } public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventEndMsg); } public static string FormatLeaderBoardHeader(string rawMessage) { return ReplaceVariables(rawMessage); } public static string FormatLeaderBoardHeader(string rawMessage, int n) { return ReplaceVariables(rawMessage).Replace("%N%", n.ToString()); } public static string CleanCaretFormatting(string str) { string input = OpenCaretRegex.Replace(str, "", 1); return CloseCaretRegex.Replace(input, "", 1); } public static string FormatVector3AsPos(Vector3 vec3) { return Plugin.StaticConfig.PosVarFormat.Replace("%X%", vec3.x.ToString("F1")).Replace("%Y%", vec3.y.ToString("F1")).Replace("%Z%", vec3.z.ToString("F1")); } public static string FormatAppendedPos(Vector3 vec3) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string newValue = FormatVector3AsPos(vec3); return Plugin.StaticConfig.AppendedPosFormat.Replace("%POS%", newValue); } } [BepInPlugin("games.nwest.valheim.discordconnector", "Valheim Discord Connector", "2.3.2")] public class Plugin : BaseUnityPlugin { internal static VDCLogger StaticLogger; internal static PluginConfig StaticConfig; internal static Database StaticDatabase; internal static LeaderbBoard StaticLeaderBoards; internal static EventWatcher StaticEventWatcher; internal static ConfigWatcher StaticConfigWatcher; private static string _publicIpAddress; private Harmony _harmony; internal static string PublicIpAddress { get { if (!string.IsNullOrEmpty(_publicIpAddress)) { return _publicIpAddress; } _publicIpAddress = PublicIPChecker.GetPublicIP(); return _publicIpAddress; } } public Plugin() { StaticLogger = new VDCLogger(((BaseUnityPlugin)this).Logger); StaticConfig = new PluginConfig(((BaseUnityPlugin)this).Config); StaticDatabase = new Database(Paths.GameRootPath); StaticLeaderBoards = new LeaderbBoard(); StaticConfigWatcher = new ConfigWatcher(); _publicIpAddress = ""; } private void Awake() { StaticLogger.LogDebug("Plugin games.nwest.valheim.discordconnector is loaded!"); if (!IsHeadless()) { StaticLogger.LogInfo("Not running on a dedicated server, some features may break -- please report them!"); } else { StaticEventWatcher = new EventWatcher(); } if (string.IsNullOrEmpty(StaticConfig.PrimaryWebhook.Url) && string.IsNullOrEmpty(StaticConfig.SecondaryWebhook.Url)) { StaticLogger.LogWarning("No value set for WebHookURL! Plugin will run without using a main Discord webhook."); } if (StaticConfig.LeaderBoards[0].Enabled) { Timer timer = new Timer(); timer.Elapsed += StaticLeaderBoards.LeaderBoard1.SendLeaderBoardOnTimer; timer.Interval = 60000 * StaticConfig.LeaderBoards[0].PeriodInMinutes; StaticLogger.LogInfo("Enabling LeaderBoard.1 timer with interval " + Strings.HumanReadableMs(timer.Interval)); timer.Start(); } if (StaticConfig.LeaderBoards[1].Enabled) { Timer timer2 = new Timer(); timer2.Elapsed += StaticLeaderBoards.LeaderBoard2.SendLeaderBoardOnTimer; timer2.Interval = 60000 * StaticConfig.LeaderBoards[1].PeriodInMinutes; StaticLogger.LogInfo("Enabling LeaderBoard.2 timer with interval " + Strings.HumanReadableMs(timer2.Interval)); timer2.Start(); } if (StaticConfig.LeaderBoards[2].Enabled) { Timer timer3 = new Timer(); timer3.Elapsed += StaticLeaderBoards.LeaderBoard3.SendLeaderBoardOnTimer; timer3.Interval = 60000 * StaticConfig.LeaderBoards[2].PeriodInMinutes; StaticLogger.LogInfo("Enabling LeaderBoard.3 timer with interval " + Strings.HumanReadableMs(timer3.Interval)); timer3.Start(); } if (StaticConfig.LeaderBoards[3].Enabled) { Timer timer4 = new Timer(); timer4.Elapsed += StaticLeaderBoards.LeaderBoard4.SendLeaderBoardOnTimer; timer4.Interval = 60000 * StaticConfig.LeaderBoards[3].PeriodInMinutes; StaticLogger.LogInfo("Enabling LeaderBoard.4 timer with interval " + Strings.HumanReadableMs(timer4.Interval)); timer4.Start(); } if (StaticConfig.LeaderBoards[4].Enabled) { Timer timer5 = new Timer(); timer5.Elapsed += StaticLeaderBoards.LeaderBoard4.SendLeaderBoardOnTimer; timer5.Interval = 60000 * StaticConfig.LeaderBoards[4].PeriodInMinutes; StaticLogger.LogInfo("Enabling LeaderBoard.5 timer with interval " + Strings.HumanReadableMs(timer5.Interval)); timer5.Start(); } if (StaticConfig.ActivePlayersAnnouncement.Enabled) { Timer timer6 = new Timer(); timer6.Elapsed += ActivePlayersAnnouncement.SendOnTimer; timer6.Interval = 60000 * StaticConfig.ActivePlayersAnnouncement.PeriodInMinutes; StaticLogger.LogInfo("Enabling Player Activity announcement with interval " + Strings.HumanReadableMs(timer6.Interval)); timer6.Start(); } _harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "games.nwest.valheim.discordconnector"); } private void OnDestroy() { _harmony.UnpatchSelf(); StaticDatabase.Dispose(); } public static bool IsHeadless() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType == 4; } } internal static class PluginInfo { public const string PLUGIN_ID = "games.nwest.valheim.discordconnector"; public const string PLUGIN_NAME = "Valheim Discord Connector"; public const string PLUGIN_VERSION = "2.3.2"; public const string PLUGIN_REPO_SHORT = "github: nwesterhausen/valheim-discordconnector"; public const string PLUGIN_AUTHOR = "Nicholas Westerhausen"; public const string SHORT_PLUGIN_ID = "discordconnector"; } internal static class Hashing { public static string GetMD5Checksum(string filename) { using MD5 mD = MD5.Create(); using FileStream inputStream = File.OpenRead(filename); return BitConverter.ToString(mD.ComputeHash(inputStream)).Replace("-", ""); } } internal static class Strings { public static string HumanReadableMs(double ms) { TimeSpan timeSpan = TimeSpan.FromMilliseconds(ms); if (timeSpan.Milliseconds == timeSpan.Seconds && timeSpan.Seconds == 0) { return $"{timeSpan.Hours:D2}h:{timeSpan.Minutes:D2}m"; } return $"{timeSpan.Hours:D2}h:{timeSpan.Minutes:D2}m:{timeSpan.Seconds:D2}s:{timeSpan.Milliseconds:D3}ms"; } } internal static class PublicIPChecker { public static string GetPublicIP() { Plugin.StaticLogger.LogDebug("Getting public IP address."); string text = string.Empty; try { using WebClient webClient = new WebClient(); text = webClient.DownloadString("https://ifconfig.me/ip"); } catch (Exception ex) { Plugin.StaticLogger.LogError("Failed to get public IP address, an empty string will be used: " + ex.Message); } Plugin.StaticLogger.LogDebug("Public IP address is '" + text + "'"); return text; } } internal static class GuidHelper { public static string GenerateShortHexGuid(int byteCount = 4) { if (byteCount <= 0 || byteCount > 16) { throw new ArgumentException("Byte count must be between 1 and 16."); } return BitConverter.ToString(Guid.NewGuid().ToByteArray(), 0, byteCount).Replace("-", "").ToLower(); } } public class Webhook { public enum Event { ServerLaunch, ServerStart, ServerStop, ServerShutdown, ServerSave, EventStart, EventPaused, EventResumed, EventStop, PlayerJoin, PlayerLeave, PlayerShout, PlayerPing, PlayerDeath, PlayerFirstJoin, PlayerFirstLeave, PlayerFirstShout, PlayerFirstPing, PlayerFirstDeath, ActivePlayers, Leaderboard1, Leaderboard2, Leaderboard3, Leaderboard4, Leaderboard5, ALL, ServerLifecycle, EventLifecycle, PlayerAll, PlayerFirstAll, LeaderboardsAll, None, Other, CronJob, NewDayNumber } public static Event StringToEvent(string eventToken) { switch (eventToken) { case "ALL": return Event.ALL; case "serverLifecycle": return Event.ServerLifecycle; case "eventLifecycle": return Event.EventLifecycle; case "playerAll": return Event.PlayerAll; case "playerFirstAll": return Event.PlayerFirstAll; case "leaderboardsAll": return Event.LeaderboardsAll; case "serverLaunch": return Event.ServerLaunch; case "serverStart": return Event.ServerStart; case "serverStop": return Event.ServerStop; case "serverShutdown": return Event.ServerShutdown; case "serverSave": return Event.ServerSave; case "eventStart": return Event.EventStart; case "eventPaused": return Event.EventPaused; case "eventResumed": return Event.EventResumed; case "eventStop": return Event.EventStop; case "playerJoin": return Event.PlayerJoin; case "playerLeave": return Event.PlayerLeave; case "playerShout": return Event.PlayerShout; case "playerPing": return Event.PlayerPing; case "playerDeath": return Event.PlayerDeath; case "playerFirstJoin": return Event.PlayerFirstJoin; case "playerFirstLeave": return Event.PlayerFirstLeave; case "playerFirstShout": return Event.PlayerFirstShout; case "playerFirstPing": return Event.PlayerFirstPing; case "playerFirstDeath": return Event.PlayerFirstDeath; case "activePlayers": return Event.ActivePlayers; case "leaderboard1": return Event.Leaderboard1; case "leaderboard2": return Event.Leaderboard2; case "leaderboard3": return Event.Leaderboard3; case "leaderboard4": return Event.Leaderboard4; case "leaderboard5": return Event.Leaderboard5; case "cronjob": return Event.CronJob; case "newDayNumber": return Event.NewDayNumber; default: Plugin.StaticLogger.LogDebug("Unmatched event token '" + eventToken + "'"); return Event.None; } } public static List<Event> StringToEventList(string configEntry) { if (string.IsNullOrEmpty(configEntry)) { return new List<Event>(); } string text = Regex.Replace(configEntry, "[^;\\w]", ""); Plugin.StaticLogger.LogDebug("Webhooks: cleaned config entry '" + configEntry + "' => '" + text + "'"); if (text.Equals("ALL")) { return new List<Event>(1) { Event.ALL }; } List<Event> list = new List<Event>(); string[] array = text.Split(new char[1] { ';' }); foreach (string eventToken in array) { list.Add(StringToEvent(eventToken)); } Plugin.StaticLogger.LogDebug("Webhooks: parsed config entry '" + configEntry + "' => '" + string.Join(", ", list) + "'"); return list; } } internal class WebhookEntry { public string Url { get; set; } public List<Webhook.Event> FireOnEvents { get; set; } public string UsernameOverride { get; set; } = string.Empty; public string AvatarOverride { get; set; } = string.Empty; public WebhookEntry(string url) { Url = url; FireOnEvents = new List<Webhook.Event>(1) { Webhook.Event.ALL }; } public WebhookEntry(string url, List<Webhook.Event> fireOnEvents, string usernameOverride = "", string avatarOverride = "") { if (string.IsNullOrEmpty(url)) { Plugin.StaticLogger.LogDebug("Coerced null or empty webhook url to empty string. Ignoring event list."); Url = ""; FireOnEvents = new List<Webhook.Event>(); return; } Url = url; if (fireOnEvents == null || fireOnEvents.Count == 0) { Plugin.StaticLogger.LogDebug("Coerced null or empty webhook event list to empty list."); FireOnEvents = new List<Webhook.Event>(); } else { FireOnEvents = fireOnEvents; } if (!string.IsNullOrEmpty(usernameOverride)) { UsernameOverride = usernameOverride; } if (!string.IsNullOrEmpty(avatarOverride)) { AvatarOverride = avatarOverride; } } public bool HasUsernameOverride() { return !string.IsNullOrEmpty(UsernameOverride); } public bool HasAvatarOverride() { return !string.IsNullOrEmpty(AvatarOverride); } internal bool HasEvent(Webhook.Event ev) { if (FireOnEvents.Count == 0) { return false; } if (FireOnEvents.Contains(Webhook.Event.ALL)) { Plugin.StaticLogger.LogDebug("Webhook has 'ALL' enabled"); return true; } if (FireOnEvents.Contains(Webhook.Event.PlayerAll)) { Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of PlayerAll"); if (ev == Webhook.Event.PlayerDeath || ev == Webhook.Event.PlayerJoin || ev == Webhook.Event.PlayerLeave || ev == Webhook.Event.PlayerPing || ev == Webhook.Event.PlayerShout) { return true; } } if (FireOnEvents.Contains(Webhook.Event.PlayerFirstAll)) { Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of PlayerFirstAll"); if (ev == Webhook.Event.PlayerFirstDeath || ev == Webhook.Event.PlayerFirstJoin || ev == Webhook.Event.PlayerFirstLeave || ev == Webhook.Event.PlayerFirstPing || ev == Webhook.Event.PlayerFirstShout) { return true; } } if (FireOnEvents.Contains(Webhook.Event.EventLifecycle)) { Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of EventLifecycle"); if (ev == Webhook.Event.EventStart || ev == Webhook.Event.EventStop || ev == Webhook.Event.EventResumed || ev == Webhook.Event.EventPaused) { return true; } } if (FireOnEvents.Contains(Webhook.Event.ServerLifecycle)) { Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of ServerLifecycle"); if (ev == Webhook.Event.ServerLaunch || ev == Webhook.Event.ServerShutdown || ev == Webhook.Event.ServerStart || ev == Webhook.Event.ServerStop || ev == Webhook.Event.NewDayNumber) { return true; } } if (FireOnEvents.Contains(Webhook.Event.LeaderboardsAll)) { Plugin.StaticLogger.LogDebug($"Checking if {ev} is part of LeaderboardsAll"); if (ev == Webhook.Event.ActivePlayers || ev == Webhook.Event.Leaderboard1 || ev == Webhook.Event.Leaderboard2 || ev == Webhook.Event.Leaderboard3 || ev == Webhook.Event.Leaderboard4 || ev == Webhook.Event.Leaderboard5) { return true; } } Plugin.StaticLogger.LogDebug($"Checking for exact match of {ev}"); return FireOnEvents.Contains(ev); } } } namespace DiscordConnector.Records { public class CountResult { public string Name { get; } public int Count { get; } [BsonCtor] public CountResult(string name, int count) { Name = name; Count = count; } public static int CompareByCount(CountResult cr1, CountResult cr2) { return cr1.Count.CompareTo(cr2.Count); } public static int CompareByName(CountResult cr1, CountResult cr2) { return cr1.Name.CompareTo(cr2.Name); } public static List<CountResult> ConvertFromBsonDocuments(List<BsonDocument> bsonDocuments) { List<CountResult> list = new List<CountResult>(); if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"ConvertBsonDocumentCountToDotNet r={bsonDocuments.Count}"); } foreach (BsonDocument bsonDocument in bsonDocuments) { if (bsonDocument.ContainsKey("Count")) { if (bsonDocument.ContainsKey("Name")) { list.Add(new CountResult(((BsonValue)bsonDocument)["Name"].AsString, ((BsonValue)bsonDocument)["Count"].AsInt32)); } else if (bsonDocument.ContainsKey("NamePlayer")) { list.Add(new CountResult(((BsonValue)bsonDocument)["NamePlayer"]["Name"].AsString, ((BsonValue)bsonDocument)["Count"].AsInt32)); } else if (bsonDocument.ContainsKey("Player") && !((BsonValue)bsonDocument)["Player"].IsNull) { list.Add(new CountResult(Plugin.StaticDatabase.GetLatestCharacterNameForPlayer(BsonValue.op_Implicit(((BsonValue)bsonDocument)["Player"])), ((BsonValue)bsonDocument)["Count"].AsInt32)); } } } return list; } public override string ToString() { return $"{Name}: {Count}"; } } public class PlayerToName { public ObjectId _id { get; } public string CharacterName { get; } public string PlayerId { get; } public DateTime InsertedDate { get; } public PlayerToName(string characterName, string playerHostName) : this(ObjectId.NewObjectId(), characterName, playerHostName, DateTime.Now) { } [BsonCtor] public PlayerToName(ObjectId id, string characterName, string playerId, DateTime insertedDate) { _id = id; CharacterName = characterName; PlayerId = playerId; InsertedDate = insertedDate; } public override string ToString() { return CharacterName + " (" + PlayerId + ")"; } } public class Position { public float x { get; } public float y { get; } public float z { get; } public Position() { x = 0f; y = 0f; z = 0f; } public Position(float _x, float _y, float _z) { x = _x; y = _y; z = _z; } public override string ToString() { return $"({x},{y},{z})"; } } public class SimpleStat { public ObjectId StatId { get; } public string Name { get; } public DateTime Date { get; } public string PlayerId { get; } public Position Pos { get; } public SimpleStat(string name, string playerId, float x, float y, float z) : this(ObjectId.NewObjectId(), name, DateTime.Now, playerId, new Position(x, y, z)) { } [BsonCtor] public SimpleStat(ObjectId id, ObjectId statId, string name, DateTime date, string playerId, BsonDocument pos) : this(statId, name, date, playerId, BsonMapper.Global.Deserialize<Position>((BsonValue)(object)pos)) { } public SimpleStat(ObjectId statId, string name, DateTime date, string playerId, Position pos) { StatId = statId; Name = name; Date = date; PlayerId = playerId; Pos = pos; } public override string ToString() { return $"{Date.ToShortDateString()} {Date.ToShortTimeString()}: {Name} ({PlayerId}) at {Pos}"; } } internal class Database { private struct JoinLeaveTime { public DateTime Time; public bool IsJoin; } private const string DB_NAME = "records.db"; private static string DbPath; private LiteDatabase db; private ILiteCollection<SimpleStat> DeathCollection; private ILiteCollection<SimpleStat> JoinCollection; private ILiteCollection<SimpleStat> LeaveCollection; private ILiteCollection<SimpleStat> ShoutCollection; private ILiteCollection<SimpleStat> PingCollection; private ILiteCollection<PlayerToName> PlayerToNameCollection; public Database(string rootStorePath) { DbPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector", "records.db"); string text = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector-records.db"); if (File.Exists(text)) { File.Move(text, DbPath); } Initialize(); } public void Initialize() { Task.Run(delegate { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown try { db = new LiteDatabase(DbPath, (BsonMapper)null); Plugin.StaticLogger.LogDebug("LiteDB Connection Established to " + DbPath); DeathCollection = db.GetCollection<SimpleStat>("deaths", (BsonAutoId)10); JoinCollection = db.GetCollection<SimpleStat>("joins", (BsonAutoId)10); LeaveCollection = db.GetCollection<SimpleStat>("leaves", (BsonAutoId)10); ShoutCollection = db.GetCollection<SimpleStat>("shouts", (BsonAutoId)10); PingCollection = db.GetCollection<SimpleStat>("pings", (BsonAutoId)10); PlayerToNameCollection = db.GetCollection<PlayerToName>("player_name", (BsonAutoId)10); Task.Run(delegate { EnsureIndicesOnCollections(); Plugin.StaticLogger.LogDebug("Created indices on database collections"); }).ConfigureAwait(continueOnCapturedContext: false); } catch (IOException ex) { Plugin.StaticLogger.LogError("Unable to acquire un-shared access to " + DbPath); Plugin.StaticLogger.LogDebug(ex.ToString()); } }).ConfigureAwait(continueOnCapturedContext: false); } private void EnsureIndicesOnCollections() { DeathCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false); DeathCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false); JoinCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false); JoinCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false); LeaveCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false); LeaveCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false); ShoutCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false); ShoutCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false); PingCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.PlayerId), false); PingCollection.EnsureIndex<string>((Expression<Func<SimpleStat, string>>)((SimpleStat x) => x.Name), false); PlayerToNameCollection.EnsureIndex<string>((Expression<Func<PlayerToName, string>>)((PlayerToName x) => x.PlayerId), false); PlayerToNameCollection.EnsureIndex<string>((Expression<Func<PlayerToName, string>>)((PlayerToName x) => x.CharacterName), false); } public void Dispose() { Plugin.StaticLogger.LogDebug("Closing LiteDB connection"); db.Dispose(); } private void InsertSimpleStatRecord(ILiteCollection<SimpleStat> collection, string playerName, string playerHostName, Vector3 pos) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Task.Run(delegate { SimpleStat simpleStat = new SimpleStat(playerName, playerHostName, pos.x, pos.y, pos.z); collection.Insert(simpleStat); }).ConfigureAwait(continueOnCapturedContext: false); } private void EnsurePlayerNameRecorded(string characterName, string playerHostName) { Task.Run(delegate { if (!PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName) && x.CharacterName.Equals(characterName)))) { if (PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName)))) { Plugin.StaticLogger.LogDebug("Multiple characters from " + playerHostName + ", latest is " + characterName); } PlayerToName playerToName = new PlayerToName(characterName, playerHostName); PlayerToNameCollection.Insert(playerToName); } }).ConfigureAwait(continueOnCapturedContext: false); } private void InsertSimpleStatRecord(ILiteCollection<SimpleStat> collection, string playerName, string playerHostName) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) InsertSimpleStatRecord(collection, playerName, playerHostName, Vector3.zero); } public void InsertSimpleStatRecord(string key, string playerName, string playerHostName, Vector3 pos) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) switch (key) { case "death": InsertSimpleStatRecord(DeathCollection, playerName, playerHostName, pos); break; case "join": EnsurePlayerNameRecorded(playerName, playerHostName); InsertSimpleStatRecord(JoinCollection, playerName, playerHostName, pos); break; case "leave": InsertSimpleStatRecord(LeaveCollection, playerName, playerHostName, pos); break; case "ping": InsertSimpleStatRecord(PingCollection, playerName, playerHostName, pos); break; case "shout": InsertSimpleStatRecord(ShoutCollection, playerName, playerHostName, pos); break; default: Plugin.StaticLogger.LogDebug("InsertSimpleStatRecord, invalid key '" + key + "'"); break; } } public void InsertSimpleStatRecord(string key, string playerName, string playerHostName) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) InsertSimpleStatRecord(key, playerName, playerHostName, Vector3.zero); } internal string GetLatestCharacterNameForPlayer(string playerHostName) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug("GetLatestNameForCharacterId " + playerHostName + " begin"); } if (PlayerToNameCollection.Exists((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName)))) { try { return ((ILiteQueryableResult<PlayerToName>)(object)PlayerToNameCollection.Query().Where((Expression<Func<PlayerToName, bool>>)((PlayerToName x) => x.PlayerId.Equals(playerHostName))).OrderByDescending<DateTime>((Expression<Func<PlayerToName, DateTime>>)((PlayerToName x) => x.InsertedDate))).First().CharacterName; } catch (InvalidOperationException) { Plugin.StaticLogger.LogWarning("Should have found " + playerHostName + " in player_name table but did not!"); } } List<BsonDocument> list = JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId.Equals(playerHostName))).OrderByDescending(BsonExpression.op_Implicit("Date")) .Select(BsonExpression.op_Implicit("$.Name")) .ToList(); if (list.Count == 0) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug("GetLatestNameForCharacterId " + playerHostName + " result = NONE"); } return "undefined"; } if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"nameQuery has {list.Count} results"); } BsonDocument result = list[0]; if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"GetLatestNameForCharacterId {playerHostName} result = {result}"); } Task.Run(delegate { EnsurePlayerNameRecorded(BsonValue.op_Implicit(((BsonValue)result)["Name"]), playerHostName); }).ConfigureAwait(continueOnCapturedContext: false); return ((BsonValue)result)["Name"].AsString; } public List<CountResult> CountAllRecordsGrouped(string key) { switch (key) { case "death": return CountAllRecordsGrouped(DeathCollection); case "join": return CountAllRecordsGrouped(JoinCollection); case "leave": return CountAllRecordsGrouped(LeaveCollection); case "ping": return CountAllRecordsGrouped(PingCollection); case "shout": return CountAllRecordsGrouped(ShoutCollection); case "time_online": return TimeOnlineRecordsGrouped(); default: Plugin.StaticLogger.LogDebug("CountAllRecordsGrouped, invalid key '" + key + "'"); return new List<CountResult>(); } } private List<CountResult> TimeOnlineRecordsGrouped(DateTime? startDate = null, DateTime? endDate = null, bool inclusiveStart = true, bool inclusiveEnd = true) { PlayerToName[] array = ((ILiteQueryableResult<PlayerToName>)(object)PlayerToNameCollection.Query()).ToArray(); List<CountResult> list = new List<CountResult>(); PlayerToName[] array2 = array; foreach (PlayerToName player in array2) { TimeSpan timeSpan = TimeSpan.FromSeconds(0.0); ILiteQueryable<SimpleStat> val = JoinCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId.Equals(player.PlayerId) && x.Name.Equals(player.CharacterName))); ILiteQueryable<SimpleStat> val2 = LeaveCollection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.PlayerId.Equals(player.PlayerId) && x.Name.Equals(player.CharacterName))); Func<int, bool> startCompare = (inclusiveStart ? ((Func<int, bool>)((int x) => x >= 0)) : ((Func<int, bool>)((int x) => x > 0))); Func<int, bool> endCompare = (inclusiveEnd ? ((Func<int, bool>)((int x) => x <= 0)) : ((Func<int, bool>)((int x) => x < 0))); if (startDate.HasValue) { val = val.Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => startCompare(x.Date.CompareTo(((DateTime?)startDate).GetValueOrDefault())))); } if (endDate.HasValue) { val = val.Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => endCompare(x.Date.CompareTo(((DateTime?)endDate).GetValueOrDefault())))); } JoinLeaveTime[] array3 = Array.ConvertAll(((ILiteQueryableResult<SimpleStat>)(object)val).ToArray(), delegate(SimpleStat stat) { JoinLeaveTime result2 = default(JoinLeaveTime); result2.Time = stat.Date; result2.IsJoin = true; return result2; }); JoinLeaveTime[] array4 = Array.ConvertAll(((ILiteQueryableResult<SimpleStat>)(object)val2).ToArray(), delegate(SimpleStat stat) { JoinLeaveTime result = default(JoinLeaveTime); result.Time = stat.Date; result.IsJoin = false; return result; }); JoinLeaveTime[] array5 = (from j in array3.Concat(array4) orderby j.Time select j).ToArray(); Plugin.StaticLogger.LogDebug($"{player.PlayerId} as {player.CharacterName} has {array3.Length} joins, {array4.Length} leaves"); DateTime? dateTime = null; JoinLeaveTime[] array6 = array5; for (int k = 0; k < array6.Length; k++) { JoinLeaveTime joinLeaveTime = array6[k]; if (!dateTime.HasValue) { if (joinLeaveTime.IsJoin) { dateTime = joinLeaveTime.Time; } else { Plugin.StaticLogger.LogDebug($"Player {player.CharacterName} left at {joinLeaveTime.Time} but was not joined."); } } else if (joinLeaveTime.IsJoin) { Plugin.StaticLogger.LogDebug($"Player {player.CharacterName} joined at {joinLeaveTime.Time} but was already joined at {dateTime}"); dateTime = joinLeaveTime.Time; } else { TimeSpan timeSpan2 = timeSpan; DateTime time = joinLeaveTime.Time; timeSpan = timeSpan2 + time.Subtract(dateTime ?? joinLeaveTime.Time); dateTime = null; } } Plugin.StaticLogger.LogDebug($"{timeSpan} total online time."); list.Add(new CountResult(player.CharacterName, (int)timeSpan.TotalSeconds)); } return list; } public int CountOfRecordsByName(string key, string playerName) { if (!Plugin.StaticConfig.CollectStatsEnabled) { return -1; } switch (key) { case "death": return CountOfRecordsByName(DeathCollection, playerName); case "join": return CountOfRecordsByName(JoinCollection, playerName); case "leave": return CountOfRecordsByName(LeaveCollection, playerName); case "ping": return CountOfRecordsByName(PingCollection, playerName); case "shout": return CountOfRecordsByName(ShoutCollection, playerName); default: Plugin.StaticLogger.LogDebug("CountOfRecordsBySteamId, invalid key '" + key + "'"); return -2; } } public List<CountResult> CountAllRecordsGrouped(string key, TimeRange timeRange) { if (timeRange == TimeRange.AllTime) { return CountAllRecordsGrouped(key); } Tuple<DateTime, DateTime> tuple = DateHelper.StartEndDatesForTimeRange(timeRange); return CountRecordsBetweenDatesGrouped(key, tuple.Item1, tuple.Item2); } internal List<CountResult> CountRecordsBetweenDatesGrouped(string key, DateTime startDate, DateTime endDate, bool inclusiveStart = true, bool inclusiveEnd = true) { switch (key) { case "death": return CountAllRecordsGroupsWhereDate(DeathCollection, startDate, endDate, inclusiveStart, inclusiveEnd); case "join": return CountAllRecordsGroupsWhereDate(JoinCollection, startDate, endDate, inclusiveStart, inclusiveEnd); case "leave": return CountAllRecordsGroupsWhereDate(LeaveCollection, startDate, endDate, inclusiveStart, inclusiveEnd); case "ping": return CountAllRecordsGroupsWhereDate(PingCollection, startDate, endDate, inclusiveStart, inclusiveEnd); case "shout": return CountAllRecordsGroupsWhereDate(ShoutCollection, startDate, endDate, inclusiveStart, inclusiveEnd); case "time_online": return TimeOnlineRecordsGrouped(startDate, endDate, inclusiveStart, inclusiveEnd); default: Plugin.StaticLogger.LogDebug("CountTodaysRecordsGrouped, invalid key '" + key + "'"); return new List<CountResult>(); } } internal int CountOfRecordsByName(ILiteCollection<SimpleStat> collection, string playerName) { try { return ((ILiteQueryableResult<SimpleStat>)(object)collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Name.Equals(playerName)))).Count(); } catch { Plugin.StaticLogger.LogDebug("Error when trying to find " + playerName + " to count!"); return -3; } } internal List<CountResult> CountAllRecordsGrouped(ILiteCollection<SimpleStat> collection) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"CountAllRecordsGrouped {Plugin.StaticConfig.RecordRetrievalDiscernmentMethod}"); } if (collection.Count() == 0) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug("Collection is empty, skipping."); } return new List<CountResult>(); } string text = "PlayerId"; string text2 = "{Player: @Key, Count: Count(*)}"; if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.NameAndPlayerId) { text = "{Name,PlayerId}"; text2 = "{NamePlayer: @Key, Count: COUNT(*)}"; } if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.Name) { text = "Name"; text2 = "{Name: @Key, Count: Count(*)}"; } List<CountResult> list = CountResult.ConvertFromBsonDocuments(collection.Query().GroupBy(BsonExpression.op_Implicit(text)).Select(BsonExpression.op_Implicit(text2)) .ToList()); if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"CountAllRecordsGrouped {list.Count} records returned"); } return list; } internal List<CountResult> CountAllRecordsGroupsWhereDate(ILiteCollection<SimpleStat> collection, DateTime startDate, DateTime endDate, bool inclusiveStart = true, bool inclusiveEnd = true) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug($"CountAllRecordsGroupsWhereDate {Plugin.StaticConfig.RecordRetrievalDiscernmentMethod} {startDate} {endDate}"); } if (collection.Count() == 0) { if (Plugin.StaticConfig.DebugDatabaseMethods) { Plugin.StaticLogger.LogDebug("Collection is empty, skipping."); } return new List<CountResult>(); } string text = "PlayerId"; string text2 = "{Player: @Key, Count: Count(*)}"; if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.NameAndPlayerId) { text = "{Name,PlayerId}"; text2 = "{NamePlayer: @Key, Count: COUNT(*)}"; } if (Plugin.StaticConfig.RecordRetrievalDiscernmentMethod == MainConfig.RetrievalDiscernmentMethods.Name) { text = "Name"; text2 = "{Name: @Key, Count: Count(*)}"; } List<CountResult> list = ((inclusiveStart && inclusiveEnd) ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year >= ((DateTime)startDate).Date.Year && x.Date.Month >= ((DateTime)startDate).Date.Month && x.Date.Day >= ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text)) .Select(BsonExpression.op_Implicit(text2)) .ToList()) : (inclusiveEnd ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year <= ((DateTime)endDate).Date.Year && x.Date.Month <= ((DateTime)endDate).Date.Month && x.Date.Day <= ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text)) .Select(BsonExpression.op_Implicit(text2)) .ToList()) : ((!inclusiveStart) ? CountResult.ConvertFromBsonDocuments(collection.Query().Where((Expression<Func<SimpleStat, bool>>)((SimpleStat x) => x.Date.Year > ((DateTime)startDate).Date.Year && x.Date.Month > ((DateTime)startDate).Date.Month && x.Date.Day > ((DateTime)startDate).Date.Day && x.Date.Year < ((DateTime)endDate).Date.Year && x.Date.Month < ((DateTime)endDate).Date.Month && x.Date.Day < ((DateTime)endDate).Date.Day)).GroupBy(BsonExpression.op_Implicit(text)) .Select(BsonExpres
plugins/System.Runtime.Serialization.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Configuration; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Configuration; using System.Runtime.Serialization.Diagnostics; using System.Runtime.Serialization.Diagnostics.Application; using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Json; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using System.Xml.XPath; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("System.Runtime.Serialization.dll")] [assembly: AssemblyDescription("System.Runtime.Serialization.dll")] [assembly: AssemblyDefaultAlias("System.Runtime.Serialization.dll")] [assembly: AssemblyCompany("Mono development team")] [assembly: AssemblyProduct("Mono Common Language Infrastructure")] [assembly: AssemblyCopyright("(c) Various Mono authors")] [assembly: SatelliteContractVersion("4.0.0.0")] [assembly: AssemblyInformationalVersion("4.6.57.0")] [assembly: AssemblyFileVersion("4.6.57.0")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: CLSCompliant(true)] [assembly: AssemblyDelaySign(true)] [assembly: AssemblyKeyFile("../ecma.pub")] [assembly: AllowPartiallyTrustedCallers] [assembly: ComCompatibleVersion(1, 0, 3300, 0)] [assembly: SecurityCritical(SecurityCriticalScope.Explicit)] [assembly: ComVisible(false)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.0.0")] [module: UnverifiableCode] internal static class SR { internal static string GetString(string name, params object[] args) { return GetString(CultureInfo.InvariantCulture, name, args); } internal static string GetString(CultureInfo culture, string name, params object[] args) { return string.Format(culture, name, args); } internal static string GetString(string name) { return name; } internal static string GetString(CultureInfo culture, string name) { return name; } internal static string Format(string resourceFormat, params object[] args) { if (args != null) { return string.Format(CultureInfo.InvariantCulture, resourceFormat, args); } return resourceFormat; } internal static string Format(string resourceFormat, object p1) { return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1); } internal static string Format(string resourceFormat, object p1, object p2) { return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1, p2); } internal static string Format(CultureInfo ci, string resourceFormat, object p1, object p2) { return string.Format(ci, resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object p1, object p2, object p3) { return string.Format(CultureInfo.InvariantCulture, resourceFormat, p1, p2, p3); } internal static string GetResourceString(string str) { return str; } } namespace System { internal static class LocalAppContextSwitches { public static readonly bool DoNotUseTimeZoneInfo; public static readonly bool DoNotUseEcmaScriptV6EscapeControlCharacter; } internal static class NotImplemented { internal static Exception ByDesign => new NotImplementedException(); internal static Exception ByDesignWithMessage(string message) { return new NotImplementedException(message); } } } namespace System.Xml { internal abstract class ArrayHelper<TArgument, TArray> { public TArray[] ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, int maxArrayLength) { TArray[][] array = null; TArray[] array2 = null; int num = 0; int num2 = 0; if (reader.TryGetArrayLength(out var count)) { if (count > maxArrayLength) { XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); } if (count > 65535) { count = 65535; } } else { count = 32; } while (true) { array2 = new TArray[count]; int i; int num3; for (i = 0; i < array2.Length; i += num3) { num3 = ReadArray(reader, localName, namespaceUri, array2, i, array2.Length - i); if (num3 == 0) { break; } } if (num2 > maxArrayLength - i) { XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); } num2 += i; if (i < array2.Length || reader.NodeType == XmlNodeType.EndElement) { break; } if (array == null) { array = new TArray[32][]; } array[num++] = array2; count *= 2; } if (num2 != array2.Length || num > 0) { TArray[] array3 = new TArray[num2]; int num4 = 0; for (int j = 0; j < num; j++) { Array.Copy(array[j], 0, array3, num4, array[j].Length); num4 += array[j].Length; } Array.Copy(array2, 0, array3, num4, num2 - num4); array2 = array3; } return array2; } public void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, XmlDictionaryReader reader) { int count = ((!reader.TryGetArrayLength(out count)) ? 256 : Math.Min(count, 256)); TArray[] array = new TArray[count]; while (true) { int num = ReadArray(reader, localName, namespaceUri, array, 0, array.Length); if (num != 0) { WriteArray(writer, prefix, localName, namespaceUri, array, 0, num); continue; } break; } } protected abstract int ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count); protected abstract void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count); } internal class BooleanArrayHelperWithString : ArrayHelper<string, bool> { public static readonly BooleanArrayHelperWithString Instance = new BooleanArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, bool[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, bool[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class BooleanArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, bool> { public static readonly BooleanArrayHelperWithDictionaryString Instance = new BooleanArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int16ArrayHelperWithString : ArrayHelper<string, short> { public static readonly Int16ArrayHelperWithString Instance = new Int16ArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, short[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, short[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int16ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, short> { public static readonly Int16ArrayHelperWithDictionaryString Instance = new Int16ArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int32ArrayHelperWithString : ArrayHelper<string, int> { public static readonly Int32ArrayHelperWithString Instance = new Int32ArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, int[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, int[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int32ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, int> { public static readonly Int32ArrayHelperWithDictionaryString Instance = new Int32ArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int64ArrayHelperWithString : ArrayHelper<string, long> { public static readonly Int64ArrayHelperWithString Instance = new Int64ArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, long[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, long[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class Int64ArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, long> { public static readonly Int64ArrayHelperWithDictionaryString Instance = new Int64ArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class SingleArrayHelperWithString : ArrayHelper<string, float> { public static readonly SingleArrayHelperWithString Instance = new SingleArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, float[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, float[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class SingleArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, float> { public static readonly SingleArrayHelperWithDictionaryString Instance = new SingleArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DoubleArrayHelperWithString : ArrayHelper<string, double> { public static readonly DoubleArrayHelperWithString Instance = new DoubleArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, double[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, double[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DoubleArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, double> { public static readonly DoubleArrayHelperWithDictionaryString Instance = new DoubleArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DecimalArrayHelperWithString : ArrayHelper<string, decimal> { public static readonly DecimalArrayHelperWithString Instance = new DecimalArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, decimal[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, decimal[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DecimalArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, decimal> { public static readonly DecimalArrayHelperWithDictionaryString Instance = new DecimalArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DateTimeArrayHelperWithString : ArrayHelper<string, DateTime> { public static readonly DateTimeArrayHelperWithString Instance = new DateTimeArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, DateTime[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, DateTime[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class DateTimeArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, DateTime> { public static readonly DateTimeArrayHelperWithDictionaryString Instance = new DateTimeArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class GuidArrayHelperWithString : ArrayHelper<string, Guid> { public static readonly GuidArrayHelperWithString Instance = new GuidArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, Guid[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, Guid[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class GuidArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, Guid> { public static readonly GuidArrayHelperWithDictionaryString Instance = new GuidArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class TimeSpanArrayHelperWithString : ArrayHelper<string, TimeSpan> { public static readonly TimeSpanArrayHelperWithString Instance = new TimeSpanArrayHelperWithString(); protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, TimeSpan[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, TimeSpan[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class TimeSpanArrayHelperWithDictionaryString : ArrayHelper<XmlDictionaryString, TimeSpan> { public static readonly TimeSpanArrayHelperWithDictionaryString Instance = new TimeSpanArrayHelperWithDictionaryString(); protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count) { return reader.ReadArray(localName, namespaceUri, array, offset, count); } protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count) { writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); } } internal class EncodingStreamWrapper : Stream { private enum SupportedEncoding { UTF8, UTF16LE, UTF16BE, None } private static readonly UTF8Encoding SafeUTF8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); private static readonly UnicodeEncoding SafeUTF16 = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: false); private static readonly UnicodeEncoding SafeBEUTF16 = new UnicodeEncoding(bigEndian: true, byteOrderMark: false, throwOnInvalidBytes: false); private static readonly UTF8Encoding ValidatingUTF8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); private static readonly UnicodeEncoding ValidatingUTF16 = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); private static readonly UnicodeEncoding ValidatingBEUTF16 = new UnicodeEncoding(bigEndian: true, byteOrderMark: false, throwOnInvalidBytes: true); private const int BufferLength = 128; private static readonly byte[] encodingAttr = new byte[8] { 101, 110, 99, 111, 100, 105, 110, 103 }; private static readonly byte[] encodingUTF8 = new byte[5] { 117, 116, 102, 45, 56 }; private static readonly byte[] encodingUnicode = new byte[6] { 117, 116, 102, 45, 49, 54 }; private static readonly byte[] encodingUnicodeLE = new byte[8] { 117, 116, 102, 45, 49, 54, 108, 101 }; private static readonly byte[] encodingUnicodeBE = new byte[8] { 117, 116, 102, 45, 49, 54, 98, 101 }; private SupportedEncoding encodingCode; private Encoding encoding; private Encoder enc; private Decoder dec; private bool isReading; private Stream stream; private char[] chars; private byte[] bytes; private int byteOffset; private int byteCount; private byte[] byteBuffer = new byte[1]; public override bool CanRead { get { if (!isReading) { return false; } return stream.CanRead; } } public override bool CanSeek => false; public override bool CanWrite { get { if (isReading) { return false; } return stream.CanWrite; } } public override long Position { get { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } set { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } public override bool CanTimeout => stream.CanTimeout; public override long Length => stream.Length; public override int ReadTimeout { get { return stream.ReadTimeout; } set { stream.ReadTimeout = value; } } public override int WriteTimeout { get { return stream.WriteTimeout; } set { stream.WriteTimeout = value; } } public EncodingStreamWrapper(Stream stream, Encoding encoding) { try { isReading = true; this.stream = new BufferedStream(stream); SupportedEncoding supportedEncoding = GetSupportedEncoding(encoding); SupportedEncoding supportedEncoding2 = ReadBOMEncoding(encoding == null); if (supportedEncoding != SupportedEncoding.None && supportedEncoding != supportedEncoding2) { ThrowExpectedEncodingMismatch(supportedEncoding, supportedEncoding2); } if (supportedEncoding2 == SupportedEncoding.UTF8) { FillBuffer(2); if (bytes[byteOffset + 1] == 63 && bytes[byteOffset] == 60) { FillBuffer(128); CheckUTF8DeclarationEncoding(bytes, byteOffset, byteCount, supportedEncoding2, supportedEncoding); } return; } EnsureBuffers(); FillBuffer(254); SetReadDocumentEncoding(supportedEncoding2); CleanupCharBreak(); int charCount = this.encoding.GetChars(bytes, byteOffset, byteCount, chars, 0); byteOffset = 0; byteCount = ValidatingUTF8.GetBytes(chars, 0, charCount, bytes, 0); if (bytes[1] == 63 && bytes[0] == 60) { CheckUTF8DeclarationEncoding(bytes, 0, byteCount, supportedEncoding2, supportedEncoding); } else if (supportedEncoding == SupportedEncoding.None) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents."))); } } catch (DecoderFallbackException innerException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException)); } } private void SetReadDocumentEncoding(SupportedEncoding e) { EnsureBuffers(); encodingCode = e; encoding = GetEncoding(e); } private static Encoding GetEncoding(SupportedEncoding e) { return e switch { SupportedEncoding.UTF8 => ValidatingUTF8, SupportedEncoding.UTF16LE => ValidatingUTF16, SupportedEncoding.UTF16BE => ValidatingBEUTF16, _ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), }; } private static Encoding GetSafeEncoding(SupportedEncoding e) { return e switch { SupportedEncoding.UTF8 => SafeUTF8, SupportedEncoding.UTF16LE => SafeUTF16, SupportedEncoding.UTF16BE => SafeBEUTF16, _ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), }; } private static string GetEncodingName(SupportedEncoding enc) { return enc switch { SupportedEncoding.UTF8 => "utf-8", SupportedEncoding.UTF16LE => "utf-16LE", SupportedEncoding.UTF16BE => "utf-16BE", _ => throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))), }; } private static SupportedEncoding GetSupportedEncoding(Encoding encoding) { if (encoding == null) { return SupportedEncoding.None; } if (encoding.WebName == ValidatingUTF8.WebName) { return SupportedEncoding.UTF8; } if (encoding.WebName == ValidatingUTF16.WebName) { return SupportedEncoding.UTF16LE; } if (encoding.WebName == ValidatingBEUTF16.WebName) { return SupportedEncoding.UTF16BE; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("XML encoding not supported."))); } public EncodingStreamWrapper(Stream stream, Encoding encoding, bool emitBOM) { isReading = false; this.encoding = encoding; this.stream = new BufferedStream(stream); encodingCode = GetSupportedEncoding(encoding); if (encodingCode == SupportedEncoding.UTF8) { return; } EnsureBuffers(); dec = ValidatingUTF8.GetDecoder(); enc = this.encoding.GetEncoder(); if (emitBOM) { byte[] preamble = this.encoding.GetPreamble(); if (preamble.Length != 0) { this.stream.Write(preamble, 0, preamble.Length); } } } private SupportedEncoding ReadBOMEncoding(bool notOutOfBand) { int num = stream.ReadByte(); int num2 = stream.ReadByte(); int num3 = stream.ReadByte(); int num4 = stream.ReadByte(); if (num4 == -1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file."))); } int preserve; SupportedEncoding result = ReadBOMEncoding((byte)num, (byte)num2, (byte)num3, (byte)num4, notOutOfBand, out preserve); EnsureByteBuffer(); switch (preserve) { case 1: bytes[0] = (byte)num4; break; case 2: bytes[0] = (byte)num3; bytes[1] = (byte)num4; break; case 4: bytes[0] = (byte)num; bytes[1] = (byte)num2; bytes[2] = (byte)num3; bytes[3] = (byte)num4; break; } byteCount = preserve; return result; } private static SupportedEncoding ReadBOMEncoding(byte b1, byte b2, byte b3, byte b4, bool notOutOfBand, out int preserve) { SupportedEncoding result = SupportedEncoding.UTF8; preserve = 0; if (b1 == 60 && b2 != 0) { result = SupportedEncoding.UTF8; preserve = 4; } else if (b1 == byte.MaxValue && b2 == 254) { result = SupportedEncoding.UTF16LE; preserve = 2; } else if (b1 == 254 && b2 == byte.MaxValue) { result = SupportedEncoding.UTF16BE; preserve = 2; } else if (b1 == 0 && b2 == 60) { result = SupportedEncoding.UTF16BE; if (notOutOfBand && (b3 != 0 || b4 != 63)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration is required for all non-UTF8 documents."))); } preserve = 4; } else if (b1 == 60 && b2 == 0) { result = SupportedEncoding.UTF16LE; if (notOutOfBand && (b3 != 63 || b4 != 0)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration is required for all non-UTF8 documents."))); } preserve = 4; } else if (b1 == 239 && b2 == 187) { if (notOutOfBand && b3 != 191) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unrecognized Byte Order Mark."))); } preserve = 1; } else { preserve = 4; } return result; } private void FillBuffer(int count) { count -= byteCount; while (count > 0) { int num = stream.Read(bytes, byteOffset + byteCount, count); if (num != 0) { byteCount += num; count -= num; continue; } break; } } private void EnsureBuffers() { EnsureByteBuffer(); if (chars == null) { chars = new char[128]; } } private void EnsureByteBuffer() { if (bytes == null) { bytes = new byte[512]; byteOffset = 0; byteCount = 0; } } private static void CheckUTF8DeclarationEncoding(byte[] buffer, int offset, int count, SupportedEncoding e, SupportedEncoding expectedEnc) { byte b = 0; int num = -1; int num2 = offset + Math.Min(count, 128); int num3 = 0; int num4 = 0; for (num3 = offset + 2; num3 < num2; num3++) { if (b != 0) { if (buffer[num3] == b) { b = 0; } } else if (buffer[num3] == 39 || buffer[num3] == 34) { b = buffer[num3]; } else if (buffer[num3] == 61) { if (num4 == 1) { num = num3; break; } num4++; } else if (buffer[num3] == 63) { break; } } if (num == -1) { if (e != 0 && expectedEnc == SupportedEncoding.None) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents."))); } return; } if (num < 28) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration."))); } num3 = num - 1; while (IsWhitespace(buffer[num3])) { num3--; } if (!Compare(encodingAttr, buffer, num3 - encodingAttr.Length + 1)) { if (e == SupportedEncoding.UTF8 || expectedEnc != SupportedEncoding.None) { return; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents."))); } for (num3 = num + 1; num3 < num2 && IsWhitespace(buffer[num3]); num3++) { } if (buffer[num3] != 39 && buffer[num3] != 34) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration."))); } b = buffer[num3]; int num5 = num3++; for (; buffer[num3] != b && num3 < num2; num3++) { } if (buffer[num3] != b) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Malformed XML declaration."))); } int num6 = num5 + 1; int num7 = num3 - num6; SupportedEncoding supportedEncoding = e; if (num7 == encodingUTF8.Length && CompareCaseInsensitive(encodingUTF8, buffer, num6)) { supportedEncoding = SupportedEncoding.UTF8; } else if (num7 == encodingUnicodeLE.Length && CompareCaseInsensitive(encodingUnicodeLE, buffer, num6)) { supportedEncoding = SupportedEncoding.UTF16LE; } else if (num7 == encodingUnicodeBE.Length && CompareCaseInsensitive(encodingUnicodeBE, buffer, num6)) { supportedEncoding = SupportedEncoding.UTF16BE; } else if (num7 == encodingUnicode.Length && CompareCaseInsensitive(encodingUnicode, buffer, num6)) { if (e == SupportedEncoding.UTF8) { ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), SafeUTF8.GetString(encodingUTF8, 0, encodingUTF8.Length)); } } else { ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), e); } if (e != supportedEncoding) { ThrowEncodingMismatch(SafeUTF8.GetString(buffer, num6, num7), e); } } private static bool CompareCaseInsensitive(byte[] key, byte[] buffer, int offset) { for (int i = 0; i < key.Length; i++) { if (key[i] != buffer[offset + i] && key[i] != char.ToLower((char)buffer[offset + i], CultureInfo.InvariantCulture)) { return false; } } return true; } private static bool Compare(byte[] key, byte[] buffer, int offset) { for (int i = 0; i < key.Length; i++) { if (key[i] != buffer[offset + i]) { return false; } } return true; } private static bool IsWhitespace(byte ch) { if (ch != 32 && ch != 10 && ch != 9) { return ch == 13; } return true; } internal static ArraySegment<byte> ProcessBuffer(byte[] buffer, int offset, int count, Encoding encoding) { if (count < 4) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file."))); } try { SupportedEncoding supportedEncoding = GetSupportedEncoding(encoding); int preserve; SupportedEncoding supportedEncoding2 = ReadBOMEncoding(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], encoding == null, out preserve); if (supportedEncoding != SupportedEncoding.None && supportedEncoding != supportedEncoding2) { ThrowExpectedEncodingMismatch(supportedEncoding, supportedEncoding2); } offset += 4 - preserve; count -= 4 - preserve; if (supportedEncoding2 == SupportedEncoding.UTF8) { if (buffer[offset + 1] != 63 || buffer[offset] != 60) { return new ArraySegment<byte>(buffer, offset, count); } CheckUTF8DeclarationEncoding(buffer, offset, count, supportedEncoding2, supportedEncoding); return new ArraySegment<byte>(buffer, offset, count); } Encoding safeEncoding = GetSafeEncoding(supportedEncoding2); int num = Math.Min(count, 256); char[] array = new char[safeEncoding.GetMaxCharCount(num)]; int charCount = safeEncoding.GetChars(buffer, offset, num, array, 0); byte[] array2 = new byte[ValidatingUTF8.GetMaxByteCount(charCount)]; int count2 = ValidatingUTF8.GetBytes(array, 0, charCount, array2, 0); if (array2[1] == 63 && array2[0] == 60) { CheckUTF8DeclarationEncoding(array2, 0, count2, supportedEncoding2, supportedEncoding); } else if (supportedEncoding == SupportedEncoding.None) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("An XML declaration with an encoding is required for all non-UTF8 documents."))); } return new ArraySegment<byte>(ValidatingUTF8.GetBytes(GetEncoding(supportedEncoding2).GetChars(buffer, offset, count))); } catch (DecoderFallbackException innerException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException)); } } private static void ThrowExpectedEncodingMismatch(SupportedEncoding expEnc, SupportedEncoding actualEnc) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("The expected encoding '{0}' does not match the actual encoding '{1}'.", GetEncodingName(expEnc), GetEncodingName(actualEnc)))); } private static void ThrowEncodingMismatch(string declEnc, SupportedEncoding enc) { ThrowEncodingMismatch(declEnc, GetEncodingName(enc)); } private static void ThrowEncodingMismatch(string declEnc, string docEnc) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("The encoding in the declaration '{0}' does not match the encoding of the document '{1}'.", declEnc, docEnc))); } public override void Close() { Flush(); base.Close(); stream.Close(); } public override void Flush() { stream.Flush(); } public override int ReadByte() { if (byteCount == 0 && encodingCode == SupportedEncoding.UTF8) { return stream.ReadByte(); } if (Read(byteBuffer, 0, 1) == 0) { return -1; } return byteBuffer[0]; } public override int Read(byte[] buffer, int offset, int count) { try { if (byteCount == 0) { if (encodingCode == SupportedEncoding.UTF8) { return stream.Read(buffer, offset, count); } byteOffset = 0; byteCount = stream.Read(bytes, byteCount, (chars.Length - 1) * 2); if (byteCount == 0) { return 0; } CleanupCharBreak(); int charCount = encoding.GetChars(bytes, 0, byteCount, chars, 0); byteCount = Encoding.UTF8.GetBytes(chars, 0, charCount, bytes, 0); } if (byteCount < count) { count = byteCount; } Buffer.BlockCopy(bytes, byteOffset, buffer, offset, count); byteOffset += count; byteCount -= count; return count; } catch (DecoderFallbackException innerException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Invalid byte encoding."), innerException)); } } private void CleanupCharBreak() { int num = byteOffset + byteCount; if (byteCount % 2 != 0) { int num2 = stream.ReadByte(); if (num2 < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file."))); } bytes[num++] = (byte)num2; byteCount++; } int num3 = ((encodingCode != SupportedEncoding.UTF16LE) ? (bytes[num - 1] + (bytes[num - 2] << 8)) : (bytes[num - 2] + (bytes[num - 1] << 8))); if ((num3 & 0xDC00) != 56320 && num3 >= 55296 && num3 <= 56319) { int num4 = stream.ReadByte(); int num5 = stream.ReadByte(); if (num5 < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(System.Runtime.Serialization.SR.GetString("Unexpected end of file."))); } bytes[num++] = (byte)num4; bytes[num++] = (byte)num5; byteCount += 2; } } public override long Seek(long offset, SeekOrigin origin) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } public override void WriteByte(byte b) { if (encodingCode == SupportedEncoding.UTF8) { stream.WriteByte(b); return; } byteBuffer[0] = b; Write(byteBuffer, 0, 1); } public override void Write(byte[] buffer, int offset, int count) { if (encodingCode == SupportedEncoding.UTF8) { stream.Write(buffer, offset, count); return; } while (count > 0) { int num = ((chars.Length < count) ? chars.Length : count); int charCount = dec.GetChars(buffer, offset, num, chars, 0, flush: false); byteCount = enc.GetBytes(chars, 0, charCount, bytes, 0, flush: false); stream.Write(bytes, 0, byteCount); offset += num; count -= num; } } public override void SetLength(long value) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } public interface IFragmentCapableXmlDictionaryWriter { bool CanFragment { get; } void StartFragment(Stream stream, bool generateSelfContainedTextFragment); void EndFragment(); void WriteFragment(byte[] buffer, int offset, int count); } public interface IStreamProvider { Stream GetStream(); void ReleaseStream(Stream stream); } public interface IXmlDictionary { bool TryLookup(string value, out XmlDictionaryString result); bool TryLookup(int key, out XmlDictionaryString result); bool TryLookup(XmlDictionaryString value, out XmlDictionaryString result); } internal enum PrefixHandleType { Empty, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Buffer, Max } internal class PrefixHandle { private XmlBufferReader bufferReader; private PrefixHandleType type; private int offset; private int length; private static string[] prefixStrings = new string[27] { "", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" }; private static byte[] prefixBuffer = new byte[26] { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 }; public bool IsEmpty => type == PrefixHandleType.Empty; public bool IsXmlns { get { if (type != PrefixHandleType.Buffer) { return false; } if (length != 5) { return false; } byte[] buffer = bufferReader.Buffer; int num = offset; if (buffer[num] == 120 && buffer[num + 1] == 109 && buffer[num + 2] == 108 && buffer[num + 3] == 110) { return buffer[num + 4] == 115; } return false; } } public bool IsXml { get { if (type != PrefixHandleType.Buffer) { return false; } if (length != 3) { return false; } byte[] buffer = bufferReader.Buffer; int num = offset; if (buffer[num] == 120 && buffer[num + 1] == 109) { return buffer[num + 2] == 108; } return false; } } public PrefixHandle(XmlBufferReader bufferReader) { this.bufferReader = bufferReader; } public void SetValue(PrefixHandleType type) { this.type = type; } public void SetValue(PrefixHandle prefix) { type = prefix.type; offset = prefix.offset; length = prefix.length; } public void SetValue(int offset, int length) { switch (length) { case 0: SetValue(PrefixHandleType.Empty); return; case 1: { byte @byte = bufferReader.GetByte(offset); if (@byte >= 97 && @byte <= 122) { SetValue(GetAlphaPrefix(@byte - 97)); return; } break; } } type = PrefixHandleType.Buffer; this.offset = offset; this.length = length; } public bool TryGetShortPrefix(out PrefixHandleType type) { type = this.type; return type != PrefixHandleType.Buffer; } public static string GetString(PrefixHandleType type) { return prefixStrings[(int)type]; } public static PrefixHandleType GetAlphaPrefix(int index) { return (PrefixHandleType)(1 + index); } public static byte[] GetString(PrefixHandleType type, out int offset, out int length) { if (type == PrefixHandleType.Empty) { offset = 0; length = 0; } else { length = 1; offset = (int)(type - 1); } return prefixBuffer; } public string GetString(XmlNameTable nameTable) { PrefixHandleType prefixHandleType = type; if (prefixHandleType != PrefixHandleType.Buffer) { return GetString(prefixHandleType); } return bufferReader.GetString(offset, length, nameTable); } public string GetString() { PrefixHandleType prefixHandleType = type; if (prefixHandleType != PrefixHandleType.Buffer) { return GetString(prefixHandleType); } return bufferReader.GetString(offset, length); } public byte[] GetString(out int offset, out int length) { PrefixHandleType prefixHandleType = type; if (prefixHandleType != PrefixHandleType.Buffer) { return GetString(prefixHandleType, out offset, out length); } offset = this.offset; length = this.length; return bufferReader.Buffer; } public int CompareTo(PrefixHandle that) { return GetString().CompareTo(that.GetString()); } private bool Equals2(PrefixHandle prefix2) { PrefixHandleType prefixHandleType = type; PrefixHandleType prefixHandleType2 = prefix2.type; if (prefixHandleType != prefixHandleType2) { return false; } if (prefixHandleType != PrefixHandleType.Buffer) { return true; } if (bufferReader == prefix2.bufferReader) { return bufferReader.Equals2(offset, length, prefix2.offset, prefix2.length); } return bufferReader.Equals2(offset, length, prefix2.bufferReader, prefix2.offset, prefix2.length); } private bool Equals2(string prefix2) { PrefixHandleType prefixHandleType = type; if (prefixHandleType != PrefixHandleType.Buffer) { return GetString(prefixHandleType) == prefix2; } return bufferReader.Equals2(offset, length, prefix2); } private bool Equals2(XmlDictionaryString prefix2) { return Equals2(prefix2.Value); } public static bool operator ==(PrefixHandle prefix1, string prefix2) { return prefix1.Equals2(prefix2); } public static bool operator !=(PrefixHandle prefix1, string prefix2) { return !prefix1.Equals2(prefix2); } public static bool operator ==(PrefixHandle prefix1, XmlDictionaryString prefix2) { return prefix1.Equals2(prefix2); } public static bool operator !=(PrefixHandle prefix1, XmlDictionaryString prefix2) { return !prefix1.Equals2(prefix2); } public static bool operator ==(PrefixHandle prefix1, PrefixHandle prefix2) { return prefix1.Equals2(prefix2); } public static bool operator !=(PrefixHandle prefix1, PrefixHandle prefix2) { return !prefix1.Equals2(prefix2); } public override bool Equals(object obj) { if (!(obj is PrefixHandle prefixHandle)) { return false; } return this == prefixHandle; } public override string ToString() { return GetString(); } public override int GetHashCode() { return GetString().GetHashCode(); } } internal enum StringHandleConstStringType { Type, Root, Item } internal class StringHandle { private enum StringHandleType { Dictionary, UTF8, EscapedUTF8, ConstString } private XmlBufferReader bufferReader; private StringHandleType type; private int key; private int offset; private int length; private static string[] constStrings = new string[3] { "type", "root", "item" }; public bool IsEmpty { get { if (type == StringHandleType.UTF8) { return length == 0; } return Equals2(string.Empty); } } public bool IsXmlns { get { if (type == StringHandleType.UTF8) { if (length != 5) { return false; } byte[] buffer = bufferReader.Buffer; int num = offset; if (buffer[num] == 120 && buffer[num + 1] == 109 && buffer[num + 2] == 108 && buffer[num + 3] == 110) { return buffer[num + 4] == 115; } return false; } return Equals2("xmlns"); } } public StringHandle(XmlBufferReader bufferReader) { this.bufferReader = bufferReader; SetValue(0, 0); } public void SetValue(int offset, int length) { type = StringHandleType.UTF8; this.offset = offset; this.length = length; } public void SetConstantValue(StringHandleConstStringType constStringType) { type = StringHandleType.ConstString; key = (int)constStringType; } public void SetValue(int offset, int length, bool escaped) { type = ((!escaped) ? StringHandleType.UTF8 : StringHandleType.EscapedUTF8); this.offset = offset; this.length = length; } public void SetValue(int key) { type = StringHandleType.Dictionary; this.key = key; } public void SetValue(StringHandle value) { type = value.type; key = value.key; offset = value.offset; length = value.length; } public void ToPrefixHandle(PrefixHandle prefix) { prefix.SetValue(offset, length); } public string GetString(XmlNameTable nameTable) { return type switch { StringHandleType.UTF8 => bufferReader.GetString(offset, length, nameTable), StringHandleType.Dictionary => nameTable.Add(bufferReader.GetDictionaryString(key).Value), StringHandleType.ConstString => nameTable.Add(constStrings[key]), _ => bufferReader.GetEscapedString(offset, length, nameTable), }; } public string GetString() { return type switch { StringHandleType.UTF8 => bufferReader.GetString(offset, length), StringHandleType.Dictionary => bufferReader.GetDictionaryString(key).Value, StringHandleType.ConstString => constStrings[key], _ => bufferReader.GetEscapedString(offset, length), }; } public byte[] GetString(out int offset, out int length) { switch (type) { case StringHandleType.UTF8: offset = this.offset; length = this.length; return bufferReader.Buffer; case StringHandleType.Dictionary: { byte[] array3 = bufferReader.GetDictionaryString(key).ToUTF8(); offset = 0; length = array3.Length; return array3; } case StringHandleType.ConstString: { byte[] array2 = XmlConverter.ToBytes(constStrings[key]); offset = 0; length = array2.Length; return array2; } default: { byte[] array = XmlConverter.ToBytes(bufferReader.GetEscapedString(this.offset, this.length)); offset = 0; length = array.Length; return array; } } } public bool TryGetDictionaryString(out XmlDictionaryString value) { if (type == StringHandleType.Dictionary) { value = bufferReader.GetDictionaryString(key); return true; } if (IsEmpty) { value = XmlDictionaryString.Empty; return true; } value = null; return false; } public override string ToString() { return GetString(); } private bool Equals2(int key2, XmlBufferReader bufferReader2) { return type switch { StringHandleType.Dictionary => bufferReader.Equals2(key, key2, bufferReader2), StringHandleType.UTF8 => bufferReader.Equals2(offset, length, bufferReader2.GetDictionaryString(key2).Value), _ => GetString() == bufferReader.GetDictionaryString(key2).Value, }; } private bool Equals2(XmlDictionaryString xmlString2) { return type switch { StringHandleType.Dictionary => bufferReader.Equals2(key, xmlString2), StringHandleType.UTF8 => bufferReader.Equals2(offset, length, xmlString2.ToUTF8()), _ => GetString() == xmlString2.Value, }; } private bool Equals2(string s2) { return type switch { StringHandleType.Dictionary => bufferReader.GetDictionaryString(key).Value == s2, StringHandleType.UTF8 => bufferReader.Equals2(offset, length, s2), _ => GetString() == s2, }; } private bool Equals2(int offset2, int length2, XmlBufferReader bufferReader2) { return type switch { StringHandleType.Dictionary => bufferReader2.Equals2(offset2, length2, bufferReader.GetDictionaryString(key).Value), StringHandleType.UTF8 => bufferReader.Equals2(offset, length, bufferReader2, offset2, length2), _ => GetString() == bufferReader.GetString(offset2, length2), }; } private bool Equals2(StringHandle s2) { return s2.type switch { StringHandleType.Dictionary => Equals2(s2.key, s2.bufferReader), StringHandleType.UTF8 => Equals2(s2.offset, s2.length, s2.bufferReader), _ => Equals2(s2.GetString()), }; } public static bool operator ==(StringHandle s1, XmlDictionaryString xmlString2) { return s1.Equals2(xmlString2); } public static bool operator !=(StringHandle s1, XmlDictionaryString xmlString2) { return !s1.Equals2(xmlString2); } public static bool operator ==(StringHandle s1, string s2) { return s1.Equals2(s2); } public static bool operator !=(StringHandle s1, string s2) { return !s1.Equals2(s2); } public static bool operator ==(StringHandle s1, StringHandle s2) { return s1.Equals2(s2); } public static bool operator !=(StringHandle s1, StringHandle s2) { return !s1.Equals2(s2); } public int CompareTo(StringHandle that) { if (type == StringHandleType.UTF8 && that.type == StringHandleType.UTF8) { return bufferReader.Compare(offset, length, that.offset, that.length); } return string.Compare(GetString(), that.GetString(), StringComparison.Ordinal); } public override bool Equals(object obj) { if (!(obj is StringHandle stringHandle)) { return false; } return this == stringHandle; } public override int GetHashCode() { return GetString().GetHashCode(); } } public class UniqueId { private long idLow; private long idHigh; [SecurityCritical] private string s; private const int guidLength = 16; private const int uuidLength = 45; private static short[] char2val = new short[256] { 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 160, 176, 192, 208, 224, 240, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 }; private const string val2char = "0123456789abcdef"; public int CharArrayLength { [SecuritySafeCritical] get { if (s != null) { return s.Length; } return 45; } } public bool IsGuid => (idLow | idHigh) != 0; public UniqueId() : this(Guid.NewGuid()) { } public UniqueId(Guid guid) : this(guid.ToByteArray()) { } public UniqueId(byte[] guid) : this(guid, 0) { } [SecuritySafeCritical] public unsafe UniqueId(byte[] guid, int offset) { if (guid == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("guid")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative."))); } if (offset > guid.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", guid.Length))); } if (16 > guid.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(System.Runtime.Serialization.SR.GetString("Array too small. Length of available data must be at least {0}.", 16), "guid")); } fixed (byte* ptr = &guid[offset]) { idLow = UnsafeGetInt64(ptr); idHigh = UnsafeGetInt64(ptr + 8); } } [SecuritySafeCritical] public unsafe UniqueId(string value) { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } if (value.Length == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(System.Runtime.Serialization.SR.GetString("UniqueId cannot be zero length."))); } fixed (char* chars = value) { UnsafeParse(chars, value.Length); } s = value; } [SecuritySafeCritical] public unsafe UniqueId(char[] chars, int offset, int count) { if (chars == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative."))); } if (offset > chars.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", chars.Length))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative."))); } if (count > chars.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", System.Runtime.Serialization.SR.GetString("The specified size exceeds the remaining buffer space ({0} bytes).", chars.Length - offset))); } if (count == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(System.Runtime.Serialization.SR.GetString("UniqueId cannot be zero length."))); } fixed (char* chars2 = &chars[offset]) { UnsafeParse(chars2, count); } if (!IsGuid) { s = new string(chars, offset, count); } } [SecurityCritical] private unsafe int UnsafeDecode(short* char2val, char ch1, char ch2) { if ((ch1 | ch2) >= 128) { return 256; } return char2val[(int)ch1] | char2val[128 + ch2]; } [SecurityCritical] private unsafe void UnsafeEncode(char* val2char, byte b, char* pch) { *pch = val2char[b >> 4]; pch[1] = val2char[b & 0xF]; } [SecurityCritical] private unsafe void UnsafeParse(char* chars, int charCount) { if (charCount != 45 || *chars != 'u' || chars[1] != 'r' || chars[2] != 'n' || chars[3] != ':' || chars[4] != 'u' || chars[5] != 'u' || chars[6] != 'i' || chars[7] != 'd' || chars[8] != ':' || chars[17] != '-' || chars[22] != '-' || chars[27] != '-' || chars[32] != '-') { return; } byte* ptr = stackalloc byte[16]; int num = 0; fixed (short* ptr2 = char2val) { short* ptr3 = ptr2; num = UnsafeDecode(ptr3, chars[15], chars[16]); *ptr = (byte)num; int num2 = 0 | num; num = UnsafeDecode(ptr3, chars[13], chars[14]); ptr[1] = (byte)num; int num3 = num2 | num; num = UnsafeDecode(ptr3, chars[11], chars[12]); ptr[2] = (byte)num; int num4 = num3 | num; num = UnsafeDecode(ptr3, chars[9], chars[10]); ptr[3] = (byte)num; int num5 = num4 | num; num = UnsafeDecode(ptr3, chars[20], chars[21]); ptr[4] = (byte)num; int num6 = num5 | num; num = UnsafeDecode(ptr3, chars[18], chars[19]); ptr[5] = (byte)num; int num7 = num6 | num; num = UnsafeDecode(ptr3, chars[25], chars[26]); ptr[6] = (byte)num; int num8 = num7 | num; num = UnsafeDecode(ptr3, chars[23], chars[24]); ptr[7] = (byte)num; int num9 = num8 | num; num = UnsafeDecode(ptr3, chars[28], chars[29]); ptr[8] = (byte)num; int num10 = num9 | num; num = UnsafeDecode(ptr3, chars[30], chars[31]); ptr[9] = (byte)num; int num11 = num10 | num; num = UnsafeDecode(ptr3, chars[33], chars[34]); ptr[10] = (byte)num; int num12 = num11 | num; num = UnsafeDecode(ptr3, chars[35], chars[36]); ptr[11] = (byte)num; int num13 = num12 | num; num = UnsafeDecode(ptr3, chars[37], chars[38]); ptr[12] = (byte)num; int num14 = num13 | num; num = UnsafeDecode(ptr3, chars[39], chars[40]); ptr[13] = (byte)num; int num15 = num14 | num; num = UnsafeDecode(ptr3, chars[41], chars[42]); ptr[14] = (byte)num; int num16 = num15 | num; num = UnsafeDecode(ptr3, chars[43], chars[44]); ptr[15] = (byte)num; if ((num16 | num) >= 256) { return; } idLow = UnsafeGetInt64(ptr); idHigh = UnsafeGetInt64(ptr + 8); } } [SecuritySafeCritical] public unsafe int ToCharArray(char[] chars, int offset) { int charArrayLength = CharArrayLength; if (chars == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative."))); } if (offset > chars.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", chars.Length))); } if (charArrayLength > chars.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("chars", System.Runtime.Serialization.SR.GetString("Array too small. Must be able to hold at least {0}.", charArrayLength))); } if (s != null) { s.CopyTo(0, chars, offset, charArrayLength); } else { byte* ptr = stackalloc byte[16]; UnsafeSetInt64(idLow, ptr); UnsafeSetInt64(idHigh, ptr + 8); fixed (char* ptr2 = &chars[offset]) { *ptr2 = 'u'; ptr2[1] = 'r'; ptr2[2] = 'n'; ptr2[3] = ':'; ptr2[4] = 'u'; ptr2[5] = 'u'; ptr2[6] = 'i'; ptr2[7] = 'd'; ptr2[8] = ':'; ptr2[17] = '-'; ptr2[22] = '-'; ptr2[27] = '-'; ptr2[32] = '-'; fixed (char* ptr3 = "0123456789abcdef") { char* ptr4 = ptr3; UnsafeEncode(ptr4, *ptr, ptr2 + 15); UnsafeEncode(ptr4, ptr[1], ptr2 + 13); UnsafeEncode(ptr4, ptr[2], ptr2 + 11); UnsafeEncode(ptr4, ptr[3], ptr2 + 9); UnsafeEncode(ptr4, ptr[4], ptr2 + 20); UnsafeEncode(ptr4, ptr[5], ptr2 + 18); UnsafeEncode(ptr4, ptr[6], ptr2 + 25); UnsafeEncode(ptr4, ptr[7], ptr2 + 23); UnsafeEncode(ptr4, ptr[8], ptr2 + 28); UnsafeEncode(ptr4, ptr[9], ptr2 + 30); UnsafeEncode(ptr4, ptr[10], ptr2 + 33); UnsafeEncode(ptr4, ptr[11], ptr2 + 35); UnsafeEncode(ptr4, ptr[12], ptr2 + 37); UnsafeEncode(ptr4, ptr[13], ptr2 + 39); UnsafeEncode(ptr4, ptr[14], ptr2 + 41); UnsafeEncode(ptr4, ptr[15], ptr2 + 43); } } } return charArrayLength; } public bool TryGetGuid(out Guid guid) { byte[] array = new byte[16]; if (!TryGetGuid(array, 0)) { guid = Guid.Empty; return false; } guid = new Guid(array); return true; } [SecuritySafeCritical] public unsafe bool TryGetGuid(byte[] buffer, int offset) { if (!IsGuid) { return false; } if (buffer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer")); } if (offset < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The value of this argument must be non-negative."))); } if (offset > buffer.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", System.Runtime.Serialization.SR.GetString("The specified offset exceeds the buffer size ({0} bytes).", buffer.Length))); } if (16 > buffer.Length - offset) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("buffer", System.Runtime.Serialization.SR.GetString("Array too small. Must be able to hold at least {0}.", 16))); } fixed (byte* ptr = &buffer[offset]) { UnsafeSetInt64(idLow, ptr); UnsafeSetInt64(idHigh, ptr + 8); } return true; } [SecuritySafeCritical] public override string ToString() { if (s == null) { int charArrayLength = CharArrayLength; char[] array = new char[charArrayLength]; ToCharArray(array, 0); s = new string(array, 0, charArrayLength); } return s; } public static bool operator ==(UniqueId id1, UniqueId id2) { if ((object)id1 == null && (object)id2 == null) { return true; } if ((object)id1 == null || (object)id2 == null) { return false; } if (id1.IsGuid && id2.IsGuid) { if (id1.idLow == id2.idLow) { return id1.idHigh == id2.idHigh; } return false; } return id1.ToString() == id2.ToString(); } public static bool operator !=(UniqueId id1, UniqueId id2) { return !(id1 == id2); } public override bool Equals(object obj) { return this == obj as UniqueId; } public override int GetHashCode() { if (IsGuid) { long num = idLow ^ idHigh; return (int)(num >> 32) ^ (int)num; } return ToString().GetHashCode(); } [SecurityCritical] private unsafe long UnsafeGetInt64(byte* pb) { int num = UnsafeGetInt32(pb); return ((long)UnsafeGetInt32(pb + 4) << 32) | (uint)num; } [SecurityCritical] private unsafe int UnsafeGetInt32(byte* pb) { return (((((pb[3] << 8) | pb[2]) << 8) | pb[1]) << 8) | *pb; } [SecurityCritical] private unsafe void UnsafeSetInt64(long value, byte* pb) { UnsafeSetInt32((int)value, pb); UnsafeSetInt32((int)(value >> 32), pb + 4); } [SecurityCritical] private unsafe void UnsafeSetInt32(int value, byte* pb) { *pb = (byte)value; value >>= 8; pb[1] = (byte)value; value >>= 8; pb[2] = (byte)value; value >>= 8; pb[3] = (byte)value; } } internal enum ValueHandleConstStringType { String, Number, Array, Object, Boolean, Null } internal static class ValueHandleLength { public const int Int8 = 1; public const int Int16 = 2; public const int Int32 = 4; public const int Int64 = 8; public const int UInt64 = 8; public const int Single = 4; public const int Double = 8; public const int Decimal = 16; public const int DateTime = 8; public const int TimeSpan = 8; public const int Guid = 16; public const int UniqueId = 16; } internal enum ValueHandleType { Empty, True, False, Zero, One, Int8, Int16, Int32, Int64, UInt64, Single, Double, Decimal, DateTime, TimeSpan, Guid, UniqueId, UTF8, EscapedUTF8, Base64, Dictionary, List, Char, Unicode, QName, ConstString } internal class ValueHandle { private XmlBufferReader bufferReader; private ValueHandleType type; private int offset; private int length; private static Base64Encoding base64Encoding; private static string[] constStrings = new string[6] { "string", "number", "array", "object", "boolean", "null" }; private static Base64Encoding Base64Encoding { get { if (base64Encoding == null) { base64Encoding = new Base64Encoding(); } return base64Encoding; } } public ValueHandle(XmlBufferReader bufferReader) { this.bufferReader = bufferReader; type = ValueHandleType.Empty; } public void SetConstantValue(ValueHandleConstStringType constStringType) { type = ValueHandleType.ConstString; offset = (int)constStringType; } public void SetValue(ValueHandleType type) { this.type = type; } public void SetDictionaryValue(int key) { SetValue(ValueHandleType.Dictionary, key, 0); } public void SetCharValue(int ch) { SetValue(ValueHandleType.Char, ch, 0); } public void SetQNameValue(int prefix, int key) { SetValue(ValueHandleType.QName, key, prefix); } public void SetValue(ValueHandleType type, int offset, int length) { this.type = type; this.offset = offset; this.length = length; } public bool IsWhitespace() { switch (type) { case ValueHandleType.UTF8: return bufferReader.IsWhitespaceUTF8(offset, length); case ValueHandleType.Dictionary: return bufferReader.IsWhitespaceKey(offset); case ValueHandleType.Char: { int @char = GetChar(); if (@char > 65535) { return false; } return XmlConverter.IsWhitespace((char)@char); } case ValueHandleType.EscapedUTF8: return bufferReader.IsWhitespaceUTF8(offset, length); case ValueHandleType.Unicode: return bufferReader.IsWhitespaceUnicode(offset, length); case ValueHandleType.True: case ValueHandleType.False: case ValueHandleType.Zero: case ValueHandleType.One: return false; case ValueHandleType.ConstString: return constStrings[offset].Length == 0; default: return length == 0; } } public Type ToType() { switch (type) { case ValueHandleType.True: case ValueHandleType.False: return typeof(bool); case ValueHandleType.Zero: case ValueHandleType.One: case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: return typeof(int); case ValueHandleType.Int64: return typeof(long); case ValueHandleType.UInt64: return typeof(ulong); case ValueHandleType.Single: return typeof(float); case ValueHandleType.Double: return typeof(double); case ValueHandleType.Decimal: return typeof(decimal); case ValueHandleType.DateTime: return typeof(DateTime); case ValueHandleType.Empty: case ValueHandleType.UTF8: case ValueHandleType.EscapedUTF8: case ValueHandleType.Dictionary: case ValueHandleType.Char: case ValueHandleType.Unicode: case ValueHandleType.QName: case ValueHandleType.ConstString: return typeof(string); case ValueHandleType.Base64: return typeof(byte[]); case ValueHandleType.List: return typeof(object[]); case ValueHandleType.UniqueId: return typeof(UniqueId); case ValueHandleType.Guid: return typeof(Guid); case ValueHandleType.TimeSpan: return typeof(TimeSpan); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); } } public bool ToBoolean() { switch (type) { case ValueHandleType.False: return false; case ValueHandleType.True: return true; case ValueHandleType.UTF8: return XmlConverter.ToBoolean(bufferReader.Buffer, offset, length); case ValueHandleType.Int8: switch (GetInt8()) { case 0: return false; case 1: return true; } break; } return XmlConverter.ToBoolean(GetString()); } public int ToInt() { ValueHandleType valueHandleType = type; switch (valueHandleType) { case ValueHandleType.Zero: return 0; case ValueHandleType.One: return 1; case ValueHandleType.Int8: return GetInt8(); case ValueHandleType.Int16: return GetInt16(); case ValueHandleType.Int32: return GetInt32(); case ValueHandleType.Int64: { long @int = GetInt64(); if (@int >= int.MinValue && @int <= int.MaxValue) { return (int)@int; } break; } } if (valueHandleType == ValueHandleType.UInt64) { ulong uInt = GetUInt64(); if (uInt <= int.MaxValue) { return (int)uInt; } } if (valueHandleType == ValueHandleType.UTF8) { return XmlConverter.ToInt32(bufferReader.Buffer, offset, length); } return XmlConverter.ToInt32(GetString()); } public long ToLong() { ValueHandleType valueHandleType = type; switch (valueHandleType) { case ValueHandleType.Zero: return 0L; case ValueHandleType.One: return 1L; case ValueHandleType.Int8: return GetInt8(); case ValueHandleType.Int16: return GetInt16(); case ValueHandleType.Int32: return GetInt32(); case ValueHandleType.Int64: return GetInt64(); case ValueHandleType.UInt64: { ulong uInt = GetUInt64(); if (uInt <= long.MaxValue) { return (long)uInt; } break; } } if (valueHandleType == ValueHandleType.UTF8) { return XmlConverter.ToInt64(bufferReader.Buffer, offset, length); } return XmlConverter.ToInt64(GetString()); } public ulong ToULong() { ValueHandleType valueHandleType = type; switch (valueHandleType) { case ValueHandleType.Zero: return 0uL; case ValueHandleType.One: return 1uL; case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: case ValueHandleType.Int64: { long num = ToLong(); if (num >= 0) { return (ulong)num; } break; } } return valueHandleType switch { ValueHandleType.UInt64 => GetUInt64(), ValueHandleType.UTF8 => XmlConverter.ToUInt64(bufferReader.Buffer, offset, length), _ => XmlConverter.ToUInt64(GetString()), }; } public float ToSingle() { ValueHandleType valueHandleType = type; switch (valueHandleType) { case ValueHandleType.Single: return GetSingle(); case ValueHandleType.Double: { double @double = GetDouble(); if ((@double >= -3.4028234663852886E+38 && @double <= 3.4028234663852886E+38) || double.IsInfinity(@double) || double.IsNaN(@double)) { return (float)@double; } break; } } return valueHandleType switch { ValueHandleType.Zero => 0f, ValueHandleType.One => 1f, ValueHandleType.Int8 => GetInt8(), ValueHandleType.Int16 => GetInt16(), ValueHandleType.UTF8 => XmlConverter.ToSingle(bufferReader.Buffer, offset, length), _ => XmlConverter.ToSingle(GetString()), }; } public double ToDouble() { return type switch { ValueHandleType.Double => GetDouble(), ValueHandleType.Single => GetSingle(), ValueHandleType.Zero => 0.0, ValueHandleType.One => 1.0, ValueHandleType.Int8 => GetInt8(), ValueHandleType.Int16 => GetInt16(), ValueHandleType.Int32 => GetInt32(), ValueHandleType.UTF8 => XmlConverter.ToDouble(bufferReader.Buffer, offset, length), _ => XmlConverter.ToDouble(GetString()), }; } public decimal ToDecimal() { ValueHandleType valueHandleType = type; switch (valueHandleType) { case ValueHandleType.Decimal: return GetDecimal(); case ValueHandleType.Zero: return 0m; case ValueHandleType.One: return 1m; case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: case ValueHandleType.Int64: return ToLong(); default: return valueHandleType switch { ValueHandleType.UInt64 => GetUInt64(), ValueHandleType.UTF8 => XmlConverter.ToDecimal(bufferReader.Buffer, offset, length), _ => XmlConverter.ToDecimal(GetString()), }; } } public DateTime ToDateTime() { if (type == ValueHandleType.DateTime) { return XmlConverter.ToDateTime(GetInt64()); } if (type == ValueHandleType.UTF8) { return XmlConverter.ToDateTime(bufferReader.Buffer, offset, length); } return XmlConverter.ToDateTime(GetString()); } public UniqueId ToUniqueId() { if (type == ValueHandleType.UniqueId) { return GetUniqueId(); } if (type == ValueHandleType.UTF8) { return XmlConverter.ToUniqueId(bufferReader.Buffer, offset, length); } return XmlConverter.ToUniqueId(GetString()); } public TimeSpan ToTimeSpan() { if (type == ValueHandleType.TimeSpan) { return new TimeSpan(GetInt64()); } if (type == ValueHandleType.UTF8) { return XmlConverter.ToTimeSpan(bufferReader.Buffer, offset, length); } return XmlConverter.ToTimeSpan(GetString()); } public Guid ToGuid() { if (type == ValueHandleType.Guid) { return GetGuid(); } if (type == ValueHandleType.UTF8) { return XmlConverter.ToGuid(bufferReader.Buffer, offset, length); } return XmlConverter.ToGuid(GetString()); } public override string ToString() { return GetString(); } public byte[] ToByteArray() { if (type == ValueHandleType.Base64) { byte[] array = new byte[length]; GetBase64(array, 0, length); return array; } if (type == ValueHandleType.UTF8 && length % 4 == 0) { try { int num = length / 4 * 3; if (length > 0 && bufferReader.Buffer[offset + length - 1] == 61) { num--; if (bufferReader.Buffer[offset + length - 2] == 61) { num--; } } byte[] array2 = new byte[num]; int bytes = Base64Encoding.GetBytes(bufferReader.Buffer, offset, length, array2, 0); if (bytes != array2.Length) { byte[] array3 = new byte[bytes]; Buffer.BlockCopy(array2, 0, array3, 0, bytes); array2 = array3; } return array2; } catch (FormatException) { } } try { return Base64Encoding.GetBytes(XmlConverter.StripWhitespace(GetString())); } catch (FormatException ex2) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(ex2.Message, ex2.InnerException)); } } public string GetString() { ValueHandleType valueHandleType = type; if (valueHandleType == ValueHandleType.UTF8) { return GetCharsText(); } switch (valueHandleType) { case ValueHandleType.False: return "false"; case ValueHandleType.True: return "true"; case ValueHandleType.Zero: return "0"; case ValueHandleType.One: return "1"; case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: return XmlConverter.ToString(ToInt()); case ValueHandleType.Int64: return XmlConverter.ToString(GetInt64()); case ValueHandleType.UInt64: return XmlConverter.ToString(GetUInt64()); case ValueHandleType.Single: return XmlConverter.ToString(GetSingle()); case ValueHandleType.Double: return XmlConverter.ToString(GetDouble()); case ValueHandleType.Decimal: return XmlConverter.ToString(GetDecimal()); case ValueHandleType.DateTime: return XmlConverter.ToString(ToDateTime()); case ValueHandleType.Empty: return string.Empty; case ValueHandleType.UTF8: return GetCharsText(); case ValueHandleType.Unicode: return GetUnicodeCharsText(); case ValueHandleType.EscapedUTF8: return GetEscapedCharsText(); case ValueHandleType.Char: return GetCharText(); case ValueHandleType.Dictionary: return GetDictionaryString().Value; case ValueHandleType.Base64: return Base64Encoding.GetString(ToByteArray()); case ValueHandleType.List: return XmlConverter.ToString(ToList()); case ValueHandleType.UniqueId: return XmlConverter.ToString(ToUniqueId()); case ValueHandleType.Guid: return XmlConverter.ToString(ToGuid()); case ValueHandleType.TimeSpan: return XmlConverter.ToString(ToTimeSpan()); case ValueHandleType.QName: return GetQNameDictionaryText(); case ValueHandleType.ConstString: return constStrings[offset]; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); } } public bool Equals2(string str, bool checkLower) { if (type != ValueHandleType.UTF8) { return GetString() == str; } if (length != str.Length) { return false; } byte[] buffer = bufferReader.Buffer; for (int i = 0; i < length; i++) { byte b = buffer[i + offset]; if (b != str[i] && (!checkLower || char.ToLowerInvariant((char)b) != str[i])) { return false; } } return true; } public void Sign(XmlSigningNodeWriter writer) { switch (type) { case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: writer.WriteInt32Text(ToInt()); break; case ValueHandleType.Int64: writer.WriteInt64Text(GetInt64()); break; case ValueHandleType.UInt64: writer.WriteUInt64Text(GetUInt64()); break; case ValueHandleType.Single: writer.WriteFloatText(GetSingle()); break; case ValueHandleType.Double: writer.WriteDoubleText(GetDouble()); break; case ValueHandleType.Decimal: writer.WriteDecimalText(GetDecimal()); break; case ValueHandleType.DateTime: writer.WriteDateTimeText(ToDateTime()); break; case ValueHandleType.UTF8: writer.WriteEscapedText(bufferReader.Buffer, offset, length); break; case ValueHandleType.Base64: writer.WriteBase64Text(bufferReader.Buffer, 0, bufferReader.Buffer, offset, length); break; case ValueHandleType.UniqueId: writer.WriteUniqueIdText(ToUniqueId()); break; case ValueHandleType.Guid: writer.WriteGuidText(ToGuid()); break; case ValueHandleType.TimeSpan: writer.WriteTimeSpanText(ToTimeSpan()); break; default: writer.WriteEscapedText(GetString()); break; case ValueHandleType.Empty: break; } } public object[] ToList() { return bufferReader.GetList(offset, length); } public object ToObject() { switch (type) { case ValueHandleType.True: case ValueHandleType.False: return ToBoolean(); case ValueHandleType.Zero: case ValueHandleType.One: case ValueHandleType.Int8: case ValueHandleType.Int16: case ValueHandleType.Int32: return ToInt(); case ValueHandleType.Int64: return ToLong(); case ValueHandleType.UInt64: return GetUInt64(); case ValueHandleType.Single: return ToSingle(); case ValueHandleType.Double: return ToDouble(); case ValueHandleType.Decimal: return ToDecimal(); case ValueHandleType.DateTime: return ToDateTime(); case ValueHandleType.Empty: case ValueHandleType.UTF8: case ValueHandleType.EscapedUTF8: case ValueHandleType.Dictionary: case ValueHandleType.Char: case ValueHandleType.Unicode: case ValueHandleType.ConstString: return ToString(); case ValueHandleType.Base64: return ToByteArray(); case ValueHandleType.List: return ToList(); case ValueHandleType.UniqueId: return ToUniqueId(); case ValueHandleType.Guid: return ToGuid(); case ValueHandleType.TimeSpan: return ToTimeSpan(); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); } } public bool TryReadBase64(byte[] buffer, int offset, int count, out int actual) { if (type == ValueHandleType.Base64) { actual = Math.Min(length, count); GetBase64(buffer, offset, actual); this.offset += actual; length -= actual; return true; } if (type == ValueHandleType.UTF8 && count >= 3 && length % 4 == 0) { try { int num = Math.Min(count / 3 * 4, length); actual = Base64Encoding.GetBytes(bufferReader.Buffer, this.offset, num, buffer, offset); this.offset += num; length -= num; return true; } catch (FormatException) { } } actual = 0; return false; } public bool TryReadChars(char[] chars, int offset, int count, out int actual) { if (type == ValueHandleType.Unicode) { return TryReadUnicodeChars(chars, offset, count, out actual); } if (type != ValueHandleType.UTF8) { actual = 0; return false; } int num = offset; int num2 = count; byte[] buffer = bufferReader.Buffer; int num3 = this.offset; int num4 = length; bool flag = false; while (true) { if (num2 > 0 && num4 > 0) { byte b = buffer[num3]; if (b < 128) { chars[num] = (char)b; num3++; num4--; num++; num2--; continue; } } if (num2 == 0 || num4 == 0 || flag) { break; } UTF8Encoding uTF8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); int chars2; int num5; try { if (num2 >= uTF8Encoding.GetMaxCharCount(num4) || num2 >= uTF8Encoding.GetCharCount(buffer, num3, num4)) { chars2 = uTF8Encoding.GetChars(buffer, num3, num4, chars, num); num5 = num4; } else { Decoder decoder = uTF8Encoding.GetDecoder(); num5 = Math.Min(num2, num4); chars2 = decoder.GetChars(buffer, num3, num5, chars, num); while (chars2 == 0) { if (num5 >= 3 && num2 < 2) { flag = true; break; } chars2 = decoder.GetChars(buffer, num3 + num5, 1, chars, num); num5++; } num5 = uTF8Encoding.GetByteCount(chars, num, chars2); } } catch (FormatException exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, num3, num4, exception)); } num3 += num5; num4 -= num5; num += chars2; num2 -= chars2; } this.offset = num3; length = num4; actual = count - num2; return true; } private bool TryReadUnicodeChars(char[] chars, int offset, int count, out int actual) { int num = Math.Min(count, length / 2); for (int i = 0; i < num; i++) { chars[offset + i] = (char)bufferReader.GetInt16(this.offset + i * 2); } this.offset += num * 2; length -= num * 2; actual = num; return true; } public bool TryGetDictionaryString(out XmlDictionaryString value) { if (type == ValueHandleType.Dictionary) { value = GetDictionaryString(); return true; } value = null; return false; } public bool TryGetByteArrayLength(out int length) { if (type == ValueHandleType.Base64) { length = this.length; return true; } length = 0; return false; } private string GetCharsText() { if (length == 1 && bufferReader.GetByte(offset) == 49) { return "1"; } return bufferReader.GetString(offset, length); } private string GetUnicodeCharsText() { return bufferReader.GetUnicodeString(offset, length); } private string GetEscapedCharsText() { return bufferReader.GetEscapedString(offset, length); } private string GetCharText() { int @char = GetChar(); if (@char > 65535) { SurrogateChar surrogateChar = new SurrogateChar(@char); return new string(new char[2] { surrogateChar.HighChar, surrogateChar.LowChar }, 0, 2); } return ((char)@char).ToString(); } private int GetChar() { return offset; } private int GetInt8() { return bufferReader.GetInt8(offset); } private int GetInt16() { return bufferReader.GetInt16(offset); } private int GetInt32() { return bufferReader.GetInt32(offset); } private long GetInt64() { return bufferReader.GetInt64(offset); } private ulong GetUInt64() { return bufferReader.GetUInt64(offset); } private float GetSingle() { return bufferReader.GetSingle(offset); } private double GetDouble() { return bufferReader.GetDouble(offset); } private decimal GetDecimal() { return bufferReader.GetDecimal(offset); } private UniqueId GetUniqueId() { return bufferReader.GetUniqueId(offset); } private Guid GetGuid() { return bufferReader.GetGuid(offset); } private void GetBase64(byte[] buffer, int offset, int count) { bufferReader.GetBase64(this.offset, buffer, offset, count); } private XmlDictionaryString GetDictionaryString() { return bufferReader.GetDictionaryString(offset); } private string GetQNameDictionaryText() { return PrefixHandle.GetString(PrefixHandle.GetAlphaPrefix(length)) + ":" + bufferReader.GetDictionaryString(offset); } } internal abstract class XmlBaseReader : XmlDictionaryReader { protected enum QNameType { Normal, Xmlns } protected class XmlNode { protected enum XmlNodeFlags { None = 0, CanGetAttribute = 1, CanMoveToElement = 2, HasValue = 4, AtomicValue = 8, SkipValue = 0x10, HasContent = 0x20 } private XmlNodeType nodeType; private PrefixHandle prefix; private StringHandle localName; private ValueHandle value; private Namespace ns; private bool hasValue; private bool canGetAttribute; private bool canMoveToElement; private ReadState readState; private XmlAttributeTextNode attributeTextNode; private bool exitScope; private int depthDelta; private bool isAtomicValue; private bool skipValue; private QNameType qnameType; private bool hasContent; private bool isEmptyElement; private char quoteChar; public bool HasValue => hasValue; public ReadState ReadState => readState; public StringHandle LocalName => localName; public PrefixHandle Prefix => prefix; public bool CanGetAttribute => canGetAttribute; public bool CanMoveToElement => canMoveToElement; public XmlAttributeTextNode AttributeText => attributeTextNode; public bool SkipValue => skipValue; public ValueHandle Value => value; public int DepthDelta => depthDelta; public bool HasContent => hasContent; public XmlNodeType NodeType { get { return nodeType; } set { nodeType = value; } } public QNameType QNameType { get { return qnameType; } set { qnameType = value; } } public Namespace Namespace { get { return ns; } set { ns = value; } } public bool IsAtomicValue { get { return isAtomicValue; } set { isAtomicValue = value; } } public bool ExitScope { get { return exitScope; } set { exitScope = value; } } public bool IsEmptyElement { get { return isEmptyElement; } set { isEmptyElement = value; } } public char QuoteChar { get { return quoteChar; } set { quoteChar = value; } } public string ValueAsString { get { if (qnameType == QNameType.Normal) { return Value.GetString(); } return Namespace.Uri.GetString(); } } protected XmlNode(XmlNodeType nodeType, PrefixHandle prefix, StringHandle localName, ValueHandle value, XmlNodeFlags nodeFlags, ReadState readState, XmlAttributeTextNode attributeTextNode, int depthDelta) { this.nodeType = nodeType; this.prefix = prefix; this.localName = localName; this.value = value; ns = NamespaceManager.EmptyNamespace; hasValue = (nodeFlags & XmlNodeFlags.HasValue) != 0; canGetAttribute = (nodeFlags & XmlNodeFlags.CanGetAttribute) != 0; canMoveToElement = (nodeFlags & XmlNodeFlags.CanMoveToElement) != 0; isAtomicValue = (nodeFlags & XmlNodeFlags.AtomicValue) != 0; skipValue = (nodeFlags & XmlNodeFlags.SkipValue) != 0; hasContent = (nodeFlags & XmlNodeFlags.HasContent) != 0; this.readState = readState; this.attributeTextNode = attributeTextNode; exitScope = nodeType == XmlNodeType.EndElement; this.depthDelta = depthDelta; isEmptyElement = false; quoteChar = '"'; qnameType = QNameType.Normal; } public bool IsLocalName(string localName) { if (qnameType == QNameType.Normal) { return LocalName == localName; } return Namespace.Prefix == localName; } public bool IsLocalName(XmlDictionaryString localName) { if (qnameType == QNameType.Normal) { return LocalName == localName; } return Namespace.Prefix == localName; } public bool IsNamespaceUri(string ns) { if (qnameType == QNameType.Normal) { return Namespace.IsUri(ns); } return ns == "http://www.w3.org/2000/xmlns/"; } public bool IsNamespaceUri(XmlDictionaryString ns) { if (qnameType == QNameType.Normal) { return Namespace.IsUri(ns); } return ns.Value == "http://www.w3.org/2000/xmlns/"; } public bool IsLocalNameAndNamespaceUri(string localName, string ns) { if (qnameType == QNameType.Normal) { if (LocalName == localName) { return Namespace.IsUri(ns); } return false; } if (Namespace.Prefix == localName) { return ns == "http://www.w3.org/2000/xmlns/"; } return false; } public bool IsLocalNameAndNamespaceUri(XmlDictionaryString localName, XmlDictionaryString ns) { if (qnameType == QNameType.Normal) { if (LocalName == localName) { return Namespace.IsUri(ns); } return false; } if (Namespace.Prefix == localName) { return ns.Value == "http://www.w3.org/2000/xmlns/"; } return false; } public bool IsPrefixAndLocalName(string prefix, string localName) { if (qnameType == QNameType.Normal) { if (Prefix == prefix) { return LocalName == localName; } return false; } if (prefix == "xmlns") { return Namespace.Prefix == localName; } return false; } public bool TryGetLocalNameAsDictionaryString(out XmlDictionaryString localName) { if (qnameType == QNameType.Normal) { return LocalName.TryGetDictionaryString(out localName); } localName = null; return false; } public bool TryGetNamespaceUriAsDictionaryString(out XmlDictionaryString ns) { if (qnameType == QNameType.Normal) { return Namespace.Uri.TryGetDictionaryString(out ns); } ns = null; return false; } public bool TryGetValueAsDictionaryString(out XmlDictionaryString value) { if (qnameType == QNameType.Normal) { return Value.TryGetDictionaryString(out value); } value = null; return false; } } protected class XmlElementNode : XmlNode { private XmlEndElementNode endElementNode; private int bufferOffset; public int NameOffset; public int NameLength; public XmlEndElementNode EndElement => endElementNode; public int BufferOffset { get { return bufferOffset; } set { bufferOffset = value; } } public XmlElementNode(XmlBufferReader bufferReader) : this(new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader)) { } private XmlElementNode(PrefixHandle prefix, StringHandle localName, ValueHandle value) : base(XmlNodeType.Element, prefix, localName, value, (XmlNodeFlags)33, ReadState.Interactive, null, -1) { endElementNode = new XmlEndElementNode(prefix, localName, value); } } protected class XmlAttributeNode : XmlNode { public XmlAttributeNode(XmlBufferReader bufferReader) : this(new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader)) { } private XmlAttributeNode(PrefixHandle prefix, StringHandle localName, ValueHandle value) : base(XmlNodeType.Attribute, prefix, localName, value, (XmlNodeFlags)15, ReadState.Interactive, new XmlAttributeTextNode(prefix, localName, value), 0) { } } protected class XmlEndElementNode : XmlNode { public XmlEndElementNode(PrefixHandle prefix, StringHandle localName, ValueHandle value) : base(XmlNodeType.EndElement, prefix, localName, value, XmlNodeFlags.HasContent, ReadState.Interactive, null, -1) { } } protected class XmlTextNode : XmlNode { protected XmlTextNode(XmlNodeType nodeType, PrefixHandle prefix, StringHandle localName, ValueHandle value, XmlNodeFlags nodeFlags, ReadState readState, XmlAttributeTextNode attributeTextNode, int depthDelta) : base(nodeType, prefix, localName, value, nodeFlags, readState, attributeTextNode, depthDelta) { } } protected class XmlAtomicTextNode : XmlTextNode { public XmlAtomicTextNode(XmlBufferReader bufferReader) : base(XmlNodeType.Text, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)60, ReadState.Interactive, null, 0) { } } protected class XmlComplexTextNode : XmlTextNode { public XmlComplexTextNode(XmlBufferReader bufferReader) : base(XmlNodeType.Text, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)36, ReadState.Interactive, null, 0) { } } protected class XmlWhitespaceTextNode : XmlTextNode { public XmlWhitespaceTextNode(XmlBufferReader bufferReader) : base(XmlNodeType.Whitespace, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.HasValue, ReadState.Interactive, null, 0) { } } protected class XmlCDataNode : XmlTextNode { public XmlCDataNode(XmlBufferReader bufferReader) : base(XmlNodeType.CDATA, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), (XmlNodeFlags)36, ReadState.Interactive, null, 0) { } } protected class XmlAttributeTextNode : XmlTextNode { public XmlAttributeTextNode(PrefixHandle prefix, StringHandle localName, ValueHandle value) : base(XmlNodeType.Text, prefix, localName, value, (XmlNodeFlags)47, ReadState.Interactive, null, 1) { } } protected class XmlInitialNode : XmlNode { public XmlInitialNode(XmlBufferReader bufferReader) : base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.Initial, null, 0) { } } protected class XmlDeclarationNode : XmlNode { public XmlDeclarationNode(XmlBufferReader bufferReader) : base(XmlNodeType.XmlDeclaration, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.CanGetAttribute, ReadState.Interactive, null, 0) { } } protected class XmlCommentNode : XmlNode { public XmlCommentNode(XmlBufferReader bufferReader) : base(XmlNodeType.Comment, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.HasValue, ReadState.Interactive, null, 0) { } } protected class XmlEndOfFileNode : XmlNode { public XmlEndOfFileNode(XmlBufferReader bufferReader) : base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.EndOfFile, null, 0) { } } protected class XmlClosedNode : XmlNode { public XmlClosedNode(XmlBufferReader bufferReader) : base(XmlNodeType.None, new PrefixHandle(bufferReader), new StringHandle(bufferReader), new ValueHandle(bufferReader), XmlNodeFlags.None, ReadState.Closed, null, 0) { } } private class AttributeSorter : IComparer { private object[] indeces; private XmlAttributeNode[] attributeNodes; private int attributeCount; private int attributeIndex1; private int attributeIndex2; public bool Sort(XmlAttributeNode[] attributeNodes, int attributeCount) { attributeIndex1 = -1; attributeIndex2 = -1; this.attributeNodes = attributeNodes; this.attributeCount = attributeCount; bool result = Sort(); this.attributeNodes = null; this.attributeCount = 0; return result; } public void GetIndeces(out int attributeIndex1, out int attributeIndex2) { attributeIndex1 = this.attributeIndex1; attributeIndex2 = this.attributeIndex2; } public void Close() { if (indeces != null && indeces.Length > 32) { indeces = null; } } private bool Sort() { if (indeces != null && indeces.Length == attributeCount && IsSorted()) { return true; } object[] array = new object[attributeCount]; for (int i = 0; i < array.Length; i++) { array[i] = i; } indeces = array; Array.Sort(indeces, 0, attributeCount, this); return IsSorted(); } private bool IsSorted() { for (int i = 0; i < indeces.Length - 1; i++) { if (Compare(indeces[i], indeces[i + 1]) >= 0) { attributeIndex1 = (int)indeces[i]; attributeIndex2 = (int)indeces[i + 1]; return false; } } return true; } public int Compare(object obj1, object obj2) { int num = (int)obj1; int num2 = (int)obj2; XmlAttributeNode xmlAttributeNode = attributeNodes[num]; XmlAttributeNode xmlAttributeNode2 = attributeNodes[num2]; int num3 = CompareQNameType(xmlAttributeNode.QNameType, xmlAttributeNode2.QNameType); if (num3 == 0) { if (xmlAttributeNode.QNameType == QNameType.Normal) { num3 = xmlAttributeNode.LocalName.CompareTo(xmlAttributeNode2.LocalName); if (num3 == 0) { num3 = xmlAttributeNode.Namespace.Uri.CompareTo(xmlAttributeNode2.Namespace.Uri); } } else { num3 = xmlAttributeNode.Namespace.Prefix.CompareTo(xmlAttributeNode2.Namespace.Prefix); } } return num3; } public int CompareQNameType(QNameType type1, QNameType type2) { return type1 - type2; } } private class NamespaceManager { private class XmlAttribute { private XmlSpace space; private string lang; private int depth; public int Depth { get { return depth; } set { depth = value; } } public string XmlLang { get { return lang;
plugins/LiteDB.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.AccessControl; using System.Security.Cryptography; using System.Security.Permissions; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using LiteDB.Engine; using LiteDB.Utils; using LiteDB.Utils.Extensions; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("LiteDB.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010029e66990e22110ce40a7197e37f8f82df3332c399e696df7f27d09e14ee590ac2dda735d4777fe554c427540bde93b14d3d26c04731c963383dcaa18859c8cbcd4a1a9c394d1204f474c2ab6f23a2eaadf81eb8a7a3d3cc73658868b0302163b92a2614ca050ab703be33c3e1d76f55b11f4f87cb73558f3aa69c1ce726d9ee8")] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Maurício David")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("MIT")] [assembly: AssemblyDescription("LiteDB - A lightweight embedded .NET NoSQL document store in a single datafile")] [assembly: AssemblyFileVersion("5.0.21")] [assembly: AssemblyInformationalVersion("5.0.21+391cc9318c5be6e56cb71b3ce14b1ed9cb324763")] [assembly: AssemblyProduct("LiteDB")] [assembly: AssemblyTitle("LiteDB")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mbdavid/LiteDB")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("5.0.21.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } 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; } } [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 LiteDB { public sealed class LiteCollection<T> : ILiteCollection<T> { private readonly string _collection; private readonly ILiteEngine _engine; private readonly List<BsonExpression> _includes; private readonly BsonMapper _mapper; private readonly EntityMapper _entity; private readonly MemberMapper _id; private readonly BsonAutoId _autoId; public string Name => _collection; public BsonAutoId AutoId => _autoId; public EntityMapper EntityMapper => _entity; public int Count() { return Query().Count(); } public int Count(BsonExpression predicate) { if (predicate == null) { throw new ArgumentNullException("predicate"); } return Query().Where(predicate).Count(); } public int Count(string predicate, BsonDocument parameters) { return Count(BsonExpression.Create(predicate, parameters)); } public int Count(string predicate, params BsonValue[] args) { return Count(BsonExpression.Create(predicate, args)); } public int Count(Expression<Func<T, bool>> predicate) { return Count(_mapper.GetExpression(predicate)); } public int Count(Query query) { return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count(); } public long LongCount() { return Query().LongCount(); } public long LongCount(BsonExpression predicate) { if (predicate == null) { throw new ArgumentNullException("predicate"); } return Query().Where(predicate).LongCount(); } public long LongCount(string predicate, BsonDocument parameters) { return LongCount(BsonExpression.Create(predicate, parameters)); } public long LongCount(string predicate, params BsonValue[] args) { return LongCount(BsonExpression.Create(predicate, args)); } public long LongCount(Expression<Func<T, bool>> predicate) { return LongCount(_mapper.GetExpression(predicate)); } public long LongCount(Query query) { return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count(); } public bool Exists(BsonExpression predicate) { if (predicate == null) { throw new ArgumentNullException("predicate"); } return Query().Where(predicate).Exists(); } public bool Exists(string predicate, BsonDocument parameters) { return Exists(BsonExpression.Create(predicate, parameters)); } public bool Exists(string predicate, params BsonValue[] args) { return Exists(BsonExpression.Create(predicate, args)); } public bool Exists(Expression<Func<T, bool>> predicate) { return Exists(_mapper.GetExpression(predicate)); } public bool Exists(Query query) { return new LiteQueryable<T>(_engine, _mapper, _collection, query).Exists(); } public BsonValue Min(BsonExpression keySelector) { if (string.IsNullOrEmpty(keySelector)) { throw new ArgumentNullException("keySelector"); } BsonDocument bsonDocument = Query().OrderBy(keySelector).Select(keySelector).ToDocuments() .First(); return bsonDocument[bsonDocument.Keys.First()]; } public BsonValue Min() { return Min("_id"); } public K Min<K>(Expression<Func<T, K>> keySelector) { if (keySelector == null) { throw new ArgumentNullException("keySelector"); } BsonExpression expression = _mapper.GetExpression(keySelector); BsonValue value = Min(expression); return (K)_mapper.Deserialize(typeof(K), value); } public BsonValue Max(BsonExpression keySelector) { if (string.IsNullOrEmpty(keySelector)) { throw new ArgumentNullException("keySelector"); } BsonDocument bsonDocument = Query().OrderByDescending(keySelector).Select(keySelector).ToDocuments() .First(); return bsonDocument[bsonDocument.Keys.First()]; } public BsonValue Max() { return Max("_id"); } public K Max<K>(Expression<Func<T, K>> keySelector) { if (keySelector == null) { throw new ArgumentNullException("keySelector"); } BsonExpression expression = _mapper.GetExpression(keySelector); BsonValue value = Max(expression); return (K)_mapper.Deserialize(typeof(K), value); } public bool Delete(BsonValue id) { if (id == null || id.IsNull) { throw new ArgumentNullException("id"); } return _engine.Delete(_collection, new BsonValue[1] { id }) == 1; } public int DeleteAll() { return _engine.DeleteMany(_collection, null); } public int DeleteMany(BsonExpression predicate) { if (predicate == null) { throw new ArgumentNullException("predicate"); } return _engine.DeleteMany(_collection, predicate); } public int DeleteMany(string predicate, BsonDocument parameters) { return DeleteMany(BsonExpression.Create(predicate, parameters)); } public int DeleteMany(string predicate, params BsonValue[] args) { return DeleteMany(BsonExpression.Create(predicate, args)); } public int DeleteMany(Expression<Func<T, bool>> predicate) { return DeleteMany(_mapper.GetExpression(predicate)); } public ILiteQueryable<T> Query() { return new LiteQueryable<T>(_engine, _mapper, _collection, new Query()).Include(_includes); } public IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue) { if (predicate == null) { throw new ArgumentNullException("predicate"); } return Query().Include(_includes).Where(predicate).Skip(skip) .Limit(limit) .ToEnumerable(); } public IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue) { if (query == null) { throw new ArgumentNullException("query"); } if (skip != 0) { query.Offset = skip; } if (limit != int.MaxValue) { query.Limit = limit; } return new LiteQueryable<T>(_engine, _mapper, _collection, query).ToEnumerable(); } public IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue) { return Find(_mapper.GetExpression(predicate), skip, limit); } public T FindById(BsonValue id) { if (id == null || id.IsNull) { throw new ArgumentNullException("id"); } return Find(BsonExpression.Create("_id = @0", id)).FirstOrDefault(); } public T FindOne(BsonExpression predicate) { return Find(predicate).FirstOrDefault(); } public T FindOne(string predicate, BsonDocument parameters) { return FindOne(BsonExpression.Create(predicate, parameters)); } public T FindOne(BsonExpression predicate, params BsonValue[] args) { return FindOne(BsonExpression.Create(predicate, args)); } public T FindOne(Expression<Func<T, bool>> predicate) { return FindOne(_mapper.GetExpression(predicate)); } public T FindOne(Query query) { return Find(query).FirstOrDefault(); } public IEnumerable<T> FindAll() { return Query().Include(_includes).ToEnumerable(); } public ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector) { if (keySelector == null) { throw new ArgumentNullException("keySelector"); } BsonExpression expression = _mapper.GetExpression(keySelector); return Include(expression); } public ILiteCollection<T> Include(BsonExpression keySelector) { if (string.IsNullOrEmpty(keySelector)) { throw new ArgumentNullException("keySelector"); } LiteCollection<T> liteCollection = new LiteCollection<T>(_collection, _autoId, _engine, _mapper); liteCollection._includes.AddRange(_includes); liteCollection._includes.Add(keySelector); return liteCollection; } public bool EnsureIndex(string name, BsonExpression expression, bool unique = false) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (expression == null) { throw new ArgumentNullException("expression"); } return _engine.EnsureIndex(_collection, name, expression, unique); } public bool EnsureIndex(BsonExpression expression, bool unique = false) { if (expression == null) { throw new ArgumentNullException("expression"); } string name = Regex.Replace(expression.Source, "[^a-z0-9]", "", RegexOptions.IgnoreCase | RegexOptions.Compiled); return EnsureIndex(name, expression, unique); } public bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false) { BsonExpression indexExpression = GetIndexExpression(keySelector); return EnsureIndex(indexExpression, unique); } public bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false) { BsonExpression indexExpression = GetIndexExpression(keySelector); return EnsureIndex(name, indexExpression, unique); } private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector) { BsonExpression bsonExpression = _mapper.GetIndexExpression(keySelector); if (typeof(K).IsEnumerable() && bsonExpression.IsScalar) { if (bsonExpression.Type != BsonExpressionType.Path) { throw new LiteException(0, "Expression `" + bsonExpression.Source + "` must return a enumerable expression"); } bsonExpression = bsonExpression.Source + "[*]"; } return bsonExpression; } public bool DropIndex(string name) { return _engine.DropIndex(_collection, name); } public BsonValue Insert(T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } BsonDocument bsonDocument = _mapper.ToDocument(entity); bool flag = RemoveDocId(bsonDocument); _engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId); BsonValue bsonValue = bsonDocument["_id"]; if (flag) { _id.Setter(entity, bsonValue.RawValue); } return bsonValue; } public void Insert(BsonValue id, T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } if (id == null || id.IsNull) { throw new ArgumentNullException("id"); } BsonDocument bsonDocument = _mapper.ToDocument(entity); bsonDocument["_id"] = id; _engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId); } public int Insert(IEnumerable<T> entities) { if (entities == null) { throw new ArgumentNullException("entities"); } return _engine.Insert(_collection, GetBsonDocs(entities), _autoId); } [Obsolete("Use normal Insert()")] public int InsertBulk(IEnumerable<T> entities, int batchSize = 5000) { if (entities == null) { throw new ArgumentNullException("entities"); } return _engine.Insert(_collection, GetBsonDocs(entities), _autoId); } private IEnumerable<BsonDocument> GetBsonDocs(IEnumerable<T> documents) { foreach (T document in documents) { BsonDocument doc = _mapper.ToDocument(document); bool removed = RemoveDocId(doc); yield return doc; if (removed && _id != null) { _id.Setter(document, doc["_id"].RawValue); } } } private bool RemoveDocId(BsonDocument doc) { if (_id != null && doc.TryGetValue("_id", out var value) && ((_autoId == BsonAutoId.Int32 && value.IsInt32 && value.AsInt32 == 0) || (_autoId == BsonAutoId.ObjectId && (value.IsNull || (value.IsObjectId && value.AsObjectId == ObjectId.Empty))) || (_autoId == BsonAutoId.Guid && value.IsGuid && value.AsGuid == Guid.Empty) || (_autoId == BsonAutoId.Int64 && value.IsInt64 && value.AsInt64 == 0L))) { doc.Remove("_id"); return true; } return false; } public bool Update(T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } BsonDocument bsonDocument = _mapper.ToDocument(entity); return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0; } public bool Update(BsonValue id, T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } if (id == null || id.IsNull) { throw new ArgumentNullException("id"); } BsonDocument bsonDocument = _mapper.ToDocument(entity); bsonDocument["_id"] = id; return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0; } public int Update(IEnumerable<T> entities) { if (entities == null) { throw new ArgumentNullException("entities"); } return _engine.Update(_collection, entities.Select((T x) => _mapper.ToDocument(x))); } public int UpdateMany(BsonExpression transform, BsonExpression predicate) { if (transform == null) { throw new ArgumentNullException("transform"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } if (transform.Type != BsonExpressionType.Document) { throw new ArgumentException("Extend expression must return a document. Eg: `col.UpdateMany('{ Name: UPPER(Name) }', 'Age > 10')`"); } return _engine.UpdateMany(_collection, transform, predicate); } public int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate) { if (extend == null) { throw new ArgumentNullException("extend"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } BsonExpression expression = _mapper.GetExpression(extend); BsonExpression expression2 = _mapper.GetExpression(predicate); if (expression.Type != BsonExpressionType.Document) { throw new ArgumentException("Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`"); } return _engine.UpdateMany(_collection, expression, expression2); } public bool Upsert(T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } return Upsert(new T[1] { entity }) == 1; } public int Upsert(IEnumerable<T> entities) { if (entities == null) { throw new ArgumentNullException("entities"); } return _engine.Upsert(_collection, GetBsonDocs(entities), _autoId); } public bool Upsert(BsonValue id, T entity) { if (entity == null) { throw new ArgumentNullException("entity"); } if (id == null || id.IsNull) { throw new ArgumentNullException("id"); } BsonDocument bsonDocument = _mapper.ToDocument(entity); bsonDocument["_id"] = id; return _engine.Upsert(_collection, new BsonDocument[1] { bsonDocument }, _autoId) > 0; } internal LiteCollection(string name, BsonAutoId autoId, ILiteEngine engine, BsonMapper mapper) { _collection = name ?? mapper.ResolveCollectionName(typeof(T)); _engine = engine; _mapper = mapper; _includes = new List<BsonExpression>(); if (typeof(T) == typeof(BsonDocument)) { _entity = null; _id = null; _autoId = autoId; return; } _entity = mapper.GetEntityMapper(typeof(T)); _id = _entity.Id; if (_id != null && _id.AutoId) { _autoId = ((_id.DataType == typeof(int) || _id.DataType == typeof(int?)) ? BsonAutoId.Int32 : ((_id.DataType == typeof(long) || _id.DataType == typeof(long?)) ? BsonAutoId.Int64 : ((_id.DataType == typeof(Guid) || _id.DataType == typeof(Guid?)) ? BsonAutoId.Guid : BsonAutoId.ObjectId))); } else { _autoId = autoId; } } } public interface ILiteCollection<T> { string Name { get; } BsonAutoId AutoId { get; } EntityMapper EntityMapper { get; } ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector); ILiteCollection<T> Include(BsonExpression keySelector); bool Upsert(T entity); int Upsert(IEnumerable<T> entities); bool Upsert(BsonValue id, T entity); bool Update(T entity); bool Update(BsonValue id, T entity); int Update(IEnumerable<T> entities); int UpdateMany(BsonExpression transform, BsonExpression predicate); int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate); BsonValue Insert(T entity); void Insert(BsonValue id, T entity); int Insert(IEnumerable<T> entities); int InsertBulk(IEnumerable<T> entities, int batchSize = 5000); bool EnsureIndex(string name, BsonExpression expression, bool unique = false); bool EnsureIndex(BsonExpression expression, bool unique = false); bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false); bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false); bool DropIndex(string name); ILiteQueryable<T> Query(); IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue); IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue); IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue); T FindById(BsonValue id); T FindOne(BsonExpression predicate); T FindOne(string predicate, BsonDocument parameters); T FindOne(BsonExpression predicate, params BsonValue[] args); T FindOne(Expression<Func<T, bool>> predicate); T FindOne(Query query); IEnumerable<T> FindAll(); bool Delete(BsonValue id); int DeleteAll(); int DeleteMany(BsonExpression predicate); int DeleteMany(string predicate, BsonDocument parameters); int DeleteMany(string predicate, params BsonValue[] args); int DeleteMany(Expression<Func<T, bool>> predicate); int Count(); int Count(BsonExpression predicate); int Count(string predicate, BsonDocument parameters); int Count(string predicate, params BsonValue[] args); int Count(Expression<Func<T, bool>> predicate); int Count(Query query); long LongCount(); long LongCount(BsonExpression predicate); long LongCount(string predicate, BsonDocument parameters); long LongCount(string predicate, params BsonValue[] args); long LongCount(Expression<Func<T, bool>> predicate); long LongCount(Query query); bool Exists(BsonExpression predicate); bool Exists(string predicate, BsonDocument parameters); bool Exists(string predicate, params BsonValue[] args); bool Exists(Expression<Func<T, bool>> predicate); bool Exists(Query query); BsonValue Min(BsonExpression keySelector); BsonValue Min(); K Min<K>(Expression<Func<T, K>> keySelector); BsonValue Max(BsonExpression keySelector); BsonValue Max(); K Max<K>(Expression<Func<T, K>> keySelector); } public interface ILiteDatabase : IDisposable { BsonMapper Mapper { get; } ILiteStorage<string> FileStorage { get; } int UserVersion { get; set; } TimeSpan Timeout { get; set; } bool UtcDate { get; set; } long LimitSize { get; set; } int CheckpointSize { get; set; } Collation Collation { get; } ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId); ILiteCollection<T> GetCollection<T>(); ILiteCollection<T> GetCollection<T>(BsonAutoId autoId); ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId); bool BeginTrans(); bool Commit(); bool Rollback(); ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks"); IEnumerable<string> GetCollectionNames(); bool CollectionExists(string name); bool DropCollection(string name); bool RenameCollection(string oldName, string newName); IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null); IBsonDataReader Execute(string command, BsonDocument parameters = null); IBsonDataReader Execute(string command, params BsonValue[] args); void Checkpoint(); long Rebuild(RebuildOptions options = null); BsonValue Pragma(string name); BsonValue Pragma(string name, BsonValue value); } public interface ILiteQueryable<T> : ILiteQueryableResult<T> { ILiteQueryable<T> Include(BsonExpression path); ILiteQueryable<T> Include(List<BsonExpression> paths); ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path); ILiteQueryable<T> Where(BsonExpression predicate); ILiteQueryable<T> Where(string predicate, BsonDocument parameters); ILiteQueryable<T> Where(string predicate, params BsonValue[] args); ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate); ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1); ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1); ILiteQueryable<T> OrderByDescending(BsonExpression keySelector); ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector); ILiteQueryable<T> GroupBy(BsonExpression keySelector); ILiteQueryable<T> Having(BsonExpression predicate); ILiteQueryableResult<BsonDocument> Select(BsonExpression selector); ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector); } public interface ILiteQueryableResult<T> { ILiteQueryableResult<T> Limit(int limit); ILiteQueryableResult<T> Skip(int offset); ILiteQueryableResult<T> Offset(int offset); ILiteQueryableResult<T> ForUpdate(); BsonDocument GetPlan(); IBsonDataReader ExecuteReader(); IEnumerable<BsonDocument> ToDocuments(); IEnumerable<T> ToEnumerable(); List<T> ToList(); T[] ToArray(); int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId); T First(); T FirstOrDefault(); T Single(); T SingleOrDefault(); int Count(); long LongCount(); bool Exists(); } public interface ILiteRepository : IDisposable { ILiteDatabase Database { get; } BsonValue Insert<T>(T entity, string collectionName = null); int Insert<T>(IEnumerable<T> entities, string collectionName = null); bool Update<T>(T entity, string collectionName = null); int Update<T>(IEnumerable<T> entities, string collectionName = null); bool Upsert<T>(T entity, string collectionName = null); int Upsert<T>(IEnumerable<T> entities, string collectionName = null); bool Delete<T>(BsonValue id, string collectionName = null); int DeleteMany<T>(BsonExpression predicate, string collectionName = null); int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null); ILiteQueryable<T> Query<T>(string collectionName = null); bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null); bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null); bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null); bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null); T SingleById<T>(BsonValue id, string collectionName = null); List<T> Fetch<T>(BsonExpression predicate, string collectionName = null); List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null); T First<T>(BsonExpression predicate, string collectionName = null); T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null); T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null); T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null); T Single<T>(BsonExpression predicate, string collectionName = null); T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null); T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null); T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null); } public class LiteDatabase : ILiteDatabase, IDisposable { private readonly ILiteEngine _engine; private readonly BsonMapper _mapper; private readonly bool _disposeOnClose; private ILiteStorage<string> _fs; public BsonMapper Mapper => _mapper; public ILiteStorage<string> FileStorage => _fs ?? (_fs = GetStorage<string>()); public int UserVersion { get { return _engine.Pragma("USER_VERSION"); } set { _engine.Pragma("USER_VERSION", value); } } public TimeSpan Timeout { get { return TimeSpan.FromSeconds(_engine.Pragma("TIMEOUT").AsInt32); } set { _engine.Pragma("TIMEOUT", (int)value.TotalSeconds); } } public bool UtcDate { get { return _engine.Pragma("UTC_DATE"); } set { _engine.Pragma("UTC_DATE", value); } } public long LimitSize { get { return _engine.Pragma("LIMIT_SIZE"); } set { _engine.Pragma("LIMIT_SIZE", value); } } public int CheckpointSize { get { return _engine.Pragma("CHECKPOINT"); } set { _engine.Pragma("CHECKPOINT", value); } } public Collation Collation => new Collation(_engine.Pragma("COLLATION").AsString); public LiteDatabase(string connectionString, BsonMapper mapper = null) : this(new ConnectionString(connectionString), mapper) { } public LiteDatabase(ConnectionString connectionString, BsonMapper mapper = null) { if (connectionString == null) { throw new ArgumentNullException("connectionString"); } _engine = connectionString.CreateEngine(); _mapper = mapper ?? BsonMapper.Global; _disposeOnClose = true; } public LiteDatabase(Stream stream, BsonMapper mapper = null, Stream logStream = null) { EngineSettings settings = new EngineSettings { DataStream = (stream ?? throw new ArgumentNullException("stream")), LogStream = logStream }; _engine = new LiteEngine(settings); _mapper = mapper ?? BsonMapper.Global; _disposeOnClose = true; } public LiteDatabase(ILiteEngine engine, BsonMapper mapper = null, bool disposeOnClose = true) { _engine = engine ?? throw new ArgumentNullException("engine"); _mapper = mapper ?? BsonMapper.Global; _disposeOnClose = disposeOnClose; } public ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId) { return new LiteCollection<T>(name, autoId, _engine, _mapper); } public ILiteCollection<T> GetCollection<T>() { return GetCollection<T>(null); } public ILiteCollection<T> GetCollection<T>(BsonAutoId autoId) { return GetCollection<T>(null, autoId); } public ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId) { if (name.IsNullOrWhiteSpace()) { throw new ArgumentNullException("name"); } return new LiteCollection<BsonDocument>(name, autoId, _engine, _mapper); } public bool BeginTrans() { return _engine.BeginTrans(); } public bool Commit() { return _engine.Commit(); } public bool Rollback() { return _engine.Rollback(); } public ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks") { return new LiteStorage<TFileId>(this, filesCollection, chunksCollection); } public IEnumerable<string> GetCollectionNames() { return (from x in GetCollection("$cols").Query().Where("type = 'user'").ToDocuments() select x["name"].AsString).ToArray(); } public bool CollectionExists(string name) { if (name.IsNullOrWhiteSpace()) { throw new ArgumentNullException("name"); } return GetCollectionNames().Contains<string>(name, StringComparer.OrdinalIgnoreCase); } public bool DropCollection(string name) { if (name.IsNullOrWhiteSpace()) { throw new ArgumentNullException("name"); } return _engine.DropCollection(name); } public bool RenameCollection(string oldName, string newName) { if (oldName.IsNullOrWhiteSpace()) { throw new ArgumentNullException("oldName"); } if (newName.IsNullOrWhiteSpace()) { throw new ArgumentNullException("newName"); } return _engine.RenameCollection(oldName, newName); } public IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null) { if (commandReader == null) { throw new ArgumentNullException("commandReader"); } Tokenizer tokenizer = new Tokenizer(commandReader); return new SqlParser(_engine, tokenizer, parameters).Execute(); } public IBsonDataReader Execute(string command, BsonDocument parameters = null) { if (command == null) { throw new ArgumentNullException("command"); } Tokenizer tokenizer = new Tokenizer(command); return new SqlParser(_engine, tokenizer, parameters).Execute(); } public IBsonDataReader Execute(string command, params BsonValue[] args) { BsonDocument bsonDocument = new BsonDocument(); int num = 0; foreach (BsonValue value in args) { bsonDocument[num.ToString()] = value; num++; } return Execute(command, bsonDocument); } public void Checkpoint() { _engine.Checkpoint(); } public long Rebuild(RebuildOptions options = null) { return _engine.Rebuild(options ?? new RebuildOptions()); } public BsonValue Pragma(string name) { return _engine.Pragma(name); } public BsonValue Pragma(string name, BsonValue value) { return _engine.Pragma(name, value); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } ~LiteDatabase() { Dispose(disposing: false); } protected virtual void Dispose(bool disposing) { if (disposing && _disposeOnClose) { _engine.Dispose(); } } } public class LiteQueryable<T> : ILiteQueryable<T>, ILiteQueryableResult<T> { protected readonly ILiteEngine _engine; protected readonly BsonMapper _mapper; protected readonly string _collection; protected readonly Query _query; private readonly bool _isSimpleType = Reflection.IsSimpleType(typeof(T)); internal LiteQueryable(ILiteEngine engine, BsonMapper mapper, string collection, Query query) { _engine = engine; _mapper = mapper; _collection = collection; _query = query; } public ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path) { _query.Includes.Add(_mapper.GetExpression(path)); return this; } public ILiteQueryable<T> Include(BsonExpression path) { _query.Includes.Add(path); return this; } public ILiteQueryable<T> Include(List<BsonExpression> paths) { _query.Includes.AddRange(paths); return this; } public ILiteQueryable<T> Where(BsonExpression predicate) { _query.Where.Add(predicate); return this; } public ILiteQueryable<T> Where(string predicate, BsonDocument parameters) { _query.Where.Add(BsonExpression.Create(predicate, parameters)); return this; } public ILiteQueryable<T> Where(string predicate, params BsonValue[] args) { _query.Where.Add(BsonExpression.Create(predicate, args)); return this; } public ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate) { return Where(_mapper.GetExpression(predicate)); } public ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1) { if (_query.OrderBy != null) { throw new ArgumentException("ORDER BY already defined in this query builder"); } _query.OrderBy = keySelector; _query.Order = order; return this; } public ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1) { return OrderBy(_mapper.GetExpression(keySelector), order); } public ILiteQueryable<T> OrderByDescending(BsonExpression keySelector) { return OrderBy(keySelector, -1); } public ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector) { return OrderBy(keySelector, -1); } public ILiteQueryable<T> GroupBy(BsonExpression keySelector) { if (_query.GroupBy != null) { throw new ArgumentException("GROUP BY already defined in this query"); } _query.GroupBy = keySelector; return this; } public ILiteQueryable<T> Having(BsonExpression predicate) { if (_query.Having != null) { throw new ArgumentException("HAVING already defined in this query"); } _query.Having = predicate; return this; } public ILiteQueryableResult<BsonDocument> Select(BsonExpression selector) { _query.Select = selector; return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query); } public ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector) { if (_query.GroupBy != null) { throw new ArgumentException("Use Select(BsonExpression selector) when using GroupBy query"); } _query.Select = _mapper.GetExpression(selector); return new LiteQueryable<K>(_engine, _mapper, _collection, _query); } public ILiteQueryableResult<T> ForUpdate() { _query.ForUpdate = true; return this; } public ILiteQueryableResult<T> Offset(int offset) { _query.Offset = offset; return this; } public ILiteQueryableResult<T> Skip(int offset) { return Offset(offset); } public ILiteQueryableResult<T> Limit(int limit) { _query.Limit = limit; return this; } public IBsonDataReader ExecuteReader() { _query.ExplainPlan = false; return _engine.Query(_collection, _query); } public IEnumerable<BsonDocument> ToDocuments() { using IBsonDataReader reader = ExecuteReader(); while (reader.Read()) { yield return reader.Current as BsonDocument; } } public IEnumerable<T> ToEnumerable() { if (_isSimpleType) { return from x in ToDocuments() select x[x.Keys.First()] into x select (T)_mapper.Deserialize(typeof(T), x); } return from x in ToDocuments() select (T)_mapper.Deserialize(typeof(T), x); } public List<T> ToList() { return ToEnumerable().ToList(); } public T[] ToArray() { return ToEnumerable().ToArray(); } public BsonDocument GetPlan() { _query.ExplainPlan = true; return _engine.Query(_collection, _query).ToEnumerable().FirstOrDefault()?.AsDocument; } public T Single() { return ToEnumerable().Single(); } public T SingleOrDefault() { return ToEnumerable().SingleOrDefault(); } public T First() { return ToEnumerable().First(); } public T FirstOrDefault() { return ToEnumerable().FirstOrDefault(); } public int Count() { BsonExpression select = _query.Select; try { Select("{ count: COUNT(*._id) }"); return ToDocuments().Single()["count"].AsInt32; } finally { _query.Select = select; } } public long LongCount() { BsonExpression select = _query.Select; try { Select("{ count: COUNT(*._id) }"); return ToDocuments().Single()["count"].AsInt64; } finally { _query.Select = select; } } public bool Exists() { BsonExpression select = _query.Select; try { Select("{ exists: ANY(*._id) }"); return ToDocuments().Single()["exists"].AsBoolean; } finally { _query.Select = select; } } public int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId) { _query.Into = newCollection; _query.IntoAutoId = autoId; using IBsonDataReader bsonDataReader = ExecuteReader(); return bsonDataReader.Current.AsInt32; } } public class LiteRepository : ILiteRepository, IDisposable { private readonly ILiteDatabase _db; public ILiteDatabase Database => _db; public LiteRepository(ILiteDatabase database) { _db = database; } public LiteRepository(string connectionString, BsonMapper mapper = null) { _db = new LiteDatabase(connectionString, mapper); } public LiteRepository(ConnectionString connectionString, BsonMapper mapper = null) { _db = new LiteDatabase(connectionString, mapper); } public LiteRepository(Stream stream, BsonMapper mapper = null, Stream logStream = null) { _db = new LiteDatabase(stream, mapper, logStream); } public BsonValue Insert<T>(T entity, string collectionName = null) { return _db.GetCollection<T>(collectionName).Insert(entity); } public int Insert<T>(IEnumerable<T> entities, string collectionName = null) { return _db.GetCollection<T>(collectionName).Insert(entities); } public bool Update<T>(T entity, string collectionName = null) { return _db.GetCollection<T>(collectionName).Update(entity); } public int Update<T>(IEnumerable<T> entities, string collectionName = null) { return _db.GetCollection<T>(collectionName).Update(entities); } public bool Upsert<T>(T entity, string collectionName = null) { return _db.GetCollection<T>(collectionName).Upsert(entity); } public int Upsert<T>(IEnumerable<T> entities, string collectionName = null) { return _db.GetCollection<T>(collectionName).Upsert(entities); } public bool Delete<T>(BsonValue id, string collectionName = null) { return _db.GetCollection<T>(collectionName).Delete(id); } public int DeleteMany<T>(BsonExpression predicate, string collectionName = null) { return _db.GetCollection<T>(collectionName).DeleteMany(predicate); } public int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return _db.GetCollection<T>(collectionName).DeleteMany(predicate); } public ILiteQueryable<T> Query<T>(string collectionName = null) { return _db.GetCollection<T>(collectionName).Query(); } public bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null) { return _db.GetCollection<T>(collectionName).EnsureIndex(name, expression, unique); } public bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null) { return _db.GetCollection<T>(collectionName).EnsureIndex(expression, unique); } public bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null) { return _db.GetCollection<T>(collectionName).EnsureIndex(keySelector, unique); } public bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null) { return _db.GetCollection<T>(collectionName).EnsureIndex(name, keySelector, unique); } public T SingleById<T>(BsonValue id, string collectionName = null) { return _db.GetCollection<T>(collectionName).Query().Where("_id = @0", id) .Single(); } public List<T> Fetch<T>(BsonExpression predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).ToList(); } public List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).ToList(); } public T First<T>(BsonExpression predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).First(); } public T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).First(); } public T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).FirstOrDefault(); } public T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).FirstOrDefault(); } public T Single<T>(BsonExpression predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).Single(); } public T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).Single(); } public T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).SingleOrDefault(); } public T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null) { return Query<T>(collectionName).Where(predicate).SingleOrDefault(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } ~LiteRepository() { Dispose(disposing: false); } protected virtual void Dispose(bool disposing) { if (disposing) { _db.Dispose(); } } } public class BsonCtorAttribute : Attribute { } public class BsonFieldAttribute : Attribute { public string Name { get; set; } public BsonFieldAttribute(string name) { Name = name; } public BsonFieldAttribute() { } } public class BsonIdAttribute : Attribute { public bool AutoId { get; private set; } public BsonIdAttribute() { AutoId = true; } public BsonIdAttribute(bool autoId) { AutoId = autoId; } } public class BsonIgnoreAttribute : Attribute { } public class BsonRefAttribute : Attribute { public string Collection { get; set; } public BsonRefAttribute(string collection) { Collection = collection; } public BsonRefAttribute() { Collection = null; } } public class BsonMapper { public delegate BsonValue DeserializationCallback(BsonMapper sender, Type target, BsonValue value); private readonly Dictionary<Type, EntityMapper> _entities = new Dictionary<Type, EntityMapper>(); private readonly ConcurrentDictionary<Type, Func<object, BsonValue>> _customSerializer = new ConcurrentDictionary<Type, Func<object, BsonValue>>(); private readonly ConcurrentDictionary<Type, Func<BsonValue, object>> _customDeserializer = new ConcurrentDictionary<Type, Func<BsonValue, object>>(); private readonly Func<Type, object> _typeInstantiator; private readonly ITypeNameBinder _typeNameBinder; public static BsonMapper Global = new BsonMapper(); public Func<string, string> ResolveFieldName; public Action<Type, MemberInfo, MemberMapper> ResolveMember; public Func<Type, string> ResolveCollectionName; private readonly Regex _lowerCaseDelimiter = new Regex("(?!(^[A-Z]))([A-Z])", RegexOptions.Compiled); private readonly HashSet<Type> _bsonTypes = new HashSet<Type> { typeof(string), typeof(int), typeof(long), typeof(bool), typeof(Guid), typeof(DateTime), typeof(byte[]), typeof(ObjectId), typeof(double), typeof(decimal) }; private readonly HashSet<Type> _basicTypes = new HashSet<Type> { typeof(short), typeof(ushort), typeof(uint), typeof(float), typeof(char), typeof(byte), typeof(sbyte) }; public bool SerializeNullValues { get; set; } public bool TrimWhitespace { get; set; } public bool EmptyStringToNull { get; set; } public bool EnumAsInteger { get; set; } public bool IncludeFields { get; set; } public bool IncludeNonPublic { get; set; } public int MaxDepth { get; set; } public DeserializationCallback? OnDeserialization { get; set; } public BsonMapper(Func<Type, object> customTypeInstantiator = null, ITypeNameBinder typeNameBinder = null) { SerializeNullValues = false; TrimWhitespace = true; EmptyStringToNull = true; EnumAsInteger = false; ResolveFieldName = (string s) => s; ResolveMember = delegate { }; ResolveCollectionName = (Type t) => (!Reflection.IsEnumerable(t)) ? t.Name : Reflection.GetListItemType(t).Name; IncludeFields = false; MaxDepth = 20; _typeInstantiator = customTypeInstantiator ?? ((Func<Type, object>)((Type t) => null)); _typeNameBinder = typeNameBinder ?? DefaultTypeNameBinder.Instance; RegisterType((Uri uri) => uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.ToString(), (BsonValue bson) => new Uri(bson.AsString)); RegisterType((DateTimeOffset value) => new BsonValue(value.UtcDateTime), (BsonValue bson) => bson.AsDateTime.ToUniversalTime()); RegisterType((TimeSpan value) => new BsonValue(value.Ticks), (BsonValue bson) => new TimeSpan(bson.AsInt64)); RegisterType((Regex r) => (r.Options != 0) ? new BsonDocument { { "p", r.ToString() }, { "o", (int)r.Options } } : new BsonValue(r.ToString()), (BsonValue value) => (!value.IsString) ? new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32) : new Regex(value)); } public void RegisterType<T>(Func<T, BsonValue> serialize, Func<BsonValue, T> deserialize) { _customSerializer[typeof(T)] = (object o) => serialize((T)o); _customDeserializer[typeof(T)] = (BsonValue b) => deserialize(b); } public void RegisterType(Type type, Func<object, BsonValue> serialize, Func<BsonValue, object> deserialize) { _customSerializer[type] = (object o) => serialize(o); _customDeserializer[type] = (BsonValue b) => deserialize(b); } public EntityBuilder<T> Entity<T>() { return new EntityBuilder<T>(this, _typeNameBinder); } public BsonExpression GetExpression<T, K>(Expression<Func<T, K>> predicate) { return new LinqExpressionVisitor(this, predicate).Resolve(typeof(K) == typeof(bool)); } public BsonExpression GetIndexExpression<T, K>(Expression<Func<T, K>> predicate) { return new LinqExpressionVisitor(this, predicate).Resolve(predicate: false); } public BsonMapper UseCamelCase() { ResolveFieldName = (string s) => char.ToLower(s[0]) + s.Substring(1); return this; } public BsonMapper UseLowerCaseDelimiter(char delimiter = '_') { ResolveFieldName = (string s) => _lowerCaseDelimiter.Replace(s, delimiter + "$2").ToLower(); return this; } internal EntityMapper GetEntityMapper(Type type) { if (!_entities.TryGetValue(type, out var value)) { lock (_entities) { if (!_entities.TryGetValue(type, out value)) { return BuildAddEntityMapper(type); } } } return value; } protected virtual EntityMapper BuildAddEntityMapper(Type type) { EntityMapper entityMapper = new EntityMapper(type); _entities[type] = entityMapper; Type typeFromHandle = typeof(BsonIdAttribute); Type typeFromHandle2 = typeof(BsonIgnoreAttribute); Type typeFromHandle3 = typeof(BsonFieldAttribute); Type typeFromHandle4 = typeof(BsonRefAttribute); IEnumerable<MemberInfo> typeMembers = GetTypeMembers(type); MemberInfo idMember = GetIdMember(typeMembers); foreach (MemberInfo item in typeMembers) { if (!CustomAttributeExtensions.IsDefined(item, typeFromHandle2, inherit: true)) { string name = ResolveFieldName(item.Name); BsonFieldAttribute bsonFieldAttribute = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle3, inherit: true).FirstOrDefault(); if (bsonFieldAttribute != null && bsonFieldAttribute.Name != null) { name = bsonFieldAttribute.Name; } if (item == idMember) { name = "_id"; } GenericGetter getter = Reflection.CreateGenericGetter(type, item); GenericSetter setter = Reflection.CreateGenericSetter(type, item); BsonIdAttribute bsonIdAttribute = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle, inherit: true).FirstOrDefault(); Type type2 = ((item is PropertyInfo) ? (item as PropertyInfo).PropertyType : (item as FieldInfo).FieldType); bool flag = Reflection.IsEnumerable(type2); MemberMapper memberMapper = new MemberMapper { AutoId = (bsonIdAttribute?.AutoId ?? true), FieldName = name, MemberName = item.Name, DataType = type2, IsEnumerable = flag, UnderlyingType = (flag ? Reflection.GetListItemType(type2) : type2), Getter = getter, Setter = setter }; BsonRefAttribute bsonRefAttribute = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle4, inherit: false).FirstOrDefault(); if (bsonRefAttribute != null && item is PropertyInfo) { RegisterDbRef(this, memberMapper, _typeNameBinder, bsonRefAttribute.Collection ?? ResolveCollectionName((item as PropertyInfo).PropertyType)); } ResolveMember?.Invoke(type, item, memberMapper); if (memberMapper.FieldName != null && !entityMapper.Members.Any((MemberMapper x) => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) && !memberMapper.IsIgnore) { entityMapper.Members.Add(memberMapper); } } } return entityMapper; } protected virtual MemberInfo GetIdMember(IEnumerable<MemberInfo> members) { return Reflection.SelectMember(members, (MemberInfo x) => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), inherit: true), (MemberInfo x) => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), (MemberInfo x) => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase)); } protected virtual IEnumerable<MemberInfo> GetTypeMembers(Type type) { List<MemberInfo> list = new List<MemberInfo>(); BindingFlags bindingAttr = (IncludeNonPublic ? (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : (BindingFlags.Instance | BindingFlags.Public)); list.AddRange((from x in type.GetProperties(bindingAttr) where x.CanRead && x.GetIndexParameters().Length == 0 select x).Select((Func<PropertyInfo, MemberInfo>)((PropertyInfo x) => x))); if (IncludeFields) { list.AddRange((from x in type.GetFields(bindingAttr) where !x.Name.EndsWith("k__BackingField") && !x.IsStatic select x).Select((Func<FieldInfo, MemberInfo>)((FieldInfo x) => x))); } return list; } protected virtual CreateObject GetTypeCtor(EntityMapper mapper) { Type type = mapper.ForType; List<CreateObject> list = new List<CreateObject>(); bool flag = false; ConstructorInfo[] constructors = type.GetConstructors(); foreach (ConstructorInfo constructorInfo in constructors) { ParameterInfo[] parameters = constructorInfo.GetParameters(); if (parameters.Length == 0) { flag = true; continue; } KeyValuePair<string, Type>[] paramMap = new KeyValuePair<string, Type>[parameters.Length]; int j; for (j = 0; j < parameters.Length; j++) { ParameterInfo parameterInfo = parameters[j]; MemberMapper memberMapper = null; foreach (MemberMapper member in mapper.Members) { if (member.MemberName.ToLower() == parameterInfo.Name.ToLower() && member.DataType == parameterInfo.ParameterType) { memberMapper = member; break; } } if (memberMapper == null) { break; } paramMap[j] = new KeyValuePair<string, Type>(memberMapper.FieldName, memberMapper.DataType); } if (j < parameters.Length) { continue; } CreateObject createObject = (BsonDocument value) => Activator.CreateInstance(type, paramMap.Select((KeyValuePair<string, Type> x) => Deserialize(x.Value, value[x.Key])).ToArray()); if (constructorInfo.GetCustomAttribute<BsonCtorAttribute>() != null) { return createObject; } list.Add(createObject); } if (flag) { return null; } return list.FirstOrDefault(); } internal static void RegisterDbRef(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection) { member.IsDbRef = true; if (member.IsEnumerable) { RegisterDbRefList(mapper, member, typeNameBinder, collection); } else { RegisterDbRefItem(mapper, member, typeNameBinder, collection); } } private static void RegisterDbRefItem(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection) { EntityMapper entity = mapper.GetEntityMapper(member.DataType); member.Serialize = delegate(object obj, BsonMapper m) { if (obj == null) { return BsonValue.Null; } object obj2 = (entity.Id ?? throw new LiteException(0, "There is no _id field mapped in your type: " + member.DataType.FullName)).Getter(obj); BsonDocument bsonDocument = new BsonDocument { ["$id"] = m.Serialize(obj2.GetType(), obj2, 0), ["$ref"] = collection }; if (member.DataType != obj.GetType()) { bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType()); } return bsonDocument; }; member.Deserialize = delegate(BsonValue bson, BsonMapper m) { if (bson == null || !bson.IsDocument) { return null; } BsonDocument asDocument = bson.AsDocument; BsonValue value = asDocument["$id"]; bool num = asDocument["$missing"] == true; bool flag = !asDocument.ContainsKey("$ref"); if (num) { return null; } if (flag) { asDocument["_id"] = value; if (asDocument.ContainsKey("$type")) { asDocument["_type"] = bson["$type"]; } return m.Deserialize(entity.ForType, asDocument); } return m.Deserialize(entity.ForType, asDocument.ContainsKey("$type") ? new BsonDocument { ["_id"] = value, ["_type"] = bson["$type"] } : new BsonDocument { ["_id"] = value }); }; } private static void RegisterDbRefList(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection) { EntityMapper entity = mapper.GetEntityMapper(member.UnderlyingType); member.Serialize = delegate(object list, BsonMapper m) { if (list == null) { return BsonValue.Null; } BsonArray bsonArray2 = new BsonArray(); MemberMapper id = entity.Id; foreach (object item in (IEnumerable)list) { if (item != null) { object obj = id.Getter(item); BsonDocument bsonDocument2 = new BsonDocument { ["$id"] = m.Serialize(obj.GetType(), obj, 0), ["$ref"] = collection }; if (member.UnderlyingType != item.GetType()) { bsonDocument2["$type"] = typeNameBinder.GetName(item.GetType()); } bsonArray2.Add(bsonDocument2); } } return bsonArray2; }; member.Deserialize = delegate(BsonValue bson, BsonMapper m) { if (!bson.IsArray) { return null; } BsonArray asArray = bson.AsArray; if (asArray.Count == 0) { return m.Deserialize(member.DataType, asArray); } BsonArray bsonArray = new BsonArray(); foreach (BsonValue item2 in asArray) { if (item2.IsDocument) { BsonDocument asDocument = item2.AsDocument; BsonValue value = asDocument["$id"]; bool flag = asDocument["$missing"] == true; bool flag2 = !asDocument.ContainsKey("$ref"); if (!flag) { if (flag2) { item2["_id"] = value; if (item2.AsDocument.ContainsKey("$type")) { item2["_type"] = item2["$type"]; } bsonArray.Add(item2); } else { BsonDocument bsonDocument = new BsonDocument { ["_id"] = value }; if (item2.AsDocument.ContainsKey("$type")) { bsonDocument["_type"] = item2["$type"]; } bsonArray.Add(bsonDocument); } } } } return m.Deserialize(member.DataType, bsonArray); }; } public virtual object ToObject(Type type, BsonDocument doc) { if (doc == null) { throw new ArgumentNullException("doc"); } if (type == typeof(BsonDocument)) { return doc; } return Deserialize(type, doc); } public virtual T ToObject<T>(BsonDocument doc) { return (T)ToObject(typeof(T), doc); } public T Deserialize<T>(BsonValue value) { if (value == null) { return default(T); } return (T)Deserialize(typeof(T), value); } public object Deserialize(Type type, BsonValue value) { if (OnDeserialization != null) { BsonValue bsonValue = OnDeserialization(this, type, value); if ((object)bsonValue != null) { value = bsonValue; } } if (value.IsNull) { return null; } if (Reflection.IsNullable(type)) { type = Reflection.UnderlyingTypeOf(type); } if (_customDeserializer.TryGetValue(type, out var value2)) { return value2(value); } TypeInfo typeInfo = type.GetTypeInfo(); if (type == typeof(BsonValue)) { return value; } if (type == typeof(BsonDocument)) { return value.AsDocument; } if (type == typeof(BsonArray)) { return value.AsArray; } if (_bsonTypes.Contains(type)) { return value.RawValue; } if (_basicTypes.Contains(type)) { return Convert.ChangeType(value.RawValue, type); } if (type == typeof(ulong)) { return (ulong)value.AsInt64; } if (typeInfo.IsEnum) { if (value.IsString) { return Enum.Parse(type, value.AsString); } if (value.IsNumber) { return Enum.ToObject(type, value.AsInt32); } } else { if (value.IsArray) { if (type == typeof(object)) { return DeserializeArray(typeof(object), value.AsArray); } if (type.IsArray) { return DeserializeArray(type.GetElementType(), value.AsArray); } return DeserializeList(type, value.AsArray); } if (value.IsDocument) { if (type.IsAnonymousType()) { return DeserializeAnonymousType(type, value.AsDocument); } BsonDocument asDocument = value.AsDocument; if (asDocument.TryGetValue("_type", out var value3) && value3.IsString) { Type type2 = _typeNameBinder.GetType(value3.AsString); if (type2 == null) { throw LiteException.InvalidTypedName(value3.AsString); } if (!type.IsAssignableFrom(type2)) { throw LiteException.DataTypeNotAssignable(type.FullName, type2.FullName); } type = type2; } else if (type == typeof(object)) { type = typeof(Dictionary<string, object>); } EntityMapper entity = GetEntityMapper(type); if (entity.CreateInstance == null) { entity.CreateInstance = GetTypeCtor(entity) ?? ((CreateObject)((BsonDocument v) => Reflection.CreateInstance(entity.ForType))); } object obj = _typeInstantiator(type) ?? entity.CreateInstance(asDocument); if (obj is IDictionary dict) { if (obj.GetType().GetTypeInfo().IsGenericType) { Type k = type.GetGenericArguments()[0]; Type t = type.GetGenericArguments()[1]; DeserializeDictionary(k, t, dict, value.AsDocument); } else { DeserializeDictionary(typeof(object), typeof(object), dict, value.AsDocument); } } else { DeserializeObject(entity, obj, asDocument); } return obj; } } return value.RawValue; } private object DeserializeArray(Type type, BsonArray array) { Array array2 = Array.CreateInstance(type, array.Count); int num = 0; foreach (BsonValue item in array) { array2.SetValue(Deserialize(type, item), num++); } return array2; } private object DeserializeList(Type type, BsonArray value) { Type listItemType = Reflection.GetListItemType(type); IEnumerable enumerable = (IEnumerable)Reflection.CreateInstance(type); if (enumerable is IList list) { foreach (BsonValue item in value) { list.Add(Deserialize(listItemType, item)); } } else { MethodInfo method = type.GetMethod("Add", new Type[1] { listItemType }); foreach (BsonValue item2 in value) { method.Invoke(enumerable, new object[1] { Deserialize(listItemType, item2) }); } } return enumerable; } private void DeserializeDictionary(Type K, Type T, IDictionary dict, BsonDocument value) { bool isEnum = K.GetTypeInfo().IsEnum; foreach (KeyValuePair<string, BsonValue> element in value.GetElements()) { object key = (isEnum ? Enum.Parse(K, element.Key) : ((K == typeof(Uri)) ? new Uri(element.Key) : Convert.ChangeType(element.Key, K))); object value2 = Deserialize(T, element.Value); dict.Add(key, value2); } } private void DeserializeObject(EntityMapper entity, object obj, BsonDocument value) { foreach (MemberMapper item in entity.Members.Where((MemberMapper x) => x.Setter != null)) { if (value.TryGetValue(item.FieldName, out var value2)) { if (item.Deserialize != null) { item.Setter(obj, item.Deserialize(value2, this)); } else { item.Setter(obj, Deserialize(item.DataType, value2)); } } } } private object DeserializeAnonymousType(Type type, BsonDocument value) { List<object> list = new List<object>(); ParameterInfo[] parameters = type.GetConstructors()[0].GetParameters(); foreach (ParameterInfo parameterInfo in parameters) { object obj = Deserialize(parameterInfo.ParameterType, value[parameterInfo.Name]); if (obj == null && StringComparer.OrdinalIgnoreCase.Equals(parameterInfo.Name, "Id") && value.TryGetValue("_id", out var value2)) { obj = Deserialize(parameterInfo.ParameterType, value2); } list.Add(obj); } return Activator.CreateInstance(type, list.ToArray()); } public virtual BsonDocument ToDocument(Type type, object entity) { if (entity == null) { throw new ArgumentNullException("entity"); } if (entity is BsonDocument) { return (BsonDocument)entity; } return Serialize(type, entity, 0).AsDocument; } public virtual BsonDocument ToDocument<T>(T entity) { return ToDocument(typeof(T), entity)?.AsDocument; } public BsonValue Serialize<T>(T obj) { return Serialize(typeof(T), obj, 0); } public BsonValue Serialize(Type type, object obj) { return Serialize(type, obj, 0); } internal BsonValue Serialize(Type type, object obj, int depth) { if (++depth > MaxDepth) { throw LiteException.DocumentMaxDepth(MaxDepth, type); } if (obj == null) { return BsonValue.Null; } if (obj is BsonValue result) { return result; } if (_customSerializer.TryGetValue(type, out var value) || _customSerializer.TryGetValue(obj.GetType(), out value)) { return value(obj); } if (obj is string) { string text = (TrimWhitespace ? (obj as string).Trim() : ((string)obj)); if (EmptyStringToNull && text.Length == 0) { return BsonValue.Null; } return new BsonValue(text); } if (obj is int) { return new BsonValue((int)obj); } if (obj is long) { return new BsonValue((long)obj); } if (obj is double) { return new BsonValue((double)obj); } if (obj is decimal) { return new BsonValue((decimal)obj); } if (obj is byte[]) { return new BsonValue((byte[])obj); } if (obj is ObjectId) { return new BsonValue((ObjectId)obj); } if (obj is Guid) { return new BsonValue((Guid)obj); } if (obj is bool) { return new BsonValue((bool)obj); } if (obj is DateTime) { return new BsonValue((DateTime)obj); } if (obj is short || obj is ushort || obj is byte || obj is sbyte) { return new BsonValue(Convert.ToInt32(obj)); } if (obj is uint) { return new BsonValue(Convert.ToInt64(obj)); } if (obj is ulong) { return new BsonValue((long)(ulong)obj); } if (obj is float) { return new BsonValue(Convert.ToDouble(obj)); } if (obj is char) { return new BsonValue(obj.ToString()); } if (obj is Enum) { if (EnumAsInteger) { return new BsonValue((int)obj); } return new BsonValue(obj.ToString()); } if (obj is IDictionary dict) { if (type == typeof(object)) { type = obj.GetType(); } Type type2 = (type.GetTypeInfo().IsGenericType ? type.GetGenericArguments()[1] : typeof(object)); return SerializeDictionary(type2, dict, depth); } if (obj is IEnumerable) { return SerializeArray(Reflection.GetListItemType(type), obj as IEnumerable, depth); } return SerializeObject(type, obj, depth); } private BsonArray SerializeArray(Type type, IEnumerable array, int depth) { BsonArray bsonArray = new BsonArray(); foreach (object item in array) { bsonArray.Add(Serialize(type, item, depth)); } return bsonArray; } private BsonDocument SerializeDictionary(Type type, IDictionary dict, int depth) { BsonDocument bsonDocument = new BsonDocument(); foreach (object key in dict.Keys) { object obj = dict[key]; string name = key.ToString(); if (key is DateTime dateTime) { name = dateTime.ToString("o"); } bsonDocument[name] = Serialize(type, obj, depth); } return bsonDocument; } private BsonDocument SerializeObject(Type type, object obj, int depth) { Type type2 = obj.GetType(); BsonDocument bsonDocument = new BsonDocument(); EntityMapper entityMapper = GetEntityMapper(type2); if (type != type2) { bsonDocument["_type"] = new BsonValue(_typeNameBinder.GetName(type2)); } foreach (MemberMapper item in entityMapper.Members.Where((MemberMapper x) => x.Getter != null)) { object obj2 = item.Getter(obj); if (obj2 != null || SerializeNullValues || !(item.FieldName != "_id")) { if (item.Serialize != null) { bsonDocument[item.FieldName] = item.Serialize(obj2, this); } else { bsonDocument[item.FieldName] = Serialize(item.DataType, obj2, depth); } } } return bsonDocument; } } public class EntityBuilder<T> { private readonly BsonMapper _mapper; private readonly EntityMapper _entity; private readonly ITypeNameBinder _typeNameBinder; internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder) { _mapper = mapper; _typeNameBinder = typeNameBinder; _entity = mapper.GetEntityMapper(typeof(T)); } public EntityBuilder<T> Ignore<K>(Expression<Func<T, K>> member) { return GetMember(member, delegate(MemberMapper p) { _entity.Members.Remove(p); }); } public EntityBuilder<T> Field<K>(Expression<Func<T, K>> member, string field) { if (field.IsNullOrWhiteSpace()) { throw new ArgumentNullException("field"); } return GetMember(member, delegate(MemberMapper p) { p.FieldName = field; }); } public EntityBuilder<T> Id<K>(Expression<Func<T, K>> member, bool autoId = true) { return GetMember(member, delegate(MemberMapper p) { MemberMapper memberMapper = _entity.Members.FirstOrDefault((MemberMapper x) => x.FieldName == "_id"); if (memberMapper != null) { memberMapper.FieldName = _mapper.ResolveFieldName(memberMapper.MemberName); memberMapper.AutoId = false; } p.FieldName = "_id"; p.AutoId = autoId; }); } public EntityBuilder<T> Ctor(Func<BsonDocument, T> createInstance) { _entity.CreateInstance = (BsonDocument v) => createInstance(v); return this; } public EntityBuilder<T> DbRef<K>(Expression<Func<T, K>> member, string collection = null) { return GetMember(member, delegate(MemberMapper p) { BsonMapper.RegisterDbRef(_mapper, p, _typeNameBinder, collection ?? _mapper.ResolveCollectionName(typeof(K))); }); } private EntityBuilder<T> GetMember<TK, K>(Expression<Func<TK, K>> member, Action<MemberMapper> action) { if (member == null) { throw new ArgumentNullException("member"); } MemberMapper member2 = _entity.GetMember(member); if (member2 == null) { throw new ArgumentNullException("Member '" + member.GetPath() + "' not found in type '" + _entity.ForType.Name + "' (use IncludeFields in BsonMapper)"); } action(member2); return this; } } public class EntityMapper { public Type ForType { get; } public List<MemberMapper> Members { get; } = new List<MemberMapper>(); public MemberMapper Id => Members.SingleOrDefault((MemberMapper x) => x.FieldName == "_id"); public CreateObject CreateInstance { get; set; } public EntityMapper(Type forType) { ForType = forType; } public MemberMapper GetMember(Expression expr) { return Members.FirstOrDefault((MemberMapper x) => x.MemberName == expr.GetPath()); } } internal class LinqExpressionVisitor : ExpressionVisitor { private static readonly Dictionary<Type, ITypeResolver> _resolver = new Dictionary<Type, ITypeResolver> { [typeof(BsonValue)] = new BsonValueResolver(), [typeof(BsonArray)] = new BsonValueResolver(), [typeof(BsonDocument)] = new BsonValueResolver(), [typeof(Convert)] = new ConvertResolver(), [typeof(DateTime)] = new DateTimeResolver(), [typeof(int)] = new NumberResolver("INT32"), [typeof(long)] = new NumberResolver("INT64"), [typeof(decimal)] = new NumberResolver("DECIMAL"), [typeof(double)] = new NumberResolver("DOUBLE"), [typeof(ICollection)] = new ICollectionResolver(), [typeof(Enumerable)] = new EnumerableResolver(), [typeof(Guid)] = new GuidResolver(), [typeof(Math)] = new MathResolver(), [typeof(Regex)] = new RegexResolver(), [typeof(ObjectId)] = new ObjectIdResolver(), [typeof(string)] = new StringResolver(), [typeof(Nullable)] = new NullableResolver() }; private readonly BsonMapper _mapper; private readonly Expression _expr; private readonly ParameterExpression _rootParameter; private readonly BsonDocument _parameters = new BsonDocument(); private int _paramIndex; private Type _dbRefType; private readonly StringBuilder _builder = new StringBuilder(); private readonly Stack<Expression> _nodes = new Stack<Expression>(); public LinqExpressionVisitor(BsonMapper mapper, Expression expr) { _mapper = mapper; _expr = expr; if (expr is LambdaExpression lambdaExpression) { _rootParameter = lambdaExpression.Parameters.First(); return; } throw new NotSupportedException("Expression " + expr.ToString() + " must be a lambda expression"); } public BsonExpression Resolve(bool predicate) { Visit(_expr); Constants.ENSURE(_nodes.Count == 0, "node stack must be empty when finish expression resolve"); string text = _builder.ToString(); try { BsonExpression bsonExpression = BsonExpression.Create(text, _parameters); if (predicate && (bsonExpression.Type == BsonExpressionType.Path || bsonExpression.Type == BsonExpressionType.Call || bsonExpression.Type == BsonExpressionType.Parameter)) { text = "(" + text + " = true)"; bsonExpression = BsonExpression.Create(text, _parameters); } return bsonExpression; } catch (Exception innerException) { throw new NotSupportedException("Invalid BsonExpression when converted from Linq expression: " + _expr.ToString() + " - `" + text + "`", innerException); } } protected override Expression VisitLambda<T>(Expression<T> node) { Expression result = base.VisitLambda(node); _builder.Length--; return result; } protected override Expression VisitInvocation(InvocationExpression node) { Expression result = base.VisitInvocation(node); _builder.Length--; return result; } protected override Expression VisitParameter(ParameterExpression node) { _builder.Append(_rootParameter.Equals(node) ? "$" : "@"); return base.VisitParameter(node); } protected override Expression VisitMember(MemberExpression node) { bool flag = ParameterExpressionVisitor.Test(node); MemberInfo member = node.Member; if (TryGetResolver(member.DeclaringType, out var typeResolver)) { string text = typeResolver.ResolveMember(member); if (text == null) { throw new NotSupportedException("Member " + member.Name + " are not support in " + member.DeclaringType.Name + " when convert to BsonExpression (" + node.ToString() + ")."); } ResolvePattern(text, node.Expression, new Expression[0]); } else if (node.Expression != null) { _nodes.Push(node); base.Visit(node.Expression); if (flag) { string value = ResolveMember(member); _builder.Append(value); } } else { object value2 = Evaluate(node); base.Visit(Expression.Constant(value2)); } if (_nodes.Count > 0) { _nodes.Pop(); } return node; } protected override Expression VisitMethodCall(MethodCallExpression node) { if (IsMethodIndexEval(node, out var obj, out var idx)) { Visit(obj); object obj2 = Evaluate(idx, typeof(string), typeof(int)); if (obj2 is string) { _builder.Append("."); _builder.Append($"['{obj2}']"); } else { _builder.Append($"[{obj2}]"); } return node; } if (!TryGetResolver(node.Method.DeclaringType, out var typeResolver)) { if (ParameterExpressionVisitor.Test(node)) { throw new NotSupportedException("Method " + node.Method.Name + " not available to convert to BsonExpression (" + node.ToString() + ")."); } object value = Evaluate(node); base.Visit(Expression.Constant(value)); return node; } string text = typeResolver.ResolveMethod(node.Method); if (text == null) { throw new NotSupportedException("Method " + Reflection.MethodName(node.Method) + " in " + node.Method.DeclaringType.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ")."); } ResolvePattern(text, node.Object, node.Arguments); return node; } protected override Expression VisitConstant(ConstantExpression node) { object value = node.Value; while (_nodes.Count > 0 && _nodes.Peek() is MemberExpression memberExpression) { if (memberExpression.Member is FieldInfo fieldInfo) { value = fieldInfo.GetValue(value); } else if (memberExpression.Member is PropertyInfo propertyInfo) { value = propertyInfo.GetValue(value); } _nodes.Pop(); } Constants.ENSURE(_nodes.Count == 0, "counter stack must be zero to eval all properties/field over object"); string text = "p" + _paramIndex++; _builder.AppendFormat("@" + text); Type type = value?.GetType(); BsonValue value2 = ((type == null) ? BsonValue.Null : ((type == typeof(string)) ? new BsonValue((string)value) : _mapper.Serialize(value.GetType(), value))); _parameters[text] = value2; return node; } protected override Expression VisitUnary(UnaryExpression node) { if (node.NodeType == ExpressionType.Not) { if (node.Operand.NodeType == ExpressionType.MemberAccess) { _builder.Append("("); Visit(node.Operand); _builder.Append(" = false)"); } else { _builder.Append("("); Visit(node.Operand); _builder.Append(")"); _builder.Append(" = false"); } } else if (node.NodeType == ExpressionType.Convert) { Type fromType = node.Operand.Type; Type type = node.Type; if ((fromType == typeof(double) || fromType == typeof(decimal)) && (type == typeof(int) || type == typeof(long))) { string methodName = "To" + type.Name.ToString(); MethodInfo methodInfo = (from x in typeof(Convert).GetMethods() where x.Name == methodName where x.GetParameters().Length == 1 && x.GetParameters().Any((ParameterInfo z) => z.ParameterType == fromType) select x).FirstOrDefault(); if (methodInfo == null) { throw new NotSupportedException("Cast from " + fromType.Name + " are not supported when convert to BsonExpression"); } MethodCallExpression node2 = Expression.Call(null, methodInfo, node.Operand); VisitMethodCall(node2); } else { base.VisitUnary(node); } } else if (node.NodeType == ExpressionType.ArrayLength) { _builder.Append("LENGTH("); Visit(node.Operand); _builder.Append(")"); } else { base.VisitUnary(node); } return node; } protected override Expression VisitNew(NewExpression node) { if (node.Members == null) { if (!TryGetResolver(node.Type, out var typeResolver)) { throw new NotSupportedException($"New instance are not supported for {node.Type} when convert to BsonExpression ({node.ToString()})."); } string text = typeResolver.ResolveCtor(node.Constructor); if (text == null) { throw new NotSupportedException("Constructor for " + node.Type.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ")."); } ResolvePattern(text, null, node.Arguments); } else { _builder.Append("{ "); for (int i = 0; i < node.Members.Count; i++) { MemberInfo memberInfo = node.Members[i]; _builder.Append((i > 0) ? ", " : ""); _builder.AppendFormat("'{0}': ", memberInfo.Name); Visit(node.Arguments[i]); } _builder.Append(" }"); } return node; } protected override Expression VisitMemberInit(MemberInitExpression node) { if (node.NewExpression.Constructor.GetParameters().Length != 0) { throw new NotSupportedException($"New instance of {node.Type} are not supported because contains ctor with parameter. Try use only property initializers: `new {node.Type.Name} {{ PropA = 1, PropB == \"John\" }}`."); } _builder.Append("{"); for (int i = 0; i < node.Bindings.Count; i++) { MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment; string text = ResolveMember(memberAssignment.Member); _builder.Append((i > 0) ? ", " : ""); _builder.Append(text.Substring(1)); _builder.Append(":"); Visit(memberAssignment.Expression); } _builder.Append("}"); return node; } protected override Expression VisitNewArray(NewArrayExpression node) { _builder.Append("[ "); for (int i = 0; i < node.Expressions.Count; i++) { _builder.Append((i > 0) ? ", " : ""); Visit(node.Expressions[i]); } _builder.Append(" ]"); return node; } protected override Expression VisitBinary(BinaryExpression node) { bool ensurePredicate = node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse; if (node.NodeType == ExpressionType.Coalesce) { return VisitCoalesce(node); } if (node.NodeType == ExpressionType.ArrayIndex) { return VisitArrayIndex(node); } string @operator = GetOperator(node.NodeType); _builder.Append("("); VisitAsPredicate(node.Left, ensurePredicate); _builder.Append(@operator); if (!_mapper.EnumAsInteger && node.Left.NodeType == ExpressionType.Convert && node.Left is UnaryExpression unaryExpression && unaryExpression.Operand.Type.GetTypeInfo().IsEnum && unaryExpression.Type == typeof(int)) { VisitAsPredicate(Expression.Constant(Enum.GetName(unaryExpression.Operand.Type, Evaluate(node.Right))), ensurePredicate); } else { VisitAsPredicate(node.Right, ensurePredicate); } _builder.Append(")"); return node; } protected override Expression VisitConditional(ConditionalExpression node) { _builder.Append("IIF("); Visit(node.Test); _builder.Append(", "); Visit(node.IfTrue); _builder.Append(", "); Visit(node.IfFalse); _builder.Append(")"); return node; } private Expression VisitCoalesce(BinaryExpression node) { _builder.Append("COALESCE("); Visit(node.Left); _builder.Append(", "); Visit(node.Right); _builder.Append(")"); return node; } private Expression VisitArrayIndex(BinaryExpression node) { Visit(node.Left); _builder.Append("["); object value = Evaluate(node.Right, typeof(int)); _builder.Append(value); _builder.Append("]"); return node; } private void ResolvePattern(string pattern, Expression obj, IList<Expression> args) { Tokenizer tokenizer = new Tokenizer(pattern); while (!tokenizer.EOF) { Token token = tokenizer.ReadToken(eatWhitespace: false); if (token.Type == TokenType.Hashtag) { Visit(obj); } else if (token.Type == TokenType.At && tokenizer.LookAhead(eatWhitespace: false).Type == TokenType.Int) { int index = Convert.ToInt32(tokenizer.ReadToken(eatWhitespace: false).Expect(TokenType.Int).Value); Visit(args[index]); } else if (token.Type == TokenType.Percent) { VisitEnumerablePredicate(args[1] as LambdaExpression); } else { _builder.Append((token.Type == TokenType.String) ? ("'" + token.Value + "'") : token.Value); } } } private void VisitEnumerablePredicate(LambdaExpression lambda) { Expression body = lambda.Body; if (body is BinaryExpression binaryExpression) { if (binaryExpression.Left.NodeType != ExpressionType.Parameter) { throw new LiteException(0, "Any/All requires simple parameter on left side. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`"); } string @operator = GetOperator(binaryExpression.NodeType); _builder.Append(@operator); VisitAsPredicate(binaryExpression.Right, ensurePredicate: false); return; } if (body is MethodCallExpression methodCallExpression) { if (methodCallExpression.Object.NodeType != ExpressionType.Parameter) { throw new NotSupportedException("Any/All requires simple parameter on left side. Eg: `x.Customers.Select(c => c.Name).Any(n => n.StartsWith('J'))`"); } if (!TryGetResolver(methodCallExpression.Method.DeclaringType, out var typeResolver)) { throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call."); } string text = typeResolver.ResolveMethod(methodCallExpression.Method); if (text == null || !text.StartsWith("#")) { throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call."); } ResolvePattern(text.Substring(1), methodCallExpression.Object, methodCallExpression.Arguments); return; } throw new LiteException(0, "When using Any/All method test do only simple predicate variable. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`"); } private string GetOperator(ExpressionType nodeType) { return nodeType switch { ExpressionType.Add => " + ", ExpressionType.Multiply => " * ", ExpressionType.Subtract => " - ", ExpressionType.Divide => " / ", ExpressionType.Equal => " = ", ExpressionType.NotEqual => " != ", ExpressionType.GreaterThan => " > ", ExpressionType.GreaterThanOrEqual => " >= ", ExpressionType.LessThan => " < ", ExpressionType.LessThanOrEqual => " <= ", ExpressionType.And => " AND ", ExpressionType.AndAlso => " AND ", ExpressionType.Or => " OR ", ExpressionType.OrElse => " OR ", _ => throw new NotSupportedException($"Operator not supported {nodeType}"), }; } private string ResolveMember(MemberInfo member) { string name = member.Name; bool flag = _dbRefType != null && member.DeclaringType.IsAssignableFrom(_dbRefType); MemberMapper memberMapper = _mapper.GetEntityMapper(member.DeclaringType).Members.FirstOrDefault((MemberMapper x) => x.MemberName == name); if (memberMapper == null) { throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}."); } _dbRefType = (memberMapper.IsDbRef ? memberMapper.UnderlyingType : null); return "." + ((flag && memberMapper.FieldName == "_id") ? "$id" : memberMapper.FieldName); } private bool IsMethodIndexEval(MethodCallExpression node, out Expression obj, out Expression idx) { MethodInfo method = node.Method; _ = method.DeclaringType; ParameterInfo[] parameters = method.GetParameters(); if (method.Name == "get_Item" && parameters.Length == 1 && (parameters[0].ParameterType == typeof(int) || parameters[0].ParameterType == typeof(string))) { obj = node.Object; idx = node.Arguments[0]; return true; } obj = null; idx = null; return false; } private void VisitAsPredicate(Expression expr, bool ensurePredicate) { ensurePredicate = ensurePredicate && (expr.NodeType == ExpressionType.MemberAccess || expr.NodeType == ExpressionType.Call || expr.NodeType == ExpressionType.Invoke || expr.NodeType == ExpressionType.Constant); if (ensurePredicate) { _builder.Append("("); _builder.Append("("); base.Visit(expr); _builder.Append(")"); _builder.Append(" = true)"); } else { base.Visit(expr); } } private object Evaluate(Expression expr, params Type[] validTypes) { object value = null; if (expr.NodeType == ExpressionType.Constant) { ConstantExpression constantExpression = (ConstantExpression)expr; value = constantExpression.Value; } else { Delegate @delegate = Expression.Lambda(expr).Compile(); value = @delegate.DynamicInvoke(); } if (validTypes.Length != 0 && value == null) { throw new NotSupportedException($"Expression {expr} can't return null value"); } if (validTypes.Length != 0 && !validTypes.Any((Type x) => x == value.GetType())) { throw new NotSupportedException(string.Format("Expression {0} must return on of this types: {1}", expr, string.Join(", ", validTypes.Select((Type x) => "`" + x.Name + "`")))); } return value; } private bool TryGetResolver(Type declaringType, out ITypeResolver typeResolver) { bool num = Reflection.IsCollection(declaringType); bool flag = Reflection.IsEnumerable(declaringType); bool flag2 = Reflection.IsNullable(declaringType); Type key = (num ? typeof(ICollection) : (flag ? typeof(Enumerable) : (flag2 ? typeof(Nullable) : declaringType))); return _resolver.TryGetValue(key, out typeResolver); } } internal class ParameterExpressionVisitor : ExpressionVisitor { public bool IsParameter { get; private set; } protected override Expression VisitParameter(ParameterExpression node) { IsParameter = true; return base.VisitParameter(node); } public static bool Test(Expression node) { ParameterExpressionVisitor parameterExpressionVisitor = new ParameterExpressionVisitor(); parameterExpressionVisitor.Visit(node); return parameterExpressionVisitor.IsParameter; } } internal class BsonValueResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { return null; } public string ResolveMember(MemberInfo member) { switch (member.Name) { case "AsInt32": case "AsInt64": case "AsArray": case "AsDateTime": case "AsDocument": case "AsObjectId": case "AsString": case "AsBinary": case "AsDouble": case "AsBoolean": case "AsDecimal": case "AsGuid": return "#"; case "IsNull": return "IS_NULL(#)"; case "IsArray": return "IS_ARRAY(#)"; case "IsDocument": return "IS_DOCUMENT(#)"; case "IsInt32": return "IS_INT32(#)"; case "IsInt64": return "IS_INT64(#)"; case "IsDouble": return "IS_DOUBLE(#)"; case "IsDecimal": return "IS_DECIMAL(#)"; case "IsNumber": return "IS_NUMBER(#)"; case "IsBinary": return "IS_BINARY(#)"; case "IsBoolean": return "IS_BOOLEAN(#)"; case "IsString": return "IS_STRING(#)"; case "IsObjectId": return "IS_OBJECTID(#)"; case "IsGuid": return "IS_GUID(#)"; case "IsDateTime": return "IS_DATETIME(#)"; case "IsMinValue": return "IS_MINVALUE(#)"; case "IsMaxValue": return "IS_MAXVALUE(#)"; default: return null; } } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class ConvertResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { return method.Name switch { "ToInt32" => "INT32(@0)", "ToInt64" => "INT64(@0)", "ToDouble" => "DOUBLE(@0)", "ToDecimal" => "DECIMAL(@0)", "ToDateTime" => "DATE(@0)", "FromBase64String" => "BINARY(@0)", "ToBoolean" => "BOOL(@0)", "ToString" => "STRING(@0)", _ => null, }; } public string ResolveMember(MemberInfo member) { return null; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class DateTimeResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { switch (method.Name) { case "AddYears": return "DATEADD('y', @0, #)"; case "AddMonths": return "DATEADD('M', @0, #)"; case "AddDays": return "DATEADD('d', @0, #)"; case "AddHours": return "DATEADD('h', @0, #)"; case "AddMinutes": return "DATEADD('m', @0, #)"; case "AddSeconds": return "DATEADD('s', @0, #)"; case "ToString": { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { return "STRING(#)"; } if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return "FORMAT(#, @0)"; } break; } case "ToUniversalTime": return "TO_UTC(#)"; case "Parse": return "DATETIME(@0)"; case "Equals": return "# = @0"; } return null; } public string ResolveMember(MemberInfo member) { return member.Name switch { "Now" => "NOW()", "UtcNow" => "NOW_UTC()", "Today" => "TODAY()", "Year" => "YEAR(#)", "Month" => "MONTH(#)", "Day" => "DAY(#)", "Hour" => "HOUR(#)", "Minute" => "MINUTE(#)", "Second" => "SECOND(#)", "Date" => "DATETIME(YEAR(#), MONTH(#), DAY(#))", "ToLocalTime" => "TO_LOCAL(#)", "ToUniversalTime" => "TO_UTC(#)", _ => null, }; } public string ResolveCtor(ConstructorInfo ctor) { ParameterInfo[] parameters = ctor.GetParameters(); if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int)) { return "DATETIME(@0, @1, @2)"; } return null; } } internal class EnumerableResolver : ITypeResolver { public virtual string ResolveMethod(MethodInfo method) { switch (Reflection.MethodName(method, 1)) { case "AsEnumerable()": return "@0[*]"; case "get_Item(int)": return "#[@0]"; case "ElementAt(int)": return "@0[@1]"; case "Single()": case "First()": case "SingleOrDefault()": case "FirstOrDefault()": return "@0[0]"; case "Last()": case "LastOrDefault()": return "@0[-1]"; case "Single(Func<T,TResult>)": case "First(Func<T,TResult>)": case "SingleOrDefault(Func<T,TResult>)": case "FirstOrDefault(Func<T,TResult>)": return "FIRST(FILTER(@0 => @1))"; case "Last(Func<T,TResult>)": case "LastOrDefault(Func<T,TResult>)": return "LAST(FILTER(@0 => @1))"; case "Where(Func<T,TResult>)": return "FILTER(@0 => @1)"; case "Select(Func<T,TResult>)": return "MAP(@0 => @1)"; case "Count()": return "COUNT(@0)"; case "Sum()": return "SUM(@0)"; case "Average()": return "AVG(@0)"; case "Max()": return "MAX(@0)"; case "Min()": return "MIN(@0)"; case "Count(Func<T,TResult>)": return "COUNT(FILTER(@0 => @1))"; case "Sum(Func<T,TResult>)": return "SUM(MAP(@0 => @1))"; case "Average(Func<T,TResult>)": return "AVG(MAP(@0 => @1))"; case "Max(Func<T,TResult>)": return "MAX(MAP(@0 => @1))"; case "Min(Func<T,TResult>)": return "MIN(MAP(@0 => @1))"; case "ToList()": case "ToArray()": return "ARRAY(@0)"; case "Any(Func<T,TResult>)": return "@0 ANY %"; case "All(Func<T,TResult>)": return "@0 ALL %"; case "Any()": return "COUNT(@0) > 0"; default: if (method.Name == "Contains") { return "@0 ANY = @1"; } return null; } } public virtual string ResolveMember(MemberInfo member) { string name = member.Name; if (!(name == "Length")) { if (name == "Count") { return "COUNT(#)"; } return null; } return "LENGTH(#)"; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class GuidResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { return method.Name switch { "ToString" => "STRING(#)", "NewGuid" => "GUID()", "Parse" => "GUID(@0)", "TryParse" => throw new NotSupportedException("There is no TryParse translate. Use Guid.Parse()"), "Equals" => "# = @0", _ => null, }; } public string ResolveMember(MemberInfo member) { if (member.Name == "Empty") { return "GUID('00000000-0000-0000-0000-000000000000')"; } return null; } public string ResolveCtor(ConstructorInfo ctor) { ParameterInfo[] parameters = ctor.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return "GUID(@0)"; } return null; } } internal class ICollectionResolver : EnumerableResolver { public override string ResolveMethod(MethodInfo method) { if (method.Name == "Contains") { return "# ANY = @0"; } return base.ResolveMethod(method); } } internal interface ITypeResolver { string ResolveMethod(MethodInfo method); string ResolveMember(MemberInfo member); string ResolveCtor(ConstructorInfo ctor); } internal class MathResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { int num = method.GetParameters().Length; switch (method.Name) { case "Abs": return "ABS(@0)"; case "Pow": return "POW(@0, @1)"; case "Round": if (num != 2) { throw new ArgumentOutOfRangeException("Method Round need 2 arguments when convert to BsonExpression"); } return "ROUND(@0, @1)"; default: return null; } } public string ResolveMember(MemberInfo member) { return null; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class NullableResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { return null; } public string ResolveMember(MemberInfo member) { string name = member.Name; if (!(name == "HasValue")) { if (name == "Value") { return "#"; } return null; } return "(IS_NULL(#) = false)"; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class NumberResolver : ITypeResolver { private readonly string _parseMethod; public NumberResolver(string parseMethod) { _parseMethod = parseMethod; } public string ResolveMethod(MethodInfo method) { switch (method.Name) { case "ToString": { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0) { return "STRING(#)"; } if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return "FORMAT(#, @0)"; } break; } case "Parse": return _parseMethod + "(@0)"; case "Equals": return "# = @0"; } return null; } public string ResolveMember(MemberInfo member) { return null; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class ObjectIdResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { string name = method.Name; if (!(name == "ToString")) { if (name == "Equals") { return "# = @0"; } return null; } return "STRING(#)"; } public string ResolveMember(MemberInfo member) { string name = member.Name; if (!(name == "Empty")) { if (name == "CreationTime") { return "OID_CREATIONTIME(#)"; } return null; } return "OBJECTID('000000000000000000000000')"; } public string ResolveCtor(ConstructorInfo ctor) { ParameterInfo[] parameters = ctor.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return "OBJECTID(@0)"; } return null; } } internal class RegexResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { string name = method.Name; if (!(name == "Split")) { if (name == "IsMatch") { return "IS_MATCH(@0, @1)"; } return null; } return "SPLIT(@0, @1, true)"; } public string ResolveMember(MemberInfo member) { return null; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } internal class StringResolver : ITypeResolver { public string ResolveMethod(MethodInfo method) { int num = method.GetParameters().Length; switch (method.Name) { case "Count": return "LENGTH(#)"; case "Trim": return "TRIM(#)"; case "TrimStart": return "LTRIM(#)"; case "TrimEnd": return "RTRIM(#)"; case "ToUpper": return "UPPER(#)"; case "ToUpperInvariant": return "UPPER(#)"; case "ToLower": return "LOWER(#)"; case "ToLowerInvariant": return "LOWER(#)"; case "Replace": return "REPLACE(#, @0, @1)"; case "PadLeft": return "LPAD(#, @0, @1)"; case "RightLeft": return "RPAD(#, @0, @1)"; case "IndexOf": if (num != 1) { return "INDEXOF(#, @0, @1)"; } return "INDEXOF(#, @0)"; case "Substring": if (num != 1) { return "SUBSTRING(#, @0, @1)"; } return "SUBSTRING(#, @0)"; case "StartsWith": return "# LIKE (@0 + '%')"; case "Contains": return "# LIKE ('%' + @0 + '%')"; case "EndsWith": return "# LIKE ('%' + @0)"; case "ToString": return "#"; case "Equals": return "# = @0"; case "IsNullOrEmpty": return "(LENGTH(@0) = 0)"; case "IsNullOrWhiteSpace": return "(LENGTH(TRIM(@0)) = 0)"; case "Format": throw new NotImplementedException(); case "Join": throw new NotImplementedException(); default: return null; } } public string ResolveMember(MemberInfo member) { string name = member.Name; if (!(name == "Length")) { if (name == "Empty") { return "''"; } return null; } return "LENGTH(#)"; } public string ResolveCtor(ConstructorInfo ctor) { return null; } } public class MemberMapper { public bool AutoId { get; set; } public string MemberName { get; set; } public Type DataType { get; set; } public string FieldName { get; set; } public GenericGetter Getter { get; set; } public GenericSetter Setter { get; set; } public Func<object, BsonMapper, BsonValue> Serialize { get; set; } public Func<BsonValue, BsonMapper, object> Deserialize { get; set; } public bool IsDbRef { get; set; } public bool IsEnumerable { get; set; } public Type UnderlyingType { get; set; } public bool IsIgnore { get; set; } } public delegate object CreateObject(BsonDocument value); public delegate void GenericSetter(object target, object value); public delegate object GenericGetter(object obj); internal class Reflection { private static readonly Dictionary<Type, CreateObject> _cacheCtor = new Dictionary<Type, CreateObject>(); public static readonly Dictionary<Type, PropertyInfo> ConvertType = new Dictionary<Type, PropertyInfo> { [typeof(DateTime)] = typeof(BsonValue).GetProperty("AsDateTime"), [typeof(decimal)] = typeof(BsonValue).GetProperty("AsDecimal"), [typeof(double)] = typeof(BsonValue).GetProperty("AsDouble"), [typeof(long)] = typeof(BsonValue).GetProperty("AsInt64"), [typeof(int)] = typeof(BsonValue).GetProperty("AsInt32"), [typeof(bool)] = typeof(BsonValue).GetProperty("AsBoolean"), [typeof(byte[])] = typeof(BsonValue).GetProperty("AsBinary"), [typ
plugins/Newtonsoft.Json.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
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.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Resources; 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 Microsoft.CodeAnalysis; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AllowPartiallyTrustedCallers] [assembly: InternalsVisibleTo("Newtonsoft.Json.Schema, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")] [assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")] [assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")] [assembly: CLSCompliant(true)] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Newtonsoft")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © James Newton-King 2008")] [assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")] [assembly: AssemblyFileVersion("13.0.3.27908")] [assembly: AssemblyInformationalVersion("13.0.3+0a2e291c0d9c0c7675d445703e51750363a549ef")] [assembly: AssemblyProduct("Json.NET")] [assembly: AssemblyTitle("Json.NET .NET 4.5")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JamesNK/Newtonsoft.Json")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyVersion("13.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } 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 { public enum ConstructorHandling { Default, AllowNonPublicDefaultConstructor } public enum DateFormatHandling { IsoDateFormat, MicrosoftDateFormat } public enum DateParseHandling { None, DateTime, DateTimeOffset } public enum DateTimeZoneHandling { Local, Utc, Unspecified, RoundtripKind } public 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] public enum DefaultValueHandling { Include = 0, Ignore = 1, Populate = 2, IgnoreAndPopulate = 3 } public enum FloatFormatHandling { String, Symbol, DefaultValue } public enum FloatParseHandling { Double, Decimal } public enum Formatting { None, Indented } public interface IArrayPool<T> { T[] Rent(int minimumLength); void Return(T[]? array); } public interface IJsonLineInfo { int LineNumber { get; } int LinePosition { get; } bool HasLineInfo(); } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public 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)] public sealed class JsonConstructorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public 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; } } public 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); } } public 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); } public 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)] public 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; } } public class JsonConverterCollection : Collection<JsonConverter> { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public sealed class JsonDictionaryAttribute : JsonContainerAttribute { public JsonDictionaryAttribute() { } public JsonDictionaryAttribute(string id) : base(id) { } } [Serializable] public 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)] public 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)] public sealed class JsonIgnoreAttribute : Attribute { } public abstract class JsonNameTable { public abstract string? Get(char[] key, int start, int length); } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)] public 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)] public 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; } } public 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] public 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)] public sealed class JsonRequiredAttribute : Attribute { } [Serializable] public 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(JsonReader reader, string message) { return Create(reader, message, null); } internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } internal static JsonSerializationException 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 JsonSerializationException(message, path, lineNumber, linePosition, ex); } } public class JsonSerializer { internal TypeNameHandling _typeNameHandling; internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling; internal PreserveReferencesHandling _preserveReferencesHandling; internal ReferenceLoopHandling _referenceLoopHandling; internal MissingMemberHandling _missingMemberHandling; internal ObjectCreationHandling _objectCreationHandling; internal NullValueHandling _nullValueHandling; internal DefaultValueHandling _defaultValueHandling; internal ConstructorHandling _constructorHandling; internal MetadataPropertyHandling _metadataPropertyHandling; internal JsonConverterCollection? _converters; internal IContractResolver _contractResolver; internal ITraceWriter? _traceWriter; internal IEqualityComparer? _equalityComparer; internal ISerializationBinder _serializationBinder; internal StreamingContext _context; private IReferenceResolver? _referenceResolver; private Formatting? _formatting; private DateFormatHandling? _dateFormatHandling; private DateTimeZoneHandling? _dateTimeZoneHandling; private DateParseHandling? _dateParseHandling; private FloatFormatHandling? _floatFormatHandling; private FloatParseHandling? _floatParseHandling; private StringEscapeHandling? _stringEscapeHandling; private CultureInfo _culture; private int? _maxDepth; private bool _maxDepthSet; private bool? _checkAdditionalContent; private string? _dateFormatString; private bool _dateFormatStringSet; public virtual IReferenceResolver? ReferenceResolver { get { return GetReferenceResolver(); } set { if (value == null) { throw new ArgumentNullException("value", "Reference resolver cannot be null."); } _referenceResolver = value; } } [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] public virtual SerializationBinder Binder { get { if (_serializationBinder is SerializationBinder result) { return result; } if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter) { return serializationBinderAdapter.SerializationBinder; } throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); } set { if (value == null) { throw new ArgumentNullException("value", "Serialization binder cannot be null."); } _serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value); } } public virtual ISerializationBinder SerializationBinder { get { return _serializationBinder; } set { if (value == null) { throw new ArgumentNullException("value", "Serialization binder cannot be null."); } _serializationBinder = value; } } public virtual ITraceWriter? TraceWriter { get { return _traceWriter; } set { _traceWriter = value; } } public virtual IEqualityComparer? EqualityComparer { get { return _equalityComparer; } set { _equalityComparer = value; } } public virtual TypeNameHandling TypeNameHandling { get { return _typeNameHandling; } set { if (value < TypeNameHandling.None || value > TypeNameHandling.Auto) { throw new ArgumentOutOfRangeException("value"); } _typeNameHandling = value; } } [Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")] public virtual FormatterAssemblyStyle TypeNameAssemblyFormat { get { return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling; } set { if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full) { throw new ArgumentOutOfRangeException("value"); } _typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value; } } public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling { get { return _typeNameAssemblyFormatHandling; } set { if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full) { throw new ArgumentOutOfRangeException("value"); } _typeNameAssemblyFormatHandling = value; } } public virtual PreserveReferencesHandling PreserveReferencesHandling { get { return _preserveReferencesHandling; } set { if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All) { throw new ArgumentOutOfRangeException("value"); } _preserveReferencesHandling = value; } } public virtual ReferenceLoopHandling ReferenceLoopHandling { get { return _referenceLoopHandling; } set { if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize) { throw new ArgumentOutOfRangeException("value"); } _referenceLoopHandling = value; } } public virtual MissingMemberHandling MissingMemberHandling { get { return _missingMemberHandling; } set { if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error) { throw new ArgumentOutOfRangeException("value"); } _missingMemberHandling = value; } } public virtual NullValueHandling NullValueHandling { get { return _nullValueHandling; } set { if (value < NullValueHandling.Include || value > NullValueHandling.Ignore) { throw new ArgumentOutOfRangeException("value"); } _nullValueHandling = value; } } public virtual DefaultValueHandling DefaultValueHandling { get { return _defaultValueHandling; } set { if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate) { throw new ArgumentOutOfRangeException("value"); } _defaultValueHandling = value; } } public virtual ObjectCreationHandling ObjectCreationHandling { get { return _objectCreationHandling; } set { if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace) { throw new ArgumentOutOfRangeException("value"); } _objectCreationHandling = value; } } public virtual ConstructorHandling ConstructorHandling { get { return _constructorHandling; } set { if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor) { throw new ArgumentOutOfRangeException("value"); } _constructorHandling = value; } } public virtual MetadataPropertyHandling MetadataPropertyHandling { get { return _metadataPropertyHandling; } set { if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore) { throw new ArgumentOutOfRangeException("value"); } _metadataPropertyHandling = value; } } public virtual JsonConverterCollection Converters { get { if (_converters == null) { _converters = new JsonConverterCollection(); } return _converters; } } public virtual IContractResolver ContractResolver { get { return _contractResolver; } set { _contractResolver = value ?? DefaultContractResolver.Instance; } } public virtual StreamingContext Context { get { return _context; } set { _context = value; } } public virtual Formatting Formatting { get { return _formatting.GetValueOrDefault(); } set { _formatting = value; } } public virtual DateFormatHandling DateFormatHandling { get { return _dateFormatHandling.GetValueOrDefault(); } set { _dateFormatHandling = value; } } public virtual DateTimeZoneHandling DateTimeZoneHandling { get { return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind; } set { _dateTimeZoneHandling = value; } } public virtual DateParseHandling DateParseHandling { get { return _dateParseHandling ?? DateParseHandling.DateTime; } set { _dateParseHandling = value; } } public virtual FloatParseHandling FloatParseHandling { get { return _floatParseHandling.GetValueOrDefault(); } set { _floatParseHandling = value; } } public virtual FloatFormatHandling FloatFormatHandling { get { return _floatFormatHandling.GetValueOrDefault(); } set { _floatFormatHandling = value; } } public virtual StringEscapeHandling StringEscapeHandling { get { return _stringEscapeHandling.GetValueOrDefault(); } set { _stringEscapeHandling = value; } } public virtual string DateFormatString { get { return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; } set { _dateFormatString = value; _dateFormatStringSet = true; } } public virtual CultureInfo Culture { get { return _culture ?? JsonSerializerSettings.DefaultCulture; } set { _culture = value; } } public virtual int? MaxDepth { get { return _maxDepth; } set { if (value <= 0) { throw new ArgumentException("Value must be positive.", "value"); } _maxDepth = value; _maxDepthSet = true; } } public virtual bool CheckAdditionalContent { get { return _checkAdditionalContent.GetValueOrDefault(); } set { _checkAdditionalContent = value; } } public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error; internal bool IsCheckAdditionalContentSet() { return _checkAdditionalContent.HasValue; } public JsonSerializer() { _referenceLoopHandling = ReferenceLoopHandling.Error; _missingMemberHandling = MissingMemberHandling.Ignore; _nullValueHandling = NullValueHandling.Include; _defaultValueHandling = DefaultValueHandling.Include; _objectCreationHandling = ObjectCreationHandling.Auto; _preserveReferencesHandling = PreserveReferencesHandling.None; _constructorHandling = ConstructorHandling.Default; _typeNameHandling = TypeNameHandling.None; _metadataPropertyHandling = MetadataPropertyHandling.Default; _context = JsonSerializerSettings.DefaultContext; _serializationBinder = DefaultSerializationBinder.Instance; _culture = JsonSerializerSettings.DefaultCulture; _contractResolver = DefaultContractResolver.Instance; } public static JsonSerializer Create() { return new JsonSerializer(); } public static JsonSerializer Create(JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = Create(); if (settings != null) { ApplySerializerSettings(jsonSerializer, settings); } return jsonSerializer; } public static JsonSerializer CreateDefault() { return Create(JsonConvert.DefaultSettings?.Invoke()); } public static JsonSerializer CreateDefault(JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = CreateDefault(); if (settings != null) { ApplySerializerSettings(jsonSerializer, settings); } return jsonSerializer; } private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings) { if (!CollectionUtils.IsNullOrEmpty(settings.Converters)) { for (int i = 0; i < settings.Converters.Count; i++) { serializer.Converters.Insert(i, settings.Converters[i]); } } if (settings._typeNameHandling.HasValue) { serializer.TypeNameHandling = settings.TypeNameHandling; } if (settings._metadataPropertyHandling.HasValue) { serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling; } if (settings._typeNameAssemblyFormatHandling.HasValue) { serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling; } if (settings._preserveReferencesHandling.HasValue) { serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling; } if (settings._referenceLoopHandling.HasValue) { serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling; } if (settings._missingMemberHandling.HasValue) { serializer.MissingMemberHandling = settings.MissingMemberHandling; } if (settings._objectCreationHandling.HasValue) { serializer.ObjectCreationHandling = settings.ObjectCreationHandling; } if (settings._nullValueHandling.HasValue) { serializer.NullValueHandling = settings.NullValueHandling; } if (settings._defaultValueHandling.HasValue) { serializer.DefaultValueHandling = settings.DefaultValueHandling; } if (settings._constructorHandling.HasValue) { serializer.ConstructorHandling = settings.ConstructorHandling; } if (settings._context.HasValue) { serializer.Context = settings.Context; } if (settings._checkAdditionalContent.HasValue) { serializer._checkAdditionalContent = settings._checkAdditionalContent; } if (settings.Error != null) { serializer.Error += settings.Error; } if (settings.ContractResolver != null) { serializer.ContractResolver = settings.ContractResolver; } if (settings.ReferenceResolverProvider != null) { serializer.ReferenceResolver = settings.ReferenceResolverProvider(); } if (settings.TraceWriter != null) { serializer.TraceWriter = settings.TraceWriter; } if (settings.EqualityComparer != null) { serializer.EqualityComparer = settings.EqualityComparer; } if (settings.SerializationBinder != null) { serializer.SerializationBinder = settings.SerializationBinder; } if (settings._formatting.HasValue) { serializer._formatting = settings._formatting; } if (settings._dateFormatHandling.HasValue) { serializer._dateFormatHandling = settings._dateFormatHandling; } if (settings._dateTimeZoneHandling.HasValue) { serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling; } if (settings._dateParseHandling.HasValue) { serializer._dateParseHandling = settings._dateParseHandling; } if (settings._dateFormatStringSet) { serializer._dateFormatString = settings._dateFormatString; serializer._dateFormatStringSet = settings._dateFormatStringSet; } if (settings._floatFormatHandling.HasValue) { serializer._floatFormatHandling = settings._floatFormatHandling; } if (settings._floatParseHandling.HasValue) { serializer._floatParseHandling = settings._floatParseHandling; } if (settings._stringEscapeHandling.HasValue) { serializer._stringEscapeHandling = settings._stringEscapeHandling; } if (settings._culture != null) { serializer._culture = settings._culture; } if (settings._maxDepthSet) { serializer._maxDepth = settings._maxDepth; serializer._maxDepthSet = settings._maxDepthSet; } } [DebuggerStepThrough] public void Populate(TextReader reader, object target) { Populate(new JsonTextReader(reader), target); } [DebuggerStepThrough] public void Populate(JsonReader reader, object target) { PopulateInternal(reader, target); } internal virtual void PopulateInternal(JsonReader reader, object target) { ValidationUtils.ArgumentNotNull(reader, "reader"); ValidationUtils.ArgumentNotNull(target, "target"); SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString); TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null); new JsonSerializerInternalReader(this).Populate(traceJsonReader ?? reader, target); if (traceJsonReader != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); } [DebuggerStepThrough] public object? Deserialize(JsonReader reader) { return Deserialize(reader, null); } [DebuggerStepThrough] public object? Deserialize(TextReader reader, Type objectType) { return Deserialize(new JsonTextReader(reader), objectType); } [DebuggerStepThrough] public T? Deserialize<T>(JsonReader reader) { return (T)Deserialize(reader, typeof(T)); } [DebuggerStepThrough] public object? Deserialize(JsonReader reader, Type? objectType) { return DeserializeInternal(reader, objectType); } internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType) { ValidationUtils.ArgumentNotNull(reader, "reader"); SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString); TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null); object? result = new JsonSerializerInternalReader(this).Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); if (traceJsonReader != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); return result; } internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString) { if (_culture != null && !_culture.Equals(reader.Culture)) { previousCulture = reader.Culture; reader.Culture = _culture; } else { previousCulture = null; } if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling) { previousDateTimeZoneHandling = reader.DateTimeZoneHandling; reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault(); } else { previousDateTimeZoneHandling = null; } if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling) { previousDateParseHandling = reader.DateParseHandling; reader.DateParseHandling = _dateParseHandling.GetValueOrDefault(); } else { previousDateParseHandling = null; } if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling) { previousFloatParseHandling = reader.FloatParseHandling; reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault(); } else { previousFloatParseHandling = null; } if (_maxDepthSet && reader.MaxDepth != _maxDepth) { previousMaxDepth = reader.MaxDepth; reader.MaxDepth = _maxDepth; } else { previousMaxDepth = null; } if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString) { previousDateFormatString = reader.DateFormatString; reader.DateFormatString = _dateFormatString; } else { previousDateFormatString = null; } if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver) { jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable(); } } private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString) { if (previousCulture != null) { reader.Culture = previousCulture; } if (previousDateTimeZoneHandling.HasValue) { reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault(); } if (previousDateParseHandling.HasValue) { reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault(); } if (previousFloatParseHandling.HasValue) { reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault(); } if (_maxDepthSet) { reader.MaxDepth = previousMaxDepth; } if (_dateFormatStringSet) { reader.DateFormatString = previousDateFormatString; } if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable()) { jsonTextReader.PropertyNameTable = null; } } public void Serialize(TextWriter textWriter, object? value) { Serialize(new JsonTextWriter(textWriter), value); } public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { SerializeInternal(jsonWriter, value, objectType); } public void Serialize(TextWriter textWriter, object? value, Type objectType) { Serialize(new JsonTextWriter(textWriter), value, objectType); } public void Serialize(JsonWriter jsonWriter, object? value) { SerializeInternal(jsonWriter, value, null); } private TraceJsonReader CreateTraceJsonReader(JsonReader reader) { TraceJsonReader traceJsonReader = new TraceJsonReader(reader); if (reader.TokenType != 0) { traceJsonReader.WriteCurrentToken(); } return traceJsonReader; } internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType) { ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter"); Formatting? formatting = null; if (_formatting.HasValue && jsonWriter.Formatting != _formatting) { formatting = jsonWriter.Formatting; jsonWriter.Formatting = _formatting.GetValueOrDefault(); } DateFormatHandling? dateFormatHandling = null; if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling) { dateFormatHandling = jsonWriter.DateFormatHandling; jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault(); } DateTimeZoneHandling? dateTimeZoneHandling = null; if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling) { dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling; jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault(); } FloatFormatHandling? floatFormatHandling = null; if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling) { floatFormatHandling = jsonWriter.FloatFormatHandling; jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault(); } StringEscapeHandling? stringEscapeHandling = null; if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling) { stringEscapeHandling = jsonWriter.StringEscapeHandling; jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault(); } CultureInfo cultureInfo = null; if (_culture != null && !_culture.Equals(jsonWriter.Culture)) { cultureInfo = jsonWriter.Culture; jsonWriter.Culture = _culture; } string dateFormatString = null; if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString) { dateFormatString = jsonWriter.DateFormatString; jsonWriter.DateFormatString = _dateFormatString; } TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null); new JsonSerializerInternalWriter(this).Serialize(traceJsonWriter ?? jsonWriter, value, objectType); if (traceJsonWriter != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); } if (formatting.HasValue) { jsonWriter.Formatting = formatting.GetValueOrDefault(); } if (dateFormatHandling.HasValue) { jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault(); } if (dateTimeZoneHandling.HasValue) { jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault(); } if (floatFormatHandling.HasValue) { jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault(); } if (stringEscapeHandling.HasValue) { jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault(); } if (_dateFormatStringSet) { jsonWriter.DateFormatString = dateFormatString; } if (cultureInfo != null) { jsonWriter.Culture = cultureInfo; } } internal IReferenceResolver GetReferenceResolver() { if (_referenceResolver == null) { _referenceResolver = new DefaultReferenceResolver(); } return _referenceResolver; } internal JsonConverter? GetMatchingConverter(Type type) { return GetMatchingConverter(_converters, type); } internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType) { if (converters != null) { for (int i = 0; i < converters.Count; i++) { JsonConverter jsonConverter = converters[i]; if (jsonConverter.CanConvert(objectType)) { return jsonConverter; } } } return null; } internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e) { this.Error?.Invoke(this, e); } } public class JsonSerializerSettings { internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error; internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore; internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include; internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include; internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto; internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None; internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default; internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None; internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default; internal static readonly StreamingContext DefaultContext; internal const Formatting DefaultFormatting = Formatting.None; internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat; internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime; internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double; internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String; internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default; internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple; internal static readonly CultureInfo DefaultCulture; internal const bool DefaultCheckAdditionalContent = false; internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; internal const int DefaultMaxDepth = 64; internal Formatting? _formatting; internal DateFormatHandling? _dateFormatHandling; internal DateTimeZoneHandling? _dateTimeZoneHandling; internal DateParseHandling? _dateParseHandling; internal FloatFormatHandling? _floatFormatHandling; internal FloatParseHandling? _floatParseHandling; internal StringEscapeHandling? _stringEscapeHandling; internal CultureInfo? _culture; internal bool? _checkAdditionalContent; internal int? _maxDepth; internal bool _maxDepthSet; internal string? _dateFormatString; internal bool _dateFormatStringSet; internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling; internal DefaultValueHandling? _defaultValueHandling; internal PreserveReferencesHandling? _preserveReferencesHandling; internal NullValueHandling? _nullValueHandling; internal ObjectCreationHandling? _objectCreationHandling; internal MissingMemberHandling? _missingMemberHandling; internal ReferenceLoopHandling? _referenceLoopHandling; internal StreamingContext? _context; internal ConstructorHandling? _constructorHandling; internal TypeNameHandling? _typeNameHandling; internal MetadataPropertyHandling? _metadataPropertyHandling; public ReferenceLoopHandling ReferenceLoopHandling { get { return _referenceLoopHandling.GetValueOrDefault(); } set { _referenceLoopHandling = value; } } public MissingMemberHandling MissingMemberHandling { get { return _missingMemberHandling.GetValueOrDefault(); } set { _missingMemberHandling = value; } } public ObjectCreationHandling ObjectCreationHandling { get { return _objectCreationHandling.GetValueOrDefault(); } set { _objectCreationHandling = value; } } public NullValueHandling NullValueHandling { get { return _nullValueHandling.GetValueOrDefault(); } set { _nullValueHandling = value; } } public DefaultValueHandling DefaultValueHandling { get { return _defaultValueHandling.GetValueOrDefault(); } set { _defaultValueHandling = value; } } public IList<JsonConverter> Converters { get; set; } public PreserveReferencesHandling PreserveReferencesHandling { get { return _preserveReferencesHandling.GetValueOrDef