Decompiled source of BundleSlimmer v1.1.0

patchers/BundleSlimmer.dll

Decompiled a week ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BundleSlimmer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("BundleSlimmer")]
[assembly: AssemblyTitle("BundleSlimmer")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace 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")
		{
		}
	}
	public interface ICodeProgress
	{
		void SetProgress(long inSize, long outSize);
	}
	public interface ICoder
	{
		void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress);
	}
	internal class InvalidParamException : ApplicationException
	{
		public InvalidParamException()
			: base("Invalid Parameter")
		{
		}
	}
	public interface ISetDecoderProperties
	{
		void SetDecoderProperties(byte[] properties);
	}
}
namespace SevenZip.Compression.LZ
{
	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.RangeCoder
{
	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) | rangeDecoder.NextByte();
					rangeDecoder.Range <<= 8;
				}
				return 0u;
			}
			rangeDecoder.Range -= num;
			rangeDecoder.Code -= num;
			Prob -= Prob >> 5;
			if (rangeDecoder.Range < 16777216)
			{
				rangeDecoder.Code = (rangeDecoder.Code << 8) | rangeDecoder.NextByte();
				rangeDecoder.Range <<= 8;
			}
			return 1u;
		}
	}
	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;
		}
	}
	internal class Decoder
	{
		public const uint kTopValue = 16777216u;

		public uint Range;

		public uint Code;

		public Stream Stream;

		private readonly byte[] _in = new byte[65536];

		private int _inPos;

		private int _inLen;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public byte NextByte()
		{
			if (_inPos == _inLen)
			{
				_inLen = Stream.Read(_in, 0, _in.Length);
				_inPos = 0;
				if (_inLen <= 0)
				{
					_inLen = 0;
					return byte.MaxValue;
				}
			}
			return _in[_inPos++];
		}

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

		public void ReleaseStream()
		{
			Stream = null;
		}

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

		public void Normalize()
		{
			while (Range < 16777216)
			{
				Code = (Code << 8) | NextByte();
				Range <<= 8;
			}
		}

		public void Normalize2()
		{
			if (Range < 16777216)
			{
				Code = (Code << 8) | NextByte();
				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) | NextByte();
					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;
		}
	}
}
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) & 1);
						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 num4 = 0u; num4 < 4; num4++)
			{
				m_PosSlotDecoder[num4].Init();
			}
			for (uint num5 = 0u; num5 < 114; num5++)
			{
				m_PosDecoders[num5].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 prevByte = m_OutWindow.GetByte(0u);
					byte b2 = (state.IsCharState() ? m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)num5, prevByte) : m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, (uint)num5, prevByte, 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);
		}
	}
}
namespace BundleSlimmer
{
	internal static class AudioPatch
	{
		private class Reader
		{
			private readonly FileStream f;

			private readonly long origin;

			private readonly byte[] b = new byte[8];

			internal bool BigEndian;

			internal Reader(FileStream f, long origin)
			{
				this.f = f;
				this.origin = origin;
				f.Position = origin;
			}

			private byte[] Take(int n)
			{
				if (f.Read(b, 0, n) != n)
				{
					throw new EndOfStreamException();
				}
				if (BigEndian != !BitConverter.IsLittleEndian)
				{
					Array.Reverse(b, 0, n);
				}
				return b;
			}

			internal byte U8()
			{
				return Take(1)[0];
			}

			internal short I16()
			{
				return BitConverter.ToInt16(Take(2), 0);
			}

			internal int I32()
			{
				return BitConverter.ToInt32(Take(4), 0);
			}

			internal uint U32()
			{
				return BitConverter.ToUInt32(Take(4), 0);
			}

			internal long I64()
			{
				return BitConverter.ToInt64(Take(8), 0);
			}

			internal void Skip(long n)
			{
				f.Position += n;
			}

			internal void Align4()
			{
				f.Position = origin + ((f.Position - origin + 3) & -4);
			}

			internal string CString()
			{
				StringBuilder stringBuilder = new StringBuilder();
				int num;
				while ((num = f.ReadByte()) > 0)
				{
					stringBuilder.Append((char)num);
				}
				return stringBuilder.ToString();
			}
		}

