using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CompressSave.Wrapper;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MonoMod.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CompressSave")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("DSP MOD - CompressSave")]
[assembly: AssemblyFileVersion("1.3.6.0")]
[assembly: AssemblyInformationalVersion("1.3.6+aae3d7df4c74cff3c07d9925034f833f5c701f1a")]
[assembly: AssemblyProduct("CompressSave")]
[assembly: AssemblyTitle("CompressSave")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
public static class I18N
{
private static bool _initialized;
private static bool _dirty;
private static readonly List<Tuple<string, string, int>> Keys = new List<Tuple<string, string, int>>();
private static readonly Dictionary<int, List<string>> Strings = new Dictionary<int, List<string>>();
public static void Init()
{
Harmony.CreateAndPatchAll(typeof(I18N), (string)null);
}
public static bool Initialized()
{
return _initialized;
}
public static void Add(string key, string enus, string zhcn = null)
{
if (zhcn != null || !(key == enus))
{
Keys.Add(Tuple.Create(key, enus, -1));
if (Strings.TryGetValue(2052, out var value))
{
value.Add(string.IsNullOrEmpty(zhcn) ? enus : zhcn);
}
else
{
Strings.Add(2052, new List<string>(1) { string.IsNullOrEmpty(zhcn) ? enus : zhcn });
}
_dirty = true;
}
}
private static void ApplyIndexers()
{
Dictionary<string, int> namesIndexer = Localization.namesIndexer;
int num = namesIndexer.Count;
int count = Keys.Count;
for (int i = 0; i < count; i++)
{
var (text3, item, num3) = Keys[i];
if (num3 < 0)
{
if (namesIndexer.TryGetValue(text3, out var value))
{
Keys[i] = Tuple.Create(text3, item, value);
continue;
}
namesIndexer[text3] = num;
Keys[i] = Tuple.Create(text3, item, num);
num++;
}
}
_dirty = false;
string[][] strings = Localization.strings;
if (strings == null)
{
return;
}
int num4 = strings.Length;
for (int j = 0; j < num4; j++)
{
ApplyLanguage(j);
if (j == Localization.currentLanguageIndex)
{
Localization.currentStrings = Localization.strings[j];
Localization.currentFloats = Localization.floats[j];
}
}
}
private static void ApplyLanguage(int index)
{
int count = Localization.namesIndexer.Count;
string[] array = Localization.strings[index];
if (array == null)
{
return;
}
if (array.Length < count)
{
string[] array2 = new string[count];
Array.Copy(array, array2, array.Length);
array = array2;
Localization.strings[index] = array;
}
float[] array3 = Localization.floats[index];
if (array3 != null && array3.Length < count)
{
float[] array4 = new float[count];
Array.Copy(array3, array4, array3.Length);
array3 = array4;
Localization.floats[index] = array3;
}
int count2 = Keys.Count;
if (Strings.TryGetValue(Localization.Languages[index].lcId, out var value))
{
for (int i = 0; i < count2; i++)
{
array[Keys[i].Item3] = value[i];
}
}
else
{
for (int j = 0; j < count2; j++)
{
array[Keys[j].Item3] = Keys[j].Item2;
}
}
}
public static void Apply()
{
if (_initialized && Keys.Count != 0 && _dirty)
{
ApplyIndexers();
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Localization), "LoadSettings")]
private static void Localization_LoadSettings_Postfix()
{
if (!_initialized)
{
_initialized = true;
Apply();
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Localization), "LoadLanguage")]
private static void Localization_LoadLanguage_Postfix(int index)
{
if (_initialized)
{
ApplyLanguage(index);
}
}
}
namespace CompressSave
{
public enum CompressionType
{
None,
LZ4,
Zstd
}
[BepInPlugin("org.soardev.compresssave", "CompressSave", "1.3.6")]
public class CompressSave : BaseUnityPlugin
{
private Harmony _patchSave;
private Harmony _patchUISave;
private Harmony _patchUILoad;
public static string StringFromCompresstionType(CompressionType type)
{
return type switch
{
CompressionType.LZ4 => "lz4",
CompressionType.Zstd => "zstd",
CompressionType.None => "none",
_ => throw new ArgumentException("Unknown compression type."),
};
}
private static CompressionType CompressionTypeFromString(string str)
{
if (!(str == "lz4"))
{
if (str == "zstd")
{
return CompressionType.Zstd;
}
return CompressionType.None;
}
return CompressionType.LZ4;
}
public void Awake()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Expected O, but got Unknown
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
SaveUtil.Logger = ((BaseUnityPlugin)this).Logger;
if (LZ4API.Avaliable && ZstdAPI.Avaliable)
{
PatchSave.CompressionTypeForSavesConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Compression", "Type", StringFromCompresstionType(PatchSave.CompressionTypeForSaves), new ConfigDescription("Set default compression type for manual saves.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "lz4", "zstd", "none" }), new object[1]
{
new { }
}));
PatchSave.CompressionTypeForSaves = CompressionTypeFromString(PatchSave.CompressionTypeForSavesConfig.Value);
PatchSave.CompressionTypeForAutoSavesConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Compression", "TypeForAuto", StringFromCompresstionType(PatchSave.CompressionTypeForAutoSaves), new ConfigDescription("Set default compression type for auto saves and last-exit save.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "lz4", "zstd", "none" }), new object[1]
{
new { }
}));
PatchSave.CompressionTypeForAutoSaves = CompressionTypeFromString(PatchSave.CompressionTypeForAutoSavesConfig.Value);
PatchSave.CompressionLevelForSaves = ((BaseUnityPlugin)this).Config.Bind<int>("Compression", "Level", PatchSave.CompressionLevelForSaves, "Set default compression level for manual saves.\n0 for default level.\n3 ~ 12 for lz4, -5 ~ 22 for zstd.\nSmaller level leads to faster speed and less compression ratio.").Value;
PatchSave.CompressionLevelForAutoSaves = ((BaseUnityPlugin)this).Config.Bind<int>("Compression", "LevelForAuto", PatchSave.CompressionLevelForAutoSaves, "Set default compression level for auto saves and last-exit save.\n0 for default level.\n3 ~ 12 for lz4, -5 ~ 22 for zstd.\nSmaller level leads to faster speed and less compression ratio.").Value;
PatchSave.EnableForAutoSaves = ((BaseUnityPlugin)this).Config.Bind<bool>("Compression", "EnableForAutoSaves", true, "Enable the feature for auto saves and last-exit save.");
PatchSave.CreateCompressBuffer();
if (GameConfig.gameVersion != SaveUtil.VerifiedVersion)
{
SaveUtil.Logger.LogWarning((object)$"Save version mismatch. Expect:{SaveUtil.VerifiedVersion}, Current:{GameConfig.gameVersion}. MOD may not work as expected.");
}
_patchSave = Harmony.CreateAndPatchAll(typeof(PatchSave), (string)null);
if (PatchSave.EnableCompress)
{
_patchUISave = Harmony.CreateAndPatchAll(typeof(PatchUISaveGame), (string)null);
}
_patchUILoad = Harmony.CreateAndPatchAll(typeof(PatchUILoadGame), (string)null);
}
else
{
SaveUtil.Logger.LogWarning((object)"Either nonewrap.dll, lz4warp.dll or zstdwrap.dll is not avaliable.");
}
I18N.Init();
I18N.Add("Store", "Store (No Compression)", "存储(不压缩)");
I18N.Add("Decompress", "Decompress", "解压存档");
I18N.Add("Save with Compression", "Save (Compress)", "压缩保存");
I18N.Add("Compression for auto saves", "Compression for auto saves", "\u3000\u3000自动存档压缩方式");
I18N.Add("Compression for manual saves", "Compression for manual saves", "\u3000\u3000手动存档压缩方式");
I18N.Apply();
}
public void OnDestroy()
{
if (_patchUISave != null)
{
PatchUISaveGame.OnDestroy();
_patchUISave.UnpatchSelf();
_patchUISave = null;
}
if (_patchUILoad != null)
{
PatchUILoadGame.OnDestroy();
_patchUILoad.UnpatchSelf();
_patchUILoad = null;
}
Harmony patchSave = _patchSave;
if (patchSave != null)
{
patchSave.UnpatchSelf();
}
_patchSave = null;
}
}
public class PatchSave
{
public static readonly WrapperDefines LZ4Wrapper = new LZ4API();
public static readonly WrapperDefines ZstdWrapper = new ZstdAPI();
private static readonly WrapperDefines NoneWrapper = new NoneAPI();
private static CompressionStream.CompressBuffer _compressBuffer;
public static bool UseCompressSave;
private static CompressionType _compressionTypeForLoading = CompressionType.None;
private static CompressionType _compressionTypeForSaving = CompressionType.Zstd;
private static int _compressionLevelForSaving;
public static CompressionType CompressionTypeForSaves = CompressionType.Zstd;
public static CompressionType CompressionTypeForAutoSaves = CompressionType.Zstd;
public static ConfigEntry<string> CompressionTypeForSavesConfig;
public static ConfigEntry<string> CompressionTypeForAutoSavesConfig;
public static int CompressionLevelForSaves;
public static int CompressionLevelForAutoSaves;
public static ConfigEntry<bool> EnableForAutoSaves;
private static Stream _compressionStream;
public static bool EnableCompress;
public static void CreateCompressBuffer()
{
_compressBuffer = CompressionStream.CreateBuffer((int)Math.Max(Math.Max(LZ4Wrapper.CompressBufferBound(1048576L), ZstdWrapper.CompressBufferBound(1048576L)), NoneWrapper.CompressBufferBound(1048576L)), 1048576);
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
}
private static void WriteHeader(FileStream fileStream)
{
if (fileStream == null)
{
throw new ArgumentNullException("fileStream");
}
switch (_compressionTypeForSaving)
{
case CompressionType.Zstd:
{
for (int j = 0; j < 3; j++)
{
fileStream.WriteByte(204);
}
fileStream.WriteByte(205);
break;
}
case CompressionType.LZ4:
{
for (int i = 0; i < 4; i++)
{
fileStream.WriteByte(204);
}
break;
}
default:
throw new ArgumentException("Unknown compression type.");
case CompressionType.None:
break;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "AutoSave")]
[HarmonyPatch(typeof(GameSave), "SaveAsLastExit")]
private static void BeforeAutoSave()
{
UseCompressSave = EnableForAutoSaves.Value && EnableCompress;
if (UseCompressSave)
{
_compressionTypeForSaving = CompressionTypeForAutoSaves;
_compressionLevelForSaving = CompressionLevelForAutoSaves;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
private static IEnumerable<CodeInstruction> SaveCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Expected O, but got Unknown
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Expected O, but got Unknown
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Expected O, but got Unknown
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Expected O, but got Unknown
CodeMatcher val = new CodeMatcher(instructions, generator);
try
{
val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Newobj, (object)AccessTools.Constructor(typeof(BinaryWriter), new Type[1] { typeof(FileStream) }, false), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "CreateBinaryWriter", (Type[])null, (Type[])null)).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(PerformanceMonitor), "BeginStream", (Type[])null, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "MonitorStream", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Stream), "Seek", (Type[])null, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthWrite0", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(BinaryWriter), "Write", new Type[1] { typeof(long) }, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthWrite1", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(IDisposable), "Dispose", (Type[])null, (Type[])null), (string)null)
})
.Advance(1)
.Insert((CodeInstruction[])(object)new CodeInstruction[1]
{
new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream", (Type[])null, (Type[])null))
});
EnableCompress = true;
return val.InstructionEnumeration();
}
catch (Exception ex)
{
SaveUtil.Logger.LogError((object)"SaveCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.Logger.LogError((object)ex);
}
return val.InstructionEnumeration();
}
public static void MonitorStream(Stream fileStream)
{
PerformanceMonitor.BeginStream(UseCompressSave ? _compressionStream : fileStream);
}
public static BinaryWriter CreateBinaryWriter(FileStream fileStream)
{
if (UseCompressSave)
{
SaveUtil.Logger.LogDebug((object)"Begin compress save");
WriteHeader(fileStream);
_compressionStream = _compressionTypeForSaving switch
{
CompressionType.LZ4 => new CompressionStream(LZ4Wrapper, _compressionLevelForSaving, fileStream, _compressBuffer, multiThread: true),
CompressionType.Zstd => new CompressionStream(ZstdWrapper, _compressionLevelForSaving, fileStream, _compressBuffer, multiThread: true),
CompressionType.None => new CompressionStream(NoneWrapper, 0, fileStream, _compressBuffer, multiThread: true),
_ => _compressionStream,
};
return ((CompressionStream)_compressionStream).BufferWriter;
}
SaveUtil.Logger.LogDebug((object)"Begin normal save");
return new BinaryWriter(fileStream);
}
public static long FileLengthWrite0(FileStream fileStream, long offset, SeekOrigin origin)
{
if (!UseCompressSave)
{
return fileStream.Seek(offset, origin);
}
return 0L;
}
public static void FileLengthWrite1(BinaryWriter binaryWriter, long value)
{
if (!UseCompressSave)
{
binaryWriter.Write(value);
}
}
public static void DisposeCompressionStream()
{
if (!UseCompressSave)
{
return;
}
if (_compressionStream == null)
{
UseCompressSave = false;
return;
}
bool canWrite = _compressionStream.CanWrite;
Stream stream = null;
if (canWrite && _compressionTypeForSaving == CompressionType.None)
{
stream = ((CompressionStream)_compressionStream).OutStream;
}
_compressionStream.Dispose();
_compressionStream = null;
if (canWrite)
{
if (stream != null)
{
long value = stream.Seek(0L, SeekOrigin.End);
stream.Seek(6L, SeekOrigin.Begin);
BinaryWriter binaryWriter = new BinaryWriter(stream);
binaryWriter.Write(value);
binaryWriter.Dispose();
}
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
UseCompressSave = false;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameSave), "LoadCurrentGame")]
[HarmonyPatch(typeof(GameSave), "LoadGameDesc")]
[HarmonyPatch(typeof(GameSave), "ReadHeader")]
[HarmonyPatch(typeof(GameSave), "ReadHeaderAndDescAndProperty")]
[HarmonyPatch(typeof(GameSave), "ReadModes")]
private static IEnumerable<CodeInstruction> LoadCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Expected O, but got Unknown
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Expected O, but got Unknown
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Expected O, but got Unknown
CodeMatcher val = new CodeMatcher(instructions, generator);
try
{
val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Newobj, (object)AccessTools.Constructor(typeof(BinaryReader), new Type[1] { typeof(FileStream) }, false), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "CreateBinaryReader", (Type[])null, (Type[])null)).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(PerformanceMonitor), "BeginStream", (Type[])null, (Type[])null), (string)null)
});
if (val.IsValid)
{
val.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "MonitorStream", (Type[])null, (Type[])null));
}
val.Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(BinaryReader), "ReadInt64", (Type[])null, (Type[])null), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthRead", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(IDisposable), "Dispose", (Type[])null, (Type[])null), (string)null)
})
.Advance(1)
.Insert((CodeInstruction[])(object)new CodeInstruction[1]
{
new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream", (Type[])null, (Type[])null))
})
.MatchBack(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Stream), "Seek", (Type[])null, (Type[])null), (string)null)
});
if (val.IsValid)
{
val.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "ReadSeek", (Type[])null, (Type[])null));
}
return val.InstructionEnumeration();
}
catch (Exception ex)
{
SaveUtil.Logger.LogError((object)"LoadCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.Logger.LogError((object)ex);
}
return val.InstructionEnumeration();
}
public static BinaryReader CreateBinaryReader(FileStream fileStream)
{
switch (_compressionTypeForLoading = SaveUtil.SaveGetCompressType(fileStream))
{
case CompressionType.LZ4:
UseCompressSave = true;
_compressionStream = new DecompressionStream(LZ4Wrapper, fileStream);
return new PeekableReader((DecompressionStream)_compressionStream);
case CompressionType.Zstd:
UseCompressSave = true;
_compressionStream = new DecompressionStream(ZstdWrapper, fileStream);
return new PeekableReader((DecompressionStream)_compressionStream);
case CompressionType.None:
UseCompressSave = false;
fileStream.Seek(0L, SeekOrigin.Begin);
return new BinaryReader(fileStream);
default:
throw new ArgumentOutOfRangeException();
}
}
public static long FileLengthRead(BinaryReader binaryReader)
{
switch (_compressionTypeForLoading)
{
case CompressionType.LZ4:
case CompressionType.Zstd:
binaryReader.ReadInt64();
return _compressionStream.Length;
case CompressionType.None:
return binaryReader.ReadInt64();
default:
throw new ArgumentOutOfRangeException();
}
}
public static long ReadSeek(FileStream fileStream, long offset, SeekOrigin origin)
{
switch (_compressionTypeForLoading)
{
case CompressionType.LZ4:
case CompressionType.Zstd:
while (offset > 0)
{
offset -= _compressionStream.Read(_compressBuffer.OutBuffer, 0, (int)offset);
}
return _compressionStream.Position;
case CompressionType.None:
return fileStream.Seek(offset, origin);
default:
throw new ArgumentOutOfRangeException();
}
}
}
internal class PatchUILoadGame
{
private static UIButton _decompressButton;
[HarmonyPatch(typeof(UILoadGameWindow), "OnSelectedChange")]
[HarmonyPostfix]
private static void OnSelectedChange(UILoadGameWindow __instance)
{
UIGameSaveEntry selected = __instance.selected;
CompressionType compressionType = SaveUtil.SaveGetCompressType(((Object)(object)selected == (Object)null) ? null : selected._saveName);
Text prop3Text = __instance.prop3Text;
Text val = prop3Text;
val.text = compressionType switch
{
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text,
};
if (Object.op_Implicit((Object)(object)_decompressButton))
{
((Selectable)_decompressButton.button).interactable = compressionType != CompressionType.None;
((Component)_decompressButton).gameObject.SetActive(compressionType != CompressionType.None);
}
}
[HarmonyPatch(typeof(UILoadGameWindow), "_OnOpen")]
[HarmonyPostfix]
private static void _OnOpen(UILoadGameWindow __instance)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)_decompressButton))
{
return;
}
UIButton loadButton = __instance.loadButton;
bool flag = false;
Transform obj = ((Component)__instance).transform.Find("button-decompress");
GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
if ((Object)(object)val == (Object)null)
{
val = Object.Instantiate<GameObject>(((Component)loadButton).gameObject, ((Component)loadButton).transform.parent);
flag = true;
}
_decompressButton = val.GetComponent<UIButton>();
if (flag)
{
Vector3 anchoredPosition3D = ((RectTransform)__instance.loadSandboxGroup.transform).anchoredPosition3D;
((Object)((Component)_decompressButton).gameObject).name = "button-decompress";
RectTransform val2 = (RectTransform)((Component)_decompressButton).transform;
Vector3 val3 = anchoredPosition3D;
((Vector3)(ref anchoredPosition3D))..ctor(val3.x - 230f, val3.y, val3.z);
val2.anchoredPosition3D = anchoredPosition3D;
((Graphic)((Selectable)_decompressButton.button).image).color = Color32.op_Implicit(new Color32((byte)0, (byte)244, (byte)146, (byte)119));
Transform obj2 = ((Component)_decompressButton).transform.Find("button-text");
((Component)obj2).GetComponent<Text>().text = Localization.Translate("Decompress");
Localizer component = ((Component)obj2).GetComponent<Localizer>();
if (Object.op_Implicit((Object)(object)component))
{
component.stringKey = "Decompress";
component.translation = Localization.Translate("Decompress");
}
_decompressButton.onClick += delegate
{
if (SaveUtil.DecompressSave(__instance.selected._saveName, out var newfileName))
{
__instance.RefreshList();
__instance.selected = __instance.entries.First((UIGameSaveEntry e) => e._saveName == newfileName);
}
};
}
((Selectable)_decompressButton.button).interactable = false;
((Component)_decompressButton).gameObject.SetActive(false);
}
public static void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_decompressButton))
{
Object.Destroy((Object)(object)((Component)_decompressButton).gameObject);
}
_decompressButton = null;
}
}
internal static class PatchUISaveGame
{
private class UIContext
{
public UIButton ButtonCompress;
public UIButton SaveButton;
public GameObject ManualSaveTypeComboBox;
public GameObject AutoSaveTypeComboBox;
public Text ButtonCompressText;
public Text SaveButtonText;
public UISaveGameWindow Window;
}
private static UIContext _context = new UIContext();
public static void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_context.ButtonCompress))
{
Object.Destroy((Object)(object)((Component)_context.ButtonCompress).gameObject);
}
if (Object.op_Implicit((Object)(object)_context.Window))
{
_context.SaveButton.onClick -= WrapClick;
_context.SaveButton.onClick += _context.Window.OnSaveClick;
}
_OnDestroy();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSelectedChange")]
[HarmonyPostfix]
private static void OnSelectedChange(UISaveGameWindow __instance)
{
UIGameSaveEntry selected = __instance.selected;
CompressionType compressionType = SaveUtil.SaveGetCompressType(((Object)(object)selected == (Object)null) ? null : selected._saveName);
Text prop3Text = __instance.prop3Text;
Text val = prop3Text;
val.text = compressionType switch
{
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text,
};
}
[HarmonyPatch(typeof(UISaveGameWindow), "_OnDestroy")]
[HarmonyPostfix]
private static void _OnDestroy()
{
_context = new UIContext();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick")]
[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
private static void OSaveGameAs(this UISaveGameWindow ui, int data)
{
}
[HarmonyPatch(typeof(UISaveGameWindow), "CheckAndSetSaveButtonEnable")]
[HarmonyPostfix]
private static void CheckAndSetSaveButtonEnable(UISaveGameWindow __instance)
{
_OnOpen(__instance);
if (Object.op_Implicit((Object)(object)_context.SaveButton))
{
((Selectable)_context.ButtonCompress.button).interactable = ((Selectable)_context.SaveButton.button).interactable;
}
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick")]
[HarmonyPrefix]
private static void OnSaveClick()
{
PatchSave.UseCompressSave = true;
}
[HarmonyPatch(typeof(UISaveGameWindow), "_OnOpen")]
[HarmonyPostfix]
private static void _OnOpen(UISaveGameWindow __instance)
{
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_0279: Unknown result type (might be due to invalid IL or missing references)
//IL_028d: Unknown result type (might be due to invalid IL or missing references)
//IL_0294: Expected O, but got Unknown
//IL_0296: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
//IL_029c: Unknown result type (might be due to invalid IL or missing references)
//IL_029f: Unknown result type (might be due to invalid IL or missing references)
//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0406: Unknown result type (might be due to invalid IL or missing references)
//IL_0410: Expected O, but got Unknown
//IL_041c: Unknown result type (might be due to invalid IL or missing references)
//IL_0421: Unknown result type (might be due to invalid IL or missing references)
//IL_0422: Unknown result type (might be due to invalid IL or missing references)
//IL_0427: Unknown result type (might be due to invalid IL or missing references)
//IL_0428: Unknown result type (might be due to invalid IL or missing references)
//IL_0429: Unknown result type (might be due to invalid IL or missing references)
//IL_0435: Unknown result type (might be due to invalid IL or missing references)
//IL_043b: Unknown result type (might be due to invalid IL or missing references)
//IL_0441: Unknown result type (might be due to invalid IL or missing references)
//IL_044b: Unknown result type (might be due to invalid IL or missing references)
//IL_044c: Unknown result type (might be due to invalid IL or missing references)
//IL_0451: 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_045f: Unknown result type (might be due to invalid IL or missing references)
//IL_0534: Unknown result type (might be due to invalid IL or missing references)
//IL_0548: Unknown result type (might be due to invalid IL or missing references)
//IL_054f: Expected O, but got Unknown
//IL_0551: Unknown result type (might be due to invalid IL or missing references)
//IL_0556: Unknown result type (might be due to invalid IL or missing references)
//IL_0557: Unknown result type (might be due to invalid IL or missing references)
//IL_055a: Unknown result type (might be due to invalid IL or missing references)
//IL_0564: Unknown result type (might be due to invalid IL or missing references)
//IL_0567: Unknown result type (might be due to invalid IL or missing references)
//IL_0571: Unknown result type (might be due to invalid IL or missing references)
//IL_0574: Unknown result type (might be due to invalid IL or missing references)
//IL_057e: Unknown result type (might be due to invalid IL or missing references)
//IL_057f: Unknown result type (might be due to invalid IL or missing references)
//IL_058b: Unknown result type (might be due to invalid IL or missing references)
//IL_0597: Unknown result type (might be due to invalid IL or missing references)
//IL_059d: Unknown result type (might be due to invalid IL or missing references)
//IL_06e2: Unknown result type (might be due to invalid IL or missing references)
//IL_06ec: Expected O, but got Unknown
//IL_06f8: Unknown result type (might be due to invalid IL or missing references)
//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
//IL_06fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0703: Unknown result type (might be due to invalid IL or missing references)
//IL_0704: Unknown result type (might be due to invalid IL or missing references)
//IL_0705: Unknown result type (might be due to invalid IL or missing references)
//IL_0711: Unknown result type (might be due to invalid IL or missing references)
//IL_0717: Unknown result type (might be due to invalid IL or missing references)
//IL_071d: Unknown result type (might be due to invalid IL or missing references)
//IL_0727: Unknown result type (might be due to invalid IL or missing references)
//IL_0728: Unknown result type (might be due to invalid IL or missing references)
//IL_072d: Unknown result type (might be due to invalid IL or missing references)
//IL_0734: Unknown result type (might be due to invalid IL or missing references)
//IL_073b: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)_context.ButtonCompress))
{
return;
}
_context.SaveButton = __instance.saveButton;
_context.SaveButtonText = __instance.saveButtonText;
_context.Window = __instance;
Transform obj = ((Component)__instance).transform.Find("button-compress");
GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
bool flag = false;
if ((Object)(object)val == (Object)null)
{
val = Object.Instantiate<GameObject>(((Component)__instance.saveButton).gameObject, ((Component)__instance.saveButton).transform.parent);
flag = true;
}
_context.ButtonCompress = val.GetComponent<UIButton>();
Vector3 anchoredPosition3D;
if (flag)
{
((Object)((Component)_context.ButtonCompress).gameObject).name = "button-compress";
RectTransform val2 = (RectTransform)((Component)_context.ButtonCompress).transform;
anchoredPosition3D = val2.anchoredPosition3D;
val2.anchoredPosition3D = new Vector3(anchoredPosition3D.x - 180f, anchoredPosition3D.y, anchoredPosition3D.z);
((Graphic)((Selectable)_context.ButtonCompress.button).image).color = Color32.op_Implicit(new Color32((byte)252, (byte)111, (byte)0, (byte)119));
Transform val3 = ((Component)_context.ButtonCompress).transform.Find("button-text");
_context.ButtonCompressText = ((Component)val3).GetComponent<Text>();
_context.ButtonCompress.onClick += __instance.OnSaveClick;
_context.SaveButton.onClick -= __instance.OnSaveClick;
_context.SaveButton.onClick += WrapClick;
_context.ButtonCompressText.text = Localization.Translate("Save with Compression");
Localizer component = ((Component)val3).GetComponent<Localizer>();
if (Object.op_Implicit((Object)(object)component))
{
component.stringKey = "Save with Compression";
component.translation = Localization.Translate("Save with Compression");
}
}
flag = false;
Transform obj2 = ((Component)__instance).transform.Find("manual-save-type-combobox");
val = ((obj2 != null) ? ((Component)obj2).gameObject : null);
if ((Object)(object)val == (Object)null)
{
val = Object.Instantiate<GameObject>(((Component)((Component)UIRoot.instance.optionWindow.resolutionComp).transform.parent).gameObject, ((Component)__instance.saveButton).transform.parent);
flag = true;
}
_context.ManualSaveTypeComboBox = val;
if (flag)
{
((Object)val).name = "manual-save-type-combobox";
RectTransform val4 = (RectTransform)val.transform;
RectTransform val5 = (RectTransform)((Component)_context.ButtonCompress).transform;
anchoredPosition3D = val5.anchoredPosition3D;
val4.anchorMin = val5.anchorMin;
val4.anchorMax = val5.anchorMax;
val4.pivot = val5.pivot;
val4.anchoredPosition3D = new Vector3(anchoredPosition3D.x + 100f, anchoredPosition3D.y + 45f, anchoredPosition3D.z);
Transform val6 = ((Component)val4).transform.Find("ComboBox");
Transform obj3 = val6.Find("Dropdown List ScrollBox");
object obj4;
if (obj3 == null)
{
obj4 = null;
}
else
{
Transform obj5 = obj3.Find("Mask");
obj4 = ((obj5 != null) ? obj5.Find("Content Panel") : null);
}
Transform val7 = (Transform)obj4;
if ((Object)(object)val7 != (Object)null)
{
for (int num = val7.childCount - 1; num >= 0; num--)
{
Transform child = val7.GetChild(num);
if (((Object)child).name == "Item Button(Clone)")
{
Object.Destroy((Object)(object)((Component)child).gameObject);
}
}
}
UIComboBox cb2 = ((Component)val6).GetComponent<UIComboBox>();
((UnityEventBase)cb2.onSubmit).RemoveAllListeners();
((UnityEventBase)cb2.onItemIndexChange).RemoveAllListeners();
cb2.Items = new List<string>(3)
{
Localization.Translate("Store"),
"LZ4",
"Zstd"
};
cb2.itemIndex = (int)PatchSave.CompressionTypeForSaves;
((UnityEvent)cb2.onItemIndexChange).AddListener((UnityAction)delegate
{
PatchSave.CompressionTypeForSaves = (CompressionType)cb2.itemIndex;
PatchSave.CompressionTypeForSavesConfig.Value = CompressSave.StringFromCompresstionType(PatchSave.CompressionTypeForSaves);
});
RectTransform val8 = (RectTransform)((Component)cb2).transform;
anchoredPosition3D = val8.anchoredPosition3D;
val8.anchoredPosition3D = new Vector3(anchoredPosition3D.x - 50f, anchoredPosition3D.y, anchoredPosition3D.z);
Vector2 sizeDelta = val8.sizeDelta;
val8.sizeDelta = new Vector2(150f, sizeDelta.y);
val.GetComponent<Text>().text = Localization.Translate("Compression for manual saves");
Localizer component2 = val.GetComponent<Localizer>();
if ((Object)(object)component2 != (Object)null)
{
component2.stringKey = "Compression for manual saves";
component2.translation = Localization.Translate("Compression for manual saves");
}
}
flag = false;
Transform obj6 = ((Component)__instance).transform.Find("auto-save-type-combobox");
val = ((obj6 != null) ? ((Component)obj6).gameObject : null);
if ((Object)(object)val == (Object)null)
{
val = Object.Instantiate<GameObject>(((Component)((Component)UIRoot.instance.optionWindow.resolutionComp).transform.parent).gameObject, ((Component)__instance.saveButton).transform.parent);
flag = true;
}
_context.AutoSaveTypeComboBox = val;
if (!flag)
{
return;
}
((Object)val).name = "auto-save-type-combobox";
RectTransform val9 = (RectTransform)val.transform;
RectTransform val10 = (RectTransform)((Component)_context.ButtonCompress).transform;
anchoredPosition3D = val10.anchoredPosition3D;
val9.anchorMin = val10.anchorMin;
val9.anchorMax = val10.anchorMax;
val9.pivot = val10.pivot;
val9.anchoredPosition3D = new Vector3(anchoredPosition3D.x + 510f, anchoredPosition3D.y + 45f, anchoredPosition3D.z);
Transform val11 = ((Component)val9).transform.Find("ComboBox");
Transform obj7 = val11.Find("Dropdown List ScrollBox");
object obj8;
if (obj7 == null)
{
obj8 = null;
}
else
{
Transform obj9 = obj7.Find("Mask");
obj8 = ((obj9 != null) ? obj9.Find("Content Panel") : null);
}
Transform val12 = (Transform)obj8;
if ((Object)(object)val12 != (Object)null)
{
for (int num2 = val12.childCount - 1; num2 >= 0; num2--)
{
Transform child2 = val12.GetChild(num2);
if (((Object)child2).name == "Item Button(Clone)")
{
Object.Destroy((Object)(object)((Component)child2).gameObject);
}
}
}
UIComboBox cb = ((Component)val11).GetComponent<UIComboBox>();
((UnityEventBase)cb.onSubmit).RemoveAllListeners();
((UnityEventBase)cb.onItemIndexChange).RemoveAllListeners();
cb.Items = new List<string>(4)
{
Localization.Translate("已停用"),
Localization.Translate("Store"),
"LZ4",
"Zstd"
};
cb.itemIndex = (int)(PatchSave.EnableForAutoSaves.Value ? (PatchSave.CompressionTypeForAutoSaves + 1) : CompressionType.None);
((UnityEvent)cb.onItemIndexChange).AddListener((UnityAction)delegate
{
int itemIndex = cb.itemIndex;
if (itemIndex == 0)
{
PatchSave.EnableForAutoSaves.Value = false;
}
else
{
PatchSave.EnableForAutoSaves.Value = true;
PatchSave.CompressionTypeForAutoSaves = (CompressionType)(itemIndex - 1);
PatchSave.CompressionTypeForAutoSavesConfig.Value = CompressSave.StringFromCompresstionType(PatchSave.CompressionTypeForAutoSaves);
}
});
RectTransform val13 = (RectTransform)((Component)cb).transform;
anchoredPosition3D = val13.anchoredPosition3D;
val13.anchoredPosition3D = new Vector3(anchoredPosition3D.x - 50f, anchoredPosition3D.y, anchoredPosition3D.z);
Vector2 sizeDelta2 = val13.sizeDelta;
val13.sizeDelta = new Vector2(150f, sizeDelta2.y);
val.GetComponent<Text>().text = Localization.Translate("Compression for auto saves");
Localizer component3 = val.GetComponent<Localizer>();
if ((Object)(object)component3 != (Object)null)
{
component3.stringKey = "Compression for auto saves";
component3.translation = Localization.Translate("Compression for auto saves");
}
}
private static void WrapClick(int data)
{
PatchSave.UseCompressSave = false;
_context.Window.OSaveGameAs(data);
}
}
public static class SaveUtil
{
public static ManualLogSource Logger;
public static readonly Version VerifiedVersion = new Version
{
Major = 0,
Minor = 10,
Release = 28
};
private static string UnzipToFile(DecompressionStream lzStream, string fullPath)
{
lzStream.ResetStream();
string directoryName = Path.GetDirectoryName(fullPath);
string text = "[Recovery]-" + Path.GetFileNameWithoutExtension(fullPath);
fullPath = text + GameSave.saveExt;
if (directoryName != null)
{
fullPath = Path.Combine(directoryName, fullPath);
}
int num = 0;
while (File.Exists(fullPath))
{
fullPath = $"{text}[{num++}]{GameSave.saveExt}";
if (directoryName != null)
{
fullPath = Path.Combine(directoryName, fullPath);
}
}
byte[] array = new byte[1048576];
using (FileStream fileStream = new FileStream(fullPath, FileMode.Create))
{
using BinaryWriter binaryWriter = new BinaryWriter(fileStream);
for (int num2 = lzStream.Read(array, 0, array.Length); num2 > 0; num2 = lzStream.Read(array, 0, array.Length))
{
fileStream.Write(array, 0, num2);
}
fileStream.Seek(6L, SeekOrigin.Begin);
binaryWriter.Write(fileStream.Length);
}
return Path.GetFileNameWithoutExtension(fullPath);
}
public static bool DecompressSave(string saveName, out string newSaveName)
{
newSaveName = string.Empty;
string text = GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
try
{
using FileStream fileStream = new FileStream(text, FileMode.Open, FileAccess.Read);
CompressionType compressionType = SaveGetCompressType(fileStream);
if (compressionType != 0)
{
if ((uint)(compressionType - 1) <= 1u)
{
using (DecompressionStream lzStream = new DecompressionStream((compressionType == CompressionType.LZ4) ? PatchSave.LZ4Wrapper : PatchSave.ZstdWrapper, fileStream))
{
newSaveName = UnzipToFile(lzStream, text);
}
return true;
}
throw new ArgumentOutOfRangeException();
}
return false;
}
catch (Exception ex)
{
Logger.LogError((object)ex);
return false;
}
}
public static CompressionType SaveGetCompressType(FileStream fs)
{
for (int i = 0; i < 3; i++)
{
if (204 != fs.ReadByte())
{
return CompressionType.None;
}
}
return fs.ReadByte() switch
{
204 => CompressionType.LZ4,
205 => CompressionType.Zstd,
_ => CompressionType.None,
};
}
internal static CompressionType SaveGetCompressType(string saveName)
{
if (string.IsNullOrEmpty(saveName))
{
return CompressionType.None;
}
try
{
using FileStream fs = new FileStream(GetFullSavePath(saveName), FileMode.Open);
return SaveGetCompressType(fs);
}
catch (Exception ex)
{
Logger.LogWarning((object)ex);
return CompressionType.None;
}
}
private static string GetFullSavePath(string saveName)
{
return GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "org.soardev.compresssave";
public const string PLUGIN_NAME = "CompressSave";
public const string PLUGIN_VERSION = "1.3.6";
}
}
namespace CompressSave.Wrapper
{
internal class BlackHoleStream : Stream
{
private long _length;
private readonly byte[] _testBuffer = new byte[1048576];
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => _length;
public override long Position { get; set; }
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
return count;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
_length = value;
}
public override void Write(byte[] buffer, int offset, int count)
{
Array.Copy(buffer, offset, _testBuffer, 0, Math.Min(count, _testBuffer.Length));
}
}
public class BufferWriter : BinaryWriter
{
private readonly DoubleBuffer _doubleBuffer;
private readonly Encoding _encoding;
private readonly int _maxBytesPerChar;
private long _swapedBytes;
private unsafe byte* _curPos;
private unsafe byte* _endPos;
private unsafe byte* _startPos;
private readonly Stream _baseStream;
private ByteSpan CurrentBuffer => _doubleBuffer.WriteBuffer;
private byte[] Buffer => CurrentBuffer.Buffer;
private unsafe long SuplusCapacity => _endPos - _curPos;
public unsafe long WriteSum => _swapedBytes + _curPos - _startPos;
public override Stream BaseStream => _baseStream;
public override void Write(char[] chars, int index, int count)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
byte[] bytes = _encoding.GetBytes(chars, index, count);
Write(bytes);
}
public BufferWriter(DoubleBuffer doubleBuffer, CompressionStream outStream)
: this(doubleBuffer, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), outStream)
{
}
private BufferWriter(DoubleBuffer buffer, UTF8Encoding encoding, CompressionStream outStream)
: base(Stream.Null, encoding)
{
_baseStream = outStream;
_swapedBytes = 0L;
_doubleBuffer = buffer;
RefreshStatus();
_encoding = encoding;
_maxBytesPerChar = _encoding.GetMaxByteCount(1);
}
private unsafe void SwapBuffer()
{
CurrentBuffer.Position = 0;
CurrentBuffer.Length = (int)(_curPos - _startPos);
_swapedBytes += CurrentBuffer.Length;
_doubleBuffer.SwapBuffer();
RefreshStatus();
}
private unsafe void RefreshStatus()
{
_startPos = (byte*)System.Runtime.CompilerServices.Unsafe.AsPointer<byte>(ref Buffer[0]);
_curPos = _startPos;
_endPos = (byte*)System.Runtime.CompilerServices.Unsafe.AsPointer<byte>(ref Buffer[Buffer.Length - 1]) + 1;
}
private void CheckCapacityAndSwap(int requiredCapacity)
{
if (SuplusCapacity < requiredCapacity)
{
SwapBuffer();
}
}
public unsafe override void Write(byte value)
{
CheckCapacityAndSwap(1);
*(_curPos++) = value;
}
public override void Write(bool value)
{
Write(value ? ((byte)1) : ((byte)0));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
SwapBuffer();
}
base.Dispose(disposing);
}
public override void Close()
{
Dispose(disposing: true);
}
public override void Flush()
{
SwapBuffer();
}
public override long Seek(int offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void Write(sbyte value)
{
Write((byte)value);
}
public override void Write(byte[] buffer)
{
Write(buffer, 0, buffer.Length);
}
public unsafe override void Write(byte[] buffer, int index, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
fixed (byte* ptr = buffer)
{
byte* ptr2 = ptr + index;
while (SuplusCapacity <= count)
{
int num = (int)SuplusCapacity;
System.Runtime.CompilerServices.Unsafe.CopyBlock((void*)_curPos, (void*)ptr2, (uint)num);
count -= num;
ptr2 += num;
_curPos = _endPos;
SwapBuffer();
}
System.Runtime.CompilerServices.Unsafe.CopyBlock((void*)_curPos, (void*)ptr2, (uint)count);
_curPos += count;
}
}
public unsafe override void Write(char ch)
{
if (char.IsSurrogate(ch))
{
throw new ArgumentException("Arg_SurrogatesNotAllowedAsSingleChar");
}
CheckCapacityAndSwap(_maxBytesPerChar);
_curPos += _encoding.GetBytes(&ch, 1, _curPos, (int)SuplusCapacity);
}
public override void Write(char[] chars)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
byte[] bytes = _encoding.GetBytes(chars, 0, chars.Length);
Write(bytes);
}
public unsafe override void Write(double value)
{
CheckCapacityAndSwap(8);
ulong num = *(ulong*)(&value);
*(_curPos++) = (byte)num;
*(_curPos++) = (byte)(num >> 8);
*(_curPos++) = (byte)(num >> 16);
*(_curPos++) = (byte)(num >> 24);
*(_curPos++) = (byte)(num >> 32);
*(_curPos++) = (byte)(num >> 40);
*(_curPos++) = (byte)(num >> 48);
*(_curPos++) = (byte)(num >> 56);
}
public override void Write(decimal d)
{
CheckCapacityAndSwap(16);
int[] bits = decimal.GetBits(d);
Write(bits[0]);
Write(bits[1]);
Write(bits[2]);
Write(bits[3]);
}
public unsafe override void Write(short value)
{
CheckCapacityAndSwap(2);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
}
public unsafe override void Write(ushort value)
{
CheckCapacityAndSwap(2);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
}
public unsafe override void Write(int value)
{
if (SuplusCapacity < 4)
{
SwapBuffer();
}
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
}
public unsafe override void Write(uint value)
{
CheckCapacityAndSwap(4);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
}
public unsafe override void Write(long value)
{
CheckCapacityAndSwap(8);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
*(_curPos++) = (byte)(value >> 32);
*(_curPos++) = (byte)(value >> 40);
*(_curPos++) = (byte)(value >> 48);
*(_curPos++) = (byte)(value >> 56);
}
public unsafe override void Write(ulong value)
{
CheckCapacityAndSwap(8);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
*(_curPos++) = (byte)(value >> 32);
*(_curPos++) = (byte)(value >> 40);
*(_curPos++) = (byte)(value >> 48);
*(_curPos++) = (byte)(value >> 56);
}
public unsafe override void Write(float value)
{
CheckCapacityAndSwap(4);
uint num = *(uint*)(&value);
*(_curPos++) = (byte)num;
*(_curPos++) = (byte)(num >> 8);
*(_curPos++) = (byte)(num >> 16);
*(_curPos++) = (byte)(num >> 24);
}
public override void Write(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
byte[] bytes = _encoding.GetBytes(value);
Write7BitEncodedInt(bytes.Length);
Write(bytes);
}
private new void Write7BitEncodedInt(int value)
{
uint num;
for (num = (uint)value; num >= 128; num >>= 7)
{
Write((byte)(num | 0x80u));
}
Write((byte)num);
}
}
public class CompressionStream : Stream
{
public struct CompressBuffer
{
public byte[] ReadBuffer;
public byte[] WriteBuffer;
public byte[] OutBuffer;
}
private readonly WrapperDefines _wrapper;
public const int Mb = 1048576;
public readonly Stream OutStream;
private long _totalWrite;
private readonly bool _useMultiThread;
private DoubleBuffer _doubleBuffer;
private byte[] _outBuffer;
private IntPtr _cctx;
private long _lastError;
private bool _stopWorker = true;
private bool _closed;
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => _totalWrite;
public override long Position
{
get
{
return BufferWriter.WriteSum;
}
set
{
throw new NotImplementedException();
}
}
public BufferWriter BufferWriter { get; private set; }
public bool HasError()
{
return _lastError != 0;
}
private void HandleError(long errorCode)
{
if (errorCode < 0)
{
_wrapper.CompressContextFree(_cctx);
_cctx = IntPtr.Zero;
_lastError = errorCode;
throw new Exception(errorCode.ToString());
}
}
public static CompressBuffer CreateBuffer(int outBufferSize, int exBufferSize = 4194304)
{
try
{
CompressBuffer result = default(CompressBuffer);
result.OutBuffer = new byte[outBufferSize];
result.ReadBuffer = new byte[exBufferSize];
result.WriteBuffer = new byte[exBufferSize];
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return default(CompressBuffer);
}
public CompressionStream(WrapperDefines wrap, int compressionLevel, Stream outputStream, CompressBuffer compressBuffer, bool multiThread)
{
_wrapper = wrap;
OutStream = outputStream;
InitBuffer(compressBuffer.ReadBuffer, compressBuffer.WriteBuffer, compressBuffer.OutBuffer);
long num = _wrapper.CompressBegin(out _cctx, compressionLevel, _outBuffer, _outBuffer.Length, null, 0L);
HandleError(num);
outputStream.Write(_outBuffer, 0, (int)num);
_useMultiThread = multiThread;
if (multiThread)
{
_stopWorker = false;
new Thread(CompressAsync).Start();
}
}
private void InitBuffer(byte[] readBuffer, byte[] writeBuffer, byte[] outputBuffer)
{
_doubleBuffer = new DoubleBuffer(readBuffer ?? new byte[4194304], writeBuffer ?? new byte[4194304], Compress);
_outBuffer = outputBuffer ?? new byte[_wrapper.CompressBufferBound((writeBuffer != null) ? writeBuffer.Length : 4194304)];
BufferWriter = new BufferWriter(_doubleBuffer, this);
}
public override void Flush()
{
_doubleBuffer.SwapBuffer();
if (_useMultiThread)
{
_doubleBuffer.WaitReadEnd();
}
lock (_outBuffer)
{
OutStream.Flush();
}
}
private void Compress()
{
if (!_useMultiThread)
{
Compress_Internal();
}
}
private void Compress_Internal()
{
ByteSpan byteSpan = _doubleBuffer.ReadBegin();
if (byteSpan.Length > 0)
{
lock (_outBuffer)
{
long num;
try
{
num = _wrapper.CompressUpdateEx(_cctx, _outBuffer, 0L, byteSpan.Buffer, 0L, byteSpan.Length);
HandleError(num);
}
finally
{
_doubleBuffer.ReadEnd();
}
OutStream.Write(_outBuffer, 0, (int)num);
_totalWrite += num;
return;
}
}
_doubleBuffer.ReadEnd();
}
private void CompressAsync()
{
while (!_stopWorker)
{
Compress_Internal();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
BufferWriter.Write(buffer, offset, count);
}
private void FreeContext()
{
_wrapper.CompressContextFree(_cctx);
_cctx = IntPtr.Zero;
}
public override void Close()
{
if (!_closed)
{
BufferWriter.Close();
_closed = true;
Flush();
_stopWorker = true;
_doubleBuffer.SwapBuffer();
long num = _wrapper.CompressEnd(_cctx, _outBuffer, _outBuffer.Length);
OutStream.Write(_outBuffer, 0, (int)num);
base.Close();
}
}
protected override void Dispose(bool disposing)
{
FreeContext();
base.Dispose(disposing);
}
}
public class DecompressionStream : Stream
{
private readonly WrapperDefines _wrapper;
private readonly Stream _inStream;
private IntPtr _dctx = IntPtr.Zero;
private readonly ByteSpan _srcBuffer;
private readonly ByteSpan _dcmpBuffer;
private bool _decompressFinish;
private readonly long _startPos;
private long _readPos;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => _inStream.Length;
public override long Position
{
get
{
return _readPos;
}
set
{
if (value < _readPos)
{
ResetStream();
}
else
{
value -= _readPos;
}
byte[] buffer = new byte[1024];
while (value > 0)
{
value -= Read(buffer, 0, (int)((value < 1024) ? value : 1024));
}
}
}
public DecompressionStream(WrapperDefines wrap, Stream inputStream, int extraBufferSize = 524288)
{
_wrapper = wrap;
_inStream = inputStream;
_startPos = inputStream.Position;
_srcBuffer = new ByteSpan(new byte[extraBufferSize]);
int inBufferSize = Fill();
int blockSize;
long num = _wrapper.DecompressBegin(ref _dctx, _srcBuffer.Buffer, ref inBufferSize, out blockSize, null, 0L);
_srcBuffer.Position += inBufferSize;
if (num < 0)
{
throw new Exception(num.ToString());
}
_dcmpBuffer = new ByteSpan(new byte[blockSize]);
}
public void ResetStream()
{
_inStream.Seek(_startPos, SeekOrigin.Begin);
_decompressFinish = false;
_srcBuffer.Clear();
_dcmpBuffer.Clear();
_wrapper.DecompressContextReset(_dctx);
_readPos = 0L;
}
private int Fill()
{
int num = _srcBuffer.Length - _srcBuffer.Position;
if (_srcBuffer.Length > 0 && _srcBuffer.Position >= num)
{
Array.Copy((byte[])_srcBuffer, _srcBuffer.Position, (byte[])_srcBuffer, 0, num);
_srcBuffer.Length -= _srcBuffer.Position;
_srcBuffer.Position = 0;
}
if (_srcBuffer.IdleCapacity > 0)
{
int num2 = _inStream.Read(_srcBuffer, _srcBuffer.Length, _srcBuffer.IdleCapacity);
_srcBuffer.Length += num2;
}
return _srcBuffer.Length - _srcBuffer.Position;
}
public override void Flush()
{
}
protected override void Dispose(bool disposing)
{
_wrapper.DecompressEnd(_dctx);
_dctx = IntPtr.Zero;
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count)
{
int num = 0;
while (count > (num += _dcmpBuffer.Read(buffer, offset + num, count - num)) && !_decompressFinish)
{
int num2 = Fill();
if (num2 <= 0)
{
return num;
}
DecompressStatus decompressStatus = _wrapper.DecompressUpdateEx(_dctx, _dcmpBuffer, 0, _dcmpBuffer.Capacity, _srcBuffer, _srcBuffer.Position, num2);
if (decompressStatus.Expect < 0)
{
throw new Exception(decompressStatus.Expect.ToString());
}
if (decompressStatus.Expect == 0L)
{
_decompressFinish = true;
}
_srcBuffer.Position += (int)decompressStatus.ReadLen;
_dcmpBuffer.Position = 0;
_dcmpBuffer.Length = (int)decompressStatus.WriteLen;
}
_readPos += num;
return num;
}
public int PeekByte()
{
if (_dcmpBuffer.Length <= _dcmpBuffer.Position)
{
int num = Fill();
if (num <= 0)
{
return -1;
}
DecompressStatus decompressStatus = _wrapper.DecompressUpdateEx(_dctx, _dcmpBuffer, 0, _dcmpBuffer.Capacity, _srcBuffer, _srcBuffer.Position, num);
if (decompressStatus.Expect < 0)
{
throw new Exception(decompressStatus.Expect.ToString());
}
if (decompressStatus.Expect == 0L)
{
_decompressFinish = true;
}
_srcBuffer.Position += (int)decompressStatus.ReadLen;
_dcmpBuffer.Position = 0;
_dcmpBuffer.Length = (int)decompressStatus.WriteLen;
}
return _dcmpBuffer.Buffer[_dcmpBuffer.Position];
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
public class ByteSpan
{
public int Length;
public readonly int Capacity;
public int Position;
public byte[] Buffer { get; }
public int IdleCapacity => Capacity - Length;
public ByteSpan(byte[] buffer)
{
Buffer = buffer;
Capacity = Buffer.Length;
}
public void Clear()
{
Length = 0;
Position = 0;
}
public int Write(byte[] src, int offset, int count)
{
int num = Math.Min(Capacity - Length, count);
Array.Copy(src, offset, Buffer, Length, num);
Length += num;
return num;
}
public int Read(byte[] dst, int offset, int count)
{
count = Math.Min(Length - Position, count);
Array.Copy(Buffer, Position, dst, offset, count);
Position += count;
return count;
}
public static implicit operator byte[](ByteSpan bs)
{
return bs.Buffer;
}
}
public struct ReadOnlySpan
{
[CompilerGenerated]
private int <length>P;
private readonly byte[] _buffer;
private int _position;
public ReadOnlySpan(byte[] buffer, int length)
{
<length>P = length;
_buffer = buffer;
_position = 0;
}
public int Read(byte[] dst, int offset, int count)
{
count = Math.Min(<length>P - _position, count);
Array.Copy(_buffer, _position, dst, offset, count);
_position += count;
return count;
}
public static implicit operator byte[](ReadOnlySpan s)
{
return s._buffer;
}
}
public class DoubleBuffer
{
[CompilerGenerated]
private Action <onReadBufferReadyAction>P;
public const int Mb = 1048576;
public ByteSpan WriteBuffer;
private ByteSpan _readBuffer;
private ByteSpan _midBuffer;
private readonly Semaphore _readEnd;
private readonly Semaphore _writeEnd;
public DoubleBuffer(byte[] readingBuffer, byte[] writingBuffer, Action onReadBufferReadyAction)
{
<onReadBufferReadyAction>P = onReadBufferReadyAction;
WriteBuffer = new ByteSpan(writingBuffer);
_midBuffer = new ByteSpan(readingBuffer);
_readEnd = new Semaphore(1, 1);
_writeEnd = new Semaphore(0, 1);
base..ctor();
}
public ByteSpan ReadBegin()
{
_writeEnd.WaitOne();
return _readBuffer;
}
public void ReadEnd()
{
_readBuffer.Clear();
_midBuffer = _readBuffer;
_readBuffer = null;
_readEnd.Release();
}
public ByteSpan SwapBuffer(bool triggerEvent = true)
{
ByteSpan result = SwapBegin();
SwapEnd();
Action action = <onReadBufferReadyAction>P;
if (action != null)
{
action();
return result;
}
return result;
}
public void WaitReadEnd()
{
_readEnd.WaitOne();
_readEnd.Release();
}
private ByteSpan SwapBegin()
{
_readEnd.WaitOne();
_readBuffer = WriteBuffer;
WriteBuffer = _midBuffer;
_midBuffer = null;
return WriteBuffer;
}
private void SwapEnd()
{
_writeEnd.Release();
}
}
public class LZ4API : WrapperDefines
{
public static readonly bool Avaliable;
[DynDllImport("lz4wrap.dll", new string[] { "CompressBufferBound" })]
protected static CompressBufferBoundFunc CompressBufferBound_;
[DynDllImport("lz4wrap.dll", new string[] { "CompressBegin" })]
protected static CompressBeginFunc CompressBegin_;
[DynDllImport("lz4wrap.dll", new string[] { "CompressEnd" })]
protected static CompressEndFunc CompressEnd_;
[DynDllImport("lz4wrap.dll", new string[] { "CompressUpdate" })]
protected static CompressUpdateFunc CompressUpdate_;
[DynDllImport("lz4wrap.dll", new string[] { "CompressContextFree" })]
protected static CompressContextFreeFunc CompressContextFree_;
[DynDllImport("lz4wrap.dll", new string[] { "DecompressBegin" })]
protected static DecompressBeginFunc DecompressBegin_;
[DynDllImport("lz4wrap.dll", new string[] { "DecompressEnd" })]
protected static DecompressEndFunc DecompressEnd_;
[DynDllImport("lz4wrap.dll", new string[] { "DecompressUpdate" })]
protected static DecompressUpdateFunc DecompressUpdate_;
[DynDllImport("lz4wrap.dll", new string[] { "DecompressContextReset" })]
protected static DecompressContextResetFunc DecompressContextReset_;
static LZ4API()
{
Avaliable = true;
string location = Assembly.GetAssembly(typeof(LZ4API)).Location;
string path = string.Empty;
try
{
if (!string.IsNullOrEmpty(location))
{
path = Path.GetDirectoryName(location) ?? string.Empty;
}
Dictionary<string, List<DynDllMapping>> dictionary = new Dictionary<string, List<DynDllMapping>> {
{
"lz4wrap.dll",
new List<DynDllMapping>(7)
{
DynDllMapping.op_Implicit("lz4wrap.dll"),
DynDllMapping.op_Implicit("x64/lz4wrap.dll"),
DynDllMapping.op_Implicit("plugins/x64/lz4wrap.dll"),
DynDllMapping.op_Implicit("BepInEx/scripts/x64/lz4wrap.dll"),
DynDllMapping.op_Implicit(Path.Combine(path, "lz4wrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "x64/lz4wrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "plugins/x64/lz4wrap.dll"))
}
} };
DynDll.ResolveDynDllImports(typeof(LZ4API), dictionary);
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
public LZ4API()
{
CompressBufferBound = CompressBufferBound_;
CompressBegin = CompressBegin_;
CompressEnd = CompressEnd_;
CompressUpdate = CompressUpdate_;
CompressContextFree = CompressContextFree_;
DecompressBegin = DecompressBegin_;
DecompressEnd = DecompressEnd_;
DecompressUpdate = DecompressUpdate_;
DecompressContextReset = DecompressContextReset_;
}
}
public class NoneAPI : WrapperDefines
{
public static readonly bool Avaliable;
[DynDllImport("nonewrap.dll", new string[] { "CompressBufferBound" })]
protected static CompressBufferBoundFunc CompressBufferBound_;
[DynDllImport("nonewrap.dll", new string[] { "CompressBegin" })]
protected static CompressBeginFunc CompressBegin_;
[DynDllImport("nonewrap.dll", new string[] { "CompressEnd" })]
protected static CompressEndFunc CompressEnd_;
[DynDllImport("nonewrap.dll", new string[] { "CompressUpdate" })]
protected static CompressUpdateFunc CompressUpdate_;
[DynDllImport("nonewrap.dll", new string[] { "CompressContextFree" })]
protected static CompressContextFreeFunc CompressContextFree_;
[DynDllImport("nonewrap.dll", new string[] { "DecompressBegin" })]
protected static DecompressBeginFunc DecompressBegin_;
[DynDllImport("nonewrap.dll", new string[] { "DecompressEnd" })]
protected static DecompressEndFunc DecompressEnd_;
[DynDllImport("nonewrap.dll", new string[] { "DecompressUpdate" })]
protected static DecompressUpdateFunc DecompressUpdate_;
[DynDllImport("nonewrap.dll", new string[] { "DecompressContextReset" })]
protected static DecompressContextResetFunc DecompressContextReset_;
static NoneAPI()
{
Avaliable = true;
string location = Assembly.GetAssembly(typeof(NoneAPI)).Location;
string path = string.Empty;
try
{
if (!string.IsNullOrEmpty(location))
{
path = Path.GetDirectoryName(location) ?? string.Empty;
}
Dictionary<string, List<DynDllMapping>> dictionary = new Dictionary<string, List<DynDllMapping>> {
{
"nonewrap.dll",
new List<DynDllMapping>(7)
{
DynDllMapping.op_Implicit("nonewrap.dll"),
DynDllMapping.op_Implicit("x64/nonewrap.dll"),
DynDllMapping.op_Implicit("plugins/x64/nonewrap.dll"),
DynDllMapping.op_Implicit("BepInEx/scripts/x64/nonewrap.dll"),
DynDllMapping.op_Implicit(Path.Combine(path, "nonewrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "x64/nonewrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "plugins/x64/nonewrap.dll"))
}
} };
DynDll.ResolveDynDllImports(typeof(NoneAPI), dictionary);
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
public NoneAPI()
{
CompressBufferBound = CompressBufferBound_;
CompressBegin = CompressBegin_;
CompressEnd = CompressEnd_;
CompressUpdate = CompressUpdate_;
CompressContextFree = CompressContextFree_;
DecompressBegin = DecompressBegin_;
DecompressEnd = DecompressEnd_;
DecompressUpdate = DecompressUpdate_;
DecompressContextReset = DecompressContextReset_;
}
}
internal class PeekableReader : BinaryReader
{
[CompilerGenerated]
private DecompressionStream <input>P;
public PeekableReader(DecompressionStream input)
{
<input>P = input;
base..ctor(<input>P);
}
public override int PeekChar()
{
return <input>P.PeekByte();
}
}
public struct DecompressStatus
{
public long WriteLen;
public long ReadLen;
public long Expect;
}
public class WrapperDefines
{
public delegate long CompressBufferBoundFunc(long inBufferSize);
public delegate long CompressBeginFunc(out IntPtr ctx, int compressionLevel, byte[] outBuff, long outCapacity, byte[] dictBuffer = null, long dictSize = 0L);
public delegate long CompressEndFunc(IntPtr ctx, byte[] dstBuffer, long dstCapacity);
public delegate void CompressContextFreeFunc(IntPtr ctx);
public delegate long DecompressBeginFunc(ref IntPtr pdctx, byte[] inBuffer, ref int inBufferSize, out int blockSize, byte[] dict = null, long dictSize = 0L);
public delegate long DecompressEndFunc(IntPtr dctx);
public delegate void DecompressContextResetFunc(IntPtr dctx);
protected unsafe delegate long CompressUpdateFunc(IntPtr ctx, byte* dstBuffer, long dstCapacity, byte* srcBuffer, long srcSize);
protected unsafe delegate long DecompressUpdateFunc(IntPtr dctx, byte* dstBuffer, ref long dstCapacity, byte* srcBuffer, ref long srcSize);
public CompressBufferBoundFunc CompressBufferBound;
public CompressBeginFunc CompressBegin;
public CompressEndFunc CompressEnd;
public CompressContextFreeFunc CompressContextFree;
public DecompressBeginFunc DecompressBegin;
public DecompressEndFunc DecompressEnd;
public DecompressContextResetFunc DecompressContextReset;
protected CompressUpdateFunc CompressUpdate;
protected DecompressUpdateFunc DecompressUpdate;
public unsafe long CompressUpdateEx(IntPtr ctx, byte[] dstBuffer, long dstOffset, byte[] srcBuffer, long srcOffset, long srcLen)
{
fixed (byte* ptr = dstBuffer)
{
fixed (byte* ptr2 = srcBuffer)
{
return CompressUpdate(ctx, ptr + dstOffset, dstBuffer.Length - dstOffset, ptr2 + srcOffset, srcLen - srcOffset);
}
}
}
public unsafe DecompressStatus DecompressUpdateEx(IntPtr dctx, byte[] dstBuffer, int dstOffset, int dstCount, byte[] srcBuffer, long srcOffset, long count)
{
long dstCapacity = Math.Min(dstCount, dstBuffer.Length - dstOffset);
long expect;
fixed (byte* ptr = dstBuffer)
{
fixed (byte* ptr2 = srcBuffer)
{
expect = DecompressUpdate(dctx, ptr + dstOffset, ref dstCapacity, ptr2 + srcOffset, ref count);
}
}
DecompressStatus result = default(DecompressStatus);
result.Expect = expect;
result.ReadLen = count;
result.WriteLen = dstCapacity;
return result;
}
}
public class ZstdAPI : WrapperDefines
{
public static readonly bool Avaliable;
[DynDllImport("zstdwrap.dll", new string[] { "CompressBufferBound" })]
protected static CompressBufferBoundFunc CompressBufferBound_;
[DynDllImport("zstdwrap.dll", new string[] { "CompressBegin" })]
protected static CompressBeginFunc CompressBegin_;
[DynDllImport("zstdwrap.dll", new string[] { "CompressEnd" })]
protected static CompressEndFunc CompressEnd_;
[DynDllImport("zstdwrap.dll", new string[] { "CompressUpdate" })]
protected static CompressUpdateFunc CompressUpdate_;
[DynDllImport("zstdwrap.dll", new string[] { "CompressContextFree" })]
protected static CompressContextFreeFunc CompressContextFree_;
[DynDllImport("zstdwrap.dll", new string[] { "DecompressBegin" })]
protected static DecompressBeginFunc DecompressBegin_;
[DynDllImport("zstdwrap.dll", new string[] { "DecompressEnd" })]
protected static DecompressEndFunc DecompressEnd_;
[DynDllImport("zstdwrap.dll", new string[] { "DecompressUpdate" })]
protected static DecompressUpdateFunc DecompressUpdate_;
[DynDllImport("zstdwrap.dll", new string[] { "DecompressContextReset" })]
protected static DecompressContextResetFunc DecompressContextReset_;
static ZstdAPI()
{
Avaliable = true;
string location = Assembly.GetAssembly(typeof(ZstdAPI)).Location;
string path = string.Empty;
try
{
if (!string.IsNullOrEmpty(location))
{
path = Path.GetDirectoryName(location) ?? string.Empty;
}
Dictionary<string, List<DynDllMapping>> dictionary = new Dictionary<string, List<DynDllMapping>> {
{
"zstdwrap.dll",
new List<DynDllMapping>(7)
{
DynDllMapping.op_Implicit("zstdwrap.dll"),
DynDllMapping.op_Implicit("x64/zstdwrap.dll"),
DynDllMapping.op_Implicit("plugins/x64/zstdwrap.dll"),
DynDllMapping.op_Implicit("BepInEx/scripts/x64/zstdwrap.dll"),
DynDllMapping.op_Implicit(Path.Combine(path, "zstdwrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "x64/zstdwrap.dll")),
DynDllMapping.op_Implicit(Path.Combine(path, "plugins/x64/zstdwrap.dll"))
}
} };
DynDll.ResolveDynDllImports(typeof(ZstdAPI), dictionary);
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
public ZstdAPI()
{
CompressBufferBound = CompressBufferBound_;
CompressBegin = CompressBegin_;
CompressEnd = CompressEnd_;
CompressUpdate = CompressUpdate_;
CompressContextFree = CompressContextFree_;
DecompressBegin = DecompressBegin_;
DecompressEnd = DecompressEnd_;
DecompressUpdate = DecompressUpdate_;
DecompressContextReset = DecompressContextReset_;
}
}
}