Decompiled source of FixPluginTypesSerialization v1.1.1

BepInEx/patchers/FixPluginTypesSerialization/FixPluginTypesSerialization.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FixPluginTypesSerialization.Patchers;
using FixPluginTypesSerialization.UnityPlayer;
using FixPluginTypesSerialization.UnityPlayer.Structs.Default;
using FixPluginTypesSerialization.Util;
using Microsoft.CodeAnalysis;
using Microsoft.Deployment.Compression;
using Microsoft.Deployment.Compression.Cab;
using Mono.Cecil;
using MonoMod.RuntimeDetour;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FixPluginTypesSerialization")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+18666a053a1d3d5c39ebafa9bb4683203fadb3a7")]
[assembly: AssemblyProduct("FixPluginTypesSerialization")]
[assembly: AssemblyTitle("FixPluginTypesSerialization")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NativeIntegerAttribute : Attribute
	{
		public readonly bool[] TransformFlags;

		public NativeIntegerAttribute()
		{
			TransformFlags = new bool[1] { true };
		}

		public NativeIntegerAttribute(bool[] P_0)
		{
			TransformFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FixPluginTypesSerialization
{
	internal static class Config
	{
		private static readonly ConfigFile _config = new ConfigFile(Path.Combine(Paths.ConfigPath, "FixPluginTypesSerialization.cfg"), true);

		internal static ConfigEntry<string> UnityVersionOverride = _config.Bind<string>("Cache", "UnityVersionOverride", "", "Unity version is Major.Minor.Patch format i.e. 2017.2.1. If specified, this version will be used instead of auto-detection from executable info. Specify only if the patcher doesn't work otherwise.");

		internal static ConfigEntry<string> LastDownloadedGUID = _config.Bind<string>("Cache", "LastDownloadedGUID", "000000000000000000000000000000000", "The GUID of the last downloaded UnityPlayer pdb file." + Environment.NewLine + "If this GUID matches with the current one," + Environment.NewLine + "the offsets for the functions below will be used" + Environment.NewLine + "instead of generating them at runtime.");

		internal static ConfigEntry<string> MonoManagerAwakeFromLoadOffset = _config.Bind<string>("Cache", "MonoManagerAwakeFromLoadOffset", "00", "The in-memory offset of the MonoManager::AwakeFromLoad function.");

		internal static ConfigEntry<string> MonoManagerIsAssemblyCreatedOffset = _config.Bind<string>("Cache", "MonoManagerIsAssemblyCreatedOffset", "00", "The in-memory offset of the MonoManager::IsAssemblyCreated function.");

		internal static ConfigEntry<string> IsFileCreatedOffset = _config.Bind<string>("Cache", "IsFileCreatedOffset", "00", "The in-memory offset of the IsFileCreated function.");

		internal static ConfigEntry<string> ScriptingManagerDeconstructorOffset = _config.Bind<string>("Cache", "ScriptingManagerDeconstructorOffset", "00", "The in-memory offset of the ScriptingManagerDeconstructor function.");

		internal static ConfigEntry<string> ConvertSeparatorsToPlatformOffset = _config.Bind<string>("Cache", "ConvertSeparatorsToPlatformOffset", "00", "The in-memory offset of the ConvertSeparatorsToPlatform function.");

		internal static ConfigEntry<string> FreeAllocInternalOffset = _config.Bind<string>("Cache", "FreeAllocInternalOffset", "00", "The in-memory offset of the free_alloc_internal function.");

		internal static ConfigEntry<string> MallocInternalOffset = _config.Bind<string>("Cache", "MallocInternalOffset", "00", "The in-memory offset of the malloc_internal function.");

		internal static ConfigEntry<string> ScriptingAssembliesOffset = _config.Bind<string>("Cache", "ScriptingAssembliesOffset", "00", "The in-memory offset of the m_ScriptingAssemblies global field.");
	}
	internal static class FixPluginTypesSerializationPatcher
	{
		public static List<string> PluginPaths = (from f in Directory.GetFiles(Paths.PluginPath, "*.dll", SearchOption.AllDirectories)
			where IsNetAssembly(f)
			select f).ToList();

		public static List<string> PluginNames = PluginPaths.Select((string p) => Path.GetFileName(p)).ToList();

		public static IEnumerable<string> TargetDLLs { get; } = new string[0];


		public static bool IsNetAssembly(string fileName)
		{
			try
			{
				AssemblyName.GetAssemblyName(fileName);
			}
			catch (BadImageFormatException)
			{
				return false;
			}
			return true;
		}

		public static void Patch(AssemblyDefinition ass)
		{
		}

		public static void Initialize()
		{
			Log.Init();
			try
			{
				InitializeInternal();
			}
			catch (Exception ex)
			{
				Log.Error($"Failed to initialize plugin types serialization fix: ({ex.GetType()}) {ex.Message}. Some plugins may not work properly.");
				Log.Error(ex);
			}
		}

		private static void InitializeInternal()
		{
			DetourUnityPlayer();
		}

		private static void DetourUnityPlayer()
		{
			string text = Path.Combine(Paths.GameRootPath, "UnityPlayer.dll");
			if (!File.Exists(text))
			{
				text = Paths.ExecutablePath;
			}
			MiniPdbReader pdbReader = new MiniPdbReader(text);
			ProcessModule processModule = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().FirstOrDefault(IsUnityPlayer) ?? Process.GetCurrentProcess().MainModule;
			CommonUnityFunctions.Init(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader);
			AwakeFromLoad awakeFromLoad = new AwakeFromLoad();
			IsAssemblyCreated isAssemblyCreated = new IsAssemblyCreated();
			IsFileCreated isFileCreated = new IsFileCreated();
			ScriptingManagerDeconstructor scriptingManagerDeconstructor = new ScriptingManagerDeconstructor();
			ConvertSeparatorsToPlatform convertSeparatorsToPlatform = new ConvertSeparatorsToPlatform();
			awakeFromLoad.Patch(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader, Config.MonoManagerAwakeFromLoadOffset);
			isAssemblyCreated.Patch(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader, Config.MonoManagerIsAssemblyCreatedOffset);
			if (!IsAssemblyCreated.IsApplied)
			{
				isFileCreated.Patch(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader, Config.IsFileCreatedOffset);
			}
			convertSeparatorsToPlatform.Patch(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader, Config.ConvertSeparatorsToPlatformOffset);
			scriptingManagerDeconstructor.Patch(processModule.BaseAddress, processModule.ModuleMemorySize, pdbReader, Config.ScriptingManagerDeconstructorOffset);
			static bool IsUnityPlayer(ProcessModule p)
			{
				return p.ModuleName.ToLowerInvariant().Contains("unityplayer");
			}
		}
	}
	internal static class Log
	{
		internal static ManualLogSource _logSource;

		internal static void Init()
		{
			_logSource = Logger.CreateLogSource("FixPluginTypesSerialization");
		}

		internal static void Debug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "FixPluginTypesSerialization";

		public const string PLUGIN_NAME = "FixPluginTypesSerialization";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace FixPluginTypesSerialization.Util
{
	internal class BytePattern
	{
		private readonly byte?[] pattern;

		private int[] jumpTable;

		public int Length => pattern.Length;

		public bool IsE8 => pattern[0] == 232;

		public BytePattern(string bytes)
		{
			pattern = bytes.ParseHexBytes();
			CreateJumpTable();
		}

		public BytePattern(byte[] bytes)
		{
			pattern = bytes.Cast<byte?>().ToArray();
			CreateJumpTable();
		}

		public static implicit operator BytePattern(string pattern)
		{
			return new BytePattern(pattern);
		}

		public static implicit operator BytePattern(byte[] pattern)
		{
			return new BytePattern(pattern);
		}

		private void CreateJumpTable()
		{
			jumpTable = new int[pattern.Length];
			int num = 0;
			jumpTable[0] = -1;
			int num2 = 1;
			while (num2 < pattern.Length)
			{
				if (pattern[num2] == pattern[num])
				{
					jumpTable[num2] = jumpTable[num];
				}
				else
				{
					jumpTable[num2] = num;
					while (num >= 0 && pattern[num2] != pattern[num])
					{
						num = jumpTable[num];
					}
				}
				num2++;
				num++;
			}
		}

		public unsafe long Match(IntPtr start, long maxSize)
		{
			byte* ptr = (byte*)start.ToPointer();
			long num = 0L;
			long num2 = 0L;
			while (num < maxSize)
			{
				if (!pattern[num2].HasValue || ptr[num] == pattern[num2])
				{
					num++;
					num2++;
					if (num2 == pattern.Length)
					{
						return num - num2;
					}
				}
				else
				{
					num2 = jumpTable[num2];
					if (num2 < 0)
					{
						num++;
						num2++;
					}
				}
			}
			return 0L;
		}
	}
	internal class CommonUnityFunctions
	{
		public enum AllocateOptions
		{
			None,
			NullIfOutOfMemory
		}

		private delegate IntPtr MallocInternalFunc(ulong size, ulong allign, int label, AllocateOptions allocateOptions, IntPtr file, int line);

		private delegate void FreeAllocInternalV1Func(IntPtr ptr, int label);

		private delegate void FreeAllocInternalV2Func(IntPtr ptr, int label, IntPtr file, int line);

		private static MallocInternalFunc mallocInternal;

		private static FreeAllocInternalV1Func freeAllocInternalV1;

		private static FreeAllocInternalV2Func freeAllocInternalV2;

		public static IntPtr ScriptingAssemblies { get; private set; }

		public static void Init(IntPtr unityModule, int moduleSize, MiniPdbReader pdbReader)
		{
			IntPtr intPtr = PatternDiscover.Discover(unityModule, moduleSize, pdbReader, Config.MallocInternalOffset, new BytePattern[1] { Encoding.ASCII.GetBytes("malloc_internal") }, Array.Empty<BytePattern>());
			if (intPtr != IntPtr.Zero)
			{
				mallocInternal = (MallocInternalFunc)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(MallocInternalFunc));
			}
			IntPtr intPtr2 = PatternDiscover.Discover(unityModule, moduleSize, pdbReader, Config.FreeAllocInternalOffset, new BytePattern[1] { Encoding.ASCII.GetBytes("free_alloc_internal") }, Array.Empty<BytePattern>());
			if (intPtr2 != IntPtr.Zero)
			{
				if (UseRightStructs.UnityVersion >= new Version(2019, 3))
				{
					freeAllocInternalV2 = (FreeAllocInternalV2Func)Marshal.GetDelegateForFunctionPointer(intPtr2, typeof(FreeAllocInternalV2Func));
				}
				else
				{
					freeAllocInternalV1 = (FreeAllocInternalV1Func)Marshal.GetDelegateForFunctionPointer(intPtr2, typeof(FreeAllocInternalV1Func));
				}
			}
			IntPtr intPtr3 = PatternDiscover.Discover(unityModule, moduleSize, pdbReader, Config.ScriptingAssembliesOffset, new BytePattern[1] { Encoding.ASCII.GetBytes("m_ScriptingAssemblies@") }, Array.Empty<BytePattern>());
			if (intPtr3 != IntPtr.Zero)
			{
				ScriptingAssemblies = intPtr3;
			}
		}

		public unsafe static IntPtr MallocString(string str, int label, out ulong length)
		{
			IntPtr intPtr = Marshal.StringToHGlobalAnsi(str);
			length = (ulong)str.Length;
			byte* ptr = (byte*)(void*)intPtr + length;
			while (*ptr != 0)
			{
				ptr++;
				length++;
			}
			IntPtr intPtr2 = mallocInternal(length + 1, 16uL, label, AllocateOptions.NullIfOutOfMemory, IntPtr.Zero, 0);
			for (ulong num = 0uL; num <= length; num++)
			{
				((byte*)(void*)intPtr2)[num] = ((byte*)(void*)intPtr)[num];
			}
			Marshal.FreeHGlobal(intPtr);
			return intPtr2;
		}

		public static IntPtr MallocInternal(ulong size, ulong allign, int label)
		{
			return mallocInternal(size, allign, label, AllocateOptions.NullIfOutOfMemory, IntPtr.Zero, 0);
		}

		public static void FreeAllocInternal(IntPtr ptr, int label)
		{
			if (UseRightStructs.UnityVersion >= new Version(2019, 3))
			{
				freeAllocInternalV2(ptr, label, IntPtr.Zero, 0);
			}
			else
			{
				freeAllocInternalV1(ptr, label);
			}
		}
	}
	internal static class DictionaryExtensions
	{
		public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
		{
			key = tuple.Key;
			value = tuple.Value;
		}

		public static void Deconstruct(this VersionedHandler versionedHandler, out Version version, out object handler)
		{
			version = versionedHandler.version;
			handler = versionedHandler.handler;
		}
	}
	internal class MiniPdbReader
	{
		private static readonly HttpClient _httpClient = new HttpClient
		{
			Timeout = TimeSpan.FromMinutes(5.0)
		};

		private readonly PeReader _peReader;

		private byte[] _pdbFile;

		internal bool IsPdbAvailable;

		internal bool UseCache;

		private static byte[] DownloadFromWeb(string url)
		{
			Log.Info("Downloading : " + url + "\nThis pdb file is needed for the plugin to work properly. This may take a while, relax, modding is coming.");
			try
			{
				HttpResponseMessage result = _httpClient.GetAsync(url).GetAwaiter().GetResult();
				Log.Info("Status Code : " + result.StatusCode);
				if (result.StatusCode != HttpStatusCode.OK)
				{
					return null;
				}
				return result.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
			}
			catch (TaskCanceledException)
			{
				Log.Info("Could not download pdb. Plugin may not work correctly.");
				return null;
			}
		}

		internal MiniPdbReader(string targetFilePath)
		{
			_peReader = new PeReader(targetFilePath);
			if (_peReader.RsdsPdbFileName == null)
			{
				Log.Info("No pdb path found in the pe file. Falling back to sig matching");
				return;
			}
			UseCache = Config.LastDownloadedGUID.Value == _peReader.PdbGuid;
			Log.Message((UseCache ? "U" : "Not u") + "sing the config cache");
			if (!UseCache)
			{
				if (DownloadUnityPdb(_peReader))
				{
					Config.LastDownloadedGUID.Value = _peReader.PdbGuid;
					IsPdbAvailable = true;
				}
				else
				{
					Log.Info("Failed to find the linked pdb in the unity symbol server. Falling back to sig matching");
				}
			}
			else
			{
				IsPdbAvailable = true;
			}
		}

		private bool DownloadUnityPdb(PeReader peReader)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			string path = peReader.RsdsPdbFileName.TrimEnd('b') + "_";
			byte[] array = DownloadFromWeb(Path.Combine("http://symbolserver.unity3d.com/", peReader.RsdsPdbFileName, peReader.PdbGuid, path));
			if (array != null)
			{
				string tempPath = Path.GetTempPath();
				string text = Path.Combine(tempPath, "pdb.cab");
				try
				{
					File.Delete(text);
				}
				catch (Exception)
				{
				}
				Log.Info("Writing the compressed pdb to " + text);
				File.WriteAllBytes(text, array);
				CabInfo val = new CabInfo(text);
				Log.Info("Unpacking the compressed pdb");
				((ArchiveInfo)val).Unpack(tempPath);
				string path2 = Path.Combine(tempPath, peReader.RsdsPdbFileName);
				_pdbFile = File.ReadAllBytes(path2);
				File.Delete(text);
				File.Delete(path2);
			}
			return _pdbFile != null;
		}

		internal unsafe IntPtr FindFunctionOffset(BytePattern[] bytePatterns)
		{
			fixed (byte* ptr = &_pdbFile[0])
			{
				IntPtr pdbStartAddress = (IntPtr)ptr;
				long sizeOfPdb = _pdbFile.Length;
				var anon = bytePatterns.Select((BytePattern p) => new
				{
					p = p,
					res = p.Match(pdbStartAddress, sizeOfPdb)
				}).FirstOrDefault(m => m.res > 0);
				if (anon == null)
				{
					Log.Error("No function offset found, cannot hook ! Please report it to the r2api devs !");
					return IntPtr.Zero;
				}
				Log.Info($"Found at {anon.res:X} ({pdbStartAddress.ToInt64() + anon.res:X})");
				uint* ptr2 = (uint*)(pdbStartAddress.ToInt64() + anon.res - 7);
				uint num = *ptr2;
				ushort* ptr3 = (ushort*)(pdbStartAddress.ToInt64() + anon.res - 3);
				int num2 = *ptr3 - 1;
				num += _peReader.ImageSectionHeaders[num2].VirtualAddress;
				Log.Info("Function offset : " + num.ToString("X") + " | PE section : " + num2);
				return new IntPtr(num);
			}
		}
	}
	internal static class MonoManagerCommon
	{
		public unsafe static void CopyNativeAssemblyListToManagedV1(List<StringStorageDefaultV1> managedAssemblyList, Vector<StringStorageDefaultV1> assemblyNames)
		{
			managedAssemblyList.Clear();
			for (StringStorageDefaultV1* ptr = assemblyNames.first; ptr != assemblyNames.last; ptr++)
			{
				managedAssemblyList.Add(*ptr);
			}
		}

		public unsafe static void AddAssembliesToManagedListV1(List<StringStorageDefaultV1> managedAssemblyList, List<string> pluginAssemblyPaths)
		{
			foreach (string pluginAssemblyPath in pluginAssemblyPaths)
			{
				string? fileName = Path.GetFileName(pluginAssemblyPath);
				ulong num = (ulong)fileName.Length;
				IntPtr intPtr = Marshal.StringToHGlobalAnsi(fileName);
				byte* ptr = (byte*)(void*)intPtr + num;
				while (*ptr != 0)
				{
					ptr++;
					num++;
				}
				StringStorageDefaultV1 stringStorageDefaultV = default(StringStorageDefaultV1);
				stringStorageDefaultV.label = UseRightStructs.LabelMemStringId;
				stringStorageDefaultV.data = intPtr;
				stringStorageDefaultV.capacity = num;
				stringStorageDefaultV.size = num;
				StringStorageDefaultV1 item = stringStorageDefaultV;
				managedAssemblyList.Add(item);
			}
		}

		public unsafe static void AllocNativeAssemblyListFromManagedV1(List<StringStorageDefaultV1> managedAssemblyList, Vector<StringStorageDefaultV1>* assemblyNames)
		{
			StringStorageDefaultV1* ptr = (StringStorageDefaultV1*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StringStorageDefaultV1)) * managedAssemblyList.Count);
			int i = 0;
			StringStorageDefaultV1* ptr2 = ptr;
			for (; i < managedAssemblyList.Count; i++)
			{
				*ptr2 = managedAssemblyList[i];
				ptr2++;
			}
			assemblyNames->first = ptr;
			assemblyNames->last = ptr + managedAssemblyList.Count;
			assemblyNames->end = assemblyNames->last;
		}

		public unsafe static void PrintAssembliesV1(Vector<StringStorageDefaultV1> assemblyNames)
		{
			for (StringStorageDefaultV1* ptr = assemblyNames.first; ptr != assemblyNames.last; ptr++)
			{
				nint ptr2 = ptr->data;
				if (ptr->data == 0)
				{
					ptr2 = (nint)((byte*)ptr + 8);
				}
				Log.Warning($"Ass: {Marshal.PtrToStringAnsi(ptr2, (int)ptr->size)} | label : {ptr->label:X}");
			}
		}

		public unsafe static void CopyNativeAssemblyListToManagedV2(List<StringStorageDefaultV1> managedAssemblyList, DynamicArrayData assemblyNames)
		{
			managedAssemblyList.Clear();
			ulong num = 0uL;
			StringStorageDefaultV1* ptr = (StringStorageDefaultV1*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				managedAssemblyList.Add(*ptr);
				ptr++;
			}
		}

		public unsafe static void AllocNativeAssemblyListFromManagedV2(List<StringStorageDefaultV1> managedAssemblyList, DynamicArrayData* assemblyNames)
		{
			StringStorageDefaultV1* ptr = (StringStorageDefaultV1*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StringStorageDefaultV1)) * managedAssemblyList.Count);
			int i = 0;
			StringStorageDefaultV1* ptr2 = ptr;
			for (; i < managedAssemblyList.Count; i++)
			{
				*ptr2 = managedAssemblyList[i];
				ptr2++;
			}
			assemblyNames->ptr = (nint)ptr;
			assemblyNames->size = (ulong)managedAssemblyList.Count;
			assemblyNames->capacity = assemblyNames->size;
		}

		public unsafe static void PrintAssembliesV2(DynamicArrayData assemblyNames)
		{
			ulong num = 0uL;
			StringStorageDefaultV1* ptr = (StringStorageDefaultV1*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				nint ptr2 = ptr->data;
				if (ptr->data == 0)
				{
					ptr2 = (nint)((byte*)ptr + 8);
				}
				Log.Warning($"Ass: {Marshal.PtrToStringAnsi(ptr2, (int)ptr->size)} | label : {ptr->label:X}");
				ptr++;
			}
		}

		public unsafe static void CopyNativeAssemblyListToManagedV3(List<StringStorageDefaultV2> managedAssemblyList, DynamicArrayData assemblyNames)
		{
			managedAssemblyList.Clear();
			ulong num = 0uL;
			StringStorageDefaultV2* ptr = (StringStorageDefaultV2*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				managedAssemblyList.Add(*ptr);
				ptr++;
			}
		}

		public unsafe static void AddAssembliesToManagedListV3(List<StringStorageDefaultV2> managedAssemblyList, List<string> pluginAssemblyPaths)
		{
			foreach (string pluginAssemblyPath in pluginAssemblyPaths)
			{
				string? fileName = Path.GetFileName(pluginAssemblyPath);
				ulong num = (ulong)fileName.Length;
				IntPtr intPtr = Marshal.StringToHGlobalAnsi(fileName);
				byte* ptr = (byte*)(void*)intPtr + num;
				while (*ptr != 0)
				{
					ptr++;
					num++;
				}
				StringStorageDefaultV2 stringStorageDefaultV = default(StringStorageDefaultV2);
				stringStorageDefaultV.union = new StringStorageDefaultV2Union
				{
					heap = new HeapAllocatedRepresentationV2
					{
						data = intPtr,
						capacity = num,
						size = num
					}
				};
				stringStorageDefaultV.data_repr = StringRepresentation.Heap;
				stringStorageDefaultV.label = UseRightStructs.LabelMemStringId;
				StringStorageDefaultV2 item = stringStorageDefaultV;
				managedAssemblyList.Add(item);
			}
		}

		public unsafe static void AllocNativeAssemblyListFromManagedV3(List<StringStorageDefaultV2> managedAssemblyList, DynamicArrayData* assemblyNames)
		{
			StringStorageDefaultV2* ptr = (StringStorageDefaultV2*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StringStorageDefaultV2)) * managedAssemblyList.Count);
			int i = 0;
			StringStorageDefaultV2* ptr2 = ptr;
			for (; i < managedAssemblyList.Count; i++)
			{
				*ptr2 = managedAssemblyList[i];
				ptr2++;
			}
			assemblyNames->ptr = (nint)ptr;
			assemblyNames->size = (ulong)managedAssemblyList.Count;
			assemblyNames->capacity = assemblyNames->size;
		}

		public unsafe static void PrintAssembliesV3(DynamicArrayData assemblyNames)
		{
			ulong num = 0uL;
			StringStorageDefaultV2* ptr = (StringStorageDefaultV2*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				if (ptr->data_repr == StringRepresentation.Embedded)
				{
					Log.Warning($"Ass: {Marshal.PtrToStringAnsi((IntPtr)ptr->union.embedded.data)} | label : {ptr->label:X}");
				}
				else
				{
					Log.Warning($"Ass: {Marshal.PtrToStringAnsi(ptr->union.heap.data, (int)ptr->union.heap.size)} | label : {ptr->label:X}");
				}
				ptr++;
			}
		}

		public unsafe static void CopyNativeAssemblyListToManagedV4(List<StringStorageDefaultV3> managedAssemblyList, DynamicArrayData assemblyNames)
		{
			managedAssemblyList.Clear();
			ulong num = 0uL;
			StringStorageDefaultV3* ptr = (StringStorageDefaultV3*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				managedAssemblyList.Add(*ptr);
				ptr++;
			}
		}

		public unsafe static void AddAssembliesToManagedListV4(List<StringStorageDefaultV3> managedAssemblyList, List<string> pluginAssemblyPaths)
		{
			foreach (string pluginAssemblyPath in pluginAssemblyPaths)
			{
				string? fileName = Path.GetFileName(pluginAssemblyPath);
				ulong num = (ulong)fileName.Length;
				IntPtr intPtr = Marshal.StringToHGlobalAnsi(fileName);
				byte* ptr = (byte*)(void*)intPtr + num;
				while (*ptr != 0)
				{
					ptr++;
					num++;
				}
				StringStorageDefaultV3 stringStorageDefaultV = default(StringStorageDefaultV3);
				stringStorageDefaultV.union = new StringStorageDefaultV3Union
				{
					heap = new HeapAllocatedRepresentationV3
					{
						data = intPtr,
						capacity = num,
						size = num,
						flags = new StringStorageDefaultV3Flags
						{
							IsHeap = true
						}
					}
				};
				stringStorageDefaultV.label = UseRightStructs.LabelMemStringId;
				StringStorageDefaultV3 item = stringStorageDefaultV;
				managedAssemblyList.Add(item);
			}
		}

		public unsafe static void AllocNativeAssemblyListFromManagedV4(List<StringStorageDefaultV3> managedAssemblyList, DynamicArrayData* assemblyNames)
		{
			StringStorageDefaultV3* ptr = (StringStorageDefaultV3*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StringStorageDefaultV3)) * managedAssemblyList.Count);
			int i = 0;
			StringStorageDefaultV3* ptr2 = ptr;
			for (; i < managedAssemblyList.Count; i++)
			{
				*ptr2 = managedAssemblyList[i];
				ptr2++;
			}
			assemblyNames->ptr = (nint)ptr;
			assemblyNames->size = (ulong)managedAssemblyList.Count;
			assemblyNames->capacity = assemblyNames->size;
		}

		public unsafe static void PrintAssembliesV4(DynamicArrayData assemblyNames)
		{
			ulong num = 0uL;
			StringStorageDefaultV3* ptr = (StringStorageDefaultV3*)assemblyNames.ptr;
			for (; num < assemblyNames.size; num++)
			{
				if (ptr->union.embedded.flags.IsEmbedded)
				{
					Log.Warning($"Ass: {Marshal.PtrToStringAnsi((IntPtr)ptr->union.embedded.data)} | label : {ptr->label:X}");
				}
				else
				{
					Log.Warning($"Ass: {Marshal.PtrToStringAnsi(ptr->union.heap.data, (int)ptr->union.heap.size)} | label : {ptr->label:X}");
				}
				ptr++;
			}
		}
	}
	internal static class NativeLibraryHelper
	{
		[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
		public class DynamicDllImportAttribute : Attribute
		{
			public string DLL;

			public string[] EntryPoints;

			public DynamicDllImportAttribute(string dll, params string[] entryPoints)
			{
				DLL = dll;
				EntryPoints = entryPoints;
			}
		}

		private static readonly IntPtr NULL = IntPtr.Zero;

		public static Dictionary<string, string> DllMap = new Dictionary<string, string>();

		private static IntPtr _EntryPoint = NULL;

		public static IntPtr EntryPoint
		{
			get
			{
				if (_EntryPoint != NULL)
				{
					return _EntryPoint;
				}
				return _EntryPoint = OpenLibrary(null);
			}
		}

		public static ulong CurrentThreadId
		{
			get
			{
				if (Environment.OSVersion.Platform == PlatformID.Win32NT)
				{
					return GetCurrentThreadId();
				}
				return 0uL;
			}
		}

		[DllImport("kernel32")]
		private static extern IntPtr GetModuleHandle(string lpModuleName);

		[DllImport("kernel32")]
		private static extern IntPtr LoadLibrary(string lpFileName);

		[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
		private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

		public static IntPtr OpenLibrary(string name)
		{
			if (DllMap.TryGetValue(name, out var value))
			{
				name = value;
			}
			if (Environment.OSVersion.Platform == PlatformID.Win32NT)
			{
				IntPtr intPtr = GetModuleHandle(name);
				if (intPtr == NULL)
				{
					intPtr = LoadLibrary(name);
				}
				return intPtr;
			}
			return NULL;
		}

		public static IntPtr GetFunction(this IntPtr lib, string name)
		{
			if (lib == NULL)
			{
				return NULL;
			}
			if (Environment.OSVersion.Platform == PlatformID.Win32NT)
			{
				return GetProcAddress(lib, name);
			}
			return NULL;
		}

		public static T GetDelegate<T>(this IntPtr lib, string name) where T : class
		{
			if (lib == NULL)
			{
				return null;
			}
			IntPtr function = lib.GetFunction(name);
			if (function == NULL)
			{
				return null;
			}
			return function.AsDelegate<T>();
		}

		public static T GetDelegateAtRVA<T>(this IntPtr basea, long rva) where T : class
		{
			return new IntPtr(basea.ToInt64() + rva).AsDelegate<T>();
		}

		public static T AsDelegate<T>(this IntPtr s) where T : class
		{
			return Marshal.GetDelegateForFunctionPointer(s, typeof(T)) as T;
		}

		[DllImport("kernel32")]
		private static extern uint GetCurrentThreadId();

		public static void ResolveDynamicDllImports(this Type type)
		{
			FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				bool flag = true;
				object[] customAttributes = fieldInfo.GetCustomAttributes(typeof(DynamicDllImportAttribute), inherit: true);
				for (int j = 0; j < customAttributes.Length; j++)
				{
					DynamicDllImportAttribute dynamicDllImportAttribute = (DynamicDllImportAttribute)customAttributes[j];
					flag = false;
					IntPtr intPtr = OpenLibrary(dynamicDllImportAttribute.DLL);
					if (intPtr == NULL)
					{
						continue;
					}
					string[] entryPoints = dynamicDllImportAttribute.EntryPoints;
					foreach (string name in entryPoints)
					{
						IntPtr function = intPtr.GetFunction(name);
						if (!(function == NULL))
						{
							fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(function, fieldInfo.FieldType));
							flag = true;
							break;
						}
					}
					if (flag)
					{
						break;
					}
				}
				if (!flag)
				{
					throw new EntryPointNotFoundException("No matching entry point found for " + fieldInfo.Name + " in " + fieldInfo.DeclaringType.FullName);
				}
			}
		}
	}
	public struct OriginalPathData
	{
		public IntPtr thisRef;

		public IntPtr thisDataRef;

		public ulong size;

		public OriginalPathData(IntPtr thisRef, IntPtr thisDataRef, ulong size)
		{
			this.thisRef = thisRef;
			this.thisDataRef = thisDataRef;
			this.size = size;
		}
	}
	internal class PatternDiscover
	{
		public static IntPtr Discover(IntPtr unityModule, int moduleSize, MiniPdbReader pdbReader, ConfigEntry<string> functionOffsetCache, BytePattern[] pdbPatterns, BytePattern[] sigPatterns)
		{
			if (pdbReader.IsPdbAvailable)
			{
				return DiscoverWithPdb(unityModule, pdbReader, functionOffsetCache, pdbPatterns);
			}
			return DiscoverWithSig(unityModule, moduleSize, sigPatterns);
		}

		public static IntPtr DiscoverWithPdb(IntPtr unityModule, MiniPdbReader pdbReader, ConfigEntry<string> functionOffsetCache, BytePattern[] pdbPatterns)
		{
			IntPtr intPtr;
			if (pdbReader.UseCache)
			{
				intPtr = new IntPtr(Convert.ToInt64(functionOffsetCache.Value, 16));
				if (intPtr == IntPtr.Zero)
				{
					return intPtr;
				}
			}
			else
			{
				intPtr = pdbReader.FindFunctionOffset(pdbPatterns);
				if (intPtr == IntPtr.Zero)
				{
					functionOffsetCache.Value = "00";
					return intPtr;
				}
				functionOffsetCache.Value = intPtr.ToString("X");
			}
			return (IntPtr)(unityModule.ToInt64() + intPtr.ToInt64());
		}

		public unsafe static IntPtr DiscoverWithSig(IntPtr unityModule, int moduleSize, BytePattern[] sigPatterns)
		{
			var anon = sigPatterns.Select((BytePattern p) => new
			{
				p = p,
				res = p.Match(unityModule, moduleSize)
			}).FirstOrDefault(m => m.res > 0);
			if (anon == null)
			{
				return IntPtr.Zero;
			}
			byte* ptr = (byte*)unityModule.ToPointer();
			Log.Info($"Found at {anon.res:X} ({unityModule.ToInt64() + anon.res:X})");
			long num = unityModule.ToInt64() + anon.res;
			if (anon.p.IsE8)
			{
				int num2 = *(int*)(unityModule.ToInt64() + anon.res + 1);
				Log.Info($"Parsed e8_offset: {num2:X}");
				num = num + 5 + num2;
			}
			Log.Info($"memory address: {num:X} (image base: {unityModule.ToInt64():X})");
			return new IntPtr(num);
		}
	}
	internal class PeReader
	{
		public struct IMAGE_DOS_HEADER
		{
			public ushort e_magic;

			public ushort e_cblp;

			public ushort e_cp;

			public ushort e_crlc;

			public ushort e_cparhdr;

			public ushort e_minalloc;

			public ushort e_maxalloc;

			public ushort e_ss;

			public ushort e_sp;

			public ushort e_csum;

			public ushort e_ip;

			public ushort e_cs;

			public ushort e_lfarlc;

			public ushort e_ovno;

			public ushort e_res_0;

			public ushort e_res_1;

			public ushort e_res_2;

			public ushort e_res_3;

			public ushort e_oemid;

			public ushort e_oeminfo;

			public ushort e_res2_0;

			public ushort e_res2_1;

			public ushort e_res2_2;

			public ushort e_res2_3;

			public ushort e_res2_4;

			public ushort e_res2_5;

			public ushort e_res2_6;

			public ushort e_res2_7;

			public ushort e_res2_8;

			public ushort e_res2_9;

			public uint e_lfanew;
		}

		public struct IMAGE_DATA_DIRECTORY
		{
			public uint VirtualAddress;

			public uint Size;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct IMAGE_OPTIONAL_HEADER32
		{
			public ushort Magic;

			public byte MajorLinkerVersion;

			public byte MinorLinkerVersion;

			public uint SizeOfCode;

			public uint SizeOfInitializedData;

			public uint SizeOfUninitializedData;

			public uint AddressOfEntryPoint;

			public uint BaseOfCode;

			public uint BaseOfData;

			public uint ImageBase;

			public uint SectionAlignment;

			public uint FileAlignment;

			public ushort MajorOperatingSystemVersion;

			public ushort MinorOperatingSystemVersion;

			public ushort MajorImageVersion;

			public ushort MinorImageVersion;

			public ushort MajorSubsystemVersion;

			public ushort MinorSubsystemVersion;

			public uint Win32VersionValue;

			public uint SizeOfImage;

			public uint SizeOfHeaders;

			public uint CheckSum;

			public ushort Subsystem;

			public ushort DllCharacteristics;

			public uint SizeOfStackReserve;

			public uint SizeOfStackCommit;

			public uint SizeOfHeapReserve;

			public uint SizeOfHeapCommit;

			public uint LoaderFlags;

			public uint NumberOfRvaAndSizes;

			public IMAGE_DATA_DIRECTORY ExportTable;

			public IMAGE_DATA_DIRECTORY ImportTable;

			public IMAGE_DATA_DIRECTORY ResourceTable;

			public IMAGE_DATA_DIRECTORY ExceptionTable;

			public IMAGE_DATA_DIRECTORY CertificateTable;

			public IMAGE_DATA_DIRECTORY BaseRelocationTable;

			public IMAGE_DATA_DIRECTORY Debug;

			public IMAGE_DATA_DIRECTORY Architecture;

			public IMAGE_DATA_DIRECTORY GlobalPtr;

			public IMAGE_DATA_DIRECTORY TLSTable;

			public IMAGE_DATA_DIRECTORY LoadConfigTable;

			public IMAGE_DATA_DIRECTORY BoundImport;

			public IMAGE_DATA_DIRECTORY IAT;

			public IMAGE_DATA_DIRECTORY DelayImportDescriptor;

			public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;

			public IMAGE_DATA_DIRECTORY Reserved;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct IMAGE_OPTIONAL_HEADER64
		{
			public ushort Magic;

			public byte MajorLinkerVersion;

			public byte MinorLinkerVersion;

			public uint SizeOfCode;

			public uint SizeOfInitializedData;

			public uint SizeOfUninitializedData;

			public uint AddressOfEntryPoint;

			public uint BaseOfCode;

			public ulong ImageBase;

			public uint SectionAlignment;

			public uint FileAlignment;

			public ushort MajorOperatingSystemVersion;

			public ushort MinorOperatingSystemVersion;

			public ushort MajorImageVersion;

			public ushort MinorImageVersion;

			public ushort MajorSubsystemVersion;

			public ushort MinorSubsystemVersion;

			public uint Win32VersionValue;

			public uint SizeOfImage;

			public uint SizeOfHeaders;

			public uint CheckSum;

			public ushort Subsystem;

			public ushort DllCharacteristics;

			public ulong SizeOfStackReserve;

			public ulong SizeOfStackCommit;

			public ulong SizeOfHeapReserve;

			public ulong SizeOfHeapCommit;

			public uint LoaderFlags;

			public uint NumberOfRvaAndSizes;

			public IMAGE_DATA_DIRECTORY ExportTable;

			public IMAGE_DATA_DIRECTORY ImportTable;

			public IMAGE_DATA_DIRECTORY ResourceTable;

			public IMAGE_DATA_DIRECTORY ExceptionTable;

			public IMAGE_DATA_DIRECTORY CertificateTable;

			public IMAGE_DATA_DIRECTORY BaseRelocationTable;

			public IMAGE_DATA_DIRECTORY Debug;

			public IMAGE_DATA_DIRECTORY Architecture;

			public IMAGE_DATA_DIRECTORY GlobalPtr;

			public IMAGE_DATA_DIRECTORY TLSTable;

			public IMAGE_DATA_DIRECTORY LoadConfigTable;

			public IMAGE_DATA_DIRECTORY BoundImport;

			public IMAGE_DATA_DIRECTORY IAT;

			public IMAGE_DATA_DIRECTORY DelayImportDescriptor;

			public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;

			public IMAGE_DATA_DIRECTORY Reserved;
		}

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct IMAGE_FILE_HEADER
		{
			public ushort Machine;

			public ushort NumberOfSections;

			public uint TimeDateStamp;

			public uint PointerToSymbolTable;

			public uint NumberOfSymbols;

			public ushort SizeOfOptionalHeader;

			public ushort Characteristics;
		}

		[StructLayout(LayoutKind.Explicit)]
		public struct IMAGE_SECTION_HEADER
		{
			[FieldOffset(0)]
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
			public string Name;

			[FieldOffset(8)]
			public uint VirtualSize;

			[FieldOffset(12)]
			public uint VirtualAddress;

			[FieldOffset(16)]
			public uint SizeOfRawData;

			[FieldOffset(20)]
			public uint PointerToRawData;

			[FieldOffset(24)]
			public uint PointerToRelocations;

			[FieldOffset(28)]
			public uint PointerToLinenumbers;

			[FieldOffset(32)]
			public ushort NumberOfRelocations;

			[FieldOffset(34)]
			public ushort NumberOfLinenumbers;

			[FieldOffset(36)]
			public DataSectionFlags Characteristics;
		}

		[Flags]
		public enum DataSectionFlags : uint
		{
			TypeReg = 0u,
			TypeDsect = 1u,
			TypeNoLoad = 2u,
			TypeGroup = 4u,
			TypeNoPadded = 8u,
			TypeCopy = 0x10u,
			ContentCode = 0x20u,
			ContentInitializedData = 0x40u,
			ContentUninitializedData = 0x80u,
			LinkOther = 0x100u,
			LinkInfo = 0x200u,
			TypeOver = 0x400u,
			LinkRemove = 0x800u,
			LinkComDat = 0x1000u,
			NoDeferSpecExceptions = 0x4000u,
			RelativeGP = 0x8000u,
			MemPurgeable = 0x20000u,
			Memory16Bit = 0x20000u,
			MemoryLocked = 0x40000u,
			MemoryPreload = 0x80000u,
			Align1Bytes = 0x100000u,
			Align2Bytes = 0x200000u,
			Align4Bytes = 0x300000u,
			Align8Bytes = 0x400000u,
			Align16Bytes = 0x500000u,
			Align32Bytes = 0x600000u,
			Align64Bytes = 0x700000u,
			Align128Bytes = 0x800000u,
			Align256Bytes = 0x900000u,
			Align512Bytes = 0xA00000u,
			Align1024Bytes = 0xB00000u,
			Align2048Bytes = 0xC00000u,
			Align4096Bytes = 0xD00000u,
			Align8192Bytes = 0xE00000u,
			LinkExtendedRelocationOverflow = 0x1000000u,
			MemoryDiscardable = 0x2000000u,
			MemoryNotCached = 0x4000000u,
			MemoryNotPaged = 0x8000000u,
			MemoryShared = 0x10000000u,
			MemoryExecute = 0x20000000u,
			MemoryRead = 0x40000000u,
			MemoryWrite = 0x80000000u
		}

		public struct IMAGE_DEBUG_DIRECTORY
		{
			public enum _Type : uint
			{
				IMAGE_DEBUG_TYPE_UNKNOWN,
				IMAGE_DEBUG_TYPE_COFF,
				IMAGE_DEBUG_TYPE_CODEVIEW,
				IMAGE_DEBUG_TYPE_FPO,
				IMAGE_DEBUG_TYPE_MISC,
				IMAGE_DEBUG_TYPE_EXCEPTION,
				IMAGE_DEBUG_TYPE_FIXUP,
				IMAGE_DEBUG_TYPE_OMAP_TO_SRC,
				IMAGE_DEBUG_TYPE_OMAP_FROM_SRC,
				IMAGE_DEBUG_TYPE_BORLAND,
				IMAGE_DEBUG_TYPE_RESERVED10,
				IMAGE_DEBUG_TYPE_CLSID,
				IMAGE_DEBUG_TYPE_VC_FEATURE,
				IMAGE_DEBUG_TYPE_POGO,
				IMAGE_DEBUG_TYPE_ILTCG,
				IMAGE_DEBUG_TYPE_MPX,
				IMAGE_DEBUG_TYPE_REPRO
			}

			public uint Characteristics;

			public uint TimeDateStamp;

			public ushort MajorVersion;

			public ushort MinorVersion;

			public _Type Type;

			public uint SizeOfData;

			public uint AddressOfRawData;

			public uint PointerToRawData;
		}

		public struct RSDS
		{
			internal const int Magic = 1396986706;

			[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
			internal byte[] Guid;

			internal uint Age;
		}

		private IMAGE_DOS_HEADER dosHeader;

		private IMAGE_FILE_HEADER fileHeader;

		private IMAGE_OPTIONAL_HEADER32 optionalHeader32;

		private IMAGE_OPTIONAL_HEADER64 optionalHeader64;

		private IMAGE_DEBUG_DIRECTORY? imageDebugDirectory;

		private string rsdsPdbFileName;

		private string pdbGuid;

		private readonly IMAGE_SECTION_HEADER[] imageSectionHeaders;

		public bool Is32BitHeader
		{
			get
			{
				ushort num = 256;
				return (num & FileHeader.Characteristics) == num;
			}
		}

		public IMAGE_FILE_HEADER FileHeader => fileHeader;

		public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 => optionalHeader32;

		public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 => optionalHeader64;

		public IMAGE_DEBUG_DIRECTORY? ImageDebugDirectory => imageDebugDirectory;

		public IMAGE_SECTION_HEADER[] ImageSectionHeaders => imageSectionHeaders;

		public string RsdsPdbFileName => rsdsPdbFileName;

		public string PdbGuid => pdbGuid;

		public DateTime TimeStamp
		{
			get
			{
				DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(fileHeader.TimeDateStamp);
				return dateTime + TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
			}
		}

		public PeReader(string filePath)
		{
			using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
			BinaryReader binaryReader = new BinaryReader(fileStream);
			dosHeader = FromBinaryReader<IMAGE_DOS_HEADER>(binaryReader);
			fileStream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
			binaryReader.ReadUInt32();
			fileHeader = FromBinaryReader<IMAGE_FILE_HEADER>(binaryReader);
			uint virtualAddress;
			if (Is32BitHeader)
			{
				optionalHeader32 = FromBinaryReader<IMAGE_OPTIONAL_HEADER32>(binaryReader);
				virtualAddress = optionalHeader32.Debug.VirtualAddress;
			}
			else
			{
				optionalHeader64 = FromBinaryReader<IMAGE_OPTIONAL_HEADER64>(binaryReader);
				virtualAddress = optionalHeader64.Debug.VirtualAddress;
			}
			imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections];
			for (int i = 0; i < imageSectionHeaders.Length; i++)
			{
				IMAGE_SECTION_HEADER imageSectionHeader = FromBinaryReader<IMAGE_SECTION_HEADER>(binaryReader);
				imageSectionHeaders[i] = imageSectionHeader;
				if (!imageDebugDirectory.HasValue)
				{
					imageDebugDirectory = TryGetDebugDirectory(binaryReader, virtualAddress, ref imageSectionHeader);
				}
			}
			if (imageDebugDirectory.HasValue)
			{
				TryGetRSDS(binaryReader);
			}
		}

		private IMAGE_DEBUG_DIRECTORY? TryGetDebugDirectory(BinaryReader reader, uint debugRva, ref IMAGE_SECTION_HEADER imageSectionHeader)
		{
			uint num = ((imageSectionHeader.VirtualSize != 0) ? imageSectionHeader.VirtualSize : imageSectionHeader.SizeOfRawData);
			if (debugRva >= imageSectionHeader.VirtualAddress && debugRva < imageSectionHeader.VirtualAddress + num)
			{
				long position = reader.BaseStream.Position;
				uint num2 = debugRva - imageSectionHeader.VirtualAddress + imageSectionHeader.PointerToRawData;
				reader.BaseStream.Position = num2;
				IMAGE_DEBUG_DIRECTORY value = FromBinaryReader<IMAGE_DEBUG_DIRECTORY>(reader);
				reader.BaseStream.Position = position;
				return value;
			}
			return null;
		}

		private void TryGetRSDS(BinaryReader reader)
		{
			var anon = new
			{
				RSDSFileOffset = ImageDebugDirectory.Value.PointerToRawData,
				Size = ImageDebugDirectory.Value.SizeOfData
			};
			reader.BaseStream.Position = anon.RSDSFileOffset;
			long num = anon.RSDSFileOffset + anon.Size;
			while (reader.BaseStream.Position != num)
			{
				if (reader.ReadInt32() != 1396986706)
				{
					continue;
				}
				GCHandle gCHandle = GCHandle.Alloc(reader.ReadBytes(Marshal.SizeOf<RSDS>()), GCHandleType.Pinned);
				try
				{
					RSDS rSDS = Marshal.PtrToStructure<RSDS>(gCHandle.AddrOfPinnedObject());
					pdbGuid = new Guid(rSDS.Guid).ToString("N").ToUpperInvariant() + rSDS.Age;
					List<byte> list = new List<byte>();
					bool flag = true;
					while (flag)
					{
						byte b = reader.ReadByte();
						if (b != 0)
						{
							list.Add(b);
						}
						else
						{
							flag = false;
						}
					}
					rsdsPdbFileName = Path.GetFileName(Encoding.Default.GetString(list.ToArray()));
					break;
				}
				finally
				{
					gCHandle.Free();
				}
			}
		}

		public static PeReader GetCallingAssemblyHeader()
		{
			return new PeReader(Assembly.GetCallingAssembly().Location);
		}

		public static PeReader GetAssemblyHeader()
		{
			return new PeReader(Assembly.GetAssembly(typeof(PeReader)).Location);
		}

		public static T FromBinaryReader<T>(BinaryReader reader)
		{
			GCHandle gCHandle = GCHandle.Alloc(reader.ReadBytes(Marshal.SizeOf(typeof(T))), GCHandleType.Pinned);
			T result = (T)Marshal.PtrToStructure(gCHandle.AddrOfPinnedObject(), typeof(T));
			gCHandle.Free();
			return result;
		}
	}
	internal static class Polyfills
	{
		public static bool StringIsNullOrWhiteSpace(string value)
		{
			return string.IsNullOrWhiteSpace(value);
		}

		public static Version VersionParse(string input)
		{
			return Version.Parse(input);
		}
	}
	internal static class StringExtensions
	{
		public static string Format(this string fmt, Dictionary<string, Func<string>> vars)
		{
			return vars.Aggregate(fmt, (string str, KeyValuePair<string, Func<string>> kv) => str.Replace("{" + kv.Key + "}", kv.Value()));
		}

		public static byte?[] ParseHexBytes(this string str)
		{
			List<byte?> list = new List<byte?>();
			StringReader stringReader = new StringReader(str);
			while (stringReader.Peek() > 0)
			{
				char c = char.ToLower((char)stringReader.Read());
				if (char.IsWhiteSpace(c))
				{
					continue;
				}
				switch (c)
				{
				case ';':
					stringReader.ReadLine();
					continue;
				case '?':
					list.Add(null);
					stringReader.Read();
					continue;
				}
				if (IsHexChar(c) && stringReader.Peek() > 0)
				{
					char c2 = char.ToLower((char)stringReader.Peek());
					if (IsHexChar(c2))
					{
						stringReader.Read();
						list.Add(byte.Parse($"{c}{c2}", NumberStyles.HexNumber));
					}
				}
			}
			return list.ToArray();
			static bool IsHexChar(char lowerC)
			{
				if ('0' > lowerC || lowerC > '9')
				{
					if ('a' <= lowerC)
					{
						return lowerC <= 'f';
					}
					return false;
				}
				return true;
			}
		}
	}
	public struct VersionedHandler
	{
		public Version version;

		public object handler;

		public VersionedHandler(Version version, object handler)
		{
			this.version = version;
			this.handler = handler;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer
{
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
	internal class ApplicableToUnityVersionsSinceAttribute : Attribute
	{
		public string StartVersion { get; }

		public ApplicableToUnityVersionsSinceAttribute(string startVersion)
		{
			StartVersion = startVersion;
		}
	}
	public static class UseRightStructs
	{
		private static readonly Type[] InterfacesOfInterest;

		private static readonly Dictionary<Type, List<VersionedHandler>> VersionedHandlers;

		private static readonly Dictionary<Type, object> CurrentHandlers;

		private static Version _unityVersion;

		public static Version UnityVersion
		{
			get
			{
				if (_unityVersion == null)
				{
					InitializeUnityVersion();
				}
				return _unityVersion;
			}
		}

		public static int LabelMemStringId { get; private set; }

		private static void InitializeUnityVersion()
		{
			if (!Polyfills.StringIsNullOrWhiteSpace(Config.UnityVersionOverride.Value))
			{
				if (TryInitializeUnityVersion(Config.UnityVersionOverride.Value))
				{
					Log.Debug("Unity version obtained from config file");
					return;
				}
				Log.Error("Unity version " + Config.UnityVersionOverride.Value + " has incorrect format.");
			}
			if (TryInitializeUnityVersion(Process.GetCurrentProcess().MainModule.FileVersionInfo.FileVersion))
			{
				Log.Debug("Unity version obtained from main application module.");
			}
			else
			{
				Log.Error("Running under default Unity version. UnityVersionHandler is not initialized.");
			}
		}

		private static bool TryInitializeUnityVersion(string version)
		{
			try
			{
				if (Polyfills.StringIsNullOrWhiteSpace(version))
				{
					return false;
				}
				string[] array = version.Split('.');
				int result = 0;
				int result2 = 0;
				int result3 = 0;
				bool flag = int.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
				if (flag && array.Length > 1)
				{
					flag = int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result2);
				}
				if (flag && array.Length > 2)
				{
					flag = int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out result3);
				}
				if (!flag)
				{
					Log.Error("Failed to parse Unity version: " + version);
					return false;
				}
				_unityVersion = new Version(result, result2, result3);
				Log.Info($"Running under Unity v{UnityVersion}");
				return true;
			}
			catch (Exception arg)
			{
				Log.Error($"Failed to parse Unity version: {arg}");
				return false;
			}
		}

		static UseRightStructs()
		{
			VersionedHandlers = new Dictionary<Type, List<VersionedHandler>>();
			CurrentHandlers = new Dictionary<Type, object>();
			Type[] allTypesSafe = GetAllTypesSafe();
			InterfacesOfInterest = allTypesSafe.Where((Type t) => t.IsInterface && typeof(INativeStruct).IsAssignableFrom(t) && t != typeof(INativeStruct)).ToArray();
			Type[] interfacesOfInterest = InterfacesOfInterest;
			foreach (Type key in interfacesOfInterest)
			{
				VersionedHandlers[key] = new List<VersionedHandler>();
			}
			foreach (Type item in allTypesSafe.Where((Type t) => !t.IsAbstract && InterfacesOfInterest.Any((Type i) => i.IsAssignableFrom(t))))
			{
				foreach (ApplicableToUnityVersionsSinceAttribute customAttribute in item.GetCustomAttributes<ApplicableToUnityVersionsSinceAttribute>())
				{
					object handler = Activator.CreateInstance(item);
					interfacesOfInterest = item.GetInterfaces();
					foreach (Type type in interfacesOfInterest)
					{
						if (InterfacesOfInterest.Contains(type))
						{
							VersionedHandlers[type].Add(new VersionedHandler(Polyfills.VersionParse(customAttribute.StartVersion), handler));
						}
					}
				}
			}
			foreach (List<VersionedHandler> value in VersionedHandlers.Values)
			{
				value.Sort((VersionedHandler a, VersionedHandler b) => -a.version.CompareTo(b.version));
			}
			GatherUnityVersionSpecificHandlers();
			SetUnityVersionSpecificMemStringId();
		}

		private static void GatherUnityVersionSpecificHandlers()
		{
			CurrentHandlers.Clear();
			Type[] interfacesOfInterest = InterfacesOfInterest;
			foreach (Type key in interfacesOfInterest)
			{
				foreach (var (version2, value) in VersionedHandlers[key])
				{
					if (!(version2 > UnityVersion))
					{
						CurrentHandlers[key] = value;
						break;
					}
				}
			}
		}

		private static T GetHandler<T>()
		{
			if (CurrentHandlers.TryGetValue(typeof(T), out var value))
			{
				return (T)value;
			}
			Log.Error($"No direct for {typeof(T).FullName} found for Unity {UnityVersion}; this likely indicates a severe error somewhere");
			throw new ApplicationException("No handler");
		}

		private static Type[] GetAllTypesSafe()
		{
			try
			{
				return typeof(UseRightStructs).Assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types.Where((Type t) => t != null).ToArray();
			}
		}

		internal static T GetStruct<T>(IntPtr ptr) where T : INativeStruct
		{
			if (ptr == IntPtr.Zero)
			{
				throw new ArgumentNullException("ptr");
			}
			T handler = GetHandler<T>();
			handler.Pointer = ptr;
			return handler;
		}

		private static void SetUnityVersionSpecificMemStringId()
		{
			if (UnityVersion >= new Version(2023, 1))
			{
				LabelMemStringId = 9;
			}
			else if (UnityVersion >= new Version(2021, 1))
			{
				LabelMemStringId = 73;
			}
			else if (UnityVersion >= new Version(2020, 2))
			{
				LabelMemStringId = 43;
			}
			else if (UnityVersion >= new Version(2020, 1))
			{
				LabelMemStringId = 42;
			}
			else if (UnityVersion >= new Version(2019, 4))
			{
				LabelMemStringId = 43;
			}
			else if (UnityVersion >= new Version(2019, 3))
			{
				LabelMemStringId = 42;
			}
			else if (UnityVersion >= new Version(2019, 1))
			{
				LabelMemStringId = 43;
			}
			else if (UnityVersion >= new Version(2018, 3))
			{
				LabelMemStringId = 69;
			}
			else if (UnityVersion >= new Version(2017, 2))
			{
				LabelMemStringId = 68;
			}
			else
			{
				LabelMemStringId = 66;
			}
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2023.v1
{
	[ApplicableToUnityVersionsSince("2023.1.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private ScriptingAssemblies _originalScriptingAssemblies;

		public List<StringStorageDefaultV3> ManagedAssemblyList = new List<StringStorageDefaultV3>();

		public IntPtr Pointer
		{
			get
			{
				return CommonUnityFunctions.ScriptingAssemblies;
			}
			set
			{
			}
		}

		private unsafe RuntimeStatic<ScriptingAssemblies>* _this => (RuntimeStatic<ScriptingAssemblies>*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV4(ManagedAssemblyList, _this->value->names);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV4(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV4(ManagedAssemblyList, &_this->value->names);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV4(_this->value->names);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			*_this->value = _originalScriptingAssemblies;
		}
	}
	[ApplicableToUnityVersionsSince("2023.1.0")]
	public class RelativePathString : IRelativePathString, INativeStruct
	{
		public IntPtr Pointer { get; set; }

		private unsafe StringStorageDefaultV3* _this => (StringStorageDefaultV3*)(void*)Pointer;

		public RelativePathString()
		{
		}

		public RelativePathString(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void FixAbsolutePath()
		{
			if (!_this->union.embedded.flags.IsEmbedded && (_this->union.heap.data == 0 || _this->union.heap.size == 0L))
			{
				return;
			}
			string fileName = Path.GetFileName(_this->union.embedded.flags.IsEmbedded ? Marshal.PtrToStringAnsi((IntPtr)_this->union.embedded.data) : Marshal.PtrToStringAnsi(_this->union.heap.data, (int)_this->union.heap.size));
			int num = FixPluginTypesSerializationPatcher.PluginNames.IndexOf(fileName);
			if (num != -1)
			{
				ulong length;
				IntPtr data = CommonUnityFunctions.MallocString(FixPluginTypesSerializationPatcher.PluginPaths[num], UseRightStructs.LabelMemStringId, out length);
				if (!_this->union.embedded.flags.IsEmbedded)
				{
					CommonUnityFunctions.FreeAllocInternal(_this->union.heap.data, _this->label);
				}
				StringStorageDefaultV3* @this = _this;
				@this->union = new StringStorageDefaultV3Union
				{
					heap = new HeapAllocatedRepresentationV3
					{
						data = data,
						capacity = length,
						size = length,
						flags = new StringStorageDefaultV3Flags
						{
							IsHeap = true
						}
					}
				};
				@this->label = UseRightStructs.LabelMemStringId;
			}
		}

		public unsafe string ToStringAnsi()
		{
			if (!_this->union.embedded.flags.IsEmbedded && (_this->union.heap.data == 0 || _this->union.heap.size == 0L))
			{
				return null;
			}
			if (_this->union.embedded.flags.IsEmbedded)
			{
				return Marshal.PtrToStringAnsi((IntPtr)_this->union.embedded.data);
			}
			return Marshal.PtrToStringAnsi(_this->union.heap.data, (int)_this->union.heap.size);
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2021.v1
{
	[ApplicableToUnityVersionsSince("2021.1.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private ScriptingAssemblies _originalScriptingAssemblies;

		public List<StringStorageDefaultV2> ManagedAssemblyList = new List<StringStorageDefaultV2>();

		public IntPtr Pointer
		{
			get
			{
				return CommonUnityFunctions.ScriptingAssemblies;
			}
			set
			{
			}
		}

		private unsafe RuntimeStatic<ScriptingAssemblies>* _this => (RuntimeStatic<ScriptingAssemblies>*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV3(ManagedAssemblyList, _this->value->names);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV3(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV3(ManagedAssemblyList, &_this->value->names);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV3(_this->value->names);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			*_this->value = _originalScriptingAssemblies;
		}
	}
	[ApplicableToUnityVersionsSince("2021.1.0")]
	public class RelativePathString : IRelativePathString, INativeStruct
	{
		public IntPtr Pointer { get; set; }

		private unsafe StringStorageDefaultV2* _this => (StringStorageDefaultV2*)(void*)Pointer;

		public RelativePathString()
		{
		}

		public RelativePathString(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void FixAbsolutePath()
		{
			if (_this->data_repr != StringRepresentation.Embedded && (_this->union.heap.data == 0 || _this->union.heap.size == 0L))
			{
				return;
			}
			string path = ((_this->data_repr != StringRepresentation.Embedded) ? Marshal.PtrToStringAnsi(_this->union.heap.data, (int)_this->union.heap.size) : Marshal.PtrToStringAnsi((IntPtr)_this->union.embedded.data));
			string fileName = Path.GetFileName(path);
			int num = FixPluginTypesSerializationPatcher.PluginNames.IndexOf(fileName);
			if (num != -1)
			{
				ulong length;
				IntPtr data = CommonUnityFunctions.MallocString(FixPluginTypesSerializationPatcher.PluginPaths[num], UseRightStructs.LabelMemStringId, out length);
				if (_this->data_repr != StringRepresentation.Embedded)
				{
					CommonUnityFunctions.FreeAllocInternal(_this->union.heap.data, _this->label);
				}
				StringStorageDefaultV2* @this = _this;
				@this->union = new StringStorageDefaultV2Union
				{
					heap = new HeapAllocatedRepresentationV2
					{
						data = data,
						capacity = length,
						size = length
					}
				};
				@this->data_repr = StringRepresentation.Heap;
				@this->label = UseRightStructs.LabelMemStringId;
			}
		}

		public unsafe string ToStringAnsi()
		{
			if (_this->data_repr != StringRepresentation.Embedded && (_this->union.heap.data == 0 || _this->union.heap.size == 0L))
			{
				return null;
			}
			if (_this->data_repr == StringRepresentation.Embedded)
			{
				return Marshal.PtrToStringAnsi((IntPtr)_this->union.embedded.data);
			}
			return Marshal.PtrToStringAnsi(_this->union.heap.data, (int)_this->union.heap.size);
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2020.v2
{
	[ApplicableToUnityVersionsSince("2020.2.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private ScriptingAssemblies _originalScriptingAssemblies;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer
		{
			get
			{
				return CommonUnityFunctions.ScriptingAssemblies;
			}
			set
			{
			}
		}

		private unsafe RuntimeStatic<ScriptingAssemblies>* _this => (RuntimeStatic<ScriptingAssemblies>*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV2(ManagedAssemblyList, _this->value->names);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV2(ManagedAssemblyList, &_this->value->names);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV2(_this->value->names);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			*_this->value = _originalScriptingAssemblies;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2020.v1
{
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(448)]
		public DynamicArrayData m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2020.1.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private DynamicArrayData _originalAssemblyNames;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV2(ManagedAssemblyList, _this->m_AssemblyNames);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			_originalAssemblyNames = _this->m_AssemblyNames;
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV2(ManagedAssemblyList, &_this->m_AssemblyNames);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV2(_this->m_AssemblyNames);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2019
{
	public struct AssemblyList
	{
		public nint ptr;

		public int label;

		public ulong size;

		public ulong capacity;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct AssemblyStringStruct
	{
		public const int ValidStringLabel = 42;

		public nint data;

		public ulong capacity;

		public ulong extra;

		public ulong size;

		public int label;

		public bool IsValid()
		{
			if (data != 0)
			{
				return label == 42;
			}
			return false;
		}
	}
	[ApplicableToUnityVersionsSince("2019.3.0")]
	public class AssemblyString : IAssemblyString, INativeStruct
	{
		public IntPtr Pointer { get; set; }

		private unsafe AssemblyStringStruct* _this => (AssemblyStringStruct*)(void*)Pointer;

		public AssemblyString()
		{
		}

		public AssemblyString(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void FixAbsolutePath()
		{
			if (_this->data != 0)
			{
				string pathNameStr = Marshal.PtrToStringAnsi(_this->data, (int)_this->size);
				string text = FixPluginTypesSerializationPatcher.PluginPaths.FirstOrDefault((string p) => Path.GetFileName(p) == Path.GetFileName(pathNameStr));
				if (!string.IsNullOrEmpty(text))
				{
					ulong num = (ulong)text.Length;
					IntPtr intPtr = Marshal.StringToHGlobalAnsi(text);
					(IntPtr, IntPtr, ulong) value = ((IntPtr)_this, _this->data, _this->size);
					ReadStringFromFile.ModifiedPathsToOriginalPaths.Add(intPtr, value);
					_this->data = intPtr;
					_this->capacity = num;
					_this->size = num;
				}
			}
		}

		public unsafe void RestoreOriginalString(IntPtr constCharPtr)
		{
			if (ReadStringFromFile.ModifiedPathsToOriginalPaths.TryGetValue(constCharPtr, out var value))
			{
				AssemblyStringStruct* ptr = (AssemblyStringStruct*)(void*)value.Item1;
				ptr->data = value.Item2;
				ptr->size = value.Item3;
				ptr->capacity = value.Item3;
			}
		}
	}
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(432)]
		public AssemblyList m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2019.3.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private AssemblyList _originalAssemblyNames;

		public List<AssemblyStringStruct> ManagedAssemblyList = new List<AssemblyStringStruct>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			ManagedAssemblyList.Clear();
			ulong num = 0uL;
			AssemblyStringStruct* ptr = (AssemblyStringStruct*)_this->m_AssemblyNames.ptr;
			for (; num < _this->m_AssemblyNames.size; num++)
			{
				AssemblyStringStruct assemblyStringStruct = default(AssemblyStringStruct);
				assemblyStringStruct.capacity = ptr->capacity;
				assemblyStringStruct.extra = ptr->extra;
				assemblyStringStruct.label = ptr->label;
				assemblyStringStruct.size = ptr->size;
				assemblyStringStruct.data = ptr->data;
				AssemblyStringStruct item = assemblyStringStruct;
				ManagedAssemblyList.Add(item);
				ptr++;
			}
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			foreach (string pluginAssemblyPath in pluginAssemblyPaths)
			{
				string fileName = Path.GetFileName(pluginAssemblyPath);
				ulong num = (ulong)fileName.Length;
				AssemblyStringStruct assemblyStringStruct = default(AssemblyStringStruct);
				assemblyStringStruct.label = 42;
				assemblyStringStruct.data = Marshal.StringToHGlobalAnsi(fileName);
				assemblyStringStruct.capacity = num;
				assemblyStringStruct.size = num;
				AssemblyStringStruct item = assemblyStringStruct;
				ManagedAssemblyList.Add(item);
			}
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			AssemblyStringStruct* ptr = (AssemblyStringStruct*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf<AssemblyStringStruct>() * ManagedAssemblyList.Count);
			int i = 0;
			AssemblyStringStruct* ptr2 = ptr;
			for (; i < ManagedAssemblyList.Count; i++)
			{
				ptr2->label = ManagedAssemblyList[i].label;
				ptr2->size = ManagedAssemblyList[i].size;
				ptr2->capacity = ManagedAssemblyList[i].capacity;
				ptr2->extra = ManagedAssemblyList[i].extra;
				ptr2->data = ManagedAssemblyList[i].data;
				ptr2++;
			}
			_originalAssemblyNames = _this->m_AssemblyNames;
			_this->m_AssemblyNames.ptr = (nint)ptr;
			_this->m_AssemblyNames.size = (ulong)ManagedAssemblyList.Count;
			_this->m_AssemblyNames.capacity = _this->m_AssemblyNames.size;
		}

		public unsafe void PrintAssemblies()
		{
			ulong num = 0uL;
			AssemblyStringStruct* ptr = (AssemblyStringStruct*)_this->m_AssemblyNames.ptr;
			for (; num < _this->m_AssemblyNames.size; num++)
			{
				if (ptr->IsValid())
				{
					Log.Warning($"Ass: {Marshal.PtrToStringAnsi(ptr->data, (int)ptr->size)} | label : {ptr->label:X}");
				}
				ptr++;
			}
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2019.v1
{
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(432)]
		public DynamicArrayData m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2019.1.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private DynamicArrayData _originalAssemblyNames;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV2(ManagedAssemblyList, _this->m_AssemblyNames);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			_originalAssemblyNames = _this->m_AssemblyNames;
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV2(ManagedAssemblyList, &_this->m_AssemblyNames);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV2(_this->m_AssemblyNames);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2018
{
	public struct AssemblyList
	{
		public unsafe AssemblyStringStruct* first;

		public unsafe AssemblyStringStruct* last;

		public unsafe AssemblyStringStruct* end;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct AssemblyStringStruct
	{
		public const int ValidStringLabel = 69;

		public nint data;

		public ulong capacity;

		public ulong extra;

		public ulong size;

		public int label;

		public bool IsValid()
		{
			if (data != 0)
			{
				return label == 69;
			}
			return false;
		}
	}
	[ApplicableToUnityVersionsSince("5.3.0")]
	public class AssemblyString : IAssemblyString, INativeStruct
	{
		public IntPtr Pointer { get; set; }

		private unsafe AssemblyStringStruct* _this => (AssemblyStringStruct*)(void*)Pointer;

		public AssemblyString()
		{
		}

		public AssemblyString(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void FixAbsolutePath()
		{
			if (_this->data != 0)
			{
				string pathNameStr = Marshal.PtrToStringAnsi(_this->data, (int)_this->size);
				string text = FixPluginTypesSerializationPatcher.PluginPaths.FirstOrDefault((string p) => Path.GetFileName(p) == Path.GetFileName(pathNameStr));
				if (!string.IsNullOrEmpty(text))
				{
					ulong num = (ulong)text.Length;
					IntPtr intPtr = Marshal.StringToHGlobalAnsi(text);
					(IntPtr, IntPtr, ulong) value = ((IntPtr)_this, _this->data, _this->size);
					ReadStringFromFile.ModifiedPathsToOriginalPaths.Add(intPtr, value);
					_this->data = intPtr;
					_this->capacity = num;
					_this->size = num;
				}
			}
		}

		public unsafe void RestoreOriginalString(IntPtr constCharPtr)
		{
			if (ReadStringFromFile.ModifiedPathsToOriginalPaths.TryGetValue(constCharPtr, out var value))
			{
				AssemblyStringStruct* ptr = (AssemblyStringStruct*)(void*)value.Item1;
				ptr->data = value.Item2;
				ptr->size = value.Item3;
				ptr->capacity = value.Item3;
			}
		}
	}
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(408)]
		public AssemblyList m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("5.0.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private AssemblyList _originalAssemblyNames;

		public List<AssemblyStringStruct> ManagedAssemblyList = new List<AssemblyStringStruct>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			ManagedAssemblyList.Clear();
			for (AssemblyStringStruct* ptr = _this->m_AssemblyNames.first; ptr != _this->m_AssemblyNames.last; ptr++)
			{
				AssemblyStringStruct assemblyStringStruct = default(AssemblyStringStruct);
				assemblyStringStruct.capacity = ptr->capacity;
				assemblyStringStruct.extra = ptr->extra;
				assemblyStringStruct.label = ptr->label;
				assemblyStringStruct.size = ptr->size;
				assemblyStringStruct.data = ptr->data;
				AssemblyStringStruct item = assemblyStringStruct;
				ManagedAssemblyList.Add(item);
			}
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			foreach (string pluginAssemblyPath in pluginAssemblyPaths)
			{
				string fileName = Path.GetFileName(pluginAssemblyPath);
				ulong num = (ulong)fileName.Length;
				AssemblyStringStruct assemblyStringStruct = default(AssemblyStringStruct);
				assemblyStringStruct.label = 69;
				assemblyStringStruct.data = Marshal.StringToHGlobalAnsi(fileName);
				assemblyStringStruct.capacity = num;
				assemblyStringStruct.size = num;
				AssemblyStringStruct item = assemblyStringStruct;
				ManagedAssemblyList.Add(item);
			}
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			AssemblyStringStruct* ptr = (AssemblyStringStruct*)(void*)Marshal.AllocHGlobal(Marshal.SizeOf<AssemblyStringStruct>() * ManagedAssemblyList.Count);
			int i = 0;
			AssemblyStringStruct* ptr2 = ptr;
			for (; i < ManagedAssemblyList.Count; i++)
			{
				ptr2->label = ManagedAssemblyList[i].label;
				ptr2->size = ManagedAssemblyList[i].size;
				ptr2->capacity = ManagedAssemblyList[i].capacity;
				ptr2->extra = ManagedAssemblyList[i].extra;
				ptr2->data = ManagedAssemblyList[i].data;
				ptr2++;
			}
			_originalAssemblyNames = _this->m_AssemblyNames;
			_this->m_AssemblyNames.first = ptr;
			_this->m_AssemblyNames.last = ptr + ManagedAssemblyList.Count;
			_this->m_AssemblyNames.end = _this->m_AssemblyNames.last;
		}

		public unsafe void PrintAssemblies()
		{
			for (AssemblyStringStruct* ptr = _this->m_AssemblyNames.first; ptr != _this->m_AssemblyNames.last; ptr++)
			{
				if (ptr->IsValid())
				{
					Log.Warning("Ass: " + Marshal.PtrToStringAnsi(ptr->data, (int)ptr->size));
				}
			}
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2017.v3
{
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(408)]
		public Vector<StringStorageDefaultV1> m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2017.3.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private Vector<StringStorageDefaultV1> _originalAssemblyNames;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV1(ManagedAssemblyList, _this->m_AssemblyNames);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			_originalAssemblyNames = _this->m_AssemblyNames;
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV1(ManagedAssemblyList, &_this->m_AssemblyNames);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV1(_this->m_AssemblyNames);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2017.v2
{
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(448)]
		public Vector<StringStorageDefaultV1> m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2017.2.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private Vector<StringStorageDefaultV1> _originalAssemblyNames;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV1(ManagedAssemblyList, _this->m_AssemblyNames);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			_originalAssemblyNames = _this->m_AssemblyNames;
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV1(ManagedAssemblyList, &_this->m_AssemblyNames);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV1(_this->m_AssemblyNames);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.v2017.v1
{
	[StructLayout(LayoutKind.Explicit)]
	public struct MonoManagerStruct
	{
		[FieldOffset(504)]
		public Vector<StringStorageDefaultV1> m_AssemblyNames;
	}
	[ApplicableToUnityVersionsSince("2017.1.0")]
	public class MonoManager : IMonoManager, INativeStruct
	{
		private Vector<StringStorageDefaultV1> _originalAssemblyNames;

		public List<StringStorageDefaultV1> ManagedAssemblyList = new List<StringStorageDefaultV1>();

		public IntPtr Pointer { get; set; }

		private unsafe MonoManagerStruct* _this => (MonoManagerStruct*)(void*)Pointer;

		public int AssemblyCount => ManagedAssemblyList.Count;

		public MonoManager()
		{
		}

		public MonoManager(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void CopyNativeAssemblyListToManaged()
		{
			MonoManagerCommon.CopyNativeAssemblyListToManagedV1(ManagedAssemblyList, _this->m_AssemblyNames);
		}

		public void AddAssembliesToManagedList(List<string> pluginAssemblyPaths)
		{
			MonoManagerCommon.AddAssembliesToManagedListV1(ManagedAssemblyList, pluginAssemblyPaths);
		}

		public unsafe void AllocNativeAssemblyListFromManaged()
		{
			_originalAssemblyNames = _this->m_AssemblyNames;
			MonoManagerCommon.AllocNativeAssemblyListFromManagedV1(ManagedAssemblyList, &_this->m_AssemblyNames);
		}

		public unsafe void PrintAssemblies()
		{
			MonoManagerCommon.PrintAssembliesV1(_this->m_AssemblyNames);
		}

		public unsafe void RestoreOriginalAssemblyNamesArrayPtr()
		{
			_this->m_AssemblyNames = _originalAssemblyNames;
		}
	}
	[ApplicableToUnityVersionsSince("2017.1.0")]
	public class RelativePathString : IRelativePathString, INativeStruct
	{
		public IntPtr Pointer { get; set; }

		private unsafe StringStorageDefaultV1* _this => (StringStorageDefaultV1*)(void*)Pointer;

		public RelativePathString()
		{
		}

		public RelativePathString(IntPtr pointer)
		{
			Pointer = pointer;
		}

		public unsafe void FixAbsolutePath()
		{
			if (_this->size == 0L)
			{
				return;
			}
			nint num = _this->data;
			if (num == 0)
			{
				num = (IntPtr)(Pointer.ToInt64() + 8);
			}
			string fileName = Path.GetFileName(Marshal.PtrToStringAnsi(num, (int)_this->size));
			int num2 = FixPluginTypesSerializationPatcher.PluginNames.IndexOf(fileName);
			if (num2 != -1)
			{
				ulong length;
				IntPtr data = CommonUnityFunctions.MallocString(FixPluginTypesSerializationPatcher.PluginPaths[num2], UseRightStructs.LabelMemStringId, out length);
				if (_this->data != 0)
				{
					CommonUnityFunctions.FreeAllocInternal(_this->data, _this->label);
				}
				StringStorageDefaultV1* @this = _this;
				@this->data = data;
				@this->capacity = length;
				@this->extra = 0uL;
				@this->size = length;
				@this->label = UseRightStructs.LabelMemStringId;
			}
		}

		public unsafe string ToStringAnsi()
		{
			if (_this->size == 0L)
			{
				return null;
			}
			nint num = _this->data;
			if (num == 0)
			{
				num = (nint)((byte*)_this + 8);
			}
			return Marshal.PtrToStringAnsi(num, (int)_this->size);
		}
	}
}
namespace FixPluginTypesSerialization.UnityPlayer.Structs.Default
{
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct DynamicArrayData
	{
		public nint ptr;

		public int label;

		public ulong size;

		public ulong capacity;
	}
	public interface IAssemblyString : INativeStruct
	{
		void FixAbsolutePath();

		void RestoreOriginalString(IntPtr constCharPtr);
	}
	public interface IMonoManager : INativeStruct
	{
		int AssemblyCount { get; }

		void CopyNativeAssemblyListToManaged();

		void AddAssembliesToManagedList(List<string> pluginAssemblyPaths);

		void AllocNativeAssemblyListFromManaged();

		void PrintAssemblies();

		void RestoreOriginalAssemblyNamesArrayPtr();
	}
	public interface IRelativePathString : INativeStruct
	{
		void FixAbsolutePath();

		string ToStringAnsi();
	}
	public struct RuntimeStatic<T> where T : struct
	{
		public unsafe T* value;

		public int label;

		public int unknown1;

		public ulong memAlign;

		public unsafe fixed byte memAreaName[32];

		public unsafe fixed byte memObjectName[32];

		public RegisterRuntimeInitializeAndCleanup registerCallbacks;

		public ulong unknown2;

		public ulong unknown3;

		public ulong unknown4;

		public ulong unknown5;

		public ulong unknown6;

		public ulong unknown7;

		public ReadWriteSpinLock @lock;
	}
	public struct RegisterRuntimeInitializeAndCleanup
	{
		public int order;

		public IntPtr userData;

		public IntPtr init;

		public IntPtr cleanup;

		public bool initCalled;

		public unsafe RegisterRuntimeInitializeAndCleanup* m_Next;

		public unsafe RegisterRuntimeInitializeAndCleanup* m_Prev;
	}
	public struct ReadWriteSpinLock
	{
		public long m_Counter;

		public ulong unknown1;

		public ulong unknown2;

		public ulong unknown3;

		public ulong unknown4;

		public ulong unknown5;

		public ulong unknown6;

		public ulong unknown7;
	}
	public struct ScriptingAssemblies
	{
		public DynamicArrayData names;

		public DynamicArrayData types;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct StringStorageDefaultV1
	{
		public nint data;

		public ulong capacity;

		public ulong extra;

		public ulong size;

		public int label;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct StringStorageDefaultV2
	{
		public StringStorageDefaultV2Union union;

		public StringRepresentation data_repr;

		public int label;
	}
	[StructLayout(LayoutKind.Explicit, Pack = 8)]
	public struct StringStorageDefaultV2Union
	{
		[FieldOffset(0)]
		public StackAllocatedRepresentationV2 embedded;

		[FieldOffset(0)]
		public HeapAllocatedRepresentationV2 heap;
	}
	public struct StackAllocatedRepresentationV2
	{
		public unsafe fixed byte data[25];
	}
	public struct HeapAllocatedRepresentationV2
	{
		public nint data;

		public ulong capacity;

		public ulong size;
	}
	public enum StringRepresentation
	{
		Heap,
		Embedded,
		External
	}
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct StringStorageDefaultV3
	{
		public StringStorageDefaultV3Union union;

		public int label;
	}
	[StructLayout(LayoutKind.Explicit, Pack = 8)]
	public struct StringStorageDefaultV3Union
	{
		[FieldOffset(0)]
		public StackAllocatedRepresentationV3 embedded;

		[FieldOffset(0)]
		public HeapAllocatedRepresentationV3 heap;
	}
	public struct StackAllocatedRepresentationV3
	{
		public unsafe fixed byte data[31];

		public StringStorageDefaultV3Flags flags;
	}
	public struct StringStorageDefaultV3Flags
	{
		public byte flags;

		public bool IsHeap
		{
			get
			{
				return (flags & 0x40) > 0;
			}
			set
			{
				if (value)
				{
					flags = 95;
				}
				else
				{
					flags = 0;
				}
			}
		}

		public bool IsExternal
		{
			get
			{
				return (flags & 0x80) > 0;
			}
			set
			{
				if (value)
				{
					flags = byte.MaxValue;
				}
				else
				{
					flags = 0;
				}
			}
		}

		public bool IsEmbedded
		{
			get
			{
				return flags < 64;
			}
			set
			{
				IsHeap = !value;
			}
		}

		public static implicit operator int(StringStorageDefaultV3Flags f)
		{
			return f.flags;
		}

		public static implicit operator byte(StringStorageDefaultV3Flags f)
		{
			return f.flags;
		}
	}
	[StructLayout(LayoutKind.Explicit)]
	public struct HeapAllocatedRepresentationV3
	{
		[FieldOffset(0)]
		public nint data;

		[FieldOffset(8)]
		public ulong capacity;

		[FieldOffset(16)]
		public ulong size;

		[FieldOffset(31)]
		public StringStorageDefaultV3Flags flags;
	}
	public struct Vector<T> where T : struct
	{
		public unsafe T* first;

		public unsafe T* last;

		public unsafe T* end;
	}
	public interface INativeStruct
	{
		IntPtr Pointer { get; set; }
	}
}
namespace FixPluginTypesSerialization.Patchers
{
	internal class AwakeFromLoad : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate void AwakeFromLoadDelegate(IntPtr _monoManager, int awakeMode);

		private static AwakeFromLoadDelegate original;

		private static NativeDetour _detour;

		internal static IMonoManager CurrentMonoManager;

		internal static bool IsApplied { get; private set; }

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[2]
		{
			Encoding.ASCII.GetBytes("MonoManager::AwakeFromLoad"),
			Encoding.ASCII.GetBytes("AwakeFromLoad@MonoManager")
		};


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[1] { "40 53 48 81 EC ? ? ? ? 33 C0 C7 44 24 ? ? ? ? ? 0F 57 C0" };


		protected override void Apply(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<AwakeFromLoadDelegate>(OnAwakeFromLoad);
			_detour = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			original = _detour.GenerateTrampoline<AwakeFromLoadDelegate>();
			_detour.Apply();
			IsApplied = true;
		}

		internal static void Dispose()
		{
			NativeDetour detour = _detour;
			if (detour != null)
			{
				detour.Dispose();
			}
			IsApplied = false;
		}

		private static void OnAwakeFromLoad(IntPtr _monoManager, int awakeMode)
		{
			CurrentMonoManager = UseRightStructs.GetStruct<IMonoManager>(_monoManager);
			CurrentMonoManager.CopyNativeAssemblyListToManaged();
			IsAssemblyCreated.VanillaAssemblyCount = CurrentMonoManager.AssemblyCount;
			CurrentMonoManager.AddAssembliesToManagedList(FixPluginTypesSerializationPatcher.PluginPaths);
			CurrentMonoManager.AllocNativeAssemblyListFromManaged();
			original(_monoManager, awakeMode);
			IsFileCreated.Dispose();
			ConvertSeparatorsToPlatform.Dispose();
			IsAssemblyCreated.Dispose();
		}
	}
	internal class ConvertSeparatorsToPlatform : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate void ConvertSeparatorsToPlatformDelegate(IntPtr assemblyStringPathName);

		private static NativeDetour _detourConvertSeparatorsToPlatform;

		private static ConvertSeparatorsToPlatformDelegate originalConvertSeparatorsToPlatform;

		internal static bool IsApplied { get; private set; }

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[1] { Encoding.ASCII.GetBytes("ConvertSeparatorsToPlatform") };


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[0];


		protected override void Apply(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<ConvertSeparatorsToPlatformDelegate>(OnConvertSeparatorsToPlatformV1);
			_detourConvertSeparatorsToPlatform = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			originalConvertSeparatorsToPlatform = _detourConvertSeparatorsToPlatform.GenerateTrampoline<ConvertSeparatorsToPlatformDelegate>();
			_detourConvertSeparatorsToPlatform.Apply();
			IsApplied = true;
		}

		internal static void Dispose()
		{
			if (_detourConvertSeparatorsToPlatform != null && _detourConvertSeparatorsToPlatform.IsApplied)
			{
				_detourConvertSeparatorsToPlatform.Dispose();
			}
			IsApplied = false;
		}

		private static void OnConvertSeparatorsToPlatformV1(IntPtr assemblyStringPathName)
		{
			UseRightStructs.GetStruct<IRelativePathString>(assemblyStringPathName).FixAbsolutePath();
			originalConvertSeparatorsToPlatform(assemblyStringPathName);
		}
	}
	internal class IsAssemblyCreated : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate bool IsAssemblyCreatedDelegate(IntPtr _monoManager, int index);

		private static IsAssemblyCreatedDelegate original;

		private static NativeDetour _detour;

		internal static int VanillaAssemblyCount;

		internal static bool IsApplied { get; private set; }

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[2]
		{
			Encoding.ASCII.GetBytes("MonoManager::IsAssemblyCreated"),
			Encoding.ASCII.GetBytes("IsAssemblyCreated@MonoManager")
		};


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[2] { "E8 ? ? ? ? 84 C0 74 43 45 84 FF", "E8 ? ? ? ? 84 C0 74 41 45 84 FF" };


		protected override void Apply(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<IsAssemblyCreatedDelegate>(OnIsAssemblyCreated);
			_detour = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			original = _detour.GenerateTrampoline<IsAssemblyCreatedDelegate>();
			NativeDetour detour = _detour;
			if (detour != null)
			{
				detour.Apply();
			}
			IsApplied = true;
		}

		internal static void Dispose()
		{
			NativeDetour detour = _detour;
			if (detour != null)
			{
				detour.Dispose();
			}
			IsApplied = false;
		}

		private static bool OnIsAssemblyCreated(IntPtr _monoManager, int index)
		{
			if (index >= VanillaAssemblyCount)
			{
				return true;
			}
			return original(_monoManager, index);
		}
	}
	internal class IsFileCreated : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate bool IsFileCreatedDelegate(IntPtr str);

		private static IsFileCreatedDelegate original;

		private static NativeDetour _detour;

		internal static bool IsApplied { get; private set; }

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[1] { Encoding.ASCII.GetBytes("IsFileCreated") };


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[0];


		protected override void Apply(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<IsFileCreatedDelegate>(OnIsFileCreated);
			_detour = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			original = _detour.GenerateTrampoline<IsFileCreatedDelegate>();
			_detour.Apply();
			IsApplied = true;
		}

		internal static void Dispose()
		{
			NativeDetour detour = _detour;
			if (detour != null)
			{
				detour.Dispose();
			}
			IsApplied = false;
		}

		private static bool OnIsFileCreated(IntPtr str)
		{
			string text = UseRightStructs.GetStruct<IRelativePathString>(str).ToStringAnsi();
			if (text != null && FixPluginTypesSerializationPatcher.PluginNames.Any(text.EndsWith))
			{
				return true;
			}
			return original(str);
		}
	}
	internal abstract class Patcher
	{
		protected abstract BytePattern[] PdbPatterns { get; }

		protected abstract BytePattern[] SigPatterns { get; }

		public void Patch(IntPtr unityModule, int moduleSize, MiniPdbReader pdbReader, ConfigEntry<string> functionOffsetCache)
		{
			IntPtr intPtr = PatternDiscover.Discover(unityModule, moduleSize, pdbReader, functionOffsetCache, PdbPatterns, SigPatterns);
			if (intPtr != IntPtr.Zero)
			{
				Apply(intPtr);
			}
		}

		protected abstract void Apply(IntPtr from);
	}
	internal class ReadStringFromFile : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate bool ReadStringFromFileDelegate(IntPtr outData, IntPtr assemblyStringPathName);

		private delegate IntPtr mono_assembly_load_from_full_delegate(IntPtr image, IntPtr constCharFName, IntPtr status, IntPtr refonly);

		private static NativeDetour _detourReadStringFromFile;

		private static ReadStringFromFileDelegate originalReadStringFromFile;

		private static readonly IntPtr Mono = NativeLibraryHelper.OpenLibrary("mono-2.0-bdwgc.dll");

		private static readonly IntPtr mono_assembly_load_from_full_fn = Mono.GetFunction("mono_assembly_load_from_full");

		private static NativeDetour _monoDetour;

		private static mono_assembly_load_from_full_delegate originalMonoAssemblyLoadFromFull;

		internal static readonly Dictionary<IntPtr, (IntPtr, IntPtr, ulong)> ModifiedPathsToOriginalPaths = new Dictionary<IntPtr, (IntPtr, IntPtr, ulong)>();

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[1] { Encoding.ASCII.GetBytes("ReadStringFromFile") };


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[3] { "E8 ? ? ? ? 4C 8D 45 EF 48 8D 4D 17 84 C0", "E8 ? ? ? ? 48 8B 4D B7 0F B6 F0", "E8 ? ? ? ? 48 8D 4D 8F 0F B6 D8" };


		protected override void Apply(IntPtr from)
		{
			ApplyReadStringFromFileDetour(from);
			ApplyMonoDetour();
		}

		private void ApplyReadStringFromFileDetour(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<ReadStringFromFileDelegate>(OnReadStringFromFile);
			_detourReadStringFromFile = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			originalReadStringFromFile = _detourReadStringFromFile.GenerateTrampoline<ReadStringFromFileDelegate>();
			_detourReadStringFromFile.Apply();
		}

		private void ApplyMonoDetour()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<mono_assembly_load_from_full_delegate>(OnMonoAssemblyLoadFromFull);
			_monoDetour = new NativeDetour(mono_assembly_load_from_full_fn, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			originalMonoAssemblyLoadFromFull = _monoDetour.GenerateTrampoline<mono_assembly_load_from_full_delegate>();
			_monoDetour.Apply();
		}

		internal static void Dispose()
		{
			DisposeDetours();
		}

		private static void DisposeDetours()
		{
			if (_detourReadStringFromFile != null && _detourReadStringFromFile.IsApplied)
			{
				_detourReadStringFromFile.Dispose();
			}
			if (_monoDetour != null && _monoDetour.IsApplied)
			{
				_monoDetour.Dispose();
			}
			foreach (KeyValuePair<IntPtr, (IntPtr, IntPtr, ulong)> modifiedPathsToOriginalPath in ModifiedPathsToOriginalPaths)
			{
				modifiedPathsToOriginalPath.Deconstruct(out var key, out var _);
				Marshal.FreeHGlobal(key);
			}
		}

		private static bool OnReadStringFromFile(IntPtr outData, IntPtr assemblyStringPathName)
		{
			UseRightStructs.GetStruct<IAssemblyString>(assemblyStringPathName).FixAbsolutePath();
			return originalReadStringFromFile(outData, assemblyStringPathName);
		}

		private static IntPtr OnMonoAssemblyLoadFromFull(IntPtr image, IntPtr constCharFNamePtr, IntPtr status, IntPtr refonly)
		{
			IntPtr result = originalMonoAssemblyLoadFromFull(image, constCharFNamePtr, status, refonly);
			UseRightStructs.GetStruct<IAssemblyString>(constCharFNamePtr).RestoreOriginalString(constCharFNamePtr);
			return result;
		}
	}
	internal class ScriptingManagerDeconstructor : Patcher
	{
		[UnmanagedFunctionPointer(CallingConvention.FastCall)]
		private delegate void ScriptingManagerDeconstructorDelegate(IntPtr scriptingManagerPtr);

		private static NativeDetour _detour;

		private static ScriptingManagerDeconstructorDelegate orig;

		internal static bool IsApplied { get; private set; }

		protected override BytePattern[] PdbPatterns { get; } = new BytePattern[2]
		{
			Encoding.ASCII.GetBytes("ScriptingManager::~ScriptingManager"),
			Encoding.ASCII.GetBytes("?1ScriptingManager@")
		};


		protected override BytePattern[] SigPatterns { get; } = new BytePattern[1] { "48 89 5C 24 ? 57 48 83 EC 20 48 8D 05 ? ? ? ? 48 8B D9 48 89 01 48 81 C1 ? ? ? ? E8 ? ? ? ? 48 8D 8B ? ? ? ? E8 ? ? ? ? 48 8D 8B" };


		protected override void Apply(IntPtr from)
		{
			ApplyDetour(from);
			IsApplied = true;
		}

		private void ApplyDetour(IntPtr from)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<ScriptingManagerDeconstructorDelegate>(OnDeconstructor);
			_detour = new NativeDetour(from, functionPointerForDelegate, new NativeDetourConfig
			{
				ManualApply = true
			});
			orig = _detour.GenerateTrampoline<ScriptingManagerDeconstructorDelegate>();
			_detour.Apply();
		}

		internal static void Dispose()
		{
			DisposeDetours();
			IsApplied = false;
		}

		private static void DisposeDetours()
		{
			if (_detour != null && _detour.IsApplied)
			{
				_detour.Dispose();
			}
		}

		private static void OnDeconstructor(IntPtr scriptingManagerPtr)
		{
			AwakeFromLoad.CurrentMonoManager.RestoreOriginalAssemblyNamesArrayPtr();
			Log.Info("Restored original AssemblyNames list");
			orig(scriptingManagerPtr);
		}
	}
}

BepInEx/patchers/FixPluginTypesSerialization/Microsoft.Deployment.Compression.Cab.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyDescription("Managed libraries for cabinet archive packing and unpacking")]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: AssemblyFileVersion("3.10.1.2213")]
[assembly: AssemblyCompany("Outercurve Foundation")]
[assembly: AssemblyCopyright("Copyright (c) Outercurve Foundation. All rights reserved.")]
[assembly: AssemblyProduct("Windows Installer XML Toolset")]
[assembly: AssemblyConfiguration("")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion = true, UnmanagedCode = true)]
[assembly: AssemblyVersion("3.0.0.0")]
namespace Microsoft.Tools.WindowsInstallerXml
{
	internal static class WixDistribution
	{
		public static string NewsUrl = "http://wixtoolset.org/news/";

		public static string ShortProduct = "WiX Toolset";

		public static string SupportUrl = "http://wixtoolset.org/";

		public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}";

		public static string ReplacePlaceholders(string original, Assembly assembly)
		{
			if ((object)assembly != null)
			{
				FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
				original = original.Replace("[FileComments]", versionInfo.Comments);
				original = original.Replace("[FileCopyright]", versionInfo.LegalCopyright);
				original = original.Replace("[FileProductName]", versionInfo.ProductName);
				original = original.Replace("[FileVersion]", versionInfo.FileVersion);
				if (original.Contains("[FileVersionMajorMinor]"))
				{
					Version version = new Version(versionInfo.FileVersion);
					original = original.Replace("[FileVersionMajorMinor]", version.Major + "." + version.Minor);
				}
				if (TryGetAttribute<AssemblyCompanyAttribute>(assembly, out var attribute))
				{
					original = original.Replace("[AssemblyCompany]", attribute.Company);
				}
				if (TryGetAttribute<AssemblyCopyrightAttribute>(assembly, out var attribute2))
				{
					original = original.Replace("[AssemblyCopyright]", attribute2.Copyright);
				}
				if (TryGetAttribute<AssemblyDescriptionAttribute>(assembly, out var attribute3))
				{
					original = original.Replace("[AssemblyDescription]", attribute3.Description);
				}
				if (TryGetAttribute<AssemblyProductAttribute>(assembly, out var attribute4))
				{
					original = original.Replace("[AssemblyProduct]", attribute4.Product);
				}
				if (TryGetAttribute<AssemblyTitleAttribute>(assembly, out var attribute5))
				{
					original = original.Replace("[AssemblyTitle]", attribute5.Title);
				}
			}
			original = original.Replace("[NewsUrl]", NewsUrl);
			original = original.Replace("[ShortProduct]", ShortProduct);
			original = original.Replace("[SupportUrl]", SupportUrl);
			return original;
		}

		private static bool TryGetAttribute<T>(Assembly assembly, out T attribute) where T : Attribute
		{
			attribute = null;
			object[] customAttributes = assembly.GetCustomAttributes(typeof(T), inherit: false);
			if (customAttributes != null && customAttributes.Length != 0)
			{
				attribute = customAttributes[0] as T;
			}
			return attribute != null;
		}
	}
}
namespace Microsoft.Deployment.Compression.Cab
{
	internal class CabPacker : CabWorker
	{
		private const string TempStreamName = "%%TEMP%%";

		private NativeMethods.FCI.Handle fciHandle;

		private NativeMethods.FCI.PFNALLOC fciAllocMemHandler;

		private NativeMethods.FCI.PFNFREE fciFreeMemHandler;

		private NativeMethods.FCI.PFNOPEN fciOpenStreamHandler;

		private NativeMethods.FCI.PFNREAD fciReadStreamHandler;

		private NativeMethods.FCI.PFNWRITE fciWriteStreamHandler;

		private NativeMethods.FCI.PFNCLOSE fciCloseStreamHandler;

		private NativeMethods.FCI.PFNSEEK fciSeekStreamHandler;

		private NativeMethods.FCI.PFNFILEPLACED fciFilePlacedHandler;

		private NativeMethods.FCI.PFNDELETE fciDeleteFileHandler;

		private NativeMethods.FCI.PFNGETTEMPFILE fciGetTempFileHandler;

		private NativeMethods.FCI.PFNGETNEXTCABINET fciGetNextCabinet;

		private NativeMethods.FCI.PFNSTATUS fciCreateStatus;

		private NativeMethods.FCI.PFNGETOPENINFO fciGetOpenInfo;

		private IPackStreamContext context;

		private FileAttributes fileAttributes;

		private DateTime fileLastWriteTime;

		private int maxCabBytes;

		private long totalFolderBytesProcessedInCurrentCab;

		private CompressionLevel compressionLevel;

		private bool dontUseTempFiles;

		private IList<Stream> tempStreams;

		public bool UseTempFiles
		{
			get
			{
				return !dontUseTempFiles;
			}
			set
			{
				dontUseTempFiles = !value;
			}
		}

		public CompressionLevel CompressionLevel
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return compressionLevel;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				compressionLevel = value;
			}
		}

		public CabPacker(CabEngine cabEngine)
			: base(cabEngine)
		{
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			fciAllocMemHandler = base.CabAllocMem;
			fciFreeMemHandler = base.CabFreeMem;
			fciOpenStreamHandler = CabOpenStreamEx;
			fciReadStreamHandler = CabReadStreamEx;
			fciWriteStreamHandler = CabWriteStreamEx;
			fciCloseStreamHandler = CabCloseStreamEx;
			fciSeekStreamHandler = CabSeekStreamEx;
			fciFilePlacedHandler = CabFilePlaced;
			fciDeleteFileHandler = CabDeleteFile;
			fciGetTempFileHandler = CabGetTempFile;
			fciGetNextCabinet = CabGetNextCabinet;
			fciCreateStatus = CabCreateStatus;
			fciGetOpenInfo = CabGetOpenInfo;
			tempStreams = new List<Stream>();
			compressionLevel = (CompressionLevel)6;
		}

		private void CreateFci(long maxArchiveSize)
		{
			NativeMethods.FCI.CCAB cCAB = new NativeMethods.FCI.CCAB();
			checked
			{
				if (maxArchiveSize > 0 && maxArchiveSize < cCAB.cb)
				{
					cCAB.cb = Math.Max(32768, (int)maxArchiveSize);
				}
				object option = context.GetOption("maxFolderSize", (object[])null);
				if (option != null)
				{
					long num = Convert.ToInt64(option, CultureInfo.InvariantCulture);
					if (num > 0 && num < cCAB.cbFolderThresh)
					{
						cCAB.cbFolderThresh = (int)num;
					}
				}
				maxCabBytes = cCAB.cb;
				cCAB.szCab = context.GetArchiveName(0);
				if (cCAB.szCab == null)
				{
					throw new FileNotFoundException("Cabinet name not provided by stream context.");
				}
				cCAB.setID = (short)new Random().Next(-32768, 32768);
				base.CabNumbers[cCAB.szCab] = 0;
				currentArchiveName = cCAB.szCab;
				totalArchives = 1;
				base.CabStream = null;
				base.Erf.Clear();
				fciHandle = NativeMethods.FCI.Create(base.ErfHandle.AddrOfPinnedObject(), fciFilePlacedHandler, fciAllocMemHandler, fciFreeMemHandler, fciOpenStreamHandler, fciReadStreamHandler, fciWriteStreamHandler, fciCloseStreamHandler, fciSeekStreamHandler, fciDeleteFileHandler, fciGetTempFileHandler, cCAB, IntPtr.Zero);
				CheckError(extracting: false);
			}
		}

		[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
		public void Pack(IPackStreamContext streamContext, IEnumerable<string> files, long maxArchiveSize)
		{
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			if (streamContext == null)
			{
				throw new ArgumentNullException("streamContext");
			}
			if (files == null)
			{
				throw new ArgumentNullException("files");
			}
			lock (this)
			{
				try
				{
					context = streamContext;
					ResetProgressData();
					CreateFci(maxArchiveSize);
					checked
					{
						FileAttributes fileAttributes = default(FileAttributes);
						DateTime dateTime = default(DateTime);
						foreach (string file in files)
						{
							Stream stream = context.OpenFileReadStream(file, ref fileAttributes, ref dateTime);
							if (stream != null)
							{
								totalFileBytes += stream.Length;
								totalFiles++;
								context.CloseFileReadStream(file, stream);
							}
						}
						long num = 0L;
						currentFileNumber = -1;
						FileAttributes attributes = default(FileAttributes);
						DateTime lastWriteTime = default(DateTime);
						foreach (string file2 in files)
						{
							Stream stream2 = context.OpenFileReadStream(file2, ref attributes, ref lastWriteTime);
							if (stream2 == null)
							{
								continue;
							}
							if (stream2.Length >= 2147450880)
							{
								throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "File {0} exceeds maximum file size for cabinet format.", new object[1] { file2 }));
							}
							if (num > 0)
							{
								bool flag = num + stream2.Length >= 2147450880;
								if (!flag)
								{
									flag = Convert.ToBoolean(streamContext.GetOption("nextFolder", new object[2] { file2, currentFolderNumber }), CultureInfo.InvariantCulture);
								}
								if (flag)
								{
									FlushFolder();
									num = 0L;
								}
							}
							if (currentFolderTotalBytes > 0)
							{
								currentFolderTotalBytes = 0L;
								currentFolderNumber++;
								num = 0L;
							}
							currentFileName = file2;
							currentFileNumber++;
							currentFileTotalBytes = stream2.Length;
							currentFileBytesProcessed = 0L;
							OnProgress((ArchiveProgressType)0);
							num += stream2.Length;
							AddFile(file2, stream2, attributes, lastWriteTime, execute: false, CompressionLevel);
						}
						FlushFolder();
						FlushCabinet();
					}
				}
				finally
				{
					if (base.CabStream != null)
					{
						context.CloseArchiveWriteStream((int)currentArchiveNumber, currentArchiveName, base.CabStream);
						base.CabStream = null;
					}
					if (base.FileStream != null)
					{
						context.CloseFileReadStream(currentFileName, base.FileStream);
						base.FileStream = null;
					}
					context = null;
					if (fciHandle != null)
					{
						fciHandle.Dispose();
						fciHandle = null;
					}
				}
			}
		}

		internal override int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			if (base.CabNumbers.ContainsKey(path))
			{
				Stream stream = base.CabStream;
				if (stream == null)
				{
					short num = base.CabNumbers[path];
					currentFolderTotalBytes = 0L;
					stream = context.OpenArchiveWriteStream((int)num, path, true, (CompressionEngine)(object)base.CabEngine);
					if (stream == null)
					{
						throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Cabinet {0} not provided.", new object[1] { num }));
					}
					currentArchiveName = path;
					currentArchiveTotalBytes = Math.Min(totalFolderBytesProcessedInCurrentCab, maxCabBytes);
					currentArchiveBytesProcessed = 0L;
					OnProgress((ArchiveProgressType)3);
					base.CabStream = stream;
				}
				path = "%%CAB%%";
			}
			else
			{
				if (path == "%%TEMP%%")
				{
					Stream stream2 = new MemoryStream();
					tempStreams.Add(stream2);
					int result = base.StreamHandles.AllocHandle(stream2);
					err = 0;
					return result;
				}
				if (path != "%%CAB%%")
				{
					path = Path.Combine(Path.GetTempPath(), path);
					Stream stream3 = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
					tempStreams.Add(stream3);
					stream3 = (Stream)new DuplicateStream(stream3);
					int result2 = base.StreamHandles.AllocHandle(stream3);
					err = 0;
					return result2;
				}
			}
			return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv);
		}

		internal override int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
		{
			int num = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv);
			checked
			{
				if (num > 0 && err == 0 && DuplicateStream.OriginalStream(base.StreamHandles[streamHandle]) == DuplicateStream.OriginalStream(base.CabStream))
				{
					currentArchiveBytesProcessed += cb;
					if (currentArchiveBytesProcessed > currentArchiveTotalBytes)
					{
						currentArchiveBytesProcessed = currentArchiveTotalBytes;
					}
				}
				return num;
			}
		}

		internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
		{
			Stream stream = DuplicateStream.OriginalStream(base.StreamHandles[streamHandle]);
			checked
			{
				if (stream == DuplicateStream.OriginalStream(base.FileStream))
				{
					context.CloseFileReadStream(currentFileName, stream);
					base.FileStream = null;
					long num = currentFileTotalBytes - currentFileBytesProcessed;
					currentFileBytesProcessed += num;
					fileBytesProcessed += num;
					OnProgress((ArchiveProgressType)2);
					currentFileTotalBytes = 0L;
					currentFileBytesProcessed = 0L;
					currentFileName = null;
				}
				else if (stream == DuplicateStream.OriginalStream(base.CabStream))
				{
					if (stream.CanWrite)
					{
						stream.Flush();
					}
					currentArchiveBytesProcessed = currentArchiveTotalBytes;
					OnProgress((ArchiveProgressType)5);
					currentArchiveNumber++;
					totalArchives++;
					context.CloseArchiveWriteStream(unchecked((int)currentArchiveNumber), currentArchiveName, stream);
					currentArchiveName = base.NextCabinetName;
					currentArchiveBytesProcessed = (currentArchiveTotalBytes = 0L);
					totalFolderBytesProcessedInCurrentCab = 0L;
					base.CabStream = null;
				}
				else
				{
					stream.Close();
					tempStreams.Remove(stream);
				}
				return base.CabCloseStreamEx(streamHandle, out err, pv);
			}
		}

		protected override void Dispose(bool disposing)
		{
			try
			{
				if (disposing && fciHandle != null)
				{
					fciHandle.Dispose();
					fciHandle = null;
				}
			}
			finally
			{
				base.Dispose(disposing);
			}
		}

		private static NativeMethods.FCI.TCOMP GetCompressionType(CompressionLevel compLevel)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected I4, but got Unknown
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((int)compLevel < 1)
			{
				return NativeMethods.FCI.TCOMP.TYPE_NONE;
			}
			if ((int)compLevel > 10)
			{
				compLevel = (CompressionLevel)10;
			}
			int num = checked(6 * (compLevel - 1)) / 9;
			return (NativeMethods.FCI.TCOMP)checked((ushort)(3 | (3840 + (num << 8))));
		}

		private void AddFile(string name, Stream stream, FileAttributes attributes, DateTime lastWriteTime, bool execute, CompressionLevel compLevel)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			base.FileStream = stream;
			fileAttributes = attributes & (FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System | FileAttributes.Archive);
			fileLastWriteTime = lastWriteTime;
			currentFileName = name;
			NativeMethods.FCI.TCOMP compressionType = GetCompressionType(compLevel);
			IntPtr intPtr = IntPtr.Zero;
			try
			{
				Encoding encoding = Encoding.ASCII;
				if (Encoding.UTF8.GetByteCount(name) > name.Length)
				{
					encoding = Encoding.UTF8;
					fileAttributes |= FileAttributes.Normal;
				}
				byte[] bytes = encoding.GetBytes(name);
				intPtr = Marshal.AllocHGlobal(checked(bytes.Length + 1));
				Marshal.Copy(bytes, 0, intPtr, bytes.Length);
				Marshal.WriteByte(intPtr, bytes.Length, 0);
				base.Erf.Clear();
				NativeMethods.FCI.AddFile(fciHandle, string.Empty, intPtr, execute, fciGetNextCabinet, fciCreateStatus, fciGetOpenInfo, compressionType);
			}
			finally
			{
				if (intPtr != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(intPtr);
				}
			}
			CheckError(extracting: false);
			base.FileStream = null;
			currentFileName = null;
		}

		private void FlushFolder()
		{
			base.Erf.Clear();
			NativeMethods.FCI.FlushFolder(fciHandle, fciGetNextCabinet, fciCreateStatus);
			CheckError(extracting: false);
		}

		private void FlushCabinet()
		{
			base.Erf.Clear();
			NativeMethods.FCI.FlushCabinet(fciHandle, fGetNextCab: false, fciGetNextCabinet, fciCreateStatus);
			CheckError(extracting: false);
		}

		private int CabGetOpenInfo(string path, out short date, out short time, out short attribs, out int err, IntPtr pv)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			CompressionEngine.DateTimeToDosDateAndTime(fileLastWriteTime, ref date, ref time);
			attribs = checked((short)fileAttributes);
			Stream stream = base.FileStream;
			base.FileStream = (Stream)new DuplicateStream(stream);
			int result = base.StreamHandles.AllocHandle(stream);
			err = 0;
			return result;
		}

		private int CabFilePlaced(IntPtr pccab, string filePath, long fileSize, int continuation, IntPtr pv)
		{
			return 0;
		}

		private int CabGetNextCabinet(IntPtr pccab, uint prevCabSize, IntPtr pv)
		{
			NativeMethods.FCI.CCAB cCAB = new NativeMethods.FCI.CCAB();
			Marshal.PtrToStructure(pccab, (object)cCAB);
			cCAB.szDisk = string.Empty;
			cCAB.szCab = context.GetArchiveName(cCAB.iCab);
			base.CabNumbers[cCAB.szCab] = checked((short)cCAB.iCab);
			base.NextCabinetName = cCAB.szCab;
			Marshal.StructureToPtr((object)cCAB, pccab, fDeleteOld: false);
			return 1;
		}

		private int CabCreateStatus(NativeMethods.FCI.STATUS typeStatus, uint cb1, uint cb2, IntPtr pv)
		{
			checked
			{
				switch (typeStatus)
				{
				case NativeMethods.FCI.STATUS.FILE:
					if (cb2 != 0 && currentFileBytesProcessed < currentFileTotalBytes)
					{
						if (currentFileBytesProcessed + cb2 > currentFileTotalBytes)
						{
							cb2 = (uint)currentFileTotalBytes - (uint)currentFileBytesProcessed;
						}
						currentFileBytesProcessed += cb2;
						fileBytesProcessed += cb2;
						OnProgress((ArchiveProgressType)1);
					}
					break;
				case NativeMethods.FCI.STATUS.FOLDER:
					if (cb1 == 0)
					{
						currentFolderTotalBytes = cb2 - totalFolderBytesProcessedInCurrentCab;
						totalFolderBytesProcessedInCurrentCab = cb2;
					}
					else if (currentFolderTotalBytes == 0L)
					{
						OnProgress((ArchiveProgressType)4);
					}
					break;
				}
				return 0;
			}
		}

		private int CabGetTempFile(IntPtr tempNamePtr, int tempNameSize, IntPtr pv)
		{
			string s = ((!UseTempFiles) ? "%%TEMP%%" : Path.GetFileName(Path.GetTempFileName()));
			byte[] bytes = Encoding.ASCII.GetBytes(s);
			if (bytes.Length >= tempNameSize)
			{
				return -1;
			}
			Marshal.Copy(bytes, 0, tempNamePtr, bytes.Length);
			Marshal.WriteByte(tempNamePtr, bytes.Length, 0);
			return 1;
		}

		private int CabDeleteFile(string path, out int err, IntPtr pv)
		{
			try
			{
				if (path != "%%TEMP%%")
				{
					path = Path.Combine(Path.GetTempPath(), path);
					File.Delete(path);
				}
			}
			catch (IOException)
			{
			}
			err = 0;
			return 1;
		}
	}
	public class CabEngine : CompressionEngine
	{
		private CabPacker packer;

		private CabUnpacker unpacker;

		private CabPacker Packer
		{
			get
			{
				if (packer == null)
				{
					packer = new CabPacker(this);
				}
				return packer;
			}
		}

		private CabUnpacker Unpacker
		{
			get
			{
				if (unpacker == null)
				{
					unpacker = new CabUnpacker(this);
				}
				return unpacker;
			}
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (packer != null)
				{
					packer.Dispose();
					packer = null;
				}
				if (unpacker != null)
				{
					unpacker.Dispose();
					unpacker = null;
				}
			}
			((CompressionEngine)this).Dispose(disposing);
		}

		public override void Pack(IPackStreamContext streamContext, IEnumerable<string> files, long maxArchiveSize)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Packer.CompressionLevel = ((CompressionEngine)this).CompressionLevel;
			Packer.UseTempFiles = ((CompressionEngine)this).UseTempFiles;
			Packer.Pack(streamContext, files, maxArchiveSize);
		}

		public override bool IsArchive(Stream stream)
		{
			return Unpacker.IsArchive(stream);
		}

		public override IList<ArchiveFileInfo> GetFileInfo(IUnpackStreamContext streamContext, Predicate<string> fileFilter)
		{
			return Unpacker.GetFileInfo(streamContext, fileFilter);
		}

		public override void Unpack(IUnpackStreamContext streamContext, Predicate<string> fileFilter)
		{
			Unpacker.Unpack(streamContext, fileFilter);
		}

		internal void ReportProgress(ArchiveProgressEventArgs e)
		{
			((CompressionEngine)this).OnProgress(e);
		}
	}
	internal abstract class CabWorker : IDisposable
	{
		internal const string CabStreamName = "%%CAB%%";

		private CabEngine cabEngine;

		private HandleManager<Stream> streamHandles;

		private Stream cabStream;

		private Stream fileStream;

		private NativeMethods.ERF erf;

		private GCHandle erfHandle;

		private IDictionary<string, short> cabNumbers;

		private string nextCabinetName;

		private bool suppressProgressEvents;

		private byte[] buf;

		protected string currentFileName;

		protected int currentFileNumber;

		protected int totalFiles;

		protected long currentFileBytesProcessed;

		protected long currentFileTotalBytes;

		protected short currentFolderNumber;

		protected long currentFolderTotalBytes;

		protected string currentArchiveName;

		protected short currentArchiveNumber;

		protected short totalArchives;

		protected long currentArchiveBytesProcessed;

		protected long currentArchiveTotalBytes;

		protected long fileBytesProcessed;

		protected long totalFileBytes;

		public CabEngine CabEngine => cabEngine;

		internal NativeMethods.ERF Erf => erf;

		internal GCHandle ErfHandle => erfHandle;

		internal HandleManager<Stream> StreamHandles => streamHandles;

		internal bool SuppressProgressEvents
		{
			get
			{
				return suppressProgressEvents;
			}
			set
			{
				suppressProgressEvents = value;
			}
		}

		internal IDictionary<string, short> CabNumbers => cabNumbers;

		internal string NextCabinetName
		{
			get
			{
				return nextCabinetName;
			}
			set
			{
				nextCabinetName = value;
			}
		}

		internal Stream CabStream
		{
			get
			{
				return cabStream;
			}
			set
			{
				cabStream = value;
			}
		}

		internal Stream FileStream
		{
			get
			{
				return fileStream;
			}
			set
			{
				fileStream = value;
			}
		}

		protected CabWorker(CabEngine cabEngine)
		{
			this.cabEngine = cabEngine;
			streamHandles = new HandleManager<Stream>();
			erf = new NativeMethods.ERF();
			erfHandle = GCHandle.Alloc(erf, GCHandleType.Pinned);
			cabNumbers = new Dictionary<string, short>(1);
			buf = new byte[32768];
		}

		~CabWorker()
		{
			Dispose(disposing: false);
		}

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

		protected void ResetProgressData()
		{
			currentFileName = null;
			currentFileNumber = 0;
			totalFiles = 0;
			currentFileBytesProcessed = 0L;
			currentFileTotalBytes = 0L;
			currentFolderNumber = 0;
			currentFolderTotalBytes = 0L;
			currentArchiveName = null;
			currentArchiveNumber = 0;
			totalArchives = 0;
			currentArchiveBytesProcessed = 0L;
			currentArchiveTotalBytes = 0L;
			fileBytesProcessed = 0L;
			totalFileBytes = 0L;
		}

		protected void OnProgress(ArchiveProgressType progressType)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			if (!suppressProgressEvents)
			{
				ArchiveProgressEventArgs e = new ArchiveProgressEventArgs(progressType, currentFileName, (currentFileNumber >= 0) ? currentFileNumber : 0, totalFiles, currentFileBytesProcessed, currentFileTotalBytes, currentArchiveName, (int)currentArchiveNumber, (int)totalArchives, currentArchiveBytesProcessed, currentArchiveTotalBytes, fileBytesProcessed, totalFileBytes);
				CabEngine.ReportProgress(e);
			}
		}

		internal IntPtr CabAllocMem(int byteCount)
		{
			return Marshal.AllocHGlobal((IntPtr)byteCount);
		}

		internal void CabFreeMem(IntPtr memPointer)
		{
			Marshal.FreeHGlobal(memPointer);
		}

		internal int CabOpenStream(string path, int openFlags, int shareMode)
		{
			int err;
			return CabOpenStreamEx(path, openFlags, shareMode, out err, IntPtr.Zero);
		}

		internal virtual int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			path = path.Trim();
			Stream stream = cabStream;
			cabStream = (Stream)new DuplicateStream(stream);
			int result = streamHandles.AllocHandle(stream);
			err = 0;
			return result;
		}

		internal int CabReadStream(int streamHandle, IntPtr memory, int cb)
		{
			int err;
			return CabReadStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
		}

		internal virtual int CabReadStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
		{
			Stream stream = streamHandles[streamHandle];
			int num = cb;
			if (num > buf.Length)
			{
				buf = new byte[num];
			}
			num = stream.Read(buf, 0, num);
			Marshal.Copy(buf, 0, memory, num);
			err = 0;
			return num;
		}

		internal int CabWriteStream(int streamHandle, IntPtr memory, int cb)
		{
			int err;
			return CabWriteStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
		}

		internal virtual int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
		{
			Stream stream = streamHandles[streamHandle];
			if (cb > buf.Length)
			{
				buf = new byte[cb];
			}
			Marshal.Copy(memory, buf, 0, cb);
			stream.Write(buf, 0, cb);
			err = 0;
			return cb;
		}

		internal int CabCloseStream(int streamHandle)
		{
			int err;
			return CabCloseStreamEx(streamHandle, out err, IntPtr.Zero);
		}

		internal virtual int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
		{
			streamHandles.FreeHandle(streamHandle);
			err = 0;
			return 0;
		}

		internal int CabSeekStream(int streamHandle, int offset, int seekOrigin)
		{
			int err;
			return CabSeekStreamEx(streamHandle, offset, seekOrigin, out err, IntPtr.Zero);
		}

		internal virtual int CabSeekStreamEx(int streamHandle, int offset, int seekOrigin, out int err, IntPtr pv)
		{
			checked
			{
				offset = (int)streamHandles[streamHandle].Seek(offset, unchecked((SeekOrigin)seekOrigin));
				err = 0;
				return offset;
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (cabStream != null)
				{
					cabStream.Close();
					cabStream = null;
				}
				if (fileStream != null)
				{
					fileStream.Close();
					fileStream = null;
				}
			}
			if (erfHandle.IsAllocated)
			{
				erfHandle.Free();
			}
		}

		protected void CheckError(bool extracting)
		{
			if (Erf.Error)
			{
				throw new CabException(Erf.Oper, Erf.Type, CabException.GetErrorMessage(Erf.Oper, Erf.Type, extracting));
			}
		}
	}
	[Serializable]
	public class CabException : ArchiveException
	{
		private static ResourceManager errorResources;

		private int error;

		private int errorCode;

		public int Error => error;

		public int ErrorCode => errorCode;

		internal static ResourceManager ErrorResources
		{
			get
			{
				if (errorResources == null)
				{
					errorResources = new ResourceManager(typeof(CabException).Namespace + ".Errors", typeof(CabException).Assembly);
				}
				return errorResources;
			}
		}

		public CabException(string message, Exception innerException)
			: this(0, 0, message, innerException)
		{
		}

		public CabException(string message)
			: this(0, 0, message, null)
		{
		}

		public CabException()
			: this(0, 0, null, null)
		{
		}

		internal CabException(int error, int errorCode, string message, Exception innerException)
			: base(message, innerException)
		{
			this.error = error;
			this.errorCode = errorCode;
		}

		internal CabException(int error, int errorCode, string message)
			: this(error, errorCode, message, null)
		{
		}

		protected CabException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			error = info.GetInt32("cabError");
			errorCode = info.GetInt32("cabErrorCode");
		}

		[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			info.AddValue("cabError", error);
			info.AddValue("cabErrorCode", errorCode);
			((Exception)this).GetObjectData(info, context);
		}

		internal static string GetErrorMessage(int error, int errorCode, bool extracting)
		{
			int num = (extracting ? 2000 : 1000);
			string text = ErrorResources.GetString(checked(num + error).ToString(CultureInfo.InvariantCulture.NumberFormat), CultureInfo.CurrentCulture);
			if (text == null)
			{
				text = ErrorResources.GetString(num.ToString(CultureInfo.InvariantCulture.NumberFormat), CultureInfo.CurrentCulture);
			}
			if (errorCode != 0)
			{
				string @string = ErrorResources.GetString("1", CultureInfo.CurrentCulture);
				text = string.Format(CultureInfo.InvariantCulture, "{0} " + @string, new object[2] { text, errorCode });
			}
			return text;
		}
	}
	internal class CabUnpacker : CabWorker
	{
		private NativeMethods.FDI.Handle fdiHandle;

		private NativeMethods.FDI.PFNALLOC fdiAllocMemHandler;

		private NativeMethods.FDI.PFNFREE fdiFreeMemHandler;

		private NativeMethods.FDI.PFNOPEN fdiOpenStreamHandler;

		private NativeMethods.FDI.PFNREAD fdiReadStreamHandler;

		private NativeMethods.FDI.PFNWRITE fdiWriteStreamHandler;

		private NativeMethods.FDI.PFNCLOSE fdiCloseStreamHandler;

		private NativeMethods.FDI.PFNSEEK fdiSeekStreamHandler;

		private IUnpackStreamContext context;

		private List<ArchiveFileInfo> fileList;

		private int folderId;

		private Predicate<string> filter;

		[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
		public CabUnpacker(CabEngine cabEngine)
			: base(cabEngine)
		{
			fdiAllocMemHandler = base.CabAllocMem;
			fdiFreeMemHandler = base.CabFreeMem;
			fdiOpenStreamHandler = base.CabOpenStream;
			fdiReadStreamHandler = base.CabReadStream;
			fdiWriteStreamHandler = base.CabWriteStream;
			fdiCloseStreamHandler = base.CabCloseStream;
			fdiSeekStreamHandler = base.CabSeekStream;
			fdiHandle = NativeMethods.FDI.Create(fdiAllocMemHandler, fdiFreeMemHandler, fdiOpenStreamHandler, fdiReadStreamHandler, fdiWriteStreamHandler, fdiCloseStreamHandler, fdiSeekStreamHandler, 1, base.ErfHandle.AddrOfPinnedObject());
			if (base.Erf.Error)
			{
				int oper = base.Erf.Oper;
				int type = base.Erf.Type;
				base.ErfHandle.Free();
				throw new CabException(oper, type, CabException.GetErrorMessage(oper, type, extracting: true));
			}
		}

		[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
		public bool IsArchive(Stream stream)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			lock (this)
			{
				short id;
				int cabFolderCount;
				int fileCount;
				return IsCabinet(stream, out id, out cabFolderCount, out fileCount);
			}
		}

		[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
		public IList<ArchiveFileInfo> GetFileInfo(IUnpackStreamContext streamContext, Predicate<string> fileFilter)
		{
			if (streamContext == null)
			{
				throw new ArgumentNullException("streamContext");
			}
			lock (this)
			{
				context = streamContext;
				filter = fileFilter;
				base.NextCabinetName = string.Empty;
				fileList = new List<ArchiveFileInfo>();
				bool flag = base.SuppressProgressEvents;
				base.SuppressProgressEvents = true;
				try
				{
					short num = 0;
					while (base.NextCabinetName != null)
					{
						base.Erf.Clear();
						base.CabNumbers[base.NextCabinetName] = num;
						NativeMethods.FDI.Copy(fdiHandle, base.NextCabinetName, string.Empty, 0, CabListNotify, IntPtr.Zero, IntPtr.Zero);
						CheckError(extracting: true);
						num = checked((short)(num + 1));
					}
					List<ArchiveFileInfo> list = fileList;
					fileList = null;
					return list.AsReadOnly();
				}
				finally
				{
					base.SuppressProgressEvents = flag;
					if (base.CabStream != null)
					{
						context.CloseArchiveReadStream((int)currentArchiveNumber, currentArchiveName, base.CabStream);
						base.CabStream = null;
					}
					context = null;
				}
			}
		}

		[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
		public void Unpack(IUnpackStreamContext streamContext, Predicate<string> fileFilter)
		{
			checked
			{
				lock (this)
				{
					IList<ArchiveFileInfo> fileInfo = GetFileInfo(streamContext, fileFilter);
					ResetProgressData();
					if (fileInfo != null)
					{
						totalFiles = fileInfo.Count;
						for (int i = 0; i < fileInfo.Count; i++)
						{
							totalFileBytes += fileInfo[i].Length;
							if (fileInfo[i].ArchiveNumber >= totalArchives)
							{
								int num = fileInfo[i].ArchiveNumber + 1;
								totalArchives = (short)num;
							}
						}
					}
					context = streamContext;
					fileList = null;
					base.NextCabinetName = string.Empty;
					folderId = -1;
					currentFileNumber = -1;
					try
					{
						short num2 = 0;
						while (base.NextCabinetName != null)
						{
							base.Erf.Clear();
							base.CabNumbers[base.NextCabinetName] = num2;
							NativeMethods.FDI.Copy(fdiHandle, base.NextCabinetName, string.Empty, 0, CabExtractNotify, IntPtr.Zero, IntPtr.Zero);
							CheckError(extracting: true);
							num2++;
						}
					}
					finally
					{
						if (base.CabStream != null)
						{
							context.CloseArchiveReadStream(unchecked((int)currentArchiveNumber), currentArchiveName, base.CabStream);
							base.CabStream = null;
						}
						if (base.FileStream != null)
						{
							context.CloseFileWriteStream(currentFileName, base.FileStream, FileAttributes.Normal, DateTime.Now);
							base.FileStream = null;
						}
						context = null;
					}
				}
			}
		}

		internal override int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
		{
			if (base.CabNumbers.ContainsKey(path))
			{
				Stream stream = base.CabStream;
				if (stream == null)
				{
					short num = base.CabNumbers[path];
					stream = context.OpenArchiveReadStream((int)num, path, (CompressionEngine)(object)base.CabEngine);
					if (stream == null)
					{
						throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Cabinet {0} not provided.", new object[1] { num }));
					}
					currentArchiveName = path;
					currentArchiveNumber = num;
					checked
					{
						if (totalArchives <= currentArchiveNumber)
						{
							int num2 = currentArchiveNumber + 1;
							totalArchives = (short)num2;
						}
						currentArchiveTotalBytes = stream.Length;
						currentArchiveBytesProcessed = 0L;
						if (folderId != -3)
						{
							OnProgress((ArchiveProgressType)3);
						}
						base.CabStream = stream;
					}
				}
				path = "%%CAB%%";
			}
			return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv);
		}

		internal override int CabReadStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
		{
			int result = base.CabReadStreamEx(streamHandle, memory, cb, out err, pv);
			checked
			{
				if (err == 0 && base.CabStream != null && fileList == null && DuplicateStream.OriginalStream(base.StreamHandles[streamHandle]) == DuplicateStream.OriginalStream(base.CabStream))
				{
					currentArchiveBytesProcessed += cb;
					if (currentArchiveBytesProcessed > currentArchiveTotalBytes)
					{
						currentArchiveBytesProcessed = currentArchiveTotalBytes;
					}
				}
				return result;
			}
		}

		internal override int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
		{
			int num = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv);
			checked
			{
				if (num > 0 && err == 0)
				{
					currentFileBytesProcessed += cb;
					fileBytesProcessed += cb;
					OnProgress((ArchiveProgressType)1);
				}
				return num;
			}
		}

		internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
		{
			Stream stream = DuplicateStream.OriginalStream(base.StreamHandles[streamHandle]);
			if (stream == DuplicateStream.OriginalStream(base.CabStream))
			{
				if (folderId != -3)
				{
					OnProgress((ArchiveProgressType)5);
				}
				context.CloseArchiveReadStream((int)currentArchiveNumber, currentArchiveName, stream);
				currentArchiveName = base.NextCabinetName;
				currentArchiveBytesProcessed = (currentArchiveTotalBytes = 0L);
				base.CabStream = null;
			}
			return base.CabCloseStreamEx(streamHandle, out err, pv);
		}

		protected override void Dispose(bool disposing)
		{
			try
			{
				if (disposing && fdiHandle != null)
				{
					fdiHandle.Dispose();
					fdiHandle = null;
				}
			}
			finally
			{
				base.Dispose(disposing);
			}
		}

		private static string GetFileName(NativeMethods.FDI.NOTIFICATION notification)
		{
			Encoding encoding = ((((uint)notification.attribs & 0x80u) != 0) ? Encoding.UTF8 : Encoding.Default);
			int i;
			for (i = 0; Marshal.ReadByte(notification.psz1, i) != 0; i = checked(i + 1))
			{
			}
			byte[] array = new byte[i];
			Marshal.Copy(notification.psz1, array, 0, i);
			string text = encoding.GetString(array);
			if (Path.IsPathRooted(text))
			{
				text = text.Replace(Path.VolumeSeparatorChar.ToString() ?? "", "");
			}
			return text;
		}

		private bool IsCabinet(Stream cabStream, out short id, out int cabFolderCount, out int fileCount)
		{
			int num = base.StreamHandles.AllocHandle(cabStream);
			try
			{
				base.Erf.Clear();
				NativeMethods.FDI.CABINFO pfdici;
				bool result = NativeMethods.FDI.IsCabinet(fdiHandle, num, out pfdici) != 0;
				if (base.Erf.Error)
				{
					if (base.Erf.Oper != 3)
					{
						throw new CabException(base.Erf.Oper, base.Erf.Type, CabException.GetErrorMessage(base.Erf.Oper, base.Erf.Type, extracting: true));
					}
					result = false;
				}
				id = pfdici.setID;
				cabFolderCount = pfdici.cFolders;
				fileCount = pfdici.cFiles;
				return result;
			}
			finally
			{
				base.StreamHandles.FreeHandle(num);
			}
		}

		private int CabListNotify(NativeMethods.FDI.NOTIFICATIONTYPE notificationType, NativeMethods.FDI.NOTIFICATION notification)
		{
			checked
			{
				switch (notificationType)
				{
				case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO:
				{
					string text = Marshal.PtrToStringAnsi(notification.psz1);
					base.NextCabinetName = ((text.Length != 0) ? text : null);
					return 0;
				}
				case NativeMethods.FDI.NOTIFICATIONTYPE.PARTIAL_FILE:
					return 0;
				case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE:
				{
					string fileName = GetFileName(notification);
					if ((filter == null || filter(fileName)) && fileList != null)
					{
						FileAttributes fileAttributes = unchecked((FileAttributes)(notification.attribs & 0x27));
						if (fileAttributes == (FileAttributes)0)
						{
							fileAttributes = FileAttributes.Normal;
						}
						DateTime lastWriteTime = default(DateTime);
						CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, ref lastWriteTime);
						long length = notification.cb;
						CabFileInfo item = new CabFileInfo(fileName, notification.iFolder, notification.iCabinet, fileAttributes, lastWriteTime, length);
						fileList.Add((ArchiveFileInfo)(object)item);
						currentFileNumber = fileList.Count - 1;
						fileBytesProcessed += notification.cb;
					}
					totalFiles++;
					totalFileBytes += notification.cb;
					return 0;
				}
				default:
					return 0;
				}
			}
		}

		private int CabExtractNotify(NativeMethods.FDI.NOTIFICATIONTYPE notificationType, NativeMethods.FDI.NOTIFICATION notification)
		{
			switch (notificationType)
			{
			case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO:
				if (base.NextCabinetName != null && base.NextCabinetName.StartsWith("?", StringComparison.Ordinal))
				{
					base.NextCabinetName = base.NextCabinetName.Substring(1);
				}
				else
				{
					string text = Marshal.PtrToStringAnsi(notification.psz1);
					base.NextCabinetName = ((text.Length != 0) ? text : null);
				}
				return 0;
			case NativeMethods.FDI.NOTIFICATIONTYPE.NEXT_CABINET:
			{
				string key = Marshal.PtrToStringAnsi(notification.psz1);
				base.CabNumbers[key] = notification.iCabinet;
				base.NextCabinetName = "?" + base.NextCabinetName;
				return 0;
			}
			case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE:
				return CabExtractCopyFile(notification);
			case NativeMethods.FDI.NOTIFICATIONTYPE.CLOSE_FILE_INFO:
				return CabExtractCloseFile(notification);
			default:
				return 0;
			}
		}

		private int CabExtractCopyFile(NativeMethods.FDI.NOTIFICATION notification)
		{
			checked
			{
				if (notification.iFolder != folderId)
				{
					if (notification.iFolder != -3 && folderId != -1)
					{
						currentFolderNumber++;
					}
					folderId = notification.iFolder;
				}
				string fileName = GetFileName(notification);
				if (filter == null || filter(fileName))
				{
					currentFileNumber++;
					currentFileName = fileName;
					currentFileBytesProcessed = 0L;
					currentFileTotalBytes = notification.cb;
					OnProgress((ArchiveProgressType)0);
					DateTime dateTime = default(DateTime);
					CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, ref dateTime);
					Stream stream = context.OpenFileWriteStream(fileName, unchecked((long)notification.cb), dateTime);
					if (stream != null)
					{
						base.FileStream = stream;
						return base.StreamHandles.AllocHandle(stream);
					}
					fileBytesProcessed += notification.cb;
					OnProgress((ArchiveProgressType)2);
					currentFileName = null;
				}
				return 0;
			}
		}

		private int CabExtractCloseFile(NativeMethods.FDI.NOTIFICATION notification)
		{
			Stream stream = base.StreamHandles[notification.hf];
			base.StreamHandles.FreeHandle(notification.hf);
			string fileName = GetFileName(notification);
			FileAttributes fileAttributes = (FileAttributes)(notification.attribs & 0x27);
			if (fileAttributes == (FileAttributes)0)
			{
				fileAttributes = FileAttributes.Normal;
			}
			DateTime dateTime = default(DateTime);
			CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, ref dateTime);
			stream.Flush();
			context.CloseFileWriteStream(fileName, stream, fileAttributes, dateTime);
			base.FileStream = null;
			checked
			{
				long num = currentFileTotalBytes - currentFileBytesProcessed;
				currentFileBytesProcessed += num;
				fileBytesProcessed += num;
				OnProgress((ArchiveProgressType)2);
				currentFileName = null;
				return 1;
			}
		}
	}
	[Serializable]
	public class CabFileInfo : ArchiveFileInfo
	{
		private int cabFolder;

		public CabInfo Cabinet => (CabInfo)(object)((ArchiveFileInfo)this).Archive;

		public string CabinetName => ((ArchiveFileInfo)this).ArchiveName;

		public int CabinetFolderNumber
		{
			get
			{
				if (cabFolder < 0)
				{
					((ArchiveFileInfo)this).Refresh();
				}
				return cabFolder;
			}
		}

		public CabFileInfo(CabInfo cabinetInfo, string filePath)
			: base((ArchiveInfo)(object)cabinetInfo, filePath)
		{
			if (cabinetInfo == null)
			{
				throw new ArgumentNullException("cabinetInfo");
			}
			cabFolder = -1;
		}

		internal CabFileInfo(string filePath, int cabFolder, int cabNumber, FileAttributes attributes, DateTime lastWriteTime, long length)
			: base(filePath, cabNumber, attributes, lastWriteTime, length)
		{
			this.cabFolder = cabFolder;
		}

		protected CabFileInfo(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			cabFolder = info.GetInt32("cabFolder");
		}

		[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			((ArchiveFileInfo)this).GetObjectData(info, context);
			info.AddValue("cabFolder", cabFolder);
		}

		protected override void Refresh(ArchiveFileInfo newFileInfo)
		{
			((ArchiveFileInfo)this).Refresh(newFileInfo);
			cabFolder = ((CabFileInfo)(object)newFileInfo).cabFolder;
		}
	}
	[Serializable]
	public class CabInfo : ArchiveInfo
	{
		public CabInfo(string path)
			: base(path)
		{
		}

		protected CabInfo(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		protected override CompressionEngine CreateCompressionEngine()
		{
			return (CompressionEngine)(object)new CabEngine();
		}

		public IList<CabFileInfo> GetFiles()
		{
			IList<ArchiveFileInfo> files = ((ArchiveInfo)this).GetFiles();
			List<CabFileInfo> list = new List<CabFileInfo>(files.Count);
			foreach (CabFileInfo item in files)
			{
				list.Add(item);
			}
			return list.AsReadOnly();
		}

		public IList<CabFileInfo> GetFiles(string searchPattern)
		{
			IList<ArchiveFileInfo> files = ((ArchiveInfo)this).GetFiles(searchPattern);
			List<CabFileInfo> list = new List<CabFileInfo>(files.Count);
			foreach (CabFileInfo item in files)
			{
				list.Add(item);
			}
			return list.AsReadOnly();
		}
	}
	internal sealed class HandleManager<T> where T : class
	{
		private List<T> handles;

		public T this[int handle]
		{
			get
			{
				if (handle > 0 && handle <= handles.Count)
				{
					return handles[checked(handle - 1)];
				}
				return null;
			}
		}

		public HandleManager()
		{
			handles = new List<T>();
		}

		public int AllocHandle(T obj)
		{
			handles.Add(obj);
			return handles.Count;
		}

		public void FreeHandle(int handle)
		{
			if (handle > 0 && handle <= handles.Count)
			{
				handles[checked(handle - 1)] = null;
			}
		}
	}
	internal static class NativeMethods
	{
		internal static class FCI
		{
			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate IntPtr PFNALLOC(int cb);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate void PFNFREE(IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNOPEN(string path, int oflag, int pmode, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNREAD(int fileHandle, IntPtr memory, int cb, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNWRITE(int fileHandle, IntPtr memory, int cb, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNCLOSE(int fileHandle, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNSEEK(int fileHandle, int dist, int seekType, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNDELETE(string path, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNGETNEXTCABINET(IntPtr pccab, uint cbPrevCab, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNFILEPLACED(IntPtr pccab, string path, long fileSize, int continuation, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNGETOPENINFO(string path, out short date, out short time, out short pattribs, out int err, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNSTATUS(STATUS typeStatus, uint cb1, uint cb2, IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNGETTEMPFILE(IntPtr tempNamePtr, int tempNameSize, IntPtr pv);

			internal enum ERROR
			{
				NONE,
				OPEN_SRC,
				READ_SRC,
				ALLOC_FAIL,
				TEMP_FILE,
				BAD_COMPR_TYPE,
				CAB_FILE,
				USER_ABORT,
				MCI_FAIL
			}

			internal enum TCOMP : ushort
			{
				MASK_TYPE = 15,
				TYPE_NONE = 0,
				TYPE_MSZIP = 1,
				TYPE_QUANTUM = 2,
				TYPE_LZX = 3,
				BAD = 15,
				MASK_LZX_WINDOW = 7936,
				LZX_WINDOW_LO = 3840,
				LZX_WINDOW_HI = 5376,
				SHIFT_LZX_WINDOW = 8,
				MASK_QUANTUM_LEVEL = 240,
				QUANTUM_LEVEL_LO = 16,
				QUANTUM_LEVEL_HI = 112,
				SHIFT_QUANTUM_LEVEL = 4,
				MASK_QUANTUM_MEM = 7936,
				QUANTUM_MEM_LO = 2560,
				QUANTUM_MEM_HI = 5376,
				SHIFT_QUANTUM_MEM = 8,
				MASK_RESERVED = 57344
			}

			internal enum STATUS : uint
			{
				FILE,
				FOLDER,
				CABINET
			}

			[StructLayout(LayoutKind.Sequential)]
			internal class CCAB
			{
				internal int cb = int.MaxValue;

				internal int cbFolderThresh = 2147450880;

				internal int cbReserveCFHeader;

				internal int cbReserveCFFolder;

				internal int cbReserveCFData;

				internal int iCab;

				internal int iDisk;

				internal int fFailOnIncompressible;

				internal short setID;

				[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
				internal string szDisk = string.Empty;

				[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
				internal string szCab = string.Empty;

				[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
				internal string szCabPath = string.Empty;
			}

			internal class Handle : SafeHandle
			{
				public override bool IsInvalid => handle == IntPtr.Zero;

				internal Handle()
					: base(IntPtr.Zero, ownsHandle: true)
				{
				}

				[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
				protected override bool ReleaseHandle()
				{
					return Destroy(handle);
				}
			}

			internal const int MIN_DISK = 32768;

			internal const int MAX_DISK = int.MaxValue;

			internal const int MAX_FOLDER = 2147450880;

			internal const int MAX_FILENAME = 256;

			internal const int MAX_CABINET_NAME = 256;

			internal const int MAX_CAB_PATH = 256;

			internal const int MAX_DISK_NAME = 256;

			internal const int CPU_80386 = 1;

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FCICreate", ThrowOnUnmappableChar = true)]
			internal static extern Handle Create(IntPtr perf, PFNFILEPLACED pfnfcifp, PFNALLOC pfna, PFNFREE pfnf, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, PFNDELETE pfndelete, PFNGETTEMPFILE pfnfcigtf, [MarshalAs(UnmanagedType.LPStruct)] CCAB pccab, IntPtr pv);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FCIAddFile", ThrowOnUnmappableChar = true)]
			internal static extern int AddFile(Handle hfci, string pszSourceFile, IntPtr pszFileName, [MarshalAs(UnmanagedType.Bool)] bool fExecute, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis, PFNGETOPENINFO pfnfcigoi, TCOMP typeCompress);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FCIFlushCabinet", ThrowOnUnmappableChar = true)]
			internal static extern int FlushCabinet(Handle hfci, [MarshalAs(UnmanagedType.Bool)] bool fGetNextCab, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FCIFlushFolder", ThrowOnUnmappableChar = true)]
			internal static extern int FlushFolder(Handle hfci, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FCIDestroy", ThrowOnUnmappableChar = true)]
			[SuppressUnmanagedCodeSecurity]
			[return: MarshalAs(UnmanagedType.Bool)]
			internal static extern bool Destroy(IntPtr hfci);
		}

		internal static class FDI
		{
			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate IntPtr PFNALLOC(int cb);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate void PFNFREE(IntPtr pv);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNOPEN(string path, int oflag, int pmode);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNREAD(int hf, IntPtr pv, int cb);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNWRITE(int hf, IntPtr pv, int cb);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNCLOSE(int hf);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNSEEK(int hf, int dist, int seektype);

			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			internal delegate int PFNNOTIFY(NOTIFICATIONTYPE fdint, NOTIFICATION fdin);

			internal enum ERROR
			{
				NONE,
				CABINET_NOT_FOUND,
				NOT_A_CABINET,
				UNKNOWN_CABINET_VERSION,
				CORRUPT_CABINET,
				ALLOC_FAIL,
				BAD_COMPR_TYPE,
				MDI_FAIL,
				TARGET_FILE,
				RESERVE_MISMATCH,
				WRONG_CABINET,
				USER_ABORT
			}

			internal enum NOTIFICATIONTYPE
			{
				CABINET_INFO,
				PARTIAL_FILE,
				COPY_FILE,
				CLOSE_FILE_INFO,
				NEXT_CABINET,
				ENUMERATE
			}

			internal struct CABINFO
			{
				internal int cbCabinet;

				internal short cFolders;

				internal short cFiles;

				internal short setID;

				internal short iCabinet;

				internal int fReserve;

				internal int hasprev;

				internal int hasnext;
			}

			[StructLayout(LayoutKind.Sequential)]
			internal class NOTIFICATION
			{
				internal int cb;

				internal IntPtr psz1;

				internal IntPtr psz2;

				internal IntPtr psz3;

				internal IntPtr pv;

				internal IntPtr hf_ptr;

				internal short date;

				internal short time;

				internal short attribs;

				internal short setID;

				internal short iCabinet;

				internal short iFolder;

				internal int fdie;

				internal int hf => (int)hf_ptr;
			}

			internal class Handle : SafeHandle
			{
				public override bool IsInvalid => handle == IntPtr.Zero;

				internal Handle()
					: base(IntPtr.Zero, ownsHandle: true)
				{
				}

				protected override bool ReleaseHandle()
				{
					return Destroy(handle);
				}
			}

			internal const int MAX_DISK = int.MaxValue;

			internal const int MAX_FILENAME = 256;

			internal const int MAX_CABINET_NAME = 256;

			internal const int MAX_CAB_PATH = 256;

			internal const int MAX_DISK_NAME = 256;

			internal const int CPU_80386 = 1;

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FDICreate", ThrowOnUnmappableChar = true)]
			internal static extern Handle Create([MarshalAs(UnmanagedType.FunctionPtr)] PFNALLOC pfnalloc, [MarshalAs(UnmanagedType.FunctionPtr)] PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, IntPtr perf);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FDICopy", ThrowOnUnmappableChar = true)]
			internal static extern int Copy(Handle hfdi, string pszCabinet, string pszCabPath, int flags, PFNNOTIFY pfnfdin, IntPtr pfnfdid, IntPtr pvUser);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FDIDestroy", ThrowOnUnmappableChar = true)]
			[SuppressUnmanagedCodeSecurity]
			[return: MarshalAs(UnmanagedType.Bool)]
			internal static extern bool Destroy(IntPtr hfdi);

			[DllImport("cabinet.dll", BestFitMapping = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "FDIIsCabinet", ThrowOnUnmappableChar = true)]
			internal static extern int IsCabinet(Handle hfdi, int hf, out CABINFO pfdici);
		}

		[StructLayout(LayoutKind.Sequential)]
		internal class ERF
		{
			private int erfOper;

			private int erfType;

			private int fError;

			internal int Oper
			{
				get
				{
					return erfOper;
				}
				set
				{
					erfOper = value;
				}
			}

			internal int Type
			{
				get
				{
					return erfType;
				}
				set
				{
					erfType = value;
				}
			}

			internal bool Error
			{
				get
				{
					return fError != 0;
				}
				set
				{
					fError = (value ? 1 : 0);
				}
			}

			internal void Clear()
			{
				Oper = 0;
				Type = 0;
				Error = false;
			}
		}
	}
}

BepInEx/patchers/FixPluginTypesSerialization/Microsoft.Deployment.Compression.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyDescription("Abstract base libraries for archive packing and unpacking")]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: AssemblyFileVersion("3.10.1.2213")]
[assembly: AssemblyCompany("Outercurve Foundation")]
[assembly: AssemblyCopyright("Copyright (c) Outercurve Foundation. All rights reserved.")]
[assembly: AssemblyProduct("Windows Installer XML Toolset")]
[assembly: AssemblyConfiguration("")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
[assembly: AssemblyVersion("3.0.0.0")]
namespace Microsoft.Tools.WindowsInstallerXml
{
	internal static class WixDistribution
	{
		public static string NewsUrl = "http://wixtoolset.org/news/";

		public static string ShortProduct = "WiX Toolset";

		public static string SupportUrl = "http://wixtoolset.org/";

		public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}";

		public static string ReplacePlaceholders(string original, Assembly assembly)
		{
			if ((object)assembly != null)
			{
				FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
				original = original.Replace("[FileComments]", versionInfo.Comments);
				original = original.Replace("[FileCopyright]", versionInfo.LegalCopyright);
				original = original.Replace("[FileProductName]", versionInfo.ProductName);
				original = original.Replace("[FileVersion]", versionInfo.FileVersion);
				if (original.Contains("[FileVersionMajorMinor]"))
				{
					Version version = new Version(versionInfo.FileVersion);
					original = original.Replace("[FileVersionMajorMinor]", version.Major + "." + version.Minor);
				}
				if (TryGetAttribute<AssemblyCompanyAttribute>(assembly, out var attribute))
				{
					original = original.Replace("[AssemblyCompany]", attribute.Company);
				}
				if (TryGetAttribute<AssemblyCopyrightAttribute>(assembly, out var attribute2))
				{
					original = original.Replace("[AssemblyCopyright]", attribute2.Copyright);
				}
				if (TryGetAttribute<AssemblyDescriptionAttribute>(assembly, out var attribute3))
				{
					original = original.Replace("[AssemblyDescription]", attribute3.Description);
				}
				if (TryGetAttribute<AssemblyProductAttribute>(assembly, out var attribute4))
				{
					original = original.Replace("[AssemblyProduct]", attribute4.Product);
				}
				if (TryGetAttribute<AssemblyTitleAttribute>(assembly, out var attribute5))
				{
					original = original.Replace("[AssemblyTitle]", attribute5.Title);
				}
			}
			original = original.Replace("[NewsUrl]", NewsUrl);
			original = original.Replace("[ShortProduct]", ShortProduct);
			original = original.Replace("[SupportUrl]", SupportUrl);
			return original;
		}

		private static bool TryGetAttribute<T>(Assembly assembly, out T attribute) where T : Attribute
		{
			attribute = null;
			object[] customAttributes = assembly.GetCustomAttributes(typeof(T), inherit: false);
			if (customAttributes != null && customAttributes.Length != 0)
			{
				attribute = customAttributes[0] as T;
			}
			return attribute != null;
		}
	}
}
namespace Microsoft.Deployment.Compression
{
	[Serializable]
	public class ArchiveException : IOException
	{
		public ArchiveException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public ArchiveException(string message)
			: this(message, null)
		{
		}

		public ArchiveException()
			: this(null, null)
		{
		}

		protected ArchiveException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	[Serializable]
	public abstract class ArchiveFileInfo : FileSystemInfo
	{
		private ArchiveInfo archiveInfo;

		private string name;

		private string path;

		private bool initialized;

		private bool exists;

		private int archiveNumber;

		private FileAttributes attributes;

		private DateTime lastWriteTime;

		private long length;

		public override string Name => name;

		public string Path => path;

		public override string FullName
		{
			get
			{
				string text = System.IO.Path.Combine(Path, Name);
				if (Archive != null)
				{
					text = System.IO.Path.Combine(ArchiveName, text);
				}
				return text;
			}
		}

		public ArchiveInfo Archive
		{
			get
			{
				return archiveInfo;
			}
			internal set
			{
				archiveInfo = value;
				OriginalPath = value?.FullName;
				FullPath = OriginalPath;
			}
		}

		public string ArchiveName
		{
			get
			{
				if (Archive == null)
				{
					return null;
				}
				return Archive.FullName;
			}
		}

		public int ArchiveNumber => archiveNumber;

		public override bool Exists
		{
			get
			{
				if (!initialized)
				{
					Refresh();
				}
				return exists;
			}
		}

		public long Length
		{
			get
			{
				if (!initialized)
				{
					Refresh();
				}
				return length;
			}
		}

		public new FileAttributes Attributes
		{
			get
			{
				if (!initialized)
				{
					Refresh();
				}
				return attributes;
			}
		}

		public new DateTime LastWriteTime
		{
			get
			{
				if (!initialized)
				{
					Refresh();
				}
				return lastWriteTime;
			}
		}

		protected ArchiveFileInfo(ArchiveInfo archiveInfo, string filePath)
		{
			if (filePath == null)
			{
				throw new ArgumentNullException("filePath");
			}
			Archive = archiveInfo;
			name = System.IO.Path.GetFileName(filePath);
			path = System.IO.Path.GetDirectoryName(filePath);
			attributes = FileAttributes.Normal;
			lastWriteTime = DateTime.MinValue;
		}

		protected ArchiveFileInfo(string filePath, int archiveNumber, FileAttributes attributes, DateTime lastWriteTime, long length)
			: this(null, filePath)
		{
			exists = true;
			this.archiveNumber = archiveNumber;
			this.attributes = attributes;
			this.lastWriteTime = lastWriteTime;
			this.length = length;
			initialized = true;
		}

		protected ArchiveFileInfo(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			archiveInfo = (ArchiveInfo)info.GetValue("archiveInfo", typeof(ArchiveInfo));
			name = info.GetString("name");
			path = info.GetString("path");
			initialized = info.GetBoolean("initialized");
			exists = info.GetBoolean("exists");
			archiveNumber = info.GetInt32("archiveNumber");
			attributes = (FileAttributes)info.GetValue("attributes", typeof(FileAttributes));
			lastWriteTime = info.GetDateTime("lastWriteTime");
			length = info.GetInt64("length");
		}

		[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			base.GetObjectData(info, context);
			info.AddValue("archiveInfo", archiveInfo);
			info.AddValue("name", name);
			info.AddValue("path", path);
			info.AddValue("initialized", initialized);
			info.AddValue("exists", exists);
			info.AddValue("archiveNumber", archiveNumber);
			info.AddValue("attributes", attributes);
			info.AddValue("lastWriteTime", lastWriteTime);
			info.AddValue("length", length);
		}

		public override string ToString()
		{
			return FullName;
		}

		public override void Delete()
		{
			throw new NotSupportedException();
		}

		public new void Refresh()
		{
			base.Refresh();
			if (Archive != null)
			{
				string fileName = System.IO.Path.Combine(Path, Name);
				ArchiveFileInfo file = Archive.GetFile(fileName);
				if (file == null)
				{
					throw new FileNotFoundException("File not found in archive.", fileName);
				}
				Refresh(file);
			}
		}

		public void CopyTo(string destFileName)
		{
			CopyTo(destFileName, overwrite: false);
		}

		public void CopyTo(string destFileName, bool overwrite)
		{
			if (destFileName == null)
			{
				throw new ArgumentNullException("destFileName");
			}
			if (!overwrite && File.Exists(destFileName))
			{
				throw new IOException();
			}
			if (Archive == null)
			{
				throw new InvalidOperationException();
			}
			Archive.UnpackFile(System.IO.Path.Combine(Path, Name), destFileName);
		}

		public Stream OpenRead()
		{
			return Archive.OpenRead(System.IO.Path.Combine(Path, Name));
		}

		public StreamReader OpenText()
		{
			return Archive.OpenText(System.IO.Path.Combine(Path, Name));
		}

		protected virtual void Refresh(ArchiveFileInfo newFileInfo)
		{
			exists = newFileInfo.exists;
			length = newFileInfo.length;
			attributes = newFileInfo.attributes;
			lastWriteTime = newFileInfo.lastWriteTime;
		}
	}
	[Serializable]
	public abstract class ArchiveInfo : FileSystemInfo
	{
		public DirectoryInfo Directory => new DirectoryInfo(Path.GetDirectoryName(FullName));

		public string DirectoryName => Path.GetDirectoryName(FullName);

		public long Length => new FileInfo(FullName).Length;

		public override string Name => Path.GetFileName(FullName);

		public override bool Exists => File.Exists(FullName);

		protected ArchiveInfo(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			OriginalPath = path;
			FullPath = Path.GetFullPath(path);
		}

		protected ArchiveInfo(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public override string ToString()
		{
			return FullName;
		}

		public override void Delete()
		{
			File.Delete(FullName);
		}

		public void CopyTo(string destFileName)
		{
			File.Copy(FullName, destFileName);
		}

		public void CopyTo(string destFileName, bool overwrite)
		{
			File.Copy(FullName, destFileName, overwrite);
		}

		public void MoveTo(string destFileName)
		{
			File.Move(FullName, destFileName);
			FullPath = Path.GetFullPath(destFileName);
		}

		public bool IsValid()
		{
			using Stream stream = File.OpenRead(FullName);
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			return compressionEngine.FindArchiveOffset(stream) >= 0;
		}

		public IList<ArchiveFileInfo> GetFiles()
		{
			return InternalGetFiles(null);
		}

		public IList<ArchiveFileInfo> GetFiles(string searchPattern)
		{
			if (searchPattern == null)
			{
				throw new ArgumentNullException("searchPattern");
			}
			string pattern = string.Format(CultureInfo.InvariantCulture, "^{0}$", new object[1] { Regex.Escape(searchPattern).Replace("\\*", ".*").Replace("\\?", ".") });
			Regex regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
			return InternalGetFiles((string match) => regex.IsMatch(match));
		}

		public void Unpack(string destDirectory)
		{
			Unpack(destDirectory, null);
		}

		public void Unpack(string destDirectory, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			compressionEngine.Progress += progressHandler;
			ArchiveFileStreamContext archiveFileStreamContext = new ArchiveFileStreamContext(FullName, destDirectory, null);
			archiveFileStreamContext.EnableOffsetOpen = true;
			compressionEngine.Unpack(archiveFileStreamContext, null);
		}

		public void UnpackFile(string fileName, string destFileName)
		{
			if (fileName == null)
			{
				throw new ArgumentNullException("fileName");
			}
			if (destFileName == null)
			{
				throw new ArgumentNullException("destFileName");
			}
			UnpackFiles(new string[1] { fileName }, null, new string[1] { destFileName });
		}

		public void UnpackFiles(IList<string> fileNames, string destDirectory, IList<string> destFileNames)
		{
			UnpackFiles(fileNames, destDirectory, destFileNames, null);
		}

		public void UnpackFiles(IList<string> fileNames, string destDirectory, IList<string> destFileNames, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			if (fileNames == null)
			{
				throw new ArgumentNullException("fileNames");
			}
			if (destFileNames == null)
			{
				if (destDirectory == null)
				{
					throw new ArgumentNullException("destFileNames");
				}
				destFileNames = fileNames;
			}
			if (destFileNames.Count != fileNames.Count)
			{
				throw new ArgumentOutOfRangeException("destFileNames");
			}
			IDictionary<string, string> fileNames2 = CreateStringDictionary(fileNames, destFileNames);
			UnpackFileSet(fileNames2, destDirectory, progressHandler);
		}

		public void UnpackFileSet(IDictionary<string, string> fileNames, string destDirectory)
		{
			UnpackFileSet(fileNames, destDirectory, null);
		}

		public void UnpackFileSet(IDictionary<string, string> fileNames, string destDirectory, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			if (fileNames == null)
			{
				throw new ArgumentNullException("fileNames");
			}
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			compressionEngine.Progress += progressHandler;
			ArchiveFileStreamContext archiveFileStreamContext = new ArchiveFileStreamContext(FullName, destDirectory, fileNames);
			archiveFileStreamContext.EnableOffsetOpen = true;
			compressionEngine.Unpack(archiveFileStreamContext, (string match) => fileNames.ContainsKey(match));
		}

		public Stream OpenRead(string fileName)
		{
			Stream stream = File.OpenRead(FullName);
			CompressionEngine compressionEngine = CreateCompressionEngine();
			return new CargoStream(compressionEngine.Unpack(stream, fileName), stream, compressionEngine);
		}

		public StreamReader OpenText(string fileName)
		{
			return new StreamReader(OpenRead(fileName));
		}

		public void Pack(string sourceDirectory)
		{
			Pack(sourceDirectory, includeSubdirectories: false, CompressionLevel.Max, null);
		}

		public void Pack(string sourceDirectory, bool includeSubdirectories, CompressionLevel compLevel, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			IList<string> relativeFilePathsInDirectoryTree = GetRelativeFilePathsInDirectoryTree(sourceDirectory, includeSubdirectories);
			PackFiles(sourceDirectory, relativeFilePathsInDirectoryTree, relativeFilePathsInDirectoryTree, compLevel, progressHandler);
		}

		public void PackFiles(string sourceDirectory, IList<string> sourceFileNames, IList<string> fileNames)
		{
			PackFiles(sourceDirectory, sourceFileNames, fileNames, CompressionLevel.Max, null);
		}

		public void PackFiles(string sourceDirectory, IList<string> sourceFileNames, IList<string> fileNames, CompressionLevel compLevel, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			if (sourceFileNames == null)
			{
				throw new ArgumentNullException("sourceFileNames");
			}
			if (fileNames == null)
			{
				string[] array = new string[sourceFileNames.Count];
				for (int i = 0; i < sourceFileNames.Count; i = checked(i + 1))
				{
					array[i] = Path.GetFileName(sourceFileNames[i]);
				}
				fileNames = array;
			}
			else if (fileNames.Count != sourceFileNames.Count)
			{
				throw new ArgumentOutOfRangeException("fileNames");
			}
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			compressionEngine.Progress += progressHandler;
			IDictionary<string, string> files = CreateStringDictionary(fileNames, sourceFileNames);
			ArchiveFileStreamContext archiveFileStreamContext = new ArchiveFileStreamContext(FullName, sourceDirectory, files);
			archiveFileStreamContext.EnableOffsetOpen = true;
			compressionEngine.CompressionLevel = compLevel;
			compressionEngine.Pack(archiveFileStreamContext, fileNames);
		}

		public void PackFileSet(string sourceDirectory, IDictionary<string, string> fileNames)
		{
			PackFileSet(sourceDirectory, fileNames, CompressionLevel.Max, null);
		}

		public void PackFileSet(string sourceDirectory, IDictionary<string, string> fileNames, CompressionLevel compLevel, EventHandler<ArchiveProgressEventArgs> progressHandler)
		{
			if (fileNames == null)
			{
				throw new ArgumentNullException("fileNames");
			}
			string[] array = new string[fileNames.Count];
			fileNames.Keys.CopyTo(array, 0);
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			compressionEngine.Progress += progressHandler;
			ArchiveFileStreamContext archiveFileStreamContext = new ArchiveFileStreamContext(FullName, sourceDirectory, fileNames);
			archiveFileStreamContext.EnableOffsetOpen = true;
			compressionEngine.CompressionLevel = compLevel;
			compressionEngine.Pack(archiveFileStreamContext, array);
		}

		internal IList<string> GetRelativeFilePathsInDirectoryTree(string dir, bool includeSubdirectories)
		{
			IList<string> list = new List<string>();
			RecursiveGetRelativeFilePathsInDirectoryTree(dir, string.Empty, includeSubdirectories, list);
			return list;
		}

		internal ArchiveFileInfo GetFile(string path)
		{
			IList<ArchiveFileInfo> list = InternalGetFiles((string match) => string.Compare(match, path, ignoreCase: true, CultureInfo.InvariantCulture) == 0);
			if (list == null || list.Count <= 0)
			{
				return null;
			}
			return list[0];
		}

		protected abstract CompressionEngine CreateCompressionEngine();

		private static IDictionary<string, string> CreateStringDictionary(IList<string> keys, IList<string> values)
		{
			IDictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < keys.Count; i = checked(i + 1))
			{
				dictionary.Add(keys[i], values[i]);
			}
			return dictionary;
		}

		private void RecursiveGetRelativeFilePathsInDirectoryTree(string dir, string relativeDir, bool includeSubdirectories, IList<string> fileList)
		{
			string[] files = System.IO.Directory.GetFiles(dir);
			for (int i = 0; i < files.Length; i++)
			{
				string fileName = Path.GetFileName(files[i]);
				fileList.Add(Path.Combine(relativeDir, fileName));
			}
			if (includeSubdirectories)
			{
				files = System.IO.Directory.GetDirectories(dir);
				for (int i = 0; i < files.Length; i++)
				{
					string fileName2 = Path.GetFileName(files[i]);
					RecursiveGetRelativeFilePathsInDirectoryTree(Path.Combine(dir, fileName2), Path.Combine(relativeDir, fileName2), includeSubdirectories, fileList);
				}
			}
		}

		private IList<ArchiveFileInfo> InternalGetFiles(Predicate<string> fileFilter)
		{
			using CompressionEngine compressionEngine = CreateCompressionEngine();
			ArchiveFileStreamContext archiveFileStreamContext = new ArchiveFileStreamContext(FullName, null, null);
			archiveFileStreamContext.EnableOffsetOpen = true;
			IList<ArchiveFileInfo> fileInfo = compressionEngine.GetFileInfo(archiveFileStreamContext, fileFilter);
			for (int i = 0; i < fileInfo.Count; i = checked(i + 1))
			{
				fileInfo[i].Archive = this;
			}
			return fileInfo;
		}
	}
	public class ArchiveProgressEventArgs : EventArgs
	{
		private ArchiveProgressType progressType;

		private string currentFileName;

		private int currentFileNumber;

		private int totalFiles;

		private long currentFileBytesProcessed;

		private long currentFileTotalBytes;

		private string currentArchiveName;

		private short currentArchiveNumber;

		private short totalArchives;

		private long currentArchiveBytesProcessed;

		private long currentArchiveTotalBytes;

		private long fileBytesProcessed;

		private long totalFileBytes;

		public ArchiveProgressType ProgressType => progressType;

		public string CurrentFileName => currentFileName;

		public int CurrentFileNumber => currentFileNumber;

		public int TotalFiles => totalFiles;

		public long CurrentFileBytesProcessed => currentFileBytesProcessed;

		public long CurrentFileTotalBytes => currentFileTotalBytes;

		public string CurrentArchiveName => currentArchiveName;

		public int CurrentArchiveNumber => currentArchiveNumber;

		public int TotalArchives => totalArchives;

		public long CurrentArchiveBytesProcessed => currentArchiveBytesProcessed;

		public long CurrentArchiveTotalBytes => currentArchiveTotalBytes;

		public long FileBytesProcessed => fileBytesProcessed;

		public long TotalFileBytes => totalFileBytes;

		public ArchiveProgressEventArgs(ArchiveProgressType progressType, string currentFileName, int currentFileNumber, int totalFiles, long currentFileBytesProcessed, long currentFileTotalBytes, string currentArchiveName, int currentArchiveNumber, int totalArchives, long currentArchiveBytesProcessed, long currentArchiveTotalBytes, long fileBytesProcessed, long totalFileBytes)
		{
			this.progressType = progressType;
			this.currentFileName = currentFileName;
			this.currentFileNumber = currentFileNumber;
			this.totalFiles = totalFiles;
			this.currentFileBytesProcessed = currentFileBytesProcessed;
			this.currentFileTotalBytes = currentFileTotalBytes;
			this.currentArchiveName = currentArchiveName;
			checked
			{
				this.currentArchiveNumber = (short)currentArchiveNumber;
				this.totalArchives = (short)totalArchives;
				this.currentArchiveBytesProcessed = currentArchiveBytesProcessed;
				this.currentArchiveTotalBytes = currentArchiveTotalBytes;
				this.fileBytesProcessed = fileBytesProcessed;
				this.totalFileBytes = totalFileBytes;
			}
		}
	}
	public enum ArchiveProgressType
	{
		StartFile,
		PartialFile,
		FinishFile,
		StartArchive,
		PartialArchive,
		FinishArchive
	}
	public class ArchiveFileStreamContext : IPackStreamContext, IUnpackStreamContext
	{
		private IList<string> archiveFiles;

		private string directory;

		private IDictionary<string, string> files;

		private bool extractOnlyNewerFiles;

		private bool enableOffsetOpen;

		public IList<string> ArchiveFiles => archiveFiles;

		public string Directory => directory;

		public IDictionary<string, string> Files => files;

		public bool ExtractOnlyNewerFiles
		{
			get
			{
				return extractOnlyNewerFiles;
			}
			set
			{
				extractOnlyNewerFiles = value;
			}
		}

		public bool EnableOffsetOpen
		{
			get
			{
				return enableOffsetOpen;
			}
			set
			{
				enableOffsetOpen = value;
			}
		}

		public ArchiveFileStreamContext(string archiveFile)
			: this(archiveFile, null, null)
		{
		}

		public ArchiveFileStreamContext(string archiveFile, string directory, IDictionary<string, string> files)
			: this(new string[1] { archiveFile }, directory, files)
		{
			if (archiveFile == null)
			{
				throw new ArgumentNullException("archiveFile");
			}
		}

		public ArchiveFileStreamContext(IList<string> archiveFiles, string directory, IDictionary<string, string> files)
		{
			if (archiveFiles == null || archiveFiles.Count == 0)
			{
				throw new ArgumentNullException("archiveFiles");
			}
			this.archiveFiles = archiveFiles;
			this.directory = directory;
			this.files = files;
		}

		public virtual string GetArchiveName(int archiveNumber)
		{
			if (archiveNumber < archiveFiles.Count)
			{
				return Path.GetFileName(archiveFiles[archiveNumber]);
			}
			return string.Empty;
		}

		public virtual Stream OpenArchiveWriteStream(int archiveNumber, string archiveName, bool truncate, CompressionEngine compressionEngine)
		{
			if (archiveNumber >= archiveFiles.Count)
			{
				return null;
			}
			if (string.IsNullOrEmpty(archiveName))
			{
				throw new ArgumentNullException("archiveName");
			}
			Stream stream = File.Open(Path.Combine(Path.GetDirectoryName(archiveFiles[0]), archiveName), truncate ? FileMode.OpenOrCreate : FileMode.Open, FileAccess.ReadWrite);
			if (enableOffsetOpen)
			{
				long num = compressionEngine.FindArchiveOffset(new DuplicateStream(stream));
				if (num < 0)
				{
					num = stream.Length;
				}
				if (num > 0)
				{
					stream = new OffsetStream(stream, num);
				}
				stream.Seek(0L, SeekOrigin.Begin);
			}
			if (truncate)
			{
				stream.SetLength(0L);
			}
			return stream;
		}

		public virtual void CloseArchiveWriteStream(int archiveNumber, string archiveName, Stream stream)
		{
			if (stream == null)
			{
				return;
			}
			stream.Close();
			if (!(stream is FileStream fileStream))
			{
				return;
			}
			string name = fileStream.Name;
			if (!string.IsNullOrEmpty(archiveName) && archiveName != Path.GetFileName(name))
			{
				string text = Path.Combine(Path.GetDirectoryName(archiveFiles[0]), archiveName);
				if (File.Exists(text))
				{
					File.Delete(text);
				}
				File.Move(name, text);
			}
		}

		public virtual Stream OpenFileReadStream(string path, out FileAttributes attributes, out DateTime lastWriteTime)
		{
			string text = TranslateFilePath(path);
			if (text == null)
			{
				attributes = FileAttributes.Normal;
				lastWriteTime = DateTime.Now;
				return null;
			}
			attributes = File.GetAttributes(text);
			lastWriteTime = File.GetLastWriteTime(text);
			return File.Open(text, FileMode.Open, FileAccess.Read, FileShare.Read);
		}

		public virtual void CloseFileReadStream(string path, Stream stream)
		{
			stream?.Close();
		}

		public virtual object GetOption(string optionName, object[] parameters)
		{
			return null;
		}

		public virtual Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine)
		{
			if (archiveNumber >= archiveFiles.Count)
			{
				return null;
			}
			Stream stream = File.Open(archiveFiles[archiveNumber], FileMode.Open, FileAccess.Read, FileShare.Read);
			if (enableOffsetOpen)
			{
				long num = compressionEngine.FindArchiveOffset(new DuplicateStream(stream));
				if (num > 0)
				{
					stream = new OffsetStream(stream, num);
				}
				else
				{
					stream.Seek(0L, SeekOrigin.Begin);
				}
			}
			return stream;
		}

		public virtual void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream)
		{
			stream?.Close();
		}

		public virtual Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime)
		{
			string text = TranslateFilePath(path);
			if (text == null)
			{
				return null;
			}
			FileInfo fileInfo = new FileInfo(text);
			if (fileInfo.Exists)
			{
				if (extractOnlyNewerFiles && lastWriteTime != DateTime.MinValue && fileInfo.LastWriteTime >= lastWriteTime)
				{
					return null;
				}
				FileAttributes fileAttributes = FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System;
				if ((fileInfo.Attributes & fileAttributes) != 0)
				{
					fileInfo.Attributes &= ~fileAttributes;
				}
			}
			if (!fileInfo.Directory.Exists)
			{
				fileInfo.Directory.Create();
			}
			return File.Open(text, FileMode.Create, FileAccess.Write, FileShare.None);
		}

		public virtual void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime)
		{
			stream?.Close();
			string text = TranslateFilePath(path);
			if (text == null)
			{
				return;
			}
			FileInfo fileInfo = new FileInfo(text);
			if (lastWriteTime != DateTime.MinValue)
			{
				try
				{
					fileInfo.LastWriteTime = lastWriteTime;
				}
				catch (ArgumentException)
				{
				}
				catch (IOException)
				{
				}
			}
			try
			{
				fileInfo.Attributes = attributes;
			}
			catch (IOException)
			{
			}
		}

		private string TranslateFilePath(string path)
		{
			string text = ((files == null) ? path : files[path]);
			if (text != null && directory != null)
			{
				text = Path.Combine(directory, text);
			}
			return text;
		}
	}
	public class BasicUnpackStreamContext : IUnpackStreamContext
	{
		private Stream archiveStream;

		private Stream fileStream;

		public Stream FileStream => fileStream;

		public BasicUnpackStreamContext(Stream archiveStream)
		{
			this.archiveStream = archiveStream;
		}

		public Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine)
		{
			return new DuplicateStream(archiveStream);
		}

		public void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream)
		{
		}

		public Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime)
		{
			fileStream = new MemoryStream(new byte[fileSize], 0, checked((int)fileSize), writable: true, publiclyVisible: true);
			return fileStream;
		}

		public void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime)
		{
		}
	}
	public abstract class CompressionEngine : IDisposable
	{
		private CompressionLevel compressionLevel;

		private bool dontUseTempFiles;

		public bool UseTempFiles
		{
			get
			{
				return !dontUseTempFiles;
			}
			set
			{
				dontUseTempFiles = !value;
			}
		}

		public CompressionLevel CompressionLevel
		{
			get
			{
				return compressionLevel;
			}
			set
			{
				compressionLevel = value;
			}
		}

		public event EventHandler<ArchiveProgressEventArgs> Progress;

		protected CompressionEngine()
		{
			compressionLevel = CompressionLevel.Normal;
		}

		~CompressionEngine()
		{
			Dispose(disposing: false);
		}

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

		public void Pack(IPackStreamContext streamContext, IEnumerable<string> files)
		{
			if (files == null)
			{
				throw new ArgumentNullException("files");
			}
			Pack(streamContext, files, 0L);
		}

		public abstract void Pack(IPackStreamContext streamContext, IEnumerable<string> files, long maxArchiveSize);

		public abstract bool IsArchive(Stream stream);

		public virtual long FindArchiveOffset(Stream stream)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			long num = 4L;
			long length = stream.Length;
			checked
			{
				for (long num2 = 0L; num2 <= length - num; num2 += num)
				{
					stream.Seek(num2, SeekOrigin.Begin);
					if (IsArchive(stream))
					{
						return num2;
					}
				}
				return -1L;
			}
		}

		public IList<ArchiveFileInfo> GetFileInfo(Stream stream)
		{
			return GetFileInfo(new BasicUnpackStreamContext(stream), null);
		}

		public abstract IList<ArchiveFileInfo> GetFileInfo(IUnpackStreamContext streamContext, Predicate<string> fileFilter);

		public IList<string> GetFiles(Stream stream)
		{
			return GetFiles(new BasicUnpackStreamContext(stream), null);
		}

		public IList<string> GetFiles(IUnpackStreamContext streamContext, Predicate<string> fileFilter)
		{
			if (streamContext == null)
			{
				throw new ArgumentNullException("streamContext");
			}
			IList<ArchiveFileInfo> fileInfo = GetFileInfo(streamContext, fileFilter);
			IList<string> list = new List<string>(fileInfo.Count);
			for (int i = 0; i < fileInfo.Count; i = checked(i + 1))
			{
				list.Add(fileInfo[i].Name);
			}
			return list;
		}

		public Stream Unpack(Stream stream, string path)
		{
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			BasicUnpackStreamContext basicUnpackStreamContext = new BasicUnpackStreamContext(stream);
			Unpack(basicUnpackStreamContext, (string match) => string.Compare(match, path, ignoreCase: true, CultureInfo.InvariantCulture) == 0);
			Stream fileStream = basicUnpackStreamContext.FileStream;
			if (fileStream != null)
			{
				fileStream.Position = 0L;
			}
			return fileStream;
		}

		public abstract void Unpack(IUnpackStreamContext streamContext, Predicate<string> fileFilter);

		protected void OnProgress(ArchiveProgressEventArgs e)
		{
			if (this.Progress != null)
			{
				this.Progress(this, e);
			}
		}

		protected virtual void Dispose(bool disposing)
		{
		}

		public static void DosDateAndTimeToDateTime(short dosDate, short dosTime, out DateTime dateTime)
		{
			if (dosDate == 0 && dosTime == 0)
			{
				dateTime = DateTime.MinValue;
				return;
			}
			SafeNativeMethods.DosDateTimeToFileTime(dosDate, dosTime, out var fileTime);
			dateTime = DateTime.FromFileTimeUtc(fileTime);
			dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Local);
		}

		public static void DateTimeToDosDateAndTime(DateTime dateTime, out short dosDate, out short dosTime)
		{
			dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc);
			long fileTime = dateTime.ToFileTimeUtc();
			SafeNativeMethods.FileTimeToDosDateTime(ref fileTime, out dosDate, out dosTime);
		}
	}
	public enum CompressionLevel
	{
		None = 0,
		Min = 1,
		Normal = 6,
		Max = 10
	}
	public class CargoStream : Stream
	{
		private Stream source;

		private List<IDisposable> cargo;

		public Stream Source => source;

		public IList<IDisposable> Cargo => cargo;

		public override bool CanRead => source.CanRead;

		public override bool CanWrite => source.CanWrite;

		public override bool CanSeek => source.CanSeek;

		public override long Length => source.Length;

		public override long Position
		{
			get
			{
				return source.Position;
			}
			set
			{
				source.Position = value;
			}
		}

		public CargoStream(Stream source, params IDisposable[] cargo)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			this.source = source;
			this.cargo = new List<IDisposable>(cargo);
		}

		public override void Flush()
		{
			source.Flush();
		}

		public override void SetLength(long value)
		{
			source.SetLength(value);
		}

		public override void Close()
		{
			source.Close();
			foreach (IDisposable item in cargo)
			{
				item.Dispose();
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			return source.Read(buffer, offset, count);
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			source.Write(buffer, offset, count);
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			return source.Seek(offset, origin);
		}
	}
	public class DuplicateStream : Stream
	{
		private Stream source;

		private long position;

		public Stream Source => source;

		public override bool CanRead => source.CanRead;

		public override bool CanWrite => source.CanWrite;

		public override bool CanSeek => source.CanSeek;

		public override long Length => source.Length;

		public override long Position
		{
			get
			{
				return position;
			}
			set
			{
				position = value;
			}
		}

		public DuplicateStream(Stream source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			this.source = OriginalStream(source);
		}

		public static Stream OriginalStream(Stream stream)
		{
			if (!(stream is DuplicateStream duplicateStream))
			{
				return stream;
			}
			return duplicateStream.Source;
		}

		public override void Flush()
		{
			source.Flush();
		}

		public override void SetLength(long value)
		{
			source.SetLength(value);
		}

		public override void Close()
		{
			source.Close();
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			long num = source.Position;
			source.Position = position;
			int result = source.Read(buffer, offset, count);
			position = source.Position;
			source.Position = num;
			return result;
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			long num = source.Position;
			source.Position = position;
			source.Write(buffer, offset, count);
			position = source.Position;
			source.Position = num;
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			long num = 0L;
			switch (origin)
			{
			case SeekOrigin.Current:
				num = position;
				break;
			case SeekOrigin.End:
				num = Length;
				break;
			}
			position = checked(num + offset);
			return position;
		}
	}
	public interface IPackStreamContext
	{
		string GetArchiveName(int archiveNumber);

		Stream OpenArchiveWriteStream(int archiveNumber, string archiveName, bool truncate, CompressionEngine compressionEngine);

		void CloseArchiveWriteStream(int archiveNumber, string archiveName, Stream stream);

		Stream OpenFileReadStream(string path, out FileAttributes attributes, out DateTime lastWriteTime);

		void CloseFileReadStream(string path, Stream stream);

		object GetOption(string optionName, object[] parameters);
	}
	public interface IUnpackStreamContext
	{
		Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine);

		void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream);

		Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime);

		void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime);
	}
	public class OffsetStream : Stream
	{
		private Stream source;

		private long sourceOffset;

		public Stream Source => source;

		public long Offset => sourceOffset;

		public override bool CanRead => source.CanRead;

		public override bool CanWrite => source.CanWrite;

		public override bool CanSeek => source.CanSeek;

		public override long Length => checked(source.Length - sourceOffset);

		public override long Position
		{
			get
			{
				return checked(source.Position - sourceOffset);
			}
			set
			{
				source.Position = checked(value + sourceOffset);
			}
		}

		public OffsetStream(Stream source, long offset)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			this.source = source;
			sourceOffset = offset;
			this.source.Seek(sourceOffset, SeekOrigin.Current);
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			return source.Read(buffer, offset, count);
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			source.Write(buffer, offset, count);
		}

		public override int ReadByte()
		{
			return source.ReadByte();
		}

		public override void WriteByte(byte value)
		{
			source.WriteByte(value);
		}

		public override void Flush()
		{
			source.Flush();
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			return checked(source.Seek(offset + ((origin == SeekOrigin.Begin) ? sourceOffset : 0), origin) - sourceOffset);
		}

		public override void SetLength(long value)
		{
			source.SetLength(checked(value + sourceOffset));
		}

		public override void Close()
		{
			source.Close();
		}
	}
	[SuppressUnmanagedCodeSecurity]
	internal static class SafeNativeMethods
	{
		[DllImport("kernel32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool DosDateTimeToFileTime(short wFatDate, short wFatTime, out long fileTime);

		[DllImport("kernel32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool FileTimeToDosDateTime(ref long fileTime, out short wFatDate, out short wFatTime);
	}
}