		private const int AudioClipClassId = 83;

		private const int DecompressOnLoad = 0;

		private const int CompressedInMemory = 1;

		private const int FormatPcm = 0;

		internal static int Patch(FileStream file, long start, long size)
		{
			Reader reader = new Reader(file, start);
			reader.BigEndian = true;
			reader.U32();
			reader.U32();
			uint num = reader.U32();
			long num2 = reader.U32();
			if (num < 17 || num > 22)
			{
				return 0;
			}
			bool flag = reader.U8() != 0;
			reader.Skip(3L);
			if (num >= 22)
			{
				reader.U32();
				reader.I64();
				num2 = reader.I64();
				reader.I64();
			}
			reader.BigEndian = flag;
			reader.CString();
			reader.I32();
			bool flag2 = reader.U8() != 0;
			int num3 = reader.I32();
			int[] array = new int[num3];
			for (int i = 0; i < num3; i++)
			{
				int num4 = (array[i] = reader.I32());
				reader.U8();
				reader.I16();
				if (num4 == 114)
				{
					reader.Skip(16L);
				}
				reader.Skip(16L);
				if (flag2)
				{
					int num5 = reader.I32();
					int num6 = reader.I32();
					reader.Skip((long)num5 * (long)((num >= 19) ? 32 : 24) + num6);
					if (num >= 21)
					{
						reader.Skip(4L * (long)reader.I32());
					}
				}
			}
			int num7 = reader.I32();
			int num8 = 0;
			byte[] buf = new byte[8];
			for (int j = 0; j < num7; j++)
			{
				reader.Align4();
				reader.I64();
				long num9 = ((num >= 22) ? reader.I64() : reader.U32());
				long num10 = reader.U32();
				int num11 = reader.I32();
				if (num11 < 0 || num11 >= num3 || array[num11] != 83)
				{
					continue;
				}
				long num12 = start + num2 + num9;
				if (num9 + num10 > size - num2 || num10 < 16)
				{
					continue;
				}
				long position = file.Position;
				int num13 = ReadInt(file, num12, buf, flag);
				long num14 = num12 + 4 + ((num13 + 3) & -4);
				if (num13 < 0 || num14 + 4 > num12 + num10)
				{
					file.Position = position;
					continue;
				}
				int num15 = ReadInt(file, num14, buf, flag);
				int num16 = ReadInt(file, num12 + num10 - 4, buf, flag);
				if (num15 == 0 && num16 != 0)
				{
					WriteInt(file, num14, 1, flag);
					num8++;
				}
				file.Position = position;
			}
			return num8;
		}

		private static int ReadInt(FileStream f, long pos, byte[] buf, bool big)
		{
			f.Position = pos;
			if (f.Read(buf, 0, 4) != 4)
			{
				throw new EndOfStreamException();
			}
			if (!big)
			{
				return BitConverter.ToInt32(buf, 0);
			}
			return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
		}

		private static void WriteInt(FileStream f, long pos, int v, bool big)
		{
			byte[] bytes = BitConverter.GetBytes(v);
			if (big)
			{
				Array.Reverse(bytes);
			}
			f.Position = pos;
			f.Write(bytes, 0, 4);
		}
	}
	internal static class Converter
	{
		internal class Bundle
		{
			internal uint Version;

			internal string UnityVersion;

			internal string Revision;

			internal uint Flags;

			internal long DataStart;

			internal uint[] BlockUncompressed;

			internal uint[] BlockCompressed;

			internal ushort[] BlockFlags;

			internal byte[] Nodes;

			internal bool HasLzma
			{
				get
				{
					ushort[] blockFlags = BlockFlags;
					for (int i = 0; i < blockFlags.Length; i++)
					{
						if ((blockFlags[i] & 0x3F) == 1)
						{
							return true;
						}
					}
					return false;
				}
			}

			internal long UncompressedSize
			{
				get
				{
					long num = 0L;
					uint[] blockUncompressed = BlockUncompressed;
					foreach (uint num2 in blockUncompressed)
					{
						num += num2;
					}
					return num;
				}
			}
		}

