Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShaderHelperForMac v3.2.0
plugins/ShaderHelperForMac.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 AssetsTools.NET; using AssetsTools.NET.Extra; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using ShaderHelperForMac.Commands; using ShaderHelperForMac.Config; using ShaderHelperForMac.Diagnostics; using ShaderHelperForMac.Provenance; using ShaderHelperForMac.Replacement; using ShaderHelperForMac.Shaders; using ShaderHelperForMac.Sweep; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ShaderHelperForMac")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("3.2.0.0")] [assembly: AssemblyInformationalVersion("3.2.0+ed52adef9958d16b08ea973bab179130d4c353bc")] [assembly: AssemblyProduct("ShaderHelperForMac")] [assembly: AssemblyTitle("ShaderHelperForMac")] [assembly: AssemblyVersion("3.2.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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 Prefix() { Plugin.RetroactiveBundleSweep("ZNetScene.Awake prefix"); } private static void Postfix() { Plugin.Log.LogDebug((object)"[ZNetScene.Awake] Postfix — running post-ZNetScene sweep."); Plugin._zNetSceneAwakeFired = true; Plugin.TryUpgradeFallbackShader(); Plugin.TryUpgradeTransparentShader(); Plugin.RefreshCanonicalShaderIdsFromLoadedAssets(); Plugin.CheckCachedVanillaCacheVersionDrift(); if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.Instance.SweepMaterialsCoroutine("ZNetScene.Awake")); } } } [HarmonyPatch(typeof(Location), "Awake")] internal static class PatchLocationAwake { private static void Postfix() { Plugin.Log.LogDebug((object)"[Location.Awake] Postfix — sweeping materials after location/dungeon spawn."); if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.Instance.SweepMaterialsCoroutine("Location.Awake")); } } } [HarmonyPatch] internal static class PatchMeleeWeaponTrailStartProbe { private static readonly FieldInfo? _materialField = AccessTools.Field(AccessTools.TypeByName("MeleeWeaponTrail"), "_material"); private static readonly FieldInfo? _trailObjectField = AccessTools.Field(AccessTools.TypeByName("MeleeWeaponTrail"), "m_trailObject"); private static readonly FieldInfo[] _colorFields = ResolveColorFields(); private static readonly FieldInfo? _colorsArrayField = ResolveColorsArrayField(); private static FieldInfo? ResolveColorsArrayField() { FieldInfo[] colorFields = _colorFields; foreach (FieldInfo fieldInfo in colorFields) { if (fieldInfo.Name == "_colors" && fieldInfo.FieldType == typeof(Color[])) { return fieldInfo; } } return null; } private static FieldInfo[] ResolveColorFields() { Type type = AccessTools.TypeByName("MeleeWeaponTrail"); if (type == null) { return Array.Empty<FieldInfo>(); } List<FieldInfo> list = new List<FieldInfo>(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { Type fieldType = fieldInfo.FieldType; if (fieldType == typeof(Color) || fieldType == typeof(Gradient) || fieldType == typeof(Color[])) { list.Add(fieldInfo); } } return list.ToArray(); } private static string FormatColorField(object? value) { //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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) if (value != null) { if (!(value is Color val)) { if (!(value is Color[] array)) { Gradient val2 = (Gradient)((value is Gradient) ? value : null); if (val2 != null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Gradient{"); GradientColorKey[] colorKeys = val2.colorKeys; for (int i = 0; i < colorKeys.Length; i++) { if (i > 0) { stringBuilder.Append(','); } Color color = colorKeys[i].color; stringBuilder.Append($"@{colorKeys[i].time:F2}=({color.r:F2},{color.g:F2},{color.b:F2})"); } stringBuilder.Append("}"); return stringBuilder.ToString(); } return "<" + value.GetType().Name + ">"; } if (array.Length == 0) { return "Color[0]"; } StringBuilder stringBuilder2 = new StringBuilder(); stringBuilder2.Append("Color[").Append(array.Length).Append("]{"); int num = Math.Min(array.Length, 4); for (int j = 0; j < num; j++) { if (j > 0) { stringBuilder2.Append(','); } Color val3 = array[j]; stringBuilder2.Append($"({val3.r:F2},{val3.g:F2},{val3.b:F2},{val3.a:F2})"); } if (array.Length > num) { stringBuilder2.Append(",…"); } stringBuilder2.Append('}'); return stringBuilder2.ToString(); } return $"Color({val.r:F3},{val.g:F3},{val.b:F3},{val.a:F3})"; } return "<null>"; } private static bool IsAdditiveParticleShaderName(string? shaderName) { if (string.IsNullOrEmpty(shaderName)) { return false; } switch (shaderName) { case "Legacy Shaders/Particles/Additive": case "Legacy Shaders/Particles/Additive (Soft)": case "Legacy Shaders/Particles/~Additive-Multiply": case "Mobile/Particles/Additive": case "Particles/Additive": case "Particles/Additive (Soft)": return true; default: return false; } } private static IEnumerable<MethodBase> TargetMethods() { Type t = AccessTools.TypeByName("MeleeWeaponTrail"); if (!(t == null)) { MethodInfo m = AccessTools.Method(t, "Start", Type.EmptyTypes, (Type[])null); if (m != null) { yield return m; } } } private static void Postfix(object __instance) { //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) try { Component val = (Component)((__instance is Component) ? __instance : null); string text = (((Object)(object)val != (Object)null) ? TransformPath(val.transform) : "<no-transform>"); string text2 = "<field-unreadable>"; string text3 = "<field-unreadable>"; if (_materialField != null) { object? value = _materialField.GetValue(__instance); Material val2 = (Material)((value is Material) ? value : null); if ((Object)(object)val2 == (Object)null) { text2 = "<null>"; text3 = "<null>"; } else { text2 = Plugin.StripCloneSuffix(((Object)val2).name); text3 = (((Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : "<null-shader>"); } } string arg = "<none>"; if (_colorFields.Length != 0) { StringBuilder stringBuilder = new StringBuilder(); FieldInfo[] colorFields = _colorFields; foreach (FieldInfo fieldInfo in colorFields) { object value2 = null; try { value2 = fieldInfo.GetValue(__instance); } catch { } if (stringBuilder.Length > 0) { stringBuilder.Append(" "); } stringBuilder.Append(fieldInfo.Name).Append('=').Append(FormatColorField(value2)); } arg = stringBuilder.ToString(); } string text4 = "<trail-object-unreadable>"; if (_trailObjectField != null) { object? value3 = _trailObjectField.GetValue(__instance); GameObject val3 = (GameObject)((value3 is GameObject) ? value3 : null); if ((Object)(object)val3 == (Object)null) { text4 = "<trail-object-null>"; } else { Renderer component = val3.GetComponent<Renderer>(); Material val4 = (((Object)(object)component != (Object)null) ? component.sharedMaterial : null); if ((Object)(object)val4 == (Object)null) { text4 = "<clone-mat-null>"; } else { string text5 = (((Object)(object)val4.shader != (Object)null) ? ((Object)val4.shader).name : "<null-shader>"); string text6 = (val4.HasProperty("_TintColor") ? FormatColorField(val4.GetColor("_TintColor")) : "<absent>"); string text7 = (val4.HasProperty("_EmissionColor") ? FormatColorField(val4.GetColor("_EmissionColor")) : "<absent>"); string text8 = (val4.HasProperty("_Color") ? FormatColorField(val4.color) : "<absent>"); string[] shaderKeywords = val4.shaderKeywords; string text9 = ((shaderKeywords == null || shaderKeywords.Length == 0) ? "<none>" : string.Join("|", shaderKeywords)); text4 = "name='" + Plugin.StripCloneSuffix(((Object)val4).name) + "' shader='" + text5 + "'" + $" matId={((Object)val4).GetInstanceID()}" + " _TintColor=" + text6 + " _EmissionColor=" + text7 + " _Color=" + text8 + " keywords=" + text9; if ((Object)(object)val4.shader != (Object)null && !val4.shader.isSupported && IsAdditiveParticleShaderName(text5)) { Shader val5 = Plugin.FindShaderByNameInternal(text5); if ((Object)(object)val5 != (Object)null && ((Object)val5).GetInstanceID() != ((Object)val4.shader).GetInstanceID()) { int instanceID = ((Object)val4.shader).GetInstanceID(); val4.shader = val5; Plugin.Log.LogInfo((object)("[TrailRebind] '" + text5 + "' on mat '" + Plugin.StripCloneSuffix(((Object)val4).name) + "'" + $" rebound from broken instance id={instanceID} (supported=False)" + $" → canonical id={((Object)val5).GetInstanceID()} (supported=True).")); } if (val4.HasProperty("_TintColor")) { Color val6 = default(Color); ((Color)(ref val6))..ctor(0.5f, 0.5f, 0.5f, 0.5f); Color color = val4.GetColor("_TintColor"); if (!(Math.Abs(color.r - val6.r) < 0.01f) || !(Math.Abs(color.g - val6.g) < 0.01f) || !(Math.Abs(color.b - val6.b) < 0.01f) || !(Math.Abs(color.a - val6.a) < 0.01f)) { val4.SetColor("_TintColor", val6); Plugin.Log.LogInfo((object)("[TrailRebind] '" + text5 + "' on mat '" + Plugin.StripCloneSuffix(((Object)val4).name) + "'" + $" had _TintColor=({color.r:F3},{color.g:F3}," + $"{color.b:F3},{color.a:F3}) → neutralized to" + " vanilla grey (0.5,0.5,0.5,0.5) so the trail matches vanilla with no edge color (Option B: full vanilla match).")); } } } } } } if (Plugin.TrailProbe) { Plugin.Log.LogInfo((object)("[TrailProbe] MeleeWeaponTrail.Start go='" + text + "' trailMaterial='" + text2 + "' shader='" + text3 + "'" + $" colorFields[{_colorFields.Length}]: {arg}" + " liveClone: " + text4)); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("[TrailProbe] swallowed exception: " + ex.GetType().Name + ": " + ex.Message)); } } private static string TransformPath(Transform? t) { if ((Object)(object)t == (Object)null) { return "<null>"; } List<string> list = new List<string>(); Transform val = t; int num = 0; while ((Object)(object)val != (Object)null && num++ < 64) { list.Add(Plugin.StripCloneSuffix(((Object)val).name)); val = val.parent; } StringBuilder stringBuilder = new StringBuilder(); for (int num2 = list.Count - 1; num2 >= 0; num2--) { stringBuilder.Append('/').Append(list[num2]); } return stringBuilder.ToString(); } } [HarmonyPatch(typeof(VisEquipment), "AttachItem")] internal static class PatchVisEquipmentAttachItem { private static readonly HashSet<int> _autoPolishedEquippedMatIds = new HashSet<int>(); private static void Postfix(VisEquipment __instance) { if ((Object)(object)Plugin.Instance == (Object)null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("[AttachItem] " + ((Object)__instance).name + " renderers:"); Renderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null)) { string[] obj = new string[7] { " [", ((object)val).GetType().Name, "] mat='", ((Object)val2).name, "' shader='", null, null }; Shader shader = val2.shader; obj[5] = ((shader != null) ? ((Object)shader).name : null); obj[6] = "'"; stringBuilder.Append(string.Concat(obj)); if (!Plugin.IsMaterialProcessedPublic(val2)) { Plugin.DumpMatPropertiesPublic(val2, "AttachItem"); Plugin.TryReplaceMaterialPublic(val2); } } } } if (Plugin.AutoPolishEquippedMetal) { Renderer[] componentsInChildren2 = ((Component)__instance).GetComponentsInChildren<Renderer>(true); foreach (Renderer val3 in componentsInChildren2) { if ((Object)(object)val3 == (Object)null) { continue; } Material[] sharedMaterials2 = val3.sharedMaterials; foreach (Material val4 in sharedMaterials2) { if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.shader == (Object)null) && !(((Object)val4.shader).name != "Custom/Creature") && val4.HasProperty("_MetallicGlossMap") && !((Object)(object)val4.GetTexture("_MetallicGlossMap") == (Object)null)) { int instanceID = ((Object)val4).GetInstanceID(); if (_autoPolishedEquippedMatIds.Add(instanceID)) { val4.SetFloat("_UseGlossmap", Plugin.AutoPolishUseGlossmap ? 1f : 0f); val4.SetFloat("_MetalGloss", Plugin.AutoPolishMetalGloss); val4.SetFloat("_Glossiness", Plugin.AutoPolishGlossiness); val4.SetFloat("_Metallic", Plugin.AutoPolishMetalAmount); ManualLogSource log = Plugin.Log; string[] obj2 = new string[9] { $"[AutoPolishEquippedMetal] polished mat='{((Object)val4).name}' matId={instanceID}", " shader='", ((Object)val4.shader).name, "' metallicGlossMap='", null, null, null, null, null }; Texture texture = val4.GetTexture("_MetallicGlossMap"); obj2[4] = ((texture != null) ? ((Object)texture).name : null); obj2[5] = "'"; obj2[6] = $" → _UseGlossmap={(Plugin.AutoPolishUseGlossmap ? 1 : 0)}"; obj2[7] = $" _MetalGloss={Plugin.AutoPolishMetalGloss:F2} _Glossiness={Plugin.AutoPolishGlossiness:F2}"; obj2[8] = $" _Metallic={Plugin.AutoPolishMetalAmount:F2}"; log.LogDebug((object)string.Concat(obj2)); } } } } } Plugin.Log.LogDebug((object)stringBuilder.ToString()); } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromFile { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo sync = AccessTools.Method(t, "LoadFromFile", new Type[1] { typeof(string) }, (Type[])null); if (sync != null) { yield return sync; } MethodInfo crc = AccessTools.Method(t, "LoadFromFile", new Type[2] { typeof(string), typeof(uint) }, (Type[])null); if (crc != null) { yield return crc; } MethodInfo off = AccessTools.Method(t, "LoadFromFile", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }, (Type[])null); if (off != null) { yield return off; } } private static void Postfix(AssetBundle __result, string path) { Plugin.OnBundleLoadedFromFile(__result, path); } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromMemory { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo one = AccessTools.Method(t, "LoadFromMemory", new Type[1] { typeof(byte[]) }, (Type[])null); if (one != null) { yield return one; } MethodInfo two = AccessTools.Method(t, "LoadFromMemory", new Type[2] { typeof(byte[]), typeof(uint) }, (Type[])null); if (two != null) { yield return two; } } private static void Postfix(AssetBundle __result) { Plugin.OnBundleLoadedFromMemoryOrStream(__result); } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromStream { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo one = AccessTools.Method(t, "LoadFromStream", new Type[1] { typeof(Stream) }, (Type[])null); if (one != null) { yield return one; } MethodInfo two = AccessTools.Method(t, "LoadFromStream", new Type[2] { typeof(Stream), typeof(uint) }, (Type[])null); if (two != null) { yield return two; } MethodInfo three = AccessTools.Method(t, "LoadFromStream", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }, (Type[])null); if (three != null) { yield return three; } } private static void Postfix(AssetBundle __result) { Plugin.OnBundleLoadedFromMemoryOrStream(__result); } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromFileAsync { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo one = AccessTools.Method(t, "LoadFromFileAsync", new Type[1] { typeof(string) }, (Type[])null); if (one != null) { yield return one; } MethodInfo two = AccessTools.Method(t, "LoadFromFileAsync", new Type[2] { typeof(string), typeof(uint) }, (Type[])null); if (two != null) { yield return two; } MethodInfo three = AccessTools.Method(t, "LoadFromFileAsync", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }, (Type[])null); if (three != null) { yield return three; } } private static void Postfix(AssetBundleCreateRequest __result, string path) { if (__result != null) { ((AsyncOperation)__result).completed += delegate { Plugin.OnBundleLoadedFromFile(__result.assetBundle, path); }; } } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromMemoryAsync { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo one = AccessTools.Method(t, "LoadFromMemoryAsync", new Type[1] { typeof(byte[]) }, (Type[])null); if (one != null) { yield return one; } MethodInfo two = AccessTools.Method(t, "LoadFromMemoryAsync", new Type[2] { typeof(byte[]), typeof(uint) }, (Type[])null); if (two != null) { yield return two; } } private static void Postfix(AssetBundleCreateRequest __result) { if (__result != null) { ((AsyncOperation)__result).completed += delegate { Plugin.OnBundleLoadedFromMemoryOrStream(__result.assetBundle); }; } } } [HarmonyPatch] internal static class PatchAssetBundleLoadFromStreamAsync { private static IEnumerable<MethodBase> TargetMethods() { Type t = typeof(AssetBundle); MethodInfo one = AccessTools.Method(t, "LoadFromStreamAsync", new Type[1] { typeof(Stream) }, (Type[])null); if (one != null) { yield return one; } MethodInfo two = AccessTools.Method(t, "LoadFromStreamAsync", new Type[2] { typeof(Stream), typeof(uint) }, (Type[])null); if (two != null) { yield return two; } MethodInfo three = AccessTools.Method(t, "LoadFromStreamAsync", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }, (Type[])null); if (three != null) { yield return three; } } private static void Postfix(AssetBundleCreateRequest __result) { if (__result != null) { ((AsyncOperation)__result).completed += delegate { Plugin.OnBundleLoadedFromMemoryOrStream(__result.assetBundle); }; } } } internal static class AssetBundleMethodResolver { public static MethodInfo? FindNonGeneric(string name, Type[] paramTypes) { MethodInfo[] methods = typeof(AssetBundle).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.IsGenericMethodDefinition || methodInfo.Name != name) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != paramTypes.Length) { continue; } bool flag = true; for (int j = 0; j < parameters.Length; j++) { if (parameters[j].ParameterType != paramTypes[j]) { flag = false; break; } } if (flag) { return methodInfo; } } return null; } } [HarmonyPatch] internal static class PatchAssetBundleLoadAssetNoType { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo m = AssetBundleMethodResolver.FindNonGeneric("LoadAsset", new Type[1] { typeof(string) }); if (m != null) { yield return m; } } private static void Postfix(AssetBundle __instance, Object __result) { if (!(__result == (Object)null)) { Plugin.OnLoadAssetResult(__instance, __result); Material val = (Material)(object)((__result is Material) ? __result : null); if (val != null) { Plugin.TryReplaceMaterialPublic(val); } } } } [HarmonyPatch] internal static class PatchAssetBundleLoadAsset { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo m = AssetBundleMethodResolver.FindNonGeneric("LoadAsset", new Type[2] { typeof(string), typeof(Type) }); if (m != null) { yield return m; } } private static void Postfix(AssetBundle __instance, Object __result) { if (!(__result == (Object)null)) { Plugin.OnLoadAssetResult(__instance, __result); Material val = (Material)(object)((__result is Material) ? __result : null); if (val != null) { Plugin.TryReplaceMaterialPublic(val); } } } } [HarmonyPatch] internal static class PatchAssetBundleLoadAllAssets { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo none = AssetBundleMethodResolver.FindNonGeneric("LoadAllAssets", new Type[0]); if (none != null) { yield return none; } MethodInfo typed = AssetBundleMethodResolver.FindNonGeneric("LoadAllAssets", new Type[1] { typeof(Type) }); if (typed != null) { yield return typed; } } private static void Postfix(AssetBundle __instance, Object[] __result) { if (__result == null) { return; } foreach (Object val in __result) { if (!(val == (Object)null)) { Plugin.OnLoadAssetResult(__instance, val); Material val2 = (Material)(object)((val is Material) ? val : null); if (val2 != null) { Plugin.TryReplaceMaterialPublic(val2); } } } } } [HarmonyPatch] internal static class PatchAssetBundleLoadAssetAsync { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo one = AssetBundleMethodResolver.FindNonGeneric("LoadAssetAsync", new Type[1] { typeof(string) }); if (one != null) { yield return one; } MethodInfo two = AssetBundleMethodResolver.FindNonGeneric("LoadAssetAsync", new Type[2] { typeof(string), typeof(Type) }); if (two != null) { yield return two; } } private static void Postfix(AssetBundle __instance, AssetBundleRequest __result) { if (__result == null) { return; } ((AsyncOperation)__result).completed += delegate { Object asset = __result.asset; if (!(asset == (Object)null)) { Plugin.OnLoadAssetResult(__instance, asset); Material val = (Material)(object)((asset is Material) ? asset : null); if (val != null) { Plugin.TryReplaceMaterialPublic(val); } } }; } } [HarmonyPatch] internal static class PatchAssetBundleLoadAllAssetsAsync { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo none = AssetBundleMethodResolver.FindNonGeneric("LoadAllAssetsAsync", new Type[0]); if (none != null) { yield return none; } MethodInfo typed = AssetBundleMethodResolver.FindNonGeneric("LoadAllAssetsAsync", new Type[1] { typeof(Type) }); if (typed != null) { yield return typed; } } private static void Postfix(AssetBundle __instance, AssetBundleRequest __result) { if (__result == null) { return; } ((AsyncOperation)__result).completed += delegate { Object[] allAssets = __result.allAssets; if (allAssets != null) { Object[] array = allAssets; foreach (Object val in array) { if (!(val == (Object)null)) { Plugin.OnLoadAssetResult(__instance, val); Material val2 = (Material)(object)((val is Material) ? val : null); if (val2 != null) { Plugin.TryReplaceMaterialPublic(val2); } } } } }; } } internal static class PatchEffectListCreateSwingProbe { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo m = AccessTools.Method(typeof(EffectList), "Create", new Type[5] { typeof(Vector3), typeof(Quaternion), typeof(Transform), typeof(float), typeof(int) }, (Type[])null); if (m != null) { yield return m; } } private static void Postfix(GameObject[] __result) { try { if (__result == null) { return; } foreach (GameObject val in __result) { if ((Object)(object)val == (Object)null) { continue; } Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } Material[] sharedMaterials = val2.sharedMaterials; foreach (Material val3 in sharedMaterials) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.shader == (Object)null) && ((Object)val3.shader).name.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase)) { Plugin.Log.LogInfo((object)("[SwingProbe] EffectList.Create spawned error-shader material: mat='" + ((Object)val3).name + "' shader='" + ((Object)val3.shader).name + "'" + $" matId={((Object)val3).GetInstanceID()}" + " rendererType=" + ((object)val2).GetType().Name + " go='" + ((Object)((Component)val2).gameObject).name + "' rootGo='" + ((Object)val).name + "'" + $" alreadyProcessed={Plugin.IsMaterialProcessedPublic(val3)}" + $" isErrorPink={Plugin.IsErrorPinkPublic(val3)}")); } } } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("[SwingProbe] swallowed exception: " + ex.GetType().Name + ": " + ex.Message)); } } } internal static class PatchAttackSwingProbe2 { private const int HeartbeatCap = 8; private static int _heartbeatCount; private const int SceneScanCap = 4; private static int _sceneScanCount; private const int WindowCap = 2; private const int WindowFrames = 30; private static int _windowCount; private static bool _windowRunning; private static IEnumerable<MethodBase> TargetMethods() { MethodInfo trigger = AccessTools.Method(typeof(Attack), "OnAttackTrigger", Type.EmptyTypes, (Type[])null); if (trigger != null) { yield return trigger; } MethodInfo melee = AccessTools.Method(typeof(Attack), "DoMeleeAttack", Type.EmptyTypes, (Type[])null); if (melee != null) { yield return melee; } } private static string TransformPath(Transform t) { StringBuilder stringBuilder = new StringBuilder(); List<string> list = new List<string>(); Transform val = t; int num = 0; while ((Object)(object)val != (Object)null && num++ < 64) { list.Add(Plugin.StripCloneSuffix(((Object)val).name)); val = val.parent; } for (int num2 = list.Count - 1; num2 >= 0; num2--) { stringBuilder.Append('/').Append(list[num2]); } return stringBuilder.ToString(); } private static void Postfix(MethodBase __originalMethod) { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string text = __originalMethod?.Name ?? "Attack"; int num = 0; int num2 = 0; Renderer[] componentsInChildren = ((Component)localPlayer).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } num++; Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.shader == (Object)null) && ((Object)val2.shader).name.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase)) { num2++; Plugin.Log.LogInfo((object)("[SwingProbe2] hook=" + text + " error-shader material under local player: mat='" + ((Object)val2).name + "' shader='" + ((Object)val2.shader).name + "'" + $" matId={((Object)val2).GetInstanceID()}" + " rendererType=" + ((object)val).GetType().Name + " go='" + ((Object)((Component)val).gameObject).name + "'" + $" alreadyProcessed={Plugin.IsMaterialProcessedPublic(val2)}" + $" isErrorPink={Plugin.IsErrorPinkPublic(val2)}")); } } } if (_sceneScanCount < 4) { _sceneScanCount++; int num3 = 0; int num4 = 0; Renderer[] array = Resources.FindObjectsOfTypeAll<Renderer>(); foreach (Renderer val3 in array) { if ((Object)(object)val3 == (Object)null) { continue; } num3++; Material[] sharedMaterials2 = val3.sharedMaterials; foreach (Material val4 in sharedMaterials2) { if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.shader == (Object)null) && ((Object)val4.shader).name.StartsWith("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase)) { num4++; Plugin.Log.LogInfo((object)($"[SwingProbe2-Scene] scan #{_sceneScanCount}/{4} hook={text}" + " mat='" + ((Object)val4).name + "' shader='" + ((Object)val4.shader).name + "'" + $" matId={((Object)val4).GetInstanceID()}" + " rendererType=" + ((object)val3).GetType().Name + " path='" + TransformPath(((Component)val3).transform) + "'" + $" activeInHierarchy={((Component)val3).gameObject.activeInHierarchy}" + $" rendererEnabled={val3.enabled}" + $" alreadyProcessed={Plugin.IsMaterialProcessedPublic(val4)}" + $" isErrorPink={Plugin.IsErrorPinkPublic(val4)}")); } } } Plugin.Log.LogInfo((object)($"[SwingProbe2-Scene] scan #{_sceneScanCount}/{4} hook={text}" + $" sceneRenderers={num3} sceneErrorShaderMatches={num4}")); } if (_windowCount < 2 && !_windowRunning && (Object)(object)Plugin.Instance != (Object)null) { _windowCount++; _windowRunning = true; ((MonoBehaviour)Plugin.Instance).StartCoroutine(PerFrameWindowScan(text, _windowCount)); } if (_heartbeatCount < 8) { _heartbeatCount++; Plugin.Log.LogInfo((object)($"[SwingProbe2] heartbeat #{_heartbeatCount}/{8} hook={text}" + $" renderersScanned={num} errorShaderMatches={num2}")); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("[SwingProbe2] swallowed exception: " + ex.GetType().Name + ": " + ex.Message)); } } private static IEnumerator PerFrameWindowScan(string hook, int windowIndex) { Plugin.Log.LogInfo((object)($"[SwingProbe2-Window] window #{windowIndex}/{2} OPEN hook={hook}" + " — DE-ASSUMED per-frame scan (error-pink-by-color OR trail/line/particle" + $" renderer; reads sharedMaterials AND materials) for up to {30} frames")); HashSet<string> loggedKeys = new HashSet<string>(StringComparer.Ordinal); int distinctLogged = 0; MaterialPropertyBlock mpbScratch = new MaterialPropertyBlock(); HashSet<string> pinkSourceKeys = new HashSet<string>(StringComparer.Ordinal); int pinkSourceLogged = 0; for (int frame = 0; frame < 30; frame++) { yield return (object)new WaitForEndOfFrame(); Renderer[] all; try { all = Resources.FindObjectsOfTypeAll<Renderer>(); } catch (Exception ex) { Plugin.Log.LogDebug((object)$"[SwingProbe2-Window] enumerate failed frame={frame}: {ex.Message}"); continue; } Renderer[] array = all; foreach (Renderer r in array) { if ((Object)(object)r == (Object)null) { continue; } bool isTrailLikeRenderer = r is TrailRenderer || r is LineRenderer || r is ParticleSystemRenderer; Material[] shared; try { shared = r.sharedMaterials; } catch { shared = Array.Empty<Material>(); } bool sharedHasPink = false; Material[] array2 = shared; foreach (Material mat in array2) { if (!((Object)(object)mat == (Object)null)) { bool pink = false; try { pink = Plugin.IsErrorPinkPublic(mat); } catch { } if (pink) { sharedHasPink = true; } if (pink || isTrailLikeRenderer) { EmitWindowMatch(windowIndex, frame, "shared", r, mat, pink, loggedKeys, ref distinctLogged); } } } if (isTrailLikeRenderer || sharedHasPink) { Material[] inst; try { inst = r.materials; } catch { inst = Array.Empty<Material>(); } Material[] array3 = inst; foreach (Material mat2 in array3) { if (!((Object)(object)mat2 == (Object)null)) { bool pink2 = false; try { pink2 = Plugin.IsErrorPinkPublic(mat2); } catch { } if (pink2 || isTrailLikeRenderer) { EmitWindowMatch(windowIndex, frame, "instance", r, mat2, pink2, loggedKeys, ref distinctLogged); } } } } if (isTrailLikeRenderer) { try { EmitPinkSourceMatch(windowIndex, frame, r, mpbScratch, pinkSourceKeys, ref pinkSourceLogged); } catch (Exception ex2) { Exception ex3 = ex2; Plugin.Log.LogDebug((object)("[PinkSourceProbe] swallowed exception: " + ex3.GetType().Name + ": " + ex3.Message)); } } } } Plugin.Log.LogInfo((object)($"[SwingProbe2-Window] window #{windowIndex} CLOSED at frame cap ({30})" + $" — distinctLogged={distinctLogged} (each line is a candidate for what the pink" + " swing arc actually is; 0 means neither error-pink-by-color nor any trail/line/ particle material appeared in the window — next probe widens render technique).")); _windowRunning = false; } private static void EmitWindowMatch(int windowIndex, int frame, string slot, Renderer r, Material mat, bool pink, HashSet<string> loggedKeys, ref int distinctLogged) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)mat.shader != (Object)null) ? ((Object)mat.shader).name : "<null-shader>"); string text2; try { text2 = TransformPath(((Component)r).transform); } catch { text2 = "<path-failed>"; } string item = $"{((object)r).GetType().Name}|{text}|{text2}|{pink}|{slot}"; if (!loggedKeys.Add(item)) { return; } distinctLogged++; string arg = "n/a"; try { if (mat.HasProperty("_Color")) { arg = ((object)mat.color/*cast due to .constrained prefix*/).ToString(); } } catch { } Plugin.Log.LogInfo((object)($"[SwingProbe2-Window] window #{windowIndex} frame=+{frame} CANDIDATE slot={slot}" + " mat='" + ((Object)mat).name + "' shader='" + text + "'" + $" matId={((Object)mat).GetInstanceID()}" + " rendererType=" + ((object)r).GetType().Name + " path='" + text2 + "'" + $" isErrorPinkByColor={pink} color={arg}" + $" activeInHierarchy={((Component)r).gameObject.activeInHierarchy}" + $" rendererEnabled={r.enabled}" + $" alreadyProcessed={Plugin.IsMaterialProcessedPublic(mat)}")); } private static bool IsMagenta(Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return MaterialClassifier.IsMagenta(c); } private static void EmitPinkSourceMatch(int windowIndex, int frame, Renderer r, MaterialPropertyBlock mpbScratch, HashSet<string> pinkSourceKeys, ref int pinkSourceLogged) { //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) List<(string, Color)> list = new List<(string, Color)>(4); Material val = null; string text = "<none>"; string text2 = "<none>"; try { Material[] sharedMaterials = r.sharedMaterials; if (sharedMaterials != null) { Material[] array = sharedMaterials; foreach (Material val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } val = val2; text = ((Object)val2).name; text2 = (((Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : "<null-shader>"); if (val2.HasProperty("_Color")) { Color color = val2.color; if (IsMagenta(color)) { list.Add(("mat._Color", color)); } } if (val2.HasProperty("_TintColor")) { Color color2 = val2.GetColor("_TintColor"); if (IsMagenta(color2)) { list.Add(("mat._TintColor", color2)); } } if (val2.HasProperty("_EmissionColor")) { Color color3 = val2.GetColor("_EmissionColor"); if (IsMagenta(color3)) { list.Add(("mat._EmissionColor", color3)); } } break; } } } catch { } try { if (r.HasPropertyBlock()) { mpbScratch.Clear(); r.GetPropertyBlock(mpbScratch); Color color4 = mpbScratch.GetColor("_Color"); Color color5 = mpbScratch.GetColor("_MainColor"); Color color6 = mpbScratch.GetColor("_TintColor"); if (IsMagenta(color4)) { list.Add(("mpb._Color", color4)); } if (IsMagenta(color5)) { list.Add(("mpb._MainColor", color5)); } if (IsMagenta(color6)) { list.Add(("mpb._TintColor", color6)); } } } catch { } try { ParticleSystem component = ((Component)r).gameObject.GetComponent<ParticleSystem>(); if ((Object)(object)component != (Object)null) { MainModule main = component.main; MinMaxGradient startColor = ((MainModule)(ref main)).startColor; Color color7 = ((MinMaxGradient)(ref startColor)).color; if (IsMagenta(color7)) { list.Add(("ps.startColor", color7)); } } } catch { } if (list.Count == 0) { return; } string text3; try { text3 = TransformPath(((Component)r).transform); } catch { text3 = "<path-failed>"; } string text4 = string.Join("+", list.ConvertAll(((string src, Color col) h) => h.src)); string item = ((object)r).GetType().Name + "|" + text2 + "|" + text3 + "|" + text4; if (pinkSourceKeys.Add(item)) { pinkSourceLogged++; bool flag = list.Exists(((string src, Color col) h) => ((Color)(ref h.col)).maxColorComponent > 1f); string arg = string.Join(" ", list.ConvertAll(((string src, Color col) h) => $"{h.src}=RGBA({h.col.r:F2},{h.col.g:F2},{h.col.b:F2},{h.col.a:F2})|HDR={((Color)(ref h.col)).maxColorComponent > 1f}")); Plugin.Log.LogInfo((object)($"[PinkSourceProbe] window #{windowIndex} frame=+{frame} MAGENTA-SOURCE={text4}" + $" anyHDR={flag} values=[{arg}]" + " mat='" + text + "' shader='" + text2 + "'" + $" matId={(((Object)(object)val != (Object)null) ? ((Object)val).GetInstanceID() : 0)}" + " rendererType=" + ((object)r).GetType().Name + " path='" + text3 + "'" + $" activeInHierarchy={((Component)r).gameObject.activeInHierarchy}" + $" rendererEnabled={r.enabled}")); } } } internal static class PatchShaderFindBindProbe { private static readonly HashSet<string> _shaderFindProbeFiredNames = new HashSet<string>(StringComparer.Ordinal); private static void Postfix(string name, Shader __result) { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__result == (Object)null) { return; } string text = ((Object)__result).name ?? string.Empty; if (string.IsNullOrEmpty(text) || !BundleAttribution.IsVanillaShaderName(text) || !_shaderFindProbeFiredNames.Add(text)) { return; } Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); int num = 0; List<int> list = new List<int>(); int instanceID = ((Object)__result).GetInstanceID(); Shader[] array2 = array; foreach (Shader val in array2) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name != text) && ((Object)val).GetInstanceID() != instanceID) { num++; if (list.Count < 8) { list.Add(((Object)val).GetInstanceID()); } } } if (num >= 1) { string text2 = string.Join(",", list); string text3 = ((num > list.Count) ? ("+" + (num - list.Count) + "more") : string.Empty); string text4 = "n/a"; try { int num2 = __result.FindPropertyIndex("_Color"); text4 = ((num2 < 0) ? "no-_Color" : ((object)__result.GetPropertyType(num2)/*cast due to .constrained prefix*/).ToString()); } catch (Exception) { } Plugin.Log.LogInfo((object)("[BindProbe-ShaderFind] requestedName='" + name + "' returnedName='" + text + "'" + $" returnedId={instanceID} peerCount={num} peerIds=[{text2}{text3}]" + $" returnedRQ={__result.renderQueue} returnedIsSupported={__result.isSupported}" + " schema=" + text4 + " vanillaName=true")); } } catch (Exception ex2) { Plugin.Log.LogDebug((object)("[BindProbe-ShaderFind] swallowed exception for Find request '" + (name ?? "<null>") + "': " + ex2.GetType().Name + ": " + ex2.Message)); } } } [DefaultExecutionOrder(30000)] internal sealed 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; } } } internal enum ShaderAction { Transparent, Fallback, Original, UseShader } [BepInPlugin("aaa.drummercraig.shaderhelperformac", "ShaderHelperForMac", "3.2.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "aaa.drummercraig.shaderhelperformac"; public const string PluginName = "ShaderHelperForMac"; public const string PluginVersion = "3.2.0"; internal static readonly string UseTransparentShaderFile = "usetransparentshader.txt"; internal static readonly string UseFallbackShaderFile = "usefallbackshader.txt"; internal static readonly string UseOriginalShaderFile = "useoriginalshader.txt"; internal static HashSet<string> _useTransparentDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _useFallbackDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _useOriginalDlls = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _transparentMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _fallbackMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _originalMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static List<string> _transparentMatSuffixes = new List<string>(); internal static List<string> _fallbackMatSuffixes = new List<string>(); internal static HashSet<string> _forceFallbackMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static List<string> _forceFallbackMatSuffixes = new List<string>(); internal static HashSet<string> _forceTransparentMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static List<string> _forceTransparentMatSuffixes = new List<string>(); internal static HashSet<string> _forceFallbackPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _forceTransparentPrefixSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static Dictionary<string, string> _matShaderOverrides = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); internal static Dictionary<string, List<(string prop, string value)>> _matShaderPropertyOverrides = new Dictionary<string, List<(string, string)>>(StringComparer.OrdinalIgnoreCase); internal static Dictionary<string, List<(string keyword, bool enable)>> _matShaderKeywordOverrides = new Dictionary<string, List<(string, bool)>>(StringComparer.OrdinalIgnoreCase); internal static HashSet<string> _hideRendererMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static List<string> _hideRendererMatSuffixes = new List<string>(); private FileSystemWatcher? _watcher; private ConfigEntry<float> _cfgPeriodicSweepInterval = null; private ConfigEntry<string> _cfgBridgeTraceMatNames = null; private ConfigEntry<bool> _cfgSweepProgressTrace = null; private ConfigEntry<bool> _cfgVanillaRebindEnabled = null; private ConfigEntry<bool> _cfgPreserveAdditiveParticles = null; private ConfigEntry<bool> _cfgHunFXAutoDefault = null; private ConfigEntry<bool> _cfgRepairInternalErrorShader = null; private ConfigEntry<bool> _cfgTrailProbe = null; private ConfigEntry<bool> _cfgDiagnosticProbes = null; private ConfigEntry<bool> _cfgAutoPolishMetallic = null; private ConfigEntry<bool> _cfgAutoPolishEquippedMetal = null; private ConfigEntry<bool> _cfgAutoPolishUseGlossmap = null; private ConfigEntry<float> _cfgAutoPolishMetalGloss = null; private ConfigEntry<float> _cfgAutoPolishGlossiness = null; private ConfigEntry<float> _cfgAutoPolishMetalAmount = null; private static Plugin? _instance; internal static readonly Dictionary<string, string> ModShaderDlls = new Dictionary<string, string>(); internal static readonly Dictionary<string, string> _bundleToDll = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> _tocAttributedBundles = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly Dictionary<string, string> _prefabRootToDll = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); internal static readonly string[] FallbackChain = new string[2] { "Custom/Creature", "Custom/Piece" }; internal static readonly string[] TransparentChain = new string[5] { "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended", "Particles/Standard Surface2", "Sprites/Default", "UI/Default" }; internal static readonly HashSet<int> CanonicalShaderIds = new HashSet<int>(); internal static readonly HashSet<string> _vanillaBundleNames = new HashSet<string>(StringComparer.Ordinal); internal static bool _awakeVanillaSnapshotEmpty; internal static bool _zNetSceneAwakeFired; internal static readonly List<AssetBundle> _deferredMemoryStreamBundles = new List<AssetBundle>(); internal static string? _valheimDataPath; internal static readonly HashSet<string> _modPrefabRootNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<int> _prefabScopedModMatIds = new HashSet<int>(); internal static readonly HashSet<int> _particleRendererMatIdHints = new HashSet<int>(); internal static readonly HashSet<int> _forceReplacedMaterialIds = new HashSet<int>(); internal static readonly Dictionary<int, (bool intent, Color color, Texture? map, bool keyword)> _originalEmissionByMat = new Dictionary<int, (bool, Color, Texture, bool)>(); internal static readonly HashSet<string> _baselineMatNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> _vanillaShaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly string[] ValheimShaderNames = new string[55] { "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", "Particles/Standard Unlit2", "Particles/Standard Surface2", "Standard TwoSided", "FX/Glass/Stained BumpDistort", "FX/Glass/Stained", "Unlit/Lighting", "ToonDeferredShading", "ToonDeferredShading2017", "Earthquake/Tree", "Earthquake/Leaf", "Hovl/Particles/Additive", "Hovl/Particles/AlphaBlend" }; internal static readonly HashSet<string> ValheimShaderNameSet = new HashSet<string>(ValheimShaderNames, StringComparer.OrdinalIgnoreCase); internal static readonly string[] UnityBuiltInShaderNames = new string[36] { "Standard", "Standard (Specular setup)", "Standard (Roughness setup)", "Sprites/Default", "Sprites/Mask", "UI/Default", "UI/DefaultFont", "UI/Unlit/Text", "UI/Unlit/Transparent", "Unlit/Color", "Unlit/Texture", "Unlit/Transparent", "Unlit/Transparent Cutout", "Diffuse", "Mobile/Diffuse", "Transparent/Diffuse", "VertexLit", "Mobile/VertexLit", "Legacy Shaders/Particles/Alpha Blended", "Legacy Shaders/Particles/Additive", "Legacy Shaders/Particles/Additive (Soft)", "Legacy Shaders/Particles/Multiply", "Legacy Shaders/Particles/VertexLit Blended", "Particles/Standard Unlit", "Particles/Standard Surface", "TextMeshPro/Distance Field", "TextMeshPro/Distance Field (Surface)", "TextMeshPro/Distance Field Overlay", "TextMeshPro/Distance Field SSD", "TextMeshPro/Mobile/Distance Field", "TextMeshPro/Mobile/Distance Field - Masking", "TextMeshPro/Mobile/Distance Field Overlay", "TextMeshPro/Bitmap", "TextMeshPro/Mobile/Bitmap", "TextMeshPro/Sprite", "GUI/Text Shader" }; internal static readonly HashSet<string> UnityBuiltInShaderNameSet = new HashSet<string>(UnityBuiltInShaderNames, StringComparer.OrdinalIgnoreCase); internal static Material? _transparentMat; internal static Material? _fallbackMat; internal bool _initialized; internal bool _sweepRunning; internal static bool _sweepDisabled; internal static string? _cachedValheimVersionForDriftCheck; internal static int _consecutiveSweepSkips; internal static bool _forceNextPeriodicSweep; internal static ManualLogSource Log { get; private set; } = null; internal static Plugin Instance { get; private set; } = null; internal static string ConfigDir => Path.Combine(Paths.ConfigPath, "ShaderHelperForMac"); internal static float PeriodicSweepInterval => _instance?._cfgPeriodicSweepInterval.Value ?? 30f; internal static HashSet<string> BridgeTraceMatNames { get { string text = _instance?._cfgBridgeTraceMatNames.Value ?? string.Empty; HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(text)) { return hashSet; } string[] array = text.Split(new char[1] { ',' }); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.Length > 0) { hashSet.Add(text3); } } return hashSet; } } internal static bool SweepProgressTrace => _instance?._cfgSweepProgressTrace?.Value == true; internal static bool VanillaRebindEnabled => _instance?._cfgVanillaRebindEnabled?.Value ?? true; internal static bool PreserveAdditiveParticles => _instance?._cfgPreserveAdditiveParticles?.Value == true; internal static bool HunFXAutoDefault => _instance?._cfgHunFXAutoDefault?.Value ?? true; internal static bool AutoPolishMetallic => _instance?._cfgAutoPolishMetallic?.Value == true; internal static bool AutoPolishEquippedMetal => _instance?._cfgAutoPolishEquippedMetal?.Value ?? true; internal static float AutoPolishMetalAmount => _instance?._cfgAutoPolishMetalAmount?.Value ?? 1f; internal static bool AutoPolishUseGlossmap => _instance?._cfgAutoPolishUseGlossmap?.Value ?? true; internal static float AutoPolishMetalGloss => _instance?._cfgAutoPolishMetalGloss?.Value ?? 0.7f; internal static float AutoPolishGlossiness => _instance?._cfgAutoPolishGlossiness?.Value ?? 0.9f; internal static bool RepairInternalErrorShader => _instance?._cfgRepairInternalErrorShader?.Value ?? true; internal static bool TrailProbe => _instance?._cfgTrailProbe?.Value == true; internal static bool DiagnosticProbes => _instance?._cfgDiagnosticProbes?.Value == true; internal static bool _transparentShaderIsParticleCapable { get; set; } internal static Shader? FallbackShader { get; set; } internal static string StripCloneSuffix(string name) { while (name.EndsWith("(Clone)", StringComparison.Ordinal)) { name = name.Substring(0, name.Length - "(Clone)".Length); } return name; } internal static void PopulateLane5FromSceneWalk() { _prefabScopedModMatIds.Clear(); if (_modPrefabRootNames.Count == 0) { return; } int num = 0; int num2 = 0; Renderer[] array = Resources.FindObjectsOfTypeAll<Renderer>(); Renderer[] array2 = array; foreach (Renderer val in array2) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; Transform val2 = ((Component)val).transform; while ((Object)(object)val2 != (Object)null) { string item = StripCloneSuffix(((Object)val2).name); if (_modPrefabRootNames.Contains(item)) { flag = true; break; } val2 = val2.parent; } if (!flag) { continue; } num++; Material[] sharedMaterials = val.sharedMaterials; foreach (Material val3 in sharedMaterials) { if (!((Object)(object)val3 == (Object)null) && _prefabScopedModMatIds.Add(((Object)val3).GetInstanceID())) { num2++; } } } if (num > 0) { Log.LogDebug((object)$"[Provenance] Lane-5 prefab scope: {num} renderer(s) under declared [prefab] ancestor(s), admitting {num2} material instance(s)"); } } internal static void CheckCachedVanillaCacheVersionDrift() { if (_cachedValheimVersionForDriftCheck != null) { string valheimVersionViaReflection = VanillaBaselineCache.GetValheimVersionViaReflection(); if (!string.Equals(_cachedValheimVersionForDriftCheck, valheimVersionViaReflection, StringComparison.Ordinal)) { Log.LogWarning((object)("[VanillaCache] version drift: cache was produced for Valheim '" + _cachedValheimVersionForDriftCheck + "' but this install reports '" + valheimVersionViaReflection + "'. Keeping the cache loaded; if you observe vanilla materials being replaced, run `shaderhelper capturevanilla` from a clean install to refresh.")); } _cachedValheimVersionForDriftCheck = null; } } private void Awake() { Instance = this; _instance = this; Log = ((BaseUnityPlugin)this).Logger; BundleAttribution.EmitBaselineSnapshot("Awake-Start"); _cfgPeriodicSweepInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Periodic Sweep Interval", 600f, "How often (in seconds) to re-sweep all materials. The periodic sweep is now a safety net for unobserved bundle-load / prefab-spawn events; the primary mechanisms are Harmony postfixes on ZNetScene.Awake, Location.Awake, AssetBundle.Load*, VisEquipment.AttachItem, and the scene-load handler. Default raised to 600 s in v3.0.63 because the v2.1.17 admission-epoch skip-gate already short-circuits every periodic sweep on a stable scene; the cadence only matters when the safety cap (10 consecutive skips) forces a full sweep. Lower this (e.g. 120 or 30) if you run VFX-heavy mods that spawn materials frequently and you observe pink materials between sweeps. Set to 0 to disable the periodic timer entirely."); _cfgBridgeTraceMatNames = ((BaseUnityPlugin)this).Config.Bind<string>("Diagnostics", "Bridge Trace Mat Names", "", "Diagnostic-only. Comma-separated list of material base names (case-insensitive, after StripInstance normalization). When a material's name is in this list, BridgeMaterialProperties emits one [BridgeTrace] log line per bridge call with the source _EmissionColor, IsHdrEmission result, _EMISSION keyword state, and HasEmissiveIntent result. Empty disables the trace (default). Used to gather evidence for the v3.0.7 emission-bridge timing investigation; see LESSONS_LEARNED.md and CHANGELOG v3.0.7. Pure read-only observation — does not affect any gate, sweep, or resolver decision."); _cfgSweepProgressTrace = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Sweep Progress Trace", false, "Diagnostic-only. When true, SweepMaterialsCoroutine emits one [SweepProgress] log line per SweepBatchSize (=100) renderer batch, reporting per-batch wall-clock, cumulative sweep time, renderer index, mats processed, and replacement count. Used to identify where periodic-sweep wall-clock cost is concentrated when investigating frame-time stutter. Default false; enable for one diagnostic session, then disable. Pure read-only observation — does not affect any gate, sweep decision, or resolver outcome. See CHANGELOG v3.0.16."); _cfgVanillaRebindEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Vanilla Rebind Enabled", true, "When true (DEFAULT), TryReplaceMaterial rebinds any material to the canonical Unity instance of its vanilla-named shader, ONCE per material per session, AND ONLY when the material is on a ParticleSystemRenderer this sweep. Fixes the dropped-item particle indicator (item_particle on Magic_Supremacy drops) without re-introducing the v2.1.27-class weapon flicker that v3.0.27's unscoped rebind caused. Set to false to disable the rebind entirely (restoring v3.0.28 behaviour: item_particle renders pink on dropped items, but no weapon flicker risk). The flag is provided as a kill-switch only — flipping to false is intended for users who observe regressions on materials this rebind class shouldn't have touched. See CHANGELOG v3.0.30 for the v3.0.29 evidence and v3.0.30 design."); _cfgPreserveAdditiveParticles = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Preserve Additive Particles", true, "Default ON (v3.1.33). When true, a gate-admitted mod material whose current shader is already a supported additive / alpha-blended particle shader (e.g. 'Legacy Shaders/Particles/Additive', 'Particles/Standard Unlit') AND has no hard mat:/suffix: rule is LEFT ON ITS OWN SHADER instead of being routed through the aggressive-family Fallback bind to Custom/Creature (which drops the additive _TintColor/_InvFade controls — the flame_TW 'good look' loss). This reproduces, without a rule, what '[useshader] Legacy Shaders/Particles/Additive' achieves. Any user [forcefallback]/[forcetransparent]/[useshader] rule still wins (the branch is gated on no-hard-rule). Vanilla materials are unaffected (the provenance veto runs first). The v3.1.32 default-OFF opt-in was validated in-game (2165 [PreserveAdditive] fires across 36 distinct VFX materials on 4 shader families, zero solid geometry caught) and flipped to default-ON in v3.1.33. Set to false to disable the preservation branch and route additive particles through the aggressive-family Fallback. See CHANGELOG v3.1.32 + v3.1.33."); _cfgHunFXAutoDefault = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "HunFX Auto Default", true, "Default ON (v3.1.54, validated in-game). When true, a gate-admitted mod material whose current shader is in the 'HunFX/' family (the HunFX VFX shader pack — bursts / fire / embers / slashes, shader names 'HunFX/SH_HunFX_common', 'HunFX/SH_HunFX_simple', etc.) is automatically bridged to 'Legacy Shaders/Particles/Additive' — the same target users hand-write '[useshader]' rules for on these materials, applied automatically. This branch runs BEFORE the [useshader] consumption block, so it decides purely from the material's shader identity and ignores any [useshader] rule for HunFX materials by construction. Vanilla materials are unaffected (the provenance veto runs first). The v3.1.53 default-OFF opt-in was validated in-game (449 [HunFXAutoDefault] fires across 51 distinct VFX materials on 3 HunFX shaders, all landing Additive, zero solid geometry caught) and flipped to default-ON in v3.1.54. Set to false to disable the auto-default and route HunFX materials through the aggressive-family Fallback (or your own [useshader] rules). See CHANGELOG v3.1.53 + v3.1.54."); _cfgRepairInternalErrorShader = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Repair Internal Error Shader", true, "Default ON. When true, a material whose runtime shader is Unity's 'Hidden/InternalErrorShader' placeholder (the magenta error shader Unity substitutes when a real shader fails to compile or load on Metal) is admitted to the sweep and bound to the Fallback shader (Custom/Creature) so it renders visibly instead of staying pink. Set to false to leave such materials magenta — the opt-in 'show me the pink items that were on this shader' diagnostic: both recognition sites (MaterialClassifier.NeedsReplacement and ActionResolver.ResolveByShaderName) fall through, and because 'Hidden/' is on the safe-shader prefix list NeedsReplacement returns false, leaving the material on its error-shader binding. This is a sweep-side filter toggle, NOT a provenance-gate change — vanilla materials rendering correctly are never affected (their shader is not Hidden/InternalErrorShader). See CHANGELOG v3.1.34."); _cfgTrailProbe = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Trail Probe", false, "Diagnostic-only (default OFF). When true, a read-only Harmony postfix on Valheim's MeleeWeaponTrail.Start emits one [TrailProbe] log line per weapon-trail component as it is created, reporting the trail material's name + shader + the owning GameObject path. The vanilla weapon swing/sweep trail is a runtime-generated mesh on a detached GameObject('Trail') with a MeshRenderer — NOT a TrailRenderer, NOT a particle — so it cannot be named by `nearby` / `capture` / `watchr` or by the offline bundle tools. Enable this, swing a weapon, then read the [TrailProbe] lines in LogOutput.log to get the material name. Pure read-only observation — mutates no material, renderer, gate, sweep, resolver, or cache. Disable when done. See CHANGELOG v3.1.56."); _cfgDiagnosticProbes = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Diagnostic Probes", false, "Diagnostic-only (default OFF). When true, the [BindProbe-*] shader-collision diagnostics in the bundle-load / Awake paths (OnLoadAsset, MaterialLoad, GameObjectMaterial, ShaderLoad, Baseline, RetroactiveSweep) emit [BindProbe-*] LogInfo lines and run their Resources.FindObjectsOfTypeAll<Shader>() peer-count scans. These are pure read-only observation used to localize vanilla-shader-name collisions during development; they mutate no material, gate, sweep, resolver, baseline, or cache state. Left OFF, the plugin skips the scan + log work entirely on every bundle load and Awake snapshot — recommended for normal play. Enable only for one diagnostic session when asked to capture [BindProbe-*] evidence, then disable. See CHANGELOG v3.1.65."); _cfgAutoPolishMetallic = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Auto Polish Metallic Materials", false, "Default OFF (opt-in). When true, a gate-admitted mod material whose source _Metallic >= 0.5 AND that has a metallic-gloss map bound (_MetallicGlossMap / _MetallicMap) has its smoothness slots written (_UseGlossmap=1, _MetalGloss=0.7, _Glossiness=0.9, _Smoothness=0.9) after the Fallback bridge so the matte-metal blade (e.g. BronzeClaymore_mat_TW: _Metallic=1 + metallic-roughness map + smoothness 0 = dark diffuse metal on Metal) reads polished instead of dark. This automates, without a per-sword rule, the fix the user validated by hand via '[useshader] mat:<Blade> Custom/Creature _UseGlossmap=1 _MetalGloss=0.7 _Glossiness=0.9'. The write lands at the POST-BRIDGE Frame-B site the v3.1.49 probe proved has the writable slots (the reverted v3.1.45–47 wrote inside the bridge against a different, slot-less Custom/Creature instance and no-op'd three times). Non-metals (antler/leather/wood, all _Metallic=0) never enter the branch. Any per-mod [useshader] rule still wins (a ruled material returns before reaching this branch). Vanilla materials are unaffected (the provenance veto runs first). Sweep-side property write, NOT a provenance-gate change. Set to true to enable; validate that the intended blades polish and no non-metal changes, then a future release may flip the default ON. See CHANGELOG v3.1.49 + v3.1.50."); _cfgAutoPolishEquippedMetal = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Auto Polish Equipped Metal", true, "Default ON (v3.1.52, validated in-game). When true, an equipped-item material the plugin has already bridged to Custom/Creature that carries an ASSIGNED metallic-gloss texture (_MetallicGlossMap has a real texture, not just the empty property slot) has its smoothness slots written so mod-metal weapons (e.g. Warfare IronSledge_mat_TW / bronzedark_mat_TW) read polished without a per-weapon [useshader] rule. The assigned-texture gate cleanly separates metal from equipped wood/leather (whose _MetallicGlossMap is null), which the v3.1.50 'Auto Polish Metallic Materials' _Metallic>=0.5 gate could not (mod authors ship metal weapons at _Metallic 0–0.2). The written values are the tunable 'Auto Polish Use Glossmap' / 'Auto Polish MetalGloss' / 'Auto Polish Glossiness' entries below. Does NOT raise _Metallic and does NOT touch emission (a glowing mod weapon needs a per-mod [useshader] _EmissionColor rule). Only materials already on Custom/Creature (gate-admitted, mod-owned, plugin-bridged) are touched — a correctly-rendering vanilla item is never affected. Sweep-side property write at the equip hook, NOT a provenance-gate change. See CHANGELOG v3.1.51."); _cfgAutoPolishMetalAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Diagnostics", "Auto Polish Metallic", 1f, "Tuning for 'Auto Polish Equipped Metal'. The _Metallic value written to polished equipped-metal materials (0 = dielectric/plastic, 1 = fully metallic). Default 1.0. Mods routinely ship metal weapons at _Metallic 0–0.2 (the validated iron-knife knifeironblade_mat_TW = 0), which on a PBR lit shader renders as a glossy dielectric rather than metal even after the gloss writes land — so raising metalness is needed in addition to the smoothness values. Edit, then re-equip the weapon (or reload + sweep) to see the change. Only has effect when 'Auto Polish Equipped Metal' is enabled. See CHANGELOG v3.1.52."); _cfgAutoPolishUseGlossmap = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Auto Polish Use Glossmap", true, "Tuning for 'Auto Polish Equipped Metal'. When true (default), the auto-polish writes _UseGlossmap=1 so the bound metallic-gloss map's alpha drives per-texel smoothness; false writes _UseGlossmap=0 (uniform smoothness from the MetalGloss/Glossiness values). Only has effect when 'Auto Polish Equipped Metal' is enabled. See CHANGELOG v3.1.51."); _cfgAutoPolishMetalGloss = ((BaseUnityPlugin)this).Config.Bind<float>("Diagnostics", "Auto Polish MetalGloss", 0.7f, "Tuning for 'Auto Polish Equipped Metal'. The _MetalGloss value written to polished equipped-metal materials (0 = matte, 1 = mirror). Default 0.7. Edit, then re-equip the weapon (or reload + sweep) to see the change. Only has effect when 'Auto Polish Equipped Metal' is enabled. See CHANGELOG v3.1.51."); _cfgAutoPolishGlossiness = ((BaseUnityPlugin)this).Config.Bind<float>("Diagnostics", "Auto Polish Glossiness", 0.9f, "Tuning for 'Auto Polish Equipped Metal'. The _Glossiness value written to polished equipped-metal materials (0 = matte, 1 = mirror). Default 0.9. Edit, then re-equip the weapon (or reload + sweep) to see the change. Only has effect when 'Auto Polish Equipped Metal' is enabled. See CHANGELOG v3.1.51."); foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null)) { _vanillaBundleNames.Add(((Object)allLoadedAssetBundle).name); } } VanillaBaselineCache.TryExtractEmbeddedBaseline(ConfigDir, Log); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal); HashSet<string> hashSet3 = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (VanillaBaselineCache.TryLoad(ConfigDir, Log, hashSet, hashSet2, hashSet3, out string cachedValheimVersion)) { foreach (string item in hashSet) { _baselineMatNames.Add(item); } foreach (string item2 in hashSet2) { _vanillaBundleNames.Add(item2); } foreach (string item3 in hashSet3) { _vanillaShaderNames.Add(item3); } Log.LogDebug((object)$"[VanillaCache] loaded as authoritative baseline: {_baselineMatNames.Count} material name(s), {_vanillaShaderNames.Count} shader name(s), {_vanillaBundleNames.Count} bundle name(s)."); _cachedValheimVersionForDriftCheck = cachedValheimVersion; ReplacementCore.BumpAdmissionEpoch("Awake.VanillaCacheLoaded"); } else { Log.LogWarning((object)"[VanillaCache] WARNING: no on-disk vanilla baseline found. The vanilla-name veto is DISARMED for this session — mod-name collisions with Valheim materials may be replaced unsafely. The plugin ships a pre-populated baseline as an embedded resource; if it failed to extract, run `shaderhelper capturevanilla` from a clean install:"); Log.LogWarning((object)"[VanillaCache] 1. Move all non-ShaderHelperForMac DLLs out of BepInEx/plugins/."); Log.LogWarning((object)"[VanillaCache] 2. Launch Valheim and load any world."); Log.LogWarning((object)"[VanillaCache] 3. F5 console: shaderhelper capturevanilla"); Log.LogWarning((object)"[VanillaCache] 4. Quit, restore your mod DLLs, relaunch."); } _sweepDisabled = _baselineMatNames.Count == 0 && _vanillaShaderNames.Count == 0; if (_sweepDisabled) { Log.LogWarning((object)"[v3.0] SWEEP DISABLED — vanilla truth file is empty (zero baseline mat names AND zero vanilla shader names). The option-3 admission gate cannot run safely without truth data; admitting everything would include vanilla materials. The replacement sweep will refuse on every trigger this session. Diagnostic commands remain functional. Run `shaderhelper capturevanilla` from a clean install to populate the cache (see [VanillaCache] WARNING above for the 4-step remediation), then relaunch."); } ReplacementCore.BumpAdmissionEpoch("Awake.PostCacheFlip"); _awakeVanillaSnapshotEmpty = _vanillaBundleNames.Count == 0; Log.LogDebug((object)($"Vanilla bundles snapshotted: {_vanillaBundleNames.Count}" + (_awakeVanillaSnapshotEmpty ? " (empty ⇒ memory/stream bundle tagging deferred to ZNetScene.Awake retroactive sweep)" : ""))); _valheimDataPath = Application.dataPath.Replace('\\', '/').TrimEnd(new char[1] { '/' }); Log.LogDebug((object)("Valheim data path: " + _valheimDataPath)); 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 item4 in ModShaderDlls.Values.Distinct()) { Log.LogDebug((object)(" Shaders found in: '" + item4 + "'")); } ConfigLoader.EnsureConfigFiles(); ReloadConfigFiles(); StartConfigWatcher(); BundleAttribution.EmitBaselineSnapshot("Awake-End"); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; _watcher?.Dispose(); } internal static int IndexOfInlineComment(string line) { return ConfigLoader.IndexOfInlineComment(line); } internal static void ReloadConfigFiles() { ConfigLoader.ReloadConfigFiles(); } 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(SweepCoordinator.InitAfterFrame(this)); } else { ((MonoBehaviour)this).StartCoroutine(SweepCoordinator.SweepAfterFrame(this)); } } private void RegisterCommands() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("shaderhelper", "[patch|patches|undo|sweep|nearby|status|…] ShaderHelperForMac — run `shaderhelper` alone for full usage.", (ConsoleEvent)delegate(ConsoleEventArgs args) { switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "help") { case "reload": BasicCommands.HandleReload(this, args); break; case "capturevanilla": CaptureVanillaCommand.Handle(this, args); break; case "sweep": BasicCommands.HandleSweep(this, args); break; case "dumpmod": BasicCommands.HandleDumpMod(this, args); break; case "scan": DllFilteredCommands.HandleScan(this, args); break; case "pink": GateAuditCommands.HandlePink(this, args); break; case "shaders": BasicCommands.HandleShaders(this, args); break; case "renderers": BasicCommands.HandleRenderers(this, args); break; case "all": BasicCommands.HandleAll(this, args); break; case "nearby": GateAuditCommands.HandleNearby(this, args); break; case "transparent": DllFilteredCommands.HandleTransparent(this, args); break; case "loaded": DllFilteredCommands.HandleLoaded(this, args); break; case "checkvanilla": GateAuditCommands.HandleCheckVanilla(this, args); break; case "whymat": WhymatCommand.Handle(this, args); break; case "explain": GateAuditCommands.HandleExplain(this, args); break; case "status": StatusCommand.Handle(this, args); break; case "fallbackchain": FallbackChainCommand.Handle(this, args); break; case "resolveshader": ResolveShaderCommand.Handle(this, args); break; case "bindprobe": BindProbeCommand.Handle(this, args); break; case "patch": ConfigAuthoringCommands.HandlePatch(this, args); break; case "patches": ConfigAuthoringCommands.HandlePatches(this, args); break; case "undo": ConfigAuthoringCommands.HandleUndo(this, args); break; case "dlls": DllFilteredCommands.HandleDlls(this, args); break; case "classify": InfoCommands.HandleClassify(this, args); break; case "dumpprefabmap": InfoCommands.HandleDumpPrefabMap(this, args); break; case "suggest": InfoCommands.HandleSuggest(this, args); break; case "prefab": InfoCommands.HandlePrefab(this, args); break; case "modprefabs": InfoCommands.HandleModPrefabs(this, args); break; case "bundles": InfoCommands.HandleBundles(this, args); break; case "watch": ObserverCommands.HandleWatch(this, args); break; case "watchr": ObserverCommands.HandleWatchr(this, args); break; case "matdump": MatDumpCommand.Handle(this, args); break; case "checkredesign": GateAuditCommands.HandleCheckRedesign(this, args); break; case "psprobe": PsProbeCommand.Handle(this, args); break; case "capture": { string text = ((args.Length > 2) ? args[2].ToLowerInvariant() : string.Empty); if (text == "stop") { CaptureCommand.HandleStop(this, args); } else if (text == "start") { CaptureCommand.HandleStart(this, args); } else { args.Context.AddString("Usage: shaderhelper capture start [radius] — begin continuous nearby-material capture"); args.Context.AddString(" shaderhelper capture stop — end capture and emit per-material summary"); } break; } default: args.Context.AddString("Usage: shaderhelper patch [radius] [DllName] — stand near pink object; auto-adds a rule to the owning mod's .txt (default radius 15). Pass DllName for large-DLL mods."); args.Context.AddString(" shaderhelper patches — list every batch previously added by `patch`"); args.Context.AddString(" shaderhelper undo [id|all|last] — revert the most recent patch batch (or a specific id, or all)"); args.Context.AddString(" shaderhelper sweep — run a material sweep immediately (reloads config first)"); args.Context.AddString(" shaderhelper reload — reload all config files without running a sweep"); args.Context.AddString(" shaderhelper nearby [radius] [DllName|mod] — log materials near the player; shows patch=yes when patch would add a rule"); args.Context.AddString(" shaderhelper transparent <DllName> — log materials made (or to be made) 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 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"); args.Context.AddString(" shaderhelper all — log ALL loaded materials regardless of action (diagnostics)"); args.Context.AddString(" shaderhelper explain <MatName> — audit why a material lands on Fallback/Transparent/Original"); args.Context.AddString(" shaderhelper checkvanilla <Name> [Name2] ... — report which vanilla / mod-attribution sets contain each name"); args.Context.AddString(" shaderhelper whymat <MatName> — report which lane(s) admitted a material (legacy diagnostic)"); args.Context.AddString(" shaderhelper watch <MatName> [seconds] — log per-frame material state for N seconds (default 5, max 30); diagnoses flicker invisible to `explain`"); args.Context.AddString(" shaderhelper watchr <RendererPattern> [seconds] — log per-frame renderer state for N seconds; diagnoses renderer.enabled toggling"); args.Context.AddString(" shaderhelper matdump <MatName> [--save=<label>] — dump every shader property slot; --save writes to matdump/<label>.txt for later diffing"); args.Context.AddString(" shaderhelper matdump --diff <labelA> <labelB> — diff two saved matdumps"); args.Context.AddString(" shaderhelper checkredesign — audit the live gate's per-material decisions; reports vanilla-leaks (should always be 0)"); args.Context.AddString(" shaderhelper classify [N] — read-only scene walk + histogram of which IsParticleLike signal drives the auto-default"); args.Context.AddString(" shaderhelper dlls [DllName] — dump bundle→DLL and shader→DLL attribution tables"); args.Context.AddString(" shaderhelper dumpprefabmap [DllName] — dump captured prefab-root → DLL attribution map"); args.Context.AddString(" shaderhelper modprefabs <ModName> — list every prefab root attributed to one mod with their child materials"); args.Context.AddString(" shaderhelper bundles — enumerate every loaded AssetBundle with attribution + TOC sample"); args.Context.AddString(" shaderhelper suggest <DllName> [write] — dry-run (or write) auto-generated [prefab] lines for a mod"); args.Context.AddString(" shaderhelper prefab <PrefabName> — list every material (incl. ParticleSystemRenderer effects) under a GameObject by name"); args.Context.AddString(" shaderhelper capturevanilla — force-rebuild the vanilla-baseline cache (run after a Valheim update; clean install only)"); args.Context.AddString(" shaderhelper status — show current plugin state (fallback shader, rule counts, gate inputs)"); args.Context.AddString(" shaderhelper fallbackchain — dump FallbackChain + TransparentChain resolution state (Shader.Find result, Resources matches, isSupported per entry, ACTIVE marker)"); args.Context.AddString(" shaderhelper resolveshader <ShaderName> — enumerate every Shader instance + Material binding for a given shader name; reveals cross-bundle name-collision splits"); args.Context.AddString(" shaderhelper psprobe [radius] [seconds] — read-only ParticleSystemRenderer probe; reports renderer/PS state, optionally watches over a duration"); args.Context.AddString(" shaderhelper capture start [radius] — begin continuous nearby-material capture (auto-stops at 60s)"); args.Context.AddString(" shaderhelper capture stop — end capture; emits per-material summary sorted by frames-seen ascending (transient FX first)"); break; } }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); Log.LogDebug((object)"Console command 'shaderhelper' registered."); } internal static void RegisterCommandsInternal(Plugin self) { self.RegisterCommands(); } private static void CollectCanonicalShaderIds() { ReplacementCore.CollectCanonicalShaderIds(); } internal static void RefreshCanonicalShaderIdsFromLoadedAssets() { BundleAttribution.RefreshCanonicalShaderIdsFromLoadedAssets(); } private static void BuildTransparentMaterial() { ReplacementCore.BuildTransparentMaterial(); } internal static bool IsParticleCapableShaderName(string name) { return MaterialClassifier.IsParticleCapableShaderName(name); } internal static bool NeedsReplacement(Shader shader) { return MaterialClassifier.NeedsReplacement(shader); } internal static bool IsErrorPink(Material mat) { return MaterialClassifier.IsErrorPink(mat); } internal static string? ExtractMatSuffix(string name) { return MaterialClassifier.ExtractMatSuffix(name); } internal static bool IsHdrEmission(Material mat) { return MaterialClassifier.IsHdrEmission(mat); } internal static bool HasEmissiveIntent(Material mat) { return MaterialClassifier.HasEmissiveIntent(mat); } private static Shader? GetEmissiveFallbackShader() { return MaterialClassifier.GetEmissiveFallbackShader(); } internal static Shader? GetEmissiveFallbackShaderInternal() { return GetEmissiveFallbackShader(); } internal static bool IsParticleLikeShaderName(string shaderName) { return MaterialClassifier.IsParticleLikeShaderName(shaderName); } internal static bool IsParticleLike(Material mat) { return MaterialClassifier.IsParticleLike(mat); } internal static bool NeedsReplacement(Material mat) { return MaterialClassifier.NeedsReplacement(mat); } internal static bool IsAggressivelySwappable(string shaderName) { return MaterialClassifier.IsAggressivelySwappable(shaderName); } internal static bool IsJVLMockShader(string shaderName) { return MaterialClassifier.IsJVLMockShader(shaderName); } internal static void TryUpgradeTransparentShader() { ReplacementCore.TryUpgradeTransparentShader(); } private static void BuildReplacementMaterials() { ReplacementCore.BuildReplacementMaterials(); } internal static void TryUpgradeFallbackShader() { ReplacementCore.TryUpgradeFallbackShader(); } internal static Shader? GetReplacementShader(string shaderName) { ShaderAction action = GetAction(shaderName); if (1 == 0) { } Shader result; switch (action) { case ShaderAction.Transparent: { Material? transparentMat = _transparentMat; result = ((transparentMat != null) ? transparentMat.shader : null); break; } case ShaderAction.Fallback: result = FallbackShader; break; case ShaderAction.UseShader: result = null; break; default: result = null; break; } if (1 == 0) { } return result; } 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 (value != null && (_useFallbackDlls.Contains(value) || _useTransparentDlls.Contains(value))) { return true; } return false; } internal static bool IsForceTransparentShader(string shaderName) { return IsForceTransparent(shaderName); } internal static bool IsForceTransparent(string shaderName) { foreach (string item in _forceTransparentPrefixSet) { if (shaderName.StartsWith(item, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } internal static bool IsForceFallback(string shaderName) { foreach (string item in _forceFallbackPrefixSet) { if (shaderName.StartsWith(item, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } internal static void OnBundleLoadedFromFile(AssetBundle? bundle, string? path) { BundleAttribution.OnBundleLoadedFromFile(bundle, path); } internal static void OnBundleLoadedFromMemoryOrStream(AssetBundle? bundle) { BundleAttribution.OnBundleLoadedFromMemoryOrStream(bundle); } internal static void OnLoadAssetResult(AssetBundle? bundle, Object? result) { BundleAttribution.OnLoadAssetResult(bundle, result); } internal static void RetroactiveBundleSweep(string label) { BundleAttribution.RetroactiveBundleSweep(label); } internal static ShaderAction GetAction(Material mat) { return ActionResolver.Resolve(mat); } internal static ShaderAction GetAction(string shaderName) { return ActionResolver.ResolveByShaderName(shaderName); } internal void SweepMaterials() { SweepCoordinator.RunSweepMaterials(this); } internal void SweepMaterialsWithNotify() { SweepCoordinator.RunSweepMaterialsWithNotify(this); } internal static void TryReplaceMaterialPublic(Material mat) { TryReplaceMaterial(mat); } internal static void DumpMatPropertiesPublic(Material mat, string label) { MatDump.DumpMatPropertiesIfTargeted(mat, label); } internal static bool IsMaterialProcessedPublic(Material mat) { if ((Object)(object)mat == (Object)null) { return false; } return ReplacementCore._processedMaterialIds.Contains(((Object)mat).GetInstanceID()); } internal static string StripInstancePublic(string name) { return StripInstance(name); } internal static bool IsErrorPinkPublic(Material mat) { return IsErrorPink(mat); } internal static bool IsParticleLikePublic(Material mat) { return IsParticleLike(mat); } internal IEnumerator SweepMaterialsCoroutine() { return SweepCoordinator.SweepMaterialsCoroutine(this); } internal IEnumerator SweepMaterialsCoroutine(string trigger) { return SweepCoordinator.SweepMaterialsCoroutine(this, trigger); } private static Shader? FindShaderByName(string name) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Invalid comparison between Unknown and I4 Shader val = Shader.Find(name); if ((Object)(object)val != (Object)null && val.isSupported) { return val; } Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); Shader val2 = null; Shader[] array2 = array; foreach (Shader val3 in array2) { if (!((Object)(object)val3 == (Object)null) && !(((Object)val3).name != name) && val3.isSupported) { if ((Object)(object)val2 == (Object)null) { val2 = val3; } int num = val3.FindPropertyIndex("_Color"); if (num >= 0 && (int)val3.GetPropertyType(num) == 0) { return val3; } } } return val2; } internal static Shader? FindShaderByNameInternal(string name) { return FindShaderByName(name); } internal static string StripInstance(string name) { while (name.EndsWith(" (Instance)", StringComparison.Ordinal)) { name = name.Substring(0, name.Length - " (Instance)".Length); } return name; } private static bool IsSoftMatRule(Material mat) { return PatchBatch.IsSoftMatRule(mat); } internal static bool IsHardMatRule(Material mat) { return PatchBatch.IsHardMatRule(mat); } private static bool IsExplicitMatRule(Material mat) { return PatchBatch.IsExplicitMatRule(mat); } internal static bool CheckMatNameRules(string matName, out ShaderAction action, out string reason) { return PatchBatch.CheckMatNameRules(matName, out action, out reason); } internal static string GeneratePatchBatchId() { return PatchBatch.GeneratePatchBatchId(); } internal static string AppendPatchBatch(string dllFile, Dictionary<string, List<string>> rulesBySection, string batchId) { return PatchBatch.AppendPatchBatch(dllFile, rulesBySection, batchId); } internal static List<(string filePath, string dllName, string batchId, string timestamp, List<string> bodyLines)> EnumeratePatchBatches() { return PatchBatch.EnumeratePatchBatches(); } internal static bool RemovePatchBatch(string filePath, string batchId) { return PatchBatch.RemovePatchBatch(filePath, batchId); } internal static (string section, string matName, string line, string? dllFile)? ProposeMatRule(Material mat, float distance, string parentName) { return PatchBatch.ProposeMatRule(mat, distance, parentName); } internal static bool FileAlreadyHasMatRule(string filePath, string matName) { return PatchBatch.FileAlreadyHasMatRule(filePath, matName); } internal static int TryReplaceMaterial(Material? mat) { return ReplacementCore.TryReplaceMaterial(mat); } } 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.LogDebug((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_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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.LogDebug((object)("[Diag] " + fileNameWithoutExtension + ": resource '" + ((Resource)item).Name + "' read failed: " + ex.Message)); continue; } if (IsUnityBundle(resourceData)) { log.LogDebug((object)$"[Diag] {fileNameWithoutExtension}: found Unity bundle in resource
plugins/AssetsTools.NET.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.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;