Decompiled source of UMM v1.0.2
UMM/Core/0Harmony.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.SymbolStore; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using Iced.Intel; using Iced.Intel.BlockEncoderInternal; using Iced.Intel.DecoderInternal; using Iced.Intel.EncoderInternal; using Iced.Intel.Internal; using Microsoft.Cci; using Microsoft.Cci.Pdb; using Microsoft.CodeAnalysis; using Microsoft.Win32.SafeHandles; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Metadata; using Mono.Cecil.PE; using Mono.Collections.Generic; using Mono.CompilerServices.SymbolWriter; using Mono.Security.Cryptography; using MonoMod; using MonoMod.Backports.ILHelpers; using MonoMod.Cil; using MonoMod.Core; using MonoMod.Core.Interop; using MonoMod.Core.Interop.Attributes; using MonoMod.Core.Platforms; using MonoMod.Core.Platforms.Architectures; using MonoMod.Core.Platforms.Architectures.AltEntryFactories; using MonoMod.Core.Platforms.Memory; using MonoMod.Core.Platforms.Runtimes; using MonoMod.Core.Platforms.Systems; using MonoMod.Core.Utils; using MonoMod.Logs; using MonoMod.SourceGen.Attributes; using MonoMod.Utils; using MonoMod.Utils.Cil; using MonoMod.Utils.Interop; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: ComVisible(false)] [assembly: InternalsVisibleTo("HarmonyTests")] [assembly: InternalsVisibleTo("MonoMod.Utils.Cil.ILGeneratorProxy")] [assembly: Guid("69aee16a-b6e7-4642-8081-3928b32455df")] [assembly: AssemblyCompany("Andreas Pardeike")] [assembly: AssemblyConfiguration("ReleaseFat")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyDescription("A general non-destructive patch library for .NET and Mono modules")] [assembly: AssemblyFileVersion("2.3.6.0")] [assembly: AssemblyInformationalVersion("2.3.6.0+f41da7608c5c3e9c7bf16551462b14c0b5392db3")] [assembly: AssemblyProduct("Harmony")] [assembly: AssemblyTitle("0Harmony")] [assembly: SecurityPermission(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.3.6.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] internal class <Module> { static <Module>() { <d93ed7d0-1242-4c9d-a80d-b2e3dba3921c>MMDbgLog.LogVersion(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HarmonyLib { public class DelegateTypeFactory { private readonly ModuleBuilder module; private static int counter; public DelegateTypeFactory() { counter++; string name = $"HarmonyDTFAssembly{counter}"; AssemblyBuilder assemblyBuilder = PatchTools.DefineDynamicAssembly(name); module = assemblyBuilder.DefineDynamicModule($"HarmonyDTFModule{counter}"); } public Type CreateDelegateType(MethodInfo method) { System.Reflection.TypeAttributes attr = System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Sealed; TypeBuilder typeBuilder = module.DefineType($"HarmonyDTFType{counter}", attr, typeof(MulticastDelegate)); ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[2] { typeof(object), typeof(IntPtr) }); constructorBuilder.SetImplementationFlags(System.Reflection.MethodImplAttributes.CodeTypeMask); ParameterInfo[] parameters = method.GetParameters(); MethodBuilder methodBuilder = typeBuilder.DefineMethod("Invoke", System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Virtual | System.Reflection.MethodAttributes.HideBySig, method.ReturnType, parameters.Types()); methodBuilder.SetImplementationFlags(System.Reflection.MethodImplAttributes.CodeTypeMask); for (int i = 0; i < parameters.Length; i++) { methodBuilder.DefineParameter(i + 1, System.Reflection.ParameterAttributes.None, parameters[i].Name); } return typeBuilder.CreateType(); } } [Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Func<T, S>> for property getters")] [EditorBrowsable(EditorBrowsableState.Never)] public delegate S GetterHandler<in T, out S>(T source); [Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Action<T, S>> for property setters")] [EditorBrowsable(EditorBrowsableState.Never)] public delegate void SetterHandler<in T, in S>(T source, S value); public delegate T InstantiationHandler<out T>(); public static class FastAccess { public static InstantiationHandler<T> CreateInstantiationHandler<T>() { ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); if ((object)constructor == null) { throw new ApplicationException($"The type {typeof(T)} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public)."); } DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("InstantiateObject_" + typeof(T).Name, typeof(T), null); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Newobj, constructor); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<InstantiationHandler<T>>(dynamicMethodDefinition.Generate()); } [Obsolete("Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))")] [EditorBrowsable(EditorBrowsableState.Never)] public static GetterHandler<T, S> CreateGetterHandler<T, S>(PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true); DynamicMethodDefinition dynamicMethodDefinition = CreateGetDynamicMethod<T, S>(propertyInfo.DeclaringType); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, getMethod); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<GetterHandler<T, S>>(dynamicMethodDefinition.Generate()); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")] [EditorBrowsable(EditorBrowsableState.Never)] public static GetterHandler<T, S> CreateGetterHandler<T, S>(FieldInfo fieldInfo) { DynamicMethodDefinition dynamicMethodDefinition = CreateGetDynamicMethod<T, S>(fieldInfo.DeclaringType); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldfld, fieldInfo); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<GetterHandler<T, S>>(dynamicMethodDefinition.Generate()); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(name) for fields and AccessTools.MethodDelegate<Func<T, S>>(AccessTools.PropertyGetter(typeof(T), name)) for properties")] [EditorBrowsable(EditorBrowsableState.Never)] public static GetterHandler<T, S> CreateFieldGetter<T, S>(params string[] names) { foreach (string name in names) { FieldInfo field = typeof(T).GetField(name, AccessTools.all); if ((object)field != null) { return CreateGetterHandler<T, S>(field); } PropertyInfo property = typeof(T).GetProperty(name, AccessTools.all); if ((object)property != null) { return CreateGetterHandler<T, S>(property); } } return null; } [Obsolete("Use AccessTools.MethodDelegate<Action<T, S>>(PropertyInfo.GetSetMethod(true))")] [EditorBrowsable(EditorBrowsableState.Never)] public static SetterHandler<T, S> CreateSetterHandler<T, S>(PropertyInfo propertyInfo) { MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true); DynamicMethodDefinition dynamicMethodDefinition = CreateSetDynamicMethod<T, S>(propertyInfo.DeclaringType); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, setMethod); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<SetterHandler<T, S>>(dynamicMethodDefinition.Generate()); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")] [EditorBrowsable(EditorBrowsableState.Never)] public static SetterHandler<T, S> CreateSetterHandler<T, S>(FieldInfo fieldInfo) { DynamicMethodDefinition dynamicMethodDefinition = CreateSetDynamicMethod<T, S>(fieldInfo.DeclaringType); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Stfld, fieldInfo); iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<SetterHandler<T, S>>(dynamicMethodDefinition.Generate()); } private static DynamicMethodDefinition CreateGetDynamicMethod<T, S>(Type type) { return new DynamicMethodDefinition("DynamicGet_" + type.Name, typeof(S), new Type[1] { typeof(T) }); } private static DynamicMethodDefinition CreateSetDynamicMethod<T, S>(Type type) { return new DynamicMethodDefinition("DynamicSet_" + type.Name, typeof(void), new Type[2] { typeof(T), typeof(S) }); } } public delegate object FastInvokeHandler(object target, params object[] parameters); public static class MethodInvoker { public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBoxValueAccess = false) { DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("FastInvoke_" + methodInfo.Name + "_" + (directBoxValueAccess ? "direct" : "indirect"), typeof(object), new Type[2] { typeof(object), typeof(object[]) }); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); if (!methodInfo.IsStatic) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_0); EmitUnboxIfNeeded(iLGenerator, methodInfo.DeclaringType); } bool flag = true; ParameterInfo[] parameters = methodInfo.GetParameters(); for (int i = 0; i < parameters.Length; i++) { Type type = parameters[i].ParameterType; bool isByRef = type.IsByRef; if (isByRef) { type = type.GetElementType(); } bool isValueType = type.IsValueType; if (isByRef && isValueType && !directBoxValueAccess) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_1); EmitFastInt(iLGenerator, i); } Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldarg_1); EmitFastInt(iLGenerator, i); if (isByRef && !isValueType) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldelema, typeof(object)); continue; } Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldelem_Ref); if (!isValueType) { continue; } if (!isByRef || !directBoxValueAccess) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox_Any, type); if (isByRef) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Box, type); Emit(iLGenerator, System.Reflection.Emit.OpCodes.Dup); if (flag) { flag = false; iLGenerator.DeclareLocal(typeof(object), pinned: false); } Emit(iLGenerator, System.Reflection.Emit.OpCodes.Stloc_0); Emit(iLGenerator, System.Reflection.Emit.OpCodes.Stelem_Ref); Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldloc_0); Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox, type); } } else { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Unbox, type); } } if (methodInfo.IsStatic) { EmitCall(iLGenerator, System.Reflection.Emit.OpCodes.Call, methodInfo); } else { EmitCall(iLGenerator, System.Reflection.Emit.OpCodes.Callvirt, methodInfo); } if ((object)methodInfo.ReturnType == typeof(void)) { Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ldnull); } else { EmitBoxIfNeeded(iLGenerator, methodInfo.ReturnType); } Emit(iLGenerator, System.Reflection.Emit.OpCodes.Ret); return Extensions.CreateDelegate<FastInvokeHandler>(dynamicMethodDefinition.Generate()); } internal static void Emit(ILGenerator il, System.Reflection.Emit.OpCode opcode) { il.Emit(opcode); } internal static void Emit(ILGenerator il, System.Reflection.Emit.OpCode opcode, Type type) { il.Emit(opcode, type); } internal static void EmitCall(ILGenerator il, System.Reflection.Emit.OpCode opcode, MethodInfo methodInfo) { il.EmitCall(opcode, methodInfo, null); } private static void EmitUnboxIfNeeded(ILGenerator il, Type type) { if (type.IsValueType) { Emit(il, System.Reflection.Emit.OpCodes.Unbox_Any, type); } } private static void EmitBoxIfNeeded(ILGenerator il, Type type) { if (type.IsValueType) { Emit(il, System.Reflection.Emit.OpCodes.Box, type); } } internal static void EmitFastInt(ILGenerator il, int value) { switch (value) { case -1: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1); return; case 0: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); return; case 1: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1); return; case 2: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2); return; case 3: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_3); return; case 4: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4); return; case 5: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_5); return; case 6: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_6); return; case 7: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_7); return; case 8: il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_8); return; } if (value > -129 && value < 128) { il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_S, (sbyte)value); } else { il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, value); } } } public delegate ref T RefResult<T>(); internal class AccessCache { internal enum MemberType { Any, Static, Instance } private const BindingFlags BasicFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; private static readonly Dictionary<MemberType, BindingFlags> declaredOnlyBindingFlags = new Dictionary<MemberType, BindingFlags> { { MemberType.Any, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty }, { MemberType.Instance, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty }, { MemberType.Static, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty } }; private readonly Dictionary<Type, Dictionary<string, FieldInfo>> declaredFields = new Dictionary<Type, Dictionary<string, FieldInfo>>(); private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> declaredProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> declaredMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>(); private readonly Dictionary<Type, Dictionary<string, FieldInfo>> inheritedFields = new Dictionary<Type, Dictionary<string, FieldInfo>>(); private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> inheritedProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> inheritedMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>(); private static T Get<T>(Dictionary<Type, Dictionary<string, T>> dict, Type type, string name, Func<T> fetcher) { lock (dict) { if (!dict.TryGetValue(type, out var value)) { value = (dict[type] = new Dictionary<string, T>()); } if (!value.TryGetValue(name, out var value2)) { value2 = (value[name] = fetcher()); } return value2; } } private static T Get<T>(Dictionary<Type, Dictionary<string, Dictionary<int, T>>> dict, Type type, string name, Type[] arguments, Func<T> fetcher) { lock (dict) { if (!dict.TryGetValue(type, out var value)) { value = (dict[type] = new Dictionary<string, Dictionary<int, T>>()); } if (!value.TryGetValue(name, out var value2)) { value2 = (value[name] = new Dictionary<int, T>()); } int key = AccessTools.CombinedHashCode(arguments); if (!value2.TryGetValue(key, out var value3)) { value3 = (value2[key] = fetcher()); } return value3; } } internal FieldInfo GetFieldInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false) { FieldInfo fieldInfo = Get(declaredFields, type, name, () => type.GetField(name, declaredOnlyBindingFlags[memberType])); if ((object)fieldInfo == null && !declaredOnly) { fieldInfo = Get(inheritedFields, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetField(name, AccessTools.all))); } return fieldInfo; } internal PropertyInfo GetPropertyInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false) { PropertyInfo propertyInfo = Get(declaredProperties, type, name, () => type.GetProperty(name, declaredOnlyBindingFlags[memberType])); if ((object)propertyInfo == null && !declaredOnly) { propertyInfo = Get(inheritedProperties, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetProperty(name, AccessTools.all))); } return propertyInfo; } internal MethodBase GetMethodInfo(Type type, string name, Type[] arguments, MemberType memberType = MemberType.Any, bool declaredOnly = false) { MethodBase methodBase = Get(declaredMethods, type, name, arguments, () => type.GetMethod(name, declaredOnlyBindingFlags[memberType], null, arguments, null)); if ((object)methodBase == null && !declaredOnly) { methodBase = Get(inheritedMethods, type, name, arguments, () => AccessTools.Method(type, name, arguments)); } return methodBase; } } internal class ByteBuffer { internal byte[] buffer; internal int position; internal ByteBuffer(byte[] buffer) { this.buffer = buffer; } internal byte ReadByte() { CheckCanRead(1); return buffer[position++]; } internal byte[] ReadBytes(int length) { CheckCanRead(length); byte[] array = new byte[length]; Buffer.BlockCopy(buffer, position, array, 0, length); position += length; return array; } internal short ReadInt16() { CheckCanRead(2); short result = (short)(buffer[position] | (buffer[position + 1] << 8)); position += 2; return result; } internal int ReadInt32() { CheckCanRead(4); int result = buffer[position] | (buffer[position + 1] << 8) | (buffer[position + 2] << 16) | (buffer[position + 3] << 24); position += 4; return result; } internal long ReadInt64() { CheckCanRead(8); uint num = (uint)(buffer[position] | (buffer[position + 1] << 8) | (buffer[position + 2] << 16) | (buffer[position + 3] << 24)); uint num2 = (uint)(buffer[position + 4] | (buffer[position + 5] << 8) | (buffer[position + 6] << 16) | (buffer[position + 7] << 24)); long result = (long)(((ulong)num2 << 32) | num); position += 8; return result; } internal float ReadSingle() { if (!BitConverter.IsLittleEndian) { byte[] array = ReadBytes(4); Array.Reverse((Array)array); return BitConverter.ToSingle(array, 0); } CheckCanRead(4); float result = BitConverter.ToSingle(buffer, position); position += 4; return result; } internal double ReadDouble() { if (!BitConverter.IsLittleEndian) { byte[] array = ReadBytes(8); Array.Reverse((Array)array); return BitConverter.ToDouble(array, 0); } CheckCanRead(8); double result = BitConverter.ToDouble(buffer, position); position += 8; return result; } private void CheckCanRead(int count) { if (position + count > buffer.Length) { throw new ArgumentOutOfRangeException("count", $"position({position}) + count({count}) > buffer.Length({buffer.Length})"); } } } internal class CodeTranspiler { [CompilerGenerated] private sealed class <ConvertToOurInstructions>d__7 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private int <>l__initialThreadId; private IEnumerable instructions; public IEnumerable <>3__instructions; private Type codeInstructionType; public Type <>3__codeInstructionType; private Dictionary<object, Dictionary<string, object>> unassignedValues; public Dictionary<object, Dictionary<string, object>> <>3__unassignedValues; private List<object> originalInstructions; public List<object> <>3__originalInstructions; private List<object> <newInstructions>5__2; private int <index>5__3; private List<object>.Enumerator <>7__wrap3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ConvertToOurInstructions>d__7(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <newInstructions>5__2 = null; <>7__wrap3 = default(List<object>.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <newInstructions>5__2 = instructions.Cast<object>().ToList(); <index>5__3 = -1; <>7__wrap3 = <newInstructions>5__2.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap3.MoveNext()) { object current = <>7__wrap3.Current; <index>5__3++; object root = AccessTools.MakeDeepCopy(current, codeInstructionType); if (unassignedValues.TryGetValue(current, out var value)) { bool flag = ShouldAddExceptionInfo(current, <index>5__3, originalInstructions, <newInstructions>5__2, unassignedValues); Traverse traverse = Traverse.Create(root); foreach (KeyValuePair<string, object> item in value) { if (flag || item.Key != "blocks") { traverse.Field(item.Key).SetValue(item.Value); } } } <>2__current = root; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap3 = default(List<object>.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<object> IEnumerable<object>.GetEnumerator() { <ConvertToOurInstructions>d__7 <ConvertToOurInstructions>d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; <ConvertToOurInstructions>d__ = this; } else { <ConvertToOurInstructions>d__ = new <ConvertToOurInstructions>d__7(0); } <ConvertToOurInstructions>d__.instructions = <>3__instructions; <ConvertToOurInstructions>d__.codeInstructionType = <>3__codeInstructionType; <ConvertToOurInstructions>d__.originalInstructions = <>3__originalInstructions; <ConvertToOurInstructions>d__.unassignedValues = <>3__unassignedValues; return <ConvertToOurInstructions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<object>)this).GetEnumerator(); } } private readonly IEnumerable<CodeInstruction> codeInstructions; private readonly List<MethodInfo> transpilers = new List<MethodInfo>(); private static readonly Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> allJumpCodes = new Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> { { System.Reflection.Emit.OpCodes.Beq_S, System.Reflection.Emit.OpCodes.Beq }, { System.Reflection.Emit.OpCodes.Bge_S, System.Reflection.Emit.OpCodes.Bge }, { System.Reflection.Emit.OpCodes.Bge_Un_S, System.Reflection.Emit.OpCodes.Bge_Un }, { System.Reflection.Emit.OpCodes.Bgt_S, System.Reflection.Emit.OpCodes.Bgt }, { System.Reflection.Emit.OpCodes.Bgt_Un_S, System.Reflection.Emit.OpCodes.Bgt_Un }, { System.Reflection.Emit.OpCodes.Ble_S, System.Reflection.Emit.OpCodes.Ble }, { System.Reflection.Emit.OpCodes.Ble_Un_S, System.Reflection.Emit.OpCodes.Ble_Un }, { System.Reflection.Emit.OpCodes.Blt_S, System.Reflection.Emit.OpCodes.Blt }, { System.Reflection.Emit.OpCodes.Blt_Un_S, System.Reflection.Emit.OpCodes.Blt_Un }, { System.Reflection.Emit.OpCodes.Bne_Un_S, System.Reflection.Emit.OpCodes.Bne_Un }, { System.Reflection.Emit.OpCodes.Brfalse_S, System.Reflection.Emit.OpCodes.Brfalse }, { System.Reflection.Emit.OpCodes.Brtrue_S, System.Reflection.Emit.OpCodes.Brtrue }, { System.Reflection.Emit.OpCodes.Br_S, System.Reflection.Emit.OpCodes.Br }, { System.Reflection.Emit.OpCodes.Leave_S, System.Reflection.Emit.OpCodes.Leave } }; internal CodeTranspiler(List<ILInstruction> ilInstructions) { codeInstructions = ilInstructions.Select((ILInstruction ilInstruction) => ilInstruction.GetCodeInstruction()).ToList().AsEnumerable(); } internal void Add(MethodInfo transpiler) { transpilers.Add(transpiler); } internal static object ConvertInstruction(Type type, object instruction, out Dictionary<string, object> unassigned) { Dictionary<string, object> nonExisting = new Dictionary<string, object>(); object result = AccessTools.MakeDeepCopy(instruction, type, delegate(string namePath, Traverse trvSrc, Traverse trvDest) { object value = trvSrc.GetValue(); if (!trvDest.FieldExists()) { nonExisting[namePath] = value; return null; } return (namePath == "opcode") ? ((object)ReplaceShortJumps((System.Reflection.Emit.OpCode)value)) : value; }); unassigned = nonExisting; return result; } internal static bool ShouldAddExceptionInfo(object op, int opIndex, List<object> originalInstructions, List<object> newInstructions, Dictionary<object, Dictionary<string, object>> unassignedValues) { int num = originalInstructions.IndexOf(op); if (num == -1) { return false; } if (!unassignedValues.TryGetValue(op, out var unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out var blocksObject)) { return false; } List<ExceptionBlock> blocks = blocksObject as List<ExceptionBlock>; int num2 = newInstructions.Count((object instr) => instr == op); if (num2 <= 1) { return true; } ExceptionBlock exceptionBlock = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType != ExceptionBlockType.EndExceptionBlock); ExceptionBlock exceptionBlock2 = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType == ExceptionBlockType.EndExceptionBlock); if (exceptionBlock != null && exceptionBlock2 == null) { object obj = originalInstructions.Skip(num + 1).FirstOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List<ExceptionBlock>; return blocks.Count > 0; }); if (obj != null) { int num3 = num + 1; int num4 = num3 + originalInstructions.Skip(num3).ToList().IndexOf(obj) - 1; IEnumerable<object> first = originalInstructions.GetRange(num3, num4 - num3).Intersect(newInstructions); obj = newInstructions.Skip(opIndex + 1).FirstOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List<ExceptionBlock>; return blocks.Count > 0; }); if (obj != null) { num3 = opIndex + 1; num4 = num3 + newInstructions.Skip(opIndex + 1).ToList().IndexOf(obj) - 1; List<object> range = newInstructions.GetRange(num3, num4 - num3); List<object> list = first.Except(range).ToList(); return list.Count == 0; } } } if (exceptionBlock == null && exceptionBlock2 != null) { object obj2 = originalInstructions.GetRange(0, num).LastOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List<ExceptionBlock>; return blocks.Count > 0; }); if (obj2 != null) { int num5 = originalInstructions.GetRange(0, num).LastIndexOf(obj2); int num6 = num; IEnumerable<object> first2 = originalInstructions.GetRange(num5, num6 - num5).Intersect(newInstructions); obj2 = newInstructions.GetRange(0, opIndex).LastOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List<ExceptionBlock>; return blocks.Count > 0; }); if (obj2 != null) { num5 = newInstructions.GetRange(0, opIndex).LastIndexOf(obj2); num6 = opIndex; List<object> range2 = newInstructions.GetRange(num5, num6 - num5); IEnumerable<object> source = first2.Except(range2); return !source.Any(); } } } return true; } internal static IEnumerable ConvertInstructionsAndUnassignedValues(Type type, IEnumerable enumerable, out Dictionary<object, Dictionary<string, object>> unassignedValues) { Assembly assembly = type.GetGenericTypeDefinition().Assembly; Type type2 = assembly.GetType(typeof(List<>).FullName); Type type3 = type.GetGenericArguments()[0]; Type type4 = type2.MakeGenericType(type3); Type type5 = assembly.GetType(type4.FullName); object obj = Activator.CreateInstance(type5); MethodInfo method = obj.GetType().GetMethod("Add"); unassignedValues = new Dictionary<object, Dictionary<string, object>>(); foreach (object item in enumerable) { Dictionary<string, object> unassigned; object obj2 = ConvertInstruction(type3, item, out unassigned); unassignedValues.Add(obj2, unassigned); method.Invoke(obj, new object[1] { obj2 }); } return obj as IEnumerable; } internal static IEnumerable ConvertToOurInstructions(IEnumerable instructions, Type codeInstructionType, List<object> originalInstructions, Dictionary<object, Dictionary<string, object>> unassignedValues) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ConvertToOurInstructions>d__7(-2) { <>3__instructions = instructions, <>3__codeInstructionType = codeInstructionType, <>3__originalInstructions = originalInstructions, <>3__unassignedValues = unassignedValues }; } private static bool IsCodeInstructionsParameter(Type type) { if (type.IsGenericType) { return type.GetGenericTypeDefinition().Name.StartsWith("IEnumerable", StringComparison.Ordinal); } return false; } internal static IEnumerable ConvertToGeneralInstructions(MethodInfo transpiler, IEnumerable enumerable, out Dictionary<object, Dictionary<string, object>> unassignedValues) { Type type = (from p in transpiler.GetParameters() select p.ParameterType).FirstOrDefault(IsCodeInstructionsParameter); if ((object)type == typeof(IEnumerable<CodeInstruction>)) { unassignedValues = null; object obj = enumerable as IList<CodeInstruction>; if (obj == null) { List<CodeInstruction> list = new List<CodeInstruction>(); list.AddRange((enumerable as IEnumerable<CodeInstruction>) ?? enumerable.Cast<CodeInstruction>()); obj = list; } return (IEnumerable)obj; } return ConvertInstructionsAndUnassignedValues(type, enumerable, out unassignedValues); } internal static List<object> GetTranspilerCallParameters(ILGenerator generator, MethodInfo transpiler, MethodBase method, IEnumerable instructions) { List<object> parameter = new List<object>(); (from param in transpiler.GetParameters() select param.ParameterType).Do(delegate(Type type) { if (type.IsAssignableFrom(typeof(ILGenerator))) { parameter.Add(generator); } else if (type.IsAssignableFrom(typeof(MethodBase))) { parameter.Add(method); } else if (IsCodeInstructionsParameter(type)) { parameter.Add(instructions); } }); return parameter; } internal List<CodeInstruction> GetResult(ILGenerator generator, MethodBase method) { IEnumerable instructions = codeInstructions; transpilers.ForEach(delegate(MethodInfo transpiler) { instructions = ConvertToGeneralInstructions(transpiler, instructions, out var unassignedValues); List<object> originalInstructions = null; if (unassignedValues != null) { originalInstructions = instructions.Cast<object>().ToList(); } List<object> transpilerCallParameters = GetTranspilerCallParameters(generator, transpiler, method, instructions); if (transpiler.Invoke(null, transpilerCallParameters.ToArray()) is IEnumerable enumerable) { instructions = enumerable; } if (unassignedValues != null) { instructions = ConvertToOurInstructions(instructions, typeof(CodeInstruction), originalInstructions, unassignedValues); } }); return (instructions as List<CodeInstruction>) ?? instructions.Cast<CodeInstruction>().ToList(); } private static System.Reflection.Emit.OpCode ReplaceShortJumps(System.Reflection.Emit.OpCode opcode) { foreach (KeyValuePair<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> allJumpCode in allJumpCodes) { if (opcode == allJumpCode.Key) { return allJumpCode.Value; } } return opcode; } } internal class LeaveTry { public override string ToString() { return "(autogenerated)"; } } internal class Emitter { private readonly CecilILGenerator il; private readonly Dictionary<int, CodeInstruction> instructions = new Dictionary<int, CodeInstruction>(); private readonly bool debug; internal Emitter(ILGenerator il, bool debug) { this.il = il.GetProxiedShim<CecilILGenerator>(); this.debug = debug; } internal Dictionary<int, CodeInstruction> GetInstructions() { return instructions; } internal void AddInstruction(System.Reflection.Emit.OpCode opcode, object operand) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, operand)); } internal int CurrentPos() { return il.ILOffset; } internal static string CodePos(int offset) { return $"IL_{offset:X4}: "; } internal string CodePos() { return CodePos(CurrentPos()); } internal void LogComment(string comment) { if (debug) { string str = $"{CodePos()}// {comment}"; FileLog.LogBuffered(str); } } internal void LogIL(System.Reflection.Emit.OpCode opcode) { if (debug) { FileLog.LogBuffered($"{CodePos()}{opcode}"); } } internal void LogIL(System.Reflection.Emit.OpCode opcode, object arg, string extra = null) { if (debug) { string text = FormatArgument(arg, extra); string text2 = ((text.Length > 0) ? " " : ""); string text3 = opcode.ToString(); if (opcode.FlowControl == System.Reflection.Emit.FlowControl.Branch || opcode.FlowControl == System.Reflection.Emit.FlowControl.Cond_Branch) { text3 += " =>"; } text3 = text3.PadRight(10); FileLog.LogBuffered($"{CodePos()}{text3}{text2}{text}"); } } internal void LogAllLocalVariables() { if (debug) { il.IL.Body.Variables.Do(delegate(VariableDefinition v) { string str = string.Format("{0}Local var {1}: {2}{3}", CodePos(0), v.Index, v.VariableType.FullName, v.IsPinned ? "(pinned)" : ""); FileLog.LogBuffered(str); }); } } internal static string FormatArgument(object argument, string extra = null) { if (argument == null) { return "NULL"; } Type type = argument.GetType(); if (argument is MethodBase member) { return member.FullDescription() + ((extra != null) ? (" " + extra) : ""); } if (argument is FieldInfo fieldInfo) { return $"{fieldInfo.FieldType.FullDescription()} {fieldInfo.DeclaringType.FullDescription()}::{fieldInfo.Name}"; } if ((object)type == typeof(Label)) { return $"Label{((Label)argument).GetHashCode()}"; } if ((object)type == typeof(Label[])) { return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray()); } if ((object)type == typeof(LocalBuilder)) { return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})"; } if ((object)type == typeof(string)) { return argument.ToString().ToLiteral(); } return argument.ToString().Trim(); } internal void MarkLabel(Label label) { if (debug) { FileLog.LogBuffered(CodePos() + FormatArgument(label)); } il.MarkLabel(label); } internal void MarkBlockBefore(ExceptionBlock block, out Label? label) { label = null; switch (block.blockType) { case ExceptionBlockType.BeginExceptionBlock: if (debug) { FileLog.LogBuffered(".try"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } label = il.BeginExceptionBlock(); break; case ExceptionBlockType.BeginCatchBlock: if (debug) { LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered($".catch {block.catchType}"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginCatchBlock(block.catchType); break; case ExceptionBlockType.BeginExceptFilterBlock: if (debug) { LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".filter"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginExceptFilterBlock(); break; case ExceptionBlockType.BeginFaultBlock: if (debug) { LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".fault"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFaultBlock(); break; case ExceptionBlockType.BeginFinallyBlock: if (debug) { LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".finally"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFinallyBlock(); break; } } internal void MarkBlockAfter(ExceptionBlock block) { ExceptionBlockType blockType = block.blockType; if (blockType == ExceptionBlockType.EndExceptionBlock) { if (debug) { LogIL(System.Reflection.Emit.OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end handler"); } il.EndExceptionBlock(); } } internal void Emit(System.Reflection.Emit.OpCode opcode) { instructions.Add(CurrentPos(), new CodeInstruction(opcode)); LogIL(opcode); il.Emit(opcode); } internal void Emit(System.Reflection.Emit.OpCode opcode, LocalBuilder local) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, local)); LogIL(opcode, local); il.Emit(opcode, local); } internal void Emit(System.Reflection.Emit.OpCode opcode, FieldInfo field) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, field)); LogIL(opcode, field); il.Emit(opcode, field); } internal void Emit(System.Reflection.Emit.OpCode opcode, Label[] labels) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, labels)); LogIL(opcode, labels); il.Emit(opcode, labels); } internal void Emit(System.Reflection.Emit.OpCode opcode, Label label) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, label)); LogIL(opcode, label); il.Emit(opcode, label); } internal void Emit(System.Reflection.Emit.OpCode opcode, string str) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, str)); LogIL(opcode, str); il.Emit(opcode, str); } internal void Emit(System.Reflection.Emit.OpCode opcode, float arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, byte arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, sbyte arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, double arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, int arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, MethodInfo meth) { if (opcode.Equals(System.Reflection.Emit.OpCodes.Call) || opcode.Equals(System.Reflection.Emit.OpCodes.Callvirt) || opcode.Equals(System.Reflection.Emit.OpCodes.Newobj)) { EmitCall(opcode, meth, null); return; } instructions.Add(CurrentPos(), new CodeInstruction(opcode, meth)); LogIL(opcode, meth); il.Emit(opcode, meth); } internal void Emit(System.Reflection.Emit.OpCode opcode, short arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void Emit(System.Reflection.Emit.OpCode opcode, SignatureHelper signature) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, signature)); LogIL(opcode, signature); il.Emit(opcode, signature); } internal void Emit(System.Reflection.Emit.OpCode opcode, ConstructorInfo con) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, con)); LogIL(opcode, con); il.Emit(opcode, con); } internal void Emit(System.Reflection.Emit.OpCode opcode, Type cls) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, cls)); LogIL(opcode, cls); il.Emit(opcode, cls); } internal void Emit(System.Reflection.Emit.OpCode opcode, long arg) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, arg)); LogIL(opcode, arg); il.Emit(opcode, arg); } internal void EmitCall(System.Reflection.Emit.OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, methodInfo)); string extra = ((optionalParameterTypes != null && optionalParameterTypes.Length != 0) ? optionalParameterTypes.Description() : null); LogIL(opcode, methodInfo, extra); il.EmitCall(opcode, methodInfo, optionalParameterTypes); } internal void EmitCalli(System.Reflection.Emit.OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, unmanagedCallConv)); string extra = returnType.FullName + " " + parameterTypes.Description(); LogIL(opcode, unmanagedCallConv, extra); il.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes); } internal void EmitCalli(System.Reflection.Emit.OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, callingConvention)); string extra = returnType.FullName + " " + parameterTypes.Description() + " " + optionalParameterTypes.Description(); LogIL(opcode, callingConvention, extra); il.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes); } } internal static class HarmonySharedState { private const string name = "HarmonySharedState"; internal const int internalVersion = 102; private static readonly Dictionary<MethodBase, byte[]> state; private static readonly Dictionary<MethodInfo, MethodBase> originals; private static readonly Dictionary<long, MethodBase[]> originalsMono; private static readonly AccessTools.FieldRef<StackFrame, long> methodAddressRef; internal static readonly int actualVersion; static HarmonySharedState() { Type orCreateSharedStateType = GetOrCreateSharedStateType(); if (AccessTools.IsMonoRuntime) { FieldInfo fieldInfo = AccessTools.Field(typeof(StackFrame), "methodAddress"); if ((object)fieldInfo != null) { methodAddressRef = AccessTools.FieldRefAccess<StackFrame, long>(fieldInfo); } } FieldInfo field = orCreateSharedStateType.GetField("version"); if ((int)field.GetValue(null) == 0) { field.SetValue(null, 102); } actualVersion = (int)field.GetValue(null); FieldInfo field2 = orCreateSharedStateType.GetField("state"); if (field2.GetValue(null) == null) { field2.SetValue(null, new Dictionary<MethodBase, byte[]>()); } FieldInfo field3 = orCreateSharedStateType.GetField("originals"); if ((object)field3 != null && field3.GetValue(null) == null) { field3.SetValue(null, new Dictionary<MethodInfo, MethodBase>()); } FieldInfo field4 = orCreateSharedStateType.GetField("originalsMono"); if ((object)field4 != null && field4.GetValue(null) == null) { field4.SetValue(null, new Dictionary<long, MethodBase[]>()); } state = (Dictionary<MethodBase, byte[]>)field2.GetValue(null); originals = new Dictionary<MethodInfo, MethodBase>(); if ((object)field3 != null) { originals = (Dictionary<MethodInfo, MethodBase>)field3.GetValue(null); } originalsMono = new Dictionary<long, MethodBase[]>(); if ((object)field4 != null) { originalsMono = (Dictionary<long, MethodBase[]>)field4.GetValue(null); } } private static Type GetOrCreateSharedStateType() { Type type = Type.GetType("HarmonySharedState", throwOnError: false); if ((object)type != null) { return type; } using ModuleDefinition moduleDefinition = ModuleDefinition.CreateModule("HarmonySharedState", new ModuleParameters { Kind = ModuleKind.Dll, ReflectionImporterProvider = MMReflectionImporter.Provider }); Mono.Cecil.TypeAttributes attributes = Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed; TypeDefinition typeDefinition = new TypeDefinition("", "HarmonySharedState", attributes) { BaseType = moduleDefinition.TypeSystem.Object }; moduleDefinition.Types.Add(typeDefinition); typeDefinition.Fields.Add(new FieldDefinition("state", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<MethodBase, byte[]>)))); typeDefinition.Fields.Add(new FieldDefinition("originals", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<MethodInfo, MethodBase>)))); typeDefinition.Fields.Add(new FieldDefinition("originalsMono", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(Dictionary<long, MethodBase[]>)))); typeDefinition.Fields.Add(new FieldDefinition("version", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, moduleDefinition.ImportReference(typeof(int)))); return ReflectionHelper.Load(moduleDefinition).GetType("HarmonySharedState"); } internal static PatchInfo GetPatchInfo(MethodBase method) { byte[] valueSafe; lock (state) { valueSafe = state.GetValueSafe(method); } if (valueSafe == null) { return null; } return PatchInfoSerialization.Deserialize(valueSafe); } internal static IEnumerable<MethodBase> GetPatchedMethods() { lock (state) { return state.Keys.ToArray(); } } internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo) { byte[] value = patchInfo.Serialize(); lock (state) { state[original] = value; } lock (originals) { originals[replacement.Identifiable()] = original; } if (AccessTools.IsMonoRuntime) { long key = (long)replacement.MethodHandle.GetFunctionPointer(); lock (originalsMono) { originalsMono[key] = new MethodBase[2] { original, replacement }; } } } internal static MethodBase GetRealMethod(MethodInfo method, bool useReplacement) { MethodInfo key = method.Identifiable(); lock (originals) { if (originals.TryGetValue(key, out var value)) { return value; } } if (AccessTools.IsMonoRuntime) { long key2 = (long)method.MethodHandle.GetFunctionPointer(); lock (originalsMono) { if (originalsMono.TryGetValue(key2, out var value2)) { return useReplacement ? value2[1] : value2[0]; } } } return method; } internal static MethodBase GetStackFrameMethod(StackFrame frame, bool useReplacement) { if (frame.GetMethod() is MethodInfo method) { return GetRealMethod(method, useReplacement); } if (methodAddressRef != null) { long key = methodAddressRef(frame); lock (originalsMono) { if (originalsMono.TryGetValue(key, out var value)) { return useReplacement ? value[1] : value[0]; } } } return null; } } internal class ILInstruction { internal int offset; internal System.Reflection.Emit.OpCode opcode; internal object operand; internal object argument; internal List<Label> labels = new List<Label>(); internal List<ExceptionBlock> blocks = new List<ExceptionBlock>(); internal ILInstruction(System.Reflection.Emit.OpCode opcode, object operand = null) { this.opcode = opcode; this.operand = operand; argument = operand; } internal CodeInstruction GetCodeInstruction() { CodeInstruction codeInstruction = new CodeInstruction(opcode, argument); if (opcode.OperandType == System.Reflection.Emit.OperandType.InlineNone) { codeInstruction.operand = null; } codeInstruction.labels = labels; codeInstruction.blocks = blocks; return codeInstruction; } internal int GetSize() { int num = opcode.Size; switch (opcode.OperandType) { case System.Reflection.Emit.OperandType.InlineSwitch: num += (1 + ((Array)operand).Length) * 4; break; case System.Reflection.Emit.OperandType.InlineI8: case System.Reflection.Emit.OperandType.InlineR: num += 8; break; case System.Reflection.Emit.OperandType.InlineBrTarget: case System.Reflection.Emit.OperandType.InlineField: case System.Reflection.Emit.OperandType.InlineI: case System.Reflection.Emit.OperandType.InlineMethod: case System.Reflection.Emit.OperandType.InlineSig: case System.Reflection.Emit.OperandType.InlineString: case System.Reflection.Emit.OperandType.InlineTok: case System.Reflection.Emit.OperandType.InlineType: case System.Reflection.Emit.OperandType.ShortInlineR: num += 4; break; case System.Reflection.Emit.OperandType.InlineVar: num += 2; break; case System.Reflection.Emit.OperandType.ShortInlineBrTarget: case System.Reflection.Emit.OperandType.ShortInlineI: case System.Reflection.Emit.OperandType.ShortInlineVar: num++; break; } return num; } public override string ToString() { string str = ""; AppendLabel(ref str, this); str = str + ": " + opcode.Name; if (operand == null) { return str; } str += " "; switch (opcode.OperandType) { case System.Reflection.Emit.OperandType.InlineBrTarget: case System.Reflection.Emit.OperandType.ShortInlineBrTarget: AppendLabel(ref str, operand); break; case System.Reflection.Emit.OperandType.InlineSwitch: { ILInstruction[] array = (ILInstruction[])operand; for (int i = 0; i < array.Length; i++) { if (i > 0) { str += ","; } AppendLabel(ref str, array[i]); } break; } case System.Reflection.Emit.OperandType.InlineString: str += $"\"{operand}\""; break; default: str += operand; break; } return str; } private static void AppendLabel(ref string str, object argument) { ILInstruction iLInstruction = argument as ILInstruction; str += $"IL_{iLInstruction?.offset.ToString("X4") ?? argument}"; } } internal static class InlineSignatureParser { internal static InlineSignature ImportCallSite(Module moduleFrom, byte[] data) { InlineSignature inlineSignature = new InlineSignature(); BinaryReader reader; using (MemoryStream input = new MemoryStream(data, writable: false)) { reader = new BinaryReader(input); try { ReadMethodSignature(inlineSignature); return inlineSignature; } finally { if (reader != null) { ((IDisposable)reader).Dispose(); } } } Type GetTypeDefOrRef() { uint num3 = ReadCompressedUInt32(); uint num4 = num3 >> 2; return moduleFrom.ResolveType((num3 & 3) switch { 0u => (int)(0x2000000 | num4), 1u => (int)(0x1000000 | num4), 2u => (int)(0x1B000000 | num4), _ => 0, }); } int ReadCompressedInt32() { byte b = reader.ReadByte(); reader.BaseStream.Seek(-1L, SeekOrigin.Current); int num = (int)ReadCompressedUInt32(); int num2 = num >> 1; if ((num & 1) == 0) { return num2; } switch (b & 0xC0) { case 0: case 64: return num2 - 64; case 128: return num2 - 8192; default: return num2 - 268435456; } } uint ReadCompressedUInt32() { byte b2 = reader.ReadByte(); if ((b2 & 0x80) == 0) { return b2; } if ((b2 & 0x40) == 0) { return (uint)(((b2 & -129) << 8) | reader.ReadByte()); } return (uint)(((b2 & -193) << 24) | (reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte()); } void ReadMethodSignature(InlineSignature method) { byte b3 = reader.ReadByte(); if ((b3 & 0x20u) != 0) { method.HasThis = true; b3 = (byte)(b3 & 0xFFFFFFDFu); } if ((b3 & 0x40u) != 0) { method.ExplicitThis = true; b3 = (byte)(b3 & 0xFFFFFFBFu); } method.CallingConvention = (CallingConvention)(b3 + 1); if ((b3 & 0x10u) != 0) { ReadCompressedUInt32(); } uint num7 = ReadCompressedUInt32(); method.ReturnType = ReadTypeSignature(); for (int k = 0; k < num7; k++) { method.Parameters.Add(ReadTypeSignature()); } } object ReadTypeSignature() { MetadataType metadataType = (MetadataType)reader.ReadByte(); switch (metadataType) { case MetadataType.ValueType: case MetadataType.Class: return GetTypeDefOrRef(); case MetadataType.Pointer: return ((Type)ReadTypeSignature()).MakePointerType(); case MetadataType.FunctionPointer: { InlineSignature inlineSignature2 = new InlineSignature(); ReadMethodSignature(inlineSignature2); return inlineSignature2; } case MetadataType.ByReference: return ((Type)ReadTypeSignature()).MakePointerType(); case (MetadataType)29: return ((Type)ReadTypeSignature()).MakeArrayType(); case MetadataType.Array: { Type type = (Type)ReadTypeSignature(); uint rank = ReadCompressedUInt32(); uint num5 = ReadCompressedUInt32(); for (int i = 0; i < num5; i++) { ReadCompressedUInt32(); } uint num6 = ReadCompressedUInt32(); for (int j = 0; j < num6; j++) { ReadCompressedInt32(); } return type.MakeArrayType((int)rank); } case MetadataType.OptionalModifier: return new InlineSignature.ModifierType { IsOptional = true, Modifier = GetTypeDefOrRef(), Type = ReadTypeSignature() }; case MetadataType.RequiredModifier: return new InlineSignature.ModifierType { IsOptional = false, Modifier = GetTypeDefOrRef(), Type = ReadTypeSignature() }; case MetadataType.Var: case MetadataType.MVar: throw new NotSupportedException($"Unsupported generic callsite element: {metadataType}"); case MetadataType.GenericInstance: { reader.ReadByte(); Type typeDefOrRef = GetTypeDefOrRef(); int count = (int)ReadCompressedUInt32(); return typeDefOrRef.MakeGenericType((from _ in Enumerable.Range(0, count) select (Type)ReadTypeSignature()).ToArray()); } case MetadataType.Object: return typeof(object); case MetadataType.Void: return typeof(void); case MetadataType.TypedByReference: return typeof(TypedReference); case MetadataType.IntPtr: return typeof(IntPtr); case MetadataType.UIntPtr: return typeof(UIntPtr); case MetadataType.Boolean: return typeof(bool); case MetadataType.Char: return typeof(char); case MetadataType.SByte: return typeof(sbyte); case MetadataType.Byte: return typeof(byte); case MetadataType.Int16: return typeof(short); case MetadataType.UInt16: return typeof(ushort); case MetadataType.Int32: return typeof(int); case MetadataType.UInt32: return typeof(uint); case MetadataType.Int64: return typeof(long); case MetadataType.UInt64: return typeof(ulong); case MetadataType.Single: return typeof(float); case MetadataType.Double: return typeof(double); case MetadataType.String: return typeof(string); default: throw new NotSupportedException($"Unsupported callsite element: {metadataType}"); } } } } internal class MethodCopier { private readonly MethodBodyReader reader; private readonly List<MethodInfo> transpilers = new List<MethodInfo>(); internal MethodCopier(MethodBase fromMethod, ILGenerator toILGenerator, LocalBuilder[] existingVariables = null) { if ((object)fromMethod == null) { throw new ArgumentNullException("fromMethod"); } reader = new MethodBodyReader(fromMethod, toILGenerator); reader.DeclareVariables(existingVariables); reader.GenerateInstructions(); } internal void SetDebugging(bool debug) { reader.SetDebugging(debug); } internal void AddTranspiler(MethodInfo transpiler) { transpilers.Add(transpiler); } internal List<CodeInstruction> Finalize(Emitter emitter, List<Label> endLabels, out bool hasReturnCode, out bool methodEndsInDeadCode) { return reader.FinalizeILCodes(emitter, transpilers, endLabels, out hasReturnCode, out methodEndsInDeadCode); } internal static List<CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers) { if (generator == null) { throw new ArgumentNullException("generator"); } if ((object)method == null) { throw new ArgumentNullException("method"); } LocalBuilder[] existingVariables = MethodPatcher.DeclareOriginalLocalVariables(generator, method); MethodCopier methodCopier = new MethodCopier(method, generator, existingVariables); Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo != null) { List<MethodInfo> sortedPatchMethods = PatchFunctions.GetSortedPatchMethods(method, patchInfo.Transpilers.ToArray(), debug: false); for (int i = 0; i < maxTranspilers && i < sortedPatchMethods.Count; i++) { methodCopier.AddTranspiler(sortedPatchMethods[i]); } } bool hasReturnCode; bool methodEndsInDeadCode; return methodCopier.Finalize(null, null, out hasReturnCode, out methodEndsInDeadCode); } } internal class MethodBodyReader { private class ThisParameter : ParameterInfo { internal ThisParameter(MethodBase method) { MemberImpl = method; ClassImpl = method.DeclaringType; NameImpl = "this"; PositionImpl = -1; } } private readonly ILGenerator generator; private readonly MethodBase method; private bool debug; private readonly Module module; private readonly Type[] typeArguments; private readonly Type[] methodArguments; private readonly ByteBuffer ilBytes; private readonly ParameterInfo this_parameter; private readonly ParameterInfo[] parameters; private readonly IList<ExceptionHandlingClause> exceptions; private readonly List<ILInstruction> ilInstructions; private readonly List<LocalVariableInfo> localVariables; private LocalBuilder[] variables; private static readonly Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> shortJumps; private static readonly System.Reflection.Emit.OpCode[] one_byte_opcodes; private static readonly System.Reflection.Emit.OpCode[] two_bytes_opcodes; internal static List<ILInstruction> GetInstructions(ILGenerator generator, MethodBase method) { if ((object)method == null) { throw new ArgumentNullException("method"); } MethodBodyReader methodBodyReader = new MethodBodyReader(method, generator); methodBodyReader.DeclareVariables(null); methodBodyReader.GenerateInstructions(); return methodBodyReader.ilInstructions; } internal MethodBodyReader(MethodBase method, ILGenerator generator) { this.generator = generator; this.method = method; module = method.Module; System.Reflection.MethodBody methodBody = method.GetMethodBody(); if ((methodBody?.GetILAsByteArray()?.Length).GetValueOrDefault() == 0) { ilBytes = new ByteBuffer(new byte[0]); ilInstructions = new List<ILInstruction>(); } else { byte[] iLAsByteArray = methodBody.GetILAsByteArray(); if (iLAsByteArray == null) { throw new ArgumentException("Can not get IL bytes of method " + method.FullDescription()); } ilBytes = new ByteBuffer(iLAsByteArray); ilInstructions = new List<ILInstruction>((iLAsByteArray.Length + 1) / 2); } Type declaringType = method.DeclaringType; if ((object)declaringType != null && declaringType.IsGenericType) { try { typeArguments = declaringType.GetGenericArguments(); } catch { typeArguments = null; } } if (method.IsGenericMethod) { try { methodArguments = method.GetGenericArguments(); } catch { methodArguments = null; } } if (!method.IsStatic) { this_parameter = new ThisParameter(method); } parameters = method.GetParameters(); localVariables = methodBody?.LocalVariables?.ToList() ?? new List<LocalVariableInfo>(); exceptions = methodBody?.ExceptionHandlingClauses ?? new List<ExceptionHandlingClause>(); } internal void SetDebugging(bool debug) { this.debug = debug; } internal void GenerateInstructions() { while (ilBytes.position < ilBytes.buffer.Length) { int position = ilBytes.position; ILInstruction iLInstruction = new ILInstruction(ReadOpCode()) { offset = position }; ReadOperand(iLInstruction); ilInstructions.Add(iLInstruction); } HandleNativeMethod(); ResolveBranches(); ParseExceptions(); } internal void HandleNativeMethod() { if (!(method is MethodInfo methodInfo)) { return; } DllImportAttribute dllImportAttribute = methodInfo.GetCustomAttributes(inherit: false).OfType<DllImportAttribute>().FirstOrDefault(); if (dllImportAttribute != null) { string assemblyName = (methodInfo.DeclaringType?.FullName ?? "").Replace(".", "_") + "_" + methodInfo.Name; AssemblyName assemblyName2 = new AssemblyName(assemblyName); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName2, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName2.Name); TypeBuilder typeBuilder = moduleBuilder.DefineType("NativeMethodHolder", System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.UnicodeClass); MethodBuilder methodBuilder = typeBuilder.DefinePInvokeMethod(methodInfo.Name, dllImportAttribute.Value, System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.PinvokeImpl, CallingConventions.Standard, methodInfo.ReturnType, (from x in methodInfo.GetParameters() select x.ParameterType).ToArray(), dllImportAttribute.CallingConvention, dllImportAttribute.CharSet); methodBuilder.SetImplementationFlags(methodBuilder.GetMethodImplementationFlags() | System.Reflection.MethodImplAttributes.PreserveSig); Type type = typeBuilder.CreateType(); MethodInfo operand = type.GetMethod(methodInfo.Name); int num = method.GetParameters().Length; for (int i = 0; i < num; i++) { ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Ldarg, i) { offset = 0 }); } ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Call, operand) { offset = num }); ilInstructions.Add(new ILInstruction(System.Reflection.Emit.OpCodes.Ret) { offset = num + 5 }); } } internal void DeclareVariables(LocalBuilder[] existingVariables) { if (generator == null) { return; } if (existingVariables != null) { variables = existingVariables; return; } variables = localVariables.Select((LocalVariableInfo lvi) => generator.DeclareLocal(lvi.LocalType, lvi.IsPinned)).ToArray(); } private void ResolveBranches() { foreach (ILInstruction ilInstruction in ilInstructions) { switch (ilInstruction.opcode.OperandType) { case System.Reflection.Emit.OperandType.InlineBrTarget: case System.Reflection.Emit.OperandType.ShortInlineBrTarget: ilInstruction.operand = GetInstruction((int)ilInstruction.operand, isEndOfInstruction: false); break; case System.Reflection.Emit.OperandType.InlineSwitch: { int[] array = (int[])ilInstruction.operand; ILInstruction[] array2 = new ILInstruction[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = GetInstruction(array[i], isEndOfInstruction: false); } ilInstruction.operand = array2; break; } } } } private void ParseExceptions() { foreach (ExceptionHandlingClause exception in exceptions) { int tryOffset = exception.TryOffset; int handlerOffset = exception.HandlerOffset; int offset = exception.HandlerOffset + exception.HandlerLength - 1; ILInstruction instruction = GetInstruction(tryOffset, isEndOfInstruction: false); instruction.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock)); ILInstruction instruction2 = GetInstruction(offset, isEndOfInstruction: true); instruction2.blocks.Add(new ExceptionBlock(ExceptionBlockType.EndExceptionBlock)); switch (exception.Flags) { case ExceptionHandlingClauseOptions.Filter: { ILInstruction instruction6 = GetInstruction(exception.FilterOffset, isEndOfInstruction: false); instruction6.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginExceptFilterBlock)); break; } case ExceptionHandlingClauseOptions.Finally: { ILInstruction instruction5 = GetInstruction(handlerOffset, isEndOfInstruction: false); instruction5.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginFinallyBlock)); break; } case ExceptionHandlingClauseOptions.Clause: { ILInstruction instruction4 = GetInstruction(handlerOffset, isEndOfInstruction: false); instruction4.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginCatchBlock, exception.CatchType)); break; } case ExceptionHandlingClauseOptions.Fault: { ILInstruction instruction3 = GetInstruction(handlerOffset, isEndOfInstruction: false); instruction3.blocks.Add(new ExceptionBlock(ExceptionBlockType.BeginFaultBlock)); break; } } } } private bool EndsInDeadCode(List<CodeInstruction> list) { int count = list.Count; if (count < 2 || list.Last().opcode != System.Reflection.Emit.OpCodes.Throw) { return false; } return list.GetRange(0, count - 1).All((CodeInstruction code) => code.opcode != System.Reflection.Emit.OpCodes.Ret); } internal List<CodeInstruction> FinalizeILCodes(Emitter emitter, List<MethodInfo> transpilers, List<Label> endLabels, out bool hasReturnCode, out bool methodEndsInDeadCode) { hasReturnCode = false; methodEndsInDeadCode = false; if (generator == null) { return null; } foreach (ILInstruction ilInstruction in ilInstructions) { switch (ilInstruction.opcode.OperandType) { case System.Reflection.Emit.OperandType.InlineSwitch: if (ilInstruction.operand is ILInstruction[] array) { List<Label> list = new List<Label>(); ILInstruction[] array2 = array; foreach (ILInstruction iLInstruction2 in array2) { Label item = generator.DefineLabel(); iLInstruction2.labels.Add(item); list.Add(item); } ilInstruction.argument = list.ToArray(); } break; case System.Reflection.Emit.OperandType.InlineBrTarget: case System.Reflection.Emit.OperandType.ShortInlineBrTarget: if (ilInstruction.operand is ILInstruction iLInstruction) { Label label2 = generator.DefineLabel(); iLInstruction.labels.Add(label2); ilInstruction.argument = label2; } break; } } CodeTranspiler codeTranspiler = new CodeTranspiler(ilInstructions); transpilers.Do(codeTranspiler.Add); List<CodeInstruction> result = codeTranspiler.GetResult(generator, method); if (emitter == null) { return result; } emitter.LogComment("start original"); if (debug) { List<string> buffer = FileLog.GetBuffer(clear: true); emitter.LogAllLocalVariables(); FileLog.LogBuffered(buffer); } hasReturnCode = result.Any((CodeInstruction code) => code.opcode == System.Reflection.Emit.OpCodes.Ret); methodEndsInDeadCode = EndsInDeadCode(result); while (true) { CodeInstruction codeInstruction2 = result.LastOrDefault(); if (codeInstruction2 == null || codeInstruction2.opcode != System.Reflection.Emit.OpCodes.Ret) { break; } endLabels.AddRange(codeInstruction2.labels); result.RemoveAt(result.Count - 1); } result.Do(delegate(CodeInstruction codeInstruction) { codeInstruction.labels.Do(delegate(Label label) { emitter.MarkLabel(label); }); codeInstruction.blocks.Do(delegate(ExceptionBlock block) { emitter.MarkBlockBefore(block, out var _); }); System.Reflection.Emit.OpCode opCode = codeInstruction.opcode; object obj = codeInstruction.operand; if (opCode == System.Reflection.Emit.OpCodes.Ret) { Label label3 = generator.DefineLabel(); opCode = System.Reflection.Emit.OpCodes.Br; obj = label3; endLabels.Add(label3); } if (shortJumps.TryGetValue(opCode, out var value)) { opCode = value; } switch (opCode.OperandType) { case System.Reflection.Emit.OperandType.InlineNone: emitter.Emit(opCode); break; case System.Reflection.Emit.OperandType.InlineSig: { CecilILGenerator proxiedShim = generator.GetProxiedShim<CecilILGenerator>(); if (proxiedShim == null) { throw new NotSupportedException(); } if (obj == null) { throw new Exception($"Wrong null argument: {codeInstruction}"); } if (!(obj is ICallSiteGenerator)) { throw new Exception($"Wrong Emit argument type {obj.GetType()} in {codeInstruction}"); } emitter.AddInstruction(opCode, obj); emitter.LogIL(opCode, obj); proxiedShim.Emit(opCode, (ICallSiteGenerator)obj); break; } default: if (obj == null) { throw new Exception($"Wrong null argument: {codeInstruction}"); } emitter.AddInstruction(opCode, obj); emitter.LogIL(opCode, obj); generator.DynEmit(opCode, obj); break; } codeInstruction.blocks.Do(delegate(ExceptionBlock block) { emitter.MarkBlockAfter(block); }); }); emitter.LogComment("end original" + (methodEndsInDeadCode ? " (has dead code end)" : "")); return result; } private static void GetMemberInfoValue(MemberInfo info, out object result) { result = null; switch (info.MemberType) { case MemberTypes.Constructor: result = (ConstructorInfo)info; break; case MemberTypes.Event: result = (EventInfo)info; break; case MemberTypes.Field: result = (FieldInfo)info; break; case MemberTypes.Method: result = (MethodInfo)info; break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: result = (Type)info; break; case MemberTypes.Property: result = (PropertyInfo)info; break; } } private void ReadOperand(ILInstruction instruction) { switch (instruction.opcode.OperandType) { case System.Reflection.Emit.OperandType.InlineNone: instruction.argument = null; break; case System.Reflection.Emit.OperandType.InlineSwitch: { int num6 = ilBytes.ReadInt32(); int num7 = ilBytes.position + 4 * num6; int[] array3 = new int[num6]; for (int i = 0; i < num6; i++) { array3[i] = ilBytes.ReadInt32() + num7; } instruction.operand = array3; break; } case System.Reflection.Emit.OperandType.ShortInlineBrTarget: { sbyte b4 = (sbyte)ilBytes.ReadByte(); instruction.operand = b4 + ilBytes.position; break; } case System.Reflection.Emit.OperandType.InlineBrTarget: { int num8 = ilBytes.ReadInt32(); instruction.operand = num8 + ilBytes.position; break; } case System.Reflection.Emit.OperandType.ShortInlineI: if (instruction.opcode == System.Reflection.Emit.OpCodes.Ldc_I4_S) { sbyte b = (sbyte)ilBytes.ReadByte(); instruction.operand = b; instruction.argument = (sbyte)instruction.operand; } else { byte b2 = ilBytes.ReadByte(); instruction.operand = b2; instruction.argument = (byte)instruction.operand; } break; case System.Reflection.Emit.OperandType.InlineI: { int num5 = ilBytes.ReadInt32(); instruction.operand = num5; instruction.argument = (int)instruction.operand; break; } case System.Reflection.Emit.OperandType.ShortInlineR: { float num4 = ilBytes.ReadSingle(); instruction.operand = num4; instruction.argument = (float)instruction.operand; break; } case System.Reflection.Emit.OperandType.InlineR: { double num3 = ilBytes.ReadDouble(); instruction.operand = num3; instruction.argument = (double)instruction.operand; break; } case System.Reflection.Emit.OperandType.InlineI8: { long num2 = ilBytes.ReadInt64(); instruction.operand = num2; instruction.argument = (long)instruction.operand; break; } case System.Reflection.Emit.OperandType.InlineSig: { int metadataToken3 = ilBytes.ReadInt32(); byte[] data = module.ResolveSignature(metadataToken3); instruction.argument = (instruction.operand = InlineSignatureParser.ImportCallSite(module, data)); break; } case System.Reflection.Emit.OperandType.InlineString: { int metadataToken6 = ilBytes.ReadInt32(); instruction.operand = module.ResolveString(metadataToken6); instruction.argument = (string)instruction.operand; break; } case System.Reflection.Emit.OperandType.InlineTok: { int metadataToken5 = ilBytes.ReadInt32(); instruction.operand = module.ResolveMember(metadataToken5, typeArguments, methodArguments); ((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto(); GetMemberInfoValue((MemberInfo)instruction.operand, out instruction.argument); break; } case System.Reflection.Emit.OperandType.InlineType: { int metadataToken4 = ilBytes.ReadInt32(); instruction.operand = module.ResolveType(metadataToken4, typeArguments, methodArguments); ((Type)instruction.operand).FixReflectionCacheAuto(); instruction.argument = (Type)instruction.operand; break; } case System.Reflection.Emit.OperandType.InlineMethod: { int metadataToken2 = ilBytes.ReadInt32(); instruction.operand = module.ResolveMethod(metadataToken2, typeArguments, methodArguments); ((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto(); if (instruction.operand is ConstructorInfo) { instruction.argument = (ConstructorInfo)instruction.operand; } else { instruction.argument = (MethodInfo)instruction.operand; } break; } case System.Reflection.Emit.OperandType.InlineField: { int metadataToken = ilBytes.ReadInt32(); instruction.operand = module.ResolveField(metadataToken, typeArguments, methodArguments); ((MemberInfo)instruction.operand).DeclaringType?.FixReflectionCacheAuto(); instruction.argument = (FieldInfo)instruction.operand; break; } case System.Reflection.Emit.OperandType.ShortInlineVar: { byte b3 = ilBytes.ReadByte(); if (TargetsLocalVariable(instruction.opcode)) { LocalVariableInfo localVariable2 = GetLocalVariable(b3); if (localVariable2 == null) { instruction.argument = b3; break; } instruction.operand = localVariable2; LocalBuilder[] array2 = variables; instruction.argument = ((array2 != null) ? array2[localVariable2.LocalIndex] : null) ?? localVariable2; } else { instruction.operand = GetParameter(b3); instruction.argument = b3; } break; } case System.Reflection.Emit.OperandType.InlineVar: { short num = ilBytes.ReadInt16(); if (TargetsLocalVariable(instruction.opcode)) { LocalVariableInfo localVariable = GetLocalVariable(num); if (localVariable == null) { instruction.argument = num; break; } instruction.operand = localVariable; LocalBuilder[] array = variables; instruction.argument = ((array != null) ? array[localVariable.LocalIndex] : null) ?? localVariable; } else { instruction.operand = GetParameter(num); instruction.argument = num; } break; } default: throw new NotSupportedException(); } } private ILInstruction GetInstruction(int offset, bool isEndOfInstruction) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset", offset, $"Instruction offset {offset} is less than 0"); } int num = ilInstructions.Count - 1; ILInstruction iLInstruction = ilInstructions[num]; if (offset > iLInstruction.offset + iLInstruction.GetSize() - 1) { throw new ArgumentOutOfRangeException("offset", offset, $"Instruction offset {offset} is outside valid range 0 - {iLInstruction.offset + iLInstruction.GetSize() - 1}"); } int num2 = 0; int num3 = num; while (num2 <= num3) { int num4 = num2 + (num3 - num2) / 2; iLInstruction = ilInstructions[num4]; if (isEndOfInstruction) { if (offset == iLInstruction.offset + iLInstruction.GetSize() - 1) { return iLInstruction; } } else if (offset == iLInstruction.offset) { return iLInstruction; } if (offset < iLInstruction.offset) { num3 = num4 - 1; } else { num2 = num4 + 1; } } throw new Exception($"Cannot find instruction for {offset:X4}"); } private static bool TargetsLocalVariable(System.Reflection.Emit.OpCode opcode) { return opcode.Name.Contains("loc"); } private LocalVariableInfo GetLocalVariable(int index) { return localVariables?[index]; } private ParameterInfo GetParameter(int index) { if (index == 0) { return this_parameter; } return parameters[index - 1]; } private System.Reflection.Emit.OpCode ReadOpCode() { byte b = ilBytes.ReadByte(); if (b == 254) { return two_bytes_opcodes[ilBytes.ReadByte()]; } return one_byte_opcodes[b]; } [MethodImpl(MethodImplOptions.Synchronized)] static MethodBodyReader() { shortJumps = new Dictionary<System.Reflection.Emit.OpCode, System.Reflection.Emit.OpCode> { { System.Reflection.Emit.OpCodes.Leave_S, System.Reflection.Emit.OpCodes.Leave }, { System.Reflection.Emit.OpCodes.Brfalse_S, System.Reflection.Emit.OpCodes.Brfalse }, { System.Reflection.Emit.OpCodes.Brtrue_S, System.Reflection.Emit.OpCodes.Brtrue }, { System.Reflection.Emit.OpCodes.Beq_S, System.Reflection.Emit.OpCodes.Beq }, { System.Reflection.Emit.OpCodes.Bge_S, System.Reflection.Emit.OpCodes.Bge }, { System.Reflection.Emit.OpCodes.Bgt_S, System.Reflection.Emit.OpCodes.Bgt }, { System.Reflection.Emit.OpCodes.Ble_S, System.Reflection.Emit.OpCodes.Ble }, { System.Reflection.Emit.OpCodes.Blt_S, System.Reflection.Emit.OpCodes.Blt }, { System.Reflection.Emit.OpCodes.Bne_Un_S, System.Reflection.Emit.OpCodes.Bne_Un }, { System.Reflection.Emit.OpCodes.Bge_Un_S, System.Reflection.Emit.OpCodes.Bge_Un }, { System.Reflection.Emit.OpCodes.Bgt_Un_S, System.Reflection.Emit.OpCodes.Bgt_Un }, { System.Reflection.Emit.OpCodes.Ble_Un_S, System.Reflection.Emit.OpCodes.Ble_Un }, { System.Reflection.Emit.OpCodes.Br_S, System.Reflection.Emit.OpCodes.Br }, { System.Reflection.Emit.OpCodes.Blt_Un_S, System.Reflection.Emit.OpCodes.Blt_Un } }; one_byte_opcodes = new System.Reflection.Emit.OpCode[225]; two_bytes_opcodes = new System.Reflection.Emit.OpCode[31]; FieldInfo[] fields = typeof(System.Reflection.Emit.OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { System.Reflection.Emit.OpCode opCode = (System.Reflection.Emit.OpCode)fieldInfo.GetValue(null); if (opCode.OpCodeType != System.Reflection.Emit.OpCodeType.Nternal) { if (opCode.Size == 1) { one_byte_opcodes[opCode.Value] = opCode; } else { two_bytes_opcodes[opCode.Value & 0xFF] = opCode; } } } } } internal class MethodPatcher { private const string INSTANCE_PARAM = "__instance"; private const string ORIGINAL_METHOD_PARAM = "__originalMethod"; private const string ARGS_ARRAY_VAR = "__args"; private const string RESULT_VAR = "__result"; private const string RESULT_REF_VAR = "__resultRef"; private const string STATE_VAR = "__state"; private const string EXCEPTION_VAR = "__exception"; private const string RUN_ORIGINAL_VAR = "__runOriginal"; private const string PARAM_INDEX_PREFIX = "__"; private const string INSTANCE_FIELD_PREFIX = "___"; private readonly bool debug; private readonly MethodBase original; private readonly MethodBase source; private readonly List<MethodInfo> prefixes; private readonly List<MethodInfo> postfixes; private readonly List<MethodInfo> transpilers; private readonly List<MethodInfo> finalizers; private readonly int idx; private readonly Type returnType; private readonly DynamicMethodDefinition patch; private readonly ILGenerator il; private readonly Emitter emitter; private static readonly HashSet<Type> PrimitivesWithObjectTypeCode = new HashSet<Type> { typeof(IntPtr), typeof(UIntPtr), typeof(IntPtr), typeof(UIntPtr) }; private static readonly MethodInfo m_GetMethodFromHandle1 = typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[1] { typeof(RuntimeMethodHandle) }); private static readonly MethodInfo m_GetMethodFromHandle2 = typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[2] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }); internal MethodPatcher(MethodBase original, MethodBase source, List<MethodInfo> prefixes, List<MethodInfo> postfixes, List<MethodInfo> transpilers, List<MethodInfo> finalizers, bool debug) { if ((object)original == null) { throw new ArgumentNullException("original"); } this.debug = debug; this.original = original; this.source = source; this.prefixes = prefixes; this.postfixes = postfixes; this.transpilers = transpilers; this.finalizers = finalizers; if (debug) { FileLog.LogBuffered("### Patch: " + original.FullDescription()); FileLog.FlushBuffer(); } idx = prefixes.Count + postfixes.Count + finalizers.Count; returnType = AccessTools.GetReturnedType(original); patch = CreateDynamicMethod(original, $"_Patch{idx}", debug); if (patch == null) { throw new Exception("Could not create replacement method"); } il = patch.GetILGenerator(); emitter = new Emitter(il, debug); } internal static IEnumerable<(ParameterInfo info, string realName)> OriginalParameters(MethodInfo method) { IEnumerable<HarmonyArgument> baseArgs = method.GetArgumentAttributes(); if ((object)method.DeclaringType != null) { baseArgs = baseArgs.Union(method.DeclaringType.GetArgumentAttributes()); } return method.GetParameters().Select(delegate(ParameterInfo p) { HarmonyArgument argumentAttribute = p.GetArgumentAttribute(); return (argumentAttribute != null) ? (p, argumentAttribute.OriginalName ?? p.Name) : (p, baseArgs.GetRealName(p.Name, null) ?? p.Name); }); } internal static Dictionary<string, string> RealNames(MethodInfo method) { return OriginalParameters(method).ToDictionary(((ParameterInfo info, string realName) pair) => pair.info.Name, ((ParameterInfo info, string realName) pair) => pair.realName); } internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> finalInstructions) { LocalBuilder[] existingVariables = DeclareOriginalLocalVariables(il, source ?? original); Dictionary<string, LocalBuilder> privateVars = new Dictionary<string, LocalBuilder>(); List<MethodInfo> list = prefixes.Union(postfixes).Union(finalizers).ToList(); Dictionary<MethodInfo, HashSet<(ParameterInfo info, string realName)>> parameterNames = list.ToDictionary((MethodInfo fix) => fix, (MethodInfo fix) => new HashSet<(ParameterInfo, string)>(OriginalParameters(fix))); LocalBuilder localBuilder = null; if (idx > 0) { localBuilder = DeclareLocalVariable(returnType, isReturnValue: true); privateVars["__result"] = localBuilder; } if (list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__resultRef")) && returnType.IsByRef) { LocalBuilder localBuilder2 = il.DeclareLocal(typeof(RefResult<>).MakeGenericType(returnType.GetElementType())); emitter.Emit(System.Reflection.Emit.OpCodes.Ldnull); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder2); privateVars["__resultRef"] = localBuilder2; } LocalBuilder localBuilder3 = null; if (list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__args"))) { PrepareArgumentArray(); localBuilder3 = il.DeclareLocal(typeof(object[])); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder3); privateVars["__args"] = localBuilder3; } Label? label = null; LocalBuilder localBuilder4 = null; bool flag = prefixes.Any(PrefixAffectsOriginal); bool flag2 = list.Any((MethodInfo fix) => parameterNames[fix].Any(((ParameterInfo info, string realName) pair) => pair.realName == "__runOriginal")); if (flag || flag2) { localBuilder4 = DeclareLocalVariable(typeof(bool)); emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder4); if (flag) { label = il.DefineLabel(); } } list.ForEach(delegate(MethodInfo fix) { if ((object)fix.DeclaringType != null && !privateVars.ContainsKey(fix.DeclaringType.AssemblyQualifiedName)) { (from pair in parameterNames[fix] where pair.realName == "__state" select pair.info).Do(delegate(ParameterInfo patchParam) { LocalBuilder value = DeclareLocalVariable(patchParam.ParameterType); privateVars[fix.DeclaringType.AssemblyQualifiedName] = value; }); } }); LocalBuilder local = null; if (finalizers.Count > 0) { local = DeclareLocalVariable(typeof(bool)); privateVars["__exception"] = DeclareLocalVariable(typeof(Exception)); emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock), out var _); } AddPrefixes(privateVars, localBuilder4); if (label.HasValue) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder4); emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label.Value); } MethodCopier methodCopier = new MethodCopier(source ?? original, il, existingVariables); methodCopier.SetDebugging(debug); foreach (MethodInfo transpiler in transpilers) { methodCopier.AddTranspiler(transpiler); } methodCopier.AddTranspiler(PatchTools.m_GetExecutingAssemblyReplacementTranspiler); List<Label> list2 = new List<Label>(); methodCopier.Finalize(emitter, list2, out var hasReturnCode, out var methodEndsInDeadCode); foreach (Label item in list2) { emitter.MarkLabel(item); } if (localBuilder != null && hasReturnCode) { emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder); } if (label.HasValue) { emitter.MarkLabel(label.Value); } AddPostfixes(privateVars, localBuilder4, passthroughPatches: false); if (localBuilder != null && (hasReturnCode || (methodEndsInDeadCode && label.HasValue))) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder); } bool flag3 = AddPostfixes(privateVars, localBuilder4, passthroughPatches: true); bool flag4 = finalizers.Count > 0; if (flag4) { if (flag3) { emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder); } AddFinalizers(privateVars, localBuilder4, catchExceptions: false); emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, local); Label label3 = il.DefineLabel(); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]); emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label3); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]); emitter.Emit(System.Reflection.Emit.OpCodes.Throw); emitter.MarkLabel(label3); emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginCatchBlock), out var _); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, privateVars["__exception"]); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, local); Label label5 = il.DefineLabel(); emitter.Emit(System.Reflection.Emit.OpCodes.Brtrue, label5); bool flag5 = AddFinalizers(privateVars, localBuilder4, catchExceptions: true); emitter.MarkLabel(label5); Label label6 = il.DefineLabel(); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]); emitter.Emit(System.Reflection.Emit.OpCodes.Brfalse, label6); if (flag5) { emitter.Emit(System.Reflection.Emit.OpCodes.Rethrow); } else { emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, privateVars["__exception"]); emitter.Emit(System.Reflection.Emit.OpCodes.Throw); } emitter.MarkLabel(label6); emitter.MarkBlockAfter(new ExceptionBlock(ExceptionBlockType.EndExceptionBlock)); if (localBuilder != null) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldloc, localBuilder); } } if (!methodEndsInDeadCode || label.HasValue || flag4 || postfixes.Count > 0) { emitter.Emit(System.Reflection.Emit.OpCodes.Ret); } finalInstructions = emitter.GetInstructions(); if (debug) { FileLog.LogBuffered("DONE"); FileLog.LogBuffered(""); FileLog.FlushBuffer(); } return patch.Generate(); } internal static DynamicMethodDefinition CreateDynamicMethod(MethodBase original, string suffix, bool debug) { if ((object)original == null) { throw new ArgumentNullException("original"); } string text = (original.DeclaringType?.FullName ?? "GLOBALTYPE") + "." + original.Name + suffix; text = text.Replace("<>", ""); ParameterInfo[] parameters = original.GetParameters(); List<Type> list = new List<Type>(); list.AddRange(parameters.Types()); if (!original.IsStatic) { if (AccessTools.IsStruct(original.DeclaringType)) { list.Insert(0, original.DeclaringType.MakeByRefType()); } else { list.Insert(0, original.DeclaringType); } } Type returnedType = AccessTools.GetReturnedType(original); DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition(text, returnedType, list.ToArray()); int num = ((!original.IsStatic) ? 1 : 0); if (!original.IsStatic) { dynamicMethodDefinition.Definition.Parameters[0].Name = "this"; } for (int i = 0; i < parameters.Length; i++) { ParameterDefinition parameterDefinition = dynamicMethodDefinition.Definition.Parameters[i + num]; parameterDefinition.Attributes = (Mono.Cecil.ParameterAttributes)parameters[i].Attributes; parameterDefinition.Name = parameters[i].Name; } if (debug) { List<string> list2 = list.Select((Type p) => p.FullDescription()).ToList(); if (list.Count == dynamicMethodDefinition.Definition.Parameters.Count) { for (int j = 0; j < list.Count; j++) { List<string> list3 = list2; int index = j; list3[index] = list3[index] + " " + dynamicMethodDefinition.Definition.Parameters[j].Name; } } FileLog.Log($"### Replacement: static {returnedType.FullDescription()} {original.DeclaringType?.FullName ?? "GLOBALTYPE"}::{text}({list2.Join()})"); } return dynamicMethodDefinition; } internal static LocalBuilder[] DeclareOriginalLocalVariables(ILGenerator il, MethodBase member) { IList<LocalVariableInfo> list = member.GetMethodBody()?.LocalVariables; if (list == null) { return new LocalBuilder[0]; } return list.Select((LocalVariableInfo lvi) => il.DeclareLocal(lvi.LocalType, lvi.IsPinned)).ToArray(); } private LocalBuilder DeclareLocalVariable(Type type, bool isReturnValue = false) { if (type.IsByRef) { if (isReturnValue) { LocalBuilder localBuilder = il.DeclareLocal(type); emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1); emitter.Emit(System.Reflection.Emit.OpCodes.Newarr, type.GetElementType()); emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); emitter.Emit(System.Reflection.Emit.OpCodes.Ldelema, type.GetElementType()); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder); return localBuilder; } type = type.GetElementType(); } if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } if (AccessTools.IsClass(type)) { LocalBuilder localBuilder2 = il.DeclareLocal(type); emitter.Emit(System.Reflection.Emit.OpCodes.Ldnull); emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder2); return localBuilder2; } if (AccessTools.IsStruct(type)) { LocalBuilder localBuilder3 = il.DeclareLocal(type); emitter.Emit(System.Reflection.Emit.OpCodes.Ldloca, localBuilder3); emitter.Emit(System.Reflection.Emit.OpCodes.Initobj, type); return localBuilder3; } if (AccessTools.IsValue(type)) { LocalBuilder localBuilder4 = il.DeclareLocal(type); if ((object)type == typeof(float)) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_R4, 0f); } else if ((object)type == typeof(double)) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 0.0); } else if ((object)type == typeof(long) || (object)type == typeof(ulong)) { emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I8, 0L); } else { emitter.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, 0); } emitter.Emit(System.Reflection.Emit.OpCodes.Stloc, localBuilder4); return localBuilder4; } return null; } private static System.Reflection.Emit.OpCode LoadIndOpCodeFor(Type type) { if (PrimitivesWithObjectTypeCode.Contains(type)) { return System.Reflection.Emit.OpCodes.Ldind_I; } switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: return System.Reflection.Emit.OpCodes.Ldind_I1; case TypeCode.Char: case TypeCode.Int16: case TypeCode.UInt16: return System.Reflection.Emit.OpCodes.Ldind_I2; case TypeCode.Int32: case TypeCode.UInt32: return System.Reflection.Emit.OpCodes.Ldind_I4; case TypeCode.Int64: case TypeCode.UInt64: return System.Reflection.Emit.OpCodes.Ldind_I8; case TypeCode.Single: return System.Reflection.Emit.OpCodes.Ldind_R4; case TypeCode.Double: return System.Reflection.Emit.OpCodes.Ldind_R8; case TypeCode.Decimal: case TypeCode.DateTime: throw new NotSupportedException(); case TypeCode.Empty: case TypeCode.Object: case TypeCode.DBNull: case TypeCode.String: return System.Reflection.Emit.OpCodes.Ldind_Ref; default: return System.Reflection.Emit.OpCodes.Ldind_Ref; } } private static System.Reflection.Emit.OpCode StoreIndOpCodeFor(Type type) { if (PrimitivesWithObjectTypeCode.Contains(type)) { return System.Reflection.Emit.OpCodes.Stind_I; } switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: return System.Reflection.Emit.OpCodes.Stind_I1; case TypeCode.Char: case TypeCode.Int16: case TypeCode.UInt16: return System.Reflection.Emit.OpCodes.Stind_I2; case TypeCode.Int32: case TypeCode.UInt32: return System.Reflection.Emit.OpCodes.Stind_I4; case TypeCode.Int64: case TypeCode.UInt64: return System.Reflection.Emit.OpCodes.Stind_I8; case TypeCode.Single: return System.Reflection.Emit.OpCodes.Stind_R4; case TypeCode.Double: return System.Reflection.Emit.OpCodes.Stind_R8; case TypeCode.Decimal: case TypeCode.DateTime: throw new NotSupportedException(); case TypeCode.Empty: case TypeCode.Object: case TypeCode.DBNull: case
UMM/Core/dnlib.dll
Decompiled 2 months 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.Diagnostics; using System.Diagnostics.SymbolStore; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Xml; using Microsoft.CodeAnalysis; using Microsoft.Win32.SafeHandles; using dnlib.DotNet; using dnlib.DotNet.Emit; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; using dnlib.DotNet.Pdb.Dss; using dnlib.DotNet.Pdb.Managed; using dnlib.DotNet.Pdb.Portable; using dnlib.DotNet.Pdb.Symbols; using dnlib.DotNet.Pdb.WindowsPdb; using dnlib.DotNet.Writer; using dnlib.IO; using dnlib.PE; using dnlib.Threading; using dnlib.Utils; using dnlib.W32Resources; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("0xd4d")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (C) 2012-2018 [email protected]")] [assembly: AssemblyDescription("Reads and writes .NET assemblies and modules")] [assembly: AssemblyFileVersion("3.1.0.0")] [assembly: AssemblyInformationalVersion("3.1.0+83b4eaa999fab374f28697c8900d51a60a366658")] [assembly: AssemblyProduct("dnlib")] [assembly: AssemblyTitle("dnlib (thread safe)")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.1.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace dnlib { public static class Settings { public static bool IsThreadSafe => true; } } namespace dnlib.W32Resources { public sealed class ResourceData : ResourceDirectoryEntry { private readonly DataReaderFactory dataReaderFactory; private readonly uint resourceStartOffset; private readonly uint resourceLength; private uint codePage; private uint reserved; public uint CodePage { get { return codePage; } set { codePage = value; } } public uint Reserved { get { return reserved; } set { reserved = value; } } public DataReader CreateReader() { return dataReaderFactory.CreateReader(resourceStartOffset, resourceLength); } public ResourceData(ResourceName name) : this(name, ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null), 0u, 0u) { } public ResourceData(ResourceName name, DataReaderFactory dataReaderFactory, uint offset, uint length) : this(name, dataReaderFactory, offset, length, 0u, 0u) { } public ResourceData(ResourceName name, DataReaderFactory dataReaderFactory, uint offset, uint length, uint codePage, uint reserved) : base(name) { this.dataReaderFactory = dataReaderFactory ?? throw new ArgumentNullException("dataReaderFactory"); resourceStartOffset = offset; resourceLength = length; this.codePage = codePage; this.reserved = reserved; } } public abstract class ResourceDirectory : ResourceDirectoryEntry { protected uint characteristics; protected uint timeDateStamp; protected ushort majorVersion; protected ushort minorVersion; private protected LazyList<ResourceDirectory> directories; private protected LazyList<ResourceData> data; public uint Characteristics { get { return characteristics; } set { characteristics = value; } } public uint TimeDateStamp { get { return timeDateStamp; } set { timeDateStamp = value; } } public ushort MajorVersion { get { return majorVersion; } set { majorVersion = value; } } public ushort MinorVersion { get { return minorVersion; } set { minorVersion = value; } } public IList<ResourceDirectory> Directories => directories; public IList<ResourceData> Data => data; protected ResourceDirectory(ResourceName name) : base(name) { } public ResourceDirectory FindDirectory(ResourceName name) { foreach (ResourceDirectory directory in directories) { if (directory.Name == name) { return directory; } } return null; } public ResourceData FindData(ResourceName name) { foreach (ResourceData datum in data) { if (datum.Name == name) { return datum; } } return null; } } public class ResourceDirectoryUser : ResourceDirectory { public ResourceDirectoryUser(ResourceName name) : base(name) { directories = new LazyList<ResourceDirectory>(); data = new LazyList<ResourceData>(); } } public sealed class ResourceDirectoryPE : ResourceDirectory { private readonly struct EntryInfo { public readonly ResourceName name; public readonly uint offset; public EntryInfo(ResourceName name, uint offset) { this.name = name; this.offset = offset; } public override string ToString() { return $"{offset:X8} {name}"; } } private const uint MAX_DIR_DEPTH = 10u; private readonly Win32ResourcesPE resources; private uint depth; private List<EntryInfo> dataInfos; private List<EntryInfo> dirInfos; public ResourceDirectoryPE(uint depth, ResourceName name, Win32ResourcesPE resources, ref DataReader reader) : base(name) { this.resources = resources; this.depth = depth; Initialize(ref reader); } private void Initialize(ref DataReader reader) { if (depth > 10 || !reader.CanRead(16u)) { InitializeDefault(); return; } characteristics = reader.ReadUInt32(); timeDateStamp = reader.ReadUInt32(); majorVersion = reader.ReadUInt16(); minorVersion = reader.ReadUInt16(); ushort num = reader.ReadUInt16(); ushort num2 = reader.ReadUInt16(); int num3 = num + num2; if (!reader.CanRead((uint)(num3 * 8))) { InitializeDefault(); return; } dataInfos = new List<EntryInfo>(); dirInfos = new List<EntryInfo>(); uint num4 = reader.Position; int num5 = 0; while (num5 < num3) { reader.Position = num4; uint num6 = reader.ReadUInt32(); uint num7 = reader.ReadUInt32(); ResourceName resourceName = (((num6 & 0x80000000u) == 0) ? new ResourceName((int)num6) : new ResourceName(ReadString(ref reader, num6 & 0x7FFFFFFFu) ?? string.Empty)); if ((num7 & 0x80000000u) == 0) { dataInfos.Add(new EntryInfo(resourceName, num7)); } else { dirInfos.Add(new EntryInfo(resourceName, num7 & 0x7FFFFFFFu)); } num5++; num4 += 8; } directories = new LazyList<ResourceDirectory, object>(dirInfos.Count, null, (object ctx, int i) => ReadResourceDirectory(i)); data = new LazyList<ResourceData, object>(dataInfos.Count, null, (object ctx, int i) => ReadResourceData(i)); } private static string ReadString(ref DataReader reader, uint offset) { reader.Position = offset; if (!reader.CanRead(2u)) { return null; } int num = reader.ReadUInt16() * 2; if (!reader.CanRead((uint)num)) { return null; } try { return reader.ReadUtf16String(num / 2); } catch { return null; } } private ResourceDirectory ReadResourceDirectory(int i) { EntryInfo entryInfo = dirInfos[i]; DataReader reader = resources.GetResourceReader(); reader.Position = Math.Min(reader.Length, entryInfo.offset); return new ResourceDirectoryPE(depth + 1, entryInfo.name, resources, ref reader); } private ResourceData ReadResourceData(int i) { EntryInfo entryInfo = dataInfos[i]; DataReader resourceReader = resources.GetResourceReader(); resourceReader.Position = Math.Min(resourceReader.Length, entryInfo.offset); if (resourceReader.CanRead(16u)) { RVA rva = (RVA)resourceReader.ReadUInt32(); uint size = resourceReader.ReadUInt32(); uint codePage = resourceReader.ReadUInt32(); uint reserved = resourceReader.ReadUInt32(); resources.GetDataReaderInfo(rva, size, out var dataReaderFactory, out var dataOffset, out var dataLength); return new ResourceData(entryInfo.name, dataReaderFactory, dataOffset, dataLength, codePage, reserved); } return new ResourceData(entryInfo.name); } private void InitializeDefault() { directories = new LazyList<ResourceDirectory>(); data = new LazyList<ResourceData>(); } } public abstract class ResourceDirectoryEntry { private ResourceName name; public ResourceName Name { get { return name; } set { name = value; } } protected ResourceDirectoryEntry(ResourceName name) { this.name = name; } public override string ToString() { return name.ToString(); } } public readonly struct ResourceName : IComparable<ResourceName>, IEquatable<ResourceName> { private readonly int id; private readonly string name; public bool HasId => name == null; public bool HasName => name != null; public int Id => id; public string Name => name; public ResourceName(int id) { this.id = id; name = null; } public ResourceName(string name) { id = 0; this.name = name; } public static implicit operator ResourceName(int id) { return new ResourceName(id); } public static implicit operator ResourceName(string name) { return new ResourceName(name); } public static bool operator <(ResourceName left, ResourceName right) { return left.CompareTo(right) < 0; } public static bool operator <=(ResourceName left, ResourceName right) { return left.CompareTo(right) <= 0; } public static bool operator >(ResourceName left, ResourceName right) { return left.CompareTo(right) > 0; } public static bool operator >=(ResourceName left, ResourceName right) { return left.CompareTo(right) >= 0; } public static bool operator ==(ResourceName left, ResourceName right) { return left.Equals(right); } public static bool operator !=(ResourceName left, ResourceName right) { return !left.Equals(right); } public int CompareTo(ResourceName other) { if (HasId != other.HasId) { if (!HasName) { return 1; } return -1; } if (HasId) { int num = id; return num.CompareTo(other.id); } return name.ToUpperInvariant().CompareTo(other.name.ToUpperInvariant()); } public bool Equals(ResourceName other) { return CompareTo(other) == 0; } public override bool Equals(object obj) { if (!(obj is ResourceName)) { return false; } return Equals((ResourceName)obj); } public override int GetHashCode() { if (HasId) { return id; } return name.GetHashCode(); } public override string ToString() { if (!HasId) { return name; } int num = id; return num.ToString(); } } public abstract class Win32Resources : IDisposable { public abstract ResourceDirectory Root { get; set; } public ResourceDirectory Find(ResourceName type) { return Root?.FindDirectory(type); } public ResourceDirectory Find(ResourceName type, ResourceName name) { return Find(type)?.FindDirectory(name); } public ResourceData Find(ResourceName type, ResourceName name, ResourceName langId) { return Find(type, name)?.FindData(langId); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { Root = null; } } } public class Win32ResourcesUser : Win32Resources { private ResourceDirectory root = new ResourceDirectoryUser(new ResourceName("root")); public override ResourceDirectory Root { get { return root; } set { Interlocked.Exchange(ref root, value); } } } public sealed class Win32ResourcesPE : Win32Resources { private readonly IRvaFileOffsetConverter rvaConverter; private DataReaderFactory dataReader_factory; private uint dataReader_offset; private uint dataReader_length; private bool owns_dataReader_factory; private DataReaderFactory rsrcReader_factory; private uint rsrcReader_offset; private uint rsrcReader_length; private bool owns_rsrcReader_factory; private UserValue<ResourceDirectory> root; private readonly Lock theLock = Lock.Create(); public override ResourceDirectory Root { get { return root.Value; } set { if (!root.IsValueInitialized || root.Value != value) { root.Value = value; } } } internal DataReader GetResourceReader() { return rsrcReader_factory.CreateReader(rsrcReader_offset, rsrcReader_length); } public Win32ResourcesPE(IRvaFileOffsetConverter rvaConverter, DataReaderFactory rsrcReader_factory, uint rsrcReader_offset, uint rsrcReader_length, bool owns_rsrcReader_factory, DataReaderFactory dataReader_factory, uint dataReader_offset, uint dataReader_length, bool owns_dataReader_factory) { this.rvaConverter = rvaConverter ?? throw new ArgumentNullException("rvaConverter"); this.rsrcReader_factory = rsrcReader_factory ?? throw new ArgumentNullException("rsrcReader_factory"); this.rsrcReader_offset = rsrcReader_offset; this.rsrcReader_length = rsrcReader_length; this.owns_rsrcReader_factory = owns_rsrcReader_factory; this.dataReader_factory = dataReader_factory ?? throw new ArgumentNullException("dataReader_factory"); this.dataReader_offset = dataReader_offset; this.dataReader_length = dataReader_length; this.owns_dataReader_factory = owns_dataReader_factory; Initialize(); } public Win32ResourcesPE(IPEImage peImage) : this(peImage, null, 0u, 0u, owns_rsrcReader_factory: false) { } public Win32ResourcesPE(IPEImage peImage, DataReaderFactory rsrcReader_factory, uint rsrcReader_offset, uint rsrcReader_length, bool owns_rsrcReader_factory) { rvaConverter = peImage ?? throw new ArgumentNullException("peImage"); dataReader_factory = peImage.DataReaderFactory; dataReader_offset = 0u; dataReader_length = dataReader_factory.Length; if (rsrcReader_factory != null) { this.rsrcReader_factory = rsrcReader_factory; this.rsrcReader_offset = rsrcReader_offset; this.rsrcReader_length = rsrcReader_length; this.owns_rsrcReader_factory = owns_rsrcReader_factory; } else { ImageDataDirectory imageDataDirectory = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[2]; if (imageDataDirectory.VirtualAddress != 0 && imageDataDirectory.Size != 0) { DataReader dataReader = peImage.CreateReader(imageDataDirectory.VirtualAddress, imageDataDirectory.Size); this.rsrcReader_factory = peImage.DataReaderFactory; this.rsrcReader_offset = dataReader.StartOffset; this.rsrcReader_length = dataReader.Length; } else { this.rsrcReader_factory = ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null); this.rsrcReader_offset = 0u; this.rsrcReader_length = 0u; } } Initialize(); } private void Initialize() { root.ReadOriginalValue = delegate { DataReaderFactory dataReaderFactory = rsrcReader_factory; if (dataReaderFactory == null) { return null; } DataReader reader = dataReaderFactory.CreateReader(rsrcReader_offset, rsrcReader_length); return new ResourceDirectoryPE(0u, new ResourceName("root"), this, ref reader); }; root.Lock = theLock; } public DataReader CreateReader(RVA rva, uint size) { GetDataReaderInfo(rva, size, out var dataReaderFactory, out var dataOffset, out var dataLength); return dataReaderFactory.CreateReader(dataOffset, dataLength); } internal void GetDataReaderInfo(RVA rva, uint size, out DataReaderFactory dataReaderFactory, out uint dataOffset, out uint dataLength) { dataOffset = (uint)rvaConverter.ToFileOffset(rva); if ((ulong)((long)dataOffset + (long)size) <= (ulong)dataReader_factory.Length) { dataReaderFactory = dataReader_factory; dataLength = size; } else { dataReaderFactory = ByteArrayDataReaderFactory.Create(Array2.Empty<byte>(), null); dataOffset = 0u; dataLength = 0u; } } protected override void Dispose(bool disposing) { if (disposing) { if (owns_dataReader_factory) { dataReader_factory?.Dispose(); } if (owns_rsrcReader_factory) { rsrcReader_factory?.Dispose(); } dataReader_factory = null; rsrcReader_factory = null; base.Dispose(disposing); } } } } namespace dnlib.Utils { internal class CollectionDebugView<TValue> { private readonly ICollection<TValue> list; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public TValue[] Items { get { TValue[] array = new TValue[list.Count]; list.CopyTo(array, 0); return array; } } public CollectionDebugView(ICollection<TValue> list) { this.list = list ?? throw new ArgumentNullException("list"); } } internal class CollectionDebugView<TValue, TOther> : CollectionDebugView<TValue> { public CollectionDebugView(ICollection<TValue> list) : base(list) { } } internal sealed class LocalList_CollectionDebugView : CollectionDebugView<Local> { public LocalList_CollectionDebugView(LocalList list) : base((ICollection<Local>)list) { } } internal sealed class ParameterList_CollectionDebugView : CollectionDebugView<Parameter> { public ParameterList_CollectionDebugView(ParameterList list) : base((ICollection<Parameter>)list) { } } internal interface ILazyList<TValue> : IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable { } public interface IListListener<TListValue> { void OnLazyAdd(int index, ref TListValue value); void OnAdd(int index, TListValue value); void OnRemove(int index, TListValue value); void OnResize(int index); void OnClear(); } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(CollectionDebugView<>))] public class LazyList<TValue> : ILazyList<TValue>, IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable where TValue : class { private protected class Element { protected TValue value; public virtual bool IsInitialized_NoLock => true; protected Element() { } public Element(TValue data) { value = data; } public virtual TValue GetValue_NoLock(int index) { return value; } public virtual void SetValue_NoLock(int index, TValue value) { this.value = value; } public override string ToString() { return value?.ToString() ?? string.Empty; } } public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator { private readonly LazyList<TValue> list; private readonly int id; private int index; private TValue current; public TValue Current => current; object IEnumerator.Current => current; internal Enumerator(LazyList<TValue> list) { this.list = list; index = 0; current = null; list.theLock.EnterReadLock(); try { id = list.id; } finally { list.theLock.ExitReadLock(); } } public bool MoveNext() { list.theLock.EnterWriteLock(); try { if (list.id == id && index < list.Count_NoLock) { current = list.list[index].GetValue_NoLock(index); index++; return true; } return MoveNextDoneOrThrow_NoLock(); } finally { list.theLock.ExitWriteLock(); } } private bool MoveNextDoneOrThrow_NoLock() { if (list.id != id) { throw new InvalidOperationException("List was modified"); } current = null; return false; } public void Dispose() { } void IEnumerator.Reset() { throw new NotSupportedException(); } } private protected readonly List<Element> list; private int id; private protected readonly IListListener<TValue> listener; private readonly Lock theLock = Lock.Create(); public int Count { get { theLock.EnterReadLock(); try { return Count_NoLock; } finally { theLock.ExitReadLock(); } } } internal int Count_NoLock => list.Count; public bool IsReadOnly => false; public TValue this[int index] { get { theLock.EnterWriteLock(); try { return Get_NoLock(index); } finally { theLock.ExitWriteLock(); } } set { theLock.EnterWriteLock(); try { Set_NoLock(index, value); } finally { theLock.ExitWriteLock(); } } } internal TValue Get_NoLock(int index) { return list[index].GetValue_NoLock(index); } private void Set_NoLock(int index, TValue value) { if (listener != null) { listener.OnRemove(index, list[index].GetValue_NoLock(index)); listener.OnAdd(index, value); } list[index].SetValue_NoLock(index, value); id++; } public LazyList() : this((IListListener<TValue>)null) { } public LazyList(IListListener<TValue> listener) { this.listener = listener; list = new List<Element>(); } private protected LazyList(int length, IListListener<TValue> listener) { this.listener = listener; list = new List<Element>(length); } public int IndexOf(TValue item) { theLock.EnterWriteLock(); try { return IndexOf_NoLock(item); } finally { theLock.ExitWriteLock(); } } private int IndexOf_NoLock(TValue item) { for (int i = 0; i < list.Count; i++) { if (list[i].GetValue_NoLock(i) == item) { return i; } } return -1; } public void Insert(int index, TValue item) { theLock.EnterWriteLock(); try { Insert_NoLock(index, item); } finally { theLock.ExitWriteLock(); } } private void Insert_NoLock(int index, TValue item) { if (listener != null) { listener.OnAdd(index, item); } list.Insert(index, new Element(item)); if (listener != null) { listener.OnResize(index); } id++; } public void RemoveAt(int index) { theLock.EnterWriteLock(); try { RemoveAt_NoLock(index); } finally { theLock.ExitWriteLock(); } } private void RemoveAt_NoLock(int index) { if (listener != null) { listener.OnRemove(index, list[index].GetValue_NoLock(index)); } list.RemoveAt(index); if (listener != null) { listener.OnResize(index); } id++; } public void Add(TValue item) { theLock.EnterWriteLock(); try { Add_NoLock(item); } finally { theLock.ExitWriteLock(); } } private void Add_NoLock(TValue item) { int count = list.Count; if (listener != null) { listener.OnAdd(count, item); } list.Add(new Element(item)); if (listener != null) { listener.OnResize(count); } id++; } public void Clear() { theLock.EnterWriteLock(); try { Clear_NoLock(); } finally { theLock.ExitWriteLock(); } } private void Clear_NoLock() { if (listener != null) { listener.OnClear(); } list.Clear(); if (listener != null) { listener.OnResize(0); } id++; } public bool Contains(TValue item) { return IndexOf(item) >= 0; } public void CopyTo(TValue[] array, int arrayIndex) { theLock.EnterWriteLock(); try { CopyTo_NoLock(array, arrayIndex); } finally { theLock.ExitWriteLock(); } } private void CopyTo_NoLock(TValue[] array, int arrayIndex) { for (int i = 0; i < list.Count; i++) { array[arrayIndex + i] = list[i].GetValue_NoLock(i); } } public bool Remove(TValue item) { theLock.EnterWriteLock(); try { return Remove_NoLock(item); } finally { theLock.ExitWriteLock(); } } private bool Remove_NoLock(TValue item) { int num = IndexOf_NoLock(item); if (num < 0) { return false; } RemoveAt_NoLock(num); return true; } internal bool IsInitialized(int index) { theLock.EnterReadLock(); try { return IsInitialized_NoLock(index); } finally { theLock.ExitReadLock(); } } private bool IsInitialized_NoLock(int index) { if ((uint)index >= (uint)list.Count) { return false; } return list[index].IsInitialized_NoLock; } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() { return GetEnumerator(); } internal IEnumerable<TValue> GetEnumerable_NoLock() { int id2 = id; for (int i = 0; i < list.Count; i++) { if (id != id2) { throw new InvalidOperationException("List was modified"); } yield return list[i].GetValue_NoLock(i); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(CollectionDebugView<, >))] public class LazyList<TValue, TContext> : LazyList<TValue>, ILazyList<TValue>, IList<TValue>, ICollection<TValue>, IEnumerable<TValue>, IEnumerable where TValue : class { private sealed class LazyElement : Element { internal readonly int origIndex; private LazyList<TValue, TContext> lazyList; public override bool IsInitialized_NoLock => lazyList == null; public override TValue GetValue_NoLock(int index) { if (lazyList != null) { value = lazyList.ReadOriginalValue_NoLock(index, origIndex); lazyList = null; } return value; } public override void SetValue_NoLock(int index, TValue value) { base.value = value; lazyList = null; } public LazyElement(int origIndex, LazyList<TValue, TContext> lazyList) { this.origIndex = origIndex; this.lazyList = lazyList; } public override string ToString() { if (lazyList != null) { value = lazyList.ReadOriginalValue_NoLock(this); lazyList = null; } if (value != null) { return value.ToString(); } return string.Empty; } } private TContext context; private readonly Func<TContext, int, TValue> readOriginalValue; public LazyList() : this((IListListener<TValue>)null) { } public LazyList(IListListener<TValue> listener) : base(listener) { } public LazyList(int length, TContext context, Func<TContext, int, TValue> readOriginalValue) : this(length, (IListListener<TValue>)null, context, readOriginalValue) { } public LazyList(int length, IListListener<TValue> listener, TContext context, Func<TContext, int, TValue> readOriginalValue) : base(length, listener) { this.context = context; this.readOriginalValue = readOriginalValue; for (int i = 0; i < length; i++) { list.Add(new LazyElement(i, this)); } } private TValue ReadOriginalValue_NoLock(LazyElement elem) { return ReadOriginalValue_NoLock(list.IndexOf(elem), elem.origIndex); } private TValue ReadOriginalValue_NoLock(int index, int origIndex) { TValue value = readOriginalValue(context, origIndex); listener?.OnLazyAdd(index, ref value); return value; } } [DebuggerDisplay("Count = {Length}")] internal sealed class SimpleLazyList<T> where T : class { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] private readonly T[] elements; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Func<uint, T> readElementByRID; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly uint length; public uint Length => length; public T this[uint index] { get { if (index >= length) { return null; } if (elements[index] == null) { Interlocked.CompareExchange(ref elements[index], readElementByRID(index + 1), null); } return elements[index]; } } public SimpleLazyList(uint length, Func<uint, T> readElementByRID) { this.length = length; this.readElementByRID = readElementByRID; elements = new T[length]; } } [DebuggerDisplay("Count = {Length}")] internal sealed class SimpleLazyList2<T> where T : class, IContainsGenericParameter { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] private readonly T[] elements; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Func<uint, GenericParamContext, T> readElementByRID; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly uint length; public uint Length => length; public T this[uint index, GenericParamContext gpContext] { get { if (index >= length) { return null; } if (elements[index] == null) { T val = readElementByRID(index + 1, gpContext); if (val.ContainsGenericParameter) { return val; } Interlocked.CompareExchange(ref elements[index], val, null); } return elements[index]; } } public SimpleLazyList2(uint length, Func<uint, GenericParamContext, T> readElementByRID) { this.length = length; this.readElementByRID = readElementByRID; elements = new T[length]; } } [DebuggerDisplay("{value}")] internal struct UserValue<TValue> { private Lock theLock; private Func<TValue> readOriginalValue; private TValue value; private bool isUserValue; private bool isValueInitialized; public Lock Lock { set { theLock = value; } } public Func<TValue> ReadOriginalValue { set { readOriginalValue = value; } } public TValue Value { get { theLock?.EnterWriteLock(); try { if (!isValueInitialized) { value = readOriginalValue(); readOriginalValue = null; isValueInitialized = true; } return value; } finally { theLock?.ExitWriteLock(); } } set { theLock?.EnterWriteLock(); try { this.value = value; readOriginalValue = null; isUserValue = true; isValueInitialized = true; } finally { theLock?.ExitWriteLock(); } } } public bool IsValueInitialized { get { theLock?.EnterReadLock(); try { return isValueInitialized; } finally { theLock?.ExitReadLock(); } } } public bool IsUserValue { get { theLock?.EnterReadLock(); try { return isUserValue; } finally { theLock?.ExitReadLock(); } } } } } namespace dnlib.Threading { public interface ICancellationToken { void ThrowIfCancellationRequested(); } [Serializable] internal class LockException : Exception { public LockException() { } public LockException(string msg) : base(msg) { } protected LockException(SerializationInfo info, StreamingContext context) : base(info, context) { } } internal class Lock { private readonly object lockObj; private int recurseCount; public static Lock Create() { return new Lock(); } private Lock() { lockObj = new object(); recurseCount = 0; } public void EnterReadLock() { Monitor.Enter(lockObj); if (recurseCount != 0) { Monitor.Exit(lockObj); throw new LockException("Recursive locks aren't supported"); } recurseCount++; } public void ExitReadLock() { if (recurseCount <= 0) { throw new LockException("Too many exit lock method calls"); } recurseCount--; Monitor.Exit(lockObj); } public void EnterWriteLock() { Monitor.Enter(lockObj); if (recurseCount != 0) { Monitor.Exit(lockObj); throw new LockException("Recursive locks aren't supported"); } recurseCount--; } public void ExitWriteLock() { if (recurseCount >= 0) { throw new LockException("Too many exit lock method calls"); } recurseCount++; Monitor.Exit(lockObj); } } } namespace dnlib.PE { [Flags] public enum Characteristics : ushort { RelocsStripped = 1, ExecutableImage = 2, LineNumsStripped = 4, LocalSymsStripped = 8, AggressiveWsTrim = 0x10, LargeAddressAware = 0x20, Reserved1 = 0x40, BytesReversedLo = 0x80, [Obsolete("Use Bit32Machine", false)] _32BitMachine = 0x100, Bit32Machine = 0x100, DebugStripped = 0x200, RemovableRunFromSwap = 0x400, NetRunFromSwap = 0x800, System = 0x1000, Dll = 0x2000, UpSystemOnly = 0x4000, BytesReversedHi = 0x8000 } [Flags] public enum DllCharacteristics : ushort { Reserved1 = 1, Reserved2 = 2, Reserved3 = 4, Reserved4 = 8, Reserved5 = 0x10, HighEntropyVA = 0x20, DynamicBase = 0x40, ForceIntegrity = 0x80, NxCompat = 0x100, NoIsolation = 0x200, NoSeh = 0x400, NoBind = 0x800, AppContainer = 0x1000, WdmDriver = 0x2000, GuardCf = 0x4000, TerminalServerAware = 0x8000 } public interface IImageOptionalHeader : IFileSection { ushort Magic { get; } byte MajorLinkerVersion { get; } byte MinorLinkerVersion { get; } uint SizeOfCode { get; } uint SizeOfInitializedData { get; } uint SizeOfUninitializedData { get; } RVA AddressOfEntryPoint { get; } RVA BaseOfCode { get; } RVA BaseOfData { get; } ulong ImageBase { get; } uint SectionAlignment { get; } uint FileAlignment { get; } ushort MajorOperatingSystemVersion { get; } ushort MinorOperatingSystemVersion { get; } ushort MajorImageVersion { get; } ushort MinorImageVersion { get; } ushort MajorSubsystemVersion { get; } ushort MinorSubsystemVersion { get; } uint Win32VersionValue { get; } uint SizeOfImage { get; } uint SizeOfHeaders { get; } uint CheckSum { get; } Subsystem Subsystem { get; } DllCharacteristics DllCharacteristics { get; } ulong SizeOfStackReserve { get; } ulong SizeOfStackCommit { get; } ulong SizeOfHeapReserve { get; } ulong SizeOfHeapCommit { get; } uint LoaderFlags { get; } uint NumberOfRvaAndSizes { get; } ImageDataDirectory[] DataDirectories { get; } } [DebuggerDisplay("{virtualAddress} {dataSize}")] public sealed class ImageDataDirectory : FileSection { private readonly RVA virtualAddress; private readonly uint dataSize; public RVA VirtualAddress => virtualAddress; public uint Size => dataSize; public ImageDataDirectory() { } public ImageDataDirectory(ref DataReader reader, bool verify) { SetStartOffset(ref reader); virtualAddress = (RVA)reader.ReadUInt32(); dataSize = reader.ReadUInt32(); SetEndoffset(ref reader); } } [DebuggerDisplay("{type}: TS:{timeDateStamp,h} V:{majorVersion,d}.{minorVersion,d} SZ:{sizeOfData} RVA:{addressOfRawData,h} FO:{pointerToRawData,h}")] public sealed class ImageDebugDirectory : FileSection { private readonly uint characteristics; private readonly uint timeDateStamp; private readonly ushort majorVersion; private readonly ushort minorVersion; private readonly ImageDebugType type; private readonly uint sizeOfData; private readonly uint addressOfRawData; private readonly uint pointerToRawData; public uint Characteristics => characteristics; public uint TimeDateStamp => timeDateStamp; public ushort MajorVersion => majorVersion; public ushort MinorVersion => minorVersion; public ImageDebugType Type => type; public uint SizeOfData => sizeOfData; public RVA AddressOfRawData => (RVA)addressOfRawData; public FileOffset PointerToRawData => (FileOffset)pointerToRawData; public ImageDebugDirectory(ref DataReader reader, bool verify) { SetStartOffset(ref reader); characteristics = reader.ReadUInt32(); timeDateStamp = reader.ReadUInt32(); majorVersion = reader.ReadUInt16(); minorVersion = reader.ReadUInt16(); type = (ImageDebugType)reader.ReadUInt32(); sizeOfData = reader.ReadUInt32(); addressOfRawData = reader.ReadUInt32(); pointerToRawData = reader.ReadUInt32(); SetEndoffset(ref reader); } } public enum ImageDebugType : uint { Unknown = 0u, Coff = 1u, CodeView = 2u, FPO = 3u, Misc = 4u, Exception = 5u, Fixup = 6u, OmapToSrc = 7u, OmapFromSrc = 8u, Borland = 9u, Reserved10 = 10u, CLSID = 11u, VcFeature = 12u, POGO = 13u, ILTCG = 14u, MPX = 15u, Reproducible = 16u, EmbeddedPortablePdb = 17u, PdbChecksum = 19u } public sealed class ImageDosHeader : FileSection { private readonly uint ntHeadersOffset; public uint NTHeadersOffset => ntHeadersOffset; public ImageDosHeader(ref DataReader reader, bool verify) { SetStartOffset(ref reader); ushort num = reader.ReadUInt16(); if (verify && num != 23117) { throw new BadImageFormatException("Invalid DOS signature"); } reader.Position = (uint)(startOffset + 60); ntHeadersOffset = reader.ReadUInt32(); SetEndoffset(ref reader); } } public sealed class ImageFileHeader : FileSection { private readonly Machine machine; private readonly ushort numberOfSections; private readonly uint timeDateStamp; private readonly uint pointerToSymbolTable; private readonly uint numberOfSymbols; private readonly ushort sizeOfOptionalHeader; private readonly Characteristics characteristics; public Machine Machine => machine; public int NumberOfSections => numberOfSections; public uint TimeDateStamp => timeDateStamp; public uint PointerToSymbolTable => pointerToSymbolTable; public uint NumberOfSymbols => numberOfSymbols; public uint SizeOfOptionalHeader => sizeOfOptionalHeader; public Characteristics Characteristics => characteristics; public ImageFileHeader(ref DataReader reader, bool verify) { SetStartOffset(ref reader); machine = (Machine)reader.ReadUInt16(); numberOfSections = reader.ReadUInt16(); timeDateStamp = reader.ReadUInt32(); pointerToSymbolTable = reader.ReadUInt32(); numberOfSymbols = reader.ReadUInt32(); sizeOfOptionalHeader = reader.ReadUInt16(); characteristics = (Characteristics)reader.ReadUInt16(); SetEndoffset(ref reader); if (verify && sizeOfOptionalHeader == 0) { throw new BadImageFormatException("Invalid SizeOfOptionalHeader"); } } } public sealed class ImageNTHeaders : FileSection { private readonly uint signature; private readonly ImageFileHeader imageFileHeader; private readonly IImageOptionalHeader imageOptionalHeader; public uint Signature => signature; public ImageFileHeader FileHeader => imageFileHeader; public IImageOptionalHeader OptionalHeader => imageOptionalHeader; public ImageNTHeaders(ref DataReader reader, bool verify) { SetStartOffset(ref reader); signature = reader.ReadUInt32(); if (verify && (ushort)signature != 17744) { throw new BadImageFormatException("Invalid NT headers signature"); } imageFileHeader = new ImageFileHeader(ref reader, verify); imageOptionalHeader = CreateImageOptionalHeader(ref reader, verify); SetEndoffset(ref reader); } private IImageOptionalHeader CreateImageOptionalHeader(ref DataReader reader, bool verify) { ushort num = reader.ReadUInt16(); reader.Position -= 2u; return num switch { 267 => new ImageOptionalHeader32(ref reader, imageFileHeader.SizeOfOptionalHeader, verify), 523 => new ImageOptionalHeader64(ref reader, imageFileHeader.SizeOfOptionalHeader, verify), _ => throw new BadImageFormatException("Invalid optional header magic"), }; } } public sealed class ImageOptionalHeader32 : FileSection, IImageOptionalHeader, IFileSection { private readonly ushort magic; private readonly byte majorLinkerVersion; private readonly byte minorLinkerVersion; private readonly uint sizeOfCode; private readonly uint sizeOfInitializedData; private readonly uint sizeOfUninitializedData; private readonly RVA addressOfEntryPoint; private readonly RVA baseOfCode; private readonly RVA baseOfData; private readonly uint imageBase; private readonly uint sectionAlignment; private readonly uint fileAlignment; private readonly ushort majorOperatingSystemVersion; private readonly ushort minorOperatingSystemVersion; private readonly ushort majorImageVersion; private readonly ushort minorImageVersion; private readonly ushort majorSubsystemVersion; private readonly ushort minorSubsystemVersion; private readonly uint win32VersionValue; private readonly uint sizeOfImage; private readonly uint sizeOfHeaders; private readonly uint checkSum; private readonly Subsystem subsystem; private readonly DllCharacteristics dllCharacteristics; private readonly uint sizeOfStackReserve; private readonly uint sizeOfStackCommit; private readonly uint sizeOfHeapReserve; private readonly uint sizeOfHeapCommit; private readonly uint loaderFlags; private readonly uint numberOfRvaAndSizes; private readonly ImageDataDirectory[] dataDirectories = new ImageDataDirectory[16]; public ushort Magic => magic; public byte MajorLinkerVersion => majorLinkerVersion; public byte MinorLinkerVersion => minorLinkerVersion; public uint SizeOfCode => sizeOfCode; public uint SizeOfInitializedData => sizeOfInitializedData; public uint SizeOfUninitializedData => sizeOfUninitializedData; public RVA AddressOfEntryPoint => addressOfEntryPoint; public RVA BaseOfCode => baseOfCode; public RVA BaseOfData => baseOfData; public ulong ImageBase => imageBase; public uint SectionAlignment => sectionAlignment; public uint FileAlignment => fileAlignment; public ushort MajorOperatingSystemVersion => majorOperatingSystemVersion; public ushort MinorOperatingSystemVersion => minorOperatingSystemVersion; public ushort MajorImageVersion => majorImageVersion; public ushort MinorImageVersion => minorImageVersion; public ushort MajorSubsystemVersion => majorSubsystemVersion; public ushort MinorSubsystemVersion => minorSubsystemVersion; public uint Win32VersionValue => win32VersionValue; public uint SizeOfImage => sizeOfImage; public uint SizeOfHeaders => sizeOfHeaders; public uint CheckSum => checkSum; public Subsystem Subsystem => subsystem; public DllCharacteristics DllCharacteristics => dllCharacteristics; public ulong SizeOfStackReserve => sizeOfStackReserve; public ulong SizeOfStackCommit => sizeOfStackCommit; public ulong SizeOfHeapReserve => sizeOfHeapReserve; public ulong SizeOfHeapCommit => sizeOfHeapCommit; public uint LoaderFlags => loaderFlags; public uint NumberOfRvaAndSizes => numberOfRvaAndSizes; public ImageDataDirectory[] DataDirectories => dataDirectories; public ImageOptionalHeader32(ref DataReader reader, uint totalSize, bool verify) { if (totalSize < 96) { throw new BadImageFormatException("Invalid optional header size"); } if (verify && (ulong)((long)reader.Position + (long)totalSize) > (ulong)reader.Length) { throw new BadImageFormatException("Invalid optional header size"); } SetStartOffset(ref reader); magic = reader.ReadUInt16(); majorLinkerVersion = reader.ReadByte(); minorLinkerVersion = reader.ReadByte(); sizeOfCode = reader.ReadUInt32(); sizeOfInitializedData = reader.ReadUInt32(); sizeOfUninitializedData = reader.ReadUInt32(); addressOfEntryPoint = (RVA)reader.ReadUInt32(); baseOfCode = (RVA)reader.ReadUInt32(); baseOfData = (RVA)reader.ReadUInt32(); imageBase = reader.ReadUInt32(); sectionAlignment = reader.ReadUInt32(); fileAlignment = reader.ReadUInt32(); majorOperatingSystemVersion = reader.ReadUInt16(); minorOperatingSystemVersion = reader.ReadUInt16(); majorImageVersion = reader.ReadUInt16(); minorImageVersion = reader.ReadUInt16(); majorSubsystemVersion = reader.ReadUInt16(); minorSubsystemVersion = reader.ReadUInt16(); win32VersionValue = reader.ReadUInt32(); sizeOfImage = reader.ReadUInt32(); sizeOfHeaders = reader.ReadUInt32(); checkSum = reader.ReadUInt32(); subsystem = (Subsystem)reader.ReadUInt16(); dllCharacteristics = (DllCharacteristics)reader.ReadUInt16(); sizeOfStackReserve = reader.ReadUInt32(); sizeOfStackCommit = reader.ReadUInt32(); sizeOfHeapReserve = reader.ReadUInt32(); sizeOfHeapCommit = reader.ReadUInt32(); loaderFlags = reader.ReadUInt32(); numberOfRvaAndSizes = reader.ReadUInt32(); for (int i = 0; i < dataDirectories.Length; i++) { if ((uint)(reader.Position - startOffset + 8) <= totalSize) { dataDirectories[i] = new ImageDataDirectory(ref reader, verify); } else { dataDirectories[i] = new ImageDataDirectory(); } } reader.Position = (uint)(startOffset + totalSize); SetEndoffset(ref reader); } } public sealed class ImageOptionalHeader64 : FileSection, IImageOptionalHeader, IFileSection { private readonly ushort magic; private readonly byte majorLinkerVersion; private readonly byte minorLinkerVersion; private readonly uint sizeOfCode; private readonly uint sizeOfInitializedData; private readonly uint sizeOfUninitializedData; private readonly RVA addressOfEntryPoint; private readonly RVA baseOfCode; private readonly ulong imageBase; private readonly uint sectionAlignment; private readonly uint fileAlignment; private readonly ushort majorOperatingSystemVersion; private readonly ushort minorOperatingSystemVersion; private readonly ushort majorImageVersion; private readonly ushort minorImageVersion; private readonly ushort majorSubsystemVersion; private readonly ushort minorSubsystemVersion; private readonly uint win32VersionValue; private readonly uint sizeOfImage; private readonly uint sizeOfHeaders; private readonly uint checkSum; private readonly Subsystem subsystem; private readonly DllCharacteristics dllCharacteristics; private readonly ulong sizeOfStackReserve; private readonly ulong sizeOfStackCommit; private readonly ulong sizeOfHeapReserve; private readonly ulong sizeOfHeapCommit; private readonly uint loaderFlags; private readonly uint numberOfRvaAndSizes; private readonly ImageDataDirectory[] dataDirectories = new ImageDataDirectory[16]; public ushort Magic => magic; public byte MajorLinkerVersion => majorLinkerVersion; public byte MinorLinkerVersion => minorLinkerVersion; public uint SizeOfCode => sizeOfCode; public uint SizeOfInitializedData => sizeOfInitializedData; public uint SizeOfUninitializedData => sizeOfUninitializedData; public RVA AddressOfEntryPoint => addressOfEntryPoint; public RVA BaseOfCode => baseOfCode; public RVA BaseOfData => (RVA)0u; public ulong ImageBase => imageBase; public uint SectionAlignment => sectionAlignment; public uint FileAlignment => fileAlignment; public ushort MajorOperatingSystemVersion => majorOperatingSystemVersion; public ushort MinorOperatingSystemVersion => minorOperatingSystemVersion; public ushort MajorImageVersion => majorImageVersion; public ushort MinorImageVersion => minorImageVersion; public ushort MajorSubsystemVersion => majorSubsystemVersion; public ushort MinorSubsystemVersion => minorSubsystemVersion; public uint Win32VersionValue => win32VersionValue; public uint SizeOfImage => sizeOfImage; public uint SizeOfHeaders => sizeOfHeaders; public uint CheckSum => checkSum; public Subsystem Subsystem => subsystem; public DllCharacteristics DllCharacteristics => dllCharacteristics; public ulong SizeOfStackReserve => sizeOfStackReserve; public ulong SizeOfStackCommit => sizeOfStackCommit; public ulong SizeOfHeapReserve => sizeOfHeapReserve; public ulong SizeOfHeapCommit => sizeOfHeapCommit; public uint LoaderFlags => loaderFlags; public uint NumberOfRvaAndSizes => numberOfRvaAndSizes; public ImageDataDirectory[] DataDirectories => dataDirectories; public ImageOptionalHeader64(ref DataReader reader, uint totalSize, bool verify) { if (totalSize < 112) { throw new BadImageFormatException("Invalid optional header size"); } if (verify && (ulong)((long)reader.Position + (long)totalSize) > (ulong)reader.Length) { throw new BadImageFormatException("Invalid optional header size"); } SetStartOffset(ref reader); magic = reader.ReadUInt16(); majorLinkerVersion = reader.ReadByte(); minorLinkerVersion = reader.ReadByte(); sizeOfCode = reader.ReadUInt32(); sizeOfInitializedData = reader.ReadUInt32(); sizeOfUninitializedData = reader.ReadUInt32(); addressOfEntryPoint = (RVA)reader.ReadUInt32(); baseOfCode = (RVA)reader.ReadUInt32(); imageBase = reader.ReadUInt64(); sectionAlignment = reader.ReadUInt32(); fileAlignment = reader.ReadUInt32(); majorOperatingSystemVersion = reader.ReadUInt16(); minorOperatingSystemVersion = reader.ReadUInt16(); majorImageVersion = reader.ReadUInt16(); minorImageVersion = reader.ReadUInt16(); majorSubsystemVersion = reader.ReadUInt16(); minorSubsystemVersion = reader.ReadUInt16(); win32VersionValue = reader.ReadUInt32(); sizeOfImage = reader.ReadUInt32(); sizeOfHeaders = reader.ReadUInt32(); checkSum = reader.ReadUInt32(); subsystem = (Subsystem)reader.ReadUInt16(); dllCharacteristics = (DllCharacteristics)reader.ReadUInt16(); sizeOfStackReserve = reader.ReadUInt64(); sizeOfStackCommit = reader.ReadUInt64(); sizeOfHeapReserve = reader.ReadUInt64(); sizeOfHeapCommit = reader.ReadUInt64(); loaderFlags = reader.ReadUInt32(); numberOfRvaAndSizes = reader.ReadUInt32(); for (int i = 0; i < dataDirectories.Length; i++) { if ((uint)(reader.Position - startOffset + 8) <= totalSize) { dataDirectories[i] = new ImageDataDirectory(ref reader, verify); } else { dataDirectories[i] = new ImageDataDirectory(); } } reader.Position = (uint)(startOffset + totalSize); SetEndoffset(ref reader); } } [DebuggerDisplay("RVA:{virtualAddress} VS:{virtualSize} FO:{pointerToRawData} FS:{sizeOfRawData} {displayName}")] public sealed class ImageSectionHeader : FileSection { private readonly string displayName; private readonly byte[] name; private readonly uint virtualSize; private readonly RVA virtualAddress; private readonly uint sizeOfRawData; private readonly uint pointerToRawData; private readonly uint pointerToRelocations; private readonly uint pointerToLinenumbers; private readonly ushort numberOfRelocations; private readonly ushort numberOfLinenumbers; private readonly uint characteristics; public string DisplayName => displayName; public byte[] Name => name; public uint VirtualSize => virtualSize; public RVA VirtualAddress => virtualAddress; public uint SizeOfRawData => sizeOfRawData; public uint PointerToRawData => pointerToRawData; public uint PointerToRelocations => pointerToRelocations; public uint PointerToLinenumbers => pointerToLinenumbers; public ushort NumberOfRelocations => numberOfRelocations; public ushort NumberOfLinenumbers => numberOfLinenumbers; public uint Characteristics => characteristics; public ImageSectionHeader(ref DataReader reader, bool verify) { SetStartOffset(ref reader); name = reader.ReadBytes(8); virtualSize = reader.ReadUInt32(); virtualAddress = (RVA)reader.ReadUInt32(); sizeOfRawData = reader.ReadUInt32(); pointerToRawData = reader.ReadUInt32(); pointerToRelocations = reader.ReadUInt32(); pointerToLinenumbers = reader.ReadUInt32(); numberOfRelocations = reader.ReadUInt16(); numberOfLinenumbers = reader.ReadUInt16(); characteristics = reader.ReadUInt32(); SetEndoffset(ref reader); displayName = ToString(name); } private static string ToString(byte[] name) { StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (byte b in name) { if (b == 0) { break; } stringBuilder.Append((char)b); } return stringBuilder.ToString(); } } public interface IRvaFileOffsetConverter { RVA ToRVA(FileOffset offset); FileOffset ToFileOffset(RVA rva); } public interface IPEImage : IRvaFileOffsetConverter, IDisposable { bool IsFileImageLayout { get; } bool MayHaveInvalidAddresses { get; } string Filename { get; } ImageDosHeader ImageDosHeader { get; } ImageNTHeaders ImageNTHeaders { get; } IList<ImageSectionHeader> ImageSectionHeaders { get; } IList<ImageDebugDirectory> ImageDebugDirectories { get; } Win32Resources Win32Resources { get; set; } DataReaderFactory DataReaderFactory { get; } DataReader CreateReader(FileOffset offset); DataReader CreateReader(FileOffset offset, uint length); DataReader CreateReader(RVA rva); DataReader CreateReader(RVA rva, uint length); DataReader CreateReader(); } public interface IInternalPEImage : IPEImage, IRvaFileOffsetConverter, IDisposable { bool IsMemoryMappedIO { get; } void UnsafeDisableMemoryMappedIO(); } public static class PEExtensions { public static ResourceData FindWin32ResourceData(this IPEImage self, ResourceName type, ResourceName name, ResourceName langId) { return self.Win32Resources?.Find(type, name, langId); } internal static uint CalculatePECheckSum(this Stream stream, long length, long checkSumOffset) { if ((length & 1) != 0L) { ThrowInvalidOperationException("Invalid PE length"); } byte[] buffer = new byte[(int)Math.Min(length, 8192L)]; uint checkSum = 0u; checkSum = CalculatePECheckSum(stream, checkSumOffset, checkSum, buffer); stream.Position += 4L; checkSum = CalculatePECheckSum(stream, length - checkSumOffset - 4, checkSum, buffer); ulong num = (ulong)(checkSum + length); return (uint)((int)num + (int)(num >> 32)); } private static uint CalculatePECheckSum(Stream stream, long length, uint checkSum, byte[] buffer) { int num3; for (long num = 0L; num < length; num += num3) { int num2 = (int)Math.Min(length - num, buffer.Length); num3 = stream.Read(buffer, 0, num2); if (num3 != num2) { ThrowInvalidOperationException("Couldn't read all bytes"); } int num4 = 0; while (num4 < num3) { checkSum += (uint)(buffer[num4++] | (buffer[num4++] << 8)); checkSum = (ushort)(checkSum + (checkSum >> 16)); } } return checkSum; } private static void ThrowInvalidOperationException(string message) { throw new InvalidOperationException(message); } public static RVA AlignUp(this RVA rva, uint alignment) { return (RVA)((uint)(rva + alignment - 1) & ~(alignment - 1)); } public static RVA AlignUp(this RVA rva, int alignment) { return (RVA)(((long)rva + (long)alignment - 1) & ~(alignment - 1)); } } internal interface IPEType { RVA ToRVA(PEInfo peInfo, FileOffset offset); FileOffset ToFileOffset(PEInfo peInfo, RVA rva); } public enum Machine : ushort { Unknown = 0, I386 = 332, R3000 = 354, R4000 = 358, R10000 = 360, WCEMIPSV2 = 361, ALPHA = 388, SH3 = 418, SH3DSP = 419, SH3E = 420, SH4 = 422, SH5 = 424, ARM = 448, THUMB = 450, ARMNT = 452, AM33 = 467, POWERPC = 496, POWERPCFP = 497, IA64 = 512, MIPS16 = 614, ALPHA64 = 644, MIPSFPU = 870, MIPSFPU16 = 1126, TRICORE = 1312, CEF = 3311, EBC = 3772, AMD64 = 34404, M32R = 36929, ARM64 = 43620, CEE = 49390, I386_Native_Apple = 18184, AMD64_Native_Apple = 49184, ARMNT_Native_Apple = 18304, ARM64_Native_Apple = 60448, I386_Native_FreeBSD = 44168, AMD64_Native_FreeBSD = 11168, ARMNT_Native_FreeBSD = 44032, ARM64_Native_FreeBSD = 1952, I386_Native_Linux = 31285, AMD64_Native_Linux = 64797, ARMNT_Native_Linux = 31421, ARM64_Native_Linux = 53533, I386_Native_NetBSD = 6367, AMD64_Native_NetBSD = 40951, ARMNT_Native_NetBSD = 6231, ARM64_Native_NetBSD = 46071 } public static class MachineExtensions { public static bool Is64Bit(this Machine machine) { switch (machine) { case Machine.IA64: case Machine.ARM64_Native_FreeBSD: case Machine.AMD64_Native_FreeBSD: case Machine.AMD64: case Machine.AMD64_Native_NetBSD: case Machine.ARM64: case Machine.ARM64_Native_NetBSD: case Machine.AMD64_Native_Apple: case Machine.ARM64_Native_Linux: case Machine.ARM64_Native_Apple: case Machine.AMD64_Native_Linux: return true; default: return false; } } public static bool IsI386(this Machine machine) { switch (machine) { case Machine.I386: case Machine.I386_Native_NetBSD: case Machine.I386_Native_Apple: case Machine.I386_Native_Linux: case Machine.I386_Native_FreeBSD: return true; default: return false; } } public static bool IsAMD64(this Machine machine) { switch (machine) { case Machine.AMD64_Native_FreeBSD: case Machine.AMD64: case Machine.AMD64_Native_NetBSD: case Machine.AMD64_Native_Apple: case Machine.AMD64_Native_Linux: return true; default: return false; } } public static bool IsARMNT(this Machine machine) { switch (machine) { case Machine.ARMNT: case Machine.ARMNT_Native_NetBSD: case Machine.ARMNT_Native_Apple: case Machine.ARMNT_Native_Linux: case Machine.ARMNT_Native_FreeBSD: return true; default: return false; } } public static bool IsARM64(this Machine machine) { switch (machine) { case Machine.ARM64_Native_FreeBSD: case Machine.ARM64: case Machine.ARM64_Native_NetBSD: case Machine.ARM64_Native_Linux: case Machine.ARM64_Native_Apple: return true; default: return false; } } } public enum ImageLayout { File, Memory } public sealed class PEImage : IInternalPEImage, IPEImage, IRvaFileOffsetConverter, IDisposable { private sealed class FilePEType : IPEType { public RVA ToRVA(PEInfo peInfo, FileOffset offset) { return peInfo.ToRVA(offset); } public FileOffset ToFileOffset(PEInfo peInfo, RVA rva) { return peInfo.ToFileOffset(rva); } } private sealed class MemoryPEType : IPEType { public RVA ToRVA(PEInfo peInfo, FileOffset offset) { return (RVA)offset; } public FileOffset ToFileOffset(PEInfo peInfo, RVA rva) { return (FileOffset)rva; } } private const bool USE_MEMORY_LAYOUT_WITH_MAPPED_FILES = false; private static readonly IPEType MemoryLayout = new MemoryPEType(); private static readonly IPEType FileLayout = new FilePEType(); private DataReaderFactory dataReaderFactory; private IPEType peType; private PEInfo peInfo; private UserValue<Win32Resources> win32Resources; private readonly Lock theLock = Lock.Create(); private ImageDebugDirectory[] imageDebugDirectories; public bool IsFileImageLayout => peType is FilePEType; public bool MayHaveInvalidAddresses => !IsFileImageLayout; public string Filename => dataReaderFactory.Filename; public ImageDosHeader ImageDosHeader => peInfo.ImageDosHeader; public ImageNTHeaders ImageNTHeaders => peInfo.ImageNTHeaders; public IList<ImageSectionHeader> ImageSectionHeaders => peInfo.ImageSectionHeaders; public IList<ImageDebugDirectory> ImageDebugDirectories { get { if (imageDebugDirectories == null) { imageDebugDirectories = ReadImageDebugDirectories(); } return imageDebugDirectories; } } public DataReaderFactory DataReaderFactory => dataReaderFactory; public Win32Resources Win32Resources { get { return win32Resources.Value; } set { IDisposable disposable = null; if (win32Resources.IsValueInitialized) { disposable = win32Resources.Value; if (disposable == value) { return; } } win32Resources.Value = value; disposable?.Dispose(); } } bool IInternalPEImage.IsMemoryMappedIO { get { if (dataReaderFactory is MemoryMappedDataReaderFactory memoryMappedDataReaderFactory) { return memoryMappedDataReaderFactory.IsMemoryMappedIO; } return false; } } public PEImage(DataReaderFactory dataReaderFactory, ImageLayout imageLayout, bool verify) { try { this.dataReaderFactory = dataReaderFactory; peType = ConvertImageLayout(imageLayout); DataReader reader = dataReaderFactory.CreateReader(); peInfo = new PEInfo(ref reader, verify); Initialize(); } catch { Dispose(); throw; } } private void Initialize() { win32Resources.ReadOriginalValue = delegate { ImageDataDirectory imageDataDirectory = peInfo.ImageNTHeaders.OptionalHeader.DataDirectories[2]; return (imageDataDirectory.VirtualAddress == (RVA)0u || imageDataDirectory.Size == 0) ? null : new Win32ResourcesPE(this); }; win32Resources.Lock = theLock; } private static IPEType ConvertImageLayout(ImageLayout imageLayout) { return imageLayout switch { ImageLayout.File => FileLayout, ImageLayout.Memory => MemoryLayout, _ => throw new ArgumentException("imageLayout"), }; } internal PEImage(string filename, bool mapAsImage, bool verify) : this(DataReaderFactoryFactory.Create(filename, mapAsImage), mapAsImage ? ImageLayout.Memory : ImageLayout.File, verify) { try { if (mapAsImage && dataReaderFactory is MemoryMappedDataReaderFactory) { ((MemoryMappedDataReaderFactory)dataReaderFactory).SetLength(peInfo.GetImageSize()); } } catch { Dispose(); throw; } } public PEImage(string filename, bool verify) : this(filename, mapAsImage: false, verify) { } public PEImage(string filename) : this(filename, verify: true) { } public PEImage(byte[] data, string filename, ImageLayout imageLayout, bool verify) : this(ByteArrayDataReaderFactory.Create(data, filename), imageLayout, verify) { } public PEImage(byte[] data, ImageLayout imageLayout, bool verify) : this(data, null, imageLayout, verify) { } public PEImage(byte[] data, bool verify) : this(data, null, ImageLayout.File, verify) { } public PEImage(byte[] data, string filename, bool verify) : this(data, filename, ImageLayout.File, verify) { } public PEImage(byte[] data) : this(data, null, verify: true) { } public PEImage(byte[] data, string filename) : this(data, filename, verify: true) { } public unsafe PEImage(IntPtr baseAddr, uint length, ImageLayout imageLayout, bool verify) : this(NativeMemoryDataReaderFactory.Create((byte*)(void*)baseAddr, length, null), imageLayout, verify) { } public PEImage(IntPtr baseAddr, uint length, bool verify) : this(baseAddr, length, ImageLayout.Memory, verify) { } public PEImage(IntPtr baseAddr, uint length) : this(baseAddr, length, verify: true) { } public unsafe PEImage(IntPtr baseAddr, ImageLayout imageLayout, bool verify) : this(NativeMemoryDataReaderFactory.Create((byte*)(void*)baseAddr, 65536u, null), imageLayout, verify) { try { ((NativeMemoryDataReaderFactory)dataReaderFactory).SetLength(peInfo.GetImageSize()); } catch { Dispose(); throw; } } public PEImage(IntPtr baseAddr, bool verify) : this(baseAddr, ImageLayout.Memory, verify) { } public PEImage(IntPtr baseAddr) : this(baseAddr, verify: true) { } public RVA ToRVA(FileOffset offset) { return peType.ToRVA(peInfo, offset); } public FileOffset ToFileOffset(RVA rva) { return peType.ToFileOffset(peInfo, rva); } public void Dispose() { IDisposable value; if (win32Resources.IsValueInitialized && (value = win32Resources.Value) != null) { value.Dispose(); } dataReaderFactory?.Dispose(); win32Resources.Value = null; dataReaderFactory = null; peType = null; peInfo = null; } public DataReader CreateReader(FileOffset offset) { return DataReaderFactory.CreateReader((uint)offset, (uint)(DataReaderFactory.Length - offset)); } public DataReader CreateReader(FileOffset offset, uint length) { return DataReaderFactory.CreateReader((uint)offset, length); } public DataReader CreateReader(RVA rva) { return CreateReader(ToFileOffset(rva)); } public DataReader CreateReader(RVA rva, uint length) { return CreateReader(ToFileOffset(rva), length); } public DataReader CreateReader() { return DataReaderFactory.CreateReader(); } void IInternalPEImage.UnsafeDisableMemoryMappedIO() { if (dataReaderFactory is MemoryMappedDataReaderFactory memoryMappedDataReaderFactory) { memoryMappedDataReaderFactory.UnsafeDisableMemoryMappedIO(); } } private ImageDebugDirectory[] ReadImageDebugDirectories() { try { ImageDataDirectory imageDataDirectory = ImageNTHeaders.OptionalHeader.DataDirectories[6]; if (imageDataDirectory.VirtualAddress == (RVA)0u) { return Array2.Empty<ImageDebugDirectory>(); } DataReader reader = DataReaderFactory.CreateReader(); if (imageDataDirectory.Size > reader.Length) { return Array2.Empty<ImageDebugDirectory>(); } int num = (int)(imageDataDirectory.Size / 28); if (num == 0) { return Array2.Empty<ImageDebugDirectory>(); } reader.CurrentOffset = (uint)ToFileOffset(imageDataDirectory.VirtualAddress); if ((ulong)((long)reader.CurrentOffset + (long)imageDataDirectory.Size) > (ulong)reader.Length) { return Array2.Empty<ImageDebugDirectory>(); } ImageDebugDirectory[] array = new ImageDebugDirectory[num]; for (int i = 0; i < array.Length; i++) { array[i] = new ImageDebugDirectory(ref reader, verify: true); } return array; } catch (IOException) { } return Array2.Empty<ImageDebugDirectory>(); } } internal sealed class PEInfo { private readonly ImageDosHeader imageDosHeader; private readonly ImageNTHeaders imageNTHeaders; private readonly ImageSectionHeader[] imageSectionHeaders; public ImageDosHeader ImageDosHeader => imageDosHeader; public ImageNTHeaders ImageNTHeaders => imageNTHeaders; public ImageSectionHeader[] ImageSectionHeaders => imageSectionHeaders; public PEInfo(ref DataReader reader, bool verify) { reader.Position = 0u; imageDosHeader = new ImageDosHeader(ref reader, verify); if (verify && imageDosHeader.NTHeadersOffset == 0) { throw new BadImageFormatException("Invalid NT headers offset"); } reader.Position = imageDosHeader.NTHeadersOffset; imageNTHeaders = new ImageNTHeaders(ref reader, verify); reader.Position = (uint)(imageNTHeaders.OptionalHeader.StartOffset + imageNTHeaders.FileHeader.SizeOfOptionalHeader); int num = imageNTHeaders.FileHeader.NumberOfSections; if (num > 0) { DataReader dataReader = reader; dataReader.Position += 20u; uint num2 = dataReader.ReadUInt32(); num = Math.Min(num, (int)((num2 - reader.Position) / 40)); } imageSectionHeaders = new ImageSectionHeader[num]; for (int i = 0; i < imageSectionHeaders.Length; i++) { imageSectionHeaders[i] = new ImageSectionHeader(ref reader, verify); } } public ImageSectionHeader ToImageSectionHeader(FileOffset offset) { ImageSectionHeader[] array = imageSectionHeaders; foreach (ImageSectionHeader imageSectionHeader in array) { if ((long)offset >= (long)imageSectionHeader.PointerToRawData && (long)offset < (long)(imageSectionHeader.PointerToRawData + imageSectionHeader.SizeOfRawData)) { return imageSectionHeader; } } return null; } public ImageSectionHeader ToImageSectionHeader(RVA rva) { ImageSectionHeader[] array = imageSectionHeaders; foreach (ImageSectionHeader imageSectionHeader in array) { if (rva >= imageSectionHeader.VirtualAddress && rva < imageSectionHeader.VirtualAddress + Math.Max(imageSectionHeader.VirtualSize, imageSectionHeader.SizeOfRawData)) { return imageSectionHeader; } } return null; } public RVA ToRVA(FileOffset offset) { ImageSectionHeader imageSectionHeader = ToImageSectionHeader(offset); if (imageSectionHeader != null) { return (RVA)((uint)(offset - imageSectionHeader.PointerToRawData) + (uint)imageSectionHeader.VirtualAddress); } return (RVA)offset; } public FileOffset ToFileOffset(RVA rva) { ImageSectionHeader imageSectionHeader = ToImageSectionHeader(rva); if (imageSectionHeader != null) { return (FileOffset)(rva - imageSectionHeader.VirtualAddress + imageSectionHeader.PointerToRawData); } return (FileOffset)rva; } private static ulong AlignUp(ulong val, uint alignment) { return (val + alignment - 1) & ~(ulong)(alignment - 1); } public uint GetImageSize() { IImageOptionalHeader optionalHeader = ImageNTHeaders.OptionalHeader; uint sectionAlignment = optionalHeader.SectionAlignment; ulong num = AlignUp(optionalHeader.SizeOfHeaders, sectionAlignment); ImageSectionHeader[] array = imageSectionHeaders; foreach (ImageSectionHeader imageSectionHeader in array) { ulong num2 = AlignUp((ulong)imageSectionHeader.VirtualAddress + (ulong)Math.Max(imageSectionHeader.VirtualSize, imageSectionHeader.SizeOfRawData), sectionAlignment); if (num2 > num) { num = num2; } } return (uint)Math.Min(num, 4294967295uL); } } internal static class ProcessorArchUtils { private static class RuntimeInformationUtils { private static Assembly RuntimeInformationAssembly => typeof(object).Assembly; private static Type System_Runtime_InteropServices_RuntimeInformation => RuntimeInformationAssembly.GetType("System.Runtime.InteropServices.RuntimeInformation", throwOnError: false); public static bool TryGet_RuntimeInformation_Architecture(out Machine machine) { machine = Machine.Unknown; MethodInfo methodInfo = System_Runtime_InteropServices_RuntimeInformation?.GetMethod("get_ProcessArchitecture", Array2.Empty<Type>()); if ((object)methodInfo == null) { return false; } return TryGetArchitecture((int)methodInfo.Invoke(null, Array2.Empty<object>()), out machine); } private static bool TryGetArchitecture(int architecture, out Machine machine) { switch (architecture) { case 0: machine = Machine.I386; return true; case 1: machine = Machine.AMD64; return true; case 2: machine = Machine.ARMNT; return true; case 3: machine = Machine.ARM64; return true; default: machine = Machine.Unknown; return false; } } } private static class WindowsUtils { private struct SYSTEM_INFO { public ushort wProcessorArchitecture; public ushort wReserved; public uint dwPageSize; public IntPtr lpMinimumApplicationAddress; public IntPtr lpMaximumApplicationAddress; public IntPtr dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public ushort wProcessorLevel; public ushort wProcessorRevision; } private enum ProcessorArchitecture : ushort { INTEL = 0, ARM = 5, IA64 = 6, AMD64 = 9, ARM64 = 12, UNKNOWN = ushort.MaxValue } private static bool canTryGetSystemInfo = true; [DllImport("kernel32")] private static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo); public static bool TryGetProcessCpuArchitecture(out Machine machine) { if (canTryGetSystemInfo) { try { GetSystemInfo(out var lpSystemInfo); switch ((ProcessorArchitecture)lpSystemInfo.wProcessorArchitecture) { case ProcessorArchitecture.INTEL: machine = Machine.I386; return true; case ProcessorArchitecture.ARM: machine = Machine.ARMNT; return true; case ProcessorArchitecture.IA64: machine = Machine.IA64; return true; case ProcessorArchitecture.AMD64: machine = Machine.AMD64; return true; case ProcessorArchitecture.ARM64: machine = Machine.ARM64; return true; } } catch (EntryPointNotFoundException) { canTryGetSystemInfo = false; } catch (DllNotFoundException) { canTryGetSystemInfo = false; } } machine = Machine.Unknown; return false; } } private static Machine cachedMachine; public static Machine GetProcessCpuArchitecture() { if (cachedMachine == Machine.Unknown) { cachedMachine = GetProcessCpuArchitectureCore(); } return cachedMachine; } private static Machine GetProcessCpuArchitectureCore() { if (WindowsUtils.TryGetProcessCpuArchitecture(out var machine)) { return machine; } try { if (RuntimeInformationUtils.TryGet_RuntimeInformation_Architecture(out machine)) { return machine; } } catch (PlatformNotSupportedException) { } if (IntPtr.Size != 4) { return Machine.AMD64; } return Machine.I386; } } public enum RVA : uint { } public enum Subsystem : ushort { Unknown = 0, Native = 1, WindowsGui = 2, WindowsCui = 3, Os2Cui = 5, PosixCui = 7, NativeWindows = 8, WindowsCeGui = 9, EfiApplication = 10, EfiBootServiceDriver = 11, EfiRuntimeDriver = 12, EfiRom = 13, Xbox = 14, WindowsBootApplication = 16 } } namespace dnlib.IO { internal sealed class AlignedByteArrayDataStream : DataStream { private readonly byte[] data; public AlignedByteArrayDataStream(byte[] data) { this.data = data; } public unsafe override void ReadBytes(uint offset, void* destination, int length) { Marshal.Copy(data, (int)offset, (IntPtr)destination, length); } public override void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length) { Array.Copy(data, (int)offset, destination, destinationIndex, length); } public override byte ReadByte(uint offset) { return data[offset]; } public override ushort ReadUInt16(uint offset) { int num = (int)offset; byte[] array = data; return (ushort)(array[num++] | (array[num] << 8)); } public override uint ReadUInt32(uint offset) { int num = (int)offset; byte[] array = data; return (uint)(array[num++] | (array[num++] << 8) | (array[num++] << 16) | (array[num] << 24)); } public override ulong ReadUInt64(uint offset) { int num = (int)offset; byte[] array = data; return array[num++] | ((ulong)array[num++] << 8) | ((ulong)array[num++] << 16) | ((ulong)array[num++] << 24) | ((ulong)array[num++] << 32) | ((ulong)array[num++] << 40) | ((ulong)array[num++] << 48) | ((ulong)array[num] << 56); } public unsafe override float ReadSingle(uint offset) { int num = (int)offset; byte[] array = data; uint num2 = (uint)(array[num++] | (array[num++] << 8) | (array[num++] << 16) | (array[num] << 24)); return *(float*)(&num2); } public unsafe override double ReadDouble(uint offset) { int num = (int)offset; byte[] array = data; ulong num2 = array[num++] | ((ulong)array[num++] << 8) | ((ulong)array[num++] << 16) | ((ulong)array[num++] << 24) | ((ulong)array[num++] << 32) | ((ulong)array[num++] << 40) | ((ulong)array[num++] << 48) | ((ulong)array[num] << 56); return *(double*)(&num2); } public unsafe override string ReadUtf16String(uint offset, int chars) { fixed (byte* ptr = data) { return new string((char*)(ptr + offset), 0, chars); } } public unsafe override string ReadString(uint offset, int length, Encoding encoding) { fixed (byte* ptr = data) { return new string((sbyte*)(ptr + offset), 0, length, encoding); } } public unsafe override bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset) { fixed (byte* ptr = data) { byte* ptr2 = ptr + offset; uint num = (endOffset - offset) / 4; for (uint num2 = 0u; num2 < num; num2++) { if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; } for (byte* ptr3 = ptr + endOffset; ptr2 != ptr3; ptr2++) { if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } } valueOffset = 0u; return false; } } } internal sealed class AlignedNativeMemoryDataStream : DataStream { private unsafe readonly byte* data; public unsafe AlignedNativeMemoryDataStream(byte* data) { this.data = data; } public unsafe override void ReadBytes(uint offset, void* destination, int length) { byte* ptr = data + offset; byte* ptr2 = (byte*)destination; int num = length / 4; length %= 4; for (int i = 0; i < num; i++) { *ptr2 = *ptr; ptr2++; ptr++; *ptr2 = *ptr; ptr2++; ptr++; *ptr2 = *ptr; ptr2++; ptr++; *ptr2 = *ptr; ptr2++; ptr++; } int num2 = 0; while (num2 < length) { *ptr2 = *ptr; num2++; ptr++; ptr2++; } } public unsafe override void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length) { Marshal.Copy((IntPtr)(data + offset), destination, destinationIndex, length); } public unsafe override byte ReadByte(uint offset) { return data[offset]; } public unsafe override ushort ReadUInt16(uint offset) { byte* ptr = data + offset; return (ushort)(*(ptr++) | (*ptr << 8)); } public unsafe override uint ReadUInt32(uint offset) { byte* ptr = data + offset; return (uint)(*(ptr++) | (*(ptr++) << 8) | (*(ptr++) << 16) | (*ptr << 24)); } public unsafe override ulong ReadUInt64(uint offset) { byte* ptr = data + offset; return *(ptr++) | ((ulong)(*(ptr++)) << 8) | ((ulong)(*(ptr++)) << 16) | ((ulong)(*(ptr++)) << 24) | ((ulong)(*(ptr++)) << 32) | ((ulong)(*(ptr++)) << 40) | ((ulong)(*(ptr++)) << 48) | ((ulong)(*ptr) << 56); } public unsafe override float ReadSingle(uint offset) { byte* ptr = data + offset; uint num = (uint)(*(ptr++) | (*(ptr++) << 8) | (*(ptr++) << 16) | (*ptr << 24)); return *(float*)(&num); } public unsafe override double ReadDouble(uint offset) { byte* ptr = data + offset; ulong num = *(ptr++) | ((ulong)(*(ptr++)) << 8) | ((ulong)(*(ptr++)) << 16) | ((ulong)(*(ptr++)) << 24) | ((ulong)(*(ptr++)) << 32) | ((ulong)(*(ptr++)) << 40) | ((ulong)(*(ptr++)) << 48) | ((ulong)(*ptr) << 56); return *(double*)(&num); } public unsafe override string ReadUtf16String(uint offset, int chars) { return new string((char*)(data + offset), 0, chars); } public unsafe override string ReadString(uint offset, int length, Encoding encoding) { return new string((sbyte*)(data + offset), 0, length, encoding); } public unsafe override bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset) { byte* ptr = data; byte* ptr2 = ptr + offset; uint num = (endOffset - offset) / 4; for (uint num2 = 0u; num2 < num; num2++) { if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } ptr2++; } for (byte* ptr3 = ptr + endOffset; ptr2 != ptr3; ptr2++) { if (*ptr2 == value) { valueOffset = (uint)(ptr2 - ptr); return true; } } valueOffset = 0u; return false; } } public sealed class ByteArrayDataReaderFactory : DataReaderFactory { private DataStream stream; private string filename; private uint length; private byte[] data; public override string Filename => filename; public override uint Length => length; internal byte[] DataArray => data; internal uint DataOffset => 0u; private ByteArrayDataReaderFactory(byte[] data, string filename) { this.filename = filename; length = (uint)data.Length; stream = DataStreamFactory.Create(data); this.data = data; } public static ByteArrayDataReaderFactory Create(byte[] data, string filename) { if (data == null) { throw new ArgumentNullException("data"); } return new ByteArrayDataReaderFactory(data, filename); } public static DataReader CreateReader(byte[] data) { return Create(data, null).CreateReader(); } public override DataReader CreateReader(uint offset, uint length) { return CreateReader(stream, offset, length); } public override void Dispose() { stream = EmptyDataStream.Instance; length = 0u; filename = null; data = null; } } [Serializable] public sealed class DataReaderException : IOException { internal DataReaderException(string message) : base(message) { } internal DataReaderException(SerializationInfo info, StreamingContext context) : base(info, context) { } } [DebuggerDisplay("{StartOffset,h}-{EndOffset,h} Length={Length} BytesLeft={BytesLeft}")] public struct DataReader { private readonly DataStream stream; private readonly uint startOffset; private readonly uint endOffset; private uint currentOffset; public uint StartOffset => startOffset; public uint EndOffset => endOffset; public uint Length => endOffset - startOffset; public uint CurrentOffset { get { return currentOffset; } set { if (value < startOffset || value > endOffset) { ThrowDataReaderException("Invalid new CurrentOffset"); } currentOffset = value; } } public uint Position { get { return currentOffset - startOffset; } set { if (value > Length) { ThrowDataReaderException("Invalid new Position"); } currentOffset = startOffset + value; } } public uint BytesLeft => endOffset - currentOffset; public DataReader(DataStream stream, uint offset, uint length) { this.stream = stream; startOffset = offset; endOffset = offset + length; currentOffset = offset; } [Conditional("DEBUG")] private void VerifyState() { } private static void ThrowNoMoreBytesLeft() { throw new DataReaderException("There's not enough bytes left to read"); } private static void ThrowDataReaderException(string message) { throw new DataReaderException(message); } private static void ThrowInvalidOperationException() { throw new InvalidOperationException(); } private static void ThrowArgumentNullException(string paramName) { throw new ArgumentNullException(paramName); } private static void ThrowInvalidArgument(string paramName) { throw new DataReaderException("Invalid argument value"); } public void Reset() { currentOffset = startOffset; } public DataReader Slice(uint start, uint length) { if ((ulong)((long)start + (long)length) > (ulong)Length) { ThrowInvalidArgument("length"); } return new DataReader(stream, startOffset + start, length); } public DataReader Slice(uint start) { if (start > Length) { ThrowInvalidArgument("start"); } return Slice(start, Length - start); } public DataReader Slice(int start, int length) { if (start < 0) { ThrowInvalidArgument("start"); } if (length < 0) { ThrowInvalidArgument("length"); } return Slice((uint)start, (uint)length); } public DataReader Slice(int start) { if (start < 0) { ThrowInvalidArgument("start"); } if ((uint)start > Length) { ThrowInvalidArgument("start"); } return Slice((uint)start, Length - (uint)start); } public bool CanRead(int length) { if (length >= 0) { return (uint)length <= BytesLeft; } return false; } public bool CanRead(uint length) { return length <= BytesLeft; } public bool ReadBoolean() { return ReadByte() != 0; } public char ReadChar() { return (char)ReadUInt16(); } public sbyte ReadSByte() { return (sbyte)ReadByte(); } public byte ReadByte() { uint num = currentOffset; if (num == endOffset) { ThrowNoMoreBytesLeft(); } byte result = stream.ReadByte(num); currentOffset = num + 1; return result; } public short ReadInt16() { return (short)ReadUInt16(); } public ushort ReadUInt16() { uint num = currentOffset; if (endOffset - num < 2) { ThrowNoMoreBytesLeft(); } ushort result = stream.ReadUInt16(num); currentOffset = num + 2; return result; } public int ReadInt32() { return (int)ReadUInt32(); } public uint ReadUInt32() { uint num = currentOffset; if (endOffset - num < 4) { ThrowNoMoreBytesLeft(); } uint result = stream.ReadUInt32(num); currentOffset = num + 4; return result; } internal byte Unsafe_ReadByte() { uint num = currentOffset; byte result = stream.ReadByte(num); currentOffset = num + 1; return result; } internal ushort Unsafe_ReadUInt16() { uint num = currentOffset; ushort result = stream.ReadUInt16(num); currentOffset = num + 2; return result; } internal uint Unsafe_ReadUInt32() { uint num = currentOffset; uint result = stream.ReadUInt32(num); currentOffset = num + 4; return result; } public long ReadInt64() { return (long)ReadUInt64(); } public ulong ReadUInt64() { uint num = currentOffset; if (endOffset - num < 8) { ThrowNoMoreBytesLeft(); } ulong result = stream.ReadUInt64(num); currentOffset = num + 8; return result; } public float ReadSingle() { uint num = currentOffset; if (endOffset - num < 4) { ThrowNoMoreBytesLeft(); } float result = stream.ReadSingle(num); currentOffset = num + 4; return result; } public double ReadDouble() { uint num = currentOffset; if (endOffset - num < 8) { ThrowNoMoreBytesLeft(); } double result = stream.ReadDouble(num); currentOffset = num + 8; return result; } public Guid ReadGuid() { uint num = currentOffset; if (endOffset - num < 16) { ThrowNoMoreBytesLeft(); } Guid result = stream.ReadGuid(num); currentOffset = num + 16; return result; } public decimal ReadDecimal() { return new decimal(new int[4] { ReadInt32(), ReadInt32(), ReadInt32(), ReadInt32() }); } public string ReadUtf16String(int chars) { if (chars < 0) { ThrowInvalidArgument("chars"); } if (chars == 0) { return string.Empty; } uint num = (uint)(chars * 2); uint num2 = currentOffset; if (endOffset - num2 < num) { ThrowNoMoreBytesLeft(); } string result = ((num == 0) ? string.Empty : stream.ReadUtf16String(num2, chars)); currentOffset = num2 + num; return result; } public unsafe void ReadBytes(void* destination, int length) { if (destination == null && length != 0) { ThrowArgumentNullException("destination"); } if (length < 0) { ThrowInvalidArgument("length"); } if (length != 0) { uint num = currentOffset; if (endOffset - num < (uint)length) { ThrowNoMoreBytesLeft(); } stream.ReadBytes(num, destination, length); currentOffset = num + (uint)length; } } public void ReadBytes(byte[] destination, int destinationIndex, int length) { if (destination == null) { ThrowArgumentNullException("destination"); } if (destinationIndex < 0) { ThrowInvalidArgument("destinationIndex"); } if (length < 0) { ThrowInvalidArgument("length"); } if (length != 0) { uint num = currentOffset; if (endOffset - num < (uint)length) { ThrowNoMoreBytesLeft(); } stream.ReadBytes(num, destination, destinationIndex, length); currentOffset = num + (uint)length; } } public byte[] ReadBytes(int length) { if (length < 0) { ThrowInvalidArgument("length"); } if (length == 0) { return Array2.Empty<byte>(); } byte[] array = new byte[length]; ReadBytes(array, 0, length); return array; } public bool TryReadCompressedUInt32(out uint value) { uint num = currentOffset; uint num2 = endOffset - num; if (num2 == 0) { value = 0u; return false; } DataStream dataStream = stream; byte b = dataStream.ReadByte(num++); if ((b & 0x80) == 0) { value = b; currentOffset = num; return true; } if ((b & 0xC0) == 128) { if (num2 < 2) { value = 0u; return false; } value = (uint)(((b & 0x3F) << 8) | dataStream.ReadByte(num++)); currentOffset = num; return true; } if (num2 < 4) { value = 0u; return false; } value = (uint)(((b & 0x1F) << 24) | (dataStream.ReadByte(num++) << 16) | (dataStream.ReadByte(num++) << 8) | dataStream.ReadByte(num++)); currentOffset = num; return true; } public uint ReadCompressedUInt32() { if (!TryReadCompressedUInt32(out var value)) { ThrowNoMoreBytesLeft(); } return value; } public bool TryReadCompressedInt32(out int value) { uint num = currentOffset; uint num2 = endOffset - num; if (num2 == 0) { value = 0; return false; } DataStream dataStream = stream; byte b = dataStream.ReadByte(num++); if ((b & 0x80) == 0) { if (((uint)b & (true ? 1u : 0u)) != 0) { value = -64 | (b >> 1); } else { value = b >> 1; } currentOffset = num; return true; } if ((b & 0xC0) == 128) { if (num2 < 2) { value = 0; return false; } uint num3 = (uint)(((b & 0x3F) << 8) | dataStream.ReadByte(num++)); if ((num3 & (true ? 1u : 0u)) != 0) { value = -8192 | (int)(num3 >> 1); } else { value = (int)(num3 >> 1); } currentOffset = num; return true; } if ((b & 0xE0) == 192) { if (num2 < 4) { value = 0; return false; } uint num4 = (uint)(((b & 0x1F) << 24) | (dataStream.ReadByte(num++) << 16) | (dataStream.ReadByte(num++) << 8) | dataStream.ReadByte(num++)); if ((num4 & (true ? 1u : 0u)) != 0) { value = -268435456 | (int)(num4 >> 1); } else { value = (int)(num4 >> 1); } currentOffset = num; return true; } value = 0; return false; } public int ReadCompressedInt32() { if (!TryReadCompressedInt32(out var value)) { ThrowNoMoreBytesLeft(); } return value; } public uint Read7BitEncodedUInt32() { uint num = 0u; int num2 = 0; for (int i = 0; i < 5; i++) { byte b = ReadByte(); num |= (uint)((b & 0x7F) << num2); if ((b & 0x80) == 0) { return num; } num2 += 7; } ThrowDataReaderException("Invalid encoded UInt32"); return 0u; } public int Read7BitEncodedInt32() { return (int)Read7BitEncodedUInt32(); } public string ReadSerializedString() { return ReadSerializedString(Encoding.UTF8); } public string ReadSerializedString(Encoding encoding) { if (encoding == null) { ThrowArgumentNullException("encoding"); } int num = Read7BitEncodedInt32(); if (num < 0) { ThrowNoMoreBytesLeft(); } if (num == 0) { return string.Empty; } return ReadString(num, encoding); } public byte[] ToArray() { int length = (int)Length; if (length < 0) { ThrowInvalidOperationException(); } if (length == 0) { return Array2.Empty<byte>(); } byte[] array = new byte[length]; stream.ReadBytes(startOffset, array, 0, array.Length); return array; } public byte[] ReadRemainingBytes() { int bytesLeft = (int)BytesLeft; if (bytesLeft < 0) { ThrowInvalidOperationException(); } return ReadBytes(bytesLeft); } public byte[] TryReadBytesUntil(byte value) { uint num = currentOffset; uint num2 = endOffset; if (num == num2) { return null; } if (!stream.TryGetOffsetOf(num, num2, value, out var valueOffset)) { return null; } int num3 = (int)(valueOffset - num); if (num3 < 0) { return null; } return ReadBytes(num3); } public string TryReadZeroTerminatedUtf8String() { return TryReadZeroTerminatedString(Encoding.UTF8); } public string TryReadZeroTerminatedString(Encoding encoding) { if (encoding == null) { ThrowArgumentNullException("encoding"); } uint num = currentOffset; uint num2 = endOffset; if (num == num2) { return null; } if (!stream.TryGetOffsetOf(num, num2, 0, out var valueOffset)) { return null; } int num3 = (int)(valueOffset - num); if (num3 < 0) { return null; } string result = ((num3 == 0) ? string.Empty : stream.ReadString(num, num3, encoding)); currentOffset = valueOffset + 1; return result; } public string ReadUtf8String(int byteCount) { return ReadString(byteCount, Encoding.UTF8); } public string ReadString(int byteCount, Encoding encoding) { if (byteCount < 0) { ThrowInvalidArgument("byteCount"); } if (encoding == null) { ThrowArgumentNullException("encoding"); } if (byteCount == 0) { return string.Empty; } if ((uint)byteCount > Length) { ThrowInvalidArgument("byteCount"); } uint num = currentOffset; string result = stream.ReadString(num, byteCount, encoding); currentOffset = num + (uint)byteCount; return result; } public Stream AsStream() { return new DataReaderStream(ref this); } private byte[] AllocTempBuffer() { return new byte[Math.Min(8192u, BytesLeft)]; } public void CopyTo(DataWriter destination) { if (destination == null) { ThrowArgumentNullException("destination"); } if (Position < Length) { CopyTo(destination.InternalStream, AllocTempBuffer()); } } public void CopyTo(DataWriter destination, byte[] dataBuffer) { if (destination == null) { ThrowArgumentNullException("destination"); } CopyTo(destination.InternalStream, dataBuffer); } public void CopyTo(BinaryWriter destination) { if (destination == null) { ThrowArgumentNullException("destination"); } if (Position < Length) { CopyTo(destination.BaseStream, AllocTempBuffer()); } } public void CopyTo(BinaryWriter destination, byte[] dataBuffer) { if (destination == null) { ThrowArgumentNullException("destination"); } CopyTo(destination.BaseStream, dataBuffer); } public void CopyTo(Stream destination) { if (destination == null) { ThrowArgumentNullException("destination"); } if (Position < Length) { CopyTo(destination, AllocTempBuffer()); } } public void CopyTo(Stream destination, byte[] dataBuffer) { if (destination == null) { ThrowArgumentNullException("destination"); } if (dataBuffer == null) { ThrowArgumentNullException("dataBuffer"); } if (Position < Length) { if (dataBuffer.Length == 0) { ThrowInvalidArgument("dataBuffer"); } uint num = BytesLeft; while (num != 0) { int num2 = (int)Math.Min((uint)dataBuffer.Length, num); num -= (uint)num2; ReadBytes(dataBuffer, 0, num2); destination.Write(dataBuffer, 0, num2); } } } } public abstract class DataReaderFactory : IDisposable { public abstract string Filename { get; } public abstract uint Length { get; } public virtual event EventHandler DataReaderInvalidated { add { } remove { } } public DataReader CreateReader() { return CreateReader(0u, Length); } public abstract DataReader CreateReader(uint offset, uint length); private static void ThrowArgumentOutOfRangeException(string paramName) { throw new ArgumentOutOfRangeException(paramName); } private static void Throw_CreateReader_2(int offset, int length) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } throw new ArgumentOutOfRangeException("length"); } public DataReader CreateReader(uint offset, int length) { if (length < 0) { ThrowArgumentOutOfRangeException("length"); } return CreateReader(offset, (uint)length); } public DataReader CreateReader(int offset, uint length) { if (offset < 0) { ThrowArgumentOutOfRangeException("offset"); } return CreateReader((uint)offset, length); } public DataReader CreateReader(int offset, int length) { if (offset < 0 || length < 0) { Throw_CreateReader_2(offset, length); } return CreateReader((uint)offset, (uint)length); } protected DataReader CreateReader(DataStream stream, uint offset, uint length) { uint length2 = Length; if (offset > length2) { offset = length2; } if ((ulong)((long)offset + (long)length) > (ulong)length2) { length = length2 - offset; } return new DataReader(stream, offset, length); } public abstract void Dispose(); } internal static class DataReaderFactoryFactory { private static readonly bool isUnix; static DataReaderFactoryFactory() { int platform = (int)Environment.OSVersion.Platform; if (platform == 4 || platform == 6 || platform == 128) { isUnix = true; } } public static DataReaderFactory Create(string fileName, bool mapAsImage) { DataReaderFactory dataReaderFactory = CreateDataReaderFactory(fileName, mapAsImage); if (dataReaderFactory != null) { return dataReaderFactory; } return ByteArrayDataReaderFactory.Create(File.ReadAllBytes(fileName), fileName); } private static DataReaderFactory CreateDataReaderFactory(string fileName, bool mapAsImage) { if (!isUnix) { return MemoryMappedDataReaderFactory.CreateWindows(fileName, mapAsImage); } return MemoryMappedDataReaderFactory.CreateUnix(fileName, mapAsImage); } } internal sealed class DataReaderStream : Stream { private DataReader reader; private long position; public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; public override long Length => reader.Length; public override long Position { get { return position; } set { position = value; } } public DataReaderStream(ref DataReader reader) { this.reader = reader; position = reader.Position; } public override void Flush() { } private bool CheckAndSetPosition() { if (position < 0 || position > reader.Length) { return false; } reader.Position = (uint)position; return true; } public override long Seek(long offset, SeekOrigin origin) { switch (origin) { case SeekOrigin.Begin: Position = offset; break; case SeekOrigin.Current: Position += offset; break; case SeekOrigin.End: Position = Length + offset; break; } return Position; } public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (!CheckAndSetPosition()) { return 0; } int num = (int)Math.Min((uint)count, reader.BytesLeft); reader.ReadBytes(buffer, offset, num); Position += num; return num; } public override int ReadByte() { if (!CheckAndSetPosition() || !reader.CanRead(1u)) { return -1; } Position++; return reader.ReadByte(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } public abstract class DataStream { public unsafe abstract void ReadBytes(uint offset, void* destination, int length); public abstract void ReadBytes(uint offset, byte[] destination, int destinationIndex, int length); public abstract byte ReadByte(uint offset); public abstract ushort ReadUInt16(uint offset); public abstract uint ReadUInt32(uint offset); public abstract ulong ReadUInt64(uint offset); public abstract float ReadSingle(uint offset); public abstract double ReadDouble(uint offset); public virtual Guid ReadGuid(uint offset) { return new Guid(ReadUInt32(offset), ReadUInt16(offset + 4), ReadUInt16(offset + 6), ReadByte(offset + 8), ReadByte(offset + 9), ReadByte(offset + 10), ReadByte(offset + 11), ReadByte(offset + 12), ReadByte(offset + 13), ReadByte(offset + 14), ReadByte(offset + 15)); } public abstract string ReadUtf16String(uint offset, int chars); public abstract string ReadString(uint offset, int length, Encoding encoding); public abstract bool TryGetOffsetOf(uint offset, uint endOffset, byte value, out uint valueOffset); } public static class DataStreamFactory { private static bool supportsUnalignedAccesses = CalculateSupportsUnalignedAccesses(); private static bool CalculateSupportsUnalignedAccesses() { switch (ProcessorArchUtils.GetProcessCpuArchitecture()) { case Machine.I386: case Machine.AMD64: return true; case Machine.ARMNT: case Machine.ARM64: return false; default: return true; } } public unsafe static DataStream Create(byte* data) { if (data == null) { throw new ArgumentNullException("data"); } if (supportsUnali
UMM/Core/UnityModManager.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Xml.Serialization; using HarmonyLib; using Microsoft.CodeAnalysis; using TinyJson; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UnityModManagerNet; using dnlib.DotNet; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("newman55")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2019-2025")] [assembly: AssemblyDescription("Mod manager for Unity games.")] [assembly: AssemblyFileVersion("0.32.4")] [assembly: AssemblyInformationalVersion("0.32.4+e166d51d08c558c16332a1fbfb6a207746110663")] [assembly: AssemblyProduct("UnityModManager")] [assembly: AssemblyTitle("UnityModManager")] [assembly: NeutralResourcesLanguage("en-001")] [assembly: AssemblyVersion("0.32.4.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TinyJson { public static class JSONParser { [ThreadStatic] private static Stack<List<string>> splitArrayPool; [ThreadStatic] private static StringBuilder stringBuilder; [ThreadStatic] private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache; [ThreadStatic] private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache; public static T FromJson<T>(this string json) { if (propertyInfoCache == null) { propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); } if (fieldInfoCache == null) { fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>(); } if (stringBuilder == null) { stringBuilder = new StringBuilder(); } if (splitArrayPool == null) { splitArrayPool = new Stack<List<string>>(); } stringBuilder.Length = 0; for (int i = 0; i < json.Length; i++) { char c = json[i]; if (c == '"') { i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json); } else if (!char.IsWhiteSpace(c)) { stringBuilder.Append(c); } } return (T)ParseValue(typeof(T), stringBuilder.ToString()); } private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json) { stringBuilder.Append(json[startIdx]); for (int i = startIdx + 1; i < json.Length; i++) { if (json[i] == '\\') { if (appendEscapeCharacter) { stringBuilder.Append(json[i]); } stringBuilder.Append(json[i + 1]); i++; } else { if (json[i] == '"') { stringBuilder.Append(json[i]); return i; } stringBuilder.Append(json[i]); } } return json.Length - 1; } private static List<string> Split(string json) { List<string> list = ((splitArrayPool.Count > 0) ? splitArrayPool.Pop() : new List<string>()); list.Clear(); if (json.Length == 2) { return list; } int num = 0; stringBuilder.Length = 0; for (int i = 1; i < json.Length - 1; i++) { switch (json[i]) { case '[': case '{': num++; break; case ']': case '}': num--; break; case '"': i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json); continue; case ',': case ':': if (num == 0) { list.Add(stringBuilder.ToString()); stringBuilder.Length = 0; continue; } break; } stringBuilder.Append(json[i]); } list.Add(stringBuilder.ToString()); return list; } internal static object ParseValue(Type type, string json) { if ((object)type == typeof(string)) { if (json.Length <= 2) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(json.Length); for (int i = 1; i < json.Length - 1; i++) { if (json[i] == '\\' && i + 1 < json.Length - 1) { int num = "\"\\nrtbf/".IndexOf(json[i + 1]); if (num >= 0) { stringBuilder.Append("\"\\\n\r\t\b\f/"[num]); i++; continue; } if (json[i + 1] == 'u' && i + 5 < json.Length - 1) { uint result = 0u; if (uint.TryParse(json.Substring(i + 2, 4), NumberStyles.AllowHexSpecifier, null, out result)) { stringBuilder.Append((char)result); i += 5; continue; } } } stringBuilder.Append(json[i]); } return stringBuilder.ToString(); } if (type.IsPrimitive) { return Convert.ChangeType(json, type, CultureInfo.InvariantCulture); } if ((object)type == typeof(decimal)) { decimal.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2); return result2; } if (json == "null") { return null; } if (type.IsEnum) { if (json[0] == '"') { json = json.Substring(1, json.Length - 2); } try { return Enum.Parse(type, json, ignoreCase: false); } catch { return 0; } } if (type.IsArray) { Type elementType = type.GetElementType(); if (json[0] != '[' || json[json.Length - 1] != ']') { return null; } List<string> list = Split(json); Array array = Array.CreateInstance(elementType, list.Count); for (int j = 0; j < list.Count; j++) { array.SetValue(ParseValue(elementType, list[j]), j); } splitArrayPool.Push(list); return array; } if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(List<>)) { Type type2 = type.GetGenericArguments()[0]; if (json[0] != '[' || json[json.Length - 1] != ']') { return null; } List<string> list2 = Split(json); IList list3 = (IList)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list2.Count }); for (int k = 0; k < list2.Count; k++) { list3.Add(ParseValue(type2, list2[k])); } splitArrayPool.Push(list2); return list3; } if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { Type[] genericArguments = type.GetGenericArguments(); Type type3 = genericArguments[0]; Type type4 = genericArguments[1]; if ((object)type3 != typeof(string)) { return null; } if (json[0] != '{' || json[json.Length - 1] != '}') { return null; } List<string> list4 = Split(json); if (list4.Count % 2 != 0) { return null; } IDictionary dictionary = (IDictionary)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list4.Count / 2 }); for (int l = 0; l < list4.Count; l += 2) { if (list4[l].Length > 2) { string key = list4[l].Substring(1, list4[l].Length - 2); object value = ParseValue(type4, list4[l + 1]); dictionary.Add(key, value); } } return dictionary; } if ((object)type == typeof(object)) { return ParseAnonymousValue(json); } if (json[0] == '{' && json[json.Length - 1] == '}') { return ParseObject(type, json); } return null; } private static object ParseAnonymousValue(string json) { if (json.Length == 0) { return null; } if (json[0] == '{' && json[json.Length - 1] == '}') { List<string> list = Split(json); if (list.Count % 2 != 0) { return null; } Dictionary<string, object> dictionary = new Dictionary<string, object>(list.Count / 2); for (int i = 0; i < list.Count; i += 2) { dictionary.Add(list[i].Substring(1, list[i].Length - 2), ParseAnonymousValue(list[i + 1])); } return dictionary; } if (json[0] == '[' && json[json.Length - 1] == ']') { List<string> list2 = Split(json); List<object> list3 = new List<object>(list2.Count); for (int j = 0; j < list2.Count; j++) { list3.Add(ParseAnonymousValue(list2[j])); } return list3; } if (json[0] == '"' && json[json.Length - 1] == '"') { return json.Substring(1, json.Length - 2).Replace("\\", string.Empty); } if (char.IsDigit(json[0]) || json[0] == '-') { if (json.Contains(".")) { double.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result); return result; } int.TryParse(json, out var result2); return result2; } if (json == "true") { return true; } if (json == "false") { return false; } return null; } private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo { Dictionary<string, T> dictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase); foreach (T val in members) { string name = val.Name; if (val.GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length == 0) { dictionary.Add(name, val); } } return dictionary; } private static object ParseObject(Type type, string json) { object uninitializedObject = FormatterServices.GetUninitializedObject(type); List<string> list = Split(json); if (list.Count % 2 != 0) { return uninitializedObject; } if (!fieldInfoCache.TryGetValue(type, out var value)) { value = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); fieldInfoCache.Add(type, value); } if (!propertyInfoCache.TryGetValue(type, out var value2)) { value2 = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)); propertyInfoCache.Add(type, value2); } for (int i = 0; i < list.Count; i += 2) { if (list[i].Length > 2) { string key = list[i].Substring(1, list[i].Length - 2); string json2 = list[i + 1]; PropertyInfo value4; if (value.TryGetValue(key, out var value3)) { value3.SetValue(uninitializedObject, ParseValue(value3.FieldType, json2)); } else if (value2.TryGetValue(key, out value4)) { value4.SetValue(uninitializedObject, ParseValue(value4.PropertyType, json2), null); } } } return uninitializedObject; } } public static class JSONWriter { public static string ToJson(this object item) { StringBuilder stringBuilder = new StringBuilder(); AppendValue(stringBuilder, item); return stringBuilder.ToString(); } private static void AppendValue(StringBuilder stringBuilder, object item) { if (item == null) { stringBuilder.Append("null"); return; } Type type = item.GetType(); if ((object)type == typeof(string)) { stringBuilder.Append('"'); string text = (string)item; for (int i = 0; i < text.Length; i++) { if (text[i] < ' ' || text[i] == '"' || text[i] == '\\') { stringBuilder.Append('\\'); int num = "\"\\\n\r\t\b\f".IndexOf(text[i]); if (num >= 0) { stringBuilder.Append("\"\\nrtbf"[num]); } else { stringBuilder.AppendFormat("u{0:X4}", (uint)text[i]); } } else { stringBuilder.Append(text[i]); } } stringBuilder.Append('"'); return; } if ((object)type == typeof(byte) || (object)type == typeof(int)) { stringBuilder.Append(item.ToString()); return; } if ((object)type == typeof(float)) { stringBuilder.Append(((float)item).ToString(CultureInfo.InvariantCulture)); return; } if ((object)type == typeof(double)) { stringBuilder.Append(((double)item).ToString(CultureInfo.InvariantCulture)); return; } if ((object)type == typeof(bool)) { stringBuilder.Append(((bool)item) ? "true" : "false"); return; } if (type.IsEnum) { stringBuilder.Append('"'); stringBuilder.Append(item.ToString()); stringBuilder.Append('"'); return; } if (item is IList) { stringBuilder.Append('['); bool flag = true; IList list = item as IList; for (int j = 0; j < list.Count; j++) { if (flag) { flag = false; } else { stringBuilder.Append(','); } AppendValue(stringBuilder, list[j]); } stringBuilder.Append(']'); return; } if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { if ((object)type.GetGenericArguments()[0] != typeof(string)) { stringBuilder.Append("{}"); return; } stringBuilder.Append('{'); IDictionary dictionary = item as IDictionary; bool flag2 = true; foreach (object key in dictionary.Keys) { if (flag2) { flag2 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append((string)key); stringBuilder.Append("\":"); AppendValue(stringBuilder, dictionary[key]); } stringBuilder.Append('}'); return; } stringBuilder.Append('{'); bool flag3 = true; FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); for (int k = 0; k < fields.Length; k++) { if (fields[k].GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length != 0) { continue; } object value = fields[k].GetValue(item); if (value != null) { if (flag3) { flag3 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append(GetMemberName(fields[k])); stringBuilder.Append("\":"); AppendValue(stringBuilder, value); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); for (int l = 0; l < properties.Length; l++) { if (properties[l].GetCustomAttributes(typeof(IgnoreJsonAttribute), inherit: false).Length != 0) { continue; } object value2 = properties[l].GetValue(item, null); if (value2 != null) { if (flag3) { flag3 = false; } else { stringBuilder.Append(','); } stringBuilder.Append('"'); stringBuilder.Append(GetMemberName(properties[l])); stringBuilder.Append("\":"); AppendValue(stringBuilder, value2); } } stringBuilder.Append('}'); } private static string GetMemberName(MemberInfo member) { return member.Name; } } public class IgnoreJsonAttribute : Attribute { } } namespace Doorstop { public class Entrypoint { public static void Start() { UnityModManager.Main(); } } } namespace UnityModManagerNet { public class UnityModManager { public sealed class Param { [Serializable] public class Mod { [XmlAttribute] public string Id; [XmlAttribute] public bool Enabled = true; public KeyBinding Hotkey = new KeyBinding(); } public static KeyBinding DefaultHotkey = new KeyBinding { keyCode = (KeyCode)291, modifiers = 1 }; public static KeyBinding EscapeHotkey = new KeyBinding { keyCode = (KeyCode)27 }; public KeyBinding Hotkey = new KeyBinding(); public int ShowOnStart = 1; public float WindowWidth; public float WindowHeight; public float UIScale = 1f; public string UIFont; public bool ShownModToggleWarning; public List<Mod> ModParams = new List<Mod>(); private static readonly string filepath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(Param).Assembly.Location), "../Config/UMM/Params.xml")); public void Save() { try { ModParams.Clear(); foreach (ModEntry modEntry in modEntries) { ModParams.Add(new Mod { Id = modEntry.Info.Id, Enabled = modEntry.Enabled, Hotkey = modEntry.Hotkey }); } Directory.CreateDirectory(Path.GetDirectoryName(filepath)); using StreamWriter textWriter = new StreamWriter(filepath); new XmlSerializer(typeof(Param)).Serialize(textWriter, this); } catch (Exception ex) { Logger.Error("Can't write file '" + filepath + "'."); Debug.LogException(ex); } } public static Param Load() { if (File.Exists(filepath)) { try { using FileStream stream = File.OpenRead(filepath); return new XmlSerializer(typeof(Param)).Deserialize(stream) as Param; } catch (Exception ex) { Logger.Error("Can't read file '" + filepath + "'."); Debug.LogException(ex); } } return new Param(); } internal void ReadModParams() { foreach (Mod modParam in ModParams) { ModEntry modEntry = FindMod(modParam.Id); if (modEntry != null) { modEntry.Enabled = modParam.Enabled; modEntry.Hotkey = ((modParam.Hotkey != null) ? modParam.Hotkey : new KeyBinding()); } } } } [XmlRoot("Param")] public sealed class InstallerParam { public string APIkey; public static InstallerParam Load() { string text = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityModManagerNet"), "Params.xml"); if (File.Exists(text)) { try { using FileStream stream = File.OpenRead(text); return new XmlSerializer(typeof(InstallerParam)).Deserialize(stream) as InstallerParam; } catch (Exception ex) { Logger.Error("Can't read file '" + text + "'."); Debug.LogException(ex); } } return new InstallerParam(); } } [XmlRoot("Config")] public class GameInfo { [XmlAttribute] public string ModsDirectory; public string RelativeModsDirectory = "../Mods"; public string ModInfo = "Info.json"; public string EntryPoint; public string StartingPoint; public string UIStartingPoint; public string TextureReplacingPoint; public string SessionStartPoint; public string SessionStopPoint; public string GameVersionPoint; public string MinimalManagerVersion; private static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Config.xml"); public static GameInfo Load() { try { if (File.Exists(filepath)) { using (FileStream stream = File.OpenRead(filepath)) { return new XmlSerializer(typeof(GameInfo)).Deserialize(stream) as GameInfo; } } return new GameInfo(); } catch (Exception ex) { Logger.Error("Can't read file '" + filepath + "'."); Debug.LogException(ex); return null; } } } private class GameScripts { private class GameScript { public virtual void OnModToggle(ModEntry modEntry, bool value) { } public virtual void OnBeforeLoadMods() { } public virtual void OnAfterLoadMods() { } public virtual void OnToggleWindow(bool value) { } } private static readonly List<GameScript> scripts = new List<GameScript>(); public static void Init() { } public static void OnBeforeLoadMods() { foreach (GameScript script in scripts) { try { script.OnBeforeLoadMods(); } catch (Exception e) { Logger.LogException("OnBeforeLoadMods", e); } } } public static void OnAfterLoadMods() { foreach (GameScript script in scripts) { try { script.OnAfterLoadMods(); } catch (Exception e) { Logger.LogException("OnAfterLoadMods", e); } } } public static void OnModToggle(ModEntry modEntry, bool value) { foreach (GameScript script in scripts) { try { script.OnModToggle(modEntry, value); } catch (Exception e) { Logger.LogException("OnModToggle", e); } } } public static void OnToggleWindow(bool value) { foreach (GameScript script in scripts) { try { script.OnToggleWindow(value); } catch (Exception e) { Logger.LogException("OnToggleWindow", e); } } } } private static class Textures { private static string WindowBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAEACAYAAACZCaebAAAAnElEQVRIS63MtQHDQADAwPdEZmaG/fdJCq2g7qqLvu/7hRBCZOF9X0ILz/MQWrjvm1DHdV3MFs7zJLRwHAehhX3fCS1s20ZoYV1XQgvLshDqmOeZ2cI0TYQWxnEktDAMA6GFvu8JLXRdR2ihbVtCHU3TMFuo65rQQlVVhBbKsiS0UBQFoYU8zwktZFlGqCNNU2YLSZIQWojjmFDCH22GtZAncD8TAAAAAElFTkSuQmCC"; private static string SettingsNormalBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAJsmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTY6MTI6NTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpiZTNlYTRkYy0zYjU4LTIxNDctOWQzMi04NmRiYTFjNmM4MjMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDoyMmYzNGE4Yy1jZjBiLTVkNDMtODRkYy05ODgyY2UyMTFhYTMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpiNjZhYTU5Ny1mODA5LTA0NGYtOWYzYi0wMTZlODdiODFkZjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmI2NmFhNTk3LWY4MDktMDQ0Zi05ZjNiLTAxNmU4N2I4MWRmMSIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNjoxMjo1MCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNGZjMTdlMS1jOWY3LTk5NDUtYmFkOC00NWZhNGI1MjgwNTgiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTg6MzI6MjcrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmZiYTVjMTY5LTkzNGItOGI0NS1hMjg3LTc2NzJkYjc1MjY2ZiIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxODozMjo0NiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YmUzZWE0ZGMtM2I1OC0yMTQ3LTlkMzItODZkYmExYzZjODIzIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE4OjMyOjQ2KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpmYmE1YzE2OS05MzRiLThiNDUtYTI4Ny03NjcyZGI3NTI2NmYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIiBzdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+KBN97QAAAGtJREFUOI3FkTESgCAMBDcOhX6ZHr+snZZy4MRBUbcLmYS7nCWAkYMVIWpJAGDJXgyXwW/XWNraBgIG5EOFpNJDs6RwttWj+YebkhTnBN/l4EjqlIPipvJ+Dl08CHN2s2h/Bac8lXRpmknLHSshDz5/7DVxAAAAAElFTkSuQmCC"; private static string SettingsActiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAJsmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTY6MTI6NTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowNTVkNWY0My00MmViLTdiNDMtOTdkZi1mYjc2MWY2NzcyNjkiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDoyZjNlNWU4NC04NzM4LTdlNDEtYmExZi00MzljMWU3YjI2NTEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpiNjZhYTU5Ny1mODA5LTA0NGYtOWYzYi0wMTZlODdiODFkZjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmI2NmFhNTk3LWY4MDktMDQ0Zi05ZjNiLTAxNmU4N2I4MWRmMSIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNjoxMjo1MCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNGZjMTdlMS1jOWY3LTk5NDUtYmFkOC00NWZhNGI1MjgwNTgiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTg6MzI6MjcrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ1NGEwNjIxLTQwZmMtNTU0Yy1hZDkzLWNkM2ZjMzIxMTdlYyIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxODozMzowMiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MDU1ZDVmNDMtNDJlYi03YjQzLTk3ZGYtZmI3NjFmNjc3MjY5IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE4OjMzOjAyKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NTRhMDYyMS00MGZjLTU1NGMtYWQ5My1jZDNmYzMyMTE3ZWMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIiBzdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjY2YWE1OTctZjgwOS0wNDRmLTlmM2ItMDE2ZTg3YjgxZGYxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+rc0l4AAAAF5JREFUOI3FkUsSgCAMQx+OC73/Zd3VpUYhTMcPb0chk9CUAFg42LCUAIjzxAsmf11ziP4jFcDXkZKCtENaMFdmdgV/9aC8Hek+api1I1nGFKdcdjamOOVppP6nVz3uep4WJ6dlbD4AAAAASUVORK5CYII="; private static string StatusActiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6MDk6MDErMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjA5OjAxKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyOWQ1NWMzNi0xNzYxLTE1NDYtOTgyMC1kMWRkNjliZDE0NTciIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDplOTEwMGY5Yi00NTU4LWE2NDYtYTY3Ny0xY2I0NjY3YTRjYjciIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NWYwNzJhODUtYjU4Zi1mMzQ4LTliOGQtZGQyZjE3NDQyOGY2IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjA5OjAxKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyOWQ1NWMzNi0xNzYxLTE1NDYtOTgyMC1kMWRkNjliZDE0NTciIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6MDk6MDErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjVmMDcyYTg1LWI1OGYtZjM0OC05YjhkLWRkMmYxNzQ0MjhmNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7dzHWlAAAEt0lEQVRIiXWWW2xUVRSGv332OTPodFoGKC2osdAOCZFbgFhoSERHuRkgJhhFffEVePSG8mSClxh8UCFRY/RFaMQHRI0QDZEHi0QJKBE1NCQggpXeYC49M917Lx/OOdOLdE1W1pyZvf9//f9eZ86owoUnSXsp0ipN2kuRUgEpFRCogAPz9uaA7cBGYAnQCtSAq0Av8A1wCBhiilDrfn+alErVwdNeio/n75sOvADsnmrjpHgdeOt2RGr978/EwGlSKuDTjnd2APuTBT3FM1wML/HPaD9lV0GjafQbmKGbyE+bT1d2xXi8ncCB/xEEKiDtBXyef/9lYC/AiVs/cPLWjxRtGa00Hh6eUgA4ERwOK5YGneGBxk4KjWsSzFeA15ILPX/XIrTyOLLgo2eBdwA+G/iKo0PfEroqAIJEwMlLHAaDFUvJVjhf+YMRV+W+OxcAFIArwDkA9eCFJzixsLsJGAboHjjKl0PfESgfX/lopdF4aOWhUHVCKw4bqzBiGBXD5tzDPDlzS9J8Dhj2jRiAlwCODB2ne+AovvIjC7Bo0XjKwxMPbzwBDhHBYDBiGRVD98BR0l6Kx3IbAF4EdisRmQEMAGzv3cWgGSalArTSkYJ6996E6RBcXYWRyK6ajJLTTXTn6zMy0yeacw4Pfs3l6lV85TOqDIHy0ei6Nd4ki5y4cVZFCqxYrthrHB78msdnPAqw3QfWA5y8eYqyG8FXPj46VpBMz5g9SbiYxMVKjBgM0Xl8f7MnIdjgA8uMMZwt/UbZViYA+0rjKU3Uu5qgQJCYxNZVGLFYsZwrXcAYg+/7S32gpVgscuNmP1YZnGcY1Qq0QnmxNUoxXoPEIysSW+UEbJTi4Ib0UywWyeVyLT5QLZfLKV1WVMWAp1CaqHoK50XvURDfZ4gkLAKOiMAJYqPPrIJSqUQul8MHrodhmG2qNlCqlSKgGDBSMUYwgUFAbFSJq7ioNvlNhGEI0OcDf4rIgpbRmfxV/jvarGJgpcBjImnsUQKGiwjFJdLgnmxrMgu/+MDxTCazeSHt/FQ+i8TdRZbEoN647us3QmxPsn7cnoXZDjKZDMAxHzjU3Nz83trMKr4YPcZQdThppB5qCgJxk9YpmJ6eztrMKpqbmwEOeXM/WDQYBMEbbW1trEmtxIUOGbFIeSxd0eKKBleKs2hwxYlrZMTiQsea1Era2toIguANYNAj6uLNfD7PptYCXanlSOhwocWNWFxlXC3HWZn0XWiR0NGVWs6m1gL5fB7gTQAPgdZ9C4e11jsKhQJbZq/j/vQypCZIzUVZjXOq65rQmV7G1pb1FAoFtNY7iX+ddXbzbMQIb5149+c9jzxn29vbH+KaoVaqMlAdomprY4fokqkZy6xqYHXDcrbO28i2bdtobGzcA7xdP5c5Hy5CKpFcqTj+ffXiDmPM/tOnT9PT08Op/jNcrl6l3wxStiMAZPQdzPJncG/6blbPWkFXVxednZ34vv//R+bcT5bUCVwl8vLG3t4c8HwYhrvPnz9Pb28vfX19FItFALLZLC0tLXR0dLB48WKmTZs29UP/roNLkRGHSyZhxCGhRWpC/75LOeApYAPR35Y58b7rwK/AMeDg7YCT+A96mKaYuYno5AAAAABJRU5ErkJggg=="; private static string StatusInactiveBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6NTg6MzErMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjU4OjMxKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphYjJiZWI3Ni0wY2JiLWIyNDctYjdhYS0zMWI1NjYzYjJjNDEiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpiNzRkODNkZC03NmM0LWQ1NDYtYWEyNi02N2Y3YjMyMGNlYzgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZThjZTMxMGEtODRkYi1lNjQyLWEyYWYtOWQyNDQ0OWUwOTBkIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjU4OjMxKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphYjJiZWI3Ni0wY2JiLWIyNDctYjdhYS0zMWI1NjYzYjJjNDEiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6NTg6MzErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4Y2UzMTBhLTg0ZGItZTY0Mi1hMmFmLTlkMjQ0NDllMDkwZCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6CJz7aAAAD3UlEQVRIiaWWS0grVxzGf2dmjIYQm/iKWRhEr6UQrQXRhXTVLHqr9QVxobhxewUXQttr6baPS6GL0nZ53VUkGxeF3m677sJ2fKT4SNCSaywSIYnJvDJdmBkmqba39MDHOcOc833/1/nPiK2tLWRZRlGUhlmSJGZmZsLAEvAe8CbQC+jAH8AJ8COwDRR4YChCCCRJQgjhYm5uLgR8CGzec8YHvFHH+8C3wOfAl/cJKUIIAJd8YWHhSf0QAOfn51xfX1MqlTAMAyEEra2t+P1+Ojs7icVi1A3ZBNaA7xoEnIVt2ySTyY+BTwHOzs7IZrNomtbgIYBhGBSLRS4vLzk+Pqa/v5/BwUHqhoWAzxxeeX5+HiEEy8vLq8DXAPv7+6TTaUzTdMWd2UGtVsO2bXRdJ5/PY5omPT09AAngHNgDkGq1GisrK68BzwFUVSWdTmNZ1n9COp1GVVXH8Od1T+4EgKcAR0dHqKqKaZqYpollWe7aMAx37YV3j6qqHB4eOiIfAQjbtjuAa4BUKkWlUkGSpAZ44+/NmRMqL/x+P4uLi862ToW7Oufg4ICbm5sHyR8SaBbRNI2DgwPi8TjAkgK8C5DJZNB1/X8L1Go1MpmMI/BYAd4yTZNcLtcgcN8FfEigWSSXy2GaJoqijCpApFgsUigUqNVqf7P+VXLQLKDrOsVikXA4HFEArVwu+wzDcG9qM7kkSQCuiHMvvOTeWZIkSqUS4XAYBXhZrVaDQggqlUpDSP6tipqJHQQCAarVKkBeAX63bfv1lpYWNE3Dtu0GkWbcF38vALq6uhw7flWAnwKBwEwoFOL09NTd5ITkVZPsPRMKhQgEAgAvFGC7u7v7m1gsxt7eHuVyuSHO95E3i3jJA4EAsViM7u5ugG356uqqMjs722aa5tsXFxdu42puA95nb9twepGTh4GBASYnJ4lEIl8APyh1C54NDQ09jcfjFAoFstks9R7l5uQhD5x3kiTR399PPB5naGgI4BmAZNs2q6urN7IsP0kkEsTjcaLRaIOlTgk3w7snGo0yPDxMIpFAluU14AZAHh8fx7IsUqnUL0tLS9bg4OA7hUKB29tbyuUyhmH8Y9X4fD76+voYGxsjmUzS3t7+CfCV46U8MTGBbdtYlsXOzs7PKysrf46MjEx3dHQghGi4VJZlAeDz+QgGg/T29jI6OsrU1BTT09P4/f41LzmAWF9fR9M0F4ZhkEqlwsAH1Wp1U1VVTk5OyOfzFItFAILBIJFIhEePHjEyMkJbW9uDH32xsbHhkuu67sKyLHZ3d8PAMvCYu9+WaP3cS+A34AXw/X3EzvgLFKrw+QQN6BEAAAAASUVORK5CYII="; private static string StatusNeedRestartBase64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIf2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDktMDlUMTc6MDg6NTIrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMDlUMTc6NTc6MTArMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA5LTA5VDE3OjU3OjEwKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphYjljYTE2MS01NTA1LTM2NDItYjBmZi04NWM2YTQ4OTQzOTMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpkZjAzYzgxNS01ZGFhLTZjNDUtOWU4ZC03NWJhYWViNWY0OGEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU4NmEyNWY2LWU2ZTQtN2U0MS1hYjQwLTYzNmQzOWNkOTBmOCIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0wOVQxNzowODo1MiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MGE1N2VhNDUtMjc3ZC01MjQxLWE2MjktYjlmYTFhYTNlNTk0IiBzdEV2dDp3aGVuPSIyMDE4LTA5LTA5VDE3OjU3OjEwKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphYjljYTE2MS01NTA1LTM2NDItYjBmZi04NWM2YTQ4OTQzOTMiIHN0RXZ0OndoZW49IjIwMTgtMDktMDlUMTc6NTc6MTArMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjBhNTdlYTQ1LTI3N2QtNTI0MS1hNjI5LWI5ZmExYWEzZTU5NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplODZhMjVmNi1lNmU0LTdlNDEtYWI0MC02MzZkMzljZDkwZjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz58w4sCAAAEb0lEQVRIiY2WT2gUdxTHP7/5t1vWTXc2bhNblQhuvbi2RaqyGonsQXuIqNFDCh5Kb3run7Q9FEqrYiltQduLJ0P2opKLVEW9SCIRFFtPQiAojWmi0U12NjuZnfn9etiZdLJG6YPHzG/mve/3fd/7Mb8RI8UiWiKBlkigJxKIRALNstAsiy3nztlAP/ARsAXoBDzgb2Ac+AMoAy94hYnRXbvQkskmiWWhJZN8MDSUAT4HBl6V2GIngNMrEYnR3buXgDXLYuvFi8eAM1HA81u3cB4+xJuawq/VELqO0daG2d7Oqk2byHZ3x/GOA2dXJrAsPrx8+Svge4Bn167x7OZN/GoVoesITQNNa2ZJiZISFQQY6TSr9+xh9d69EebXwA/RQv907VqErrPt6tVPgF8BJoeGmL50Cem6oFTTQ+DIle+jfJ/AcZi/f5+gXqetUAAoAY+B+wBiZMcOirdvvwlUACbPn+ef4WE000QYRtMjBUI0iZRaUhARyUaDzgMHeOfo0ah4G6gYstEA+BJg6sIFJgcHEaYJQYAwTYTvg6YhQm/iK1QQNIl8H9VoIH2fycFBtGSSNUeOAHwBDAilVBaYBbh78CDe7CyaZTWrNs2X+x9ZbA6q0UAFAdLzsLJZtg4PR1HtBs19zpNymYWJCYRhoBqNZe1BiBVbRKgkapPyfRYePeJJuczb/f0A/QawF2D2xg2CWg1hGMh47/+PghaSZ9evRwT7DOB93/d5cfcuvuMsBzaM/3ovxDIFS4OODzu8Vu7dw/d9DMN4zwA6qtUqlZkZkBLN89AAXQg0QAurFy0ESimQEiklEgiUQgISWJiZoVqtYtt2hwEs1mo1q26aSM9DhMC6UmiAUAotCBBACI8KXYY7SgJBbC2UwnEcbNvGAKZc1003bBvXcSACjlQohQBaJrBUrQqrjwgBrEwG13UBpg3goVLqXdXZSe3x4yWApepDMk2IZQpkDDQODmCtXx/d/mkAV1OpVK+xeTP1sTFk9FmIgQpAiz2PFMTbFM95q1AglUoBXNGAci6Xwy6VCDIZ6kqxoBQ1pahKSVVKHCmZb3En9q4WxteVIshksEslcrkcQFk7nc0+N03zZFdXF+meHhbDwMgXlMIJAeLuhO+iOFcpFpUi3dNDV1cXpmmeBJ5rYe9O5fN51vX2kuruxguD3VhyvcXdFmBPKVLd3azr7SWfzwOcimbJt7Zd0XX9WKlUYt2hQ6wqFvHCpIhs8TVrTylWFYus7+ujVCqh6/pxwq+zEQ1xIJP57USl0n748OHvLgBBMsmLO3fwq1VeZ2Y6jb1tG/n9++nr66Otre0bYqea+NG2l0n/aW7umO/7Z8bGxhgdHWVqZIT6xATe06f4tRoARiqFlcvxxoYNrNm5k2KxyPbt2zEM4+Uj8+dsFjcamJQsAr/MzdnAZ67rDjx48IDx8XGmp6ephmrS6TQdHR1s3LiRQqFAMpl89aF/NkbgxocG/D4/bwMfA/to/rasCfOmgL+AK8DQSsCR/QsjSb1FKvuN9QAAAABJRU5ErkJggg=="; private static string WWWBase64 = "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfCAYAAAAfrhY5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGjWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wOS0xOFQyMDowMjo0OSswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDktMTlUMTI6MjE6MDkrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMTlUMTI6MjE6MDkrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjllZWQwYzk5LWQ4YmItMTk0Yi1hOTU2LWI0Mzg4MzZiNGE1NyIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjE0YmE2MTBjLTcxMzMtM2E0Yy05NDkyLWUwNTczZDE5YmUxOCIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjRlYjUxNDViLTY5YjEtODE0Zi1hNmEyLWRhNGU3ZDliMjlmMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NGViNTE0NWItNjliMS04MTRmLWE2YTItZGE0ZTdkOWIyOWYzIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTE4VDIwOjAyOjQ5KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDozYWU1NzdiOS00MWEwLTU1NGUtYTU1NC0zMmViZmI1ZDFjNzMiIHN0RXZ0OndoZW49IjIwMTgtMDktMThUMjA6MDY6MTErMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjllZWQwYzk5LWQ4YmItMTk0Yi1hOTU2LWI0Mzg4MzZiNGE1NyIgc3RFdnQ6d2hlbj0iMjAxOC0wOS0xOVQxMjoyMTowOSswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5HbzubAAAEM0lEQVRIicWXTWwVVRTHf2doQUKnMWkhgOK7o2gMoiCGHZBoQozs+LCyMOwq8T2iW1pJCCZQjStiZxpwZ4wp5WslCxdScFUaJMpHjBrmloABeWxmXiFt6RwXnfcYXqcfiTY9izfz7v3N+Z+cuffMuaKqiAgzWp8uKJSH3xC0U9DVCi2itKjwQOAByh+JOF8M3VvyK4ckmcmdqiKzEff86DOEdpDCzFHqEHA8LDYfmUncmVIwiHZ6fvS3F8SKyDpN2INqr6JXaWR5WHQFICy6kiSyQtGrqPZqwh5V2eAFsXpBdKfQE22fSiNX3PhxF8pJRFag2h8W3TYHeQ6R3Q1jC7aF7e69LD+0r+luw9iCbYjsRmSFLbm7gAsgK52E08aPD89KfE2fLhRhvwqjoMWw6L6zpk8XqnAE4K9Pl9zOc1QdF6HrrWPaGH7c9DawT2FMhM41fbpwWnEviL56VK6MoKyzxeZnwmJzDyL66H7lCoIR1Z35CaxZG+A9GI8vI6Jh0fVtqXmRiqx/VK6MGD/uysK1BVcIKu856LkZnP83U1DkXVtq+vGpBSckx+dUeEIESL55EowqAOnq/AnVSfsunZuUci+INWfs/bxxVMX48cXqnKpO/JggOmCC+GResF5PvNX40WDuXJ4IYPxo0OuJt+bPxae8IOqsic+H1SrcfFmDtfYMsJ2J5dAGnAB2p9cy0JLOAZwBNgHLsqwx5oS1tgxcNMbsALDWKnDfGLPMWlvPKnDWAQZSx8+mjgG2pKItdcEOAEvrWWttlb1Uxy+11uaxAJccoLqYXgE2p/ebgVdzMjUTWy8+LSthGAJcAx4CG4HvgA+B31PwOrA240zTIDYC3wJ7qqwxprZNrbXXgNemYMeNMWurRWYgBQD602s1wrxtVmXP17FZG5iGHYQntT2brvM8bQNMbf3TzNW/giw7kCd+C7gJ2AyYW2BS1taxU4nfMsZk2UFgfvf5vFY4ByZ6NOPHp/KguarttQiqjrwg7p/Tr1oQ/5z9qtWaCeNHQyLyQl60/7OFYdF9sa57ddrnfAEoIOx98j+jZ/y4ywtiLXRX1mefMX501Qti9bqjXdnx+vQaP/7AC2I1QfRbdrwQVN70glizPdykvt2W3I7FrU2LHEevGD8a8YK4hKq0NLgbUCyO5DYcVROhF+Vm4Z67IX3Hnxg/GnXQXxa3Ni2yJbcjy09qnW+0yajCYYFGoNvrqfRf3itjidABsPro8PN5wi/5D1dNRMD+C4fksempXBQ4KtAAfH6jTUbrn8k9NNiieyCBHajeAbaYID6NcBfV3seN4+cK3ZXlWX7V18Mrx+XxD6r6faKUvSA+K7BJ0dsJ7AiL7sHcTM3yrNYB8hGCmRacsFBVj9lS85fTQbM+KAJwUB2zfPh10aQDeFmVVoFWhbIIZeBPVI6E/zRdm+0p9V+lFDjVQcCm0AAAAABJRU5ErkJggg=="; private static string UpdatesBase64 = "iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFwmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wOS0xOFQyMDozNjo0NSswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmE1Zjg4NDg3LWU0MmUtMDc0OS04MDYwLWE5YmMwNWM2Yzg2NCIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOmY1M2Q1NTJhLWNiMDgtZDc0ZS1hOGE2LTI0YjQ2MzRlZWEyMyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjQxMDdiYjQ2LWRmYzEtNWI0Mi05ZDIxLTViZGM4YmVjMjE5ZCI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NDEwN2JiNDYtZGZjMS01YjQyLTlkMjEtNWJkYzhiZWMyMTlkIiBzdEV2dDp3aGVuPSIyMDE4LTA5LTE4VDIwOjM2OjQ1KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWY4ODQ4Ny1lNDJlLTA3NDktODA2MC1hOWJjMDVjNmM4NjQiIHN0RXZ0OndoZW49IjIwMTgtMDktMTlUMTE6MDY6NTkrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+1SDzqQAAB2dJREFUeJztnG1sFMcdxp//7jl+OdsBjO00ChEmCTZqSAkJDqSlrutgjI9KNCIpTUKlVC2IM3yI+hKp+UDzqY3UqFLBl1hqFClJK6JKAZL4JdiOZacNoDa1jZTIEKilFBUwNdjGZ4x9u08/mNucz3tmd293D9T8Ps3O7sw8+3hm7r+zsxaS+ApAybSAm4VAPCEinjWypX1f0RSVKgoeAFAOyHIRFJPMF2ABABAYEZFxEhcBngJwUhGlP4uxnkMb9gx7pS0+IsRIuGzE5ramCj2g/YhkPURWisPeR0AXsJ+UFlVT33q/bueAmzo9MeKhfzRl3XFZe0oHwyJSmXaFpvCYUF4dD1z4U3f1i7G0a3PTiKquvYE8rXSnkD+HyNJ0xVmBwKBAXoqq519LxxDXjAh1RNbrYEQg9zsVkxbECeoSbt2462+OiqdrxNaPX86NRnN+L8AOT2daK5AEpCkayH2uu/rZSdtF4dCIzW1NFVog9peM9YIUEOgDtR+0bthzynIZp0bUHdlfIyIHRaTAgVY/GAO4peWxhi4rF8fv39ZPWl3H/q2KojTfxCYAQCEgrXUd+7faKWTZiFBn5AmBHACQbVua/2QL5ECo45XvWy1gaWhs6ox8F2SrQG5LX6N/EJyCyKbWmvCHKa+xOkfMRIixY4Dc7oFWH+AoqVemmkAtzRGb323K01Xtba9MKMjKxrriMqxadBdU8er5T24XUQ5Udb2eM99VgflO6rnay5h5UHKdewqK8ZvV30MwMDPlDI4P4/lPDiMau+ZBa/JgMDbxOwC7U12R8s8Q6oisB7jTA1UAgO3L1hgmAEBZfhE23/V1r5oDgHB9Z+OjqU6aGlHVtTeggxEvI8a7gwvn5C0xyXMNESGlsaprr+koMDUiGCvZ4XXUqJjMCQJvI3UBVuXHSn9sqic547pjv/BUUQbRhc+b9Yo5RgS14mf8epTOBAJZFtRKtiXnmwwNJeyHoAzTkJwxy4j6I40rAKzxTU7GkLWhI6/cl5gzu0cInvFVTwahom9PPJ5lBIGQv3IyByn1iceGEVva9xVBZKX/kjKEcFXoo4gRuBg/I1NUqkTcfeFzR24hau9cAdUkLgsG5j7ILitYjGfvXTsnX6OOD/4zgAtXx1zTJhCVk/q3ARwGEoyg4AG3w5mNd67Ak0tXW77+7uBC04hzBsEbZ467I8yoUr6B60Yk9ABZ7m4rwMEv+vGvK/9Nu57B8WEc/vcJFxTNwbhnwwgRVrjdytj0JF7ofS8tMwbHh/FC73sYnbrqojKD8njCMIJAkRctpWOGxyaAQEk8/WWPADxbgXJihtcmAAAohfFkQo/wdmXajhm+mAAAQuOefd0fYcUM30xIImFo8IofDY5NT+JXKczw3QSKcc+Jk+WoP60DV0zMyEhPEBoRWuJk6dmuFDPiZnw6cg6fjZzPyHAQYCie/jKypAyI4EG7lW1fVolHipei/9JZ/PH0UdjZnHZlehK//OSQ3SYNshQVeyqqUJZfhI5zJ50EXSfjiYQlK56CzTXDewuKsa3sIQAzq9B9l87i78Nf2BXjmO+U3oear83ERD8tWIyjFwcxNGlrqjNe+hhDQxGl366Qhdl5s45Lcv19N7wgO9dIC4DinHx7FZDGPRtGZDHWQ0BPX96tAUFNcpSe+LFhxKENe4YFtN0rblUE6G1eH74cP569QkVp8V9SZki+11lGqJr6lr9yMocW0N9MPJ71ouP9up0Dm9ojx0XwiJPK1xaXoSTHvwmzvLDUUTmCR49U7z6dmGfyHpARQBwZsXrREqxetMSROD8hlcbkvDkPXROBoT8TGLRS4dXYtBu6XGNs2sLOQvLM1cD5t5Oz5xjRXf1iTCAvWWn4s9FzvgZQ89Fz4TTORi/f8DqK/NZsp67pK/Koev61YKw0fKNNIjqJX/c1Y8FtuchRsyyLdpuJ2JSl3kCgL//S4tfNzqXcQ1XXvv9bCqQn47tqXYKATh3fbKsNH5uVf6M9VG0bdv8Vglc91ucnjckmJDLvClVe3uTPyFs/2iTxT05Nz7vn44bbCzd2RspV8vitvL0wpvLh5LjBOGt1C/IHNeGTFHmc4JTLCv3gGkUeT2VCIpYWb1trwh+Kjh8S1NLX5g8ENRE8Od+u20Qsr2K31Da8Q3AbAC82QroLOalAeaK5Jvyu1SK2P1Oo72isBnDwZp0zSIyQ3NJW29Bt7XoHnykAQMtjDV2iK2sI9Nkt6z3sVSiVVk1IxNELnubaXZ9PqLnrCERsrdZ6BAGd4B/0qdi65tpdnzupI+2P2+o7Gx+ljojM7DXIAOzVdQnPFyzNW9rp0Eimpabh44nA0MPU9R1Wn1pdgTwD8CdRdajSqQmJuPoBbFXX3kBQK9lGICyQdWlXaALBowJEourQgZvuA1gzNrXvWw6oTwMIQbhKIKqTeghqAvSS0qIF9DetBEe26vfaiERCH0UW6tdYBcpKEVaQUg5gMcBCyPWfYXIUkDERXgRwipQBgX4iKzDdfbj6uRGvtM0x4v+dr/5/xHX+BywfMF35GGAAAAAAAElFTkSuQmCC"; private static string QuestionBase64 = "iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAYAAADAQbwGAAABN2lDQ1BBZG9iZSBSR0IgKDE5OTgpAAAokZWPv0rDUBSHvxtFxaFWCOLgcCdRUGzVwYxJW4ogWKtDkq1JQ5ViEm6uf/oQjm4dXNx9AidHwUHxCXwDxamDQ4QMBYvf9J3fORzOAaNi152GUYbzWKt205Gu58vZF2aYAoBOmKV2q3UAECdxxBjf7wiA10277jTG+38yH6ZKAyNguxtlIYgK0L/SqQYxBMygn2oQD4CpTto1EE9AqZf7G1AKcv8ASsr1fBBfgNlzPR+MOcAMcl8BTB1da4Bakg7UWe9Uy6plWdLuJkEkjweZjs4zuR+HiUoT1dFRF8jvA2AxH2w3HblWtay99X/+PRHX82Vun0cIQCw9F1lBeKEuf1UYO5PrYsdwGQ7vYXpUZLs3cLcBC7dFtlqF8hY8Dn8AwMZP/fNTP8gAAAAJcEhZcwAACxMAAAsTAQCanBgAAAj9aVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzE0MiA3OS4xNjA5MjQsIDIwMTcvMDcvMTMtMDE6MDY6MzkgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMi0xMC0wOFQxMDowNzoxNiswMzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0xMC0wOFQxMjowOTo0NiswMzowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjItMTAtMDhUMTI6MDk6NDYrMDM6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjFlYmE4Yjg0LWZhMGEtOWY0MS05OTE3LWIwN2U0ZjMxMTlhMiIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjFiZDVlYzRmLTNjOGQtN2M0NS1hZWMzLTI2NzE4YTZhNGI0YiIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NzBlNzA4NTUtYTY3My00NjQ0LTgyYzEtMTkyZWE1YzlhMmNmIiBzdEV2dDp3aGVuPSIyMDIyLTEwLTA4VDEwOjA3OjE2KzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo0Y2QwZDZjOC1hZjJiLTQ3NGYtYThlZS04NDQyYWIzMzMxNGQiIHN0RXZ0OndoZW49IjIwMjItMTAtMDhUMTI6MDk6NDYrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNvbnZlcnRlZCIgc3RFdnQ6cGFyYW1ldGVycz0iZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjFlYmE4Yjg0LWZhMGEtOWY0MS05OTE3LWIwN2U0ZjMxMTlhMiIgc3RFdnQ6d2hlbj0iMjAyMi0xMC0wOFQxMjowOTo0NiswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NGNkMGQ2YzgtYWYyYi00NzRmLWE4ZWUtODQ0MmFiMzMzMTRkIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjcwZTcwODU1LWE2NzMtNDY0NC04MmMxLTE5MmVhNWM5YTJjZiIvPiA8cGhvdG9zaG9wOlRleHRMYXllcnM+IDxyZGY6QmFnPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9Ij8iIHBob3Rvc2hvcDpMYXllclRleHQ9Ij8iLz4gPC9yZGY6QmFnPiA8L3Bob3Rvc2hvcDpUZXh0TGF5ZXJzPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pm3hzHgAAAEiSURBVDiNrZXhbYMwEEafrSxAR2AFOkI6Ah0hmcBihuAJwgh0hGaEsEJHgA3s/DCoBIxt0n4SEtadH3dn3yGstXilZQacgArIZpYG+EKZm2+b3IAdgR4ogHeUESgjgDNQAt9oWfm2ilWEWhbAHRhG2M/CfgKu4+qMMk0swunLU8rPcoBh4RsEzutVeOzMgDla5jFgs/GepHUNU6Rlj8tkQJm3ucl/ymFYyW9ZLn+L0N3NO5ADN5T5WLrsjbANwfYBtbwCR+CyBQPAWht/alHZWlhbiyrmmwrsbS3aFN94yq4VMzwn6lNKDd0VUab7L6ADuSsT1WudEtD+TonoEPXQssUN1Q74XM3HhcIRuqlcjqsC33zcBXxBMWADTD+jjoT5+AD4rb8zjOF5rwAAAABJRU5ErkJggg=="; private static string TooltipBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUGFdjTE5O/s/AwMDACGMAAC3JBFO8wVSyAAAAAElFTkSuQmCC"; public static Texture2D Window = null; public static Texture2D SettingsNormal = null; public static Texture2D SettingsActive = null; public static Texture2D StatusActive = null; public static Texture2D StatusInactive = null; public static Texture2D StatusNeedRestart = null; public static Texture2D WWW = null; public static Texture2D Updates = null; public static Texture2D Question = null; public static Texture2D Tooltip = null; public static void Init() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown FieldInfo[] source = (from x in typeof(Textures).GetFields(BindingFlags.Static | BindingFlags.NonPublic) where (object)x.FieldType == typeof(string) select x).ToArray(); FieldInfo[] array = (from x in typeof(Textures).GetFields(BindingFlags.Static | BindingFlags.Public) where (object)x.FieldType == typeof(Texture2D) select x).ToArray(); foreach (FieldInfo f in array) { Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false, true); f.SetValue(null, val); Utils.LoadImage(val, Convert.FromBase64String(((string)source.FirstOrDefault((FieldInfo x) => x.Name == f.Name + "Base64")?.GetValue(null)) ?? "")); } int size = 128; SettingsNormal.ResizeToIfLess(size); SettingsActive.ResizeToIfLess(size); WWW.ResizeToIfLess(size); Updates.ResizeToIfLess(size); } } public class ModEntry { public class ModLogger { protected readonly string Prefix; protected readonly string PrefixError; protected readonly string PrefixCritical; protected readonly string PrefixWarning; protected readonly string PrefixException; public ModLogger(string Id) { Prefix = "[" + Id + "] "; PrefixError = "[" + Id + "] [Error] "; PrefixCritical = "[" + Id + "] [Critical] "; PrefixWarning = "[" + Id + "] [Warning] "; PrefixException = "[" + Id + "] [Exception] "; } public void Log(string str) { UnityModManager.Logger.Log(str, Prefix); } public void Error(string str) { UnityModManager.Logger.Log(str, PrefixError); } public void Critical(string str) { UnityModManager.Logger.Log(str, PrefixCritical); } public void Warning(string str) { UnityModManager.Logger.Log(str, PrefixWarning); } public void NativeLog(string str) { UnityModManager.Logger.NativeLog(str, Prefix); } public void LogException(string key, Exception e) { UnityModManager.Logger.LogException(key, e, PrefixException); } public void LogException(Exception e) { UnityModManager.Logger.LogException(null, e, PrefixException); } } public readonly ModInfo Info; public readonly string Path; public readonly string ConfigPath; private Assembly mAssembly; public readonly Version Version; public readonly Version ManagerVersion; public readonly Version GameVersion; public Version NewestVersion; public readonly Dictionary<string, Version> Requirements = new Dictionary<string, Version>(); public readonly List<string> LoadAfter = new List<string>(); public string CustomRequirements = string.Empty; public readonly ModLogger Logger; public KeyBinding Hotkey = new KeyBinding(); public bool HasUpdate; public Func<ModEntry, bool> OnUnload; public Func<ModEntry, bool, bool> OnToggle; public Action<ModEntry> OnGUI; public Action<ModEntry> OnFixedGUI; public Action<ModEntry> OnShowGUI; public Action<ModEntry> OnHideGUI; public Action<ModEntry> OnSaveGUI; public Action<ModEntry, float> OnUpdate; public Action<ModEntry, float> OnLateUpdate; public Action<ModEntry, float> OnFixedUpdate; public Action<ModEntry> OnSessionStart; public Action<ModEntry> OnSessionStop; private Dictionary<long, MethodInfo> mCache = new Dictionary<long, MethodInfo>(); internal readonly List<TextureReplacer.Skin> Skins = new List<TextureReplacer.Skin>(); private bool mStarted; private bool mErrorOnLoading; public bool Enabled = true; private bool mFirstLoading = true; private int mReloaderCount; private bool mActive; public Assembly Assembly => mAssembly; public bool HasAssembly { get { if (string.IsNullOrEmpty(Info.AssemblyName)) { return !string.IsNullOrEmpty(Info.EntryMethod); } return true; } } public bool CanReload { get; private set; } public bool Started => mStarted; public bool ErrorOnLoading => mErrorOnLoading; public bool Toggleable { get { if (OnToggle == null) { return !HasAssembly; } return true; } } public bool Loaded { get { if ((object)Assembly == null) { if (!HasAssembly) { return mStarted; } return false; } return true; } } public bool Active { get { return mActive; } set { if (value && !Loaded) { Stopwatch stopwatch = Stopwatch.StartNew(); Load(); Logger.NativeLog($"Loading time {(float)stopwatch.ElapsedMilliseconds / 1000f:f2} s."); } else { if (!mStarted || mErrorOnLoading) { return; } try { if (value) { if (mActive) { return; } if (OnToggle == null || OnToggle(this, arg2: true)) { mActive = true; Logger.Log("Active."); GameScripts.OnModToggle(this, value: true); if (UnityModManager.toggleModsListen != null) { UnityModManager.toggleModsListen(this, result: true); } } else { Logger.Log("Unsuccessfully."); Logger.NativeLog("OnToggle(true) failed."); } } else { if (forbidDisableMods || !mActive) { return; } if ((OnToggle != null && OnToggle(this, arg2: false)) || !HasAssembly) { mActive = false; Logger.Log("Inactive."); GameScripts.OnModToggle(this, value: false); if (UnityModManager.toggleModsListen != null) { UnityModManager.toggleModsListen(this, result: false); } } else if (OnToggle != null) { Logger.NativeLog("OnToggle(false) failed."); } } } catch (Exception e) { Logger.LogException("OnToggle", e); } } } } public ModEntry(ModInfo info, string path) { Info = info; Path = path; ConfigPath = System.IO.Path.Combine(configPath, Info.Id); Logger = new ModLogger(Info.Id); Version = ParseVersion(info.Version); ManagerVersion = ((!string.IsNullOrEmpty(info.ManagerVersion)) ? ParseVersion(info.ManagerVersion) : ((!string.IsNullOrEmpty(Config.MinimalManagerVersion)) ? ParseVersion(Config.MinimalManagerVersion) : new Version())); GameVersion = ((!string.IsNullOrEmpty(info.GameVersion)) ? ParseVersion(info.GameVersion) : new Version()); if (info.Requirements != null && info.Requirements.Length != 0) { Regex regex = new Regex("(.*)-(\\d+\\.\\d+\\.\\d+).*"); string[] requirements = info.Requirements; foreach (string text in requirements) { Match match = regex.Match(text); if (match.Success) { Requirements.Add(match.Groups[1].Value, ParseVersion(match.Groups[2].Value)); } else if (!Requirements.ContainsKey(text)) { Requirements.Add(text, null); } } } if (info.LoadAfter != null && info.LoadAfter.Length != 0) { LoadAfter.AddRange(info.LoadAfter); } } public bool Load() { //IL_06cd: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Expected O, but got Unknown if (Loaded) { return !mErrorOnLoading; } mErrorOnLoading = false; Logger.Log("Version '" + Info.Version + "'. Loading."); if (string.IsNullOrEmpty(Info.AssemblyName) && !string.IsNullOrEmpty(Info.EntryMethod)) { mErrorOnLoading = true; Logger.Error("AssemblyName is null."); } if (!string.IsNullOrEmpty(Info.AssemblyName) && string.IsNullOrEmpty(Info.EntryMethod)) { mErrorOnLoading = true; Logger.Error("EntryMethod is null."); } if (!string.IsNullOrEmpty(Info.ManagerVersion) && ManagerVersion > GetVersion()) { mErrorOnLoading = true; Logger.Error("Mod Manager must be version '" + Info.ManagerVersion + "' or higher."); } if (!string.IsNullOrEmpty(Info.GameVersion) && gameVersion != VER_0 && GameVersion > gameVersion) { mErrorOnLoading = true; Logger.Error("Game must be version '" + Info.GameVersion + "' or higher."); } if (Requirements.Count > 0) { foreach (KeyValuePair<string, Version> requirement in Requirements) { string key = requirement.Key; ModEntry modEntry = FindMod(key); if (modEntry == null) { mErrorOnLoading = true; Logger.Error("Required mod '" + key + "' missing."); } else if (requirement.Value != null && requirement.Value > modEntry.Version) { mErrorOnLoading = true; Logger.Error($"Required mod '{key}' must be version '{requirement.Value}' or higher."); } else if (!modEntry.Active) { modEntry.Enabled = true; modEntry.Active = true; if (!modEntry.Active) { Logger.Log("Required mod '" + key + "' inactive."); } } } } if (LoadAfter.Count > 0) { foreach (string item in LoadAfter) { ModEntry modEntry2 = FindMod(item); if (modEntry2 == null) { Logger.Log("Optional mod '" + item + "' not found."); } else if (!modEntry2.Active && modEntry2.Enabled) { modEntry2.Active = true; if (!modEntry2.Active) { Logger.Log("Optional mod '" + item + "' enabled, but inactive."); } } } } if (mErrorOnLoading) { return false; } if (!HasAssembly) { mStarted = true; Active = true; return true; } string text = System.IO.Path.Combine(Path, Info.AssemblyName); string text2 = text.Replace(".dll", ".pdb"); string value = string.Empty; string[] commandLineArgs = Environment.GetCommandLineArgs(); int num = Array.IndexOf(commandLineArgs, "--umm-" + Info.Id + "-assembly-path"); if (num != -1 && commandLineArgs.Length > num + 1) { value = (text = commandLineArgs[num + 1]); } if (File.Exists(text)) { if (!string.IsNullOrEmpty(value)) { try { mAssembly = Assembly.LoadFrom(text); mFirstLoading = false; } catch (Exception e) { mErrorOnLoading = true; Logger.Error("Error loading file '" + text + "'."); Logger.LogException(e); return false; } } else { try { string text3 = text; string destFileName = text2; bool flag = false; if (mFirstLoading) { ushort num2 = (ushort)((long)new FileInfo(text).LastWriteTimeUtc.GetHashCode() + (long)version.GetHashCode() + ManagerVersion.GetHashCode()).GetHashCode(); text3 = text + $".{num2}.cache"; destFileName = text3 + ".pdb"; flag = File.Exists(text3); if (!flag) { string[] files = Directory.GetFiles(Path, "*.cache*"); foreach (string path in files) { try { File.Delete(path); } catch (Exception) { } } } } if (ManagerVersion >= VER_0_13) { if (mFirstLoading) { if (!flag) { bool flag2 = false; ModuleDefMD val = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null); foreach (AssemblyRef assemblyRef in ((ModuleDef)val).GetAssemblyRefs()) { if (assemblyRef.FullName.StartsWith("0Harmony, Version=1.")) { assemblyRef.Name = UTF8String.op_Implicit("0Harmony-1.2"); flag2 = true; } } if (flag2) { ((ModuleDef)val).Write(text3); } else { File.Copy(text, text3, overwrite: true); } if (File.Exists(text2)) { File.Copy(text2, destFileName, overwrite: true); } } mAssembly = Assembly.LoadFrom(text3); Type[] types = mAssembly.GetTypes(); for (int i = 0; i < types.Length; i++) { if (types[i].GetCustomAttributes(typeof(EnableReloadingAttribute), inherit: true).Any()) { CanReload = true; break; } } } else { ModuleDefMD val2 = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null); AssemblyDef assembly = ((ModuleDef)val2).Assembly; string text4 = UTF8String.op_Implicit(assembly.Name); int i = ++mReloaderCount; assembly.Name = UTF8String.op_Implicit(text4 + i); using MemoryStream memoryStream = new MemoryStream(); ((ModuleDef)val2).Write((Stream)memoryStream); if (File.Exists(text2)) { mAssembly = Assembly.Load(memoryStream.ToArray(), File.ReadAllBytes(text2)); } else { mAssembly = Assembly.Load(memoryStream.ToArray()); } } } else { if (!flag) { bool flag3 = false; ModuleDefMD val3 = ModuleDefMD.Load(File.ReadAllBytes(text), (ModuleCreationOptions)null); foreach (TypeRef typeRef in ((ModuleDef)val3).GetTypeRefs()) { if (typeRef.FullName == "UnityModManagerNet.UnityModManager") { typeRef.ResolutionScope = (IResolutionScope)new AssemblyRefUser((IAssembly)(object)((ModuleDef)thisModuleDef).Assembly); flag3 = true; } } foreach (MemberRef item2 in from member in ((ModuleDef)val3).GetMemberRefs() where member.IsFieldRef select member) { if (item2.Name == "modsPath" && ((IFullName)item2.Class).FullName == "UnityModManagerNet.UnityModManager") { item2.Name = UTF8String.op_Implicit("OldModsPath"); flag3 = true; } } foreach (AssemblyRef assemblyRef2 in ((ModuleDef)val3).GetAssemblyRefs()) { if (assemblyRef2.FullName.StartsWith("0Harmony, Version=1.")) { assemblyRef2.Name = UTF8String.op_Implicit("0Harmony-1.2"); flag3 = true; } } if (flag3) { ((ModuleDef)val3).Write(text3); } else { File.Copy(text, text3, overwrite: true); } } mAssembly = Assembly.LoadFile(text3); } mFirstLoading = false; } catch (Exception e2) { mErrorOnLoading = true; Logger.Error("Error loading file '" + text + "'."); Logger.LogException(e2); return false; } } try { object[] param = new object[1] { this }; Type[] types2 = new Type[1] { typeof(ModEntry) }; if ((object)FindMethod(Info.EntryMethod, types2, showLog: false) == null) { param = null; types2 = null; } if (!Invoke(Info.EntryMethod, out var result, param, types2) || (result != null && !(bool)result)) { mErrorOnLoading = true; Logger.Log("Not loaded."); } } catch (Exception ex2) { mErrorOnLoading = true; Logger.Log(ex2.ToString()); return false; } mStarted = true; if (!mErrorOnLoading) { Active = true; return true; } } else { mErrorOnLoading = true; Logger.Error("File '" + text + "' not found."); } return false; } internal void LoadSkins() { foreach (TextureReplacer.Skin skin in Skins) { if (!allSkins.Contains(skin)) { allSkins.Add(skin); } foreach (KeyValuePair<string, TextureReplacer.Skin.texture> texture2 in skin.textures) { Texture2D texture = Utils.LoadTexture(texture2.Value.Path); texture2.Value.Texture = texture; } } } internal void Reload() { if (!mStarted || !CanReload) { return; } if (OnSaveGUI != null) { OnSaveGUI(this); } Logger.Log("Reloading..."); if (Toggleable) { bool forbidDisableMods = UnityModManager.forbidDisableMods; UnityModManager.forbidDisableMods = false; Active = false; UnityModManager.forbidDisableMods = forbidDisableMods; } else { mActive = false; } try { if (!Active && (OnUnload == null || OnUnload(this))) { mCache.Clear(); Type type = typeof(Traverse).Assembly.GetType("HarmonyLib.AccessCache"); object value = typeof(Traverse).GetField("Cache", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); string[] array = new string[6] { "declaredFields", "declaredProperties", "declaredMethods", "inheritedFields", "inheritedProperties", "inheritedMethods" }; foreach (string name in array) { ((IDictionary)type.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(value)).Clear(); } Assembly assembly = Assembly; mAssembly = null; mStarted = false; mErrorOnLoading = false; OnToggle = null; OnGUI = null; OnFixedGUI = null; OnShowGUI = null; OnHideGUI = null; OnSaveGUI = null; OnUnload = null; OnUpdate = null; OnFixedUpdate = null; OnLateUpdate = null; CustomRequirements = null; if (!Load()) { return; } Type[] types = assembly.GetTypes(); foreach (Type type2 in types) { Type type3 = Assembly.GetType(type2.FullName); if ((object)type3 == null) { continue; } FieldInfo[] fields = type2.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.GetCustomAttributes(typeof(SaveOnReloadAttribute), inherit: true).Any()) { continue; } FieldInfo field = type3.GetField(fieldInfo.Name); if ((object)field == null) { continue; } Logger.Log("Copying field '" + fieldInfo.DeclaringType.Name + "." + fieldInfo.Name + "'"); try { if ((object)fieldInfo.FieldType != field.FieldType) { if (fieldInfo.FieldType.IsEnum && field.FieldType.IsEnum) { field.SetValue(null, Convert.ToInt32(fieldInfo.GetValue(null))); } else if ((!fieldInfo.FieldType.IsClass || !field.FieldType.IsClass) && fieldInfo.FieldType.IsValueType && !field.FieldType.IsValueType) { } } else { field.SetValue(null, fieldInfo.GetValue(null)); } } catch (Exception ex) { Logger.Error(ex.ToString()); } } } return; } if (Active) { Logger.Log("Must be deactivated."); } } catch (Exception ex2) { Logger.Error(ex2.ToString()); } Logger.Log("Reloading canceled."); } public bool Invoke(string namespaceClassnameMethodname, out object result, object[] param = null, Type[] types = null) { result = null; try { MethodInfo methodInfo = FindMethod(namespaceClassnameMethodname, types); if ((object)methodInfo != null) { result = methodInfo.Invoke(null, param); return true; } } catch (Exception e) { Logger.Error("Error trying to call '" + namespaceClassnameMethodname + "'."); Logger.LogException(e); } return false; } private MethodInfo FindMethod(string namespaceClassnameMethodname, Type[] types, bool showLog = true) { long num = namespaceClassnameMethodname.GetHashCode(); if (types != null) { Type[] array = types; foreach (Type type in array) { num += type.GetHashCode(); } } if (!mCache.TryGetValue(num, out var value)) { if ((object)mAssembly != null) { string text = null; string text2 = null; int num2 = namespaceClassnameMethodname.LastIndexOf('.'); if (num2 != -1) { text = namespaceClassnameMethodname.Substring(0, num2); text2 = namespaceClassnameMethodname.Substring(num2 + 1); Type type2 = mAssembly.GetType(text); if ((object)type2 != null) { if (types == null) { types = new Type[0]; } value = type2.GetMethod(text2, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null); if ((object)value == null && showLog) { if (types.Length != 0) { Logger.Log("Method '" + namespaceClassnameMethodname + "[" + string.Join(", ", types.Select((Type x) => x.Name).ToArray()) + "]' not found."); } else { Logger.Log("Method '" + namespaceClassnameMethodname + "' not found."); } } } else if (showLog) { Logger.Error("Class '" + text + "' not found."); } } else if (showLog) { Logger.Error("Function name error '" + namespaceClassnameMethodname + "'."); } } else if (showLog) { UnityModManager.Logger.Error("Can't find method '" + namespaceClassnameMethodname + "'. Mod '" + Info.Id + "' is not loaded."); } mCache[num] = value; } return value; } public bool HasContentType(string str) { if (!string.IsNullOrEmpty(Info.ContentType)) { return new Regex("\\b" + str + "\\b", RegexOptions.IgnoreCase).IsMatch(Info.ContentType); } return false; } } public static class Logger { private const string Prefix = "[Manager] "; private const string PrefixError = "[Manager] [Error] "; private const string PrefixException = "[Manager] [Exception] "; public static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Log.txt"); private static bool hasErrors; private static int bufferCapacity = 100; private static List<string> buffer = new List<string>(bufferCapacity); internal static int historyCapacity = 200; internal static List<string> history = new List<string>(historyCapacity * 2); private static float timer; public static void NativeLog(string str) { NativeLog(str, "[Manager] "); } public static void NativeLog(string str, string prefix) { Write(prefix + str, onlyNative: true); } public static void Log(string str) { Log(str, "[Manager] "); } public static void Log(string str, string prefix) { Write(prefix + str); } public static void Error(string str) { Error(str, "[Manager] [Error] "); } public static void Error(string str, string prefix) { Write(prefix + str); } public static void LogException(Exception e) { LogException(null, e, "[Manager] [Exception] "); } public static void LogException(string key, Exception e) { LogException(key, e, "[Manager] [Exception] "); } public static void LogException(string key, Exception e, string prefix) { if (string.IsNullOrEmpty(key)) { Write(prefix + e.GetType().Name + " - " + e.Message); } else { Write(prefix + key + ": " + e.GetType().Name + " - " + e.Message); } Console.WriteLine(e.ToString()); } private static void Write(string str, bool onlyNative = false) { if (str == null) { return; } Console.WriteLine(str); if (!onlyNative) { buffer.Add(str); history.Add(str); if (history.Count >= historyCapacity * 2) { string[] collection = history.Skip(historyCapacity).ToArray(); history.Clear(); history.AddRange(collection); } } } internal static void Watcher(float dt) { if (buffer.Count >= bufferCapacity || timer > 0.5f) { WriteBuffers(); } else { timer += dt; } } internal static void WriteBuffers() { try { if (buffer.Count > 0 && !hasErrors) { if (!File.Exists(filepath)) { using (File.Create(filepath)) { } } using StreamWriter streamWriter = File.AppendText(filepath); foreach (string item in buffer) { streamWriter.WriteLine(item); } } } catch (UnauthorizedAccessException ex) { hasErrors = true; Console.WriteLine("[Manager] [Exception] " + ex.ToString()); Console.WriteLine("[Manager] Uncheck the read-only box from the UnityModManager folder."); history.Add("[Manager] [Exception] " + ex.ToString()); history.Add("[Manager] Uncheck the read-only box from the UnityModManager folder."); } catch (Exception ex2) { hasErrors = true; Console.WriteLine("[Manager] [Exception] " + ex2.ToString()); history.Add("[Manager] [Exception] " + ex2.ToString()); } buffer.Clear(); timer = 0f; } public static void Clear() { buffer.Clear(); history.Clear(); if (File.Exists(filepath) && !hasErrors) { try { File.Delete(filepath); } catch (UnauthorizedAccessException ex) { hasErrors = true; Console.WriteLine("[Manager] [Exception] " + ex.ToString()); Console.WriteLine("[Manager] Uncheck the read-only box from the UnityModManager folder."); history.Add("[Manager] [Exception] " + ex.ToString()); history.Add("[Manager] Uncheck the read-only box from the UnityModManager folder."); } catch (Exception ex2) { hasErrors = true; Console.WriteLine("[Manager] [Exception] " + ex2.ToString()); history.Add("[Manager] [Exception] " + ex2.ToString()); } } } } public class ModInfo : IEquatable<ModInfo> { public string Id; public string DisplayName; public string Author; public string Version; public string ManagerVersion; public string GameVersion; public string[] Requirements; public string[] LoadAfter; public string AssemblyName; public string EntryMethod; public string HomePage; public string Repository; public string ContentType; [NonSerialized] public bool IsCheat = true; public static implicit operator bool(ModInfo exists) { return exists != null; } public bool Equals(ModInfo other) { return Id.Equals(other.Id); } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is ModInfo other) { return Equals(other); } return false; } public override int GetHashCode() { return Id.GetHashCode(); } } public delegate void ToggleModsListen(ModEntry modEntry, bool result); public class ModSettings { public virtual void Save(ModEntry modEntry) { Save(this, modEntry); } public virtual string GetPath(ModEntry modEntry) { return Path.Combine(modEntry.ConfigPath, "Settings.xml"); } public static void Save<T>(T data, ModEntry modEntry) where T : ModSettings, new() { Save(data, modEntry, null); } public static void Save<T>(T data, ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new() { Directory.CreateDirectory(modEntry.ConfigPath); string path = data.GetPath(modEntry); try { using StreamWriter textWriter = new StreamWriter(path); new XmlSerializer(data.GetType(), attributes).Serialize(textWriter, data); } catch (Exception e) { modEntry.Logger.Error("Can't save " + path + "."); modEntry.Logger.LogException(e); } } public static T Load<T>(ModEntry modEntry) where T : ModSettings, new() { T val = new T(); string path = val.GetPath(modEntry); if (File.Exists(path)) { try { using FileStream stream = File.OpenRead(path); return (T)new XmlSerializer(typeof(T)).Deserialize(stream); } catch (Exception e) { modEntry.Logger.Error("Can't read " + path + "."); modEntry.Logger.LogException(e); } } return val; } public static T Load<T>(ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new() { T val = new T(); string path = val.GetPath(modEntry); if (File.Exists(path)) { try { using FileStream stream = File.OpenRead(path); return (T)new XmlSerializer(typeof(T), attributes).Deserialize(stream); } catch (Exception e) { modEntry.Logger.Error("Can't read " + path + "."); modEntry.Logger.LogException(e); } } return val; } } public class Repository { [Serializable] public class Release : IEquatable<Release> { public string Id; public string Version; public string DownloadUrl; public bool Equals(Release other) { return Id.Equals(other.Id); } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is Release other) { return Equals(other); } return false; } public override int GetHashCode() { return Id.GetHashCode(); } } public Release[] Releases; } internal class TextureReplacer { public class Skin { public struct conditions { public string MaterialName; public string ObjectName; public string ObjectComponent; public string Custom; [IgnoreJson] public bool IsEmpty { get { if (string.IsNullOrEmpty(MaterialName) && string.IsNullOrEmpty(ObjectName) && string.IsNullOrEmpty(ObjectComponent)) { return string.IsNullOrEmpty(Custom); } return false; } } } public class texture { public string Path; public Texture2D Texture; public Texture2D Previous; } [IgnoreJson] public ModEntry modEntry; public string Name; public string Tags; public conditions Conditions; [IgnoreJson] public Dictionary<string, texture> textures; public override string ToString() { return Name + " (" + modEntry.Info.DisplayName + ")"; } public void WriteFile(string filePath) { try { File.WriteAllText(filePath, this.ToJson()); } catch (Exception ex) { Logger.Error(ex.ToString()); Logger.Error("Error file creating '" + filePath + "'."); } } public static Skin ReadFile(string filePath) { try { return File.ReadAllText(filePath).FromJson<Skin>(); } catch (Exception ex) { Logger.Error(ex.ToString()); Logger.Error("Can't read file '" + filePath + "'."); return null; } } public static implicit operator bool(Skin exists) { return exists != null; } public bool Equals(Skin other) { if (Name.Equals(other.Name)) { return modEntry.Info.Equals(other.modEntry.Info); } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is Skin other) { return Equals(other); } return false; } public override int GetHashCode() { return Name.GetHashCode() + modEntry.Info.GetHashCode(); } } public static void Start() { } } public class UI : MonoBehaviour { private class PopupWindow { internal const int MARGIN = 100; internal int mId; internal Rect mWindowRect; internal Vector2 mScrollPosition; internal int mWidth; internal int mHeight; internal int mRecalculateFrame; internal bool mOpened; public HashSet<int> DestroyCounter { get; set; } = new HashSet<int>(); internal bool Recalculating => mRecalculateFrame == Time.frameCount; public bool Opened { get { return mOpened; } set { mOpened = value; if (value) { Reset(); } } } public PopupWindow() { mId = GetNextWindowId(); mPopupList.Add(this); } public void Reset() { //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) mRecalculateFrame = Time.frameCount; mWindowRect = new Rect(-9000f, 0f, 0f, 0f); } public virtual void Render() { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_003a: Expected O, but got Unknown //IL_0035: 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) if (Recalculating) { mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (((Rect)(ref mWindowRect)).width > 0f) { mWidth = (int)Math.Min(Math.Max(((Rect)(ref mWindowRect)).width, 250f), Screen.width - 100); mHeight = (int)Math.Min(((Rect)(ref mWindowRect)).height, Screen.height - 100); ((Rect)(ref mWindowRect)).x = Math.Max(Screen.width - mWidth, 0) / 2; ((Rect)(ref mWindowRect)).y = Math.Max(Screen.height - mHeight, 0) / 2; } } else { mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width((float)mWidth), GUILayout.Height((float)(mHeight + 20)) }); GUI.BringWindowToFront(mId); } } public virtual void WindowFunction(int windowId) { throw new NotImplementedException(); } } private class PopupToggleGroup_GUI : PopupWindow { public int? newSelected; public int selected; public readonly string[] values; public string title; public int unique; public PopupToggleGroup_GUI(string[] values) { this.values = values; } public void Button(string text = null, GUIStyle style = null, params GUILayoutOption[] option) { base.DestroyCounter.Clear(); if (!GUILayout.Button(text ?? values[selected], style ?? GUI.skin.button, option)) { return; } if (!base.Opened) { foreach (PopupWindow mPopup in mPopupList) { mPopup.Opened = false; } base.Opened = true; } else { base.Opened = false; } } public override void WindowFunction(int windowId) { //IL_0028: 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) if (title != null) { GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (!base.Recalculating) { mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (values != null) { int num = 0; string[] array = values; foreach (string text in array) { if (GUILayout.Button((num == selected) ? ("<b>" + text + "</b>") : text, (GUILayoutOption[])(object)new GUILayoutOption[0])) { newSelected = num; base.Opened = false; } num++; } } if (!base.Recalculating) { GUILayout.EndScrollView(); } } } private class PopupToggleMulti_GUI : PopupWindow { public int? newSelected; public int selected; public readonly string[] values; public readonly int[] flags; public string title; public int unique; public PopupToggleMulti_GUI(string[] values, int[] flags) { this.values = values; this.flags = flags; } public void Button(string text = null, GUIStyle style = null, params GUILayoutOption[] option) { base.DestroyCounter.Clear(); int num = -1; int num2 = 0; int num3 = 0; int[] array = flags; foreach (int num4 in array) { if ((selected & num4) == num4) { num = ((num >= 0) ? num : num3); num2++; } num3++; } if (!GUILayout.Button(text ?? ((num2 >= 2) ? $"{values[num]} and {num2 - 1} more" : ((num2 == 1) ? values[num] : "None")), style ?? GUI.skin.button, option)) { return; } if (!base.Opened) { foreach (PopupWindow mPopup in mPopupList) { mPopup.Opened = false; } base.Opened = true; } else { base.Opened = false; } } public override void WindowFunction(int windowId) { //IL_0028: 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) if (title != null) { GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (!base.Recalculating) { mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (values != null && flags != null) { int num = 0; string[] array = values; foreach (string text in array) { bool flag = (selected & flags[num]) == flags[num]; if (GUILayout.Toggle(flag, text, (GUILayoutOption[])(object)new GUILayoutOption[0]) != flag) { if ((selected & flags[num]) == flags[num]) { newSelected = selected ^ flags[num]; } else { newSelected = selected | flags[num]; } } num++; } } if (!base.Recalculating) { GUILayout.EndScrollView(); } if (GUILayout.Button("Close", button, (GUILayoutOption[])(object)new GUILayoutOption[0])) { base.Opened = false; } } } private class Column { public string name; public float width; public bool expand; public bool skip; } internal class WindowParams { public int? Width { get; set; } public int? Height { get; set; } } internal class Window_GUI { internal static readonly List<Window_GUI> mList = new List<Window_GUI>(); internal readonly HashSet<int> mDestroyCounter = new HashSet<int>(); private const int MARGIN = 50; private int mId; private Rect mWindowRect; private Vector2 mScrollPosition; private int mWidth; private int mHeight; private int mRecalculateFrame; private bool mOpened; internal string title; internal int unique; internal Action<Window_GUI> onGui; internal Action onClose; private bool Recalculating => mRecalculateFrame == Time.frameCount; public bool Opened { get { return mOpened; } internal set { mOpened = value; if (value) { Reset(); } } } public WindowParams Params { get; internal set; } public Window_GUI(Action<Window_GUI> onGui, Action onClose, string title, int unique, WindowParams @params = null) { mId = GetNextWindowId(); mList.Add(this); this.onGui = onGui; this.onClose = onClose; this.unique = unique; this.title = title; Params = @params ?? new WindowParams(); } public void Render() { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (Recalculating) { mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (((Rect)(ref mWindowRect)).width > 0f) { mWidth = (int)Math.Min(((float?)Params.Width) ?? ((Rect)(ref mWindowRect)).width, Screen.width - 100); mHeight = (int)Math.Min(((float?)Params.Height) ?? ((Rect)(ref mWindowRect)).height, Screen.height - 100); ((Rect)(ref mWindowRect)).x = Math.Max(Screen.width - mWidth, 0) / 2; ((Rect)(ref mWindowRect)).y = Math.Max(Screen.height - mHeight, 0) / 2; } } else { mWindowRect = GUILayout.Window(mId, mWindowRect, new WindowFunction(WindowFunction), "", window, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width((float)mWidth), GUILayout.Height((float)(mHeight + 10)) }); GUI.BringWindowToFront(mId); } } private void WindowFunction(int windowId) { //IL_0028: 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) if (title != null) { GUILayout.Label(title, h1, (GUILayoutOption[])(object)new GUILayoutOption[0]); } if (!Recalculating) { mScrollPosition = GUILayout.BeginScrollView(mScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[0]); } onGui(this); if (!Recalculating) { GUILayout.EndScrollView(); } } internal void Reset() { //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) mRecalculateFrame = Time.frameCount; mWindowRect = new Rect(-9000f, 0f, 0f, 0f); } public void Close() { if (!Opened) { return; } Opened = false; if (onClose == null) { return; } try { onClose(); } catch (Exception ex) { Logger.Error("Window.OnClose: " + ex.GetType()?.ToString() + " - " + ex.Message); Console.WriteLine(ex.ToString()); } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<Color32, Color32> <>9__68_0; public static Action<ModEntry> <>9__82_0; public static Action<ModEntry> <>9__82_1; public static UnityAction <>9__87_0; public static Func<Column, bool> <>9__89_0; public static Func<Column, float> <>9__89_1; public static Func<Column, bool> <>9__89_2; public static Func<Column, float> <>9__89_3; public static UnityAction <>9__89_5; public static Action<int> <>9__89_6; public static Func<ModEntry, bool> <>9__100_0; public static Func<object, bool> <>9__147_4; public static Func<PropertyAttribute, int> <>9__147_5; public static Converter<object, float> <>9__147_8; public static Converter<object, int> <>9__147_9; public static Converter<object, long> <>9__147_10; public static Converter<object, double> <>9__147_11; public static Converter<object, string> <>9__147_12; internal Color32 <PrepareGUI>b__68_0(Color32 x) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ((Color32)(ref x))..ctor((byte)30, (byte)30, (byte)30, byte.MaxValue); return x; } internal void <set_ShowModSettings>b__82_0(ModEntry mod) { if (mod.Active && mod.OnHideGUI != null && mod.OnGUI != null) { try { mod.OnHideGUI(mod); } catch (ExitGUIException) { } catch (Exception e) { mod.Logger.LogException("OnHideGUI", e); } } } internal void <set_ShowModSettings>b__82_1(ModEntry mod) { if (mod.Active && mod.OnShowGUI != null && mod.OnGUI != null) { try { mod.OnShowGUI(mod); } catch (ExitGUIException) { } catch (Exception e) { mod.Logger.LogException("OnShowGUI", e); } } } internal void <WindowFunction>b__87_0() { } internal bool <DrawTab>b__89_0(Column x) { return !x.skip; } internal float <DrawTab>b__89_1(Column x) { return x.width; } internal bool <DrawTab>b__89_2(Column x) { if (x.expand) { return !x.skip; } return false; } internal float <DrawTab>b__89_3(Column x) { return x.width; } internal void <DrawTab>b__89_5() { if (GUILayout.Button("Clear", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { Logger.Clear(); } if (GUILayout.Button("Open Unity log", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { OpenUnityFileLog(); } if (GUILayout.Button("Open UMM log", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { OpenUMMLog(); } } internal void <DrawTab>b__89_6(int i) { Params.ShowOnStart = i; } internal bool <FirstLaunch>b__100_0(ModEntry x) { return !x.ErrorOnLoading; } internal bool <Draw>b__147_4(object x) { return x is PropertyAttribute; } internal int <Draw>b__147_5(PropertyAttribute x) { return x.order; } internal float <Draw>b__147_8(object x) { return (float)x; } internal int <Draw>