		internal class Result
		{
			internal bool Rewritten;

			internal int ClipsFlipped;

			internal uint Checksum;

			internal long RawSize;
		}

		private struct Block
		{
			internal uint Uncompressed;

			internal uint Compressed;

			internal ushort Flags;
		}

		private class ChunkWriter : Stream
		{
			private readonly Stream output;

			private readonly byte[] buffer = new byte[131072];

			private readonly byte[] packed = new byte[Lz4.MaxOutput(131072)];

			private readonly int[] table = new int[65536];

			private int filled;

			internal readonly List<Block> Blocks = new List<Block>();

			internal long Total;

			internal uint Checksum = uint.MaxValue;

			public override bool CanRead => false;

			public override bool CanSeek => false;

			public override bool CanWrite => true;

			public override long Length => Total;

			public override long Position
			{
				get
				{
					return Total;
				}
				set
				{
					throw new NotSupportedException();
				}
			}

			internal ChunkWriter(Stream output)
			{
				this.output = output;
			}

			public override void Write(byte[] data, int offset, int count)
			{
				Checksum = Crc.Update(Checksum, data, offset, count);
				Total += count;
				while (count > 0)
				{
					int num = Math.Min(count, 131072 - filled);
					Buffer.BlockCopy(data, offset, buffer, filled, num);
					filled += num;
					offset += num;
					count -= num;
					if (filled == 131072)
					{
						Flush();
					}
				}
			}

			public override void WriteByte(byte value)
			{
				Write(new byte[1] { value }, 0, 1);
			}

			public override void Flush()
			{
				if (filled != 0)
				{
					int num = Lz4.Compress(buffer, filled, packed, table);
					if (num < filled)
					{
						output.Write(packed, 0, num);
						Blocks.Add(new Block
						{
							Uncompressed = (uint)filled,
							Compressed = (uint)num,
							Flags = 2
						});
					}
					else
					{
						output.Write(buffer, 0, filled);
						Blocks.Add(new Block
						{
							Uncompressed = (uint)filled,
							Compressed = (uint)filled,
							Flags = 0
						});
					}
					filled = 0;
				}
			}

			internal void Finish()
			{
				Flush();
			}

			public override int Read(byte[] b, int o, int c)
			{
				throw new NotSupportedException();
			}

			public override long Seek(long o, SeekOrigin so)
			{
				throw new NotSupportedException();
			}

			public override void SetLength(long v)
			{
				throw new NotSupportedException();
			}
		}

		private static class Crc
		{
			internal const uint Init = uint.MaxValue;

			private static readonly uint[] Table = MakeTable();

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

			internal static uint Update(uint crc, byte[] data, int offset, int count)
			{
				for (int i = offset; i < offset + count; i++)
				{
					crc = Table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
				}
				return crc;
			}
		}

		private const int Chunk = 131072;

		private const uint FlagCompressionMask = 63u;

		private const uint FlagBlocksInfoAtEnd = 128u;

		private const uint FlagPaddingAtStart = 512u;

		private const uint OutFlags = 194u;

		private const ushort BlockLz4 = 2;

		internal static bool LooksLikeBundle(string path)
		{
			byte[] array = new byte[8];
			using FileStream fileStream = File.OpenRead(path);
			return fileStream.Read(array, 0, 8) == 8 && Encoding.ASCII.GetString(array) == "UnityFS\0";
		}

