Decompiled source of ShaderHelperForMac v2.0.0

plugins/ShaderHelperForMac.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using AssetsTools.NET;
using AssetsTools.NET.Extra;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ShaderHelperForMac")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+dc76ebddf22ee462381df86da6106e4dcc2b673f")]
[assembly: AssemblyProduct("ShaderHelperForMac")]
[assembly: AssemblyTitle("ShaderHelperForMac")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ShaderHelperForMac
{
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class PatchZNetSceneAwake
	{
		private static void Postfix()
		{
			Plugin.Log.LogDebug((object)"[ZNetScene.Awake] Postfix — running post-ZNetScene sweep.");
			Plugin.TryUpgradeFallbackShader();
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.Instance.SweepMaterialsCoroutine());
			}
		}
	}
	[HarmonyPatch(typeof(DungeonGenerator), "GenerateDungeon")]
	internal static class PatchDungeonGeneratorGenerate
	{
		private static void Postfix()
		{
			Plugin.Log.LogDebug((object)"[DungeonGenerator.GenerateDungeon] Postfix — sweeping materials after dungeon generation.");
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.Instance.SweepMaterialsCoroutine());
			}
		}
	}
	[HarmonyPatch(typeof(VisEquipment), "AttachItem")]
	internal static class PatchVisEquipmentAttachItem
	{
		private static void Postfix()
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				Plugin.Instance.SweepMaterials();
			}
		}
	}
	[HarmonyPatch(typeof(AssetBundle), "LoadAsset", new Type[]
	{
		typeof(string),
		typeof(Type)
	})]
	internal static class PatchAssetBundleLoadAsset
	{
		private static void Postfix(Object __result)
		{
			if (!(__result == (Object)null))
			{
				Material val = (Material)(object)((__result is Material) ? __result : null);
				if (val != null)
				{
					Plugin.TryReplaceMaterialPublic(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Shader), "Find")]
	internal static class PatchShaderFind
	{
		private static void Postfix(ref Shader? __result)
		{
			if (!((Object)(object)__result == (Object)null) && (!__result.isSupported || ((Object)__result).name.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase)) && !Plugin.CanonicalShaderIds.Contains(((Object)__result).GetInstanceID()) && !ShaderScanner.IsLikelySafeShader(((Object)__result).name) && Plugin.ShouldReplace(((Object)__result).name))
			{
				Shader replacementShader = Plugin.GetReplacementShader(((Object)__result).name);
				if ((Object)(object)replacementShader != (Object)null)
				{
					__result = replacementShader;
				}
			}
		}
	}
	[DefaultExecutionOrder(30000)]
	internal class KeepRendererDisabled : MonoBehaviour
	{
		private Renderer? _renderer;

		private void Awake()
		{
			_renderer = ((Component)this).GetComponent<Renderer>();
		}

		private void LateUpdate()
		{
			if ((Object)(object)_renderer != (Object)null && _renderer.enabled)
			{
				_renderer.enabled = false;
			}
		}
	}
	[BepInPlugin("drummercraig.shaderhelperformac", "ShaderHelperForMac", "2.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private enum ShaderAction
		{
			Transparent,
			Fallback,
			Original
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass67_0
		{
			public string name;

			internal bool <InitAfterFrame>b__0(Shader sh)
			{
				if (((Object)sh).name == name)
				{
					return sh.isSupported;
				}
				return false;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass67_1
		{
			public string name;

			internal bool <InitAfterFrame>b__1(Shader sh)
			{
				return ((Object)sh).name == name;
			}
		}

		[CompilerGenerated]
		private sealed class <InitAfterFrame>d__67 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitAfterFrame>d__67(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_021a: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
					Log.LogDebug((object)$"Scanning {array.Length} loaded shader objects for a supported fallback.");
					string[] fallbackChain = FallbackChain;
					for (int i = 0; i < fallbackChain.Length; i++)
					{
						<>c__DisplayClass67_0 CS$<>8__locals0 = new <>c__DisplayClass67_0
						{
							name = fallbackChain[i]
						};
						Shader val = Shader.Find(CS$<>8__locals0.name) ?? ((IEnumerable<Shader>)array).FirstOrDefault((Func<Shader, bool>)((Shader sh) => ((Object)sh).name == CS$<>8__locals0.name && sh.isSupported));
						if ((Object)(object)val != (Object)null && val.isSupported)
						{
							FallbackShader = val;
							Log.LogDebug((object)$"Using fallback shader (supported): '{CS$<>8__locals0.name}'  id={((Object)FallbackShader).GetInstanceID()}");
							break;
						}
					}
					if ((Object)(object)FallbackShader == (Object)null)
					{
						fallbackChain = FallbackChain;
						for (int i = 0; i < fallbackChain.Length; i++)
						{
							<>c__DisplayClass67_1 CS$<>8__locals1 = new <>c__DisplayClass67_1
							{
								name = fallbackChain[i]
							};
							Shader val2 = Shader.Find(CS$<>8__locals1.name) ?? ((IEnumerable<Shader>)array).FirstOrDefault((Func<Shader, bool>)((Shader sh) => ((Object)sh).name == CS$<>8__locals1.name));
							if ((Object)(object)val2 != (Object)null)
							{
								FallbackShader = val2;
								Log.LogWarning((object)$"Using fallback shader (unsupported, last resort): '{CS$<>8__locals1.name}'  id={((Object)FallbackShader).GetInstanceID()}");
								break;
							}
						}
					}
					BuildTransparentMaterial();
					if ((Object)(object)FallbackShader == (Object)null)
					{
						Log.LogWarning((object)"No fallback shader found — transparent-only sweep running; will retry full init on next scene load.");
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					CollectCanonicalShaderIds();
					BuildReplacementMaterials();
					plugin._initialized = true;
					try
					{
						new Harmony("drummercraig.shaderhelperformac").PatchAll();
						Log.LogDebug((object)"Harmony patches installed.");
					}
					catch (Exception ex)
					{
						Log.LogError((object)("Harmony patching error (some patches may be missing): " + ex.Message));
					}
					plugin.RegisterCommands();
					<>2__current = null;
					<>1__state = 4;
					return true;
				}
				case 2:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)plugin).StartCoroutine(plugin.SweepMaterialsCoroutine());
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					return false;
				case 4:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)plugin).StartCoroutine(plugin.SweepMaterialsCoroutine());
					<>1__state = 5;
					return true;
				case 5:
					<>1__state = -1;
					((MonoBehaviour)plugin).StartCoroutine(plugin.PeriodicSweepCoroutine());
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PeriodicSweepCoroutine>d__68 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PeriodicSweepCoroutine>d__68(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Expected O, but got Unknown
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Expected O, but got Unknown
				int num = <>1__state;
				Plugin plugin = <>4__this;
				float periodicSweepInterval;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_002d;
				case 1:
					<>1__state = -1;
					goto IL_002d;
				case 2:
					<>1__state = -1;
					if (plugin._initialized && !((Object)(object)Player.m_localPlayer == (Object)null))
					{
						<>2__current = ((MonoBehaviour)plugin).StartCoroutine(plugin.SweepMaterialsCoroutine());
						<>1__state = 3;
						return true;
					}
					goto IL_002d;
				case 3:
					{
						<>1__state = -1;
						goto IL_002d;
					}
					IL_002d:
					periodicSweepInterval = PeriodicSweepInterval;
					if (periodicSweepInterval <= 0f)
					{
						<>2__current = (object)new WaitForSeconds(5f);
						<>1__state = 1;
						return true;
					}
					<>2__current = (object)new WaitForSeconds(periodicSweepInterval);
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SweepAfterFrame>d__69 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SweepAfterFrame>d__69(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)plugin).StartCoroutine(plugin.SweepMaterialsCoroutine());
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SweepAndNotifyCoroutine>d__91 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SweepAndNotifyCoroutine>d__91(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)plugin).StartCoroutine(plugin.SweepMaterialsCoroutine());
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					MessageHud instance = MessageHud.instance;
					if (instance != null)
					{
						instance.ShowMessage((MessageType)2, "Shader sweep complete", 0, (Sprite)null, false);
					}
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SweepMaterialsCoroutine>d__94 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private int <replaced>5__2;

			private Renderer[] <allRenderers>5__3;

			private Material[] <allMaterials>5__4;

			private int <ri>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SweepMaterialsCoroutine>d__94(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<allRenderers>5__3 = null;
				<allMaterials>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (plugin._sweepRunning)
					{
						return false;
					}
					if ((Object)(object)_transparentMat == (Object)null && (Object)(object)_fallbackMat == (Object)null)
					{
						return false;
					}
					plugin._sweepRunning = true;
					<replaced>5__2 = 0;
					<allRenderers>5__3 = Resources.FindObjectsOfTypeAll<Renderer>();
					<ri>5__5 = 0;
					goto IL_02d2;
				case 1:
					<>1__state = -1;
					goto IL_02c0;
				case 2:
					<>1__state = -1;
					goto IL_033a;
				case 3:
					{
						<>1__state = -1;
						goto IL_03da;
					}
					IL_034c:
					if (<ri>5__5 < <allMaterials>5__4.Length)
					{
						<replaced>5__2 += TryReplaceMaterial(<allMaterials>5__4[<ri>5__5]);
						if (<ri>5__5 % 100 == 0)
						{
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						goto IL_033a;
					}
					<ri>5__5 = 0;
					goto IL_03ec;
					IL_02c0:
					<ri>5__5++;
					goto IL_02d2;
					IL_033a:
					<ri>5__5++;
					goto IL_034c;
					IL_03ec:
					if (<ri>5__5 < <allRenderers>5__3.Length)
					{
						Renderer val = <allRenderers>5__3[<ri>5__5];
						if (!((Object)(object)val == (Object)null))
						{
							Material[] sharedMaterials = val.sharedMaterials;
							foreach (Material mat in sharedMaterials)
							{
								<replaced>5__2 += TryReplaceMaterial(mat);
							}
							if (<ri>5__5 % 100 == 0)
							{
								<>2__current = null;
								<>1__state = 3;
								return true;
							}
						}
						goto IL_03da;
					}
					if (<replaced>5__2 > 0)
					{
						Log.LogInfo((object)$"Replaced {<replaced>5__2} material(s).");
					}
					plugin._sweepRunning = false;
					return false;
					IL_02d2:
					if (<ri>5__5 < <allRenderers>5__3.Length)
					{
						Renderer val2 = <allRenderers>5__3[<ri>5__5];
						if (!((Object)(object)val2 == (Object)null))
						{
							bool flag = false;
							bool flag2 = false;
							Material[] sharedMaterials = val2.sharedMaterials;
							foreach (Material val3 in sharedMaterials)
							{
								if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.shader == (Object)null) && !((Object)(object)val3 == (Object)(object)_transparentMat) && !((Object)(object)val3 == (Object)(object)_fallbackMat))
								{
									if (_forceReplacedMaterialIds.Contains(((Object)val3).GetInstanceID()))
									{
										flag2 = true;
										break;
									}
									if ((NeedsReplacement(val3) || IsExplicitMatRule(val3)) && GetAction(val3) != ShaderAction.Original)
									{
										flag = true;
										break;
									}
								}
							}
							if (flag2 && val2 is ParticleSystemRenderer && val2.enabled)
							{
								val2.enabled = false;
								if ((Object)(object)((Component)val2).gameObject.GetComponent<KeepRendererDisabled>() == (Object)null)
								{
									((Component)val2).gameObject.AddComponent<KeepRendererDisabled>();
								}
								Log.LogDebug((object)("[RendererDisable] '" + ((Object)((Component)val2).gameObject).name + "' — ParticleSystemRenderer disabled (shared mat was force-replaced)."));
							}
							else if (flag)
							{
								Material[] materials = val2.materials;
								bool flag3 = false;
								bool flag4 = true;
								for (int j = 0; j < materials.Length; j++)
								{
									if (!((Object)(object)materials[j] == (Object)null) && !((Object)(object)materials[j].shader == (Object)null) && NeedsReplacement(materials[j]))
									{
										if (GetAction(materials[j]) != 0)
										{
											flag4 = false;
										}
										if (TryReplaceMaterial(materials[j]) > 0)
										{
											flag3 = true;
											<replaced>5__2++;
										}
									}
								}
								if (flag3)
								{
									val2.materials = materials;
									if (flag4 && val2 is ParticleSystemRenderer)
									{
										val2.enabled = false;
										if ((Object)(object)((Component)val2).gameObject.GetComponent<KeepRendererDisabled>() == (Object)null)
										{
											((Component)val2).gameObject.AddComponent<KeepRendererDisabled>();
										}
										Log.LogDebug((object)("[InstanceFix] '" + ((Object)((Component)val2).gameObject).name + "' — disabled ParticleSystemRenderer (force-transparent)."));
									}
									else
									{
										Log.LogDebug((object)$"[InstanceFix] '{((Object)((Component)val2).gameObject).name}' — {materials.Length} instance mat(s) updated.");
									}
								}
							}
							if (<ri>5__5 % 100 == 0)
							{
								<>2__current = null;
								<>1__state = 1;
								return true;
							}
						}
						goto IL_02c0;
					}
					<allMaterials>5__4 = Resources.FindObjectsOfTypeAll<Material>();
					<ri>5__5 = 0;
					goto IL_034c;
					IL_03da:
					<ri>5__5++;
					goto IL_03ec;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "drummercraig.shaderhelperformac";

		public const string PluginName = "ShaderHelperForMac";

		public const string PluginVersion = "2.0.0";

		private static readonly string UseTransparentShaderFile = "usetransparentshader.txt";

		private static readonly string UseFallbackShaderFile = "usefallbackshader.txt";

		private static readonly string UseOriginalShaderFile = "useoriginalshader.txt";

		private static HashSet<string> _useTransparentDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _useFallbackDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _useOriginalDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _transparentMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _fallbackMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _originalMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static List<string> _transparentMatSuffixes = new List<string>();

		private static List<string> _fallbackMatSuffixes = new List<string>();

		private static HashSet<string> _forceFallbackPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _forceTransparentPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> _builtInFallbackPrefixes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> _builtInTransparentPrefixes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private FileSystemWatcher? _watcher;

		private ConfigEntry<bool> _cfgDefaultAllTransparent;

		private ConfigEntry<string> _cfgForceTransparentPrefixes;

		private ConfigEntry<string> _cfgForceFallbackPrefixes;

		private ConfigEntry<float> _cfgPeriodicSweepInterval;

		private static Plugin? _instance;

		internal static readonly Dictionary<string, string> ModShaderDlls = new Dictionary<string, string>();

		private static readonly string[] FallbackChain = new string[3] { "Custom/Creature", "Custom/Piece", "Custom/Vegetation" };

		internal static readonly HashSet<int> CanonicalShaderIds = new HashSet<int>();

		private static readonly HashSet<int> _forceReplacedMaterialIds = new HashSet<int>();

		private static readonly Dictionary<int, (string originalShader, ShaderAction action)> _replacedMats = new Dictionary<int, (string, ShaderAction)>();

		private static readonly HashSet<string> _baselineMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly string[] ValheimShaderNames = new string[52]
		{
			"Custom/Piece", "Custom/Creature", "Custom/Vegetation", "Custom/StaticRock", "Custom/Lit", "Custom/LitParticles", "Custom/FlowOpaque", "Custom/Billboard", "Custom/DistantLod", "Custom/WaterLily",
			"Custom/Trilinear", "Custom/Decal", "Custom/Cliff", "Custom/Skybox", "Custom/Distortion", "Custom/Player", "Custom/Blob", "Custom/Bonemass", "Custom/Grass", "Custom/Heightmap",
			"Custom/Rug", "Custom/ShadowBlob", "Custom/Tar", "Custom/Trilinearmap", "Custom/Yggdrasil", "Custom/Yggdrasil_root", "Custom/Water", "Custom/WaterBottom", "Custom/WaterMask", "Custom/Clouds",
			"Custom/Flow", "Custom/SkyboxProcedural", "Custom/SkyObject", "Custom/icon", "Custom/LitGui", "Custom/mapshader", "Custom/UI/AntiAliasedCircle", "Custom/UI_BGBlur", "Custom/AlphaParticle", "Custom/Gradient Mapped Particle (Unlit)",
			"Custom/Mesh Flipbook Particle", "Custom/Particle (Unlit)", "Custom/ParticleDecal", "FX/Glass/Stained BumpDistort", "FX/Glass/Stained", "Unlit/Lighting", "ToonDeferredShading", "ToonDeferredShading2017", "Earthquake/Tree", "Earthquake/Leaf",
			"Hovl/Particles/Additive", "Hovl/Particles/AlphaBlend"
		};

		private static readonly HashSet<string> ValheimShaderNameSet = new HashSet<string>(ValheimShaderNames, StringComparer.OrdinalIgnoreCase);

		private static Material? _transparentMat;

		private static Material? _fallbackMat;

		private bool _initialized;

		private bool _sweepRunning;

		private const int SweepBatchSize = 100;

		internal static ManualLogSource Log { get; private set; } = null;


		internal static Plugin Instance { get; private set; } = null;


		private static string ConfigDir => Path.Combine(Paths.ConfigPath, "ShaderHelperForMac");

		internal static bool DefaultAllTransparent => _instance?._cfgDefaultAllTransparent.Value ?? true;

		internal static string ForceTransparentPrefixes => _instance?._cfgForceTransparentPrefixes.Value ?? string.Empty;

		internal static string ForceFallbackPrefixes => _instance?._cfgForceFallbackPrefixes.Value ?? string.Empty;

		internal static float PeriodicSweepInterval => _instance?._cfgPeriodicSweepInterval.Value ?? 30f;

		internal static Shader? FallbackShader { get; private set; }

		private void Awake()
		{
			Instance = this;
			_instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_cfgDefaultAllTransparent = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Default All Transparent", false, "When true, all unsupported shaders are made transparent automatically. Add DLL names to useoriginalshader.txt to skip specific mods. When false, shaders are left as-is (pink) unless the DLL is listed in usetransparentshader.txt or usefallbackshader.txt.");
			_cfgForceTransparentPrefixes = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Force Transparent Shader Prefixes", "", "Comma-separated list of shader name prefixes that are always made transparent, regardless of the Default All Transparent setting. Clear this value to disable all forced replacements.");
			_cfgForceFallbackPrefixes = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Force Fallback Shader Prefixes", "", "Comma-separated list of shader name prefixes that always use the fallback shader, even if Unity reports the shader as supported on Metal. Use this for mod shaders that render pink despite isSupported=true (e.g. Dreanegade/).");
			_cfgPeriodicSweepInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Periodic Sweep Interval", 30f, "How often (in seconds) to re-sweep all materials after the initial load. Catches shaders on objects that spawn dynamically (VFX, status effects, etc.). Set to 0 to disable the periodic sweep.");
			Log.LogDebug((object)$"[Config] DefaultAllTransparent = {_cfgDefaultAllTransparent.Value}");
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string item = StripInstance(((Object)val).name);
					_baselineMatNames.Add(item);
				}
			}
			Log.LogDebug((object)$"Baseline materials captured: {_baselineMatNames.Count}");
			int num = ShaderScanner.ScanPlugins(Paths.PluginPath, ModShaderDlls, Log);
			Log.LogDebug((object)$"Scanned plugins: {num} mod shader(s) recorded across {ModShaderDlls.Values.Distinct().Count()} DLL(s).");
			foreach (string item2 in ModShaderDlls.Values.Distinct())
			{
				Log.LogDebug((object)("  Shaders found in: '" + item2 + "'"));
			}
			EnsureConfigFiles();
			ReloadConfigFiles();
			StartConfigWatcher();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			_watcher?.Dispose();
		}

		private static void EnsureConfigFiles()
		{
			Directory.CreateDirectory(ConfigDir);
			string path = Path.Combine(ConfigDir, UseTransparentShaderFile);
			if (!File.Exists(path))
			{
				File.WriteAllText(path, "# Materials made transparent (invisible) by ShaderHelperForMac.\n# Three line formats (all case-insensitive, one per line):\n#\n#   DllName              — all unsupported materials from this mod DLL\n#   mat:MaterialName     — one specific material by exact name\n#   suffix:TW            — all materials whose name ends with this suffix\n#\n# Examples:\n# mat:smoke_TW\n# suffix:_vfx\n# DarkWoodFurnitures\n#\n");
			}
			string path2 = Path.Combine(ConfigDir, UseFallbackShaderFile);
			if (!File.Exists(path2))
			{
				File.WriteAllText(path2, "# Materials given the fallback shader by ShaderHelperForMac.\n# Three line formats (all case-insensitive, one per line):\n#\n#   DllName              — all unsupported materials from this mod DLL\n#   mat:MaterialName     — one specific material by exact name\n#   suffix:TW            — all materials whose name ends with this suffix\n#\n# Examples:\n# suffix:TW\n# mat:rocksTW\n# Warfare\n#\n");
			}
			string path3 = Path.Combine(ConfigDir, UseOriginalShaderFile);
			if (!File.Exists(path3))
			{
				File.WriteAllText(path3, "# Mods listed here will be left completely untouched (shaders not changed).\n# Use when DefaultAllTransparent=true but you want a specific mod left as-is.\n#\n# One DLL name per line (without the .dll extension), case-insensitive.\n# Lines starting with # are comments.\n#\n");
			}
		}

		private static void ParseRuleLine(string line, HashSet<string> dlls, HashSet<string> matNames, List<string> matSuffixes)
		{
			int num = line.IndexOf(" #", StringComparison.Ordinal);
			if (num >= 0)
			{
				line = line.Substring(0, num).TrimEnd(Array.Empty<char>());
			}
			if (line.Length != 0)
			{
				if (line.StartsWith("mat:", StringComparison.OrdinalIgnoreCase))
				{
					matNames.Add(line.Substring(4).Trim());
				}
				else if (line.StartsWith("suffix:", StringComparison.OrdinalIgnoreCase))
				{
					matSuffixes.Add(line.Substring(7).Trim());
				}
				else
				{
					dlls.Add(line);
				}
			}
		}

		private static void LoadConfigFile(string filename, HashSet<string> dlls, HashSet<string> matNames, List<string> matSuffixes)
		{
			string path = Path.Combine(ConfigDir, filename);
			if (!File.Exists(path))
			{
				return;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0 && !text.StartsWith("#"))
				{
					ParseRuleLine(text, dlls, matNames, matSuffixes);
				}
			}
		}

		private static void LoadModFile(string filePath)
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
			string text = string.Empty;
			string[] array = File.ReadAllLines(filePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2).ToLowerInvariant();
					continue;
				}
				switch (text)
				{
				case "default":
					if (text2.Equals("fallback", StringComparison.OrdinalIgnoreCase))
					{
						_useFallbackDlls.Add(fileNameWithoutExtension);
					}
					else if (text2.Equals("transparent", StringComparison.OrdinalIgnoreCase))
					{
						_useTransparentDlls.Add(fileNameWithoutExtension);
					}
					else if (text2.Equals("original", StringComparison.OrdinalIgnoreCase))
					{
						_useOriginalDlls.Add(fileNameWithoutExtension);
					}
					break;
				case "fallback":
					ParseRuleLine(text2, _useFallbackDlls, _fallbackMatNames, _fallbackMatSuffixes);
					break;
				case "transparent":
					ParseRuleLine(text2, _useTransparentDlls, _transparentMatNames, _transparentMatSuffixes);
					break;
				case "original":
					if (text2.StartsWith("mat:", StringComparison.OrdinalIgnoreCase))
					{
						_originalMatNames.Add(text2.Substring(4).Trim());
					}
					else if (!text2.StartsWith("suffix:", StringComparison.OrdinalIgnoreCase))
					{
						_useOriginalDlls.Add(text2);
					}
					break;
				case "forcefallback":
					_forceFallbackPrefixSet.Add(text2);
					break;
				case "forcetransparent":
					_forceTransparentPrefixSet.Add(text2);
					break;
				}
			}
		}

		private static void ReloadConfigFiles()
		{
			_useTransparentDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_useFallbackDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_useOriginalDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_transparentMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_fallbackMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_originalMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_transparentMatSuffixes = new List<string>();
			_fallbackMatSuffixes = new List<string>();
			_forceFallbackPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_forceTransparentPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			_builtInFallbackPrefixes.Clear();
			_builtInTransparentPrefixes.Clear();
			_builtInTransparentPrefixes.Add("Legacy Shaders/Particles/");
			_forceTransparentPrefixSet.Add("Legacy Shaders/Particles/");
			string[] array = ForceFallbackPrefixes.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					_forceFallbackPrefixSet.Add(text);
				}
			}
			array = ForceTransparentPrefixes.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					_forceTransparentPrefixSet.Add(text2);
				}
			}
			LoadConfigFile(UseTransparentShaderFile, _useTransparentDlls, _transparentMatNames, _transparentMatSuffixes);
			LoadConfigFile(UseFallbackShaderFile, _useFallbackDlls, _fallbackMatNames, _fallbackMatSuffixes);
			HashSet<string> matNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			List<string> matSuffixes = new List<string>();
			LoadConfigFile(UseOriginalShaderFile, _useOriginalDlls, matNames, matSuffixes);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { UseTransparentShaderFile, UseFallbackShaderFile, UseOriginalShaderFile };
			array = Directory.GetFiles(ConfigDir, "*.txt");
			foreach (string text3 in array)
			{
				if (!hashSet.Contains(Path.GetFileName(text3)))
				{
					LoadModFile(text3);
				}
			}
			Log.LogDebug((object)($"Config loaded: {_useTransparentDlls.Count} transparent, {_useFallbackDlls.Count} fallback, {_useOriginalDlls.Count} original DLL(s); " + $"{_transparentMatNames.Count + _transparentMatSuffixes.Count} transparent mat rule(s), " + $"{_fallbackMatNames.Count + _fallbackMatSuffixes.Count} fallback mat rule(s); " + $"{_forceFallbackPrefixSet.Count} force-fallback prefix(es), {_forceTransparentPrefixSet.Count} force-transparent prefix(es)."));
		}

		private void StartConfigWatcher()
		{
			try
			{
				_watcher = new FileSystemWatcher(ConfigDir, "*.txt")
				{
					NotifyFilter = NotifyFilters.LastWrite,
					EnableRaisingEvents = true
				};
				_watcher.Changed += delegate
				{
					ReloadConfigFiles();
				};
			}
			catch
			{
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (!_initialized)
			{
				((MonoBehaviour)this).StartCoroutine(InitAfterFrame());
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(SweepAfterFrame());
			}
		}

		[IteratorStateMachine(typeof(<InitAfterFrame>d__67))]
		private IEnumerator InitAfterFrame()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitAfterFrame>d__67(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<PeriodicSweepCoroutine>d__68))]
		private IEnumerator PeriodicSweepCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PeriodicSweepCoroutine>d__68(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<SweepAfterFrame>d__69))]
		private IEnumerator SweepAfterFrame()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SweepAfterFrame>d__69(0)
			{
				<>4__this = this
			};
		}

		private void RegisterCommands()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand("shaderhelper", "[sweep|scan|pink|status]  ShaderHelperForMac — manually trigger a material sweep, scan a mod's shaders, find unhandled pink materials, or show status.", (ConsoleEvent)delegate(ConsoleEventArgs args)
			{
				//IL_0a76: Unknown result type (might be due to invalid IL or missing references)
				//IL_0a82: Unknown result type (might be due to invalid IL or missing references)
				//IL_0d03: Unknown result type (might be due to invalid IL or missing references)
				//IL_0d0f: Unknown result type (might be due to invalid IL or missing references)
				//IL_1378: Unknown result type (might be due to invalid IL or missing references)
				//IL_0e51: Unknown result type (might be due to invalid IL or missing references)
				//IL_0e56: Unknown result type (might be due to invalid IL or missing references)
				//IL_0c0d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0c12: Unknown result type (might be due to invalid IL or missing references)
				string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "help");
				switch (text)
				{
				case "reload":
					ReloadConfigFiles();
					args.Context.AddString("ShaderHelperForMac: config reloaded.");
					break;
				case "sweep":
					if (!_initialized)
					{
						args.Context.AddString("ShaderHelperForMac: not yet initialized — enter a world first.");
					}
					else
					{
						ReloadConfigFiles();
						args.Context.AddString("ShaderHelperForMac: running sweep...");
						SweepMaterialsWithNotify();
					}
					break;
				case "dumpmod":
				{
					string dumpTarget = ((args.Length > 2) ? args[2] : string.Empty);
					if (string.IsNullOrEmpty(dumpTarget))
					{
						args.Context.AddString("Usage: shaderhelper dumpmod <DllName>");
					}
					else
					{
						List<string> list6 = (from kv in ModShaderDlls
							where kv.Value.Equals(dumpTarget, StringComparison.OrdinalIgnoreCase)
							select kv.Key into n
							orderby n
							select n).ToList();
						args.Context.AddString($"ShaderHelperForMac: {list6.Count} shader(s) recorded for '{dumpTarget}':");
						foreach (string item15 in list6)
						{
							Log.LogInfo((object)("[DumpMod] '" + item15 + "'"));
						}
						args.Context.AddString("See BepInEx/LogOutput.log for the full list.");
					}
					break;
				}
				case "scan":
				{
					string text22 = ((args.Length > 2) ? args[2] : string.Empty);
					if (string.IsNullOrEmpty(text22))
					{
						args.Context.AddString("Usage: shaderhelper scan <DllName>");
					}
					else
					{
						int num14 = 0;
						Material[] array = Resources.FindObjectsOfTypeAll<Material>();
						foreach (Material val17 in array)
						{
							if (!((Object)(object)val17 == (Object)null) && !((Object)(object)val17.shader == (Object)null) && ModShaderDlls.TryGetValue(((Object)val17.shader).name, out string value20) && value20.Equals(text22, StringComparison.OrdinalIgnoreCase))
							{
								Log.LogInfo((object)$"[Scan] mat='{((Object)val17).name}'  shader='{((Object)val17.shader).name}'  supported={val17.shader.isSupported}");
								num14++;
							}
						}
						args.Context.AddString($"ShaderHelperForMac: found {num14} material(s) from '{text22}'. Check BepInEx/LogOutput.log for details.");
					}
					break;
				}
				case "pink":
				{
					int num6 = 0;
					HashSet<string> hashSet3 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
					Material[] array = Resources.FindObjectsOfTypeAll<Material>();
					foreach (Material val10 in array)
					{
						if (!((Object)(object)val10 == (Object)null) && !((Object)(object)val10.shader == (Object)null) && !((Object)(object)val10 == (Object)(object)_transparentMat) && NeedsReplacement(val10) && GetAction(val10) == ShaderAction.Original)
						{
							string text15 = StripInstance(((Object)val10).name);
							if (hashSet3.Add(text15))
							{
								ModShaderDlls.TryGetValue(((Object)val10.shader).name, out string value14);
								Log.LogInfo((object)string.Format("[Pink] mat='{0}'  shader='{1}'  supported={2}  dll='{3}'", text15, ((Object)val10.shader).name, val10.shader.isSupported, value14 ?? "unknown"));
								num6++;
							}
						}
					}
					args.Context.AddString($"ShaderHelperForMac: found {num6} unhandled pink material(s). Check BepInEx/LogOutput.log for details.");
					break;
				}
				case "shaders":
				{
					int num13 = 0;
					Shader[] array5 = Resources.FindObjectsOfTypeAll<Shader>();
					foreach (Shader val16 in array5)
					{
						if (!((Object)(object)val16 == (Object)null) && (!((Object)val16).name.StartsWith("Hidden/") || ((Object)val16).name.Contains("InternalError")) && !((Object)val16).name.StartsWith("GUI/") && !((Object)val16).name.StartsWith("UI/"))
						{
							ModShaderDlls.TryGetValue(((Object)val16).name, out string value19);
							bool flag12 = ValheimShaderNameSet.Contains(((Object)val16).name);
							Log.LogInfo((object)string.Format("[Shader] name='{0}'  supported={1}  dll='{2}'  valheim={3}", ((Object)val16).name, val16.isSupported, value19 ?? "unknown", flag12));
							num13++;
						}
					}
					args.Context.AddString($"ShaderHelperForMac: dumped {num13} shader(s). Check BepInEx/LogOutput.log.");
					break;
				}
				case "renderers":
				{
					int num5 = 0;
					Renderer[] array2 = Resources.FindObjectsOfTypeAll<Renderer>();
					foreach (Renderer val8 in array2)
					{
						if (!((Object)(object)val8 == (Object)null))
						{
							Material[] array = val8.sharedMaterials;
							foreach (Material val9 in array)
							{
								if (!((Object)(object)val9 == (Object)null) && !((Object)(object)val9.shader == (Object)null) && !(((Object)val9.shader).name == "Standard") && !(((Object)val9.shader).name == "Sprites/Default"))
								{
									ModShaderDlls.TryGetValue(((Object)val9.shader).name, out string value13);
									ShaderAction action = GetAction(val9);
									Log.LogInfo((object)string.Format("[Rend] go='{0}'  mat='{1}'  shader='{2}'  supported={3}  action={4}  dll='{5}'", ((Object)((Component)val8).gameObject).name, ((Object)val9).name, ((Object)val9.shader).name, val9.shader.isSupported, action, value13 ?? "unknown"));
									num5++;
								}
							}
						}
					}
					args.Context.AddString($"ShaderHelperForMac: found {num5} renderer material(s). Check BepInEx/LogOutput.log.");
					break;
				}
				case "all":
				{
					int num7 = 0;
					Material[] array = Resources.FindObjectsOfTypeAll<Material>();
					foreach (Material val11 in array)
					{
						if (!((Object)(object)val11 == (Object)null) && !((Object)(object)val11.shader == (Object)null) && !((Object)(object)val11 == (Object)(object)_transparentMat) && !((Object)(object)val11 == (Object)(object)_fallbackMat) && !(((Object)val11.shader).name == "Standard") && !(((Object)val11.shader).name == "Sprites/Default") && !ShaderScanner.IsLikelySafeShader(((Object)val11.shader).name))
						{
							ModShaderDlls.TryGetValue(((Object)val11.shader).name, out string value15);
							ShaderAction action2 = GetAction(val11);
							Log.LogInfo((object)string.Format("[All] mat='{0}'  shader='{1}'  supported={2}  action={3}  dll='{4}'", ((Object)val11).name, ((Object)val11.shader).name, val11.shader.isSupported, action2, value15 ?? "unknown"));
							num7++;
						}
					}
					args.Context.AddString($"ShaderHelperForMac: dumped {num7} material(s). Check BepInEx/LogOutput.log for details.");
					break;
				}
				case "nearby":
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						args.Context.AddString("ShaderHelperForMac: no local player found.");
					}
					else
					{
						float num9 = 30f;
						bool flag9 = false;
						string nbDllFilter = string.Empty;
						for (int k = 2; k < args.Length; k++)
						{
							float result;
							if (args[k].Equals("mod", StringComparison.OrdinalIgnoreCase))
							{
								flag9 = true;
							}
							else if (float.TryParse(args[k], out result))
							{
								num9 = result;
							}
							else
							{
								nbDllFilter = args[k];
							}
						}
						if (!string.IsNullOrEmpty(nbDllFilter))
						{
							string text17 = ModShaderDlls.Values.FirstOrDefault((string d) => d.Equals(nbDllFilter, StringComparison.OrdinalIgnoreCase));
							if (text17 != null)
							{
								nbDllFilter = text17;
							}
							else
							{
								flag9 = true;
								args.Context.AddString("ShaderHelperForMac: '" + nbDllFilter + "' not in scan results (large embedded bundle) — applying mod filter to exclude vanilla materials.");
							}
						}
						Renderer[] array3 = Resources.FindObjectsOfTypeAll<Renderer>();
						int num10 = 0;
						Renderer[] array2 = array3;
						Color color;
						foreach (Renderer val13 in array2)
						{
							if (!((Object)(object)val13 == (Object)null))
							{
								float num11 = Vector3.Distance(((Component)val13).transform.position, ((Component)localPlayer).transform.position);
								if (!(num11 > num9))
								{
									string name = ((object)val13).GetType().Name;
									Transform parent = ((Component)val13).transform.parent;
									string text18 = ((parent != null) ? ((Object)parent).name : null) ?? "(root)";
									Material[] array = val13.sharedMaterials;
									foreach (Material val14 in array)
									{
										if (!((Object)(object)val14 == (Object)null) && !((Object)(object)val14.shader == (Object)null))
										{
											ModShaderDlls.TryGetValue(((Object)val14.shader).name, out string value17);
											if (!string.IsNullOrEmpty(nbDllFilter))
											{
												bool flag10 = value17 != null;
												if ((flag10 && !value17.Equals(nbDllFilter, StringComparison.OrdinalIgnoreCase)) || (!flag10 && ModShaderDlls.Values.Any((string d) => d.Equals(nbDllFilter, StringComparison.OrdinalIgnoreCase))))
												{
													continue;
												}
											}
											if (!flag9 || (!CanonicalShaderIds.Contains(((Object)val14.shader).GetInstanceID()) && !ValheimShaderNameSet.Contains(((Object)val14.shader).name) && !ShaderScanner.IsLikelySafeShader(((Object)val14.shader).name) && !((Object)val14.shader).name.StartsWith("Lux Lit Particles/", StringComparison.OrdinalIgnoreCase)))
											{
												ShaderAction action4 = GetAction(val14);
												object obj;
												if (!val14.HasProperty("_Color"))
												{
													obj = "n/a";
												}
												else
												{
													color = val14.color;
													obj = ((object)(Color)(ref color)).ToString();
												}
												string text19 = (string)obj;
												Log.LogInfo((object)string.Format("[Near] dist={0:F1}  type={1}  parent='{2}'  go='{3}'  mat:{4}  shader='{5}'  supported={6}  action={7}  color={8}  dll='{9}'", num11, name, text18, ((Object)((Component)val13).gameObject).name, StripInstance(((Object)val14).name), ((Object)val14.shader).name, val14.shader.isSupported, action4, text19, value17 ?? "unknown"));
												num10++;
											}
										}
									}
								}
							}
						}
						CanvasRenderer[] array4 = Resources.FindObjectsOfTypeAll<CanvasRenderer>();
						foreach (CanvasRenderer val15 in array4)
						{
							if (!((Object)(object)val15 == (Object)null))
							{
								float num12 = Vector3.Distance(((Component)val15).transform.position, ((Component)localPlayer).transform.position);
								if (!(num12 > num9))
								{
									int materialCount = val15.materialCount;
									for (int l = 0; l < materialCount; l++)
									{
										Material material = val15.GetMaterial(l);
										if (!((Object)(object)material == (Object)null) && !((Object)(object)material.shader == (Object)null))
										{
											ModShaderDlls.TryGetValue(((Object)material.shader).name, out string value18);
											if (!string.IsNullOrEmpty(nbDllFilter))
											{
												bool flag11 = value18 != null;
												if ((flag11 && !value18.Equals(nbDllFilter, StringComparison.OrdinalIgnoreCase)) || (!flag11 && ModShaderDlls.Values.Any((string d) => d.Equals(nbDllFilter, StringComparison.OrdinalIgnoreCase))))
												{
													continue;
												}
											}
											if (!flag9 || (!CanonicalShaderIds.Contains(((Object)material.shader).GetInstanceID()) && !ValheimShaderNameSet.Contains(((Object)material.shader).name) && !ShaderScanner.IsLikelySafeShader(((Object)material.shader).name)))
											{
												ShaderAction action5 = GetAction(material);
												object obj2;
												if (!material.HasProperty("_Color"))
												{
													obj2 = "n/a";
												}
												else
												{
													color = material.color;
													obj2 = ((object)(Color)(ref color)).ToString();
												}
												string text20 = (string)obj2;
												Transform parent2 = ((Component)val15).transform.parent;
												string text21 = ((parent2 != null) ? ((Object)parent2).name : null) ?? "(root)";
												Log.LogInfo((object)string.Format("[Near] dist={0:F1}  type=CanvasRenderer  parent='{1}'  go='{2}'  mat:{3}  shader='{4}'  supported={5}  action={6}  color={7}  dll='{8}'", num12, text21, ((Object)((Component)val15).gameObject).name, StripInstance(((Object)material).name), ((Object)material.shader).name, material.shader.isSupported, action5, text20, value18 ?? "unknown"));
												num10++;
											}
										}
									}
								}
							}
						}
						string arg2 = ((!string.IsNullOrEmpty(nbDllFilter)) ? (" from '" + nbDllFilter + "'") : (flag9 ? " (mod filter)" : string.Empty));
						args.Context.AddString($"ShaderHelperForMac: found {num10} materials within {num9} units{arg2}. Check BepInEx/LogOutput.log.");
					}
					break;
				}
				case "transparent":
				{
					string trFilter = ((args.Length > 2) ? args[2] : string.Empty);
					if (string.IsNullOrEmpty(trFilter))
					{
						args.Context.AddString("Usage: shaderhelper transparent <DllName>");
					}
					else
					{
						string text12 = ModShaderDlls.Values.FirstOrDefault((string d) => d.Equals(trFilter, StringComparison.OrdinalIgnoreCase));
						bool flag6 = text12 == null;
						if (flag6)
						{
							text12 = trFilter;
							args.Context.AddString("ShaderHelperForMac: '" + trFilter + "' not in scan results (large embedded bundle?) — showing all transparent materials with dll='unknown'.");
						}
						HashSet<string> hashSet2 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
						int num4 = 0;
						Material[] array = Resources.FindObjectsOfTypeAll<Material>();
						foreach (Material val7 in array)
						{
							if (!((Object)(object)val7 == (Object)null) && !((Object)(object)val7.shader == (Object)null) && !((Object)(object)val7 == (Object)(object)_transparentMat) && !((Object)(object)val7 == (Object)(object)_fallbackMat))
							{
								ModShaderDlls.TryGetValue(((Object)val7.shader).name, out string value12);
								if (flag6)
								{
									if (value12 != null)
									{
										continue;
									}
								}
								else if (!text12.Equals(value12, StringComparison.OrdinalIgnoreCase))
								{
									continue;
								}
								bool flag7 = _forceReplacedMaterialIds.Contains(((Object)val7).GetInstanceID());
								if (flag7 || (NeedsReplacement(val7) && GetAction(val7) == ShaderAction.Transparent))
								{
									string text13 = StripInstance(((Object)val7).name);
									if (hashSet2.Add(text13))
									{
										string text14 = (flag7 ? "replaced" : "pending");
										Log.LogInfo((object)("[Trans] state=" + text14 + "  mat='" + text13 + "'  shader='" + ((Object)val7.shader).name + "'  dll='" + (value12 ?? "unknown") + "'"));
										num4++;
									}
								}
							}
						}
						args.Context.AddString($"ShaderHelperForMac: {num4} transparent material(s) from '{text12}'. Add mat: rules to [fallback] to make them visible.");
						args.Context.AddString("Check BepInEx/LogOutput.log for material names.");
					}
					break;
				}
				case "loaded":
				{
					string ldFilter = ((args.Length > 2) ? args[2] : string.Empty);
					bool flag8 = !string.IsNullOrEmpty(ldFilter);
					string text16 = (flag8 ? ModShaderDlls.Values.FirstOrDefault((string d) => d.Equals(ldFilter, StringComparison.OrdinalIgnoreCase)) : null);
					if (flag8 && text16 == null)
					{
						args.Context.AddString("ShaderHelperForMac: '" + ldFilter + "' not in scan results (large embedded bundle?) — showing all materials with dll='unknown'.");
					}
					int num8 = 0;
					Material[] array = Resources.FindObjectsOfTypeAll<Material>();
					foreach (Material val12 in array)
					{
						if (!((Object)(object)val12 == (Object)null) && !((Object)(object)val12.shader == (Object)null) && !((Object)(object)val12 == (Object)(object)_transparentMat) && !((Object)(object)val12 == (Object)(object)_fallbackMat))
						{
							ModShaderDlls.TryGetValue(((Object)val12.shader).name, out string value16);
							if (flag8)
							{
								if (text16 != null)
								{
									if (!text16.Equals(value16, StringComparison.OrdinalIgnoreCase))
									{
										continue;
									}
								}
								else if (value16 != null)
								{
									continue;
								}
							}
							if (((Object)val12.shader).name.Equals("Standard", StringComparison.OrdinalIgnoreCase))
							{
								string item14 = StripInstance(((Object)val12).name);
								if (!_baselineMatNames.Contains(item14))
								{
									ShaderAction action3 = GetAction(val12);
									if (action3 == ShaderAction.Original)
									{
										Log.LogInfo((object)string.Format("[Loaded] mat='{0}'  shader='{1}'  supported={2}  action={3}  color={4}  dll='{5}'", ((Object)val12).name, ((Object)val12.shader).name, val12.shader.isSupported, action3, val12.color, value16 ?? "unknown"));
										num8++;
									}
								}
							}
						}
					}
					string arg = (flag8 ? (" from '" + ldFilter + "'") : string.Empty);
					args.Context.AddString($"ShaderHelperForMac: logged {num8} unhandled material(s){arg}. Check BepInEx/LogOutput.log.");
					break;
				}
				case "status":
				{
					args.Context.AddString("ShaderHelperForMac v2.0.0");
					args.Context.AddString($"  DefaultAllTransparent:  {DefaultAllTransparent}");
					Terminal context = args.Context;
					Shader? fallbackShader = FallbackShader;
					context.AddString("  Fallback shader:        " + (((fallbackShader != null) ? ((Object)fallbackShader).name : null) ?? "none"));
					args.Context.AddString($"  Canonical IDs:          {CanonicalShaderIds.Count}");
					args.Context.AddString($"  Transparent DLLs:       {_useTransparentDlls.Count}");
					args.Context.AddString($"  Fallback DLLs:          {_useFallbackDlls.Count}");
					args.Context.AddString($"  Original DLLs:          {_useOriginalDlls.Count}");
					args.Context.AddString($"  Transparent mat rules:  {_transparentMatNames.Count} name(s), {_transparentMatSuffixes.Count} suffix(es)");
					args.Context.AddString($"  Fallback mat rules:     {_fallbackMatNames.Count} name(s), {_fallbackMatSuffixes.Count} suffix(es)");
					args.Context.AddString($"  Force-fallback prefixes:    {_forceFallbackPrefixSet.Count}");
					args.Context.AddString($"  Force-transparent prefixes: {_forceTransparentPrefixSet.Count}");
					break;
				}
				case "initmod":
				{
					string dllArg = ((args.Length > 2) ? args[2] : string.Empty);
					bool flag = args.Length > 3 && args[3].Equals("force", StringComparison.OrdinalIgnoreCase);
					if (string.IsNullOrEmpty(dllArg))
					{
						args.Context.AddString("Usage: shaderhelper initmod <DllName> [force]");
					}
					else
					{
						string dllName = ModShaderDlls.Values.FirstOrDefault((string d) => d.Equals(dllArg, StringComparison.OrdinalIgnoreCase));
						bool flag2 = dllName == null;
						if (flag2)
						{
							dllName = dllArg;
							args.Context.AddString("ShaderHelperForMac: '" + dllArg + "' not in scan results (likely a large embedded bundle).");
							args.Context.AddString("Scanning all unsupported materials in memory — spawn/equip mod items first for best coverage.");
						}
						string text2 = Path.Combine(ConfigDir, dllName + ".txt");
						if (File.Exists(text2) && !flag)
						{
							args.Context.AddString("ShaderHelperForMac: '" + dllName + ".txt' already exists.");
							args.Context.AddString("Use 'shaderhelper initmod " + dllName + " force' to overwrite.");
						}
						else
						{
							HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
							List<(string, bool, string)> list = new List<(string, bool, string)>();
							Material[] array = Resources.FindObjectsOfTypeAll<Material>();
							foreach (Material val in array)
							{
								if (!((Object)(object)val == (Object)null) && !((Object)(object)val.shader == (Object)null) && !((Object)(object)val == (Object)(object)_transparentMat) && !((Object)(object)val == (Object)(object)_fallbackMat))
								{
									if (!flag2)
									{
										if (!ModShaderDlls.TryGetValue(((Object)val.shader).name, out string value) || !value.Equals(dllName, StringComparison.OrdinalIgnoreCase))
										{
											continue;
										}
									}
									else if (!NeedsReplacement(val.shader))
									{
										continue;
									}
									string text3 = StripInstance(((Object)val).name);
									if (hashSet.Add(text3))
									{
										bool item = IsErrorPink(val) || val.renderQueue > 2450 || (val.HasProperty("_Mode") && val.GetFloat("_Mode") >= 2f) || IsHdrEmission(val);
										list.Add((text3, item, ((Object)val.shader).name));
									}
								}
							}
							array = Resources.FindObjectsOfTypeAll<Material>();
							foreach (Material val2 in array)
							{
								if (!((Object)(object)val2 == (Object)null) && _replacedMats.TryGetValue(((Object)val2).GetInstanceID(), out (string, ShaderAction) value2))
								{
									var (text4, _) = value2;
									if ((flag2 || (ModShaderDlls.TryGetValue(text4, out string value3) && value3.Equals(dllName, StringComparison.OrdinalIgnoreCase))) && !ValheimShaderNameSet.Contains(text4) && !ShaderScanner.IsLikelySafeShader(text4))
									{
										string text5 = StripInstance(((Object)val2).name);
										if (hashSet.Add(text5))
										{
											bool item2 = text4.IndexOf("Particle", StringComparison.OrdinalIgnoreCase) >= 0 || text4.IndexOf("Alpha", StringComparison.OrdinalIgnoreCase) >= 0 || text4.IndexOf("Additive", StringComparison.OrdinalIgnoreCase) >= 0 || text4.IndexOf("Glow", StringComparison.OrdinalIgnoreCase) >= 0 || text4.IndexOf("Effect", StringComparison.OrdinalIgnoreCase) >= 0 || text4.IndexOf("VFX", StringComparison.OrdinalIgnoreCase) >= 0;
											list.Add((text5, item2, text4));
										}
									}
								}
							}
							if (list.Count != 0)
							{
								SortedDictionary<string, int> sortedDictionary = new SortedDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
								SortedDictionary<string, int> sortedDictionary2 = new SortedDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
								array = Resources.FindObjectsOfTypeAll<Material>();
								foreach (Material val3 in array)
								{
									if (!((Object)(object)val3 == (Object)null) && _replacedMats.TryGetValue(((Object)val3).GetInstanceID(), out (string, ShaderAction) value4))
									{
										var (text6, shaderAction) = value4;
										if ((flag2 || (ModShaderDlls.TryGetValue(text6, out string value5) && value5.Equals(dllName, StringComparison.OrdinalIgnoreCase))) && !ShaderScanner.IsLikelySafeShader(text6) && !ValheimShaderNameSet.Contains(text6))
										{
											Shader val4 = Shader.Find(text6);
											bool num = (Object)(object)val4 != (Object)null && val4.isSupported;
											bool flag3 = IsForceFallback(text6) || IsForceTransparent(text6);
											if (num || flag3)
											{
												switch (shaderAction)
												{
												case ShaderAction.Fallback:
												{
													sortedDictionary.TryGetValue(text6, out var value7);
													sortedDictionary[text6] = value7 + 1;
													break;
												}
												case ShaderAction.Transparent:
												{
													sortedDictionary2.TryGetValue(text6, out var value6);
													sortedDictionary2[text6] = value6 + 1;
													break;
												}
												}
											}
										}
									}
								}
								SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
								SortedSet<string> sortedSet2 = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
								array = Resources.FindObjectsOfTypeAll<Material>();
								foreach (Material val5 in array)
								{
									if (!((Object)(object)val5 == (Object)null) && !((Object)(object)val5.shader == (Object)null) && !((Object)(object)val5 == (Object)(object)_transparentMat) && !((Object)(object)val5 == (Object)(object)_fallbackMat) && val5.shader.isSupported && !CanonicalShaderIds.Contains(((Object)val5.shader).GetInstanceID()) && !ValheimShaderNameSet.Contains(((Object)val5.shader).name) && !ShaderScanner.IsLikelySafeShader(((Object)val5.shader).name))
									{
										Shader val6 = Shader.Find(((Object)val5.shader).name);
										if ((!((Object)(object)val6 != (Object)null) || !CanonicalShaderIds.Contains(((Object)val6).GetInstanceID())) && !sortedDictionary.ContainsKey(((Object)val5.shader).name) && !sortedDictionary2.ContainsKey(((Object)val5.shader).name))
										{
											if (!flag2)
											{
												if (!ModShaderDlls.TryGetValue(((Object)val5.shader).name, out string value8) || !value8.Equals(dllName, StringComparison.OrdinalIgnoreCase))
												{
													continue;
												}
											}
											else
											{
												string item3 = StripInstance(((Object)val5).name);
												if (_baselineMatNames.Contains(item3))
												{
													continue;
												}
											}
											if (IsSuspectTransparentShader(((Object)val5.shader).name))
											{
												sortedSet2.Add(((Object)val5.shader).name);
											}
											else
											{
												sortedSet.Add(((Object)val5.shader).name);
											}
										}
									}
								}
								Dictionary<string, (int, int, List<string>)> dictionary = new Dictionary<string, (int, int, List<string>)>(StringComparer.OrdinalIgnoreCase);
								List<(string, bool)> list2 = new List<(string, bool)>();
								foreach (var item16 in list)
								{
									string item4 = item16.Item1;
									bool item5 = item16.Item2;
									string text7 = ExtractMatSuffix(item4);
									if (text7 == null)
									{
										list2.Add((item4, item5));
									}
									else
									{
										if (!dictionary.TryGetValue(text7, out var value9))
										{
											value9 = (0, 0, new List<string>());
										}
										value9 = (item5 ? (value9.Item1, value9.Item2 + 1, value9.Item3) : (value9.Item1 + 1, value9.Item2, value9.Item3));
										if (value9.Item3.Count < 4)
										{
											value9.Item3.Add(item4);
										}
										dictionary[text7] = value9;
									}
								}
								List<string> values = (flag2 ? (from n in list.Select<(string, bool, string), string>(((string name, bool isTransparent, string shaderName) m) => m.shaderName).Distinct<string>(StringComparer.OrdinalIgnoreCase)
									where !ShaderScanner.IsLikelySafeShader(n) && !IsForceFallback(n) && !IsForceTransparent(n)
									orderby n
									select n).ToList() : (from kv in ModShaderDlls
									where kv.Value.Equals(dllName, StringComparison.OrdinalIgnoreCase)
									select kv.Key into n
									orderby n
									select n).ToList());
								List<KeyValuePair<string, (int, int, List<string>)>> list3 = (from kv in dictionary
									orderby kv.Value.fb + kv.Value.tr descending, kv.Key
									select kv).ToList();
								StringBuilder stringBuilder = new StringBuilder();
								stringBuilder.AppendLine("# ShaderHelperForMac — config for: " + dllName);
								stringBuilder.AppendLine("# Place this file in: BepInEx/config/ShaderHelperForMac/");
								stringBuilder.AppendLine("# The plugin loads it automatically — no other action needed.");
								if (flag2)
								{
									stringBuilder.AppendLine("# NOTE: large embedded bundle — shader-to-DLL attribution unavailable.");
									stringBuilder.AppendLine("#       Broken shader(s) found: " + string.Join(", ", values));
								}
								else
								{
									stringBuilder.AppendLine("# Shader(s) in this mod: " + string.Join(", ", values));
								}
								stringBuilder.AppendLine($"# ({list.Count} unique material(s) scanned — spawn/equip items for full coverage)");
								stringBuilder.AppendLine("#");
								stringBuilder.AppendLine("# IF OBJECTS STILL RENDER PINK after installing this file:");
								stringBuilder.AppendLine("#   Step 1 — look at [forcefallback] below. Uncomment any 'Suspected' entry and");
								stringBuilder.AppendLine("#             run  shaderhelper sweep  in the console (F5). Try one at a time.");
								stringBuilder.AppendLine("#   Step 2 — do the same for [forcetransparent] if particles/smoke are pink.");
								stringBuilder.AppendLine("#   Step 3 — if a specific material is still wrong, add  mat:MaterialName");
								stringBuilder.AppendLine("#             to [fallback] or [transparent] and sweep again.");
								stringBuilder.AppendLine("# Regenerate this file: shaderhelper initmod " + dllName + " force");
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("# [forcefallback]  ← START HERE if solid objects (armour, weapons, body) are pink");
								stringBuilder.AppendLine("# These shaders look valid to Unity but render pink on Mac. The plugin cannot");
								stringBuilder.AppendLine("# detect them automatically — entries here override that and force a fix.");
								stringBuilder.AppendLine("#   Active entries  = confirmed pink, already being fixed.");
								stringBuilder.AppendLine("#   # Commented     = suspected pink — uncomment + sweep to test.");
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("[forcefallback]");
								List<KeyValuePair<string, int>> list4 = sortedDictionary.Where((KeyValuePair<string, int> kv) => !IsCoveredByBuiltIn(kv.Key)).ToList();
								if (list4.Count > 0)
								{
									stringBuilder.AppendLine("# Confirmed (active — solid objects already fixed by these rules):");
									foreach (KeyValuePair<string, int> item17 in list4)
									{
										stringBuilder.AppendLine($"{item17.Key,-50}# {item17.Value} material(s) replaced");
									}
								}
								if (sortedSet.Count > 0)
								{
									stringBuilder.AppendLine("# Suspected (uncomment + sweep if solid objects still pink):");
									foreach (string item18 in sortedSet)
									{
										stringBuilder.AppendLine("# " + item18);
									}
								}
								if (list4.Count == 0 && sortedSet.Count == 0)
								{
									stringBuilder.AppendLine("# (none detected — paste a shader prefix here if solid objects render pink)");
								}
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("# [forcetransparent]  ← check here if particles, smoke, or spell effects are pink");
								stringBuilder.AppendLine("# Same as above but for transparent/particle shaders.");
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("[forcetransparent]");
								List<KeyValuePair<string, int>> list5 = sortedDictionary2.Where((KeyValuePair<string, int> kv) => !IsCoveredByBuiltIn(kv.Key)).ToList();
								if (list5.Count > 0)
								{
									stringBuilder.AppendLine("# Confirmed (active — particle/effect shaders already fixed by these rules):");
									foreach (KeyValuePair<string, int> item19 in list5)
									{
										stringBuilder.AppendLine($"{item19.Key,-50}# {item19.Value} material(s) replaced");
									}
								}
								if (sortedSet2.Count > 0)
								{
									if (flag2)
									{
										stringBuilder.AppendLine("# (large-bundle scan: entries below may include shaders from other mods)");
									}
									stringBuilder.AppendLine("# Suspected (uncomment + sweep if particles or effects still pink):");
									foreach (string item20 in sortedSet2)
									{
										stringBuilder.AppendLine("# " + item20);
									}
								}
								if (list5.Count == 0 && sortedSet2.Count == 0)
								{
									stringBuilder.AppendLine("# (none detected — paste a shader prefix here if particles/effects render pink)");
								}
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("# [fallback]  — handled automatically, no changes needed in most cases");
								stringBuilder.AppendLine("# These shaders are completely unsupported on Mac. The plugin replaces them with");
								stringBuilder.AppendLine("# the nearest Valheim-compatible solid shader using the rules below.");
								stringBuilder.AppendLine("#   suffix:XYZ  applies to every material whose name ends with _XYZ");
								stringBuilder.AppendLine("#   mat:Name    applies to one specific material by exact name");
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("[fallback]");
								bool flag4 = false;
								foreach (KeyValuePair<string, (int, int, List<string>)> item21 in list3)
								{
									string key = item21.Key;
									(int, int, List<string>) value10 = item21.Value;
									List<string> item6 = value10.Item3;
									int item7 = value10.Item2;
									int item8 = value10.Item1;
									string text8 = key;
									if (item8 != 0)
									{
										int num2 = item8 + item7;
										string text9 = ((item6.Count > 0) ? ("  # e.g. " + string.Join(", ", item6)) : string.Empty);
										if (item8 >= item7 && num2 >= 3)
										{
											stringBuilder.AppendLine($"suffix:{text8,-14}# {num2} material(s){text9}");
										}
										else
										{
											stringBuilder.AppendLine($"# suffix:{text8,-12}# {num2} material(s) ({item8} fallback, {item7} transparent){text9}");
										}
										flag4 = true;
									}
								}
								foreach (var item22 in list2.Where<(string, bool)>(((string name, bool isTransparent) x) => !x.isTransparent))
								{
									string item9 = item22.Item1;
									stringBuilder.AppendLine("# mat:" + item9);
									flag4 = true;
								}
								if (!flag4)
								{
									stringBuilder.AppendLine("# (none detected — add mat: or suffix: rules here if needed)");
								}
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("# [transparent]  — handled automatically, no changes needed in most cases");
								stringBuilder.AppendLine("# Same as [fallback] but uses a transparent shader (for smoke, particles, glass).");
								stringBuilder.AppendLine("# ────────────────────────────────────────────────────────────────────────────────");
								stringBuilder.AppendLine("[transparent]");
								bool flag5 = false;
								foreach (KeyValuePair<string, (int, int, List<string>)> item23 in list3)
								{
									string key2 = item23.Key;
									(int, int, List<string>) value11 = item23.Value;
									List<string> item10 = value11.Item3;
									int item11 = value11.Item2;
									int item12 = value11.Item1;
									string text10 = key2;
									if (item11 != 0)
									{
										int num3 = item12 + item11;
										string text11 = ((item10.Count > 0) ? ("  # e.g. " + string.Join(", ", item10)) : string.Empty);
										if (item11 >= item12 && item12 == 0 && num3 >= 3)
										{
											stringBuilder.AppendLine($"suffix:{text10,-14}# {num3} material(s){text11}");
										}
										else
										{
											stringBuilder.AppendLine($"# suffix:{text10,-12}# {num3} material(s) ({item12} fallback, {item11} transparent){text11}");
										}
										flag5 = true;
									}
								}
								foreach (var item24 in list2.Where<(string, bool)>(((string name, bool isTransparent) x) => x.isTransparent))
								{
									string item13 = item24.Item1;
									stringBuilder.AppendLine("# mat:" + item13);
									flag5 = true;
								}
								if (!flag5)
								{
									stringBuilder.AppendLine("# (none detected — add mat: or suffix: rules here if needed)");
								}
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("[original]");
								stringBuilder.AppendLine();
								stringBuilder.AppendLine("[default]");
								stringBuilder.AppendLine("fallback");
								try
								{
									File.WriteAllText(text2, stringBuilder.ToString());
									ReloadConfigFiles();
									args.Context.AddString($"ShaderHelperForMac: created '{dllName}.txt' — {list.Count} material(s) analyzed, {list3.Count} suffix group(s).");
									args.Context.AddString("File: " + text2);
									args.Context.AddString("Config reloaded. Run 'shaderhelper sweep' to apply new rules.");
									Log.LogInfo((object)$"[InitMod] Wrote '{dllName}.txt': {list.Count} materials, {list3.Count} suffix groups.");
									break;
								}
								catch (Exception ex)
								{
									args.Context.AddString("ShaderHelperForMac: failed to write file: " + ex.Message);
									break;
								}
							}
							args.Context.AddString("ShaderHelperForMac: no materials found in memory.");
							args.Context.AddString("Spawn or equip the mod's items first, then re-run.");
						}
					}
					break;
				}
				default:
					args.Context.AddString("Usage:  shaderhelper sweep                    — run a material sweep immediately");
					args.Context.AddString("        shaderhelper nearby [radius] [DllName|mod] — log materials near the player; filter by mod DLL name or use 'mod' to skip vanilla");
					args.Context.AddString("        shaderhelper transparent <DllName>     — log materials ShaderHelper made (or will make) transparent for a mod");
					args.Context.AddString("        shaderhelper loaded [DllName]          — log all in-memory materials incl. prefabs; optionally filter by mod DLL name");
					args.Context.AddString("        shaderhelper initmod <DllName> [force] — generate a starter config file for a mod");
					args.Context.AddString("        shaderhelper scan <DllName>            — log all materials from a mod with shader/support info");
					args.Context.AddString("        shaderhelper pink                      — log all unhandled pink/unsupported materials");
					args.Context.AddString("        shaderhelper renderers                 — log materials from active scene renderers (finds dynamic dungeon objects)");
					args.Context.AddString("        shaderhelper all                       — log ALL loaded materials regardless of action (diagnostics)");
					args.Context.AddString("        shaderhelper status                    — show current plugin state");
					break;
				}
			}, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			Log.LogDebug((object)"Console command 'shaderhelper' registered.");
			static bool IsSuspectTransparentShader(string sn)
			{
				if (sn.IndexOf("Particle", StringComparison.OrdinalIgnoreCase) < 0 && sn.IndexOf("VFX", StringComparison.OrdinalIgnoreCase) < 0 && sn.IndexOf("Effect", StringComparison.OrdinalIgnoreCase) < 0 && sn.IndexOf("Glow", StringComparison.OrdinalIgnoreCase) < 0 && sn.IndexOf("Emission", StringComparison.OrdinalIgnoreCase) < 0 && sn.IndexOf("Additive", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return sn.IndexOf("Alpha", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
		}

		private static void CollectCanonicalShaderIds()
		{
			string[] valheimShaderNames = ValheimShaderNames;
			for (int i = 0; i < valheimShaderNames.Length; i++)
			{
				Shader val = Shader.Find(valheimShaderNames[i]);
				if ((Object)(object)val != (Object)null)
				{
					CanonicalShaderIds.Add(((Object)val).GetInstanceID());
				}
			}
			Log.LogDebug((object)$"Registered {CanonicalShaderIds.Count} canonical Valheim shader ID(s).");
		}

		private static void BuildTransparentMaterial()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_transparentMat != (Object)null)
			{
				return;
			}
			Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default") ?? Shader.Find("Unlit/Transparent");
			if ((Object)(object)val != (Object)null)
			{
				_transparentMat = new Material(val)
				{
					name = "ShaderFix_Transparent"
				};
				_transparentMat.color = new Color(0f, 0f, 0f, 0f);
				Log.LogDebug((object)("Transparent material ready (shader='" + ((Object)val).name + "')."));
				return;
			}
			Shader val2 = Shader.Find("Standard");
			if ((Object)(object)val2 != (Object)null)
			{
				_transparentMat = new Material(val2)
				{
					name = "ShaderFix_Transparent"
				};
				_transparentMat.SetFloat("_Mode", 3f);
				_transparentMat.SetInt("_SrcBlend", 5);
				_transparentMat.SetInt("_DstBlend", 10);
				_transparentMat.SetInt("_ZWrite", 0);
				_transparentMat.EnableKeyword("_ALPHABLEND_ON");
				_transparentMat.renderQueue = 3000;
				_transparentMat.color = new Color(0f, 0f, 0f, 0f);
				Log.LogDebug((object)"Transparent material ready (Standard Transparent).");
			}
			else
			{
				Log.LogWarning((object)"No transparent shader found — shader replacement will not work.");
			}
		}

		private static void BuildReplacementMaterials()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			BuildTransparentMaterial();
			if ((Object)(object)FallbackShader != (Object)null)
			{
				_fallbackMat = new Material(FallbackShader)
				{
					name = "ShaderFix_Fallback"
				};
				_fallbackMat.color = Color.white;
				Log.LogDebug((object)("Fallback material ready (shader='" + ((Object)FallbackShader).name + "')."));
			}
		}

		internal static void TryUpgradeFallbackShader()
		{
			if ((Object)(object)FallbackShader == (Object)null)
			{
				return;
			}
			Shader[] source = Resources.FindObjectsOfTypeAll<Shader>();
			string[] fallbackChain = FallbackChain;
			foreach (string name in fallbackChain)
			{
				Shader val = ((IEnumerable<Shader>)source).FirstOrDefault((Func<Shader, bool>)((Shader sh) => ((Object)sh).name == name && sh.isSupported));
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find(name);
				}
				if ((Object)(object)val == (Object)null || !val.isSupported)
				{
					continue;
				}
				if (((Object)val).GetInstanceID() != ((Object)FallbackShader).GetInstanceID())
				{
					Log.LogInfo((object)$"[ZNetScene.Awake] Upgraded fallback shader: '{((Object)FallbackShader).name}' (id={((Object)FallbackShader).GetInstanceID()}) → '{((Object)val).name}' (id={((Object)val).GetInstanceID()})");
					FallbackShader = val;
					if ((Object)(object)_fallbackMat != (Object)null)
					{
						_fallbackMat.shader = val;
					}
				}
				break;
			}
		}

		internal static Shader? GetReplacementShader(string shaderName)
		{
			switch (GetAction(shaderName))
			{
			case ShaderAction.Transparent:
			{
				Material? transparentMat = _transparentMat;
				return (transparentMat != null) ? transparentMat.shader : null;
			}
			case ShaderAction.Fallback:
				return FallbackShader;
			default:
				return null;
			}
		}

		internal static bool ShouldReplace(string shaderName)
		{
			if (IsForceTransparent(shaderName))
			{
				return true;
			}
			ModShaderDlls.TryGetValue(shaderName, out string value);
			if (value != null && _useOriginalDlls.Contains(value))
			{
				return false;
			}
			if (DefaultAllTransparent)
			{
				return true;
			}
			if (value != null && (_useFallbackDlls.Contains(value) || _useTransparentDlls.Contains(value)))
			{
				return true;
			}
			return false;
		}

		internal static bool IsForceTransparentShader(string shaderName)
		{
			return IsForceTransparent(shaderName);
		}

		private static bool IsForceTransparent(string shaderName)
		{
			foreach (string item in _forceTransparentPrefixSet)
			{
				if (shaderName.StartsWith(item, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsForceFallback(string shaderName)
		{
			foreach (string item in _forceFallbackPrefixSet)
			{
				if (shaderName.StartsWith(item, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsCoveredByBuiltIn(string shaderName)
		{
			foreach (string builtInFallbackPrefix in _builtInFallbackPrefixes)
			{
				if (shaderName.StartsWith(builtInFallbackPrefix, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			foreach (string builtInTransparentPrefix in _builtInTransparentPrefixes)
			{
				if (shaderName.StartsWith(builtInTransparentPrefix, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool NeedsReplacement(Shader shader)
		{
			string name = ((Object)shader).name;
			if (name.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (name.StartsWith("TextMeshPro/", StringComparison.OrdinalIgnoreCase) && name.EndsWith(" (Surface)", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (IsForceFallback(name))
			{
				return true;
			}
			if (IsForceTransparent(name))
			{
				return true;
			}
			if (shader.isSupported)
			{
				return false;
			}
			if (CanonicalShaderIds.Contains(((Object)shader).GetInstanceID()))
			{
				return false;
			}
			if (ShaderScanner.IsLikelySafeShader(name))
			{
				return false;
			}
			return true;
		}

		private static bool IsErrorPink(Material mat)
		{
			//IL_000e: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty("_Color"))
			{
				Color color = mat.color;
				if (color.r > 0.9f && color.g < 0.1f)
				{
					return color.b > 0.7f;
				}
				return false;
			}
			return false;
		}

		private static string? ExtractMatSuffix(string name)
		{
			int num = name.LastIndexOf('_');
			if (num < 0 || num == name.Length - 1)
			{
				return null;
			}
			return name.Substring(num + 1);
		}

		private static bool IsHdrEmission(Material mat)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty("_EmissionColor"))
			{
				Color color = mat.GetColor("_EmissionColor");
				if (!(color.r > 1f) && !(color.g > 1f))
				{
					return color.b > 1f;
				}
				return true;
			}
			return false;
		}

		private static bool NeedsReplacement(Material mat)
		{
			if (!NeedsReplacement(mat.shader))
			{
				return IsErrorPink(mat);
			}
			return true;
		}

		private static ShaderAction GetAction(Material mat)
		{
			if (CanonicalShaderIds.Contains(((Object)mat.shader).GetInstanceID()))
			{
				return ShaderAction.Original;
			}
			string name = ((Object)mat).name;
			name = StripInstance(name);
			if (_originalMatNames.Contains(name))
			{
				return ShaderAction.Original;
			}
			if (_transparentMatNames.Contains(name))
			{
				return ShaderAction.Transparent;
			}
			if (_fallbackMatNames.Contains(name))
			{
				return ShaderAction.Fallback;
			}
			if (IsErrorPink(mat))
			{
				return ShaderAction.Transparent;
			}
			foreach (string transparentMatSuffix in _transparentMatSuffixes)
			{
				if (name.EndsWith(transparentMatSuffix, StringComparison.OrdinalIgnoreCase))
				{
					return ShaderAction.Transparent;
				}
			}
			foreach (string fallbackMatSuffix in _fallbackMatSuffixes)
			{
				if (!name.EndsWith(fallbackMatSuffix, StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				if (((Object)mat.shader).name != "Standard Double Sided")
				{
					if (mat.renderQueue > 2450)
					{
						return ShaderAction.Transparent;
					}
					if (mat.HasProperty("_Mode") && mat.GetFloat("_Mode") >= 2f)
					{
						return ShaderAction.Transparent;
					}
					if (IsHdrEmission(mat))
					{
						return ShaderAction.Transparent;
					}
				}
				return ShaderAction.Fallback;
			}
			return GetAction(((Object)mat.shader).name);
		}

		private static ShaderAction GetAction(string shaderName)
		{
			if (shaderName.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase))
			{
				return ShaderAction.Fallback;
			}
			if (shaderName.StartsWith("TextMeshPro/", StringComparison.OrdinalIgnoreCase) && shaderName.EndsWith(" (Surface)", StringComparison.OrdinalIgnoreCase))
			{
				return ShaderAction.Fallback;
			}
			if (IsForceTransparent(shaderName))
			{
				return ShaderAction.Transparent;
			}
			if (IsForceFallback(shaderName))
			{
				return ShaderAction.Fallback;
			}
			if (ValheimShaderNameSet.Contains(shaderName))
			{
				return ShaderAction.Fallback;
			}
			ModShaderDlls.TryGetValue(shaderName, out string value);
			if (value != null && _useOriginalDlls.Contains(value))
			{
				return ShaderAction.Original;
			}
			if (DefaultAllTransparent)
			{
				return ShaderAction.Transparent;
			}
			if (value != null && _useTransparentDlls.Contains(value))
			{
				return ShaderAction.Transparent;
			}
			if (value != null && _useFallbackDlls.Contains(value))
			{
				return ShaderAction.Fallback;
			}
			return ShaderAction.Original;
		}

		internal void SweepMaterials()
		{
			if (!_sweepRunning)
			{
				((MonoBehaviour)this).StartCoroutine(SweepMaterialsCoroutine());
			}
		}

		internal void SweepMaterialsWithNotify()
		{
			if (!_sweepRunning)
			{
				((MonoBehaviour)this).StartCoroutine(SweepAndNotifyCoroutine());
			}
		}

		[IteratorStateMachine(typeof(<SweepAndNotifyCoroutine>d__91))]
		private IEnumerator SweepAndNotifyCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SweepAndNotifyCoroutine>d__91(0)
			{
				<>4__this = this
			};
		}

		internal static void TryReplaceMaterialPublic(Material mat)
		{
			TryReplaceMaterial(mat);
		}

		[IteratorStateMachine(typeof(<SweepMaterialsCoroutine>d__94))]
		internal IEnumerator SweepMaterialsCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SweepMaterialsCoroutine>d__94(0)
			{
				<>4__this = this
			};
		}

		private static string StripInstance(string name)
		{
			while (name.EndsWith(" (Instance)", StringComparison.Ordinal))
			{
				name = name.Substring(0, name.Length - " (Instance)".Length);
			}
			return name;
		}

		private static bool IsExplicitMatRule(Material mat)
		{
			string text = StripInstance(((Object)mat).name);
			if (_transparentMatNames.Contains(text) || _fallbackMatNames.Contains(text))
			{
				return true;
			}
			foreach (string transparentMatSuffix in _transparentMatSuffixes)
			{
				if (text.EndsWith(transparentMatSuffix, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			foreach (string fallbackMatSuffix in _fallbackMatSuffixes)
			{
				if (text.EndsWith(fallbackMatSuffix, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static int TryReplaceMaterial(Material? mat)
		{
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)mat == (Object)null || (Object)(object)mat.shader == (Object)null)
			{
				return 0;
			}
			if ((Object)(object)mat == (Object)(object)_transparentMat || (Object)(object)mat == (Object)(object)_fallbackMat)
			{
				return 0;
			}
			string item = StripInstance(((Object)mat).name);
			bool flag = IsExplicitMatRule(mat);
			bool flag2 = IsForceTransparent(((Object)mat.shader).name) || IsForceFallback(((Object)mat.shader).name);
			if (_forceReplacedMaterialIds.Contains(((Object)mat).GetInstanceID()) && !flag)
			{
				return 0;
			}
			if (CanonicalShaderIds.Contains(((Object)mat.shader).GetInstanceID()))
			{
				return 0;
			}
			if (_baselineMatNames.Contains(item) && !flag && !flag2)
			{
				return 0;
			}
			if (!NeedsReplacement(mat) && !flag)
			{
				return 0;
			}
			ShaderAction action = GetAction(mat);
			if (action == ShaderAction.Original)
			{
				return 0;
			}
			if (((Object)mat.shader).name.StartsWith("TextMeshPro/", StringComparison.OrdinalIgnoreCase) && ((Object)mat.shader).name.EndsWith(" (Surface)", StringComparison.OrdinalIgnoreCase))
			{
				string text = ((Object)mat.shader).name.Substring(0, ((Object)mat.shader).name.Length - " (Surface)".Length);
				Shader val = Shader.Find(text);
				if ((Object)(object)val != (Object)null && ((Object)val).GetInstanceID() != ((Object)mat.shader).GetInstanceID())
				{
					Log.LogDebug((object)("[TMP] '" + ((Object)mat.shader).name + "' → '" + text + "' on mat '" + ((Object)mat).name + "'"));
					_replacedMats[((Object)mat).GetInstanceID()] = (((Object)mat.shader).name, action);
					mat.shader = val;
					return 1;
				}
			}
			Material val2 = ((action == ShaderAction.Fallback) ? _fallbackMat : _transparentMat);
			if ((Object)(object)val2 == (Object)null)
			{
				return 0;
			}
			if (((Object)mat.shader).GetInstanceID() == ((Object)val2.shader).GetInstanceID())
			{
				return 0;
			}
			object obj;
			if (!mat.HasProperty("_Color"))
			{
				obj = "n/a";
			}
			else
			{
				Color color = mat.color;
				obj = ((object)(Color)(ref color)).ToString();
			}
			string text2 = (string)obj;
			Log.LogDebug((object)$"[{action}] '{((Object)mat.shader).name}' → '{((Object)val2.shader).name}' on mat '{((Object)mat).name}'  color={text2}.");
			_replacedMats[((Object)mat).GetInstanceID()] = (((Object)mat.shader).name, action);
			mat.shader = val2.shader;
			if (val2.HasProperty("_Color"))
			{
				mat.color = val2.color;
			}
			if (action == ShaderAction.Fallback)
			{
				if (mat.HasProperty("_EmissionColor"))
				{
					mat.SetColor("_EmissionColor", Color.black);
				}
				mat.DisableKeyword("_EMISSION");
			}
			if (action == ShaderAction.Transparent)
			{
				_forceReplacedMaterialIds.Add(((Object)mat).GetInstanceID());
			}
			return 1;
		}
	}
	internal static class ShaderScanner
	{
		private sealed class NullAssemblyResolver : IAssemblyResolver, IDisposable
		{
			public static readonly NullAssemblyResolver Instance = new NullAssemblyResolver();

			public AssemblyDefinition? Resolve(AssemblyNameReference name)
			{
				return null;
			}

			public AssemblyDefinition? Resolve(AssemblyNameReference name, ReaderParameters p)
			{
				return null;
			}

			public void Dispose()
			{
			}
		}

		private static readonly byte[] UnityMagic = Encoding.ASCII.GetBytes("Unity");

		private static readonly string[] SafePrefixes = new string[13]
		{
			"JVLmock_", "Standard", "Hidden/", "Sprites/", "GUI/", "Particles/", "TextMeshPro/", "UI/", "Skybox/", "Custom/",
			"Unlit/", "Autodesk Interactive", "Lux Lit Particles/"
		};

		public static int ScanPlugins(string pluginsPath, Dictionary<string, string> modShaderDlls, ManualLogSource log)
		{
			if (!Directory.Exists(pluginsPath))
			{
				return 0;
			}
			int num = 0;
			List<string> list = Directory.EnumerateFiles(pluginsPath, "*.dll", SearchOption.AllDirectories).ToList();
			List<string> list2 = Directory.EnumerateFiles(pluginsPath, "*.bundle", SearchOption.AllDirectories).ToList();
			log.LogInfo((object)$"Scanner: found {list.Count} DLL(s) and {list2.Count} bundle file(s) to scan.");
			int num2 = 0;
			foreach (string item in list)
			{
				num2++;
				long num3 = 0L;
				try
				{
					num3 = new FileInfo(item).Length;
				}
				catch
				{
				}
				if (num3 > 10485760)
				{
					log.LogInfo((object)$"[{num2}/{list.Count}] Skipping large DLL '{Path.GetFileNameWithoutExtension(item)}' ({num3 / 1024 / 1024} MB) — use suffix:/mat: rules in txt files instead.");
					continue;
				}
				int num4 = ScanDll(item, modShaderDlls, log);
				if (num4 > 0)
				{
					log.LogInfo((object)$"[{num2}/{list.Count}] '{Path.GetFileNameWithoutExtension(item)}' — {num4} shader(s)");
				}
				num += num4;
			}
			foreach (string item2 in list2)
			{
				num += ScanBundleFile(item2, modShaderDlls, log);
			}
			return num;
		}

		private static int ScanDll(string dllPath, Dictionary<string, string> modShaderDlls, ManualLogSource log)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			try
			{
				AssemblyDefinition val = AssemblyDefinition.ReadAssembly(dllPath, new ReaderParameters
				{
					ReadingMode = (ReadingMode)2,
					AssemblyResolver = (IAssemblyResolver)(object)NullAssemblyResolver.Instance
				});
				try
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(dllPath);
					int num = 0;
					foreach (EmbeddedResource item in ((IEnumerable)val.MainModule.Resources).OfType<EmbeddedResource>())
					{
						byte[] resourceData;
						try
						{
							resourceData = item.GetResourceData();
						}
						catch (Exception ex)
						{
							log.LogInfo((object)("[Diag] " + fileNameWithoutExtension + ": resource '" + ((Resource)item).Name + "' read failed: " + ex.Message));
							continue;
						}
						if (IsUnityBundle(resourceData))
						{
							log.LogInfo((object)$"[Diag] {fileNameWithoutExtension}: found Unity bundle in resource '{((Resource)item).Name}' ({resourceData.Length} bytes)");
							num += ScanBundleBytes(resourceData, fileNameWithoutExtension, modShaderDlls, log);
						}
					}
					return num;
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception ex2)
			{
				log.LogInfo((object)("[Diag] ScanDll failed for '" + Path.GetFileNameWithoutExtension(dllPath) + "': " + ex2.Message));
				return 0;
			}
		}

		private static int ScanBundleFile(string bundlePath, Dictionary<string, string> modShaderDlls, ManualLogSource log)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(bundlePath);
				AssetsManager val = new AssetsManager();
				BundleFileInstance bundle = val.LoadBundleFile(bundlePath, true);
				int result = ScanBundle(val, bundle, fileNameWithoutExtension, modShaderDlls, log);
				val.UnloadAllBundleFiles();
				return result;
			}
			catch
			{
				return 0;
			}
		}

		private static int ScanBundleBytes(byte[] data, string sourceName, Dictionary<string, string> modShaderDlls, ManualLogSource log)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			try
			{
				AssetsManager val = new AssetsManager();
				using MemoryStream memoryStream = new MemoryStream(data);
				BundleFileInstance val2 = val.LoadBundleFile((Stream)memoryStream, "embedded", true);
				log.LogInfo((object)$"[Diag] {sourceName}: bundle loaded, {val2.file.BlockAndDirInfo.DirectoryInfos.Count} dir entries");
				int result = ScanBundle(val, val2, sourceName, modShaderDlls, log);
				val.UnloadAllBundleFiles();
				return result;
			}
			catch (Exception ex)
			{
				log.LogInfo((object)("[Diag] " + sourceName + ": bundle load failed: " + ex.Message));
				return 0;
			}
		}

		private static int ScanBundle(AssetsManager manager, BundleFileInstance bundle, string sourceName, Dictionary<string, string> modShaderDlls, ManualLogSource log)
		{
			int num = 0;
			List<AssetBundleDirectoryInfo> directoryInfos = bundle.file.BlockAndDirInfo.DirectoryInfos;
			for (int i = 0; i < directoryInfos.Count; i++)
			{
				AssetsFileInstance val = null;
				try
				{
					val = manager.LoadAssetsFileFromBundle(bundle, i, false);
				}
				catch
				{
				}
				if (val == null)
				{
					continue;
				}
				List<AssetFileInfo> assetsOfType = val.file.GetAssetsOfType((AssetClassID)48);
				log.LogInfo((object)$"[Diag] {sourceName}: dir[{i}] has {assetsOfType.Count} shader asset(s)");
				bool flag = true;
				foreach (AssetFileInfo item in assetsOfType)
				{
					try
					{
						string text = ReadAssetName(val, item, flag ? log : null);
						flag = false;
						log.LogInfo((object)$"[Diag] {sourceName}: shader pathId={item.PathId} name='{text}'");
						if (!string.IsNullOrEmpty(text) && !IsLikelySafeShader(text))
						{
							modShaderDlls[text] = sourceName;
							log.LogDebug((object)("Scanner: recorded shader '" + text + "' from '" + sourceName + "'"));
							num++;
						}
					}
					catch (Exception ex)
					{
						log.LogInfo((object)("[Diag] " + sourceName + ": shader read exception: " + ex.Message));
					}
				}
			}
			return num;
		}

		private static string ReadAssetName(AssetsFileInstance af, AssetFileInfo info, ManualLogSource? diagLog = null)
		{
			AssetsFileReader reader = af.file.Reader;
			long absoluteByteOffset = info.GetAbsoluteByteOffset(af.file);
			if (diagLog != null)
			{
				try
				{
					reader.Position = absoluteByteOffset;
					byte[] array = ((BinaryReader)(object)reader).ReadBytes(Math.Min(32, (int)info.ByteSize));
					diagLog.LogInfo((object)$"[Diag] pathId={info.PathId} baseOffset={absoluteByteOffset} byteSize={info.ByteSize} bytes=[{BitConverter.ToString(array)}]");
				}
				catch (Exception ex)
				{
					diagLog.LogInfo((object)$"[Diag] pathId={info.PathId} peek failed: {ex.Message}");
				}
			}
			for (long num = absoluteByteOffset; num <= absoluteByteOffset + info.ByteSize - 4; num += 4)
			{
				try
				{
					reader.Position = num;
					int num2 = ((BinaryReader)(object)reader).ReadInt32();
					if (num2 >= 3 

plugins/AssetsTools.NET.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using AssetsTools.NET.Extra;
using AssetsTools.NET.Extra.Decompressors.LZ4;
using LZ4ps;
using SevenZip;
using SevenZip.Compression.LZ;
using SevenZip.Compression.LZMA;
using SevenZip.Compression.RangeCoder;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AssetsTools.NET")]
[assembly: AssemblyDescription("A remake and port of SeriousCache's AssetTools")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nesrak1")]
[assembly: AssemblyProduct("AssetsTools.NET")]
[assembly: AssemblyCopyright("Written by nes")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e09d5ac2-1a2e-4ec1-94ad-3f5e22f17658")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]
[assembly: AssemblyVersion("3.0.0.0")]
namespace SevenZip
{
	internal class CRC
	{
		public static readonly uint[] Table;

		private uint _value = uint.MaxValue;

		static CRC()
		{
			Table = new uint[256];
			for (uint num = 0u; num < 256; num++)
			{
				uint num2 = num;
				for (int i = 0; i < 8; i++)
				{
					num2 = (((num2 & 1) == 0) ? (num2 >> 1) : ((num2 >> 1) ^ 0xEDB88320u));
				}
				Table[num] = num2;
			}
		}

		public void Init()
		{
			_value = uint.MaxValue;
		}

		public void UpdateByte(byte b)
		{
			_value = Table[(byte)_value ^ b] ^ (_value >> 8);
		}

		public void Update(byte[] data, uint offset, uint size)
		{
			for (uint num = 0u; num < size; num++)
			{
				_value = Table[(byte)_value ^ data[offset + num]] ^ (_value >> 8);
			}
		}

		public uint GetDigest()
		{
			return _value ^ 0xFFFFFFFFu;
		}

		private static uint CalculateDigest(byte[] data, uint offset, uint size)
		{
			CRC cRC = new CRC();
			cRC.Update(data, offset, size);
			return cRC.GetDigest();
		}

		private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
		{
			return CalculateDigest(data, offset, size) == digest;
		}
	}
	internal class DataErrorException : ApplicationException
	{
		public DataErrorException()
			: base("Data Error")
		{
		}
	}
	internal class InvalidParamException : ApplicationException
	{
		public InvalidParamException()
			: base("Invalid Parameter")
		{
		}
	}
	public interface ICodeProgress
	{
		void SetProgress(long inSize, long outSize);
	}
	public interface ICoder
	{
		void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress);
	}
	public enum CoderPropID
	{
		DefaultProp,
		DictionarySize,
		UsedMemorySize,
		Order,
		BlockSize,
		PosStateBits,
		LitContextBits,
		LitPosBits,
		NumFastBytes,
		MatchFinder,
		MatchFinderCycles,
		NumPasses,
		Algorithm,
		NumThreads,
		EndMarker
	}
	public interface ISetCoderProperties
	{
		void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
	}
	public interface IWriteCoderProperties
	{
		void WriteCoderProperties(Stream outStream);
	}
	public interface ISetDecoderProperties
	{
		void SetDecoderProperties(byte[] properties);
	}
}
namespace SevenZip.Compression.RangeCoder
{
	internal class Encoder
	{
		public const uint kTopValue = 16777216u;

		private Stream Stream;

		public ulong Low;

		public uint Range;

		private uint _cacheSize;

		private byte _cache;

		private long StartPosition;

		public void SetStream(Stream stream)
		{
			Stream = stream;
		}

		public void ReleaseStream()
		{
			Stream = null;
		}

		public void Init()
		{
			StartPosition = Stream.Position;
			Low = 0uL;
			Range = uint.MaxValue;
			_cacheSize = 1u;
			_cache = 0;
		}

		public void FlushData()
		{
			for (int i = 0; i < 5; i++)
			{
				ShiftLow();
			}
		}

		public void FlushStream()
		{
			Stream.Flush();
		}

		public void CloseStream()
		{
			Stream.Close();
		}

		public void Encode(uint start, uint size, uint total)
		{
			Low += start * (Range /= total);
			Range *= size;
			while (Range < 16777216)
			{
				Range <<= 8;
				ShiftLow();
			}
		}

		public void ShiftLow()
		{
			if ((uint)Low < 4278190080u || (int)(Low >> 32) == 1)
			{
				byte b = _cache;
				do
				{
					Stream.WriteByte((byte)(b + (Low >> 32)));
					b = byte.MaxValue;
				}
				while (--_cacheSize != 0);
				_cache = (byte)((uint)Low >> 24);
			}
			_cacheSize++;
			Low = (uint)((int)Low << 8);
		}

		public void EncodeDirectBits(uint v, int numTotalBits)
		{
			for (int num = numTotalBits - 1; num >= 0; num--)
			{
				Range >>= 1;
				if (((v >> num) & 1) == 1)
				{
					Low += Range;
				}
				if (Range < 16777216)
				{
					Range <<= 8;
					ShiftLow();
				}
			}
		}

		public void EncodeBit(uint size0, int numTotalBits, uint symbol)
		{
			uint num = (Range >> numTotalBits) * size0;
			if (symbol == 0)
			{
				Range = num;
			}
			else
			{
				Low += num;
				Range -= num;
			}
			while (Range < 16777216)
			{
				Range <<= 8;
				ShiftLow();
			}
		}

		public long GetProcessedSizeAdd()
		{
			return _cacheSize + Stream.Position - StartPosition + 4;
		}
	}
	internal class Decoder
	{
		public const uint kTopValue = 16777216u;

		public uint Range;

		public uint Code;

		public Stream Stream;

		public void Init(Stream stream)
		{
			Stream = stream;
			Code = 0u;
			Range = uint.MaxValue;
			for (int i = 0; i < 5; i++)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
			}
		}

		public void ReleaseStream()
		{
			Stream = null;
		}

		public void CloseStream()
		{
			Stream.Close();
		}

		public void Normalize()
		{
			while (Range < 16777216)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
				Range <<= 8;
			}
		}

		public void Normalize2()
		{
			if (Range < 16777216)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
				Range <<= 8;
			}
		}

		public uint GetThreshold(uint total)
		{
			return Code / (Range /= total);
		}

		public void Decode(uint start, uint size, uint total)
		{
			Code -= start * Range;
			Range *= size;
			Normalize();
		}

		public uint DecodeDirectBits(int numTotalBits)
		{
			uint num = Range;
			uint num2 = Code;
			uint num3 = 0u;
			for (int num4 = numTotalBits; num4 > 0; num4--)
			{
				num >>= 1;
				uint num5 = num2 - num >> 31;
				num2 -= num & (num5 - 1);
				num3 = (num3 << 1) | (1 - num5);
				if (num < 16777216)
				{
					num2 = (num2 << 8) | (byte)Stream.ReadByte();
					num <<= 8;
				}
			}
			Range = num;
			Code = num2;
			return num3;
		}

		public uint DecodeBit(uint size0, int numTotalBits)
		{
			uint num = (Range >> numTotalBits) * size0;
			uint result;
			if (Code < num)
			{
				result = 0u;
				Range = num;
			}
			else
			{
				result = 1u;
				Code -= num;
				Range -= num;
			}
			Normalize();
			return result;
		}
	}
	internal struct BitEncoder
	{
		public const int kNumBitModelTotalBits = 11;

		public const uint kBitModelTotal = 2048u;

		private const int kNumMoveBits = 5;

		private const int kNumMoveReducingBits = 2;

		public const int kNumBitPriceShiftBits = 6;

		private uint Prob;

		private static uint[] ProbPrices;

		public void Init()
		{
			Prob = 1024u;
		}

		public void UpdateModel(uint symbol)
		{
			if (symbol == 0)
			{
				Prob += 2048 - Prob >> 5;
			}
			else
			{
				Prob -= Prob >> 5;
			}
		}

		public void Encode(Encoder encoder, uint symbol)
		{
			uint num = (encoder.Range >> 11) * Prob;
			if (symbol == 0)
			{
				encoder.Range = num;
				Prob += 2048 - Prob >> 5;
			}
			else
			{
				encoder.Low += num;
				encoder.Range -= num;
				Prob -= Prob >> 5;
			}
			if (encoder.Range < 16777216)
			{
				encoder.Range <<= 8;
				encoder.ShiftLow();
			}
		}

		static BitEncoder()
		{
			ProbPrices = new uint[512];
			for (int num = 8; num >= 0; num--)
			{
				int num2 = 1 << 9 - num - 1;
				uint num3 = (uint)(1 << 9 - num);
				for (uint num4 = (uint)num2; num4 < num3; num4++)
				{
					ProbPrices[num4] = (uint)(num << 6) + (num3 - num4 << 6 >> 9 - num - 1);
				}
			}
		}

		public uint GetPrice(uint symbol)
		{
			return ProbPrices[(((Prob - symbol) ^ (int)(0 - symbol)) & 0x7FF) >> 2];
		}

		public uint GetPrice0()
		{
			return ProbPrices[Prob >> 2];
		}

		public uint GetPrice1()
		{
			return ProbPrices[2048 - Prob >> 2];
		}
	}
	internal struct BitDecoder
	{
		public const int kNumBitModelTotalBits = 11;

		public const uint kBitModelTotal = 2048u;

		private const int kNumMoveBits = 5;

		private uint Prob;

		public void UpdateModel(int numMoveBits, uint symbol)
		{
			if (symbol == 0)
			{
				Prob += 2048 - Prob >> numMoveBits;
			}
			else
			{
				Prob -= Prob >> numMoveBits;
			}
		}

		public void Init()
		{
			Prob = 1024u;
		}

		public uint Decode(Decoder rangeDecoder)
		{
			uint num = (rangeDecoder.Range >> 11) * Prob;
			if (rangeDecoder.Code < num)
			{
				rangeDecoder.Range = num;
				Prob += 2048 - Prob >> 5;
				if (rangeDecoder.Range < 16777216)
				{
					rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
					rangeDecoder.Range <<= 8;
				}
				return 0u;
			}
			rangeDecoder.Range -= num;
			rangeDecoder.Code -= num;
			Prob -= Prob >> 5;
			if (rangeDecoder.Range < 16777216)
			{
				rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
				rangeDecoder.Range <<= 8;
			}
			return 1u;
		}
	}
	internal struct BitTreeEncoder
	{
		private BitEncoder[] Models;

		private int NumBitLevels;

		public BitTreeEncoder(int numBitLevels)
		{
			NumBitLevels = numBitLevels;
			Models = new BitEncoder[1 << numBitLevels];
		}

		public void Init()
		{
			for (uint num = 1u; num < 1 << NumBitLevels; num++)
			{
				Models[num].Init();
			}
		}

		public void Encode(Encoder rangeEncoder, uint symbol)
		{
			uint num = 1u;
			int num2 = NumBitLevels;
			while (num2 > 0)
			{
				num2--;
				uint num3 = (symbol >> num2) & 1u;
				Models[num].Encode(rangeEncoder, num3);
				num = (num << 1) | num3;
			}
		}

		public void ReverseEncode(Encoder rangeEncoder, uint symbol)
		{
			uint num = 1u;
			for (uint num2 = 0u; num2 < NumBitLevels; num2++)
			{
				uint num3 = symbol & 1u;
				Models[num].Encode(rangeEncoder, num3);
				num = (num << 1) | num3;
				symbol >>= 1;
			}
		}

		public uint GetPrice(uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			int num3 = NumBitLevels;
			while (num3 > 0)
			{
				num3--;
				uint num4 = (symbol >> num3) & 1u;
				num += Models[num2].GetPrice(num4);
				num2 = (num2 << 1) + num4;
			}
			return num;
		}

		public uint ReverseGetPrice(uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			for (int num3 = NumBitLevels; num3 > 0; num3--)
			{
				uint num4 = symbol & 1u;
				symbol >>= 1;
				num += Models[num2].GetPrice(num4);
				num2 = (num2 << 1) | num4;
			}
			return num;
		}

		public static uint ReverseGetPrice(BitEncoder[] Models, uint startIndex, int NumBitLevels, uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			for (int num3 = NumBitLevels; num3 > 0; num3--)
			{
				uint num4 = symbol & 1u;
				symbol >>= 1;
				num += Models[startIndex + num2].GetPrice(num4);
				num2 = (num2 << 1) | num4;
			}
			return num;
		}

		public static void ReverseEncode(BitEncoder[] Models, uint startIndex, Encoder rangeEncoder, int NumBitLevels, uint symbol)
		{
			uint num = 1u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num2 = symbol & 1u;
				Models[startIndex + num].Encode(rangeEncoder, num2);
				num = (num << 1) | num2;
				symbol >>= 1;
			}
		}
	}
	internal struct BitTreeDecoder
	{
		private BitDecoder[] Models;

		private int NumBitLevels;

		public BitTreeDecoder(int numBitLevels)
		{
			NumBitLevels = numBitLevels;
			Models = new BitDecoder[1 << numBitLevels];
		}

		public void Init()
		{
			for (uint num = 1u; num < 1 << NumBitLevels; num++)
			{
				Models[num].Init();
			}
		}

		public uint Decode(Decoder rangeDecoder)
		{
			uint num = 1u;
			for (int num2 = NumBitLevels; num2 > 0; num2--)
			{
				num = (num << 1) + Models[num].Decode(rangeDecoder);
			}
			return num - (uint)(1 << NumBitLevels);
		}

		public uint ReverseDecode(Decoder rangeDecoder)
		{
			uint num = 1u;
			uint num2 = 0u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num3 = Models[num].Decode(rangeDecoder);
				num <<= 1;
				num += num3;
				num2 |= num3 << i;
			}
			return num2;
		}

		public static uint ReverseDecode(BitDecoder[] Models, uint startIndex, Decoder rangeDecoder, int NumBitLevels)
		{
			uint num = 1u;
			uint num2 = 0u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num3 = Models[startIndex + num].Decode(rangeDecoder);
				num <<= 1;
				num += num3;
				num2 |= num3 << i;
			}
			return num2;
		}
	}
}
namespace SevenZip.Compression.LZ
{
	internal interface IInWindowStream
	{
		void SetStream(Stream inStream);

		void Init();

		void ReleaseStream();

		byte GetIndexByte(int index);

		uint GetMatchLen(int index, uint distance, uint limit);

		uint GetNumAvailableBytes();
	}
	internal interface IMatchFinder : IInWindowStream
	{
		void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter);

		uint GetMatches(uint[] distances);

		void Skip(uint num);
	}
	public class BinTree : InWindow, IMatchFinder, IInWindowStream
	{
		private uint _cyclicBufferPos;

		private uint _cyclicBufferSize;

		private uint _matchMaxLen;

		private uint[] _son;

		private uint[] _hash;

		private uint _cutValue = 255u;

		private uint _hashMask;

		private uint _hashSizeSum;

		private bool HASH_ARRAY = true;

		private const uint kHash2Size = 1024u;

		private const uint kHash3Size = 65536u;

		private const uint kBT2HashSize = 65536u;

		private const uint kStartMaxLen = 1u;

		private const uint kHash3Offset = 1024u;

		private const uint kEmptyHashValue = 0u;

		private const uint kMaxValForNormalize = 2147483647u;

		private uint kNumHashDirectBytes;

		private uint kMinMatchCheck = 4u;

		private uint kFixHashSize = 66560u;

		public void SetType(int numHashBytes)
		{
			HASH_ARRAY = numHashBytes > 2;
			if (HASH_ARRAY)
			{
				kNumHashDirectBytes = 0u;
				kMinMatchCheck = 4u;
				kFixHashSize = 66560u;
			}
			else
			{
				kNumHashDirectBytes = 2u;
				kMinMatchCheck = 3u;
				kFixHashSize = 0u;
			}
		}

		public new void SetStream(Stream stream)
		{
			base.SetStream(stream);
		}

		public new void ReleaseStream()
		{
			base.ReleaseStream();
		}

		public new void Init()
		{
			base.Init();
			for (uint num = 0u; num < _hashSizeSum; num++)
			{
				_hash[num] = 0u;
			}
			_cyclicBufferPos = 0u;
			ReduceOffsets(-1);
		}

		public new void MovePos()
		{
			if (++_cyclicBufferPos >= _cyclicBufferSize)
			{
				_cyclicBufferPos = 0u;
			}
			base.MovePos();
			if (_pos == int.MaxValue)
			{
				Normalize();
			}
		}

		public new byte GetIndexByte(int index)
		{
			return base.GetIndexByte(index);
		}

		public new uint GetMatchLen(int index, uint distance, uint limit)
		{
			return base.GetMatchLen(index, distance, limit);
		}

		public new uint GetNumAvailableBytes()
		{
			return base.GetNumAvailableBytes();
		}

		public void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter)
		{
			if (historySize > 2147483391)
			{
				throw new Exception();
			}
			_cutValue = 16 + (matchMaxLen >> 1);
			uint keepSizeReserv = (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256;
			Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, keepSizeReserv);
			_matchMaxLen = matchMaxLen;
			uint num = historySize + 1;
			if (_cyclicBufferSize != num)
			{
				_son = new uint[(_cyclicBufferSize = num) * 2];
			}
			uint num2 = 65536u;
			if (HASH_ARRAY)
			{
				num2 = historySize - 1;
				num2 |= num2 >> 1;
				num2 |= num2 >> 2;
				num2 |= num2 >> 4;
				num2 |= num2 >> 8;
				num2 >>= 1;
				num2 |= 0xFFFFu;
				if (num2 > 16777216)
				{
					num2 >>= 1;
				}
				_hashMask = num2;
				num2++;
				num2 += kFixHashSize;
			}
			if (num2 != _hashSizeSum)
			{
				_hash = new uint[_hashSizeSum = num2];
			}
		}

		public uint GetMatches(uint[] distances)
		{
			uint num;
			if (_pos + _matchMaxLen <= _streamPos)
			{
				num = _matchMaxLen;
			}
			else
			{
				num = _streamPos - _pos;
				if (num < kMinMatchCheck)
				{
					MovePos();
					return 0u;
				}
			}
			uint num2 = 0u;
			uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u);
			uint num4 = _bufferOffset + _pos;
			uint num5 = 1u;
			uint num6 = 0u;
			uint num7 = 0u;
			uint num10;
			if (HASH_ARRAY)
			{
				uint num8 = CRC.Table[_bufferBase[num4]] ^ _bufferBase[num4 + 1];
				num6 = num8 & 0x3FFu;
				int num9 = (int)num8 ^ (_bufferBase[num4 + 2] << 8);
				num7 = (uint)num9 & 0xFFFFu;
				num10 = ((uint)num9 ^ (CRC.Table[_bufferBase[num4 + 3]] << 5)) & _hashMask;
			}
			else
			{
				num10 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8));
			}
			uint num11 = _hash[kFixHashSize + num10];
			if (HASH_ARRAY)
			{
				uint num12 = _hash[num6];
				uint num13 = _hash[1024 + num7];
				_hash[num6] = _pos;
				_hash[1024 + num7] = _pos;
				if (num12 > num3 && _bufferBase[_bufferOffset + num12] == _bufferBase[num4])
				{
					num5 = (distances[num2++] = 2u);
					distances[num2++] = _pos - num12 - 1;
				}
				if (num13 > num3 && _bufferBase[_bufferOffset + num13] == _bufferBase[num4])
				{
					if (num13 == num12)
					{
						num2 -= 2;
					}
					num5 = (distances[num2++] = 3u);
					distances[num2++] = _pos - num13 - 1;
					num12 = num13;
				}
				if (num2 != 0 && num12 == num11)
				{
					num2 -= 2;
					num5 = 1u;
				}
			}
			_hash[kFixHashSize + num10] = _pos;
			uint num14 = (_cyclicBufferPos << 1) + 1;
			uint num15 = _cyclicBufferPos << 1;
			uint val;
			uint val2 = (val = kNumHashDirectBytes);
			if (kNumHashDirectBytes != 0 && num11 > num3 && _bufferBase[_bufferOffset + num11 + kNumHashDirectBytes] != _bufferBase[num4 + kNumHashDirectBytes])
			{
				num5 = (distances[num2++] = kNumHashDirectBytes);
				distances[num2++] = _pos - num11 - 1;
			}
			uint cutValue = _cutValue;
			while (true)
			{
				if (num11 <= num3 || cutValue-- == 0)
				{
					_son[num14] = (_son[num15] = 0u);
					break;
				}
				uint num16 = _pos - num11;
				uint num17 = ((num16 <= _cyclicBufferPos) ? (_cyclicBufferPos - num16) : (_cyclicBufferPos - num16 + _cyclicBufferSize)) << 1;
				uint num18 = _bufferOffset + num11;
				uint num19 = Math.Min(val2, val);
				if (_bufferBase[num18 + num19] == _bufferBase[num4 + num19])
				{
					while (++num19 != num && _bufferBase[num18 + num19] == _bufferBase[num4 + num19])
					{
					}
					if (num5 < num19)
					{
						num5 = (distances[num2++] = num19);
						distances[num2++] = num16 - 1;
						if (num19 == num)
						{
							_son[num15] = _son[num17];
							_son[num14] = _son[num17 + 1];
							break;
						}
					}
				}
				if (_bufferBase[num18 + num19] < _bufferBase[num4 + num19])
				{
					_son[num15] = num11;
					num15 = num17 + 1;
					num11 = _son[num15];
					val = num19;
				}
				else
				{
					_son[num14] = num11;
					num14 = num17;
					num11 = _son[num14];
					val2 = num19;
				}
			}
			MovePos();
			return num2;
		}

		public void Skip(uint num)
		{
			do
			{
				uint num2;
				if (_pos + _matchMaxLen <= _streamPos)
				{
					num2 = _matchMaxLen;
				}
				else
				{
					num2 = _streamPos - _pos;
					if (num2 < kMinMatchCheck)
					{
						MovePos();
						continue;
					}
				}
				uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u);
				uint num4 = _bufferOffset + _pos;
				uint num9;
				if (HASH_ARRAY)
				{
					uint num5 = CRC.Table[_bufferBase[num4]] ^ _bufferBase[num4 + 1];
					uint num6 = num5 & 0x3FFu;
					_hash[num6] = _pos;
					int num7 = (int)num5 ^ (_bufferBase[num4 + 2] << 8);
					uint num8 = (uint)num7 & 0xFFFFu;
					_hash[1024 + num8] = _pos;
					num9 = ((uint)num7 ^ (CRC.Table[_bufferBase[num4 + 3]] << 5)) & _hashMask;
				}
				else
				{
					num9 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8));
				}
				uint num10 = _hash[kFixHashSize + num9];
				_hash[kFixHashSize + num9] = _pos;
				uint num11 = (_cyclicBufferPos << 1) + 1;
				uint num12 = _cyclicBufferPos << 1;
				uint val;
				uint val2 = (val = kNumHashDirectBytes);
				uint cutValue = _cutValue;
				while (true)
				{
					if (num10 <= num3 || cutValue-- == 0)
					{
						_son[num11] = (_son[num12] = 0u);
						break;
					}
					uint num13 = _pos - num10;
					uint num14 = ((num13 <= _cyclicBufferPos) ? (_cyclicBufferPos - num13) : (_cyclicBufferPos - num13 + _cyclicBufferSize)) << 1;
					uint num15 = _bufferOffset + num10;
					uint num16 = Math.Min(val2, val);
					if (_bufferBase[num15 + num16] == _bufferBase[num4 + num16])
					{
						while (++num16 != num2 && _bufferBase[num15 + num16] == _bufferBase[num4 + num16])
						{
						}
						if (num16 == num2)
						{
							_son[num12] = _son[num14];
							_son[num11] = _son[num14 + 1];
							break;
						}
					}
					if (_bufferBase[num15 + num16] < _bufferBase[num4 + num16])
					{
						_son[num12] = num10;
						num12 = num14 + 1;
						num10 = _son[num12];
						val = num16;
					}
					else
					{
						_son[num11] = num10;
						num11 = num14;
						num10 = _son[num11];
						val2 = num16;
					}
				}
				MovePos();
			}
			while (--num != 0);
		}

		private void NormalizeLinks(uint[] items, uint numItems, uint subValue)
		{
			for (uint num = 0u; num < numItems; num++)
			{
				uint num2 = items[num];
				num2 = ((num2 > subValue) ? (num2 - subValue) : 0u);
				items[num] = num2;
			}
		}

		private void Normalize()
		{
			uint subValue = _pos - _cyclicBufferSize;
			NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
			NormalizeLinks(_hash, _hashSizeSum, subValue);
			ReduceOffsets((int)subValue);
		}

		public void SetCutValue(uint cutValue)
		{
			_cutValue = cutValue;
		}
	}
	public class InWindow
	{
		public byte[] _bufferBase;

		private Stream _stream;

		private uint _posLimit;

		private bool _streamEndWasReached;

		private uint _pointerToLastSafePosition;

		public uint _bufferOffset;

		public uint _blockSize;

		public uint _pos;

		private uint _keepSizeBefore;

		private uint _keepSizeAfter;

		public uint _streamPos;

		public void MoveBlock()
		{
			uint num = _bufferOffset + _pos - _keepSizeBefore;
			if (num != 0)
			{
				num--;
			}
			uint num2 = _bufferOffset + _streamPos - num;
			for (uint num3 = 0u; num3 < num2; num3++)
			{
				_bufferBase[num3] = _bufferBase[num + num3];
			}
			_bufferOffset -= num;
		}

		public virtual void ReadBlock()
		{
			if (_streamEndWasReached)
			{
				return;
			}
			while (true)
			{
				int num = (int)(0 - _bufferOffset + _blockSize - _streamPos);
				if (num == 0)
				{
					return;
				}
				int num2 = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), num);
				if (num2 == 0)
				{
					break;
				}
				_streamPos += (uint)num2;
				if (_streamPos >= _pos + _keepSizeAfter)
				{
					_posLimit = _streamPos - _keepSizeAfter;
				}
			}
			_posLimit = _streamPos;
			if (_bufferOffset + _posLimit > _pointerToLastSafePosition)
			{
				_posLimit = _pointerToLastSafePosition - _bufferOffset;
			}
			_streamEndWasReached = true;
		}

		private void Free()
		{
			_bufferBase = null;
		}

		public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv)
		{
			_keepSizeBefore = keepSizeBefore;
			_keepSizeAfter = keepSizeAfter;
			uint num = keepSizeBefore + keepSizeAfter + keepSizeReserv;
			if (_bufferBase == null || _blockSize != num)
			{
				Free();
				_blockSize = num;
				_bufferBase = new byte[_blockSize];
			}
			_pointerToLastSafePosition = _blockSize - keepSizeAfter;
		}

		public void SetStream(Stream stream)
		{
			_stream = stream;
		}

		public void ReleaseStream()
		{
			_stream = null;
		}

		public void Init()
		{
			_bufferOffset = 0u;
			_pos = 0u;
			_streamPos = 0u;
			_streamEndWasReached = false;
			ReadBlock();
		}

		public void MovePos()
		{
			_pos++;
			if (_pos > _posLimit)
			{
				if (_bufferOffset + _pos > _pointerToLastSafePosition)
				{
					MoveBlock();
				}
				ReadBlock();
			}
		}

		public byte GetIndexByte(int index)
		{
			return _bufferBase[_bufferOffset + _pos + index];
		}

		public uint GetMatchLen(int index, uint distance, uint limit)
		{
			if (_streamEndWasReached && _pos + index + limit > _streamPos)
			{
				limit = _streamPos - (uint)(int)(_pos + index);
			}
			distance++;
			uint num = _bufferOffset + _pos + (uint)index;
			uint num2;
			for (num2 = 0u; num2 < limit && _bufferBase[num + num2] == _bufferBase[num + num2 - distance]; num2++)
			{
			}
			return num2;
		}

		public uint GetNumAvailableBytes()
		{
			return _streamPos - _pos;
		}

		public void ReduceOffsets(int subValue)
		{
			_bufferOffset += (uint)subValue;
			_posLimit -= (uint)subValue;
			_pos -= (uint)subValue;
			_streamPos -= (uint)subValue;
		}
	}
	public class OutWindow
	{
		private byte[] _buffer;

		private uint _pos;

		private uint _windowSize;

		private uint _streamPos;

		private Stream _stream;

		public uint TrainSize;

		public void Create(uint windowSize)
		{
			if (_windowSize != windowSize)
			{
				_buffer = new byte[windowSize];
			}
			_windowSize = windowSize;
			_pos = 0u;
			_streamPos = 0u;
		}

		public void Init(Stream stream, bool solid)
		{
			ReleaseStream();
			_stream = stream;
			if (!solid)
			{
				_streamPos = 0u;
				_pos = 0u;
				TrainSize = 0u;
			}
		}

		public bool Train(Stream stream)
		{
			long length = stream.Length;
			uint num = (TrainSize = (uint)((length < _windowSize) ? length : _windowSize));
			stream.Position = length - num;
			_streamPos = (_pos = 0u);
			while (num != 0)
			{
				uint num2 = _windowSize - _pos;
				if (num < num2)
				{
					num2 = num;
				}
				int num3 = stream.Read(_buffer, (int)_pos, (int)num2);
				if (num3 == 0)
				{
					return false;
				}
				num -= (uint)num3;
				_pos += (uint)num3;
				_streamPos += (uint)num3;
				if (_pos == _windowSize)
				{
					_streamPos = (_pos = 0u);
				}
			}
			return true;
		}

		public void ReleaseStream()
		{
			Flush();
			_stream = null;
		}

		public void Flush()
		{
			uint num = _pos - _streamPos;
			if (num != 0)
			{
				_stream.Write(_buffer, (int)_streamPos, (int)num);
				if (_pos >= _windowSize)
				{
					_pos = 0u;
				}
				_streamPos = _pos;
			}
		}

		public void CopyBlock(uint distance, uint len)
		{
			uint num = _pos - distance - 1;
			if (num >= _windowSize)
			{
				num += _windowSize;
			}
			while (len != 0)
			{
				if (num >= _windowSize)
				{
					num = 0u;
				}
				_buffer[_pos++] = _buffer[num++];
				if (_pos >= _windowSize)
				{
					Flush();
				}
				len--;
			}
		}

		public void PutByte(byte b)
		{
			_buffer[_pos++] = b;
			if (_pos >= _windowSize)
			{
				Flush();
			}
		}

		public byte GetByte(uint distance)
		{
			uint num = _pos - distance - 1;
			if (num >= _windowSize)
			{
				num += _windowSize;
			}
			return _buffer[num];
		}
	}
}
namespace SevenZip.Compression.LZMA
{
	internal abstract class Base
	{
		public struct State
		{
			public uint Index;

			public void Init()
			{
				Index = 0u;
			}

			public void UpdateChar()
			{
				if (Index < 4)
				{
					Index = 0u;
				}
				else if (Index < 10)
				{
					Index -= 3u;
				}
				else
				{
					Index -= 6u;
				}
			}

			public void UpdateMatch()
			{
				Index = ((Index < 7) ? 7u : 10u);
			}

			public void UpdateRep()
			{
				Index = ((Index < 7) ? 8u : 11u);
			}

			public void UpdateShortRep()
			{
				Index = ((Index < 7) ? 9u : 11u);
			}

			public bool IsCharState()
			{
				return Index < 7;
			}
		}

		public const uint kNumRepDistances = 4u;

		public const uint kNumStates = 12u;

		public const int kNumPosSlotBits = 6;

		public const int kDicLogSizeMin = 0;

		public const int kNumLenToPosStatesBits = 2;

		public const uint kNumLenToPosStates = 4u;

		public const uint kMatchMinLen = 2u;

		public const int kNumAlignBits = 4;

		public const uint kAlignTableSize = 16u;

		public const uint kAlignMask = 15u;

		public const uint kStartPosModelIndex = 4u;

		public const uint kEndPosModelIndex = 14u;

		public const uint kNumPosModels = 10u;

		public const uint kNumFullDistances = 128u;

		public const uint kNumLitPosStatesBitsEncodingMax = 4u;

		public const uint kNumLitContextBitsMax = 8u;

		public const int kNumPosStatesBitsMax = 4;

		public const uint kNumPosStatesMax = 16u;

		public const int kNumPosStatesBitsEncodingMax = 4;

		public const uint kNumPosStatesEncodingMax = 16u;

		public const int kNumLowLenBits = 3;

		public const int kNumMidLenBits = 3;

		public const int kNumHighLenBits = 8;

		public const uint kNumLowLenSymbols = 8u;

		public const uint kNumMidLenSymbols = 8u;

		public const uint kNumLenSymbols = 272u;

		public const uint kMatchMaxLen = 273u;

		public static uint GetLenToPosState(uint len)
		{
			len -= 2;
			if (len < 4)
			{
				return len;
			}
			return 3u;
		}
	}
	public class Decoder : ICoder, ISetDecoderProperties
	{
		private class LenDecoder
		{
			private BitDecoder m_Choice;

			private BitDecoder m_Choice2;

			private BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[16];

			private BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[16];

			private BitTreeDecoder m_HighCoder = new BitTreeDecoder(8);

			private uint m_NumPosStates;

			public void Create(uint numPosStates)
			{
				for (uint num = m_NumPosStates; num < numPosStates; num++)
				{
					m_LowCoder[num] = new BitTreeDecoder(3);
					m_MidCoder[num] = new BitTreeDecoder(3);
				}
				m_NumPosStates = numPosStates;
			}

			public void Init()
			{
				m_Choice.Init();
				for (uint num = 0u; num < m_NumPosStates; num++)
				{
					m_LowCoder[num].Init();
					m_MidCoder[num].Init();
				}
				m_Choice2.Init();
				m_HighCoder.Init();
			}

			public uint Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint posState)
			{
				if (m_Choice.Decode(rangeDecoder) == 0)
				{
					return m_LowCoder[posState].Decode(rangeDecoder);
				}
				uint num = 8u;
				if (m_Choice2.Decode(rangeDecoder) == 0)
				{
					return num + m_MidCoder[posState].Decode(rangeDecoder);
				}
				num += 8;
				return num + m_HighCoder.Decode(rangeDecoder);
			}
		}

		private class LiteralDecoder
		{
			private struct Decoder2
			{
				private BitDecoder[] m_Decoders;

				public void Create()
				{
					m_Decoders = new BitDecoder[768];
				}

				public void Init()
				{
					for (int i = 0; i < 768; i++)
					{
						m_Decoders[i].Init();
					}
				}

				public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder)
				{
					uint num = 1u;
					do
					{
						num = (num << 1) | m_Decoders[num].Decode(rangeDecoder);
					}
					while (num < 256);
					return (byte)num;
				}

				public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte)
				{
					uint num = 1u;
					do
					{
						uint num2 = (uint)(matchByte >> 7) & 1u;
						matchByte <<= 1;
						uint num3 = m_Decoders[(1 + num2 << 8) + num].Decode(rangeDecoder);
						num = (num << 1) | num3;
						if (num2 != num3)
						{
							while (num < 256)
							{
								num = (num << 1) | m_Decoders[num].Decode(rangeDecoder);
							}
							break;
						}
					}
					while (num < 256);
					return (byte)num;
				}
			}

			private Decoder2[] m_Coders;

			private int m_NumPrevBits;

			private int m_NumPosBits;

			private uint m_PosMask;

			public void Create(int numPosBits, int numPrevBits)
			{
				if (m_Coders == null || m_NumPrevBits != numPrevBits || m_NumPosBits != numPosBits)
				{
					m_NumPosBits = numPosBits;
					m_PosMask = (uint)((1 << numPosBits) - 1);
					m_NumPrevBits = numPrevBits;
					uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
					m_Coders = new Decoder2[num];
					for (uint num2 = 0u; num2 < num; num2++)
					{
						m_Coders[num2].Create();
					}
				}
			}

			public void Init()
			{
				uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
				for (uint num2 = 0u; num2 < num; num2++)
				{
					m_Coders[num2].Init();
				}
			}

			private uint GetState(uint pos, byte prevByte)
			{
				return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> 8 - m_NumPrevBits);
			}

			public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
			{
				return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder);
			}

			public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
			{
				return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte);
			}
		}

		private OutWindow m_OutWindow = new OutWindow();

		private SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();

		private BitDecoder[] m_IsMatchDecoders = new BitDecoder[192];

		private BitDecoder[] m_IsRepDecoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG0Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG1Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG2Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[192];

		private BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[4];

		private BitDecoder[] m_PosDecoders = new BitDecoder[114];

		private BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(4);

		private LenDecoder m_LenDecoder = new LenDecoder();

		private LenDecoder m_RepLenDecoder = new LenDecoder();

		private LiteralDecoder m_LiteralDecoder = new LiteralDecoder();

		private uint m_DictionarySize;

		private uint m_DictionarySizeCheck;

		private uint m_PosStateMask;

		private bool _solid;

		public Decoder()
		{
			m_DictionarySize = uint.MaxValue;
			for (int i = 0; (long)i < 4L; i++)
			{
				m_PosSlotDecoder[i] = new BitTreeDecoder(6);
			}
		}

		private void SetDictionarySize(uint dictionarySize)
		{
			if (m_DictionarySize != dictionarySize)
			{
				m_DictionarySize = dictionarySize;
				m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1u);
				uint windowSize = Math.Max(m_DictionarySizeCheck, 4096u);
				m_OutWindow.Create(windowSize);
			}
		}

		private void SetLiteralProperties(int lp, int lc)
		{
			if (lp > 8)
			{
				throw new InvalidParamException();
			}
			if (lc > 8)
			{
				throw new InvalidParamException();
			}
			m_LiteralDecoder.Create(lp, lc);
		}

		private void SetPosBitsProperties(int pb)
		{
			if (pb > 4)
			{
				throw new InvalidParamException();
			}
			uint num = (uint)(1 << pb);
			m_LenDecoder.Create(num);
			m_RepLenDecoder.Create(num);
			m_PosStateMask = num - 1;
		}

		private void Init(Stream inStream, Stream outStream)
		{
			m_RangeDecoder.Init(inStream);
			m_OutWindow.Init(outStream, _solid);
			for (uint num = 0u; num < 12; num++)
			{
				for (uint num2 = 0u; num2 <= m_PosStateMask; num2++)
				{
					uint num3 = (num << 4) + num2;
					m_IsMatchDecoders[num3].Init();
					m_IsRep0LongDecoders[num3].Init();
				}
				m_IsRepDecoders[num].Init();
				m_IsRepG0Decoders[num].Init();
				m_IsRepG1Decoders[num].Init();
				m_IsRepG2Decoders[num].Init();
			}
			m_LiteralDecoder.Init();
			for (uint num = 0u; num < 4; num++)
			{
				m_PosSlotDecoder[num].Init();
			}
			for (uint num = 0u; num < 114; num++)
			{
				m_PosDecoders[num].Init();
			}
			m_LenDecoder.Init();
			m_RepLenDecoder.Init();
			m_PosAlignDecoder.Init();
		}

		public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress)
		{
			Init(inStream, outStream);
			Base.State state = default(Base.State);
			state.Init();
			uint num = 0u;
			uint num2 = 0u;
			uint num3 = 0u;
			uint num4 = 0u;
			ulong num5 = 0uL;
			if (num5 < (ulong)outSize)
			{
				if (m_IsMatchDecoders[state.Index << 4].Decode(m_RangeDecoder) != 0)
				{
					throw new DataErrorException();
				}
				state.UpdateChar();
				byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0u, 0);
				m_OutWindow.PutByte(b);
				num5++;
			}
			while (num5 < (ulong)outSize)
			{
				uint num6 = (uint)(int)num5 & m_PosStateMask;
				if (m_IsMatchDecoders[(state.Index << 4) + num6].Decode(m_RangeDecoder) == 0)
				{
					byte @byte = m_OutWindow.GetByte(0u);
					byte b2 = (state.IsCharState() ? m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)num5, @byte) : m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, (uint)num5, @byte, m_OutWindow.GetByte(num)));
					m_OutWindow.PutByte(b2);
					state.UpdateChar();
					num5++;
					continue;
				}
				uint num8;
				if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
				{
					if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
					{
						if (m_IsRep0LongDecoders[(state.Index << 4) + num6].Decode(m_RangeDecoder) == 0)
						{
							state.UpdateShortRep();
							m_OutWindow.PutByte(m_OutWindow.GetByte(num));
							num5++;
							continue;
						}
					}
					else
					{
						uint num7;
						if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
						{
							num7 = num2;
						}
						else
						{
							if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
							{
								num7 = num3;
							}
							else
							{
								num7 = num4;
								num4 = num3;
							}
							num3 = num2;
						}
						num2 = num;
						num = num7;
					}
					num8 = m_RepLenDecoder.Decode(m_RangeDecoder, num6) + 2;
					state.UpdateRep();
				}
				else
				{
					num4 = num3;
					num3 = num2;
					num2 = num;
					num8 = 2 + m_LenDecoder.Decode(m_RangeDecoder, num6);
					state.UpdateMatch();
					uint num9 = m_PosSlotDecoder[Base.GetLenToPosState(num8)].Decode(m_RangeDecoder);
					if (num9 >= 4)
					{
						int num10 = (int)((num9 >> 1) - 1);
						num = (2 | (num9 & 1)) << num10;
						if (num9 < 14)
						{
							num += BitTreeDecoder.ReverseDecode(m_PosDecoders, num - num9 - 1, m_RangeDecoder, num10);
						}
						else
						{
							num += m_RangeDecoder.DecodeDirectBits(num10 - 4) << 4;
							num += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
						}
					}
					else
					{
						num = num9;
					}
				}
				if (num >= m_OutWindow.TrainSize + num5 || num >= m_DictionarySizeCheck)
				{
					if (num == uint.MaxValue)
					{
						break;
					}
					throw new DataErrorException();
				}
				m_OutWindow.CopyBlock(num, num8);
				num5 += num8;
			}
			m_OutWindow.Flush();
			m_OutWindow.ReleaseStream();
			m_RangeDecoder.ReleaseStream();
		}

		public void SetDecoderProperties(byte[] properties)
		{
			if (properties.Length < 5)
			{
				throw new InvalidParamException();
			}
			int lc = properties[0] % 9;
			int num = properties[0] / 9;
			int lp = num % 5;
			int num2 = num / 5;
			if (num2 > 4)
			{
				throw new InvalidParamException();
			}
			uint num3 = 0u;
			for (int i = 0; i < 4; i++)
			{
				num3 += (uint)(properties[1 + i] << i * 8);
			}
			SetDictionarySize(num3);
			SetLiteralProperties(lp, lc);
			SetPosBitsProperties(num2);
		}

		public bool Train(Stream stream)
		{
			_solid = true;
			return m_OutWindow.Train(stream);
		}
	}
	public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
	{
		private enum EMatchFinderType
		{
			BT2,
			BT4
		}

		private class LiteralEncoder
		{
			public struct Encoder2
			{
				private BitEncoder[] m_Encoders;

				public void Create()
				{
					m_Encoders = new BitEncoder[768];
				}

				public void Init()
				{
					for (int i = 0; i < 768; i++)
					{
						m_Encoders[i].Init();
					}
				}

				public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol)
				{
					uint num = 1u;
					for (int num2 = 7; num2 >= 0; num2--)
					{
						uint num3 = (uint)(symbol >> num2) & 1u;
						m_Encoders[num].Encode(rangeEncoder, num3);
						num = (num << 1) | num3;
					}
				}

				public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
				{
					uint num = 1u;
					bool flag = true;
					for (int num2 = 7; num2 >= 0; num2--)
					{
						uint num3 = (uint)(symbol >> num2) & 1u;
						uint num4 = num;
						if (flag)
						{
							uint num5 = (uint)(matchByte >> num2) & 1u;
							num4 += 1 + num5 << 8;
							flag = num5 == num3;
						}
						m_Encoders[num4].Encode(rangeEncoder, num3);
						num = (num << 1) | num3;
					}
				}

				public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
				{
					uint num = 0u;
					uint num2 = 1u;
					int num3 = 7;
					if (matchMode)
					{
						while (num3 >= 0)
						{
							uint num4 = (uint)(matchByte >> num3) & 1u;
							uint num5 = (uint)(symbol >> num3) & 1u;
							num += m_Encoders[(1 + num4 << 8) + num2].GetPrice(num5);
							num2 = (num2 << 1) | num5;
							if (num4 != num5)
							{
								num3--;
								break;
							}
							num3--;
						}
					}
					while (num3 >= 0)
					{
						uint num6 = (uint)(symbol >> num3) & 1u;
						num += m_Encoders[num2].GetPrice(num6);
						num2 = (num2 << 1) | num6;
						num3--;
					}
					return num;
				}
			}

			private Encoder2[] m_Coders;

			private int m_NumPrevBits;

			private int m_NumPosBits;

			private uint m_PosMask;

			public void Create(int numPosBits, int numPrevBits)
			{
				if (m_Coders == null || m_NumPrevBits != numPrevBits || m_NumPosBits != numPosBits)
				{
					m_NumPosBits = numPosBits;
					m_PosMask = (uint)((1 << numPosBits) - 1);
					m_NumPrevBits = numPrevBits;
					uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
					m_Coders = new Encoder2[num];
					for (uint num2 = 0u; num2 < num; num2++)
					{
						m_Coders[num2].Create();
					}
				}
			}

			public void Init()
			{
				uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
				for (uint num2 = 0u; num2 < num; num2++)
				{
					m_Coders[num2].Init();
				}
			}

			public Encoder2 GetSubCoder(uint pos, byte prevByte)
			{
				return m_Coders[(int)((pos & m_PosMask) << m_NumPrevBits) + (prevByte >> 8 - m_NumPrevBits)];
			}
		}

		private class LenEncoder
		{
			private BitEncoder _choice;

			private BitEncoder _choice2;

			private BitTreeEncoder[] _lowCoder = new BitTreeEncoder[16];

			private BitTreeEncoder[] _midCoder = new BitTreeEncoder[16];

			private BitTreeEncoder _highCoder = new BitTreeEncoder(8);

			public LenEncoder()
			{
				for (uint num = 0u; num < 16; num++)
				{
					_lowCoder[num] = new BitTreeEncoder(3);
					_midCoder[num] = new BitTreeEncoder(3);
				}
			}

			public void Init(uint numPosStates)
			{
				_choice.Init();
				_choice2.Init();
				for (uint num = 0u; num < numPosStates; num++)
				{
					_lowCoder[num].Init();
					_midCoder[num].Init();
				}
				_highCoder.Init();
			}

			public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState)
			{
				if (symbol < 8)
				{
					_choice.Encode(rangeEncoder, 0u);
					_lowCoder[posState].Encode(rangeEncoder, symbol);
					return;
				}
				symbol -= 8;
				_choice.Encode(rangeEncoder, 1u);
				if (symbol < 8)
				{
					_choice2.Encode(rangeEncoder, 0u);
					_midCoder[posState].Encode(rangeEncoder, symbol);
				}
				else
				{
					_choice2.Encode(rangeEncoder, 1u);
					_highCoder.Encode(rangeEncoder, symbol - 8);
				}
			}

			public void SetPrices(uint posState, uint numSymbols, uint[] prices, uint st)
			{
				uint price = _choice.GetPrice0();
				uint price2 = _choice.GetPrice1();
				uint num = price2 + _choice2.GetPrice0();
				uint num2 = price2 + _choice2.GetPrice1();
				uint num3 = 0u;
				for (num3 = 0u; num3 < 8; num3++)
				{
					if (num3 >= numSymbols)
					{
						return;
					}
					prices[st + num3] = price + _lowCoder[posState].GetPrice(num3);
				}
				for (; num3 < 16; num3++)
				{
					if (num3 >= numSymbols)
					{
						return;
					}
					prices[st + num3] = num + _midCoder[posState].GetPrice(num3 - 8);
				}
				for (; num3 < numSymbols; num3++)
				{
					prices[st + num3] = num2 + _highCoder.GetPrice(num3 - 8 - 8);
				}
			}
		}

		private class LenPriceTableEncoder : LenEncoder
		{
			private uint[] _prices = new uint[4352];

			private uint _tableSize;

			private uint[] _counters = new uint[16];

			public void SetTableSize(uint tableSize)
			{
				_tableSize = tableSize;
			}

			public uint GetPrice(uint symbol, uint posState)
			{
				return _prices[posState * 272 + symbol];
			}

			private void UpdateTable(uint posState)
			{
				SetPrices(posState, _tableSize, _prices, posState * 272);
				_counters[posState] = _tableSize;
			}

			public void UpdateTables(uint numPosStates)
			{
				for (uint num = 0u; num < numPosStates; num++)
				{
					UpdateTable(num);
				}
			}

			public new void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState)
			{
				base.Encode(rangeEncoder, symbol, posState);
				if (--_counters[posState] == 0)
				{
					UpdateTable(posState);
				}
			}
		}

		private class Optimal
		{
			public Base.State State;

			public bool Prev1IsChar;

			public bool Prev2;

			public uint PosPrev2;

			public uint BackPrev2;

			public uint Price;

			public uint PosPrev;

			public uint BackPrev;

			public uint Backs0;

			public uint Backs1;

			public uint Backs2;

			public uint Backs3;

			public void MakeAsChar()
			{
				BackPrev = uint.MaxValue;
				Prev1IsChar = false;
			}

			public void MakeAsShortRep()
			{
				BackPrev = 0u;
				Prev1IsChar = false;
			}

			public bool IsShortRep()
			{
				return BackPrev == 0;
			}
		}

		private const uint kIfinityPrice = 268435455u;

		private static byte[] g_FastPos;

		private Base.State _state;

		private byte _previousByte;

		private uint[] _repDistances = new uint[4];

		private const int kDefaultDictionaryLogSize = 22;

		private const uint kNumFastBytesDefault = 32u;

		private const uint kNumLenSpecSymbols = 16u;

		private const uint kNumOpts = 4096u;

		private Optimal[] _optimum = new Optimal[4096];

		private IMatchFinder _matchFinder;

		private SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();

		private BitEncoder[] _isMatch = new BitEncoder[192];

		private BitEncoder[] _isRep = new BitEncoder[12];

		private BitEncoder[] _isRepG0 = new BitEncoder[12];

		private BitEncoder[] _isRepG1 = new BitEncoder[12];

		private BitEncoder[] _isRepG2 = new BitEncoder[12];

		private BitEncoder[] _isRep0Long = new BitEncoder[192];

		private BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[4];

		private BitEncoder[] _posEncoders = new BitEncoder[114];

		private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(4);

		private LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();

		private LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

		private LiteralEncoder _literalEncoder = new LiteralEncoder();

		private uint[] _matchDistances = new uint[548];

		private uint _numFastBytes = 32u;

		private uint _longestMatchLength;

		private uint _numDistancePairs;

		private uint _additionalOffset;

		private uint _optimumEndIndex;

		private uint _optimumCurrentIndex;

		private bool _longestMatchWasFound;

		private uint[] _posSlotPrices = new uint[256];

		private uint[] _distancesPrices = new uint[512];

		private uint[] _alignPrices = new uint[16];

		private uint _alignPriceCount;

		private uint _distTableSize = 44u;

		private int _posStateBits = 2;

		private uint _posStateMask = 3u;

		private int _numLiteralPosStateBits;

		private int _numLiteralContextBits = 3;

		private uint _dictionarySize = 4194304u;

		private uint _dictionarySizePrev = uint.MaxValue;

		private uint _numFastBytesPrev = uint.MaxValue;

		private long nowPos64;

		private bool _finished;

		private Stream _inStream;

		private EMatchFinderType _matchFinderType = EMatchFinderType.BT4;

		private bool _writeEndMark;

		private bool _needReleaseMFStream;

		private uint[] reps = new uint[4];

		private uint[] repLens = new uint[4];

		private const int kPropSize = 5;

		private byte[] properties = new byte[5];

		private uint[] tempPrices = new uint[128];

		private uint _matchPriceCount;

		private static string[] kMatchFinderIDs;

		private uint _trainSize;

		static Encoder()
		{
			g_FastPos = new byte[2048];
			kMatchFinderIDs = new string[2] { "BT2", "BT4" };
			int num = 2;
			g_FastPos[0] = 0;
			g_FastPos[1] = 1;
			for (byte b = 2; b < 22; b++)
			{
				uint num2 = (uint)(1 << (b >> 1) - 1);
				uint num3 = 0u;
				while (num3 < num2)
				{
					g_FastPos[num] = b;
					num3++;
					num++;
				}
			}
		}

		private static uint GetPosSlot(uint pos)
		{
			if (pos < 2048)
			{
				return g_FastPos[pos];
			}
			if (pos < 2097152)
			{
				return (uint)(g_FastPos[pos >> 10] + 20);
			}
			return (uint)(g_FastPos[pos >> 20] + 40);
		}

		private static uint GetPosSlot2(uint pos)
		{
			if (pos < 131072)
			{
				return (uint)(g_FastPos[pos >> 6] + 12);
			}
			if (pos < 134217728)
			{
				return (uint)(g_FastPos[pos >> 16] + 32);
			}
			return (uint)(g_FastPos[pos >> 26] + 52);
		}

		private void BaseInit()
		{
			_state.Init();
			_previousByte = 0;
			for (uint num = 0u; num < 4; num++)
			{
				_repDistances[num] = 0u;
			}
		}

		private void Create()
		{
			if (_matchFinder == null)
			{
				BinTree binTree = new BinTree();
				int type = 4;
				if (_matchFinderType == EMatchFinderType.BT2)
				{
					type = 2;
				}
				binTree.SetType(type);
				_matchFinder = binTree;
			}
			_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
			if (_dictionarySize != _dictionarySizePrev || _numFastBytesPrev != _numFastBytes)
			{
				_matchFinder.Create(_dictionarySize, 4096u, _numFastBytes, 274u);
				_dictionarySizePrev = _dictionarySize;
				_numFastBytesPrev = _numFastBytes;
			}
		}

		public Encoder()
		{
			for (int i = 0; (long)i < 4096L; i++)
			{
				_optimum[i] = new Optimal();
			}
			for (int j = 0; (long)j < 4L; j++)
			{
				_posSlotEncoder[j] = new BitTreeEncoder(6);
			}
		}

		private void SetWriteEndMarkerMode(bool writeEndMarker)
		{
			_writeEndMark = writeEndMarker;
		}

		private void Init()
		{
			BaseInit();
			_rangeEncoder.Init();
			for (uint num = 0u; num < 12; num++)
			{
				for (uint num2 = 0u; num2 <= _posStateMask; num2++)
				{
					uint num3 = (num << 4) + num2;
					_isMatch[num3].Init();
					_isRep0Long[num3].Init();
				}
				_isRep[num].Init();
				_isRepG0[num].Init();
				_isRepG1[num].Init();
				_isRepG2[num].Init();
			}
			_literalEncoder.Init();
			for (uint num = 0u; num < 4; num++)
			{
				_posSlotEncoder[num].Init();
			}
			for (uint num = 0u; num < 114; num++)
			{
				_posEncoders[num].Init();
			}
			_lenEncoder.Init((uint)(1 << _posStateBits));
			_repMatchLenEncoder.Init((uint)(1 << _posStateBits));
			_posAlignEncoder.Init();
			_longestMatchWasFound = false;
			_optimumEndIndex = 0u;
			_optimumCurrentIndex = 0u;
			_additionalOffset = 0u;
		}

		private void ReadMatchDistances(out uint lenRes, out uint numDistancePairs)
		{
			lenRes = 0u;
			numDistancePairs = _matchFinder.GetMatches(_matchDistances);
			if (numDistancePairs != 0)
			{
				lenRes = _matchDistances[numDistancePairs - 2];
				if (lenRes == _numFastBytes)
				{
					lenRes += _matchFinder.GetMatchLen((int)(lenRes - 1), _matchDistances[numDistancePairs - 1], 273 - lenRes);
				}
			}
			_additionalOffset++;
		}

		private void MovePos(uint num)
		{
			if (num != 0)
			{
				_matchFinder.Skip(num);
				_additionalOffset += num;
			}
		}

		private uint GetRepLen1Price(Base.State state, uint posState)
		{
			return _isRepG0[state.Index].GetPrice0() + _isRep0Long[(state.Index << 4) + posState].GetPrice0();
		}

		private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState)
		{
			uint price;
			if (repIndex == 0)
			{
				price = _isRepG0[state.Index].GetPrice0();
				return price + _isRep0Long[(state.Index << 4) + posState].GetPrice1();
			}
			price = _isRepG0[state.Index].GetPrice1();
			if (repIndex == 1)
			{
				return price + _isRepG1[state.Index].GetPrice0();
			}
			price += _isRepG1[state.Index].GetPrice1();
			return price + _isRepG2[state.Index].GetPrice(repIndex - 2);
		}

		private uint GetRepPrice(uint repIndex, uint len, Base.State state, uint posState)
		{
			return _repMatchLenEncoder.GetPrice(len - 2, posState) + GetPureRepPrice(repIndex, state, posState);
		}

		private uint GetPosLenPrice(uint pos, uint len, uint posState)
		{
			uint lenToPosState = Base.GetLenToPosState(len);
			uint num = ((pos >= 128) ? (_posSlotPrices[(lenToPosState << 6) + GetPosSlot2(pos)] + _alignPrices[pos & 0xF]) : _distancesPrices[lenToPosState * 128 + pos]);
			return num + _lenEncoder.GetPrice(len - 2, posState);
		}

		private uint Backward(out uint backRes, uint cur)
		{
			_optimumEndIndex = cur;
			uint posPrev = _optimum[cur].PosPrev;
			uint backPrev = _optimum[cur].BackPrev;
			do
			{
				if (_optimum[cur].Prev1IsChar)
				{
					_optimum[posPrev].MakeAsChar();
					_optimum[posPrev].PosPrev = posPrev - 1;
					if (_optimum[cur].Prev2)
					{
						_optimum[posPrev - 1].Prev1IsChar = false;
						_optimum[posPrev - 1].PosPrev = _optimum[cur].PosPrev2;
						_optimum[posPrev - 1].BackPrev = _optimum[cur].BackPrev2;
					}
				}
				uint num = posPrev;
				uint backPrev2 = backPrev;
				backPrev = _optimum[num].BackPrev;
				posPrev = _optimum[num].PosPrev;
				_optimum[num].BackPrev = backPrev2;
				_optimum[num].PosPrev = cur;
				cur = num;
			}
			while (cur != 0);
			backRes = _optimum[0].BackPrev;
			_optimumCurrentIndex = _optimum[0].PosPrev;
			return _optimumCurrentIndex;
		}

		private uint GetOptimum(uint position, out uint backRes)
		{
			if (_optimumEndIndex != _optimumCurrentIndex)
			{
				uint result = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
				backRes = _optimum[_optimumCurrentIndex].BackPrev;
				_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
				return result;
			}
			_optimumCurrentIndex = (_optimumEndIndex = 0u);
			uint lenRes;
			uint numDistancePairs;
			if (!_longestMatchWasFound)
			{
				ReadMatchDistances(out lenRes, out numDistancePairs);
			}
			else
			{
				lenRes = _longestMatchLength;
				numDistancePairs = _numDistancePairs;
				_longestMatchWasFound = false;
			}
			uint num = _matchFinder.GetNumAvailableBytes() + 1;
			if (num < 2)
			{
				backRes = uint.MaxValue;
				return 1u;
			}
			if (num > 273)
			{
				num = 273u;
			}
			uint num2 = 0u;
			for (uint num3 = 0u; num3 < 4; num3++)
			{
				reps[num3] = _repDistances[num3];
				repLens[num3] = _matchFinder.GetMatchLen(-1, reps[num3], 273u);
				if (repLens[num3] > repLens[num2])
				{
					num2 = num3;
				}
			}
			if (repLens[num2] >= _numFastBytes)
			{
				backRes = num2;
				uint num4 = repLens[num2];
				MovePos(num4 - 1);
				return num4;
			}
			if (lenRes >= _numFastBytes)
			{
				backRes = _matchDistances[numDistancePairs - 1] + 4;
				MovePos(lenRes - 1);
				return lenRes;
			}
			byte indexByte = _matchFinder.GetIndexByte(-1);
			byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - 1));
			if (lenRes < 2 && indexByte != indexByte2 && repLens[num2] < 2)
			{
				backRes = uint.MaxValue;
				return 1u;
			}
			_optimum[0].State = _state;
			uint num5 = position & _posStateMask;
			_optimum[1].Price = _isMatch[(_state.Index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), indexByte2, indexByte);
			_optimum[1].MakeAsChar();
			uint price = _isMatch[(_state.Index << 4) + num5].GetPrice1();
			uint num6 = price + _isRep[_state.Index].GetPrice1();
			if (indexByte2 == indexByte)
			{
				uint num7 = num6 + GetRepLen1Price(_state, num5);
				if (num7 < _optimum[1].Price)
				{
					_optimum[1].Price = num7;
					_optimum[1].MakeAsShortRep();
				}
			}
			uint num8 = ((lenRes >= repLens[num2]) ? lenRes : repLens[num2]);
			if (num8 < 2)
			{
				backRes = _optimum[1].BackPrev;
				return 1u;
			}
			_optimum[1].PosPrev = 0u;
			_optimum[0].Backs0 = reps[0];
			_optimum[0].Backs1 = reps[1];
			_optimum[0].Backs2 = reps[2];
			_optimum[0].Backs3 = reps[3];
			uint num9 = num8;
			do
			{
				_optimum[num9--].Price = 268435455u;
			}
			while (num9 >= 2);
			for (uint num3 = 0u; num3 < 4; num3++)
			{
				uint num10 = repLens[num3];
				if (num10 < 2)
				{
					continue;
				}
				uint num11 = num6 + GetPureRepPrice(num3, _state, num5);
				do
				{
					uint num12 = num11 + _repMatchLenEncoder.GetPrice(num10 - 2, num5);
					Optimal optimal = _optimum[num10];
					if (num12 < optimal.Price)
					{
						optimal.Price = num12;
						optimal.PosPrev = 0u;
						optimal.BackPrev = num3;
						optimal.Prev1IsChar = false;
					}
				}
				while (--num10 >= 2);
			}
			uint num13 = price + _isRep[_state.Index].GetPrice0();
			num9 = ((repLens[0] >= 2) ? (repLens[0] + 1) : 2u);
			if (num9 <= lenRes)
			{
				uint num14;
				for (num14 = 0u; num9 > _matchDistances[num14]; num14 += 2)
				{
				}
				while (true)
				{
					uint num15 = _matchDistances[num14 + 1];
					uint num16 = num13 + GetPosLenPrice(num15, num9, num5);
					Optimal optimal2 = _optimum[num9];
					if (num16 < optimal2.Price)
					{
						optimal2.Price = num16;
						optimal2.PosPrev = 0u;
						optimal2.BackPrev = num15 + 4;
						optimal2.Prev1IsChar = false;
					}
					if (num9 == _matchDistances[num14])
					{
						num14 += 2;
						if (num14 == numDistancePairs)
						{
							break;
						}
					}
					num9++;
				}
			}
			uint num17 = 0u;
			uint lenRes2;
			while (true)
			{
				num17++;
				if (num17 == num8)
				{
					return Backward(out backRes, num17);
				}
				ReadMatchDistances(out lenRes2, out numDistancePairs);
				if (lenRes2 >= _numFastBytes)
				{
					break;
				}
				position++;
				uint num18 = _optimum[num17].PosPrev;
				Base.State state;
				if (_optimum[num17].Prev1IsChar)
				{
					num18--;
					if (_optimum[num17].Prev2)
					{
						state = _optimum[_optimum[num17].PosPrev2].State;
						if (_optimum[num17].BackPrev2 < 4)
						{
							state.UpdateRep();
						}
						else
						{
							state.UpdateMatch();
						}
					}
					else
					{
						state = _optimum[num18].State;
					}
					state.UpdateChar();
				}
				else
				{
					state = _optimum[num18].State;
				}
				if (num18 == num17 - 1)
				{
					if (_optimum[num17].IsShortRep())
					{
						state.UpdateShortRep();
					}
					else
					{
						state.UpdateChar();
					}
				}
				else
				{
					uint num19;
					if (_optimum[num17].Prev1IsChar && _optimum[num17].Prev2)
					{
						num18 = _optimum[num17].PosPrev2;
						num19 = _optimum[num17].BackPrev2;
						state.UpdateRep();
					}
					else
					{
						num19 = _optimum[num17].BackPrev;
						if (num19 < 4)
						{
							state.UpdateRep();
						}
						else
						{
							state.UpdateMatch();
						}
					}
					Optimal optimal3 = _optimum[num18];
					switch (num19)
					{
					case 0u:
						reps[0] = optimal3.Backs0;
						reps[1] = optimal3.Backs1;
						reps[2] = optimal3.Backs2;
						reps[3] = optimal3.Backs3;
						break;
					case 1u:
						reps[0] = optimal3.Backs1;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs2;
						reps[3] = optimal3.Backs3;
						break;
					case 2u:
						reps[0] = optimal3.Backs2;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs3;
						break;
					case 3u:
						reps[0] = optimal3.Backs3;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs2;
						break;
					default:
						reps[0] = num19 - 4;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs2;
						break;
					}
				}
				_optimum[num17].State = state;
				_optimum[num17].Backs0 = reps[0];
				_optimum[num17].Backs1 = reps[1];
				_optimum[num17].Backs2 = reps[2];
				_optimum[num17].Backs3 = reps[3];
				uint price2 = _optimum[num17].Price;
				indexByte = _matchFinder.GetIndexByte(-1);
				indexByte2 = _matchFinder.GetIndexByte((int)(0 - reps[0] - 1 - 1));
				num5 = position & _posStateMask;
				uint num20 = price2 + _isMatch[(state.Index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(-2)).GetPrice(!state.IsCharState(), indexByte2, indexByte);
				Optimal optimal4 = _optimum[num17 + 1];
				bool flag = false;
				if (num20 < optimal4.Price)
				{
					optimal4.Price = num20;
					optimal4.PosPrev = num17;
					optimal4.MakeAsChar();
					flag = true;
				}
				price = price2 + _isMatch[(state.Index << 4) + num5].GetPrice1();
				num6 = price + _isRep[state.Index].GetPrice1();
				if (indexByte2 == indexByte && (optimal4.PosPrev >= num17 || optimal4.BackPrev != 0))
				{
					uint num21 = num6 + GetRepLen1Price(state, num5);
					if (num21 <= optimal4.Price)
					{
						optimal4.Price = num21;
						optimal4.PosPrev = num17;
						optimal4.MakeAsShortRep();
						flag = true;
					}
				}
				uint val = _matchFinder.GetNumAvailableBytes() + 1;
				val = Math.Min(4095 - num17, val);
				num = val;
				if (num < 2)
				{
					continue;
				}
				if (num > _numFastBytes)
				{
					num = _numFastBytes;
				}
				if (!flag && indexByte2 != indexByte)
				{
					uint limit = Math.Min(val - 1, _numFastBytes);
					uint matchLen = _matchFinder.GetMatchLen(0, reps[0], limit);
					if (matchLen >= 2)
					{
						Base.State state2 = state;
						state2.UpdateChar();
						uint num22 = (position + 1) & _posStateMask;
						uint num23 = num20 + _isMatch[(state2.Index << 4) + num22].GetPrice1() + _isRep[state2.Index].GetPrice1();
						uint num24 = num17 + 1 + matchLen;
						while (num8 < num24)
						{
							_optimum[++num8].Price = 268435455u;
						}
						uint num25 = num23 + GetRepPrice(0u, matchLen, state2, num22);
						Optimal optimal5 = _optimum[num24];
						if (num25 < optimal5.Price)
						{
							optimal5.Price = num25;
							optimal5.PosPrev = num17 + 1;
							optimal5.BackPrev = 0u;
							optimal5.Prev1IsChar = true;
							optimal5.Prev2 = false;
						}
					}
				}
				uint num26 = 2u;
				for (uint num27 = 0u; num27 < 4; num27++)
				{
					uint num28 = _matchFinder.GetMatchLen(-1, reps[num27], num);
					if (num28 < 2)
					{
						continue;
					}
					uint num29 = num28;
					while (true)
					{
						if (num8 < num17 + num28)
						{
							_optimum[++num8].Price = 268435455u;
							continue;
						}
						uint num30 = num6 + GetRepPrice(num27, num28, state, num5);
						Optimal optimal6 = _optimum[num17 + num28];
						if (num30 < optimal6.Price)
						{
							optimal6.Price = num30;
							optimal6.PosPrev = num17;
							optimal6.BackPrev = num27;
							optimal6.Prev1IsChar = false;
						}
						if (--num28 < 2)
						{
							break;
						}
					}
					num28 = num29;
					if (num27 == 0)
					{
						num26 = num28 + 1;
					}
					if (num28 >= val)
					{
						continue;
					}
					uint limit2 = Math.Min(val - 1 - num28, _numFastBytes);
					uint matchLen2 = _matchFinder.GetMatchLen((int)num28, reps[num27], limit2);
					if (matchLen2 >= 2)
					{
						Base.State state3 = state;
						state3.UpdateRep();
						uint num31 = (position + num28) & _posStateMask;
						uint num32 = num6 + GetRepPrice(num27, num28, state, num5) + _isMatch[(state3.Index << 4) + num31].GetPrice0() + _literalEncoder.GetSubCoder(position + num28, _matchFinder.GetIndexByte((int)(num28 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num28 - 1 - (reps[num27] + 1))), _matchFinder.GetIndexByte((int)(num28 - 1)));
						state3.UpdateChar();
						num31 = (position + num28 + 1) & _posStateMask;
						uint num33 = num32 + _isMatch[(state3.Index << 4) + num31].GetPrice1() + _isRep[state3.Index].GetPrice1();
						uint num34 = num28 + 1 + matchLen2;
						while (num8 < num17 + num34)
						{
							_optimum[++num8].Price = 268435455u;
						}
						uint num35 = num33 + GetRepPrice(0u, matchLen2, state3, num31);
						Optimal optimal7 = _optimum[num17 + num34];
						if (num35 < optimal7.Price)
						{
							optimal7.Price = num35;
							optimal7.PosPrev = num17 + num28 + 1;
							optimal7.BackPrev = 0u;
							optimal7.Prev1IsChar = true;
							optimal7.Prev2 = true;
							optimal7.PosPrev2 = num17;
							optimal7.BackPrev2 = num27;
						}
					}
				}
				if (lenRes2 > num)
				{
					lenRes2 = num;
					for (numDistancePairs = 0u; lenRes2 > _matchDistances[numDistancePairs]; numDistancePairs += 2)
					{
					}
					_matchDistances[numDistancePairs] = lenRes2;
					numDistancePairs += 2;
				}
				if (lenRes2 < num26)
				{
					continue;
				}
				num13 = price + _isRep[state.Index].GetPrice0();
				while (num8 < num17 + lenRes2)
				{
					_optimum[++num8].Price = 268435455u;
				}
				uint num36;
				for (num36 = 0u; num26 > _matchDistances[num36]; num36 += 2)
				{
				}
				uint num37 = num26;
				while (true)
				{
					uint num38 = _matchDistances[num36 + 1];
					uint num39 = num13 + GetPosLenPrice(num38, num37, num5);
					Optimal optimal8 = _optimum[num17 + num37];
					if (num39 < optimal8.Price)
					{
						optimal8.Price = num39;
						optimal8.PosPrev = num17;
						optimal8.BackPrev = num38 + 4;
						optimal8.Prev1IsChar = false;
					}
					if (num37 == _matchDistances[num36])
					{
						if (num37 < val)
						{
							uint limit3 = Math.Min(val - 1 - num37, _numFastBytes);
							uint matchLen3 = _matchFinder.GetMatchLen((int)num37, num38, limit3);
							if (matchLen3 >= 2)
							{
								Base.State state4 = state;
								state4.UpdateMatch();
								uint num40 = (position + num37) & _posStateMask;
								uint num41 = num39 + _isMatch[(state4.Index << 4) + num40].GetPrice0() + _literalEncoder.GetSubCoder(position + num37, _matchFinder.GetIndexByte((int)(num37 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num37 - (num38 + 1) - 1)), _matchFinder.GetIndexByte((int)(num37 - 1)));
								state4.UpdateChar();
								num40 = (position + num37 + 1) & _posStateMask;
								uint num42 = num41 + _isMatch[(state4.Index << 4) + num40].GetPrice1() + _isRep[state4.Index].GetPrice1();
								uint num43 = num37 + 1 + matchLen3;
								while (num8 < num17 + num43)
								{
									_optimum[++num8].Price = 268435455u;
								}
								num39 = num42 + GetRepPrice(0u, matchLen3, state4, num40);
								optimal8 = _optimum[num17 + num43];
								if (num39 < optimal8.Price)
								{
									optimal8.Price = num39;
									optimal8.PosPrev = num17 + num37 + 1;
									optimal8.BackPrev = 0u;
									optimal8.Prev1IsChar = true;
									optimal8.Prev2 = true;
									optimal8.PosPrev2 = num17;
									optimal8.BackPrev2 = num38 + 4;
								}
							}
						}
						num36 += 2;
						if (num36 == numDistancePairs)
						{
							break;
						}
					}
					num37++;
				}
			}
			_numDistancePairs = numDistancePairs;
			_longestMatchLength = lenRes2;
			_longestMatchWasFound = true;
			return Backward(out backRes, num17);
		}

		private bool ChangePair(uint smallDist, uint bigDist)
		{
			if (smallDist < 33554432)
			{
				return bigDist >= smallDist << 7;
			}
			return false;
		}

		private void WriteEndMarker(uint posState)
		{
			if (_writeEndMark)
			{
				_isMatch[(_state.Index << 4) + posState].Encode(_rangeEncoder, 1u);
				_isRep[_state.Index].Encode(_rangeEncoder, 0u);
				_state.UpdateMatch();
				uint num = 2u;
				_lenEncoder.Encode(_rangeEncoder, num - 2, posState);
				uint symbol = 63u;
				uint lenToPosState = Base.GetLenToPosState(num);
				_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, symbol);
				int num2 = 30;
				uint num3 = (uint)((1 << num2) - 1);
				_rangeEncoder.EncodeDirectBits(num3 >> 4, num2 - 4);
				_posAlignEncoder.ReverseEncode(_rangeEncoder, num3 & 0xFu);
			}
		}

		private void Flush(uint nowPos)
		{
			ReleaseMFStream();
			WriteEndMarker(nowPos & _posStateMask);
			_rangeEncoder.FlushData();
			_rangeEncoder.FlushStream();
		}

		public void CodeOneBlock(out long inSize, out long outSize, out bool finished)
		{
			inSize = 0L;
			outSize = 0L;
			finished = true;
			if (_inStream != null)
			{
				_matchFinder.SetStream(_inStream);
				_matchFinder.Init();
				_needReleaseMFStream = true;
				_inStream = null;
				if (_trainSize != 0)
				{
					_matchFinder.Skip(_trainSize);
				}
			}
			if (_finished)
			{
				return;
			}
			_finished = true;
			long num = nowPos64;
			if (nowPos64 == 0L)
			{
				if (_matchFinder.GetNumAvailableBytes() == 0)
				{
					Flush((uint)nowPos64);
					return;
				}
				ReadMatchDistances(out var _, out var _);
				uint num2 = (uint)(int)nowPos64 & _posStateMask;
				_isMatch[(_state.Index << 4) + num2].Encode(_rangeEncoder, 0u);
				_state.UpdateChar();
				byte indexByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
				_literalEncoder.GetSubCoder((uint)nowPos64, _previousByte).Encode(_rangeEncoder, indexByte);
				_previousByte = indexByte;
				_additionalOffset--;
				nowPos64++;
			}
			if (_matchFinder.GetNumAvailableBytes() == 0)
			{
				Flush((uint)nowPos64);
				return;
			}
			while (true)
			{
				uint backRes;
				uint optimum = GetOptimum((uint)nowPos64, out backRes);
				uint num3 = (uint)(int)nowPos64 & _posStateMask;
				uint num4 = (_state.Index << 4) + num3;
				if (optimum == 1 && backRes == uint.MaxValue)
				{
					_isMatch[num4].Encode(_rangeEncoder, 0u);
					byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
					LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((uint)nowPos64, _previousByte);
					if (!_state.IsCharState())
					{
						byte indexByte3 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
						subCoder.EncodeMatched(_rangeEncoder, indexByte3, indexByte2);
					}
					else
					{
						subCoder.Encode(_rangeEncoder, indexByte2);
					}
					_previousByte = indexByte2;
					_state.UpdateChar();
				}
				else
				{
					_isMatch[num4].Encode(_rangeEncoder, 1u);
					if (backRes < 4)
					{
						_isRep[_state.Index].Encode(_rangeEncoder, 1u);
						if (backRes == 0)
						{
							_isRepG0[_state.Index].Encode(_rangeEncoder, 0u);
							if (optimum == 1)
							{
								_isRep0Long[num4].Encode(_rangeEncoder, 0u);
							}
							else
							{
								_isRep0Long[num4].Encode(_rangeEncoder, 1u);
							}
						}
						else
						{
							_isRepG0[_state.Index].Encode(_rangeEncoder, 1u);
							if (backRes == 1)
							{
								_isRepG1[_state.Index].Encode(_rangeEncoder, 0u);
							}
							else
							{
								_isRepG1[_state.Index].Encode(_rangeEncoder, 1u);
								_isRepG2[_state.Index].Encode(_rangeEncoder, backRes - 2);
							}
						}
						if (optimum == 1)
						{
							_state.UpdateShortRep();
						}
						else
						{
							_repMatchLenEncoder.Encode(_rangeEncoder, optimum - 2, num3);
							_state.UpdateRep();
						}
						uint num5 = _repDistances[backRes];
						if (backRes != 0)
						{
							for (uint num6 = backRes; num6 >= 1; num6--)
							{
								_repDistances[num6] = _repDistances[num6 - 1];
							}
							_repDistances[0] = num5;
						}
					}
					else
					{
						_isRep[_state.Index].Encode(_rangeEncoder, 0u);
						_state.UpdateMatch();
						_lenEncoder.Encode(_rangeEncoder, optimum - 2, num3);
						backRes -= 4;
						uint posSlot = GetPosSlot(backRes);
						uint lenToPosState = Base.GetLenToPosState(optimum);
						_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
						if (posSlot >= 4)
						{
							int num7 = (int)((posSlot >> 1) - 1);
							uint num8 = (2 | (posSlot & 1)) << num7;
							uint num9 = backRes - num8;
							if (posSlot < 14)
							{
								BitTreeEncoder.ReverseEncode(_posEncoders, num8 - posSlot - 1, _rangeEncoder, num7, num9);
							}
							else
							{
								_rangeEncoder.EncodeDirectBits(num9 >> 4, num7 - 4);
								_posAlignEncoder.ReverseEncode(_rangeEncoder, num9 & 0xFu);
								_alignPriceCount++;
							}
						}
						uint num10 = backRes;
						for (uint num11 = 3u; num11 >= 1; num11--)
						{
							_repDistances[num11] = _repDistances[num11 - 1];
						}
						_repDistances[0] = num10;
						_matchPriceCount++;
					}
					_previousByte = _matchFinder.GetIndexByte((int)(optimum - 1 - _additionalOffset));
				}
				_additionalOffset -= optimum;
				nowPos64 += optimum;
				if (_additionalOffset == 0)
				{
					if (_matchPriceCount >= 128)
					{
						FillDistancesPrices();
					}
					if (_alignPriceCount >= 16)
					{
						FillAlignPrices();
					}
					inSize = nowPos64;
					outSize = _rangeEncoder.GetProcessedSizeAdd();
					if (_matchFinder.GetNumAvailableBytes() == 0)
					{
						Flush((uint)nowPos64);
						return;
					}
					if (nowPos64 - num >= 4096)
					{
						break;
					}
				}
			}
			_finished = false;
			finished = false;
		}

		private void ReleaseMFStream()
		{
			if (_matchFinder != null && _needReleaseMFStream)
			{
				_matchFinder.ReleaseStream();
				_needReleaseMFStream = false;
			}
		}

		private void SetOutStream(Stream outStream)
		{
			_rangeEncoder.SetStream(outStream);
		}

		private void ReleaseOutStream()
		{
			_rangeEncoder.ReleaseStream();
		}

		private void ReleaseStreams()
		{
			ReleaseMFStream();
			ReleaseOutStream();
		}

		private void SetStreams(Stream inStream, Stream outStream, long inSize, long outSize)
		{
			_inStream = inStream;
			_finished = false;
			Create();
			SetOutStream(outStream);
			Init();
			FillDistancesPrices();
			FillAlignPrices();
			_lenEncoder.SetTableSize(_numFastBytes + 1 - 2);
			_lenEncoder.UpdateTables((uint)(1 << _posStateBits));
			_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - 2);
			_repMatchLenEncoder.UpdateTables((uint)(1 << _posStateBits));
			nowPos64 = 0L;
		}

		public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress)
		{
			_needReleaseMFStream = false;
			try
			{
				SetStreams(inStream, outStream, inSize, outSize);
				while (true)
				{
					CodeOneBlock(out var inSize2, out var outSize2, out var finished);
					if (finished)
					{
						break;
					}
					progress?.SetProgress(inSize2, outSize2);
				}
			}
			finally
			{
				ReleaseStreams();
			}
		}

		public void WriteCoderProperties(Stream outStream)
		{
			properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
			for (int i = 0; i < 4; i++)
			{
				properties[1 + i] = (byte)((_dictionarySize >> 8 * i) & 0xFFu);
			}
			outStream.Write(properties, 0, 5);
		}

		private void FillDistancesPrices()
		{
			for (uint num = 4u; num < 128; num++)
			{
				uint posSlot = GetPosSlot(num);
				int num2 = (int)((posSlot >> 1) - 1);
				uint num3 = (2 | (posSlot & 1)) << num2;
				tempPrices[num] = BitTreeEncoder.ReverseGetPrice(_posEncoders, num3 - posSlot - 1, num2, num - num3);
			}
			for (uint num4 = 0u; num4 < 4; num4++)
			{
				BitTreeEncoder bitTreeEncoder = _posSlotEncoder[num4];
				uint num5 = num4 << 6;
				for (uint num6 = 0u; num6 < _distTableSize; num6++)
				{
					_posSlotPrices[num5 + num6] = bitTreeEncoder.GetPrice(num6);
				}
				for (uint num6 = 14u; num6 < _distTableSize; num6++)
				{
					_posSlotPrices[num5 + num6] += (num6 >> 1) - 1 - 4 << 6;
				}
				uint num7 = num4 * 128;
				uint num8;
				for (num8 = 0u; num8 < 4; num8++)
				{
					_distancesPrices[num7 + num8] = _posSlotPrices[num5 + num8];
				}
				for (; num8 < 128; num8++)
				{
					_distancesPrices[num7 + num8] = _posSlotPrices[num5 + GetPosSlot(num8)] + tempPrices[num8];
				}
			}
			_matchPriceCount = 0u;
		}

		private void FillAlignPrices()
		{
			for (uint num = 0u; num < 16; num++)
			{
				_alignPrices[num] = _posAlignEncoder.ReverseGetPrice(num);
			}
			_alignPriceCount = 0u;
		}

		private static int FindMatchFinder(string s)
		{
			for (int i = 0; i < kMatchFinderIDs.Length; i++)
			{
				if (s == kMatchFinderIDs[i])
				{
					return i;
				}
			}
			return -1;
		}

		public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
		{
			for (uint num = 0u; num < properties.Length; num++)
			{
				object obj = properties[num];
				switch (propIDs[num])
				{
				case CoderPropID.NumFastBytes:
					if (!(obj is int num2))
					{
						throw new InvalidParamException();
					}
					if (num2 < 5 || (long)num2 > 273L)
					{
						throw new InvalidParamException();
					}
					_numFastBytes = (uint)num2;
					break;
				case CoderPropID.MatchFinder:
				{
					if (!(obj is string))
					{
						throw new InvalidParamException();
					}
					EMatchFinderType matchFinderType = _matchFinderType;
					int num6 = FindMatchFinder(((string)obj).ToUpper());
					if (num6 < 0)
					{
						throw new InvalidParamException();
					}
					_matchFinderType = (EMatchFinderType)num6;
					if (_matchFinder != null && matchFinderType != _matchFinderType)
					{
						_dictionarySizePrev = uint.MaxValue;
						_matchFinder = null;
					}
					break;
				}
				case CoderPropID.DictionarySize:
				{
					if (!(obj is int num7))
					{
						throw new InvalidParamException();
					}
					if ((long)num7 < 1L || (long)num7 > 1073741824L)
					{
						throw new InvalidParamException();
					}
					_dictionarySize = (uint)num7;
					int i;
					for (i = 0; (long)i < 30L && num7 > (uint)(1 << i); i++)
					{
					}
					_distTableSize = (uint)(i * 2);
					break;
				}
				case CoderPropID.PosStateBits:
					if (!(obj is int num3))
					{
						throw new InvalidParamException();
					}
					if (num3 < 0 || (long)num3 > 4L)
					{
						throw new InvalidParamException();
					}
					_posStateBits = num3;
					_posStateMask = (uint)((1 << _posStateBits) - 1);
					break;
				case CoderPropID.LitPosBits:
					if (!(obj is int num5))
					{
						throw new InvalidParamException();
					}
					if (num5 < 0 || (long)num5 > 4L)
					{
						throw new InvalidParamException();
					}
					_numLiteralPosStateBits = num5;
					break;
				case CoderPropID.LitContextBits:
					if (!(obj is int num4))
					{
						throw new InvalidParamException();
					}
					if (num4 < 0 || (long)num4 > 8L)
					{
						throw new InvalidParamException();
					}
					_numLiteralContextBits = num4;
					break;
				case CoderPropID.EndMarker:
					if (!(obj is bool))
					{
						throw new InvalidParamException();
					}
					SetWriteEndMarkerMode((bool)obj);
					break;
				default:
					throw new InvalidParamException();
				case CoderPropID.Algorithm:
					break;
				}
			}
		}

		public void SetTrainSize(uint trainSize)
		{
			_trainSize = trainSize;
		}
	}
	public static class SevenZipHelper
	{
		private static CoderPropID[] propIDs = new CoderPropID[8]
		{
			CoderPropID.DictionarySize,
			CoderPropID.PosStateBits,
			CoderPropID.LitContextBits,
			CoderPropID.LitPosBits,
			CoderPropID.Algorithm,
			CoderPropID.NumFastBytes,
			CoderPropID.MatchFinder,
			CoderPropID.EndMarker
		};

		private static object[] properties = new object[8] { 2097152, 2, 3, 0, 2, 32, "bt4", false };

		public static byte[] Compress(byte[] inputBytes, ICodeProgress progress = null)
		{
			MemoryStream inStream = new MemoryStream(inputBytes);
			MemoryStream memoryStream = new MemoryStream();
			Compress(inStream, memoryStream, progress);
			return memoryStream.ToArray();
		}

		public static void Compress(Stream inStream, Stream outStream, ICodeProgress progress = null)
		{
			Encoder encoder = new Encoder();
			encoder.SetCoderProperties(propIDs, properties);
			encoder.WriteCoderProperties(outStream);
			encoder.Code(inStream, outStream, -1L, -1L, progress);
		}

		public static byte[] Decompress(byte[] inputBytes)
		{
			MemoryStream memoryStream = new MemoryStream(inputBytes);
			Decoder decoder = new Decoder();
			memoryStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream2 = new MemoryStream();
			byte[] array = new byte[5];
			if (memoryStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			long num = 0L;
			for (int i = 0; i < 8; i++)
			{
				int num2 = memoryStream.ReadByte();
				if (num2 < 0)
				{
					throw new Exception("Can't Read 1");
				}
				num |= (long)((ulong)(byte)num2 << 8 * i);
			}
			decoder.SetDecoderProperties(array);
			long inSize = memoryStream.Length - memoryStream.Position;
			decoder.Code(memoryStream, memoryStream2, inSize, num, null);
			return memoryStream2.ToArray();
		}

		public static MemoryStream StreamDecompress(MemoryStream newInStream)
		{
			Decoder decoder = new Decoder();
			newInStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[5];
			if (newInStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			long num = 0L;
			for (int i = 0; i < 8; i++)
			{
				int num2 = newInStream.ReadByte();
				if (num2 < 0)
				{
					throw new Exception("Can't Read 1");
				}
				num |= (long)((ulong)(byte)num2 << 8 * i);
			}
			decoder.SetDecoderProperties(array);
			long inSize = newInStream.Length - newInStream.Position;
			decoder.Code(newInStream, memoryStream, inSize, num, null);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		public static MemoryStream StreamDecompress(MemoryStream newInStream, long outSize)
		{
			Decoder decoder = new Decoder();
			newInStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[5];
			if (newInStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			decoder.SetDecoderProperties(array);
			long inSize = newInStream.Length - newInStream.Position;
			decoder.Code(newInStream, memoryStream, inSize, outSize, null);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		public static void StreamDecompress(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize)
		{
			long position = compressedStream.Position;
			Decoder decoder = new Decoder();
			byte[] array = new byte[5];
			if (compressedStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			decoder.SetDecoderProperties(array);
			decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
			compressedStream.Position = position + compressedSize;
		}
	}
}
namespace SevenZip.Buffer
{
	public class InBuffer
	{
		private byte[] m_Buffer;

		private uint m_Pos;

		private uint m_Limit;

		private uint m_BufferSize;

		private Stream m_Stream;

		private bool m_StreamWasExhausted;

		private ulong m_ProcessedSize;

		public InBuffer(uint bufferSize)
		{
			m_Buffer = new byte[bufferSize];
			m_BufferSize = bufferSize;
		}

		public void Init(Stream stream)
		{
			m_Stream = stream;
			m_ProcessedSize = 0uL;
			m_Limit = 0u;
			m_Pos = 0u;
			m_StreamWasExhausted = false;
		}

		public bool ReadBlock()
		{
			if (m_StreamWasExhausted)
			{
				return false;
			}
			m_ProcessedSize += m_Pos;
			int num = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
			m_Pos = 0u;
			m_Limit = (uint)num;
			m_StreamWasExhausted = num == 0;
			return !m_StreamWasExhausted;
		}

		public void ReleaseStream()
		{
			m_Stream = null;
		}

		public bool ReadByte(byte b)
		{
			if (m_Pos >= m_Limit && !ReadBlock())
			{
				return false;
			}
			b = m_Buffer[m_Pos++];
			return true;
		}

		public byte ReadByte()
		{
			if (m_Pos >= m_Limit && !ReadBlock())
			{
				return byte.MaxValue;
			}
			return m_Buffer[m_Pos++];
		}

		public ulong GetProcessedSize()
		{
			return m_ProcessedSize + m_Pos;
		}
	}
	public class OutBuffer
	{
		private byte[] m_Buffer;

		private uint m_Pos;

		private uint m_BufferSize;

		private Stream m_Stream;

		private ulong m_ProcessedSize;

		public OutBuffer(uint bufferSize)
		{
			m_Buffer = new byte[bufferSize];
			m_BufferSize = bufferSize;
		}

		public void SetStream(Stream stream)
		{
			m_Stream = stream;
		}

		public void FlushStream()
		{
			m_Stream.Flush();
		}

		public void CloseStream()
		{
			m_Stream.Close();
		}

		public void ReleaseStream()
		{
			m_Stream = null;
		}

		public void Init()
		{
			m_ProcessedSize = 0uL;
			m_Pos = 0u;
		}

		public void WriteByte(byte b)
		{
			m_Buffer[m_Pos++] = b;
			if (m_Pos >= m_BufferSize)
			{
				FlushData();
			}
		}

		public void FlushData()
		{
			if (m_Pos != 0)
			{
				m_Stream.Write(m_Buffer, 0, (int)m_Pos);
				m_Pos = 0u;
			}
		}

		public ulong GetProcessedSize()
		{
			return m_ProcessedSize + m_Pos;
		}
	}
}
namespace SevenZip.CommandLineParser
{
	public enum SwitchType
	{
		Simple,
		PostMinus,
		LimitedPostString,
		UnLimitedPostString,
		PostChar
	}
	public class SwitchForm
	{
		public string IDString;

		public SwitchType Type;

		public bool Multi;

		public int MinLen;

		public int MaxLen;

		public string PostCharSet;

		public SwitchForm(string idString, SwitchType type, bool multi, int minLen, int maxLen, string postCharSet)
		{
			IDString = idString;
			Type = type;
			Multi = multi;
			MinLen = minLen;
			MaxLen = maxLen;
			PostCharSet = postCharSet;
		}

		public SwitchForm(string idString, SwitchType type, bool multi, int minLen)
			: this(idString, type, multi, minLen, 0, "")
		{
		}

		public SwitchForm(string idString, SwitchType type, bool multi)
			: this(idString, type, multi, 0)
		{
		}
	}
	public class SwitchResult
	{
		public bool ThereIs;

		public bool WithMinus;

		public ArrayList PostStrings = new ArrayList();

		public int PostCharIndex;

		public SwitchResult()
		{
			ThereIs = false;
		}
	}
	public class Parser
	{
		public ArrayList NonSwitchStrings = new ArrayList();

		private SwitchResult[] _switches;

		private const char kSwitchID1 = '-';

		private const char kSwitchID2 = '/';

		private const char kSwitchMinus = '-';

		private const string kStopSwitchParsing = "--";

		public SwitchResult this[int index] => _switches[index];

		public Parser(int numSwitches)
		{
			_switches = new SwitchResult[numSwitches];
			for (int i = 0; i < numSwitches; i++)
			{
				_switches[i] = new SwitchResult();
			}
		}

		private bool ParseString(string srcString, SwitchForm[] switchForms)
		{
			int length = srcString.Length;
			if (length == 0)
			{
				return false;
			}
			int num = 0;
			if (!IsItSwitchChar(srcString[num]))
			{
				return false;
			}
			while (num < length)
			{
				if (IsItSwitchChar(srcString[num]))
				{
					num++;
				}
				int num2 = 0;
				int num3 = -1;
				for (int i = 0; i < _switches.Length; i++)
				{
					int length2 = switchForms[i].IDString.Length;
					if (length2 > num3 && num + length2 <= length && string.Compare(switchForms[i].IDString, 0, srcString, num, length2, ignoreCase: true) == 0)
					{
						num2 = i;
						num3 = length2;
					}
				}
				if (num3 == -1)
				{
					throw new Exception("maxLen == kNoLen");
				}
				SwitchResult switchResult = _switches[num2];
				SwitchForm switchForm = switchForms[num2];
				if (!switchForm.Multi && switchResult.ThereIs)
				{
					throw new Exception("switch must be single");
				}
				switchResult.ThereIs = true;
				num += num3;
				int num4 = length - num;
				SwitchType type = switchForm.Type;
				switch (type)
				{
				case SwitchType.PostMinus:
					if (num4 == 0)
					{
						switchResult.WithMinus = false;
						break;
					}
					switchResult.WithMinus = srcString[num] == '-';
					if (switchResult.WithMinus)
					{
						num++;
					}
					break;
				case SwitchType.PostChar:
				{
					if (num4 < switchForm.MinLen)
					{
						throw new Exception("switch is not full");
					}
					string postCharSet = switchForm.PostCharSet;
					if (num4 == 0)
					{
						switchResult.PostCharIndex = -1;
						break;
					}
					int num6 = postCharSet.IndexOf(srcString[num]);
					if (num6 < 0)
					{
						switchResult.PostCharIndex = -1;
						break;
					}
					switchResult.PostCharIndex = num6;
					num++;
					break;
				}
				case SwitchType.LimitedPostString:
				case SwitchType.UnLimitedPostString:
				{
					int minLen = switchForm.MinLen;
					if (num4 < minLen)
					{
						throw new Exception("switch is not full");
					}
					if (type == SwitchType.UnLimitedPostString)
					{
						switchResult.PostStrings.Add(srcString.Substring(num));
						return true;
					}
					string text = srcString.Substring(num, minLen);
					num += minLen;
					int num5 = minLen;
					while (num5 < switchForm.MaxLen && num < length)
					{
						char c = srcString[num];
						if (IsItSwitchChar(c))
						{
							break;
						}
						text += c;
						num5++;
						num++;
					}
					switchResult.PostStrings.Add(text);
					break;
				}
				}
			}
			return true;
		}

		public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
		{
			int num = commandStrings.Length;
			bool flag = false;
			for (int i = 0; i < num; i++)
			{
				string text = commandStrings[i];
				if (flag)
				{
					NonSwitchStrings.Add(text);
				}
				else if (text == "--")
				{
					flag = true;
				}
				else if (!ParseString(text, switchForms))
				{
					NonSwitchStrings.Add(text);
				}
			}
		}

		public static int ParseCommand(CommandForm[] commandForms, string commandString, out string postString)
		{
			for (int i = 0; i < commandForms.Length; i++)
			{
				string iDString = commandForms[i].IDString;
				if (commandForms[i].PostStringMode)
				{
					if (commandString.IndexOf(iDString) == 0)
					{
						postString = commandString.Substring(iDString.Length);
						return i;
					}
				}
				else if (commandString == iDString)
				{
					postString = "";
					return i;
				}
			}
			postString = "";
			return -1;
		}

		private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, string commandString, ArrayList indices)
		{
			indices.Clear();
			int num = 0;
			for (int i = 0; i < numForms; i++)
			{
				CommandSubCharsSet commandSubCharsSet = forms[i];
				int num2 = -1;
				int length = commandSubCharsSet.Chars.Length;
				for (int j = 0; j < length; j++)
				{
					char value = commandSubCharsSet.Chars[j];
					int num3 = commandString.IndexOf(value);
					if (num3 >= 0)
					{
						if (num2 >= 0)
						{
							return false;
						}
						if (commandString.IndexOf(value, num3 + 1) >= 0)
						{
							return false;
						}
						num2 = j;
						num++;
					}
				}
				if (num2 == -1 && !commandSubCharsSet.EmptyAllowed)
				{
					return false;
				}
				indices.Add(num2);
			}
			return num == commandString.Length;
		}

		private static bool IsItSwitchChar(char c)
		{
			if (c != '-')
			{
				return c == '/';
			}
			return true;
		}
	}
	public class CommandForm
	{
		public string IDString = "";

		public bool PostStringMode;

		public CommandForm(string idString, bool postStringMode)
		{
			IDString = idString;
			PostStringMode = postStringMode;
		}
	}
	internal class CommandSubCharsSet
	{
		public string Chars = "";

		public bool EmptyAllowed;
	}
}
namespace LZ4ps
{
	public static class LZ4Codec
	{
		private class LZ4HC_Data_Structure
		{
			public byte[] src;

			public int src_base;

			public int src_end;

			public int src_LASTLITERALS;

			public byte[] dst;

			public int dst_base;

			public int dst_len;

			public int dst_end;

			public int[] hashTable;

			public ushort[] chainTable;

			public int nextToUpdate;
		}

		private const int MEMORY_USAGE = 14;

		private const int NOTCOMPRESSIBLE_DETECTIONLEVEL = 6;

		private const int BLOCK_COPY_LIMIT = 16;

		private const int MINMATCH = 4;

		private const int SKIPSTRENGTH = 6;

		private const int COPYLENGTH = 8;

		private const int LASTLITERALS = 5;

		private const int MFLIMIT = 12;

		private const int MINLENGTH = 13;

		private const int MAXD_LOG = 16;

		private const int MAXD = 65536;

		private const int MAXD_MASK = 65535;

		private const int MAX_DISTANCE = 65535;

		private const int ML_BITS = 4;

		private const int ML_MASK = 15;

		private const int RUN_BITS = 4;

		private const int RUN_MASK = 15;

		private const int STEPSIZE_64 = 8;

		private const int STEPSIZE_32 = 4;

		private const int LZ4_64KLIMIT = 65547;

		private const int HASH_LOG = 12;

		private const int HASH_TABLESIZE = 4096;

		private const int HASH_ADJUST = 20;

		private const int HASH64K_LOG = 13;

		private const int HASH64K_TABLESIZE = 8192;

		private const int HASH64K_ADJUST = 19;

		private const int HASHHC_LOG = 15;

		private const int HASHHC_TABLESIZE = 32768;

		private const int HASHHC_ADJUST = 17;

		private static readonly int[] DECODER_TABLE_32 = new int[8] { 0, 3, 2, 3, 0, 0, 0, 0 };

		private static readonly int[] DECODER_TABLE_64 = new int[8] { 0, 0, 0, -1, 0, 1, 2, 3 };

		private static readonly int[] DEBRUIJN_TABLE_32 = new int[32]
		{
			0, 0, 3, 0, 3, 1, 3, 0, 3, 2,
			2, 1, 3, 2, 0, 1, 3, 3, 1, 2,
			2, 2, 2, 0, 3, 1, 2, 0, 1, 0,
			1, 1
		};

		private static readonly int[] DEBRUIJN_TABLE_64 = new int[64]
		{
			0, 0, 0, 0, 0, 1, 1, 2, 0, 3,
			1, 3, 1, 4, 2, 7, 0, 2, 3, 6,
			1, 5, 3, 5, 1, 3, 4, 4, 2, 5,
			6, 7, 7, 0, 1, 2, 3, 3, 4, 6,
			2, 6, 5, 5, 3, 4, 5, 6, 7, 1,
			2, 4, 6, 4, 4, 5, 7, 2, 6, 5,
			7, 6, 7, 7
		};

		private const int MAX_NB_ATTEMPTS = 256;

		private const int OPTIMAL_ML = 18;

		public static int MaximumOutputLength(int inputLength)
		{
			return inputLength + inputLength / 255 + 16;
		}

		internal static void CheckArguments(byte[] input, int inputOffset, ref int inputLength, byte[] output, int outputOffset, ref int outputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (inputLength == 0)
			{
				outputLength = 0;
				return;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			if (outputLength < 0)
			{
				outputLength = output.Length - outputOffset;
			}
			if (output == null)
			{
				throw new ArgumentNullException("output");
			}
			if (outputOffset >= 0 && outputOffset + outputLength <= output.Length)
			{
				return;
			}
			throw new ArgumentException("outputOffset and outputLength are invalid for given output");
		}

		[Conditional("DEBUG")]
		private static void Assert(bool condition, string errorMessage)
		{
			if (!condition)
			{
				throw new ArgumentException(errorMessage);
			}
		}

		internal static void Poke2(byte[] buffer, int offset, ushort value)
		{
			buffer[offset] = (byte)value;
			buffer[offset + 1] = (byte)(value >> 8);
		}

		internal static ushort Peek2(byte[] buffer, int offset)
		{
			return (ushort)(buffer[offset] | (buffer[offset + 1] << 8));
		}

		internal static uint Peek4(byte[] buffer, int offset)
		{
			return (uint)(buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24));
		}

		private static uint Xor4(byte[] buffer, int offset1, int offset2)
		{
			int num = buffer[offset1] | (buffer[offset1 + 1] << 8) | (buffer[offset1 + 2] << 16) | (buffer[offset1 + 3] << 24);
			uint num2 = (uint)(buffer[offset2] | (buffer[offset2 + 1] << 8) | (buffer[offset2 + 2] << 16) | (buffer[offset2 + 3] << 24));
			return (uint)num ^ num2;
		}

		private static ulong Xor8(byte[] buffer, int offset1, int offset2)
		{
			ulong num = buffer[offset1] | ((ulong)buffer[offset1 + 1] << 8) | ((ulong)buffer[offset1 + 2] << 16) | ((ulong)buffer[offset1 + 3] << 24) | ((ulong)buffer[offset1 + 4] << 32) | ((ulong)buffer[offset1 + 5] << 40) | ((ulong)buffer[offset1 + 6] << 48) | ((ulong)buffer[offset1 + 7] << 56);
			ulong num2 = buffer[offset2] | ((ulong)buffer[offset2 + 1] << 8) | ((ulong)buffer[offset2 + 2] << 16) | ((ulong)buffer[offset2 + 3] << 24) | ((ulong)buffer[offset2 + 4] << 32) | ((ulong)buffer[offset2 + 5] << 40) | ((ulong)buffer[offset2 + 6] << 48) | ((ulong)buffer[offset2 + 7] << 56);
			return num ^ num2;
		}

		private static bool Equal2(byte[] buffer, int offset1, int offset2)
		{
			if (buffer[offset1] != buffer[offset2])
			{
				return false;
			}
			return buffer[offset1 + 1] == buffer[offset2 + 1];
		}

		private static bool Equal4(byte[] buffer, int offset1, int offset2)
		{
			if (buffer[offset1] != buffer[offset2])
			{
				return false;
			}
			if (buffer[offset1 + 1] != buffer[offset2 + 1])
			{
				return false;
			}
			if (buffer[offset1 + 2] != buffer[offset2 + 2])
			{
				return false;
			}
			return buffer[offset1 + 3] == buffer[offset2 + 3];
		}

		private static void Copy4(byte[] buf, int src, int dst)
		{
			buf[dst + 3] = buf[src + 3];
			buf[dst + 2] = buf[src + 2];
			buf[dst + 1] = buf[src + 1];
			buf[dst] = buf[src];
		}

		private static void Copy8(byte[] buf, int src, int dst)
		{
			buf[dst + 7] = buf[src + 7];
			buf[dst + 6] = buf[src + 6];
			buf[dst + 5] = buf[src + 5];
			buf[dst + 4] = buf[src + 4];
			buf[dst + 3] = buf[src + 3];
			buf[dst + 2] = buf[src + 2];
			buf[dst + 1] = buf[src + 1];
			buf[dst] = buf[src];
		}

		private static void BlockCopy(byte[] src, int src_0, byte[] dst, int dst_0, int len)
		{
			if (len >= 16)
			{
				Buffer.BlockCopy(src, src_0, dst, dst_0, len);
				return;
			}
			while (len >= 8)
			{
				dst[dst_0] = src[src_0];
				dst[dst_0 + 1] = src[src_0 + 1];
				dst[dst_0 + 2] = src[src_0 + 2];
				dst[dst_0 + 3] = src[src_0 + 3];
				dst[dst_0 + 4] = src[src_0 + 4];
				dst[dst_0 + 5] = src[src_0 + 5];
				dst[dst_0 + 6] = src[src_0 + 6];
				dst[dst_0 + 7] = src[src_0 + 7];
				len -= 8;
				src_0 += 8;
				dst_0 += 8;
			}
			while (len >= 4)
			{
				dst[dst_0] = src[src_0];
				dst[dst_0 + 1] = src[src_0 + 1];
				dst[dst_0 + 2] = src[src_0 + 2];
				dst[dst_0 + 3] = src[src_0 + 3];
				len -= 4;
				src_0 += 4;
				dst_0 += 4;
			}
			while (len-- > 0)
			{
				dst[dst_0++] = src[src_0++];
			}
		}

		private static int WildCopy(byte[] src, int src_0, byte[] dst, int dst_0, int dst_end)
		{
			int num = dst_end - dst_0;
			if (num >= 16)
			{
				Buffer.BlockCopy(src, src_0, dst, dst_0, num);
			}
			else
			{
				while (num >= 4)
				{
					dst[dst_0] = src[src_0];
					dst[dst_0 + 1] = src[src_0 + 1];
					dst[dst_0 + 2] = src[src_0 + 2];
					dst[dst_0 + 3] = src[src_0 + 3];
					num -= 4;
					src_0 += 4;
					dst_0 += 4;
				}
				while (num-- > 0)
				{
					dst[dst_0++] = src[src_0++];
				}
			}
			return num;
		}

		private static int SecureCopy(byte[] buffer, int src, int dst, int dst_end)
		{
			int num = dst - src;
			int num2 = dst_end - dst;
			int num3 = num2;
			if (num >= 16)
			{
				if (num >= num2)
				{
					Buffer.BlockCopy(buffer, src, buffer, dst, num2);
					return num2;
				}
				do
				{
					Buffer.BlockCopy(buffer, src, buffer, dst, num);
					src += num;
					dst += num;
					num3 -= num;
				}
				while (num3 >= num);
			}
			while (num3 >= 4)
			{
				buffer[dst] = buffer[src];
				buffer[dst + 1] = buffer[src + 1];
				buffer[dst + 2] = buffer[src + 2];
				buffer[dst + 3] = buffer[src + 3];
				dst += 4;
				src += 4;
				num3 -= 4;
			}
			while (num3-- > 0)
			{
				buffer[dst++] = buffer[src++];
			}
			return num2;
		}

		public static int Encode32(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;
			}
			if (inputLength < 65547)
			{
				return LZ4_compress64kCtx_safe32(new ushort[8192], input, output, inputOffset, outputOffset, inputLength, outputLength);
			}
			return LZ4_compressCtx_safe32(new int[4096], input, output, inputOffset, outputOffset, inputLength, outputLength);
		}

		public static byte[] Encode32(byte[] input, int inputOffset, int inputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			byte[] array = new byte[MaximumOutputLength(inputLength)];
			int num = Encode32(input, inputOffset, inputLength, array, 0, array.Length);
			if (num != array.Length)
			{
				if (num < 0)
				{
					throw new InvalidOperationException("Compression has been corrupted");
				}
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			return array;
		}

		public static int Encode64(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;
			}
			if (inputLength < 65547)
			{
				return LZ4_compress64kCtx_safe64(new ushort[8192], input, output, inputOffset, outputOffset, inputLength, outputLength);
			}
			return LZ4_compressCtx_safe64(new int[4096], input, output, inputOffset, outputOffset, inputLength, outputLength);
		}

		public static byte[] Encode64(byte[] input, int inputOffset, int inputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			byte[] array = new byte[MaximumOutputLength(inputLength)];
			int num = Encode64(input, inputOffset, inputLength, array, 0, array.Length);
			if (num != array.Length)
			{
				if (num < 0)
				{
					throw new InvalidOperationException("Compression has been corrupted");
				}
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			return array;
		}

		public static int Decode32(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, bool knownOutputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;