Decompiled source of Custom Car Mod v1.1.3
Distance.CustomCar.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Distance.CustomCar.Data.Car; using Distance.CustomCar.Data.Errors; using Distance.CustomCar.Data.Materials; using Events; using Events.Car; using Events.MainMenu; using HarmonyLib; using JsonFx.Json; using JsonFx.Model; using JsonFx.Serialization; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Distance.ModTemplate")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Distance.ModTemplate")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7bcb2908-b003-45d9-be68-50cba5217603")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] public static class DictionaryExtensions { public static bool ContainsKey<T>(this Dictionary<string, object> obj, string key) { try { obj.GetItem<T>(key); return true; } catch { return false; } } public static T GetItem<T>(this Dictionary<string, object> obj, string key) { if (!obj.ContainsKey(key)) { throw new KeyNotFoundException("The key requested doesn't exist in store: '" + key + "'."); } try { return (T)Convert.ChangeType(obj[key], typeof(T)); } catch (Exception innerException) { throw new Exception("Failed type conversion exception has been thrown.", innerException); } } public static T GetOrCreate<T>(this Dictionary<string, object> obj, string key) where T : new() { if (!obj.ContainsKey(key)) { obj[key] = new T(); } return obj.GetItem<T>(key); } public static T GetOrCreate<T>(this Dictionary<string, object> obj, string key, T defaultValue) { if (!obj.ContainsKey<T>(key)) { obj[key] = defaultValue; } return obj.GetItem<T>(key); } } public static class GameObjectExtensions { public static string FullName(this GameObject obj) { if (!Object.op_Implicit((Object)(object)obj.transform.parent)) { return ((Object)obj).name; } return ((Component)obj.transform.parent).gameObject.FullName() + "/" + ((Object)obj).name; } } namespace Distance.CustomCar { public class Assets { private string _filePath = null; private string RootDirectory { get; } private string FileName { get; set; } private string FilePath => _filePath ?? Path.Combine(Path.Combine(RootDirectory, "Assets"), FileName); public object Bundle { get; private set; } private Assets() { } public Assets(string fileName) { RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location); FileName = fileName; if (!File.Exists(FilePath)) { Mod.Log.LogError((object)("Couldn't find requested asset bundle at " + FilePath)); } else { Bundle = Load(); } } public static Assets FromUnsafePath(string filePath) { if (!File.Exists(filePath)) { Mod.Log.LogError((object)("Could not find requested asset bundle at " + filePath)); return null; } Assets assets = new Assets { _filePath = filePath, FileName = Path.GetFileName(filePath) }; assets.Bundle = assets.Load(); if (assets.Bundle == null) { return null; } return assets; } private object Load() { try { object result = AssetBundleBridge.LoadFrom(FilePath); Mod.Log.LogInfo((object)("Loaded asset bundle " + FilePath)); return result; } catch (Exception ex) { Mod.Log.LogInfo((object)ex); return null; } } } internal static class AssetBundleBridge { public static Type AssetBundleType => Kernel.FindTypeByFullName("UnityEngine.AssetBundle", "UnityEngine"); private static MethodInfo LoadFromFile => AssetBundleType.GetMethod("LoadFromFile", new Type[1] { typeof(string) }); public static object LoadFrom(string path) { MethodInfo loadFromFile = LoadFromFile; object[] parameters = new string[1] { path }; return loadFromFile.Invoke(null, parameters); } } internal static class Kernel { internal static Type FindTypeByFullName(string fullName, string assemblyFilter) { IEnumerable<Assembly> enumerable = from a in AppDomain.CurrentDomain.GetAssemblies() where a.GetName().Name.Contains(assemblyFilter) select a; foreach (Assembly item in enumerable) { Type type = item.GetTypes().FirstOrDefault((Type t) => t.FullName == fullName); if ((object)type == null) { continue; } return type; } Mod.Log.LogError((object)("Type " + fullName + " wasn't found in the main AppDomain at this moment.")); throw new Exception("Type " + fullName + " wasn't found in the main AppDomain at this moment."); } } public class FileSystem { public string RootDirectory { get; } public string VirtualFileSystemRoot => Path.Combine(RootDirectory, "Data"); public FileSystem() { RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location); if (!Directory.Exists(VirtualFileSystemRoot)) { Directory.CreateDirectory(VirtualFileSystemRoot); } } public bool FileExists(string path) { string path2 = Path.Combine(VirtualFileSystemRoot, path); return File.Exists(path2); } public bool DirectoryExists(string path) { string path2 = Path.Combine(VirtualFileSystemRoot, path); return Directory.Exists(path2); } public bool PathExists(string path) { return FileExists(path) || DirectoryExists(path); } public byte[] ReadAllBytes(string filePath) { string text = Path.Combine(VirtualFileSystemRoot, filePath); if (!File.Exists(text)) { Mod.Log.LogInfo((object)("Couldn't read a file for path '" + text + "'. File does not exist.")); return null; } return File.ReadAllBytes(text); } public FileStream CreateFile(string filePath, bool overwrite = false) { string text = Path.Combine(VirtualFileSystemRoot, filePath); if (File.Exists(text)) { if (!overwrite) { Mod.Log.LogInfo((object)("Couldn't create a mod VFS file for path '" + text + "'. The file already exists.")); return null; } Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'. File does not exist.")); RemoveFile(filePath); } try { return File.Create(text); } catch (Exception ex) { Mod.Log.LogInfo((object)("Couldn't create a mod VFS file for path '" + text + "'.")); Mod.Log.LogInfo((object)ex); return null; } } public void RemoveFile(string filePath) { string text = Path.Combine(VirtualFileSystemRoot, filePath); if (!File.Exists(text)) { Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'. File does not exist.")); return; } try { File.Delete(text); } catch (Exception ex) { Mod.Log.LogInfo((object)("Couldn't delete a mod VFS file for path '" + text + "'.")); Mod.Log.LogInfo((object)ex); } } public void IterateOver(string directoryPath, Action<string, bool> action, bool sort = true) { string text = Path.Combine(VirtualFileSystemRoot, directoryPath); if (!Directory.Exists(text)) { Mod.Log.LogInfo((object)("Cannot iterate over directory at '" + text + "'. It doesn't exist.")); return; } List<string> list = Directory.GetFiles(text).ToList(); list.AddRange(Directory.GetDirectories(text)); if (sort) { list = list.OrderBy((string x) => x).ToList(); } foreach (string item in list) { try { bool arg = Directory.Exists(item); action(item, arg); } catch (Exception ex) { Mod.Log.LogInfo((object)("Action for the element at path '" + item + "' failed. See file system exception log for details.")); Mod.Log.LogInfo((object)ex); break; } } } public List<string> GetDirectories(string directoryPath, string searchPattern) { string text = Path.Combine(VirtualFileSystemRoot, directoryPath); if (!Directory.Exists(text)) { Mod.Log.LogInfo((object)("Cannot get directories in directory at '" + text + "'. It doesn't exist.")); return null; } return Directory.GetDirectories(text, searchPattern).ToList(); } public List<string> GetDirectories(string directoryPath) { return GetDirectories(directoryPath, "*"); } public List<string> GetFiles(string directoryPath, string searchPattern) { string text = Path.Combine(VirtualFileSystemRoot, directoryPath); if (!Directory.Exists(text)) { Mod.Log.LogInfo((object)("Cannot get files in directory at '" + text + "'. It doesn't exist.")); return null; } return Directory.GetFiles(text, searchPattern).ToList(); } public List<string> GetFiles(string directoryPath) { return GetFiles(directoryPath, "*"); } public FileStream OpenFile(string filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare) { string text = Path.Combine(VirtualFileSystemRoot, filePath); if (!File.Exists(text)) { Mod.Log.LogInfo((object)("Couldn't open a VFS file. The requested file: '" + text + "' does not exist.")); return null; } try { return File.Open(text, fileMode, fileAccess, fileShare); } catch (Exception ex) { Mod.Log.LogInfo((object)("Couldn't open a VFS file for path '" + text + "'.")); Mod.Log.LogInfo((object)ex); return null; } } public FileStream OpenFile(string filePath) { return OpenFile(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); } public string CreateDirectory(string directoryName) { string text = Path.Combine(VirtualFileSystemRoot, directoryName); try { Directory.CreateDirectory(text); return text; } catch (Exception ex) { Mod.Log.LogInfo((object)("Couldn't create a VFS directory for path '" + text + "'.")); Mod.Log.LogInfo((object)ex); return string.Empty; } } public void RemoveDirectory(string directoryPath) { string text = Path.Combine(VirtualFileSystemRoot, directoryPath); if (!Directory.Exists(text)) { Mod.Log.LogInfo((object)("Couldn't remove a VFS directory for path '" + text + "'. Directory does not exist.")); return; } try { Directory.Delete(text, recursive: true); } catch (Exception ex) { Mod.Log.LogInfo((object)("Couldn't remove a VFS directory for path '" + text + "'.")); Mod.Log.LogInfo((object)ex); } } public static string GetValidFileName(string dirtyFileName, string replaceInvalidCharsWith = "_") { return Regex.Replace(dirtyFileName, "[^\\w\\s\\.]", replaceInvalidCharsWith, RegexOptions.None); } public static string GetValidFileNameToLower(string dirtyFileName, string replaceInvalidCharsWith = "_") { return GetValidFileName(dirtyFileName, replaceInvalidCharsWith).ToLower(); } } public sealed class MessageBox { private readonly string Message = ""; private readonly string Title = ""; private float Time = 0f; private ButtonType Buttons = (ButtonType)0; private Action Confirm; private Action Cancel; private MessageBox(string message, string title) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) Message = message; Title = title; Confirm = EmptyAction; Cancel = EmptyAction; } public static MessageBox Create(string content, string title = "") { return new MessageBox(content, title); } public MessageBox SetButtons(MessageButtons buttons) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) Buttons = (ButtonType)buttons; return this; } public MessageBox SetTimeout(float delay) { Time = delay; return this; } public MessageBox OnConfirm(Action action) { Confirm = action; return this; } public MessageBox OnCancel(Action action) { Cancel = action; return this; } public void Show() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0042: Expected O, but got Unknown //IL_0042: Expected O, but got Unknown G.Sys.MenuPanelManager_.ShowMessage(Message, Title, (OnButtonClicked)delegate { Confirm(); }, (OnButtonClicked)delegate { Cancel(); }, Buttons, false, (Pivot)4, Time); } private void EmptyAction() { } } [Flags] public enum MessageButtons { Ok = 0, OkCancel = 1, YesNo = 2 } [BepInPlugin("Distance.CustomCar", "Custom Car", "1.1.3")] public sealed class Mod : BaseUnityPlugin { private const string modGUID = "Distance.CustomCar"; private const string modName = "Custom Car"; private const string modVersion = "1.1.3"; public static string UseTrumpetKey = "Use Trumpet Horn"; private static readonly Harmony harmony = new Harmony("Distance.CustomCar"); public static ManualLogSource Log = new ManualLogSource("Custom Car"); public static Mod Instance; private bool displayErrors_ = true; public static ConfigEntry<bool> UseTrumpetHorn { get; set; } public static int DefaultCarCount { get; private set; } public static int ModdedCarCount => TotalCarCount - DefaultCarCount; public static int TotalCarCount { get; private set; } public ErrorList Errors { get; set; } public ProfileCarColors CarColors { get; set; } private void Awake() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if ((Object)(object)Instance == (Object)null) { Instance = this; } Log = Logger.CreateLogSource("Distance.CustomCar"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Thanks for using Custom Cars!"); Errors = new ErrorList(((BaseUnityPlugin)this).Logger); CarColors = ((Component)this).gameObject.AddComponent<ProfileCarColors>(); UseTrumpetHorn = ((BaseUnityPlugin)this).Config.Bind<bool>("General", UseTrumpetKey, false, new ConfigDescription("Custom car models will use the encryptor horn (the \"doot!\" trumpet).", (AcceptableValueBase)null, new object[0])); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading..."); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded!"); } public void Start() { ProfileManager profileManager_ = G.Sys.ProfileManager_; DefaultCarCount = profileManager_.CarInfos_.Length; CarInfos carInfos = new CarInfos(); carInfos.CollectInfos(); CarBuilder carBuilder = new CarBuilder(); carBuilder.CreateCars(carInfos); TotalCarCount = profileManager_.CarInfos_.Length; CarColors.LoadAll(); Errors.Show(); } private void OnEnable() { StaticEvent<Data>.Subscribe((Delegate<Data>)OnMainMenuLoaded); } private void OnDisable() { StaticEvent<Data>.Unsubscribe((Delegate<Data>)OnMainMenuLoaded); } private void OnMainMenuLoaded(Data _) { if (displayErrors_) { Errors.Show(); displayErrors_ = false; } } private void OnConfigChanged(object sender, EventArgs e) { SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null); if (val != null) { } } } public class ProfileCarColors : MonoBehaviour { internal Settings Config; public event Action<ProfileCarColors> OnChanged; protected void Load() { Config = new Settings("CustomCars"); } protected void Awake() { Load(); Save(); } protected Dictionary<string, object> Profile(string profileName) { Mod.Log.LogInfo((object)"Assigning Profile Name..."); return Config.GetOrCreate(profileName, new Dictionary<string, object>()); } protected Dictionary<string, object> Vehicle(string profileName, string vehicleName) { Mod.Log.LogInfo((object)"Assigning Vehicle Name..."); return Profile(profileName).GetOrCreate(vehicleName, new Dictionary<string, object>()); } protected CarColors GetCarColors(string profileName, string vehicleName) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> vehicle = Vehicle(profileName, vehicleName); CarColors val = default(CarColors); val.primary_ = GetColor(vehicle, "primary", Colors.whiteSmoke); val.secondary_ = GetColor(vehicle, "secondary", Colors.darkGray); val.glow_ = GetColor(vehicle, "glow", Colors.cyan); val.sparkle_ = GetColor(vehicle, "sparkle", Colors.lightSlateGray); CarColors val2 = val; SetCarColors(profileName, vehicleName, val2); return val2; } protected Color GetColor(Dictionary<string, object> vehicle, string category, Color defaultColor) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) Dictionary<string, object> orCreate = vehicle.GetOrCreate(category, new Dictionary<string, object>()); float orCreate2 = orCreate.GetOrCreate("r", defaultColor.r); float orCreate3 = orCreate.GetOrCreate("g", defaultColor.g); float orCreate4 = orCreate.GetOrCreate("b", defaultColor.b); float orCreate5 = orCreate.GetOrCreate("a", defaultColor.a); return new Color(orCreate2, orCreate3, orCreate4, orCreate5); } protected void SetCarColors(string profileName, string vehicleName, CarColors colors) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> dictionary = Vehicle(profileName, vehicleName); dictionary["primary"] = ToSection(colors.primary_); dictionary["secondary"] = ToSection(colors.secondary_); dictionary["glow"] = ToSection(colors.glow_); dictionary["sparkle"] = ToSection(colors.sparkle_); Dictionary<string, object> dictionary2 = Profile(profileName); dictionary2[vehicleName] = dictionary; Config[profileName] = dictionary2; } protected Section ToSection(Color color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) return new Section { ["r"] = color.r, ["g"] = color.g, ["b"] = color.b, ["a"] = color.a }; } protected void Save() { Config.Save(); this.OnChanged?.Invoke(this); } public void LoadAll() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) ProfileManager profileManager_ = G.Sys.ProfileManager_; List<Profile> profiles_ = profileManager_.profiles_; foreach (Profile item in profiles_) { CarColors[] array = (CarColors[])(object)new CarColors[Mod.TotalCarCount]; for (int i = 0; i < profileManager_.CarInfos_.Length; i++) { if (i < Mod.DefaultCarCount) { array[i] = item.carColorsList_[i]; continue; } CarInfo val = profileManager_.CarInfos_[i]; Mod.Log.LogInfo((object)("Getting car color in " + item.FileName_ + "'s profile for the " + val.name_ + " car")); CarColors carColors = GetCarColors(item.FileName_, val.name_); array[i] = carColors; } item.carColorsList_ = array; } } public void SaveAll() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) ProfileManager profileManager_ = G.Sys.ProfileManager_; List<Profile> profiles_ = profileManager_.profiles_; foreach (Profile item in profiles_) { for (int i = 0; i < profileManager_.CarInfos_.Length; i++) { if (i >= Mod.DefaultCarCount) { CarInfo val = profileManager_.CarInfos_[i]; CarColors colors = item.carColorsList_[i]; SetCarColors(item.FileName_, val.name_, colors); } } } Save(); } } public class Section : Dictionary<string, object> { public new object this[string key] { get { if (!ContainsKey(key)) { return null; } return base[key]; } set { if (!ContainsKey(key)) { Add(key, value); this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, base[key])); } else { object oldValue = base[key]; base[key] = value; this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, oldValue, base[key])); } } } public event EventHandler<SettingsChangedEventArgs> ValueChanged; public T GetItem<T>(string key) { if (!ContainsKey(key)) { Mod.Log.LogError((object)("The key requested doesn't exist in store: '" + key + "'.")); throw new KeyNotFoundException("The key requested doesn't exist in store: '" + key + "'."); } try { return (T)Convert.ChangeType(this[key], typeof(T)); } catch (Exception ex) { Mod.Log.LogWarning((object)$"Failed type conversion exception has been thrown. String: {key} \n{ex}"); throw new SettingsException("Failed type conversion exception has been thrown.", key, isJsonFailure: false, ex); } } public T GetOrCreate<T>(string key) where T : new() { if (!ContainsKey(key)) { this[key] = new T(); this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, this[key])); } return GetItem<T>(key); } public T GetOrCreate<T>(string key, T defaultValue) { if (!ContainsKey<T>(key)) { this[key] = defaultValue; this.ValueChanged?.Invoke(this, new SettingsChangedEventArgs(key, null, this[key])); } return GetItem<T>(key); } public bool ContainsKey<T>(string key) { try { GetItem<T>(key); return true; } catch { return false; } } } public class Settings : Section { private string FileName { get; } private string RootDirectory { get; } private string SettingsDirectory => Path.Combine(RootDirectory, "Settings"); private string FilePath => Path.Combine(SettingsDirectory, FileName); public Settings(string fileName) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown RootDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location); FileName = fileName + ".json"; Mod.Log.LogInfo((object)("Settings instance for '" + FilePath + "' initializing...")); if (!File.Exists(FilePath)) { return; } bool flag = false; using (StreamReader streamReader = new StreamReader(FilePath)) { string text = streamReader.ReadToEnd(); JsonReader val = new JsonReader(); Section section = null; try { section = ((DataReader<ModelTokenType>)(object)val).Read<Section>(text); } catch (Exception ex) { Mod.Log.LogWarning((object)ex); flag = true; } if (section != null) { foreach (string key in section.Keys) { Add(key, section[key]); } } } if (flag) { Save(); } } public void Save(bool formatJson = true) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (!Directory.Exists(SettingsDirectory)) { Directory.CreateDirectory(SettingsDirectory); } DataWriterSettings val = new DataWriterSettings { PrettyPrint = formatJson }; JsonWriter val2 = new JsonWriter(val); try { using StreamWriter streamWriter = new StreamWriter(FilePath, append: false); streamWriter.WriteLine(((DataWriter<ModelTokenType>)(object)val2).Write((object)this)); } catch (Exception ex) { Mod.Log.LogWarning((object)ex); } } } public class SettingsChangedEventArgs : EventArgs { public string Key { get; } public object OldValue { get; } public object NewValue { get; } public SettingsChangedEventArgs(string key, object oldValue = null, object newValue = null) { Key = key; OldValue = oldValue; NewValue = newValue; } } public class SettingsException : Exception { public string Key { get; } public bool IsJsonFailure { get; } public SettingsException(string message, string key, bool isJsonFailure, Exception innerException) : base(message, innerException) { Key = key; IsJsonFailure = isJsonFailure; } public SettingsException(string message, string key, bool isJsonFailure) : this(message, key, isJsonFailure, null) { } } } namespace Distance.CustomCar.Patches { [HarmonyPatch(typeof(CarAudio), "OnCarHornEvent")] internal static class OnCarHornEvent { [HarmonyPrefix] internal static bool Prefix(CarAudio __instance, Data data) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) int num = G.Sys.ProfileManager_.knownCars_[__instance.carLogic_.PlayerData_.CarName_]; if (num >= Mod.DefaultCarCount && Mod.UseTrumpetHorn.Value) { __instance.phantom_.SetRTPCValue("Horn_volume", Mathf.Clamp01(data.hornPercent_ + 0.5f)); __instance.phantom_.Play("SpookyHorn", 0f, true); return false; } return true; } } [HarmonyPatch(typeof(GadgetWithAnimation), "SetAnimationStateValues")] internal static class GadgetWithAnimation__SetAnimationStateValues { [HarmonyPrefix] internal static bool Prefix(GadgetWithAnimation __instance) { Animation componentInChildren = ((Component)__instance).GetComponentInChildren<Animation>(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { return PatchAnimations(componentInChildren, __instance.animationName_); } return false; } private static bool PatchAnimations(Animation animation, string name) { if (Object.op_Implicit((Object)(object)animation)) { if (!ChangeBlendModeToBlend(((Component)animation).transform, name)) { return true; } AnimationState val = animation[name]; if (TrackedReference.op_Implicit((TrackedReference)(object)val)) { val.layer = 3; val.blendMode = (AnimationBlendMode)0; val.wrapMode = (WrapMode)8; val.enabled = true; val.weight = 1f; val.speed = 0f; } } return false; } private static bool ChangeBlendModeToBlend(Transform obj, string animationName) { for (int i = 0; i < obj.childCount; i++) { string text = ((Object)((Component)obj.GetChild(i)).gameObject).name.ToLower(); if (!text.StartsWith("#")) { continue; } text = text.Remove(0, 1); string[] array = text.Split(new char[1] { ';' }); if (array.Length == 1) { if (array[0] == "additive") { return false; } if (array[0] == "blend") { return true; } } if (array[1] == animationName.ToLower()) { if (array[0] == "additive") { return false; } if (array[0] == "blend") { return true; } } } return false; } } [HarmonyPatch(typeof(Profile), "Awake")] internal static class Profile__Awake { [HarmonyPostfix] internal static void Postfix(Profile __instance) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) CarColors[] array = (CarColors[])(object)new CarColors[G.Sys.ProfileManager_.carInfos_.Length]; for (int i = 0; i < array.Length; i++) { array[i] = G.Sys.ProfileManager_.carInfos_[i].colors_; } __instance.carColorsList_ = array; } } [HarmonyPatch(typeof(Profile), "Save")] internal static class Profile__Save { [HarmonyPostfix] internal static void Postfix() { Mod.Instance.CarColors.SaveAll(); } } [HarmonyPatch(typeof(Profile), "SetColorsForAllCars", new Type[] { typeof(CarColors) })] internal static class Profile__SetColorsForAllCars { [HarmonyPrefix] internal static bool Prefix(Profile __instance, CarColors cc) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) CarColors[] array = (CarColors[])(object)new CarColors[G.Sys.ProfileManager_.carInfos_.Length]; for (int i = 0; i < array.Length; i++) { array[i] = cc; } __instance.carColorsList_ = array; __instance.dataModified_ = true; return false; } } } namespace Distance.CustomCar.Data.Materials { public class MaterialInfos { public Material material; public int diffuseIndex = -1; public int normalIndex = -1; public int emitIndex = -1; public void ReplaceMaterialInRenderer(Renderer renderer, int materialIndex) { if (!((Object)(object)material == (Object)null) && !((Object)(object)renderer == (Object)null) && materialIndex < renderer.materials.Length) { ref Material reference = ref renderer.materials[materialIndex]; Material val = Object.Instantiate<Material>(material); if (diffuseIndex >= 0) { val.SetTexture(diffuseIndex, reference.GetTexture("_MainTex")); } if (emitIndex >= 0) { val.SetTexture(emitIndex, reference.GetTexture("_EmissionMap")); } if (normalIndex >= 0) { val.SetTexture(normalIndex, reference.GetTexture("_BumpMap")); } renderer.materials[materialIndex] = val; } } } public class MaterialPropertyExport { public string fromName; public string toName; public int fromID = -1; public int toID = -1; public PropertyType type; } public class MaterialPropertyInfo { public string shaderName; public string name; public int diffuseIndex = -1; public int normalIndex = -1; public int emitIndex = -1; public MaterialPropertyInfo(string _shaderName, string _name, int _diffuseIndex, int _normalIndex, int _emitIndex) { shaderName = _shaderName; name = _name; diffuseIndex = _diffuseIndex; normalIndex = _normalIndex; emitIndex = _emitIndex; } } public enum PropertyType { Color, ColorArray, Float, FloatArray, Int, Matrix, MatrixArray, Texture, Vector, VectorArray } } namespace Distance.CustomCar.Data.Errors { public class ErrorList : List<string> { private readonly ManualLogSource logger_; public ErrorList(ManualLogSource logger) { logger_ = logger; } public new void Add(string value) { base.Add(value); logger_.LogInfo((object)value); } public void Add(Exception value) { base.Add(value.ToString()); logger_.LogInfo((object)value); } public void Show() { if (this.Any()) { string arg = ((base.Count < 15) ? string.Join(Environment.NewLine, ToArray()) : "There were too many errors when loading custom cars to be displayed here, please check the logs in your mod installation directory."); MessageBox.Create($"Can't load the cars correctly: {base.Count} error(s)\n{arg}", "CUSTOM CARS - ERRORS").SetButtons(MessageButtons.Ok).Show(); } } } } namespace Distance.CustomCar.Data.Car { public class CarBuilder { private CarInfos infos_; public void CreateCars(CarInfos infos) { infos_ = infos; Dictionary<string, GameObject> dictionary = LoadAssetsBundles(); List<CreateCarReturnInfos> list = new List<CreateCarReturnInfos>(); foreach (KeyValuePair<string, GameObject> item in dictionary) { try { Mod.Log.LogInfo((object)("Creating car prefab for " + item.Key + " ...")); CreateCarReturnInfos createCarReturnInfos = CreateCar(item.Value); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item.Key.Substring(0, item.Key.LastIndexOf('(') - 1)); ((Object)createCarReturnInfos.car).name = fileNameWithoutExtension; list.Add(createCarReturnInfos); } catch (Exception value) { Mod.Log.LogError((object)("Could not load car prefab: " + item.Key)); Mod.Instance.Errors.Add("Could not load car prefab: " + item.Key); Mod.Instance.Errors.Add(value); } } RegisterCars(list); } private void RegisterCars(List<CreateCarReturnInfos> carsInfos) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) Mod.Log.LogInfo((object)$"Registering {carsInfos.Count} car(s)..."); ProfileManager profileManager_ = G.Sys.ProfileManager_; CarInfo[] array = ICollectionEx.ToArray<CarInfo>((ICollection<CarInfo>)profileManager_.carInfos_); profileManager_.carInfos_ = (CarInfo[])(object)new CarInfo[array.Length + carsInfos.Count]; ref Dictionary<string, int> unlockedCars_ = ref profileManager_.unlockedCars_; ref Dictionary<string, int> knownCars_ = ref profileManager_.knownCars_; for (int i = 0; i < profileManager_.carInfos_.Length; i++) { if (i < array.Length) { profileManager_.carInfos_[i] = array[i]; continue; } int index = i - array.Length; CarInfo val = new CarInfo { name_ = ((Object)carsInfos[index].car).name, prefabs_ = new CarPrefabs { carPrefab_ = carsInfos[index].car }, colors_ = carsInfos[index].colors }; if (!knownCars_.ContainsKey(val.name_) && !unlockedCars_.ContainsKey(val.name_)) { unlockedCars_.Add(val.name_, i); knownCars_.Add(val.name_, i); } else { Mod.Instance.Errors.Add("A car with the name " + val.name_ + " is already registered, rename the car file if they're the same."); Mod.Log.LogInfo((object)("Generating unique name for car " + val.name_)); string text = $"#{Guid.NewGuid():B}"; Mod.Log.LogInfo((object)("Using GUID: " + text)); val.name_ = "[FFFF00]![-] " + val.name_ + " " + text; unlockedCars_.Add(val.name_, i); knownCars_.Add(val.name_, i); } profileManager_.carInfos_[i] = val; } CarColors[] array2 = (CarColors[])(object)new CarColors[array.Length + carsInfos.Count]; for (int j = 0; j < array2.Length; j++) { array2[j] = G.Sys.ProfileManager_.carInfos_[j].colors_; } for (int k = 0; k < profileManager_.ProfileCount_; k++) { Profile profile = profileManager_.GetProfile(k); CarColors[] carColorsList_ = profile.carColorsList_; for (int l = 0; l < carColorsList_.Length && l < array2.Length; l++) { array2[l] = carColorsList_[l]; } profile.carColorsList_ = array2; } } private Dictionary<string, GameObject> LoadAssetsBundles() { Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>(); DirectoryInfo localFolder = GetLocalFolder("Assets"); DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Resource.personalDistanceDirPath_, "CustomCars")); if (!directoryInfo.Exists) { try { directoryInfo.Create(); } catch (Exception ex) { Mod.Instance.Errors.Add("Could not create the following folder: " + directoryInfo.FullName); Mod.Log.LogError((object)("Could not create the following folder: " + directoryInfo.FullName)); Mod.Instance.Errors.Add(ex); Mod.Log.LogError((object)ex); } } DirectoryInfo directoryInfo2 = new DirectoryInfo(Directory.GetParent(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location)).ToString()); foreach (FileInfo item in from x in ArrayEx.Concat<FileInfo>(directoryInfo2.GetFiles("*", SearchOption.AllDirectories), directoryInfo.GetFiles("*", SearchOption.AllDirectories)) orderby x.Name select x) { if (!(item.Extension == "")) { continue; } try { Assets assets = Assets.FromUnsafePath(item.FullName); object bundle = assets.Bundle; AssetBundle val = (AssetBundle)((bundle is AssetBundle) ? bundle : null); int num = 0; foreach (string item2 in from name in val.GetAllAssetNames() where name.EndsWith(".prefab", StringComparison.InvariantCultureIgnoreCase) select name) { GameObject value = val.LoadAsset<GameObject>(item2); string key = item.FullName + " (" + item2 + ")"; if (!dictionary.ContainsKey(key)) { dictionary.Add(key, value); num++; } } if (num == 0) { Mod.Instance.Errors.Add("Can't find a prefab in the asset bundle: " + item.FullName); Mod.Log.LogError((object)("Can't find a prefab in the asset bundle: " + item.FullName)); } } catch (Exception ex2) { Mod.Instance.Errors.Add("Could not load assets file: " + item.FullName); Mod.Log.LogError((object)("Could not load assets file: " + item.FullName)); Mod.Instance.Errors.Add(ex2); Mod.Log.LogError((object)ex2); } } return dictionary; } public DirectoryInfo GetLocalFolder(string dir) { FileSystem fileSystem = new FileSystem(); return new DirectoryInfo(Path.GetDirectoryName(Path.Combine(fileSystem.RootDirectory, dir + (dir.EndsWith($"{Path.DirectorySeparatorChar}") ? string.Empty : $"{Path.DirectorySeparatorChar}")))); } private CreateCarReturnInfos CreateCar(GameObject car) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) CreateCarReturnInfos createCarReturnInfos = new CreateCarReturnInfos(); GameObject val = Object.Instantiate<GameObject>(infos_.baseCar); ((Object)val).name = ((Object)car).name; Object.DontDestroyOnLoad((Object)(object)val); val.SetActive(false); RemoveOldCar(val); GameObject car2 = AddNewCarOnPrefab(val, car); SetCarDatas(val, car2); createCarReturnInfos.car = val; createCarReturnInfos.colors = LoadDefaultColors(car2); return createCarReturnInfos; } private void RemoveOldCar(GameObject obj) { List<GameObject> list = new List<GameObject>(); for (int i = 0; i < obj.transform.childCount; i++) { GameObject gameObject = ((Component)obj.transform.GetChild(i)).gameObject; if (((Object)gameObject).name.IndexOf("wheel", StringComparison.InvariantCultureIgnoreCase) >= 0) { list.Add(gameObject); } } if (list.Count != 4) { Mod.Instance.Errors.Add($"Found {list.Count} wheels on base prefabs, expected 4"); Mod.Log.LogError((object)$"Found {list.Count} wheels on base prefabs, expected 4"); } Transform val = obj.transform.Find("Refractor"); if ((Object)(object)val == (Object)null) { Mod.Instance.Errors.Add("Can't find the Refractor object on the base car prefab"); Mod.Log.LogError((object)"Can't find the Refractor object on the base car prefab"); return; } Object.Destroy((Object)(object)((Component)val).gameObject); foreach (GameObject item in list) { Object.Destroy((Object)(object)item); } } private GameObject AddNewCarOnPrefab(GameObject obj, GameObject car) { return Object.Instantiate<GameObject>(car, obj.transform); } private void SetCarDatas(GameObject obj, GameObject car) { SetColorChanger(obj.GetComponent<ColorChanger>(), car); SetCarVisuals(obj.GetComponent<CarVisuals>(), car); } private void SetColorChanger(ColorChanger colorChanger, GameObject car) { if ((Object)(object)colorChanger == (Object)null) { Mod.Instance.Errors.Add("Can't find the ColorChanger component on the base car"); Mod.Log.LogError((object)"Can't find the ColorChanger component on the base car"); return; } colorChanger.rendererChangers_ = (RendererChanger[])(object)new RendererChanger[0]; Renderer[] componentsInChildren = car.GetComponentsInChildren<Renderer>(); foreach (Renderer val in componentsInChildren) { ReplaceMaterials(val); if ((Object)(object)colorChanger != (Object)null) { AddMaterialColorChanger(colorChanger, ((Component)val).transform); } } } private void ReplaceMaterials(Renderer renderer) { string[] array = new string[renderer.materials.Length]; for (int i = 0; i < array.Length; i++) { array[i] = "wheel"; } List<MaterialPropertyExport>[] array2 = new List<MaterialPropertyExport>[renderer.materials.Length]; for (int j = 0; j < array2.Length; j++) { array2[j] = new List<MaterialPropertyExport>(); } FillMaterialInfos(renderer, array, array2); Material[] array3 = ICollectionEx.ToArray<Material>((ICollection<Material>)renderer.materials); for (int k = 0; k < renderer.materials.Length; k++) { if (!infos_.materials.TryGetValue(array[k], out var value)) { Mod.Instance.Errors.Add("Can't find the material " + array[k] + " on " + ((Component)renderer).gameObject.FullName()); Mod.Log.LogError((object)("Can't find the material " + array[k] + " on " + ((Component)renderer).gameObject.FullName())); } else { if (value == null || (Object)(object)value.material == (Object)null) { continue; } Material val = Object.Instantiate<Material>(value.material); if (value.diffuseIndex >= 0) { val.SetTexture(value.diffuseIndex, renderer.materials[k].GetTexture("_MainTex")); } if (value.normalIndex >= 0) { val.SetTexture(value.normalIndex, renderer.materials[k].GetTexture("_BumpMap")); } if (value.emitIndex >= 0) { val.SetTexture(value.emitIndex, renderer.materials[k].GetTexture("_EmissionMap")); } foreach (MaterialPropertyExport item in array2[k]) { CopyMaterialProperty(renderer.materials[k], val, item); } array3[k] = val; } } renderer.materials = array3; } private void FillMaterialInfos(Renderer renderer, string[] matNames, List<MaterialPropertyExport>[] materialProperties) { int childCount = ((Component)renderer).transform.childCount; for (int i = 0; i < childCount; i++) { string text = ((Object)((Component)renderer).transform.GetChild(i)).name.ToLower(); if (!text.StartsWith("#")) { continue; } text = text.Remove(0, 1); string[] array = text.Split(new char[1] { ';' }); if (array.Length == 0) { continue; } if (array[0].Contains("mat")) { int result; if (array.Length != 3) { Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 2 arguments"); Mod.Log.LogError((object)(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 2 arguments")); } else if (!int.TryParse(array[1], out result)) { Mod.Instance.Errors.Add("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number"); Mod.Log.LogError((object)("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number")); } else if (result < matNames.Length) { matNames[result] = array[2]; } } else { if (!array[0].Contains("export")) { continue; } int result2; if (array.Length != 5) { Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 4 arguments"); Mod.Log.LogError((object)(array[0] + " property on " + ((Component)renderer).gameObject.FullName() + " must have 4 arguments")); } else if (!int.TryParse(array[1], out result2)) { Mod.Instance.Errors.Add("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number"); Mod.Log.LogError((object)("First argument of " + array[0] + " on " + ((Component)renderer).gameObject.FullName() + " property must be a number")); } else { if (result2 >= matNames.Length) { continue; } MaterialPropertyExport materialPropertyExport = new MaterialPropertyExport(); bool flag = false; foreach (PropertyType value in Enum.GetValues(typeof(PropertyType))) { if (array[2] == value.ToString().ToLower()) { flag = true; materialPropertyExport.type = value; break; } } if (!flag) { Mod.Instance.Errors.Add("The property " + array[2] + " on " + ((Component)renderer).gameObject.FullName() + " is not valid"); Mod.Log.LogError((object)("The property " + array[2] + " on " + ((Component)renderer).gameObject.FullName() + " is not valid")); } else { if (!int.TryParse(array[3], out materialPropertyExport.fromID)) { materialPropertyExport.fromName = array[3]; } if (!int.TryParse(array[4], out materialPropertyExport.toID)) { materialPropertyExport.toName = array[4]; } materialProperties[result2].Add(materialPropertyExport); } } } } } private void CopyMaterialProperty(Material from, Material to, MaterialPropertyExport property) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) int num = property.fromID; if (num == -1) { num = Shader.PropertyToID(property.fromName); } int num2 = property.toID; if (num2 == -1) { num2 = Shader.PropertyToID(property.toName); } switch (property.type) { case PropertyType.Color: to.SetColor(num2, from.GetColor(num)); break; case PropertyType.ColorArray: to.SetColorArray(num2, from.GetColorArray(num)); break; case PropertyType.Float: to.SetFloat(num2, from.GetFloat(num)); break; case PropertyType.FloatArray: to.SetFloatArray(num2, from.GetFloatArray(num)); break; case PropertyType.Int: to.SetInt(num2, from.GetInt(num)); break; case PropertyType.Matrix: to.SetMatrix(num2, from.GetMatrix(num)); break; case PropertyType.MatrixArray: to.SetMatrixArray(num2, from.GetMatrixArray(num)); break; case PropertyType.Texture: to.SetTexture(num2, from.GetTexture(num)); break; case PropertyType.Vector: to.SetVector(num2, from.GetVector(num)); break; case PropertyType.VectorArray: to.SetVectorArray(num2, from.GetVectorArray(num)); break; } } private void AddMaterialColorChanger(ColorChanger colorChanger, Transform transform) { //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) Renderer component = ((Component)transform).GetComponent<Renderer>(); if ((Object)(object)component == (Object)null) { return; } List<UniformChanger> list = new List<UniformChanger>(); for (int i = 0; i < transform.childCount; i++) { GameObject gameObject = ((Component)transform.GetChild(i)).gameObject; string text = ((Object)gameObject).name.ToLower(); if (!text.StartsWith("#")) { continue; } text = text.Remove(0, 1); string[] array = text.Split(new char[1] { ';' }); if (array.Length != 0 && array[0].Contains("color")) { if (array.Length != 6) { Mod.Instance.Errors.Add(array[0] + " property on " + ((Component)transform).gameObject.FullName() + " must have 5 arguments"); Mod.Log.LogError((object)(array[0] + " property on " + ((Component)transform).gameObject.FullName() + " must have 5 arguments")); continue; } UniformChanger val = new UniformChanger(); int.TryParse(array[1], out var result); val.materialIndex_ = result; val.colorType_ = ColorType(array[2]); val.name_ = UniformName(array[3]); float.TryParse(array[4], out var result2); val.mul_ = result2; val.alpha_ = string.Equals(array[5], "true", StringComparison.InvariantCultureIgnoreCase); list.Add(val); } } if (list.Count != 0) { RendererChanger item = new RendererChanger { renderer_ = component, uniformChangers_ = list.ToArray() }; List<RendererChanger> list2 = colorChanger.rendererChangers_.ToList(); list2.Add(item); colorChanger.rendererChangers_ = list2.ToArray(); } } private ColorType ColorType(string name) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) name = name.ToLower(); return (ColorType)(name switch { "primary" => 0, "secondary" => 1, "glow" => 2, "sparkle" => 3, _ => 0, }); } private SupportedUniform UniformName(string name) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) name = name.ToLower(); return (SupportedUniform)(name switch { "color" => 0, "color2" => 1, "emitcolor" => 2, "reflectcolor" => 4, "speccolor" => 5, _ => 0, }); } private void SetCarVisuals(CarVisuals visuals, GameObject car) { if ((Object)(object)visuals == (Object)null) { Mod.Instance.Errors.Add("Can't find the CarVisuals component on the base car"); Mod.Log.LogInfo((object)"Can't find the CarVisuals component on the base car"); return; } SkinnedMeshRenderer componentInChildren = car.GetComponentInChildren<SkinnedMeshRenderer>(); MakeMeshSkinned(componentInChildren); visuals.carBodyRenderer_ = componentInChildren; List<JetFlame> list = new List<JetFlame>(); List<JetFlame> list2 = new List<JetFlame>(); List<JetFlame> list3 = new List<JetFlame>(); PlaceJets(car, list, list2, list3); visuals.boostJetFlames_ = list.ToArray(); visuals.wingJetFlames_ = list2.ToArray(); visuals.rotationJetFlames_ = list3.ToArray(); visuals.driverPosition_ = FindCarDriver(car.transform); PlaceCarWheelsVisuals(visuals, car); } private void MakeMeshSkinned(SkinnedMeshRenderer renderer) { //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) Mesh sharedMesh = renderer.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { Mod.Instance.Errors.Add("The mesh on " + ((Component)renderer).gameObject.FullName() + " is null"); Mod.Log.LogError((object)("The mesh on " + ((Component)renderer).gameObject.FullName() + " is null")); } else if (!sharedMesh.isReadable) { Mod.Instance.Errors.Add("Can't read the car mesh " + ((Object)sharedMesh).name + " on " + ((Component)renderer).gameObject.FullName() + "You must allow reading on it's unity inspector !"); Mod.Log.LogError((object)("Can't read the car mesh " + ((Object)sharedMesh).name + " on " + ((Component)renderer).gameObject.FullName() + "You must allow reading on it's unity inspector !")); } else if (sharedMesh.vertices.Length != sharedMesh.boneWeights.Length) { BoneWeight[] array = (BoneWeight[])(object)new BoneWeight[sharedMesh.vertices.Length]; for (int i = 0; i < array.Length; i++) { ((BoneWeight)(ref array[i])).weight0 = 1f; } sharedMesh.boneWeights = array; Transform transform = ((Component)renderer).transform; sharedMesh.bindposes = (Matrix4x4[])(object)new Matrix4x4[1] { transform.worldToLocalMatrix * ((Component)renderer).transform.localToWorldMatrix }; renderer.bones = (Transform[])(object)new Transform[1] { transform }; } } private void PlaceJets(GameObject obj, List<JetFlame> boostJets, List<JetFlame> wingJets, List<JetFlame> rotationJets) { //IL_0075: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) int childCount = obj.transform.childCount; for (int i = 0; i < childCount; i++) { GameObject gameObject = GameObjectEx.GetChild(obj, i).gameObject; string text = ((Object)gameObject).name.ToLower(); if ((Object)(object)infos_.boostJet != (Object)null && text.Contains("boostjet")) { GameObject val = Object.Instantiate<GameObject>(infos_.boostJet, gameObject.transform); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; boostJets.Add(val.GetComponentInChildren<JetFlame>()); } else if ((Object)(object)infos_.wingJet != (Object)null && text.Contains("wingjet")) { GameObject val2 = Object.Instantiate<GameObject>(infos_.wingJet, gameObject.transform); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; wingJets.Add(val2.GetComponentInChildren<JetFlame>()); ListEx.Last<JetFlame>(wingJets).rotationAxis_ = JetDirection(gameObject.transform); } else if ((Object)(object)infos_.rotationJet != (Object)null && text.Contains("rotationjet")) { GameObject val3 = Object.Instantiate<GameObject>(infos_.rotationJet, gameObject.transform); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; rotationJets.Add(val3.GetComponentInChildren<JetFlame>()); ListEx.Last<JetFlame>(rotationJets).rotationAxis_ = JetDirection(gameObject.transform); } else if ((Object)(object)infos_.wingTrail != (Object)null && text.Contains("wingtrail")) { GameObject val4 = Object.Instantiate<GameObject>(infos_.wingTrail, gameObject.transform); val4.transform.localPosition = Vector3.zero; val4.transform.localRotation = Quaternion.identity; } else { PlaceJets(gameObject, boostJets, wingJets, rotationJets); } } } private Vector3 JetDirection(Transform transform) { //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) int childCount = transform.childCount; for (int i = 0; i < childCount; i++) { string text = ((Object)((Component)transform.GetChild(i)).gameObject).name.ToLower(); if (!text.StartsWith("#")) { continue; } text = text.Remove(0, 1); string[] array = text.Split(new char[1] { ';' }); if (array.Length != 0 && array[0].Contains("dir") && array.Length >= 2) { if (array[1] == "front") { return new Vector3(-1f, 0f, 0f); } if (array[1] == "back") { return new Vector3(1f, 0f, 0f); } if (array[1] == "left") { return new Vector3(0f, 1f, -1f); } if (array[1] == "right") { return new Vector3(0f, -1f, 1f); } if (array.Length == 4 && array[0].Contains("dir")) { Vector3 zero = Vector3.zero; float.TryParse(array[1], out zero.x); float.TryParse(array[2], out zero.y); float.TryParse(array[3], out zero.z); return zero; } } } return Vector3.zero; } private Transform FindCarDriver(Transform parent) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); Transform val = ((((Object)((Component)child).gameObject).name.IndexOf("driverposition", StringComparison.InvariantCultureIgnoreCase) >= 0) ? child : FindCarDriver(child)); if ((Object)(object)val != (Object)null) { return val; } } return null; } private void PlaceCarWheelsVisuals(CarVisuals visual, GameObject car) { for (int i = 0; i < car.transform.childCount; i++) { GameObject gameObject = ((Component)car.transform.GetChild(i)).gameObject; string text = ((Object)gameObject).name.ToLower(); if (!text.Contains("wheel")) { continue; } CarWheelVisuals val = gameObject.AddComponent<CarWheelVisuals>(); MeshRenderer[] componentsInChildren = gameObject.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val2 in componentsInChildren) { if (((Object)((Component)val2).gameObject).name.IndexOf("tire", StringComparison.InvariantCultureIgnoreCase) >= 0) { val.tire_ = val2; break; } } if (text.Contains("front")) { if (text.Contains("left")) { visual.wheelFL_ = val; } else if (text.Contains("right")) { visual.wheelFR_ = val; } } else if (text.Contains("back")) { if (text.Contains("left")) { visual.wheelBL_ = val; } else if (text.Contains("right")) { visual.wheelBR_ = val; } } } } private CarColors LoadDefaultColors(GameObject car) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) CarColors val2 = default(CarColors); for (int i = 0; i < car.transform.childCount; i++) { GameObject gameObject = ((Component)car.transform.GetChild(i)).gameObject; string text = ((Object)gameObject).name.ToLower(); if (!text.Contains("defaultcolor")) { continue; } for (int j = 0; j < gameObject.transform.childCount; j++) { GameObject gameObject2 = ((Component)gameObject.transform.GetChild(j)).gameObject; string text2 = ((Object)gameObject2).name.ToLower(); if (!text2.StartsWith("#")) { continue; } text2 = text2.Remove(0, 1); string[] array = text2.Split(new char[1] { ';' }); if (array.Length == 2) { Color val = ColorEx.HexToColor(array[1], byte.MaxValue); val.a = 1f; if (array[0] == "primary") { val2.primary_ = val; } else if (array[0] == "secondary") { val2.secondary_ = val; } else if (array[0] == "glow") { val2.glow_ = val; } else if (array[0] == "sparkle") { val2.sparkle_ = val; } } } } return infos_.defaultColors; } } public class CarInfos { public Dictionary<string, MaterialInfos> materials = new Dictionary<string, MaterialInfos>(); public GameObject boostJet = null; public GameObject wingJet = null; public GameObject rotationJet = null; public GameObject wingTrail = null; public GameObject baseCar = null; public CarColors defaultColors; public void CollectInfos() { GetBaseCar(); GetJetsAndTrail(); GetMaterials(); } private void GetBaseCar() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) GameObject carPrefab_ = G.Sys.ProfileManager_.carInfos_[0].prefabs_.carPrefab_; if ((Object)(object)carPrefab_ == (Object)null) { Mod.Instance.Errors.Add("Can't find the refractor base car prefab"); return; } baseCar = carPrefab_; defaultColors = G.Sys.ProfileManager_.carInfos_[0].colors_; } private void GetJetsAndTrail() { if ((Object)(object)baseCar == (Object)null) { return; } JetFlame[] componentsInChildren = baseCar.GetComponentsInChildren<JetFlame>(); foreach (JetFlame val in componentsInChildren) { switch (((Object)((Component)val).gameObject).name) { case "BoostJetFlameCenter": boostJet = ((Component)val).gameObject; break; case "JetFlameBackLeft": rotationJet = ((Component)val).gameObject; break; case "WingJetFlameLeft1": wingJet = ((Component)val).gameObject; break; } } wingTrail = ((Component)baseCar.GetComponentInChildren<WingTrail>()).gameObject; if ((Object)(object)boostJet == (Object)null) { Mod.Instance.Errors.Add("No valid BoostJet found on Refractor"); } if ((Object)(object)rotationJet == (Object)null) { Mod.Instance.Errors.Add("No valid RotationJet found on Refractor"); } if ((Object)(object)wingJet == (Object)null) { Mod.Instance.Errors.Add("No valid WingJet found on Refractor"); } if ((Object)(object)wingTrail == (Object)null) { Mod.Instance.Errors.Add("No valid WingTrail found on Refractor"); } } private void GetMaterials() { List<MaterialPropertyInfo> list = new List<MaterialPropertyInfo> { new MaterialPropertyInfo("Custom/LaserCut/CarPaint", "carpaint", 5, -1, -1), new MaterialPropertyInfo("Custom/LaserCut/CarWindow", "carwindow", -1, 218, 219), new MaterialPropertyInfo("Custom/Reflective/Bump Glow LaserCut", "wheel", 5, 218, 255), new MaterialPropertyInfo("Custom/LaserCut/CarPaintBump", "carpaintbump", 5, 218, -1), new MaterialPropertyInfo("Custom/Reflective/Bump Glow Interceptor Special", "interceptor", 5, 218, 255), new MaterialPropertyInfo("Custom/LaserCut/CarWindowTrans2Sided", "transparentglow", -1, 218, 219) }; CarInfo[] carInfos_ = G.Sys.ProfileManager_.carInfos_; foreach (CarInfo val in carInfos_) { GameObject carPrefab_ = val.prefabs_.carPrefab_; Renderer[] componentsInChildren = carPrefab_.GetComponentsInChildren<Renderer>(); foreach (Renderer val2 in componentsInChildren) { Material[] array = val2.materials; foreach (Material val3 in array) { foreach (MaterialPropertyInfo item in list) { if (!materials.ContainsKey(item.name) && ((Object)val3.shader).name == item.shaderName) { MaterialInfos value = new MaterialInfos { material = val3, diffuseIndex = item.diffuseIndex, normalIndex = item.normalIndex, emitIndex = item.emitIndex }; materials.Add(item.name, value); } } } } } foreach (MaterialPropertyInfo item2 in list) { if (!materials.ContainsKey(item2.name)) { Mod.Instance.Errors.Add("Can't find the material: " + item2.name + " - shader: " + item2.shaderName); } } materials.Add("donotreplace", new MaterialInfos()); } } public class CreateCarReturnInfos { public GameObject car; public CarColors colors; } }
JsonFx.dll
Decompiled 3 weeks 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.Generic; using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Xml; using System.Xml.Serialization; using JsonFx.CodeGen; using JsonFx.IO; using JsonFx.Json; using JsonFx.Linq; using JsonFx.Markup; using JsonFx.Model; using JsonFx.Model.Filters; using JsonFx.Serialization; using JsonFx.Serialization.Filters; using JsonFx.Serialization.GraphCycles; using JsonFx.Serialization.Resolvers; using JsonFx.Utils; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCopyright("Copyright © 2006-2010 Stephen M. McKamey. All rights reserved.")] [assembly: AssemblyCompany("http://jsonfx.net")] [assembly: AllowPartiallyTrustedCallers] [assembly: AssemblyDescription("JsonFx Serialization Framework")] [assembly: AssemblyProduct("JsonFx v2")] [assembly: AssemblyTitle("JsonFx")] [assembly: AssemblyConfiguration(".NET 3.5 Signed")] [assembly: Guid("D98A5EF8-4709-4FF8-B162-8EA04B281400")] [assembly: AssemblyFileVersion("2.0.1209.2802")] [assembly: AssemblyVersion("2.0.1209.2802")] namespace JsonFx { public sealed class About { public static readonly About Fx = new About(typeof(About).Assembly); public readonly Version Version; public readonly string FullName; public readonly string Name; public readonly string Configuration; public readonly string Copyright; public readonly string Title; public readonly string Description; public readonly string Company; public About(Assembly assembly) { if ((object)assembly == null) { throw new ArgumentNullException("assembly"); } AssemblyName name = assembly.GetName(); FullName = assembly.FullName; Version = name.Version; Name = name.Name; AssemblyCopyrightAttribute assemblyCopyrightAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute; Copyright = ((assemblyCopyrightAttribute != null) ? assemblyCopyrightAttribute.Copyright : string.Empty); AssemblyDescriptionAttribute assemblyDescriptionAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute; Description = ((assemblyDescriptionAttribute != null) ? assemblyDescriptionAttribute.Description : string.Empty); AssemblyTitleAttribute assemblyTitleAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute)) as AssemblyTitleAttribute; Title = ((assemblyTitleAttribute != null) ? assemblyTitleAttribute.Title : string.Empty); AssemblyCompanyAttribute assemblyCompanyAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute; Company = ((assemblyCompanyAttribute != null) ? assemblyCompanyAttribute.Company : string.Empty); AssemblyConfigurationAttribute assemblyConfigurationAttribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyConfigurationAttribute)) as AssemblyConfigurationAttribute; Configuration = ((assemblyConfigurationAttribute != null) ? assemblyConfigurationAttribute.Configuration : string.Empty); } } } namespace JsonFx.Bson { public enum BsonElementType : byte { None = 0, Double = 1, String = 2, Document = 3, Array = 4, Binary = 5, [Obsolete] Undefined = 6, ObjectID = 7, Boolean = 8, DateTimeUtc = 9, Null = 10, RegExp = 11, [Obsolete] DBPointer = 12, JavaScriptCode = 13, Symbol = 14, CodeWithScope = 15, Int32 = 16, TimeStamp = 17, Int64 = 18, MinKey = byte.MaxValue, MaxKey = 127 } public enum BsonBinarySubtype : byte { Generic = 0, Function = 1, [Obsolete] BinaryOld = 2, UUID = 3, MD5 = 5, UserDefined = 128 } public class BsonWriter { public class BsonFormatter : IBinaryFormatter<ModelTokenType> { public byte[] Format(IEnumerable<Token<ModelTokenType>> tokens) { if (tokens == null) { throw new ArgumentNullException("tokens"); } using MemoryStream memoryStream = new MemoryStream(); Format(tokens, memoryStream); return memoryStream.ToArray(); } public void Format(IEnumerable<Token<ModelTokenType>> tokens, Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } if (tokens == null) { throw new ArgumentNullException("tokens"); } using BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8); IStream<Token<ModelTokenType>> stream2 = Stream<Token<ModelTokenType>>.Create(tokens); if (!stream2.IsCompleted) { WriteDocument(writer, stream2); } } private int WriteDocument(BinaryWriter writer, IStream<Token<ModelTokenType>> tokens) { Token<ModelTokenType> token = tokens.Peek(); if (tokens.IsCompleted || token == null) { throw new TokenException<ModelTokenType>(token, "Unterminated document"); } bool flag; if (token.TokenType == ModelTokenType.ArrayBegin) { flag = true; } else { if (token.TokenType != ModelTokenType.ObjectBegin) { throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"); } flag = false; } tokens.Pop(); long position = writer.BaseStream.Position; int num = 5; writer.Seek(4, SeekOrigin.Current); token = tokens.Peek(); int num2 = 0; while (!tokens.IsCompleted && token != null) { if (flag) { if (token.TokenType == ModelTokenType.ArrayEnd) { tokens.Pop(); break; } } else if (token.TokenType == ModelTokenType.ObjectEnd) { tokens.Pop(); break; } string ename; if (flag) { ename = num2.ToString(CultureInfo.InvariantCulture); } else { if (token.TokenType != ModelTokenType.Property) { throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"); } ename = token.Name.LocalName; tokens.Pop(); } num += WriteElement(writer, tokens, ename); token = tokens.Peek(); num2++; } writer.Write((byte)0); long position2 = writer.BaseStream.Position; writer.Seek((int)(position - position2), SeekOrigin.Current); writer.Write(num); writer.Seek((int)(position2 - position - 4), SeekOrigin.Current); return num; } private int WriteElement(BinaryWriter writer, IStream<Token<ModelTokenType>> tokens, string ename) { Token<ModelTokenType> token = tokens.Peek(); if (tokens.IsCompleted || token == null) { throw new TokenException<ModelTokenType>(token, "Unterminated document"); } BsonElementType bsonElementType = token.TokenType switch { ModelTokenType.ArrayBegin => BsonElementType.Array, ModelTokenType.ObjectBegin => BsonElementType.Document, ModelTokenType.Primitive => GetElementType(token.Value), _ => throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"), }; writer.Write((byte)bsonElementType); int num = 1; num += WriteString(writer, ename, asCString: true); if (token.Value is IBsonFormattable bsonFormattable) { num += bsonFormattable.Format(this, writer); } else { switch (bsonElementType) { case BsonElementType.Double: tokens.Pop(); writer.Write((double)token.Value); num += 8; break; case BsonElementType.String: case BsonElementType.JavaScriptCode: case BsonElementType.Symbol: tokens.Pop(); num += WriteString(writer, token.ValueAsString(), asCString: false); break; case BsonElementType.Document: case BsonElementType.Array: num += WriteDocument(writer, tokens); break; case BsonElementType.Binary: tokens.Pop(); num += WriteBinary(writer, token); break; case BsonElementType.ObjectID: tokens.Pop(); writer.Write((byte[])token.Value); num += 12; break; case BsonElementType.Boolean: { tokens.Pop(); bool flag = true.Equals(token.Value); writer.Write((byte)(flag ? 1 : 0)); num++; break; } case BsonElementType.DateTimeUtc: { tokens.Pop(); DateTime dateTime = (DateTime)token.Value; if (dateTime.Kind == DateTimeKind.Local) { dateTime = dateTime.ToUniversalTime(); } long value2 = (long)dateTime.Subtract(UnixEpoch).TotalMilliseconds; writer.Write(value2); num += 8; break; } case BsonElementType.RegExp: tokens.Pop(); if (token.Value is Regex regex) { string value3 = regex.ToString(); num += WriteString(writer, value3, asCString: true); string text = (false ? "g" : ""); switch (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.Multiline)) { case RegexOptions.IgnoreCase: text += "i"; break; case RegexOptions.Multiline: text += "m"; break; case RegexOptions.IgnoreCase | RegexOptions.Multiline: text += "im"; break; } num += WriteString(writer, text, asCString: true); break; } goto default; case BsonElementType.DBPointer: tokens.Pop(); if (token.Value is BsonDBPointer bsonDBPointer) { num += WriteString(writer, bsonDBPointer.Namespace, asCString: false); writer.Write((byte[])bsonDBPointer.ObjectID); num += 12; break; } goto default; case BsonElementType.CodeWithScope: tokens.Pop(); if (token.Value is BsonCodeWithScope value) { num += WriteCodeWithScope(writer, value); break; } goto default; case BsonElementType.Int32: tokens.Pop(); writer.Write((int)token.Value); num += 4; break; case BsonElementType.TimeStamp: case BsonElementType.Int64: tokens.Pop(); writer.Write((long)token.Value); num += 8; break; case BsonElementType.Undefined: case BsonElementType.Null: case BsonElementType.MaxKey: case BsonElementType.MinKey: tokens.Pop(); break; default: throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"); } } return num; } private static int WriteString(BinaryWriter writer, string value, bool asCString) { int num = 1; byte[] bytes = Encoding.UTF8.GetBytes(value); if (!asCString) { writer.Write(bytes.Length + 1); num += 4; } writer.Write(bytes); num += bytes.Length; writer.Write((byte)0); return num; } private static int WriteBinary(BinaryWriter writer, Token<ModelTokenType> token) { BsonBinary bsonBinary = GetBsonBinary(token.Value); writer.Write(bsonBinary.Count); writer.Write((byte)bsonBinary.Type); writer.Write(bsonBinary.Data); return 9 + bsonBinary.Count; } private int WriteCodeWithScope(BinaryWriter writer, BsonCodeWithScope value) { long position = writer.BaseStream.Position; int num = 4; writer.Seek(4, SeekOrigin.Current); num += WriteString(writer, (string)value.Code, asCString: false); num += WriteDocument(writer, value.Scope); long position2 = writer.BaseStream.Position; writer.Seek((int)(position - position2), SeekOrigin.Current); writer.Write(num); writer.Seek((int)(position2 - position - 4), SeekOrigin.Current); return num; } private static BsonElementType GetElementType(object value) { Type type = value?.GetType(); switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: return BsonElementType.Boolean; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: return BsonElementType.Int32; case TypeCode.Char: case TypeCode.String: return BsonElementType.String; case TypeCode.DateTime: return BsonElementType.DateTimeUtc; case TypeCode.Empty: case TypeCode.DBNull: return BsonElementType.Null; case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return BsonElementType.Double; case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: return BsonElementType.Int32; default: if (value is IBsonFormattable) { return ((IBsonFormattable)value).GetElementType(); } if (value is TimeSpan) { return BsonElementType.TimeStamp; } if (value is Regex) { return BsonElementType.RegExp; } if (value is Guid || value is byte[] || value is BsonBinary || value is BsonMD5) { return BsonElementType.Binary; } if (value is BsonObjectID) { return BsonElementType.ObjectID; } if (value is BsonSymbol) { return BsonElementType.Symbol; } if (value is BsonJavaScriptCode) { return BsonElementType.JavaScriptCode; } if (value is BsonCodeWithScope) { return BsonElementType.CodeWithScope; } if (value is BsonDBPointer) { return BsonElementType.DBPointer; } throw new NotSupportedException("Unknown BSON element data type"); } } private static BsonBinary GetBsonBinary(object value) { if (value is BsonBinary result) { return result; } if (value is BsonMD5) { return new BsonBinary(BsonBinarySubtype.MD5, ((Guid)value).ToByteArray()); } if (value is Guid) { return new BsonBinary(BsonBinarySubtype.UUID, ((Guid)value).ToByteArray()); } if (value is byte[]) { return new BsonBinary(BsonBinarySubtype.Generic, (byte[])value); } throw new NotSupportedException("Unknown BSON binary data type"); } } internal const string ErrorUnterminated = "Unterminated document"; private const string ErrorUnexpectedToken = "Unexpected token ({0})"; private const string ErrorExpectedObjectValueDelim = "Expected value delimiter or end of document ({0})"; internal const int SizeOfByte = 1; internal const int SizeOfInt32 = 4; internal const int SizeOfInt64 = 8; internal const int SizeOfDouble = 8; internal const int SizeOfObjectID = 12; internal const byte NullByte = 0; internal const byte FalseByte = 0; internal const byte TrueByte = 1; internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); } } namespace JsonFx.Serialization { public interface IBinaryFormatter<T> { void Format(IEnumerable<Token<T>> tokens, Stream stream); byte[] Format(IEnumerable<Token<T>> tokens); } } namespace JsonFx.Bson { public class BsonReader { public class BsonTokenizer : IBinaryTokenizer<ModelTokenType>, IDisposable { private const string ErrorUnexpectedElementType = "Unexpected element type ({0})"; private static readonly BinaryReader NullBinaryReader = new BinaryReader(Stream.Null, Encoding.UTF8); private BinaryReader Reader = NullBinaryReader; public long Index => Reader.BaseStream.Position; private static void ReadDocument(List<Token<ModelTokenType>> tokens, BinaryReader reader, bool isArray) { if (reader.PeekChar() >= 0) { long position = reader.BaseStream.Position; int num = reader.ReadInt32(); tokens.Add(isArray ? ModelGrammar.TokenArrayBeginUnnamed : ModelGrammar.TokenObjectBeginUnnamed); while (reader.BaseStream.Position - position < num - 1) { ReadElement(tokens, reader, isArray); } if (reader.ReadByte() != 0) { throw new DeserializationException("Unterminated document", position); } tokens.Add(isArray ? ModelGrammar.TokenArrayEnd : ModelGrammar.TokenObjectEnd); } } private static void ReadElement(List<Token<ModelTokenType>> tokens, BinaryReader reader, bool isArrayItem) { BsonElementType bsonElementType = (BsonElementType)reader.ReadByte(); string localName = ReadCString(reader); if (!isArrayItem) { tokens.Add(ModelGrammar.TokenProperty(localName)); } switch (bsonElementType) { case BsonElementType.Double: { double num5 = reader.ReadDouble(); tokens.Add(ModelGrammar.TokenPrimitive(num5)); break; } case BsonElementType.String: { string value4 = ReadString(reader); tokens.Add(ModelGrammar.TokenPrimitive(value4)); break; } case BsonElementType.JavaScriptCode: { BsonJavaScriptCode bsonJavaScriptCode = (BsonJavaScriptCode)ReadString(reader); tokens.Add(ModelGrammar.TokenPrimitive(bsonJavaScriptCode)); break; } case BsonElementType.Symbol: { BsonSymbol bsonSymbol = (BsonSymbol)ReadString(reader); tokens.Add(ModelGrammar.TokenPrimitive(bsonSymbol)); break; } case BsonElementType.Document: ReadDocument(tokens, reader, isArray: false); break; case BsonElementType.Array: ReadDocument(tokens, reader, isArray: true); break; case BsonElementType.Binary: ReadBinary(tokens, reader); break; case BsonElementType.ObjectID: { byte[] bytes2 = reader.ReadBytes(12); tokens.Add(ModelGrammar.TokenPrimitive(new BsonObjectID(bytes2))); break; } case BsonElementType.Boolean: { bool flag = reader.ReadByte() != 0; tokens.Add(flag ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse); break; } case BsonElementType.DateTimeUtc: { DateTime unixEpoch = BsonWriter.UnixEpoch; DateTime dateTime = unixEpoch.AddMilliseconds(reader.ReadInt64()); tokens.Add(ModelGrammar.TokenPrimitive(dateTime)); break; } case BsonElementType.RegExp: { string pattern = ReadCString(reader); string text = ReadCString(reader); RegexOptions regexOptions = RegexOptions.ECMAScript; for (int num4 = text.Length - 1; num4 >= 0; num4--) { switch (text[num4]) { case 'i': regexOptions |= RegexOptions.IgnoreCase; break; case 'm': regexOptions |= RegexOptions.Multiline; break; } } Regex value3 = new Regex(pattern, regexOptions); tokens.Add(ModelGrammar.TokenPrimitive(value3)); break; } case BsonElementType.DBPointer: { string @namespace = ReadString(reader); byte[] bytes = reader.ReadBytes(12); BsonDBPointer bsonDBPointer = new BsonDBPointer(); bsonDBPointer.Namespace = @namespace; bsonDBPointer.ObjectID = new BsonObjectID(bytes); BsonDBPointer value2 = bsonDBPointer; tokens.Add(ModelGrammar.TokenPrimitive(value2)); break; } case BsonElementType.CodeWithScope: { reader.ReadInt32(); string value = ReadString(reader); tokens.Add(ModelGrammar.TokenPrimitive(value)); ReadDocument(tokens, reader, isArray: false); break; } case BsonElementType.Int32: { int num3 = reader.ReadInt32(); tokens.Add(ModelGrammar.TokenPrimitive(num3)); break; } case BsonElementType.TimeStamp: { long num2 = reader.ReadInt64(); tokens.Add(ModelGrammar.TokenPrimitive(num2)); break; } case BsonElementType.Int64: { long num = reader.ReadInt64(); tokens.Add(ModelGrammar.TokenPrimitive(num)); break; } default: throw new DeserializationException($"Unexpected element type ({bsonElementType})", reader.BaseStream.Position); case BsonElementType.Undefined: case BsonElementType.Null: case BsonElementType.MaxKey: case BsonElementType.MinKey: break; } } private static void ReadBinary(List<Token<ModelTokenType>> tokens, BinaryReader reader) { int num = reader.ReadInt32(); BsonBinarySubtype bsonBinarySubtype = (BsonBinarySubtype)reader.ReadByte(); byte[] array = reader.ReadBytes(num); object value; switch (bsonBinarySubtype) { case BsonBinarySubtype.MD5: if (num == 16) { value = new BsonMD5(array); break; } goto default; case BsonBinarySubtype.UUID: if (num == 16) { value = new Guid(array); break; } goto default; case BsonBinarySubtype.BinaryOld: { num = BitConverter.ToInt32(array, 0); byte[] array2 = new byte[num]; Buffer.BlockCopy(array, 4, array2, 0, num); value = new BsonBinary(BsonBinarySubtype.Generic, array2); break; } default: value = new BsonBinary(bsonBinarySubtype, array); break; } tokens.Add(ModelGrammar.TokenPrimitive(value)); } private static string ReadString(BinaryReader reader) { int num = reader.ReadInt32(); char[] value = reader.ReadChars(num); return new string(value, 0, num - 1); } private static string ReadCString(BinaryReader reader) { StringBuilder stringBuilder = new StringBuilder(); char value; while ((value = reader.ReadChar()) != 0) { stringBuilder.Append(value); } return stringBuilder.ToString(); } public IEnumerable<Token<ModelTokenType>> GetTokens(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } return GetTokens(new BinaryReader(stream, Encoding.UTF8)); } public IEnumerable<Token<ModelTokenType>> GetTokens(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } return GetTokens(new MemoryStream(bytes, writable: false)); } protected IEnumerable<Token<ModelTokenType>> GetTokens(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } Reader = reader; using (reader) { List<Token<ModelTokenType>> list = new List<Token<ModelTokenType>>(); ReadDocument(list, reader, isArray: false); Reader = NullBinaryReader; return list; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { ((IDisposable)Reader).Dispose(); } } } } } namespace JsonFx.Serialization { public interface IBinaryTokenizer<T> : IDisposable { long Index { get; } IEnumerable<Token<T>> GetTokens(Stream stream); IEnumerable<Token<T>> GetTokens(byte[] bytes); } } namespace JsonFx.Bson { public struct BsonMD5 { public readonly Guid Hash; public BsonMD5(string hash) { Hash = new Guid(hash); } public BsonMD5(byte[] hash) { Hash = new Guid(hash); } public BsonMD5(Guid hash) { Hash = hash; } public static explicit operator Guid(BsonMD5 value) { return value.Hash; } public static explicit operator BsonMD5(Guid value) { return new BsonMD5(value); } public override string ToString() { return Hash.ToString(); } public override int GetHashCode() { return EqualityComparer<Guid>.Default.GetHashCode(Hash); } } public class BsonCodeWithScope { public BsonJavaScriptCode Code { get; set; } public IStream<Token<ModelTokenType>> Scope { get; set; } } public struct BsonJavaScriptCode { public readonly string Code; public BsonJavaScriptCode(string code) { Code = code; } public static explicit operator string(BsonJavaScriptCode value) { return value.Code; } public static explicit operator BsonJavaScriptCode(string value) { return new BsonJavaScriptCode(value); } public override string ToString() { return Code; } public override int GetHashCode() { return EqualityComparer<string>.Default.GetHashCode(Code); } } public struct BsonSymbol { public readonly string Code; public BsonSymbol(string code) { Code = code; } public static explicit operator string(BsonSymbol value) { return value.Code; } public static explicit operator BsonSymbol(string value) { return new BsonSymbol(value); } public override string ToString() { return Code; } public override int GetHashCode() { return EqualityComparer<string>.Default.GetHashCode(Code); } } [Obsolete] public class BsonDBPointer { public string Namespace { get; set; } public BsonObjectID ObjectID { get; set; } } public struct BsonObjectID { public static readonly BsonObjectID Empty = new BsonObjectID(new byte[0]); private readonly byte[] Bytes; public DateTime Time { get { int num = (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | Bytes[3]; DateTime unixEpoch = BsonWriter.UnixEpoch; return unixEpoch.AddSeconds(num); } } public int Machine => Bytes[4] | (Bytes[5] << 8) | (Bytes[6] << 16); public int Pid => Bytes[7] | (Bytes[8] << 8); public int Inc => (Bytes[9] << 16) | (Bytes[10] << 8) | Bytes[11]; public BsonObjectID(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } if (bytes.Length != 12) { throw new ArgumentException("ObjectID is exact 12 bytes", "bytes"); } Bytes = bytes; } public BsonObjectID(DateTime time, int machine, int pid, int inc) { Bytes = new byte[12]; int num = (int)time.Subtract(BsonWriter.UnixEpoch).TotalSeconds; if (num < 0 || num > 65535) { throw new ArgumentOutOfRangeException("ObjectID only supports a limited range of dates (" + ushort.MaxValue + " seconds since Unix epoch)."); } Bytes[0] = (byte)((num >> 24) % 255); Bytes[1] = (byte)((num >> 16) % 255); Bytes[2] = (byte)((num >> 8) % 255); Bytes[3] = (byte)(num % 255); } public static explicit operator string(BsonObjectID value) { return value.ToString(); } public static explicit operator BsonObjectID(string value) { return Parse(value); } public static explicit operator byte[](BsonObjectID value) { return value.Bytes ?? Empty.Bytes; } public static explicit operator BsonObjectID(byte[] value) { return new BsonObjectID(value); } public override string ToString() { byte[] bytes = Bytes; if (bytes == null) { bytes = Empty.Bytes; } char[] array = new char[24]; int num = 0; int num2 = 0; while (num < 24) { array[num] = CharUtility.GetHexDigit(bytes[num2] / 16); array[num] = CharUtility.GetHexDigit(bytes[num2] % 16); num += 2; num2++; } return new string(array); } public byte[] ToByteArray() { byte[] array = new byte[12]; Buffer.BlockCopy(Bytes, 0, array, 0, 12); return array; } public static BsonObjectID Parse(string value) { if (TryParse(value, out var result)) { return result; } throw new InvalidCastException("String must be exactly 24 hex digits"); } public static bool TryParse(string value, out BsonObjectID result) { if (string.IsNullOrEmpty(value) || value.Length != 24) { result = Empty; return false; } byte[] array = new byte[12]; for (int i = 0; i < 24; i += 2) { if (!byte.TryParse(value.Substring(i, 2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out var result2)) { result = Empty; return false; } array[i] = result2; } result = new BsonObjectID(array); return true; } public override int GetHashCode() { return EqualityComparer<byte[]>.Default.GetHashCode(Bytes); } } public class BsonBinary : IEnumerable<byte>, IEnumerable { public static readonly BsonBinary Empty = new BsonBinary(BsonBinarySubtype.Generic, new byte[0]); private readonly BsonBinarySubtype Subtype; private readonly byte[] Bytes; internal byte[] Data => Bytes; public BsonBinarySubtype Type => Subtype; public byte this[int index] => Bytes[index]; public int Count => Bytes.Length; public BsonBinary(BsonBinarySubtype subtype, byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } Subtype = subtype; Bytes = bytes; } public static explicit operator string(BsonBinary value) { return value.ToString(); } public static explicit operator BsonBinary(string value) { return Parse(value); } public static explicit operator byte[](BsonBinary value) { return value.Bytes; } public static explicit operator BsonBinary(byte[] value) { return new BsonBinary(BsonBinarySubtype.Generic, value); } public override string ToString() { byte[] bytes = Bytes; char[] array = new char[24]; int num = 0; int num2 = 0; while (num < 24) { array[num] = GetHexDigit(bytes[num2] / 16); array[num] = GetHexDigit(bytes[num2] % 16); num += 2; num2++; } return new string(array); } public byte[] ToByteArray() { byte[] array = new byte[12]; Buffer.BlockCopy(Bytes, 0, array, 0, 12); return array; } public static BsonBinary Parse(string value) { if (TryParse(value, out var result)) { return result; } throw new InvalidCastException("String must be only hex digits"); } public static bool TryParse(string value, out BsonBinary result) { if (string.IsNullOrEmpty(value)) { result = Empty; return true; } byte[] array = new byte[value.Length / 2]; for (int i = 0; i < value.Length; i += 2) { if (!byte.TryParse(value.Substring(i, 2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out var result2)) { result = Empty; return false; } array[i] = result2; } result = new BsonBinary(BsonBinarySubtype.Generic, array); return true; } public override int GetHashCode() { return EqualityComparer<byte[]>.Default.GetHashCode(Bytes); } private static char GetHexDigit(int i) { if (i < 10) { return (char)(i + 48); } return (char)(i - 10 + 97); } public IEnumerator<byte> GetEnumerator() { return ((IEnumerable<byte>)Bytes).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Bytes.GetEnumerator(); } } } namespace JsonFx.Serialization { public interface IBinaryFormattable<T> { int Format(IBinaryFormatter<T> formatter, BinaryWriter writer); } } namespace JsonFx.Bson { public interface IBsonFormattable : IBinaryFormattable<ModelTokenType> { BsonElementType GetElementType(); } } namespace JsonFx.CodeGen { public delegate object FactoryDelegate(params object[] args); public delegate object ProxyDelegate(object target, params object[] args); public delegate object GetterDelegate(object target); public delegate void SetterDelegate(object target, object value); } namespace JsonFx.Serialization { public interface ITokenAnalyzer<T> { DataReaderSettings Settings { get; } IEnumerable Analyze(IEnumerable<Token<T>> tokens); IEnumerable Analyze(IEnumerable<Token<T>> tokens, Type targetType); IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<T>> tokens); IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<T>> tokens, TResult ignored); } } namespace JsonFx.Model { public class ModelAnalyzer : ITokenAnalyzer<ModelTokenType> { private const string ErrorUnexpectedToken = "Unexpected token ({0})"; private const string ErrorExpectedArray = "Expected array start ({0})"; private const string ErrorExpectedArrayItem = "Expected array item or end of array ({0})"; private const string ErrorExpectedArrayItemDelim = "Expected array item delimiter or end of array ({0})"; private const string ErrorMissingArrayItem = "Missing array item"; private const string ErrorUnterminatedArray = "Unterminated array"; private const string ErrorExpectedObject = "Expected object start ({0})"; private const string ErrorExpectedPropertyName = "Expected object property name or end of object ({0})"; private const string ErrorExpectedObjectValueDelim = "Expected value delimiter or end of object ({0})"; private const string ErrorMissingObjectProperty = "Missing object property"; private const string ErrorUnterminatedObject = "Unterminated object"; private readonly DataReaderSettings Settings; private readonly TypeCoercionUtility Coercion; private readonly IEnumerable<IDataFilter<ModelTokenType>> Filters; DataReaderSettings ITokenAnalyzer<ModelTokenType>.Settings => Settings; public ModelAnalyzer(DataReaderSettings settings) { if (settings == null) { throw new ArgumentNullException("settings"); } Settings = settings; List<IDataFilter<ModelTokenType>> list = new List<IDataFilter<ModelTokenType>>(); if (settings.Filters != null) { foreach (IDataFilter<ModelTokenType> filter in settings.Filters) { if (filter != null) { list.Add(filter); } } } Filters = list; Coercion = new TypeCoercionUtility(settings, settings.AllowNullValueTypes); } public IEnumerable Analyze(IEnumerable<Token<ModelTokenType>> tokens) { return Analyze(tokens, null); } public IEnumerable Analyze(IEnumerable<Token<ModelTokenType>> tokens, Type targetType) { if (tokens == null) { throw new ArgumentNullException("tokens"); } IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(tokens); while (!stream.IsCompleted) { yield return ConsumeValue(stream, targetType); } } public IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<ModelTokenType>> tokens) { if (tokens == null) { throw new ArgumentNullException("tokens"); } Type resultType = typeof(TResult); IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(tokens); while (!stream.IsCompleted) { yield return (TResult)ConsumeValue(stream, resultType); } } public IEnumerable<TResult> Analyze<TResult>(IEnumerable<Token<ModelTokenType>> tokens, TResult ignored) { return Analyze<TResult>(tokens); } private object ConsumeValue(IStream<Token<ModelTokenType>> tokens, Type targetType) { if (TryReadFilters(tokens, out var result)) { return result; } Token<ModelTokenType> token = tokens.Peek(); switch (token.TokenType) { case ModelTokenType.ArrayBegin: return ConsumeArray(tokens, targetType); case ModelTokenType.ObjectBegin: return ConsumeObject(tokens, targetType); case ModelTokenType.Primitive: tokens.Pop(); return Coercion.CoerceType(targetType, token.Value); default: tokens.Pop(); throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"); } } private object ConsumeObject(IStream<Token<ModelTokenType>> tokens, Type targetType) { Token<ModelTokenType> token = tokens.Pop(); if (token.TokenType != ModelTokenType.ObjectBegin) { throw new TokenException<ModelTokenType>(token, $"Expected object start ({token.TokenType})"); } IDictionary<string, MemberMap> dictionary = Settings.Resolver.LoadMaps(targetType); Type dictionaryItemType = TypeCoercionUtility.GetDictionaryItemType(targetType); object obj = Coercion.InstantiateObjectDefaultCtor(targetType); while (!tokens.IsCompleted) { token = tokens.Peek(); string localName; MemberMap value; Type targetType2; switch (token.TokenType) { case ModelTokenType.Property: tokens.Pop(); localName = token.Name.LocalName; if ((object)dictionaryItemType != null) { value = null; targetType2 = dictionaryItemType; } else if (dictionary != null && dictionary.TryGetValue(localName, out value)) { targetType2 = value?.Type; } else { value = null; targetType2 = null; } break; case ModelTokenType.ObjectEnd: tokens.Pop(); return Coercion.CoerceType(targetType, obj); default: tokens.Pop(); throw new TokenException<ModelTokenType>(token, $"Expected object property name or end of object ({token.TokenType})"); } object memberValue = ConsumeValue(tokens, targetType2); Coercion.SetMemberValue(obj, targetType, value, localName, memberValue); } throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unterminated object"); } private object ConsumeArray(IStream<Token<ModelTokenType>> tokens, Type arrayType) { Token<ModelTokenType> token = tokens.Pop(); if (token.TokenType != ModelTokenType.ArrayBegin) { throw new TokenException<ModelTokenType>(token, $"Expected array start ({token.TokenType})"); } Type type = TypeCoercionUtility.GetElementType(arrayType); bool flag = (object)type == null; IList list = new List<object>(); while (!tokens.IsCompleted) { token = tokens.Peek(); object result; switch (token.TokenType) { case ModelTokenType.ArrayBegin: result = ConsumeArray(tokens, flag ? null : type); break; case ModelTokenType.ArrayEnd: tokens.Pop(); return Coercion.CoerceCollection(arrayType, type, list); case ModelTokenType.ObjectBegin: result = ConsumeObject(tokens, flag ? null : type); break; case ModelTokenType.Primitive: if (!TryReadFilters(tokens, out result)) { token = tokens.Pop(); result = ((token != null) ? token.Value : null); } if (!flag) { result = Coercion.CoerceType(type, result); } break; default: tokens.Pop(); throw new TokenException<ModelTokenType>(token, $"Expected array item or end of array ({token.TokenType})"); } type = TypeCoercionUtility.FindCommonType(type, result); list.Add(result); } throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unterminated array"); } private bool TryReadFilters(IStream<Token<ModelTokenType>> tokens, out object result) { if (!tokens.IsCompleted) { foreach (IDataFilter<ModelTokenType> filter in Filters) { if (filter.TryRead(Settings, tokens, out result)) { return true; } } } result = null; return false; } } public static class ModelGrammar { public static readonly Token<ModelTokenType> TokenNone = new Token<ModelTokenType>(ModelTokenType.None); public static readonly Token<ModelTokenType> TokenArrayEnd = new Token<ModelTokenType>(ModelTokenType.ArrayEnd); public static readonly Token<ModelTokenType> TokenObjectEnd = new Token<ModelTokenType>(ModelTokenType.ObjectEnd); public static readonly Token<ModelTokenType> TokenNull = new Token<ModelTokenType>(ModelTokenType.Primitive); public static readonly Token<ModelTokenType> TokenFalse = new Token<ModelTokenType>(ModelTokenType.Primitive, false); public static readonly Token<ModelTokenType> TokenTrue = new Token<ModelTokenType>(ModelTokenType.Primitive, true); public static readonly Token<ModelTokenType> TokenArrayBeginUnnamed = new Token<ModelTokenType>(ModelTokenType.ArrayBegin); public static readonly Token<ModelTokenType> TokenObjectBeginUnnamed = new Token<ModelTokenType>(ModelTokenType.ObjectBegin); internal static readonly Token<ModelTokenType> TokenNaN = new Token<ModelTokenType>(ModelTokenType.Primitive, double.NaN); internal static readonly Token<ModelTokenType> TokenPositiveInfinity = new Token<ModelTokenType>(ModelTokenType.Primitive, double.PositiveInfinity); internal static readonly Token<ModelTokenType> TokenNegativeInfinity = new Token<ModelTokenType>(ModelTokenType.Primitive, double.NegativeInfinity); public static Token<ModelTokenType> TokenArrayBegin(string name) { return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, new DataName(name)); } public static Token<ModelTokenType> TokenArrayBegin(string name, string prefix, string namespaceUri) { return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, new DataName(name, prefix, namespaceUri)); } public static Token<ModelTokenType> TokenArrayBegin(DataName name) { return new Token<ModelTokenType>(ModelTokenType.ArrayBegin, name); } public static Token<ModelTokenType> TokenObjectBegin(string name) { return new Token<ModelTokenType>(ModelTokenType.ObjectBegin, new DataName(name)); } public static Token<ModelTokenType> TokenObjectBegin(DataName name) { return new Token<ModelTokenType>(ModelTokenType.ObjectBegin, name); } internal static Token<ModelTokenType> TokenProperty(object localName) { string localName2 = Token<ModelTokenType>.ToString(localName); return new Token<ModelTokenType>(ModelTokenType.Property, new DataName(localName2)); } public static Token<ModelTokenType> TokenProperty(string localName) { return new Token<ModelTokenType>(ModelTokenType.Property, new DataName(localName)); } public static Token<ModelTokenType> TokenProperty(DataName name) { return new Token<ModelTokenType>(ModelTokenType.Property, name); } public static Token<ModelTokenType> TokenPrimitive(object value) { return new Token<ModelTokenType>(ModelTokenType.Primitive, value); } } } namespace JsonFx.Serialization { public interface IDataReader { IEnumerable<string> ContentType { get; } DataReaderSettings Settings { get; } TResult Read<TResult>(TextReader input, TResult ignored); TResult Read<TResult>(TextReader input); object Read(TextReader input); object Read(TextReader input, Type targetType); TResult Read<TResult>(string input, TResult ignored); TResult Read<TResult>(string input); object Read(string input); object Read(string input, Type targetType); IEnumerable ReadMany(TextReader input); } public abstract class DataReader<T> : IDataReader { private readonly DataReaderSettings settings; public abstract IEnumerable<string> ContentType { get; } public DataReaderSettings Settings => settings; protected DataReader(DataReaderSettings settings) { if (settings == null) { throw new NullReferenceException("settings"); } this.settings = settings; } public virtual TResult Read<TResult>(TextReader input, TResult ignored) { return Read<TResult>(input); } public virtual TResult Read<TResult>(TextReader input) { object obj = Read(input, typeof(TResult)); if (!(obj is TResult)) { return default(TResult); } return (TResult)obj; } public virtual object Read(TextReader input) { return Read(input, null); } public virtual object Read(TextReader input, Type targetType) { ITextTokenizer<T> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } return ReadSingle(tokenizer, tokenizer.GetTokens(input), targetType); } public virtual TResult Read<TResult>(string input, TResult ignored) { return Read<TResult>(input); } public virtual TResult Read<TResult>(string input) { object obj = Read(input, typeof(TResult)); if (!(obj is TResult)) { return default(TResult); } return (TResult)obj; } public virtual object Read(string input) { return Read(input, null); } public virtual object Read(string input, Type targetType) { ITextTokenizer<T> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new ArgumentNullException("tokenizer"); } return ReadSingle(tokenizer, tokenizer.GetTokens(input), targetType); } public IEnumerable ReadMany(TextReader input) { ITextTokenizer<T> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new ArgumentNullException("tokenizer"); } ITokenAnalyzer<T> analyzer = GetAnalyzer(); if (analyzer == null) { throw new ArgumentNullException("analyzer"); } try { return analyzer.Analyze(tokenizer.GetTokens(input)); } catch (DeserializationException) { throw; } catch (Exception ex2) { throw new DeserializationException(ex2.Message, tokenizer.Index, tokenizer.Line, tokenizer.Column, ex2); } } private object ReadSingle(ITextTokenizer<T> tokenizer, IEnumerable<Token<T>> tokens, Type targetType) { ITokenAnalyzer<T> analyzer = GetAnalyzer(); if (analyzer == null) { throw new ArgumentNullException("analyzer"); } try { IEnumerator enumerator = analyzer.Analyze(tokens, targetType).GetEnumerator(); if (!enumerator.MoveNext()) { return null; } object current = enumerator.Current; if (!Settings.AllowTrailingContent && enumerator.MoveNext()) { throw new DeserializationException("Invalid trailing content", tokenizer.Index, tokenizer.Line, tokenizer.Column); } return current; } catch (DeserializationException) { throw; } catch (Exception ex2) { throw new DeserializationException(ex2.Message, tokenizer.Index, tokenizer.Line, tokenizer.Column, ex2); } } protected abstract ITextTokenizer<T> GetTokenizer(); protected abstract ITokenAnalyzer<T> GetAnalyzer(); } } namespace JsonFx.Linq { public interface IQueryableReader : IDataReader { IQueryable<TResult> Query<TResult>(TextReader input, TResult ignored); IQueryable<TResult> Query<TResult>(TextReader input); IQueryable Query(TextReader input); IQueryable Query(TextReader input, Type targetType); IQueryable<TResult> Query<TResult>(string input, TResult ignored); IQueryable<TResult> Query<TResult>(string input); IQueryable Query(string input); IQueryable Query(string input, Type targetType); } } namespace JsonFx.Model { public abstract class ModelReader : DataReader<ModelTokenType>, IQueryableReader, IDataReader { protected ModelReader(DataReaderSettings settings) : base(settings) { } protected override ITokenAnalyzer<ModelTokenType> GetAnalyzer() { return new ModelAnalyzer(base.Settings); } IQueryable<T> IQueryableReader.Query<T>(TextReader input, T ignored) { return Query<T>(input); } IQueryable<T> IQueryableReader.Query<T>(TextReader input) { return Query<T>(input); } IQueryable<T> IQueryableReader.Query<T>(string input, T ignored) { return Query<T>(input); } IQueryable<T> IQueryableReader.Query<T>(string input) { return Query<T>(input); } public Query<T> Query<T>(TextReader input, T ignored) { return Query<T>(input); } public Query<T> Query<T>(TextReader input) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); return new Query<T>(GetAnalyzer(), tokens); } public IQueryable Query(TextReader input) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); return new Query<object>(GetAnalyzer(), tokens); } public IQueryable Query(TextReader input, Type targetType) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); try { return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(targetType), GetAnalyzer(), tokens); } catch (TargetInvocationException ex) { throw ex.InnerException; } } public Query<T> Query<T>(string input, T ignored) { return Query<T>(input); } public Query<T> Query<T>(string input) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); return new Query<T>(GetAnalyzer(), tokens); } public IQueryable Query(string input) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); return new Query<object>(GetAnalyzer(), tokens); } public IQueryable Query(string input, Type targetType) { ITextTokenizer<ModelTokenType> tokenizer = GetTokenizer(); if (tokenizer == null) { throw new InvalidOperationException("Tokenizer is invalid"); } IEnumerable<Token<ModelTokenType>> tokens = tokenizer.GetTokens(input); try { return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(targetType), GetAnalyzer(), tokens); } catch (TargetInvocationException ex) { throw ex.InnerException; } } } public static class ModelSubsequencer { private const string ErrorUnexpectedEndOfInput = "Unexpected end of token stream"; private const string ErrorInvalidPropertyValue = "Invalid property value token ({0})"; private static readonly IEnumerable<Token<ModelTokenType>> EmptySequence = new Token<ModelTokenType>[0]; public static bool IsPrimitive(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { throw new ArgumentNullException("source"); } if (source is IList<Token<ModelTokenType>> list) { if (list.Count > 0) { return list[0].TokenType == ModelTokenType.Primitive; } return false; } using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { Token<ModelTokenType> current = enumerator.Current; return current.TokenType == ModelTokenType.Primitive; } } return false; } public static bool IsObject(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { throw new ArgumentNullException("source"); } if (source is IList<Token<ModelTokenType>> list) { if (list.Count > 0) { return list[0].TokenType == ModelTokenType.ObjectBegin; } return false; } using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { Token<ModelTokenType> current = enumerator.Current; return current.TokenType == ModelTokenType.ObjectBegin; } } return false; } public static bool HasProperty(this IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate) { if (source == null) { throw new ArgumentNullException("source"); } IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source); if (stream.IsCompleted || stream.Pop().TokenType != ModelTokenType.ObjectBegin) { return false; } int num = 0; while (!stream.IsCompleted) { Token<ModelTokenType> token = stream.Peek(); switch (token.TokenType) { case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: num++; stream.Pop(); break; case ModelTokenType.ArrayEnd: num--; stream.Pop(); break; case ModelTokenType.ObjectEnd: if (num != 0) { num--; stream.Pop(); break; } return false; case ModelTokenType.Property: stream.Pop(); if (num == 0 && (predicate == null || predicate(token.Name))) { return true; } break; default: stream.Pop(); break; } } return false; } public static IEnumerable<Token<ModelTokenType>> Property(this IEnumerable<Token<ModelTokenType>> source, DataName propertyName) { Func<DataName, bool> predicate = (DataName name) => name == propertyName; using IEnumerator<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> enumerator = source.Properties(predicate).GetEnumerator(); return enumerator.MoveNext() ? enumerator.Current.Value : null; } public static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> Properties(this IEnumerable<Token<ModelTokenType>> source) { return source.Properties(null); } public static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> Properties(this IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate) { if (source == null) { throw new ArgumentNullException("source"); } if (!(source is IList<Token<ModelTokenType>>)) { source = new SequenceBuffer<Token<ModelTokenType>>(source); } return PropertiesIterator(source, predicate); } private static IEnumerable<KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>> PropertiesIterator(IEnumerable<Token<ModelTokenType>> source, Func<DataName, bool> predicate) { IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source); if (stream.IsCompleted || stream.Pop().TokenType != ModelTokenType.ObjectBegin) { yield break; } int depth = 0; while (!stream.IsCompleted) { Token<ModelTokenType> token = stream.Peek(); switch (token.TokenType) { case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: depth++; stream.Pop(); break; case ModelTokenType.ArrayEnd: depth--; stream.Pop(); break; case ModelTokenType.ObjectEnd: if (depth != 0) { depth--; stream.Pop(); break; } yield break; case ModelTokenType.Property: stream.Pop(); if (depth == 0 && (predicate == null || predicate(token.Name))) { yield return new KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>>(token.Name, SpliceNextValue(stream)); } break; default: stream.Pop(); break; } } } public static bool IsArray(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { throw new ArgumentNullException("source"); } if (source is IList<Token<ModelTokenType>> list) { if (list.Count > 0) { return list[0].TokenType == ModelTokenType.ArrayBegin; } return false; } using (IEnumerator<Token<ModelTokenType>> enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { Token<ModelTokenType> current = enumerator.Current; return current.TokenType == ModelTokenType.ArrayBegin; } } return false; } public static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItems(this IEnumerable<Token<ModelTokenType>> source) { return source.ArrayItems(null); } public static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItems(this IEnumerable<Token<ModelTokenType>> source, Func<int, bool> predicate) { if (source == null) { throw new ArgumentNullException("source"); } if (!(source is IList<Token<ModelTokenType>>)) { source = new SequenceBuffer<Token<ModelTokenType>>(source); } return ArrayItemsIterator(source, predicate); } private static IEnumerable<IEnumerable<Token<ModelTokenType>>> ArrayItemsIterator(IEnumerable<Token<ModelTokenType>> source, Func<int, bool> predicate) { IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source); if (stream.IsCompleted) { yield break; } if (stream.Pop().TokenType != ModelTokenType.ArrayBegin) { yield return source; yield break; } int index = 0; while (!stream.IsCompleted) { Token<ModelTokenType> token = stream.Peek(); if (token.TokenType != ModelTokenType.ArrayEnd) { if (predicate == null || predicate(index)) { yield return SpliceNextValue(stream); } else { SkipNextValue(stream); } index++; continue; } break; } } public static IEnumerable<IEnumerable<Token<ModelTokenType>>> Descendants(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { throw new ArgumentNullException("source"); } if (!(source is IList<Token<ModelTokenType>>)) { source = new SequenceBuffer<Token<ModelTokenType>>(source); } return DescendantsIterator(source); } private static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsIterator(IEnumerable<Token<ModelTokenType>> source) { if (source.IsPrimitive()) { yield break; } if (source.IsObject()) { foreach (KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> property in source.Properties(null)) { KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> keyValuePair = property; yield return keyValuePair.Value; KeyValuePair<DataName, IEnumerable<Token<ModelTokenType>>> keyValuePair2 = property; foreach (IEnumerable<Token<ModelTokenType>> item2 in keyValuePair2.Value.Descendants()) { yield return item2; } } yield break; } if (!source.IsArray()) { yield break; } foreach (IEnumerable<Token<ModelTokenType>> item in source.ArrayItems(null)) { yield return item; foreach (IEnumerable<Token<ModelTokenType>> item3 in item.Descendants()) { yield return item3; } } } public static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsAndSelf(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { throw new ArgumentNullException("source"); } if (!(source is IList<Token<ModelTokenType>>)) { source = new SequenceBuffer<Token<ModelTokenType>>(source); } return DescendantsAndSelfIterator(source); } private static IEnumerable<IEnumerable<Token<ModelTokenType>>> DescendantsAndSelfIterator(IEnumerable<Token<ModelTokenType>> source) { yield return source; foreach (IEnumerable<Token<ModelTokenType>> item in DescendantsIterator(source)) { yield return item; } } internal static IEnumerable<IEnumerable<Token<ModelTokenType>>> SplitValues(this IEnumerable<Token<ModelTokenType>> source) { if (source == null) { return new IEnumerable<Token<ModelTokenType>>[0]; } if (!(source is IList<Token<ModelTokenType>>)) { source = new SequenceBuffer<Token<ModelTokenType>>(source); } return SplitValuesIterator(source); } private static IEnumerable<IEnumerable<Token<ModelTokenType>>> SplitValuesIterator(IEnumerable<Token<ModelTokenType>> source) { using IStream<Token<ModelTokenType>> stream = Stream<Token<ModelTokenType>>.Create(source); while (!stream.IsCompleted) { yield return SpliceNextValue(stream); } } [Obsolete("TODO: Lazy does not mix well with shared IStream<T>.", true)] private static IEnumerable<Token<ModelTokenType>> SpliceNextValueLazy(IStream<Token<ModelTokenType>> stream) { if (stream.IsCompleted) { yield break; } int depth2 = 0; Token<ModelTokenType> token2 = stream.Pop(); switch (token2.TokenType) { case ModelTokenType.Primitive: yield return token2; break; case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: depth2++; yield return token2; while (!stream.IsCompleted && depth2 > 0) { token2 = stream.Pop(); switch (token2.TokenType) { case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: depth2++; yield return token2; break; case ModelTokenType.ObjectEnd: case ModelTokenType.ArrayEnd: depth2--; yield return token2; break; default: yield return token2; break; } } if (depth2 > 0) { throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream"); } break; default: throw new TokenException<ModelTokenType>(token2, $"Invalid property value token ({token2.TokenType})"); } } private static IEnumerable<Token<ModelTokenType>> SpliceNextValue(IStream<Token<ModelTokenType>> stream) { if (stream.IsCompleted) { throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream"); } stream.BeginChunk(); int num = 0; Token<ModelTokenType> token = stream.Pop(); switch (token.TokenType) { case ModelTokenType.Primitive: return stream.EndChunk(); case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: num++; while (!stream.IsCompleted && num > 0) { switch (stream.Pop().TokenType) { case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: num++; break; case ModelTokenType.ObjectEnd: case ModelTokenType.ArrayEnd: num--; break; } } if (num > 0) { throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream"); } return stream.EndChunk(); default: throw new TokenException<ModelTokenType>(token, $"Invalid property value token ({token.TokenType})"); } } private static void SkipNextValue(IStream<Token<ModelTokenType>> stream) { if (stream.IsCompleted) { return; } int num = 0; Token<ModelTokenType> token = stream.Pop(); switch (token.TokenType) { case ModelTokenType.Primitive: break; case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: num++; while (!stream.IsCompleted && num > 0) { switch (stream.Pop().TokenType) { case ModelTokenType.ObjectBegin: case ModelTokenType.ArrayBegin: num++; break; case ModelTokenType.ObjectEnd: case ModelTokenType.ArrayEnd: num--; break; } } if (num > 0) { throw new TokenException<ModelTokenType>(ModelGrammar.TokenNone, "Unexpected end of token stream"); } break; default: throw new TokenException<ModelTokenType>(token, $"Invalid property value token ({token.TokenType})"); } } } public enum ModelTokenType { None, ObjectBegin, ObjectEnd, ArrayBegin, ArrayEnd, Property, Primitive } } namespace JsonFx.Serialization { public interface IObjectWalker<T> { IEnumerable<Token<T>> GetTokens(object value); } } namespace JsonFx.Model { public class ModelWalker : IObjectWalker<ModelTokenType> { private readonly DataWriterSettings Settings; private readonly IEnumerable<IDataFilter<ModelTokenType>> Filters; public ModelWalker(DataWriterSettings settings) { if (settings == null) { throw new ArgumentNullException("settings"); } Settings = settings; List<IDataFilter<ModelTokenType>> list = new List<IDataFilter<ModelTokenType>>(); if (settings.Filters != null) { foreach (IDataFilter<ModelTokenType> filter in settings.Filters) { if (filter != null) { list.Add(filter); } } } Filters = list; } public IEnumerable<Token<ModelTokenType>> GetTokens(object value) { GraphCycleType graphCycles = Settings.GraphCycles; ICycleDetector detector = ((graphCycles != GraphCycleType.MaxDepth) ? ((ICycleDetector)new ReferenceSet()) : ((ICycleDetector)new DepthCounter(Settings.MaxDepth))); List<Token<ModelTokenType>> list = new List<Token<ModelTokenType>>(); GetTokens(list, detector, value); return list; } private void GetTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, object value) { if (value == null) { tokens.Add(ModelGrammar.TokenNull); return; } if (detector.Add(value)) { switch (Settings.GraphCycles) { case GraphCycleType.Reference: throw new GraphCycleException(GraphCycleType.Reference, "Graph cycle detected: repeated references"); case GraphCycleType.MaxDepth: throw new GraphCycleException(GraphCycleType.MaxDepth, "Graph cycle potentially detected: maximum depth exceeded"); } tokens.Add(ModelGrammar.TokenNull); return; } try { foreach (IDataFilter<ModelTokenType> filter in Filters) { if (filter.TryWrite(Settings, value, out var tokens2)) { tokens.AddRange(tokens2); return; } } Type type = value.GetType(); if (type.IsEnum) { tokens.Add(ModelGrammar.TokenPrimitive((Enum)value)); return; } switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: tokens.Add(true.Equals(value) ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Decimal: tokens.Add(ModelGrammar.TokenPrimitive((ValueType)value)); break; case TypeCode.Double: { double num2 = (double)value; if (double.IsNaN(num2)) { tokens.Add(ModelGrammar.TokenNaN); } else if (double.IsPositiveInfinity(num2)) { tokens.Add(ModelGrammar.TokenPositiveInfinity); } else if (double.IsNegativeInfinity(num2)) { tokens.Add(ModelGrammar.TokenNegativeInfinity); } else { tokens.Add(ModelGrammar.TokenPrimitive(num2)); } break; } case TypeCode.Single: { float num = (float)value; if (float.IsNaN(num)) { tokens.Add(ModelGrammar.TokenNaN); } else if (float.IsPositiveInfinity(num)) { tokens.Add(ModelGrammar.TokenPositiveInfinity); } else if (float.IsNegativeInfinity(num)) { tokens.Add(ModelGrammar.TokenNegativeInfinity); } else { tokens.Add(ModelGrammar.TokenPrimitive(num)); } break; } case TypeCode.Char: case TypeCode.DateTime: case TypeCode.String: tokens.Add(ModelGrammar.TokenPrimitive(value)); break; case TypeCode.Empty: case TypeCode.DBNull: tokens.Add(ModelGrammar.TokenNull); break; default: if (value is IEnumerable) { GetArrayTokens(tokens, detector, (IEnumerable)value); } else if (value is Guid || value is Uri || value is Version) { tokens.Add(ModelGrammar.TokenPrimitive(value)); } else if (value is TimeSpan) { tokens.Add(ModelGrammar.TokenPrimitive((TimeSpan)value)); } else { GetObjectTokens(tokens, detector, type, value); } break; } } finally { detector.Remove(value); } } private void GetArrayTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, IEnumerable value) { DataName typeName = GetTypeName(value); IEnumerator enumerator = value.GetEnumerator(); if (enumerator is IEnumerator<KeyValuePair<string, object>>) { GetObjectTokens(tokens, detector, typeName, (IEnumerator<KeyValuePair<string, object>>)enumerator); return; } if (enumerator is IDictionaryEnumerator) { GetObjectTokens(tokens, detector, typeName, (IDictionaryEnumerator)enumerator); return; } tokens.Add(ModelGrammar.TokenArrayBegin(typeName)); while (enumerator.MoveNext()) { GetTokens(tokens, detector, enumerator.Current); } tokens.Add(ModelGrammar.TokenArrayEnd); } private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, DataName typeName, IDictionaryEnumerator enumerator) { tokens.Add(ModelGrammar.TokenObjectBegin(typeName)); while (enumerator.MoveNext()) { tokens.Add(ModelGrammar.TokenProperty(enumerator.Key)); GetTokens(tokens, detector, enumerator.Value); } tokens.Add(ModelGrammar.TokenObjectEnd); } private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, DataName typeName, IEnumerator<KeyValuePair<string, object>> enumerator) { tokens.Add(ModelGrammar.TokenObjectBegin(typeName)); while (enumerator.MoveNext()) { KeyValuePair<string, object> current = enumerator.Current; tokens.Add(ModelGrammar.TokenProperty(current.Key)); GetTokens(tokens, detector, current.Value); } tokens.Add(ModelGrammar.TokenObjectEnd); } private void GetObjectTokens(List<Token<ModelTokenType>> tokens, ICycleDetector detector, Type type, object value) { DataName typeName = GetTypeName(value); tokens.Add(ModelGrammar.TokenObjectBegin(typeName)); IDictionary<string, MemberMap> dictionary = Settings.Resolver.LoadMaps(type); if (dictionary == null) { tokens.Add(ModelGrammar.TokenObjectEnd); return; } IEnumerable<MemberMap> enumerable = Settings.Resolver.SortMembers(dictionary.Values); foreach (MemberMap item in enumerable) { if (!item.IsAlternate && item.Getter != null) { object obj = item.Getter(value); if (item.IsIgnored == null || !item.IsIgnored(value, obj)) { tokens.Add(ModelGrammar.TokenProperty(item.DataName)); GetTokens(tokens, detector, obj); } } } tokens.Add(ModelGrammar.TokenObjectEnd); } private DataName GetTypeName(object value) { IEnumerable<DataName> enumerable = Settings.Resolver.LoadTypeName(value?.GetType()); if (enumerable != null) { foreach (DataName item in enumerable) { if (!item.IsEmpty) { return item; } } } return DataName.Empty; } } } namespace JsonFx.Serialization.Filters { public interface IDataFilter<TTokenType> { bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out object value); bool TryWrite(DataWriterSettings settings, object value, out IEnumerable<Token<TTokenType>> tokens); } public interface IDataFilter<TTokenType, TResult> : IDataFilter<TTokenType> { bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out TResult value); bool TryWrite(DataWriterSettings settings, TResult value, out IEnumerable<Token<TTokenType>> tokens); } public abstract class DataFilter<TTokenType, TResult> : IDataFilter<TTokenType, TResult>, IDataFilter<TTokenType> { public abstract bool TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out TResult value); public abstract bool TryWrite(DataWriterSettings settings, TResult value, out IEnumerable<Token<TTokenType>> tokens); bool IDataFilter<TTokenType>.TryRead(DataReaderSettings settings, IStream<Token<TTokenType>> tokens, out object value) { TResult value2; bool result = TryRead(settings, tokens, out value2); value = value2; return result; } bool IDataFilter<TTokenType>.TryWrite(DataWriterSettings settings, object value, out IEnumerable<Token<TTokenType>> tokens) { tokens = null; if (value is TResult) { return TryWrite(settings, (TResult)value, out tokens); } return false; } } } namespace JsonFx.Model.Filters { public abstract class ModelFilter<T> : DataFilter<ModelTokenType, T> { } public class Iso8601DateFilter : ModelFilter<DateTime> { public enum Precision { Seconds, Milliseconds, Ticks } private const string ShortFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK"; private const string LongFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"; private const string FullFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFK"; private string iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"; public Precision Format { get { return iso8601Format switch { "yyyy'-'MM'-'dd'T'HH':'mm':'ssK" => Precision.Seconds, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK" => Precision.Milliseconds, _ => Precision.Ticks, }; } set { switch (value) { case Precision.Seconds: iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK"; break; case Precision.Milliseconds: iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"; break; default: iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFK"; break; } } } public override bool TryRead(DataReaderSettings settings, IStream<Token<ModelTokenType>> tokens, out DateTime value) { Token<ModelTokenType> token = tokens.Peek(); if (token == null || token.TokenType != ModelTokenType.Primitive || !(token.Value is string)) { value = default(DateTime); return false; } if (!TryParseIso8601(token.ValueAsString(), out value)) { value = default(DateTime); return false; } tokens.Pop(); return true; } public override bool TryWrite(DataWriterSettings settings, DateTime value, out IEnumerable<Token<ModelTokenType>> tokens) { tokens = new Token<ModelTokenType>[1] { ModelGrammar.TokenPrimitive(FormatIso8601(value)) }; return true; } private static bool TryParseIso8601(string date, out DateTime value) { try { value = DateTime.ParseExact(date, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFK", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind); } catch (Exception) { value = default(DateTime); return false; } if (value.Kind == DateTimeKind.Local) { value = value.ToUniversalTime(); } return true; } private string FormatIso8601(DateTime value) { if (value.Kind == DateTimeKind.Local) { value = value.ToUniversalTime(); } return value.ToString(iso8601Format); } } public class MSAjaxDateFilter : ModelFilter<DateTime> { private const long MinValueMilliseconds = -62135596800000L; private const long MaxValueMilliseconds = 253402300800000L; private const string MSAjaxDatePattern = "^/Date\\(([+\\-]?\\d+?)([+\\-]\\d{4})?\\)/$"; private const string MSAjaxDatePrefix = "/Date("; private const string MSAjaxDateSuffix = ")/"; private static readonly DateTime EcmaScriptEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); private static readonly Regex MSAjaxDateRegex = new Regex("^/Date\\(([+\\-]?\\d+?)([+\\-]\\d{4})?\\)/$", RegexOptions.Compiled | RegexOptions.ECMAScript | RegexOptions.CultureInvariant); public override bool TryRead(DataReaderSettings settings, IStream<Token<ModelTokenType>> tokens, out DateTime value) { Token<ModelTokenType> token = tokens.Peek(); if (token == null || token.TokenType != ModelTokenType.Primitive || !(token.Value is string)) { value = default(DateTime); return false; } if (!TryParseMSAjaxDate(token.ValueAsString(), out value)) { value = default(DateTime); return false; } tokens.Pop(); return true; } public override bool TryWrite(DataWriterSettings settings, DateTime value, out IEnumerable<Token<ModelTokenType>> tokens) { tokens = new Token<ModelTokenType>[1] { ModelGrammar.TokenPrimitive(FormatMSAjaxDate(value)) }; return true; } internal static bool TryParseMSAjaxDate(string date, out DateTime value) { if (string.IsNullOrEmpty(date)) { value = default(DateTime); return false; } Match match = MSAjaxDateRegex.Match(date); if (!match.Success || !long.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { value = default(DateTime); return false; } if (result <= -62135596800000L) { value = DateTime.MinValue; } else if (result >= 253402300800000L) { value = DateTime.MaxValue; } else { DateTime ecmaScriptEpoch = EcmaScriptEpoch; value = ecmaScriptEpoch.AddMilliseconds(result); } return true; } private string FormatMSAjaxDate(DateTime value) { if (value.Kind == DateTimeKind.Local) { value = value.ToUniversalTime(); } long num = (long)value.Subtract(EcmaScriptEpoch).TotalMilliseconds; return "/Date(" + num + ")/"; } } } namespace JsonFx.Serialization { public interface IDataWriter { Encoding ContentEncoding { get; } IEnumerable<string> ContentType { get; } IEnumerable<string> FileExtension { get; } DataWriterSettings Settings { get; } void Write(object data, TextWriter output); string Write(object data); } public abstract class DataWriter<T> : IDataWriter { private readonly DataWriterSettings settings; public abstract Encoding ContentEncoding { get; } public abstract IEnumerable<string> ContentType { get; } public abstract IEnumerable<string> FileExtension { get; } public DataWriterSettings Settings => settings; protected DataWriter(DataWriterSettings settings) { if (settings == null) { throw new NullReferenceException("settings"); } this.settings = settings; } public virtual void Write(object data, TextWriter output) { IObjectWalker<T> walker = GetWalker(); if (walker == null) { throw new ArgumentNullException("walker"); } ITextFormatter<T> formatter = GetFormatter(); if (formatter == null) { throw new ArgumentNullException("formatter"); } try { formatter.Format(walker.GetTokens(data), output); } catch (SerializationException) { throw; } catch (Exception ex2) { throw new SerializationException(ex2.Message, ex2); } } public virtual string Write(object data) { IObjectWalker<T> walker = GetWalker(); if (walker == null) { throw new ArgumentNullException("walker"); } ITextFormatter<T> formatter = GetFormatter(); if (formatter == null) { throw new ArgumentNullException("formatter"); } try { return formatter.Format(walker.GetTokens(data)); } catch (SerializationException) { throw; } catch (Exception ex2) { throw new SerializationException(ex2.Message, ex2); } } protected abstract IObjectWalker<T> GetWalker(); protected abstract ITextFormatter<T> GetFormatter(); } } namespace JsonFx.Model { public abstract class ModelWriter : DataWriter<ModelTokenType> { public override Encoding ContentEncoding => Encoding.UTF8; protected ModelWriter(DataWriterSettings settings) : base(settings) { } protected override IObjectWalker<ModelTokenType> GetWalker() { return new ModelWalker(base.Settings); } } } namespace JsonFx.Serialization { public interface ITextFormattable<T> { void Format(ITextFormatter<T> formatter, TextWriter writer); } } namespace JsonFx.EcmaScript { public class EcmaScriptIdentifier : ITextFormattable<ModelTokenType> { private readonly string identifier; public string Identifier => identifier; public EcmaScriptIdentifier() : this(null) { } public EcmaScriptIdentifier(string ident) { identifier = (string.IsNullOrEmpty(ident) ? string.Empty : VerifyIdentifier(ident, nested: true)); } public static string VerifyIdentifier(string ident, bool nested) { return VerifyIdentifier(ident, nested, throwOnEmpty: true); } public static string VerifyIdentifier(string ident, bool nested, bool throwOnEmpty) { if (string.IsNullOrEmpty(ident)) { if (throwOnEmpty) { throw new ArgumentException("Identifier is empty."); } return string.Empty; } ident = ident.Replace(" ", ""); if (!IsValidIdentifier(ident, nested)) { throw new ArgumentException("Identifier \"" + ident + "\" is not supported."); } return ident; } public static bool IsValidIdentifier(string ident, bool nested) { if (string.IsNullOrEmpty(ident)) { return false; } if (nested) { string[] array = ident.Split(new char[1] { '.' }); string[] array2 = array; foreach (string ident2 in array2) { if (!IsValidIdentifier(ident2, nested: false)) { return false; } } return true; } if (IsReservedWord(ident)) { return false; } bool flag = false; int j = 0; for (int length = ident.Length; j < length; j++) { char c = ident[j]; if (!flag || c < '0' || c > '9') { if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_' && c != '$') { return false; } flag = true; } } return true; } private static bool IsReservedWord(string ident) { switch (ident) { case "null": case "false": case "true": case "break": case "case": case "catch": case "continue": case "debugger": case "default": case "delete": case "do": case "else": case "finally": case "for": case "function": case "if": case "in": case "instanceof": case "new": case "return": case "switch": case "this": case "throw": case "try": case "typeof": case "var": case "void": case "while": case "with": case "abstract": case "boolean": case "byte": case "char": case "class": case "const": case "double": case "enum": case "export": case "extends": case "final": case "float": case "goto": case "implements": case "import": case "int": case "interface": case "long": case "native": case "package": case "private": case "protected": case "public": case "short": case "static": case "super": case "synchronized": case "throws": case "transient": case "volatile": case "let": case "yield": return true; default: return false; } } public static EcmaScriptIdentifier Parse(string value) { return new EcmaScriptIdentifier(value); } public static implicit operator string(EcmaScriptIdentifier ident) { if (ident == null) { return string.Empty; } return ident.identifier; } public static implicit operator EcmaScriptIdentifier(string ident) { return new EcmaScriptIdentifier(ident); } void ITextFormattable<ModelTokenType>.Format(ITextFormatter<ModelTokenType> formatter, TextWriter writer) { if (string.IsNullOrEmpty(identifier)) { writer.Write("null"); } else { writer.Write(identifier); } } public override string ToString() { return identifier; } public override bool Equals(object obj) { if (!(obj is EcmaScriptIdentifier ecmaScriptIdentifier)) { return base.Equals(obj); } if (string.IsNullOrEmpty(identifier) && string.IsNullOrEmpty(ecmaScriptIdentifier.identifier)) { return true; } return StringComparer.Ordinal.Equals(identifier, ecmaScriptIdentifier.identifier); } public override int GetHashCode() { return StringComparer.Ordinal.GetHashCode(identifier); } } } namespace JsonFx.Serialization { public interface ITextFormatter<T> { void Format(IEnumerable<Token<T>> tokens, TextWriter writer); string Format(IEnumerable<Token<T>> tokens); } } namespace JsonFx.Json { public class JsonWriter : ModelWriter { public class JsonFormatter : ITextFormatter<ModelTokenType> { private readonly DataWriterSettings Settings; private bool encodeLessThan; public bool EncodeLessThan { get { return encodeLessThan; } set { encodeLessThan = value; } } public JsonFormatter(DataWriterSettings settings) { if (settings == null) { throw new ArgumentNullException("settings"); } Settings = settings; } public string Format(IEnumerable<Token<ModelTokenType>> tokens) { using StringWriter stringWriter = new StringWriter(); Format(tokens, stringWriter); return stringWriter.GetStringBuilder().ToString(); } public void Format(IEnumerable<Token<ModelTokenType>> tokens, TextWriter writer) { if (tokens == null) { throw new ArgumentNullException("tokens"); } bool prettyPrint = Settings.PrettyPrint; bool flag = false; bool flag2 = false; int num = 0; foreach (Token<ModelTokenType> token in tokens) { switch (token.TokenType) { case ModelTokenType.ArrayBegin: if (flag2) { writer.Write(','); if (prettyPrint) { WriteLine(writer, num); } } if (flag) { if (prettyPrint) { WriteLine(writer, ++num); } flag = false; } writer.Write('['); flag = true; flag2 = false; break; case ModelTokenType.ArrayEnd: if (flag) { flag = false; } else if (prettyPrint) { WriteLine(writer, --num); } writer.Write(']'); flag2 = true; break; case ModelTokenType.Primitive: { if (flag2) { writer.Write(','); if (prettyPrint) { WriteLine(writer, num); } } if (flag) { if (prettyPrint) { WriteLine(writer, ++num); } flag = false; } Type type = ((token.Value == null) ? null : token.Value.GetType()); TypeCode typeCode = Type.GetTypeCode(type); switch (typeCode) { case TypeCode.Boolean: writer.Write(true.Equals(token.Value) ? "true" : "false"); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: if (!type.IsEnum) { WriteNumber(writer, token.Value, typeCode); break; } goto default; case TypeCode.Empty: case TypeCode.DBNull: writer.Write("null"); break; default: if (token.Value is ITextFormattable<ModelTokenType> textFormattable) { textFormattable.Format(this, writer); } else { WritePrimitive(writer, token.Value); } break; } flag2 = true; break; } case ModelTokenType.ObjectBegin: if (flag2) { writer.Write(','); if (prettyPrint) { WriteLine(writer, num); } } if (flag) { if (prettyPrint) { WriteLine(writer, ++num); } flag = false; } writer.Write('{'); flag = true; flag2 = false; break; case ModelTokenType.ObjectEnd: if (flag) { flag = false; } else if (prettyPrint) { WriteLine(writer, --num); } writer.Write('}'); flag2 = true; break; case ModelTokenType.Property: if (flag2) { writer.Write(','); if (prettyPrint) { WriteLine(writer, num); } } if (flag) { if (prettyPrint) { WriteLine(writer, ++num); } flag = false; } WritePropertyName(writer, token.Name.LocalName); if (prettyPrint) { writer.Write(" "); writer.Write(':'); writer.Write(" "); } else { writer.Write(':'); } flag2 = false; break; default: throw new TokenException<ModelTokenType>(token, $"Unexpected token ({token.TokenType})"); } } } protected virtual void WritePrimitive(TextWriter writer, object value) { if (value is TimeSpan) { WriteNumber(writer, ((TimeSpan)value).Ticks, TypeCode.Int64); } else { WriteString(writer, FormatString(value)); } } protected virtual void WritePropertyName(TextWriter writer, string propertyName) { WriteString(writer, FormatString(propertyName)); } protected virtual void WriteNumber(TextWriter writer, object value, TypeCode typeCode) { bool flag = false; string value2; switch (typeCode) { case TypeCode.Byte: value2 = ((byte)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.Boolean: value2 = (true.Equals(value) ? "1" : "0"); break; case TypeCode.Decimal: flag = true; value2 = ((decimal)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.Double: { double d = (double)value; if (double.IsNaN(d)) { WriteNaN(writer); return; } if (double.IsInfinity(d)) { if (double.IsNegativeInfinity(d)) { WriteNegativeInfinity(writer); } else { WritePositiveInfinity(writer); } return; } value2 = d.ToString("r", CultureInfo.InvariantCulture); break; } case TypeCode.Int16: value2 = ((short)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.Int32: value2 = ((int)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.Int64: flag = true; value2 = ((long)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.SByte: value2 = ((sbyte)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.Single: { float f = (float)value; if (float.IsNaN(f)) { WriteNaN(writer); return; } if (float.IsInfinity(f)) { if (float.IsNegativeInfinity(f)) { WriteNegativeInfinity(writer); } else { WritePositiveInfinity(writer); } return; } value2 = f.ToString("r", CultureInfo.InvariantCulture); break; } case TypeCode.UInt16: value2 = ((ushort)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.UInt32: flag = true; value2 = ((uint)value).ToString("g", CultureInfo.InvariantCulture); break; case TypeCode.UInt64: flag = true; value2 = ((ulong)value).ToString("g", CultureInfo.InvariantCulture); break; default: throw new TokenException<ModelTokenType>(ModelGrammar.TokenPrimitive(value), "Invalid number token"); } if (flag && InvalidIEEE754(Convert.ToDecimal(value))) { WriteString(writer, value2); } else { writer.Write(value2); } } protected virtual void WriteNegativeInfinity(TextWriter writer) { writer.Write("null"); } protected virtual void WritePositiveInfinity(TextWriter writer) { writer.Write("null"); } protected virtual void WriteNaN(TextWriter writer) { writer.Write("null"); } protected virtual void WriteString(TextWriter writer, string value) { int num = 0; int length = value.Length; writer.Write('"'); for (int i = num; i < length; i++) { char c = value[i]; if (c <= '\u001f' || c >= '\u007f' || (encodeLessThan && c == '<') || c == '"' || c == '\\') { if (i > num) { writer.Write(value.Substring(num, i - num)); } num = i + 1; switch (c) { case '"': case '\\': writer.Write('\\'); writer.Write(c); break; case '\b': writer.Write("\\b"); break; case '\f': writer.Write("\\f"); break; case '\n': writer.Write("\\n"); break; case '\r': writer.Write("\\r"); break; case '\t': writer.Write("\\t"); break; default: writer.Write("\\u"); writer.Write(CharUtility.ConvertToUtf32(value, i).ToString("X4")); break; } } } if (length > num) { writer.Write(value.Substring(num, length - num)); } writer.Write('"'); } private void WriteLine(TextWriter writer, int depth) { writer.Write(Settings.NewLine); for (int i = 0; i < depth; i++) { writer.Write(Settings.Tab); } } protected virtual string FormatString(object value) { if (value is Enum) { return FormatEnum((Enum)value); } return Token<ModelTokenType>.ToString(value); } private string FormatEnum(Enum value) { Type type = value.GetType(); IDictionary<Enum, string> dictionary = Settings.Resolver.LoadEnumMaps(type); if (type.IsDefined(typeof(FlagsAttribute), inherit: true) && !Enum.IsDefined(type, value)) { Enum[] flagList = GetFlagList(type, value); string[] array = new string[flagList.Length]; for (int i = 0; i < flagList.Length; i++) { if (!dictionary.TryGetValue(flagList[i], out array[i]) || string.IsNullOrEmpty(array[i])) { array[i] = flagList[i].ToString("f"); } } return string.Join(", ", array); } if (!dictionary.TryGetValue(value, out var value2) || string.IsNullOrEmpty(value2)) { return value.ToString("f"); } return value2; } private static Enum[] GetFlagList(Type enumType, object value) { ulong num = Convert.ToUInt64(value); Array values = Enum.GetValues(enumType); List<Enum> list = new List<Enum>(values.Length); if (num == 0) { list.Add((Enum)Convert.ChangeType(value, enumType, CultureInfo.InvariantCulture)); return list.ToArray(); } for (int num2 = values.Length - 1; num2 >= 0; num2--) { ulong num3 = Convert.ToUInt64(values.GetValue(num2)); if ((num2 != 0 || num3 != 0) && (num & num3) == num3) { num -= num3; list.Add(values.GetValue(num2) as Enum); } } if (num != 0) { list.Add(Enum.ToObject(enumType, num) as Enum); } return list.ToArray(); } protected virtual bool InvalidIEEE754(decimal value) { try { return (decimal)decimal.ToDouble(value) != value; } catch { return true; } } } private const string ErrorUnexpectedToken = "Unexpected token ({0})"; private readonly string[] ContentTypes; public override IEnumerable<string> ContentType { get { if (ContentTypes != null) { try { string[] contentTypes = ContentTypes; for (int i = 0; i < contentTypes.Length; i++) { yield return contentTypes[i]; } yield break; } finally { } } yield return "application/json"; yield return "text/json"; yield return "text/x-json"; } } public override IEnumerable<string> FileExtension { get { yield return ".json"; } } public JsonWriter() : base(new DataWriterSettings()) { } public JsonWriter(DataWriterSettings settings) : base((settings != null) ? settings : new DataWriterSettings()) { } public JsonWriter(DataWriterSettings settings, params string[] contentTypes) : base((settings != null) ? settings : new DataWriterSettings()) { if (contentTypes == null) { throw new NullReferenceException("contentTypes"); } ContentTypes = new string[contentTypes.Length]; Array.Copy(contentTypes, ContentTypes, contentTypes.Length); } protected override ITextFormatter<ModelTokenType> GetFormatter() { return new JsonFormatter(base.Settings); } } } namespace JsonFx.EcmaScript { public class EcmaScriptFormatter : JsonWriter.JsonFormatter { private const string EcmaScriptDateCtor1 = "new Date({0})"; private const string EcmaScriptDateCtor7 = "new Date({0:0000},{1},{2},{3},{4},{5},{6})"; private const string EmptyRegExpLiteral = "(?:)"; private const char RegExpLiteralDelim = '/'; private const char OperatorCharEscape = '\\'; private const string NamespaceDelim = "."; private const string RootDeclarationDebug = "\r\n/* namespace {1} */\r\nvar {0};"; private const string RootDeclaration = "var {0};"; private const string NamespaceCheck = "if(\"undefined\"===typeof {0}){{{0}={{}};}}"; private const string NamespaceCheckDebug = "\r\nif (\"undefined\" === typeof {0}) {{\r\n\t{0} = {{}};\r\n}}"; private static readonly DateTime EcmaScriptEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); private static readonly char[] NamespaceDelims = new char[1] { '.' }; private static readonly IList<string> BrowserObjects = new List<string>(new string[10] { "console", "document", "event", "frames", "history", "location", "navigator", "opera", "screen", "window" }); public EcmaScriptFormatter(DataWriterSettings settings) : base(settings) { } public static bool WriteNamespaceDeclaration(TextWriter writer, string ident, List<string> namespaces, bool prettyPrint) { if (string.IsNullOrEmpty(ident)) { return false; } if (namespaces == null) { namespaces = new List<string>(); } string[] array = ident.Split(NamespaceDelims, StringSplitOptions.RemoveEmptyEntries); string text = array[0]; bool flag = false; for (int i = 0; i < array.Length - 1; i++) { flag = true; if (i > 0) { text += "."; text += array[i]; } if (namespaces.Contains(text) || BrowserObjects.Contains(text)) { continue; } namespaces.Add(text); if (i == 0) { if (prettyPrint) { writer.Write("\r\n/* namespace {1} */\r\nvar {0};", text, string.Join(".", array, 0, array.Length - 1)); } else { writer.Write("var {0};", text); } } if (prettyPrint) { writer.WriteLine("\r\nif (\"undefined\" === typeof {0}) {{\r\n\t{0} = {{}};\r\n}}", text); } else { writer.Write("if(\"undefined\"===typeof {0}){{{0}={{}};}}", text); } } if (prettyPrint && flag) { writer.WriteLine(); } return flag; } protected override void WriteNaN(TextWriter writer) { writer.Write("NaN"); } protected override void WriteNegativeInfinity(TextWriter writer) { writer.Write('-'); writer.Write("Infinity"); } protected override void WritePositiveInfinity(TextWriter writer) { writer.Write("Infinity"); } protected override void WritePrimitive(TextWriter writer, object value) { if (value is DateTime) { WriteEcmaScriptDate(writer, (DateTime)value); } else if (value is Regex) { WriteEcmaScriptRegExp(writer, (Regex)value); } else { base.WritePrimitive(writer, value); } } protected override void WritePropertyName(TextWriter writer, string propertyName) { if (EcmaScriptIdentifier.IsValidIdentifier(propertyName, nested: false)) { writer.Write(propertyName); } else { base.WritePropertyName(writer, propertyName); } } public static void WriteEcmaScriptDate(TextWriter writer, DateTime value) { if (value.Kind == DateTimeKind.Unspecified) { writer.Write("new Date({0:0000},{1},{2},{3},{4},{5},{6})", value.Year, value.Month - 1, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond); } else { if (value.Kind == DateTimeKind.Local) { value = value.ToUniversalTime(); } long num = (long)value.Subtract(EcmaScriptEpoch).TotalMilliseconds; writer.Write("new Date({0})", num); } } public static void WriteEcmaScriptRegExp(TextWriter writer, Regex regex) { WriteEcmaScriptRegExp(writer, regex, isGlobal: false); } public static void WriteEcmaScriptRegExp(TextWriter writer, Regex regex, bool isGlobal) { if (regex == null) { writer.Write("null"); return; } string text = regex.ToString(); if (string.IsNullOrEmpty(text)) { text = "(?:)"; } string text2 = (isGlobal ? "g" : ""); switch (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.Multiline)) { case RegexOptions.IgnoreCase: text2 += "i"; break; case RegexOptions.Multiline: text2 += "m"; break; case RegexOptions.IgnoreCase | RegexOptions.Multiline: text2 += "im"; break; } writer.Write('/'); int length = text.Length; int num = 0; for (int i = num; i < length; i++) { char c = text[i]; if (c == '/') { writer.Write(text.Substring(num, i - num)); num = i + 1; writer.Write('\\'); writer.Write(text[i]); } } writer.Write(text.Substring(num, length - num)); writer.Write('/'); writer.Write(text2); } } } namespace JsonFx.Html { public interface IHtmlFilterStrategy { bool FilterTag(DataName tag, MarkupTokenType type, HtmlTaxonomy taxonomy); bool FilterAttribute(DataName tag, DataName attribute, ref object value); bool FilterStyle(DataName tag, string style, ref object value); bool FilterLiteral(ref object value); } public class HtmlFilter { private static bool VoidTagRequired(string tag) { switch (tag) { case "area": case "base": case "basefont": case "br": case "col": case "frame": case "hr": case "img": case "input": case "isindex": case "keygen": case "link": case "meta": case "param": case "source": case "wbr": return true; default: return false; } } private static bool CloseTagOptional(string tag) { switch (tag) { case "body": case "colgroup": case "dd": case "dt": case "embed": case "head": case "html": case "li": case "option": case "p": case "tbody": case "td": case "tfoot": case "th": case "thead": case "tr": return true; default: return false; } } private static HtmlTaxonomy GetTaxonomy(string tag) { switch (tag) { case "a": case "abbr": case "acronym": case "area": case "bdo": case "cite": case "code": case "dfn": case "em": case "isindex": case "kbd": case "map": case "q": case "samp": case "span": case "strong": case "time": case "var": case "wbr": return HtmlTaxonomy.Inline; case "audio": case "bgsound": case "img": case "sound": case "source": return HtmlTaxonomy.Inline | HtmlTaxonomy.Media; case "canvas": case "math": case "svg": case "video": return HtmlTaxonomy.Block | HtmlTaxonomy.Media; case "b": case "big": case "blink": case "figcaption": case "font": case "i": case "marquee": case "mark": case "rp": case "rt": case "ruby": case "s": case "small": case "strike": case "sub": case "sup": case "tt": case "u": return HtmlTaxonomy.Inline | HtmlTaxonomy.Style; case "address": case "article": case "asside": case "blockquote": case "bq": case "br": case "center": case "del": case "details": case "div": case "figure": case "footer": case "h1": case "h2": case "h3": case "h4": case "h5": case "h6": case "header": case "hgroup": case "hr": case "ins": case "nav": case "nobr": case "p": case "pre": case "section": case "summary": return HtmlTaxonomy.Block; case "command": case "dl": case "dd": case "dir": case "dt": case "lh": case "li": case "menu": case "ol": case "ul": return HtmlTaxonomy.List; case "caption": case "col": case "colgroup": case "table": case "tbody": case "td": case "th": case "the