		internal static Bundle Read(Stream s)
		{
			Bundle bundle = new Bundle();
			if (ReadString(s) != "UnityFS")
			{
				throw new InvalidDataException("not a UnityFS bundle");
			}
			bundle.Version = ReadU32(s);
			bundle.UnityVersion = ReadString(s);
			bundle.Revision = ReadString(s);
			ReadI64(s);
			uint num = ReadU32(s);
			uint rawSize = ReadU32(s);
			bundle.Flags = ReadU32(s);
			if (bundle.Version >= 7)
			{
				Align16(s);
			}
			long position = s.Position;
			if ((bundle.Flags & 0x80) != 0)
			{
				s.Position = s.Length - num;
			}
			byte[] array = Decode(ReadExact(s, (int)num), bundle.Flags & 0x3F, (int)rawSize);
			if ((bundle.Flags & 0x80) != 0)
			{
				bundle.DataStart = position;
			}
			else
			{
				bundle.DataStart = position + num;
			}
			if ((bundle.Flags & 0x200) != 0)
			{
				bundle.DataStart = (bundle.DataStart + 15) & -16;
			}
			MemoryStream memoryStream = new MemoryStream(array)
			{
				Position = 16L
			};
			int num2 = (int)ReadU32(memoryStream);
			bundle.BlockUncompressed = new uint[num2];
			bundle.BlockCompressed = new uint[num2];
			bundle.BlockFlags = new ushort[num2];
			for (int i = 0; i < num2; i++)
			{
				bundle.BlockUncompressed[i] = ReadU32(memoryStream);
				bundle.BlockCompressed[i] = ReadU32(memoryStream);
				bundle.BlockFlags[i] = (ushort)((memoryStream.ReadByte() << 8) | memoryStream.ReadByte());
			}
			bundle.Nodes = new byte[array.Length - memoryStream.Position];
			Array.Copy(array, memoryStream.Position, bundle.Nodes, 0L, bundle.Nodes.Length);
			return bundle;
		}

		internal static Result Convert(string src, string dst, bool fixAudio)
		{
			Result result = new Result();
			string path = dst + ".raw";
			try
			{
				Bundle bundle;
				using (FileStream fileStream = new FileStream(src, FileMode.Open, FileAccess.Read, FileShare.Read, 1048576))
				{
					using FileStream fileStream2 = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 1048576);
					bundle = Read(fileStream);
					result.RawSize = bundle.UncompressedSize;
					Unpack(bundle, fileStream, fileStream2);
					if (fileStream2.Length != bundle.UncompressedSize)
					{
						throw new InvalidDataException($"data size {fileStream2.Length} != {bundle.UncompressedSize}");
					}
					if (fixAudio)
					{
						foreach (KeyValuePair<long, long> item in SerializedNodes(bundle))
						{
							result.ClipsFlipped += AudioPatch.Patch(fileStream2, item.Key, item.Value);
						}
					}
				}
				if (!bundle.HasLzma && result.ClipsFlipped == 0)
				{
					return result;
				}
				using (FileStream fileStream3 = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1048576))
				{
					using FileStream fileStream4 = new FileStream(dst, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 1048576);
					WriteHeader(fileStream4, bundle, 0L, 0u, 0u);
					ChunkWriter chunkWriter = new ChunkWriter(fileStream4);
					byte[] array = new byte[1048576];
					int count;
					while ((count = fileStream3.Read(array, 0, array.Length)) > 0)
					{
						chunkWriter.Write(array, 0, count);
					}
					chunkWriter.Finish();
					MemoryStream memoryStream = new MemoryStream();
					memoryStream.Write(new byte[16], 0, 16);
					WriteU32(memoryStream, (uint)chunkWriter.Blocks.Count);
					foreach (Block block in chunkWriter.Blocks)
					{
						WriteU32(memoryStream, block.Uncompressed);
						WriteU32(memoryStream, block.Compressed);
						memoryStream.WriteByte((byte)(block.Flags >> 8));
						memoryStream.WriteByte((byte)block.Flags);
					}
					memoryStream.Write(bundle.Nodes, 0, bundle.Nodes.Length);
					byte[] array2 = memoryStream.ToArray();
					byte[] array3 = new byte[Lz4.MaxOutput(array2.Length)];
					int num = Lz4.Compress(array2, array2.Length, array3, new int[65536]);
					fileStream4.Write(array3, 0, num);
					long position = fileStream4.Position;
					fileStream4.Position = 0L;
					WriteHeader(fileStream4, bundle, position, (uint)num, (uint)array2.Length);
					result.Checksum = chunkWriter.Checksum;
				}
				result.Rewritten = true;
				return result;
			}
			finally
			{
				try
				{
					File.Delete(path);
				}
				catch
				{
				}
			}
		}

		private static void Unpack(Bundle b, Stream input, Stream raw)
		{
			long num = b.DataStart;
			for (int i = 0; i < b.BlockFlags.Length; i++)
			{
				input.Position = num;
				num += b.BlockCompressed[i];
				uint num2 = (uint)(b.BlockFlags[i] & 0x3F);
				if (num2 == 1)
				{
					byte[] decoderProperties = ReadExact(input, 5);
					SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
					decoder.SetDecoderProperties(decoderProperties);
					decoder.Code(input, raw, b.BlockCompressed[i] - 5, b.BlockUncompressed[i], null);
				}
				else
				{
					byte[] array = Decode(ReadExact(input, (int)b.BlockCompressed[i]), num2, (int)b.BlockUncompressed[i]);
					raw.Write(array, 0, array.Length);
				}
			}
		}

		private static IEnumerable<KeyValuePair<long, long>> SerializedNodes(Bundle b)
		{
			MemoryStream r = new MemoryStream(b.Nodes);
			int count = (int)ReadU32(r);
			for (int i = 0; i < count; i++)
			{
				long key = ReadI64(r);
				long value = ReadI64(r);
				uint num = ReadU32(r);
				ReadString(r);
				if ((num & 4) != 0)
				{
					yield return new KeyValuePair<long, long>(key, value);
				}
			}
		}

		internal static void Verify(string path, uint expectedChecksum, long expectedSize)
		{
			using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1048576);
			Bundle bundle = Read(fileStream);
			if (bundle.HasLzma)
			{
				throw new InvalidDataException("still LZMA");
			}
			uint num = uint.MaxValue;
			long num2 = 0L;
			fileStream.Position = bundle.DataStart;
			for (int i = 0; i < bundle.BlockFlags.Length; i++)
			{
				byte[] array = Decode(ReadExact(fileStream, (int)bundle.BlockCompressed[i]), (uint)(bundle.BlockFlags[i] & 0x3F), (int)bundle.BlockUncompressed[i]);
				num = Crc.Update(num, array, 0, array.Length);
				num2 += array.Length;
			}
			if (num2 != expectedSize || num != expectedChecksum)
			{
				throw new InvalidDataException("converted data does not match the original");
			}
		}

		private static void WriteHeader(Stream s, Bundle b, long size, uint packedInfo, uint rawInfo)
		{
			WriteString(s, "UnityFS");
			WriteU32(s, b.Version);
			WriteString(s, b.UnityVersion);
			WriteString(s, b.Revision);
			WriteU32(s, (uint)(size >> 32));
			WriteU32(s, (uint)size);
			WriteU32(s, packedInfo);
			WriteU32(s, rawInfo);
			WriteU32(s, 194u);
			if (b.Version >= 7)
			{
				while (s.Position % 16 != 0L)
				{
					s.WriteByte(0);
				}
			}
		}

		private static byte[] Decode(byte[] packed, uint kind, int rawSize)
		{
			switch (kind)
			{
			case 0u:
				return packed;
			case 1u:
			{
				SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
				byte[] array2 = new byte[5];
				Array.Copy(packed, array2, 5);
				decoder.SetDecoderProperties(array2);
				MemoryStream memoryStream = new MemoryStream(rawSize);
				decoder.Code(new MemoryStream(packed, 5, packed.Length - 5), memoryStream, packed.Length - 5, rawSize, null);
				return memoryStream.ToArray();
			}
			case 2u:
			case 3u:
			{
				byte[] array = new byte[rawSize];
				Lz4.Decompress(packed, 0, packed.Length, array, rawSize);
				return array;
			}
			default:
				throw new NotSupportedException("unknown bundle compression " + kind);
			}
		}

		private static byte[] ReadExact(Stream s, int n)
		{
			byte[] array = new byte[n];
			int num;
			for (int i = 0; i < n; i += num)
			{
				num = s.Read(array, i, n - i);
				if (num <= 0)
				{
					throw new EndOfStreamException();
				}
			}
			return array;
		}

		private static string ReadString(Stream s)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int num;
			while ((num = s.ReadByte()) > 0)
			{
				stringBuilder.Append((char)num);
			}
			return stringBuilder.ToString();
		}

		private static uint ReadU32(Stream s)
		{
			byte[] array = ReadExact(s, 4);
			return (uint)((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]);
		}

		private static long ReadI64(Stream s)
		{
			return (long)(((ulong)ReadU32(s) << 32) | ReadU32(s));
		}

		private static void Align16(Stream s)
		{
			s.Position = (s.Position + 15) & -16;
		}

		private static void WriteString(Stream s, string v)
		{
			byte[] bytes = Encoding.ASCII.GetBytes(v);
			s.Write(bytes, 0, bytes.Length);
			s.WriteByte(0);
		}

		private static void WriteU32(Stream s, uint v)
		{
			s.WriteByte((byte)(v >> 24));
			s.WriteByte((byte)(v >> 16));
			s.WriteByte((byte)(v >> 8));
			s.WriteByte((byte)v);
		}
	}
	internal static class Lz4
	{
		private const int MinMatch = 4;

		private const int HashBits = 16;

		private const int LastLiterals = 5;

		private const int MatchSafety = 12;

		internal static int MaxOutput(int length)
		{
			return length + length / 255 + 16;
		}

		internal static int Compress(byte[] src, int srcLen, byte[] dst, int[] table)
		{
			Array.Clear(table, 0, table.Length);
			int num = 0;
			int num2 = 0;
			int op = 0;
			int num3 = srcLen - 12;
			while (num < num3)
			{
				uint num4 = BitConverter.ToUInt32(src, num);
				int num5 = (int)num4 * -1640531535 >>> 16;
				int num6 = table[num5] - 1;
				table[num5] = num + 1;
				if (num6 < 0 || num - num6 > 65535 || BitConverter.ToUInt32(src, num6) != num4)
				{
					num++;
					continue;
				}
				int num7 = num + 4;
				int num8 = num6 + 4;
				int num9 = srcLen - 5;
				while (num7 < num9 && src[num7] == src[num8])
				{
					num7++;
					num8++;
				}
				op = WriteSequence(src, num2, num - num2, dst, op, num - num6, num7 - num - 4);
				num = num7;
				num2 = num;
			}
			return WriteLastLiterals(src, num2, srcLen - num2, dst, op);
		}

		private static int WriteSequence(byte[] src, int litStart, int litLen, byte[] dst, int op, int offset, int matchLen)
		{
			dst[op++] = (byte)((Math.Min(litLen, 15) << 4) | Math.Min(matchLen, 15));
			op = WriteLength(dst, op, litLen);
			Buffer.BlockCopy(src, litStart, dst, op, litLen);
			op += litLen;
			dst[op++] = (byte)offset;
			dst[op++] = (byte)(offset >> 8);
			return WriteLength(dst, op, matchLen);
		}

		private static int WriteLastLiterals(byte[] src, int litStart, int litLen, byte[] dst, int op)
		{
			dst[op++] = (byte)(Math.Min(litLen, 15) << 4);
			op = WriteLength(dst, op, litLen);
			Buffer.BlockCopy(src, litStart, dst, op, litLen);
			return op + litLen;
		}

		private static int WriteLength(byte[] dst, int op, int len)
		{
			if (len < 15)
			{
				return op;
			}
			for (len -= 15; len >= 255; len -= 255)
			{
				dst[op++] = byte.MaxValue;
			}
			dst[op++] = (byte)len;
			return op;
		}

		internal static void Decompress(byte[] src, int srcOff, int srcLen, byte[] dst, int dstLen)
		{
			int num = srcOff;
			int num2 = srcOff + srcLen;
			int num3 = 0;
			while (num < num2)
			{
				int num4 = src[num++];
				int num5 = num4 >> 4;
				if (num5 == 15)
				{
					int num6;
					do
					{
						num6 = src[num++];
						num5 += num6;
					}
					while (num6 == 255);
				}
				Buffer.BlockCopy(src, num, dst, num3, num5);
				num += num5;
				num3 += num5;
				if (num >= num2)
				{
					break;
				}
				int num7 = src[num] | (src[num + 1] << 8);
				num += 2;
				int num8 = num4 & 0xF;
				if (num8 == 15)
				{
					int num9;
					do
					{
						num9 = src[num++];
						num8 += num9;
					}
					while (num9 == 255);
				}
				num8 += 4;
				int num10 = num3 - num7;
				if (num7 <= 0 || num10 < 0)
				{
					throw new InvalidOperationException("bad LZ4 offset");
				}
				for (int i = 0; i < num8; i++)
				{
					dst[num3++] = dst[num10 + i];
				}
			}
			if (num3 != dstLen)
			{
				throw new InvalidOperationException($"LZ4 size mismatch: {num3} != {dstLen}");
			}
		}
	}
	public static class Patcher
	{
		private const long MinFileBytes = 262144L;

		private const long GB = 1073741824L;

		private const string ManifestVersion = "2";

		private static ManualLogSource log;

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

		public static void Patch(AssemblyDefinition assembly)
		{
		}

		public static void Initialize()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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)
			log = Logger.CreateLogSource("BundleSlimmer");
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "lcmemfix.BundleSlimmer.cfg"), true);
			ConfigEntry<bool> val2 = val.Bind<bool>("General", "Enabled", true, "Convert LZMA asset bundles in BepInEx/plugins to chunked LZ4 before the game starts. Unity unpacks a whole LZMA bundle into RAM; LZ4 bundles are read from disk as needed.");
			ConfigEntry<bool> val3 = val.Bind<bool>("General", "FixAudio", true, "Also switch bundle audio clips from Decompress On Load (raw PCM held in RAM) to Compressed In Memory.");
			ConfigEntry<int> val4 = val.Bind<int>("General", "Threads", 0, "Bundles converted at the same time. 0 = half the CPU cores.");
			ConfigEntry<float> val5 = val.Bind<float>("General", "KeepFreeGB", 3f, "Skip a bundle if converting it would leave less than this much free space on the drive.");
			if (!val2.Value)
			{
				return;
			}
			try
			{
				Run((val4.Value > 0) ? val4.Value : Math.Max(1, Environment.ProcessorCount / 2), (long)(val5.Value * 1.0737418E+09f), val3.Value);
			}
			catch (Exception ex)
			{
				log.LogError((object)("Stopped: " + ex));
			}
		}

		private static void Run(int threads, long keepFree, bool fixAudio)
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			string path = Path.Combine(Paths.CachePath, "lcmemfix.BundleSlimmer.txt");
			string version = "2" + (fixAudio ? "a" : "");
			Dictionary<string, string> dictionary = LoadManifest(path, version);
			ConcurrentDictionary<string, string> finished = new ConcurrentDictionary<string, string>(dictionary);
			List<string> list = new List<string>();
			foreach (string item in Directory.EnumerateFiles(Paths.PluginPath, "*", SearchOption.AllDirectories))
			{
				if (item.EndsWith(".slimming", StringComparison.OrdinalIgnoreCase) || item.EndsWith(".slimming.raw", StringComparison.OrdinalIgnoreCase))
				{
					TryDelete(item);
					continue;
				}
				try
				{
					FileInfo fileInfo = new FileInfo(item);
					if (fileInfo.Length >= 262144)
					{
						string key = Name(item);
						if ((!dictionary.TryGetValue(key, out var value) || !(value == Stamp(fileInfo))) && Converter.LooksLikeBundle(item))
						{
							list.Add(item);
						}
					}
				}
				catch (Exception ex)
				{
					log.LogDebug((object)("Skipped " + Name(item) + ": " + ex.Message));
				}
			}
			if (list.Count == 0)
			{
				log.LogInfo((object)$"All bundles already slim ({stopwatch.ElapsedMilliseconds} ms)");
				return;
			}
			log.LogMessage((object)($"Checking {list.Count} new or changed asset bundles. Converting them makes them read from disk " + "instead of sitting unpacked in RAM. This happens once per mod version and can take a few minutes."));
			int converted = 0;
			int failed = 0;
			int clips = 0;
			long before = 0L;
			long after = 0L;
			Parallel.ForEach(list.OrderByDescending((string p) => new FileInfo(p).Length).ToList(), new ParallelOptions
			{
				MaxDegreeOfParallelism = threads
			}, delegate(string text)
			{
				long length = new FileInfo(text).Length;
				Converter.Result result = ConvertOne(text, keepFree, fixAudio);
				if (result == null)
				{
					Interlocked.Increment(ref failed);
				}
				else
				{
					finished[Name(text)] = Stamp(new FileInfo(text));
					if (result.Rewritten)
					{
						long length2 = new FileInfo(text).Length;
						Interlocked.Add(ref before, length);
						Interlocked.Add(ref after, length2);
						Interlocked.Add(ref clips, result.ClipsFlipped);
						int num = Interlocked.Increment(ref converted);
						log.LogInfo((object)($"[{num}] {Name(text)}: {length / 1048576} MB -> {length2 / 1048576} MB" + ((result.ClipsFlipped > 0) ? $", {result.ClipsFlipped} audio clips fixed" : "")));
					}
				}
			});
			SaveManifest(path, version, finished);
			log.LogMessage((object)($"Rewrote {converted} of {list.Count} bundles in {stopwatch.Elapsed.TotalSeconds:F0} s " + $"({before / 1048576} MB -> {after / 1048576} MB on disk, {clips} audio clips fixed)" + ((failed > 0) ? $", {failed} left as they were" : "")));
		}

		private static Converter.Result ConvertOne(string path, long keepFree, bool fixAudio)
		{
			string text = path + ".slimming";
			try
			{
				long uncompressedSize;
				using (FileStream s = File.OpenRead(path))
				{
					uncompressedSize = Converter.Read(s).UncompressedSize;
				}
				long availableFreeSpace = new DriveInfo(Path.GetPathRoot(Path.GetFullPath(path))).AvailableFreeSpace;
				if (availableFreeSpace - 2 * uncompressedSize < keepFree)
				{
					log.LogWarning((object)$"Skipped {Name(path)}: not enough free disk space ({availableFreeSpace / 1073741824} GB free)");
					return null;
				}
				Converter.Result result = Converter.Convert(path, text, fixAudio);
				if (!result.Rewritten)
				{
					return result;
				}
				Converter.Verify(text, result.Checksum, result.RawSize);
				File.Delete(path);
				File.Move(text, path);
				return result;
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Could not convert " + Name(path) + ", left as it was: " + ex.Message));
				TryDelete(text);
				return null;
			}
		}

		private static string Stamp(FileInfo fi)
		{
			return fi.Length + ":" + fi.LastWriteTimeUtc.Ticks;
		}

		private static Dictionary<string, string> LoadManifest(string path, string version)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				if (!File.Exists(path))
				{
					return dictionary;
				}
				string[] array = File.ReadAllLines(path);
				if (array.Length == 0 || array[0] != "v" + version)
				{
					return dictionary;
				}
				foreach (string item in array.Skip(1))
				{
					int num = item.LastIndexOf('|');
					if (num > 0)
					{
						dictionary[item.Substring(0, num)] = item.Substring(num + 1);
					}
				}
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Could not read the list of finished bundles, checking all of them: " + ex.Message));
			}
			return dictionary;
		}

		private static void SaveManifest(string path, string version, IDictionary<string, string> map)
		{
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				List<string> list = new List<string> { "v" + version };
				list.AddRange(from kv in map
					orderby kv.Key
					select kv.Key + "|" + kv.Value);
				File.WriteAllLines(path, list);
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Could not save the list of finished bundles: " + ex.Message));
			}
		}

		private static string Name(string path)
		{
			return path.Substring(Paths.PluginPath.Length).TrimStart('\\', '/');
		}

		private static void TryDelete(string path)
		{
			try
			{
				File.Delete(path);
			}
			catch
			{
			}
		}
	}
}