Decompiled source of Sound Changer v2.0.0

Patty_SoundChanger_MOD.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using ATL;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using ShinyShoe;
using ShinyShoe.Audio;
using ShinyShoe.Loading;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.U2D;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Patty_SoundChanger_MOD")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Patty_SoundChanger_MOD")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("33a86151-483d-4513-8190-9fd71a0bf018")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Patty_SoundChanger_MOD;

internal sealed class ConfigurationManagerAttributes
{
	public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);

	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public CustomHotkeyDrawerFunc CustomHotkeyDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
public interface ISoundChanger
{
	SoundData<MusicDefinition> CreateNewMusicEntry(string entryName, string description = "", string defaultVal = "");

	SoundData<SoundCueDefinition> CreateNewSFXEntry(string entryName, string description = "", string defaultVal = "");

	BattleMusicTrack RegisterToBattleMusic(SoundData<MusicDefinition> musicData, bool isBoss = false);

	void RegisterMusicEntry(SoundData<MusicDefinition> musicData);

	ConfigEntry<string> GetEntry(string entryName);

	bool IsMusicEntry(ConfigEntryBase entry);

	bool IsSFXEntry(ConfigEntryBase entry);

	bool IsValidEntry(ConfigEntryBase entry);

	SoundData<MusicDefinition> GetMusicData(string entryName);

	SoundData<MusicDefinition> GetMusicData(ConfigEntryBase entry);

	SoundData<SoundCueDefinition> GetSFXData(string entryName);

	SoundData<SoundCueDefinition> GetSFXData(ConfigEntryBase entry);

	List<BattleMusicTrack> GetBattleMusicTracks(bool isBoss = false);

	BattleMusicTrack GetBattleMusicTrack(string trackName);

	SoundManager GetSoundManager();

	CoreAudioSystem GetCoreAudioSystem();

	CoreAudioSystemData GetCoreAudioSystemData();

	MusicDefinition[] GetMusicDefinitions();

	SoundCueDefinition[] GetSFXDefinitions();

	MusicDefinition GetMusicDefinition(string trackName);

	SoundCueDefinition GetSFXDefinition(string trackName);

	void ChangeSound(string entryName, string filePath, bool replayMusic = true, Action<string> onPlay = null);

	void ChangeSound(string entryName, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null);

	void ChangeSound(ConfigEntryBase entry, string filePath, bool replayMusic = true, Action<string> onPlay = null);

	void ChangeSound(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null);

	void PlayEntry(string entryName, Action<string> onPlay = null);

	void PlayEntry(ConfigEntryBase entry, Action<string> onPlay = null);

	void PlayMusic(string entryName, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null);

	void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null);

	void PlaySFX(string entryName, bool loop = false, Action<string> onPlay = null);

	void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null);

	void LoadFileForEntry(string entryName, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null);

	void LoadFileForEntry(ConfigEntryBase entry, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null);

	void ResetEntry(string entryName);

	void ResetEntry(ConfigEntryBase entry);

	string GetCurrentlyPlayingMusicName();

	bool HasInitializedSoundManager();
}
internal class MenuPatch
{
	[HarmonyPrefix]
	[HarmonyPatch(typeof(SettingsScreen), "ApplyScreenInput")]
	public static bool SettingsScreen_ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID, ref bool __result)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)SoundDialog.Instance == (Object)null)
		{
			return true;
		}
		if (((ScreenDialog)SoundDialog.Instance).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID))
		{
			__result = true;
			return false;
		}
		return true;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(PauseDialog), "ApplyScreenInput")]
	public static void PauseDialog_ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID, ref bool __result)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (!__result && (Object)(object)SoundDialog.Instance != (Object)null)
		{
			__result = ((ScreenDialog)SoundDialog.Instance).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID);
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(SettingsScreen), "CloseDialog")]
	public static bool CloseDialog()
	{
		if ((Object)(object)SoundDialog.Instance != (Object)null && ((ScreenTransition)SoundDialog.Instance).Active)
		{
			((ScreenDialog)SoundDialog.Instance).Close();
			return false;
		}
		return true;
	}
}
internal class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection
{
	[CompilerGenerated]
	private sealed class <GetEnumerator>d__25 : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private KeyValuePair<TKey, TValue> <>2__current;

		public OrderedDictionary<TKey, TValue> <>4__this;

		private IDictionaryEnumerator <>s__1;

		private DictionaryEntry <entry>5__2;

		KeyValuePair<TKey, TValue> IEnumerator<KeyValuePair<TKey, TValue>>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>s__1 = null;
			<entry>5__2 = default(DictionaryEntry);
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>s__1 = <>4__this.privateDictionary.GetEnumerator();
					<>1__state = -3;
					break;
				case 1:
					<>1__state = -3;
					<entry>5__2 = default(DictionaryEntry);
					break;
				}
				if (<>s__1.MoveNext())
				{
					<entry>5__2 = (DictionaryEntry)<>s__1.Current;
					<>2__current = new KeyValuePair<TKey, TValue>((TKey)<entry>5__2.Key, (TValue)<entry>5__2.Value);
					<>1__state = 1;
					return true;
				}
				<>m__Finally1();
				<>s__1 = null;
				return false;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

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

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<>s__1 is IDisposable disposable)
			{
				disposable.Dispose();
			}
		}

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

	private readonly Hashtable privateHashtable;

	private readonly OrderedDictionary privateDictionary;

	public int Count => privateDictionary.Count;

	public bool IsReadOnly => false;

	public TValue this[int index]
	{
		get
		{
			if (index < 0 || index >= Count)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return (TValue)privateDictionary[index];
		}
		set
		{
			if (index < 0 || index >= Count)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			privateDictionary[index] = value;
		}
	}

	public TValue this[TKey key]
	{
		get
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (privateDictionary.Contains(key))
			{
				return (TValue)privateDictionary[key];
			}
			throw new KeyNotFoundException("key not found in dictionary");
		}
		set
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			privateDictionary[key] = value;
		}
	}

	public ICollection<TKey> Keys
	{
		get
		{
			List<TKey> list = new List<TKey>(privateDictionary.Count);
			foreach (TKey key in privateDictionary.Keys)
			{
				list.Add(key);
			}
			return list;
		}
	}

	public ICollection<TValue> Values
	{
		get
		{
			List<TValue> list = new List<TValue>(privateDictionary.Count);
			foreach (TValue value in privateDictionary.Values)
			{
				list.Add(value);
			}
			return list;
		}
	}

	bool IDictionary.IsFixedSize => ((IDictionary)privateDictionary).IsFixedSize;

	bool IDictionary.IsReadOnly => privateDictionary.IsReadOnly;

	ICollection IDictionary.Keys => privateDictionary.Keys;

	ICollection IDictionary.Values => privateDictionary.Values;

	object IDictionary.this[object key]
	{
		get
		{
			return privateDictionary[key];
		}
		set
		{
			privateDictionary[key] = value;
		}
	}

	int ICollection.Count => privateDictionary.Count;

	bool ICollection.IsSynchronized => ((ICollection)privateDictionary).IsSynchronized;

	object ICollection.SyncRoot => ((ICollection)privateDictionary).SyncRoot;

	public OrderedDictionary()
	{
		privateDictionary = new OrderedDictionary();
		privateHashtable = (Hashtable)AccessTools.DeclaredProperty(typeof(OrderedDictionary), "objectsTable").GetValue(privateDictionary);
	}

	public OrderedDictionary(IDictionary<TKey, TValue> dictionary)
	{
		if (dictionary == null)
		{
			return;
		}
		foreach (KeyValuePair<TKey, TValue> item in dictionary)
		{
			privateDictionary.Add(item.Key, item.Value);
		}
	}

	public void Add(KeyValuePair<TKey, TValue> item)
	{
		Add(item.Key, item.Value);
	}

	public void Add(TKey key, TValue value)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		privateDictionary.Add(key, value);
	}

	public void Clear()
	{
		privateDictionary.Clear();
	}

	public bool Contains(KeyValuePair<TKey, TValue> item)
	{
		if (item.Key == null || !privateDictionary.Contains(item.Key))
		{
			return false;
		}
		return privateDictionary[item.Key].Equals(item.Value);
	}

	public bool ContainsKey(TKey key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		return privateDictionary.Contains(key);
	}

	public bool ContainsValue(TValue value)
	{
		if (value == null)
		{
			throw new ArgumentNullException("value");
		}
		return privateHashtable.ContainsValue(value);
	}

	public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
	{
		if (array == null)
		{
			throw new ArgumentNullException("array");
		}
		if (arrayIndex < 0)
		{
			throw new ArgumentOutOfRangeException("arrayIndex");
		}
		if (array.Rank > 1 || arrayIndex >= array.Length || array.Length - arrayIndex < privateDictionary.Count)
		{
			throw new ArgumentOutOfRangeException("array");
		}
		int num = arrayIndex;
		foreach (DictionaryEntry item in privateDictionary)
		{
			array[num] = new KeyValuePair<TKey, TValue>((TKey)item.Key, (TValue)item.Value);
			num++;
		}
	}

	[IteratorStateMachine(typeof(OrderedDictionary<, >.<GetEnumerator>d__25))]
	public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <GetEnumerator>d__25(0)
		{
			<>4__this = this
		};
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return GetEnumerator();
	}

	public bool Remove(KeyValuePair<TKey, TValue> item)
	{
		if (Contains(item))
		{
			privateDictionary.Remove(item.Key);
			return true;
		}
		return false;
	}

	public bool Remove(TKey key)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		if (privateDictionary.Contains(key))
		{
			privateDictionary.Remove(key);
			return true;
		}
		return false;
	}

	public bool TryGetValue(TKey key, out TValue value)
	{
		if (key == null)
		{
			throw new ArgumentNullException("key");
		}
		bool flag = privateDictionary.Contains(key);
		value = (flag ? ((TValue)privateDictionary[key]) : default(TValue));
		return flag;
	}

	void IDictionary.Add(object key, object value)
	{
		privateDictionary.Add(key, value);
	}

	void IDictionary.Clear()
	{
		privateDictionary.Clear();
	}

	bool IDictionary.Contains(object key)
	{
		return privateDictionary.Contains(key);
	}

	IDictionaryEnumerator IDictionary.GetEnumerator()
	{
		return privateDictionary.GetEnumerator();
	}

	void IDictionary.Remove(object key)
	{
		privateDictionary.Remove(key);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		privateDictionary.CopyTo(array, index);
	}
}
public sealed class SoundChangerManager : ISoundChanger
{
	public SoundData<MusicDefinition> CreateNewMusicEntry(string entryName, string description = "", string defaultVal = "")
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Expected O, but got Unknown
		//IL_00b7: Expected O, but got Unknown
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.MusicEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase musicEntry) => musicEntry.Definition.Key == entryName));
		if (val != null)
		{
			Plugin.LogSource.LogError((object)("Cannot create new music entry, Already have music with same entry name " + entryName));
			return null;
		}
		ConfigEntry<string> val2 = Plugin.Config.Bind<string>(new ConfigDefinition("Basic", entryName), defaultVal, new ConfigDescription(description, (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				HideDefaultButton = true,
				HideSettingName = true,
				CustomDrawer = Plugin.MusicDrawer
			}
		}));
		val2.SettingChanged += Plugin.Entry_SettingChanged;
		Plugin.MusicEntries[(ConfigEntryBase)(object)val2] = SoundData<MusicDefinition>.Create(val2, new MusicDefinition());
		return Plugin.MusicEntries[(ConfigEntryBase)(object)val2];
	}

	public SoundData<SoundCueDefinition> CreateNewSFXEntry(string entryName, string description = "", string defaultVal = "")
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Expected O, but got Unknown
		//IL_00b7: Expected O, but got Unknown
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.SFXEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase sfxEntry) => sfxEntry.Definition.Key == entryName));
		if (val != null)
		{
			Plugin.LogSource.LogError((object)("Cannot create new sfx entry, Already have SFX with same entry name " + entryName));
			return null;
		}
		ConfigEntry<string> val2 = Plugin.Config.Bind<string>(new ConfigDefinition("Basic", entryName), defaultVal, new ConfigDescription(description, (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				HideDefaultButton = true,
				HideSettingName = true,
				CustomDrawer = Plugin.MusicDrawer
			}
		}));
		val2.SettingChanged += Plugin.Entry_SettingChanged;
		Plugin.SFXEntries[(ConfigEntryBase)(object)val2] = SoundData<SoundCueDefinition>.Create(val2, new SoundCueDefinition());
		return Plugin.SFXEntries[(ConfigEntryBase)(object)val2];
	}

	public BattleMusicTrack RegisterToBattleMusic(SoundData<MusicDefinition> musicData, bool isBoss = false)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		if (musicData == null)
		{
			Plugin.LogSource.LogError((object)"Cannot register to battle music, data is null");
			return default(BattleMusicTrack);
		}
		if (!HasInitializedSoundManager())
		{
			return default(BattleMusicTrack);
		}
		SoundManager soundManager = GetSoundManager();
		List<BattleMusicTrack> battleMusicTracks = GetBattleMusicTracks(isBoss);
		if (battleMusicTracks.Exists((BattleMusicTrack track) => track.trackNameData == musicData.definition.Name))
		{
			Plugin.LogSource.LogWarning((object)("Already registered battle music track with entry name " + musicData.definition.Name));
			Plugin.LogSource.LogWarning((object)"Removing the duplicated entry...");
			battleMusicTracks.RemoveAll((BattleMusicTrack track) => track.trackNameData == musicData.entryName);
		}
		BattleMusicTrack val = default(BattleMusicTrack);
		val.publicTrackNameKey = musicData.GetTitle();
		val.trackNameData = musicData.definition.Name;
		BattleMusicTrack val2 = val;
		battleMusicTracks.Add(val2);
		RegisterMusicEntry(musicData);
		return val2;
	}

	public void RegisterMusicEntry(SoundData<MusicDefinition> musicData)
	{
		if (musicData == null)
		{
			Plugin.LogSource.LogError((object)"Cannot register music, data is null");
		}
		else
		{
			if (!HasInitializedSoundManager())
			{
				return;
			}
			SoundManager soundManager = GetSoundManager();
			CoreAudioSystem coreAudioSystem = GetCoreAudioSystem();
			CoreAudioSystemData coreAudioSystemData = GetCoreAudioSystemData();
			if (coreAudioSystemData.MusicDefData.Tracks.Any((MusicDefinition definition) => definition.Name == musicData.definition.Name))
			{
				Plugin.LogSource.LogWarning((object)("Already registered music track with entry name " + musicData.definition.Name));
				Plugin.LogSource.LogWarning((object)"Removing the duplicated entry...");
				List<MusicDefinition> list = coreAudioSystemData.MusicDefData.Tracks.ToList();
				list.RemoveAll((MusicDefinition definition) => definition.Name == musicData.definition.Name);
				coreAudioSystemData.MusicDefData.Tracks = list.ToArray();
			}
			coreAudioSystemData.MusicDefData.Tracks = CollectionExtensions.AddToArray<MusicDefinition>(coreAudioSystemData.MusicDefData.Tracks, musicData.definition);
		}
	}

	public ConfigEntry<string> GetEntry(string entryName)
	{
		ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.MusicEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase entry) => entry.Definition.Key == entryName));
		if (val == null)
		{
			val = ((IEnumerable<ConfigEntryBase>)Plugin.SFXEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase entry) => entry.Definition.Key == entryName));
		}
		if (val == null)
		{
			Plugin.LogSource.LogError((object)("Cannot find entry named " + entryName));
		}
		return val as ConfigEntry<string>;
	}

	public bool IsMusicEntry(ConfigEntryBase entry)
	{
		return Plugin.MusicEntries.ContainsKey(entry);
	}

	public bool IsSFXEntry(ConfigEntryBase entry)
	{
		return Plugin.SFXEntries.ContainsKey(entry);
	}

	public bool IsValidEntry(ConfigEntryBase entry)
	{
		bool flag = entry != null && (IsMusicEntry(entry) || IsSFXEntry(entry));
		if (!flag)
		{
			ManualLogSource logSource = Plugin.LogSource;
			object obj;
			if (entry == null)
			{
				obj = null;
			}
			else
			{
				ConfigDefinition definition = entry.Definition;
				obj = ((definition != null) ? definition.Key : null);
			}
			logSource.LogError((object)((string?)obj + " is not a valid entry"));
		}
		return flag;
	}

	public SoundData<MusicDefinition> GetMusicData(string entryName)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		return GetMusicData((ConfigEntryBase)(object)entry);
	}

	public SoundData<MusicDefinition> GetMusicData(ConfigEntryBase entry)
	{
		if (!IsValidEntry(entry))
		{
			return null;
		}
		if (!IsMusicEntry(entry))
		{
			Plugin.LogSource.LogError((object)"Entry is valid but is not a music entry");
			return null;
		}
		return Plugin.MusicEntries[entry];
	}

	public SoundData<SoundCueDefinition> GetSFXData(string entryName)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		return GetSFXData((ConfigEntryBase)(object)entry);
	}

	public SoundData<SoundCueDefinition> GetSFXData(ConfigEntryBase entry)
	{
		if (!IsValidEntry(entry))
		{
			return null;
		}
		if (!IsSFXEntry(entry))
		{
			Plugin.LogSource.LogError((object)"Entry is valid but is not an SFX entry");
			return null;
		}
		return Plugin.SFXEntries[entry];
	}

	public void ChangeSound(string entryName, string filePath, bool replayMusic = true, Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		ChangeSound((ConfigEntryBase)(object)entry, filePath, replayMusic, onPlay);
	}

	public void ChangeSound(string entryName, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		ChangeSound((ConfigEntryBase)(object)entry, audioClip, replayMusic, onPlay);
	}

	public void ChangeSound(ConfigEntryBase entry, string filePath, bool replayMusic = true, Action<string> onPlay = null)
	{
		if (!IsValidEntry(entry))
		{
			return;
		}
		if (!File.Exists(filePath))
		{
			Plugin.LogSource.LogError((object)("Cannot load " + filePath + " because its not valid path"));
			return;
		}
		entry.BoxedValue = filePath;
		((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.LoadAudioClip(filePath, delegate(AudioClip audioClip)
		{
			Plugin.OnAudioClipLoaded(entry, audioClip, replayMusic, onPlay);
		}));
	}

	public void ChangeSound(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null)
	{
		if (IsValidEntry(entry))
		{
			if ((Object)(object)audioClip == (Object)null)
			{
				Plugin.LogSource.LogError((object)("AudioClip is null, Cannot assign to entry " + entry.Definition.Key + " because t"));
				return;
			}
			entry.BoxedValue = ((Object)audioClip).name;
			Plugin.OnAudioClipLoaded(entry, audioClip, replayMusic, onPlay);
		}
	}

	public void PlayEntry(string entryName, Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		PlayEntry((ConfigEntryBase)(object)entry, onPlay);
	}

	public void PlayEntry(ConfigEntryBase entry, Action<string> onPlay = null)
	{
		if (IsValidEntry(entry))
		{
			if (IsMusicEntry(entry))
			{
				Plugin.PlayMusic(entry, isBattleMusic: false, 0.25f, "", onPlay);
			}
			else if (IsSFXEntry(entry))
			{
				Plugin.PlaySFX(entry, loop: false, onPlay);
			}
		}
	}

	public void PlayMusic(string entryName, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		PlayMusic((ConfigEntryBase)(object)entry, isBattleMusic, crossfadeTimeSeconds, displayedName, onPlay);
	}

	public void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null)
	{
		if (IsValidEntry(entry) && IsMusicEntry(entry))
		{
			Plugin.PlayMusic(entry, isBattleMusic, crossfadeTimeSeconds, displayedName, onPlay);
		}
	}

	public void PlaySFX(string entryName, bool loop = false, Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		PlaySFX((ConfigEntryBase)(object)entry, loop, onPlay);
	}

	public void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null)
	{
		if (IsValidEntry(entry) && IsSFXEntry(entry))
		{
			Plugin.PlaySFX(entry, loop, onPlay);
		}
	}

	public void LoadFileForEntry(string entryName, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		LoadFileForEntry((ConfigEntryBase)(object)entry, onLoad, onPlay);
	}

	public void LoadFileForEntry(ConfigEntryBase entry, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null)
	{
		if (IsValidEntry(entry))
		{
			Plugin.LoadFile(entry, "", existFile: false, onLoad, onPlay);
		}
	}

	public void ResetEntry(string entryName)
	{
		ConfigEntry<string> entry = GetEntry(entryName);
		ResetEntry((ConfigEntryBase)(object)entry);
	}

	public void ResetEntry(ConfigEntryBase entry)
	{
		if (IsValidEntry(entry))
		{
			entry.BoxedValue = "";
			Plugin.ResetEntryBase(entry);
		}
	}

	public string GetCurrentlyPlayingMusicName()
	{
		if (!HasInitializedSoundManager())
		{
			return "";
		}
		SoundManager soundManager = AllGameManagers.Instance.GetSoundManager();
		string result = soundManager.GetCurrentMusicTrackName();
		if (!string.IsNullOrWhiteSpace(soundManager.currentTrackName))
		{
			result = soundManager.currentTrackName;
		}
		return result;
	}

	public bool HasInitializedSoundManager()
	{
		AllGameManagers instance = AllGameManagers.Instance;
		if ((Object)(object)instance != (Object)null && (Object)(object)instance.GetSoundManager() != (Object)null)
		{
			return true;
		}
		Plugin.LogSource.LogError((object)"SoundManager isn't initialized yet, try waiting a bit more before registering");
		return false;
	}

	public List<BattleMusicTrack> GetBattleMusicTracks(bool isBoss)
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		SoundManager soundManager = AllGameManagers.Instance.GetSoundManager();
		return (!isBoss) ? Traverse.Create((object)soundManager).Field<List<BattleMusicTrack>>("battleMusicTracks").Value : Traverse.Create((object)soundManager).Field<List<BattleMusicTrack>>("bossBattleMusicTracks").Value;
	}

	public BattleMusicTrack GetBattleMusicTrack(string trackName)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		BattleMusicTrack result = default(BattleMusicTrack);
		if (!HasInitializedSoundManager())
		{
			return result;
		}
		List<BattleMusicTrack> battleMusicTracks = GetBattleMusicTracks(isBoss: false);
		result = battleMusicTracks.Find((BattleMusicTrack track) => track.trackNameData == trackName);
		if (string.IsNullOrWhiteSpace(result.trackNameData))
		{
			battleMusicTracks = GetBattleMusicTracks(isBoss: false);
			result = battleMusicTracks.Find((BattleMusicTrack track) => track.trackNameData == trackName);
		}
		return result;
	}

	public SoundManager GetSoundManager()
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		return AllGameManagers.Instance.GetSoundManager();
	}

	public CoreAudioSystem GetCoreAudioSystem()
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		SoundManager soundManager = AllGameManagers.Instance.GetSoundManager();
		return Traverse.Create((object)soundManager).Field<CoreAudioSystem>("audioSystem").Value;
	}

	public CoreAudioSystemData GetCoreAudioSystemData()
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		SoundManager soundManager = AllGameManagers.Instance.GetSoundManager();
		CoreAudioSystem value = Traverse.Create((object)soundManager).Field<CoreAudioSystem>("audioSystem").Value;
		return Traverse.Create((object)value).Field("AudioSystemData").GetValue<CoreAudioSystemData>();
	}

	public MusicDefinition[] GetMusicDefinitions()
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		return GetCoreAudioSystemData().MusicDefData.Tracks;
	}

	public SoundCueDefinition[] GetSFXDefinitions()
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		return GetCoreAudioSystemData().GlobalSoundEffectData.Sounds;
	}

	public MusicDefinition GetMusicDefinition(string trackName)
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		return GetMusicDefinitions().First((MusicDefinition definition) => definition.Name == trackName);
	}

	public SoundCueDefinition GetSFXDefinition(string trackName)
	{
		if (!HasInitializedSoundManager())
		{
			return null;
		}
		return GetSFXDefinitions().First((SoundCueDefinition definition) => definition.Name == trackName);
	}
}
public enum SoundType
{
	Unknown,
	Music,
	SFX
}
public class SoundData<T> : IDisposable
{
	internal static readonly Lazy<Track> emptyTrack = new Lazy<Track>((Func<Track>)(() => new Track()));

	private AudioClip _audioData;

	public readonly SoundType type;

	public readonly ConfigEntry<string> entry;

	public readonly T definition;

	public readonly string entryName;

	public Track TrackData { get; private set; }

	public AudioClip AudioData
	{
		get
		{
			return _audioData;
		}
		set
		{
			_audioData = value;
			if (type == SoundType.Music)
			{
				SoundData<MusicDefinition> soundData = AsMusic();
				for (int i = 0; i < soundData.definition.Clips.Length; i++)
				{
					soundData.definition.Clips[i].Clip = _audioData;
				}
			}
			else if (type == SoundType.SFX)
			{
				SoundData<SoundCueDefinition> soundData2 = AsSFX();
				for (int j = 0; j < soundData2.definition.Clips.Length; j++)
				{
					soundData2.definition.Clips[j] = _audioData;
				}
			}
		}
	}

	public Sprite CoverSprite { get; set; }

	~SoundData()
	{
		Dispose();
	}

	public void Dispose()
	{
		entry.SettingChanged -= Entry_SettingChanged;
	}

	private SoundData(T definition, ConfigEntry<string> entry)
	{
		this.definition = definition;
		this.entry = entry;
		entryName = ((ConfigEntryBase)entry).Definition.Key;
		TrackData = emptyTrack.Value;
		if (typeof(MusicDefinition).IsAssignableFrom(typeof(T)))
		{
			type = SoundType.Music;
		}
		else if (typeof(SoundCueDefinition).IsAssignableFrom(typeof(T)))
		{
			type = SoundType.SFX;
		}
		CreateTrackInfo();
		this.entry.SettingChanged += Entry_SettingChanged;
	}

	public static SoundData<T> Create(ConfigEntry<string> entry, T definition)
	{
		if (!IsValidType())
		{
			return null;
		}
		if (entry == null)
		{
			Plugin.LogSource.LogError((object)"Cannot create SoundData with null entry");
			return null;
		}
		if (definition == null)
		{
			Plugin.LogSource.LogError((object)"Cannot create SoundData with null definition");
			return null;
		}
		return new SoundData<T>(definition, entry);
	}

	public static bool IsValidType()
	{
		if (typeof(MusicDefinition).IsAssignableFrom(typeof(T)) || typeof(SoundCueDefinition).IsAssignableFrom(typeof(T)))
		{
			return true;
		}
		Plugin.LogSource.LogError((object)"T must be of type CoreMusicData.MusicDefinition or CoreSoundEffectData.SoundCueDefinition");
		return false;
	}

	private void CreateTrackInfo()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Expected O, but got Unknown
		if (IsFileExist())
		{
			TrackData = new Track(GetFilePath(), (IProgress<float>)null, true);
			if (IEnumerableUtility.IsNullOrEmpty<PictureInfo>((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures))
			{
				return;
			}
			PictureInfo val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null && (int)picture.PicType == 2));
			if (val == null)
			{
				val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null && (int)picture.PicType == 18));
			}
			if (val == null)
			{
				val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null));
			}
			if (val != null)
			{
				AssignCover(val.PictureData);
			}
		}
		else
		{
			TrackData = emptyTrack.Value;
		}
	}

	private void Entry_SettingChanged(object sender, EventArgs e)
	{
		CreateTrackInfo();
	}

	public SoundData<MusicDefinition> AsMusic()
	{
		return this as SoundData<MusicDefinition>;
	}

	public SoundData<SoundCueDefinition> AsSFX()
	{
		return this as SoundData<SoundCueDefinition>;
	}

	public bool AssignDefinitionToData(T definition)
	{
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Expected O, but got Unknown
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Expected O, but got Unknown
		if (!IsValidType())
		{
			return false;
		}
		if (definition == null)
		{
			Plugin.LogSource.LogError((object)"Cannot assign data to null definition");
			return false;
		}
		if (type == SoundType.Music)
		{
			SoundData<MusicDefinition> soundData = AsMusic();
			object obj = definition;
			MusicDefinition val = (MusicDefinition)((obj is MusicDefinition) ? obj : null);
			if (soundData == null)
			{
				Plugin.LogSource.LogError((object)"The instance isn't SoundData<MusicDefinition> somehow despite the type is a music");
				return false;
			}
			if (val == null)
			{
				Plugin.LogSource.LogError((object)"The target instance isn't MusicDefinition somehow despite the type is a music");
				return false;
			}
			if (soundData.definition == null)
			{
				Plugin.LogSource.LogError((object)"Definition is null");
				return false;
			}
			soundData.definition.Mixer = val.Mixer;
			if (!IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)val.Clips))
			{
				soundData.definition.Clips = (MusicClipDefinition[])(object)new MusicClipDefinition[val.Clips.Length];
				for (int i = 0; i < val.Clips.Length; i++)
				{
					soundData.definition.Clips[i] = new MusicClipDefinition
					{
						MixerGroup = val.Clips[i]?.MixerGroup,
						Clip = val.Clips[i]?.Clip
					};
				}
			}
			else
			{
				soundData.definition.Clips = (MusicClipDefinition[])(object)new MusicClipDefinition[1];
			}
			if (!IEnumerableUtility.IsNullOrEmpty<MusicSnapshotDefinition>((IEnumerable<MusicSnapshotDefinition>)val.Snapshots))
			{
				soundData.definition.Snapshots = (MusicSnapshotDefinition[])(object)new MusicSnapshotDefinition[val.Snapshots.Length];
				for (int j = 0; j < val.Clips.Length; j++)
				{
					soundData.definition.Snapshots[j] = new MusicSnapshotDefinition
					{
						Name = val.Snapshots[j]?.Name,
						Snapshot = val.Snapshots[j]?.Snapshot,
						TransitionTimeSeconds = (val.Snapshots[j]?.TransitionTimeSeconds).Value
					};
				}
			}
			else
			{
				soundData.definition.Snapshots = (MusicSnapshotDefinition[])(object)new MusicSnapshotDefinition[1];
			}
			soundData.definition.Name = ((ConfigEntryBase)entry).Definition.Key;
		}
		else if (type == SoundType.SFX)
		{
			SoundData<SoundCueDefinition> soundData2 = AsSFX();
			object obj2 = definition;
			SoundCueDefinition val2 = (SoundCueDefinition)((obj2 is SoundCueDefinition) ? obj2 : null);
			if (soundData2 == null)
			{
				Plugin.LogSource.LogError((object)"The instance isn't SoundData<SoundCueDefinition> somehow despite the type is an SFX");
				return false;
			}
			if (val2 == null)
			{
				Plugin.LogSource.LogError((object)"The target instance isn't SoundCueDefinition somehow despite the type is an SFX");
				return false;
			}
			if (soundData2.definition == null)
			{
				Plugin.LogSource.LogError((object)"Definition is null");
				return false;
			}
			if (!IEnumerableUtility.IsNullOrEmpty<AudioClip>((IEnumerable<AudioClip>)val2.Clips))
			{
				soundData2.definition.Clips = (AudioClip[])(object)new AudioClip[val2.Clips.Length];
				for (int k = 0; k < val2.Clips.Length; k++)
				{
					soundData2.definition.Clips[k] = val2.Clips[k];
				}
			}
			else
			{
				soundData2.definition.Clips = (AudioClip[])(object)new AudioClip[1];
			}
			soundData2.definition.VolumeMin = val2.VolumeMin;
			soundData2.definition.VolumeMax = val2.VolumeMax;
			soundData2.definition.PitchMin = val2.PitchMin;
			soundData2.definition.PitchMax = val2.PitchMax;
			soundData2.definition.Loop = val2.Loop;
			if (!IEnumerableUtility.IsNullOrEmpty<string>((IEnumerable<string>)val2.Tags))
			{
				soundData2.definition.Tags = new string[val2.Tags.Length];
				for (int l = 0; l < val2.Tags.Length; l++)
				{
					soundData2.definition.Tags[l] = val2.Tags[l];
				}
			}
			else
			{
				soundData2.definition.Tags = new string[1];
			}
			soundData2.definition.Name = ((ConfigEntryBase)entry).Definition.Key;
		}
		return true;
	}

	public void AssignCover(string filePath)
	{
		if (!File.Exists(filePath))
		{
			Plugin.LogSource.LogError((object)("Cannot create cover for entry " + entryName + " on non-existent file"));
		}
		else
		{
			AssignCover(File.ReadAllBytes(filePath));
		}
	}

	public void AssignCover(byte[] data)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Expected O, but got Unknown
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(0, 0);
		if (ImageConversion.LoadImage(val, data))
		{
			CoverSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero, 100f, 0u, (SpriteMeshType)1);
		}
		else
		{
			Plugin.LogSource.LogError((object)("Failed creating cover image for entry " + entryName));
		}
	}

	public string GetTitle()
	{
		string result = "";
		if (!IsEmptyTrackData() && !string.IsNullOrWhiteSpace(TrackData.Title))
		{
			result = TrackData.Title;
		}
		else if (File.Exists(entry.Value))
		{
			result = Path.GetFileNameWithoutExtension(entry.Value);
		}
		else if ((Object)(object)AudioData != (Object)null)
		{
			result = Plugin.RemoveGUIDFromName(AudioData);
		}
		return result;
	}

	public string GetFilePath()
	{
		string text = entry.Value;
		if (!File.Exists(text))
		{
			if (Path.IsPathRooted(text))
			{
				Plugin.LogSource.LogError((object)("The path must not be rooted if you want to make it relative to the mod path " + text));
			}
			text = Path.Combine(Plugin.BasePath, text);
		}
		return text;
	}

	public string GetExtension()
	{
		return Path.GetExtension(entry.Value);
	}

	public bool IsFileExist()
	{
		return File.Exists(GetFilePath());
	}

	public bool IsEmptyTrackData()
	{
		return TrackData == emptyTrack.Value;
	}

	public int Duration()
	{
		int result = 0;
		if ((Object)(object)AudioData != (Object)null)
		{
			result = Mathf.RoundToInt(AudioData.length);
		}
		else if (!IsEmptyTrackData())
		{
			result = TrackData.Duration;
		}
		return result;
	}
}
public class SoundDialog : ScreenDialog
{
	internal Dictionary<string, ScrollRect> scrollRectsSection = new Dictionary<string, ScrollRect>();

	internal Dictionary<string, SettingsTab> tabsSection = new Dictionary<string, SettingsTab>();

	internal List<SoundInfo> soundList = new List<SoundInfo>();

	internal GameUISelectableButton soundChangerButton;

	internal TextMeshProUGUI headerTitle;

	internal TMP_Text musicLabel;

	internal LayoutElement ContentLayout;

	public static SoundDialog Instance { get; private set; }

	public static SettingsScreen SettingsScreen { get; } = (SettingsScreen)AllGameManagers.Instance.GetScreenManager().GetScreen((ScreenName)18);


	public static PauseDialog PauseDialog { get; private set; }

	private void Start()
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		((Object)this).name = "Sound Dialog";
		PauseDialog = Traverse.Create((object)SettingsScreen).Field<PauseDialog>("pauseDialog").Value;
		headerTitle = ((Component)((Component)this).transform.Find("Header/Title")).GetComponent<TextMeshProUGUI>();
		((TMP_Text)headerTitle).enableAutoSizing = true;
		((TMP_Text)headerTitle).overflowMode = (TextOverflowModes)1;
		((TMP_Text)headerTitle).fontSizeMin = 20f;
		((TMP_Text)headerTitle).rectTransform.sizeDelta = new Vector2(-100f, 64f);
		musicLabel = Traverse.Create((object)PauseDialog).Field<TMP_Text>("musicLabel").Value;
		musicLabel.overflowMode = (TextOverflowModes)1;
		ContentLayout = new GameObject("Content Layout").AddComponent<LayoutElement>();
		ContentLayout.preferredHeight = 818f;
		((Component)ContentLayout).transform.SetParent(((Component)this).transform.Find("Content"), false);
		InitializeTabs();
		CreateSection("Music", tabsSection["Music"], Plugin.MusicEntries.Keys.ToList());
		CreateSection("SFX", tabsSection["SFX"], Plugin.SFXEntries.Keys.ToList());
		Traverse val = Traverse.Create((object)this);
		base._canvasGroup = ((Component)this).GetComponent<CanvasGroup>();
		val.Field("_timelineTransition").SetValue((object)((Component)this).GetComponent<TimelineTransition>());
		base._closeButton = ((Component)((Component)this).transform.Find("Bg container/CloseButton")).GetComponent<GameUISelectableButton>();
		Traverse.Create((object)PauseDialog).Field<GameObject>("musicLabelRoot").Value.SetActive(true);
		Plugin.musicChanged.AddListener((Action<string>)UpdateCurrentMusicName);
		SetSection(Plugin.currentSectionEntry.Value, updateEntry: false);
		Plugin.currentSectionEntry.SettingChanged += CurrentSectionEntry_SettingChanged;
		Instance.UpdateCurrentMusicName(AllGameManagers.Instance.GetSoundManager().currentTrackName);
	}

	private void CurrentSectionEntry_SettingChanged(object sender, EventArgs e)
	{
		SetSection(Plugin.currentSectionEntry.Value, updateEntry: false);
	}

	private void CreateSoundChangerButton(PauseDialog pauseDialog)
	{
		GameUISelectableButton value = Traverse.Create((object)pauseDialog).Field<GameUISelectableButton>("settingsButton").Value;
		soundChangerButton = Object.Instantiate<GameUISelectableButton>(value, ((Component)value).transform.parent);
		((Object)soundChangerButton).name = "Sound Changer button";
		((Component)soundChangerButton).transform.SetSiblingIndex(1);
		TMP_Text componentInChildren = ((Component)soundChangerButton).GetComponentInChildren<TMP_Text>(true);
		Object.DestroyImmediate((Object)(object)((Component)componentInChildren).GetComponent<Localize>());
		componentInChildren.text = "Sound Changer";
	}

	private void OnDestroy()
	{
		Plugin.musicChanged.RemoveListener((Action<string>)UpdateCurrentMusicName);
		Plugin.currentSectionEntry.SettingChanged -= CurrentSectionEntry_SettingChanged;
	}

	internal void UpdateCurrentMusicName(string trackName)
	{
		TextMeshProHelper.SetTextSafe(musicLabel, trackName, true);
		((TMP_Text)headerTitle).text = "Currently Playing: <color=yellow>" + trackName + "</color>";
	}

	internal void SetSection(string sectionName, bool updateEntry)
	{
		if (!scrollRectsSection.ContainsKey(sectionName))
		{
			Plugin.LogSource.LogError((object)("Section named " + sectionName + " doesn't exist"));
			return;
		}
		if (updateEntry)
		{
			Plugin.SetBrowsableSection(sectionName, Plugin.currentSectionEntry.Value != sectionName);
			Plugin.currentSectionEntry.Value = sectionName;
		}
		foreach (KeyValuePair<string, SettingsTab> item in tabsSection)
		{
			item.Value.SetActivated(item.Key == sectionName);
		}
	}

	private void InitializeTabs()
	{
		Object.Destroy((Object)(object)((Component)((Component)this).transform.Find("Content/Content")).gameObject);
		Object.Destroy((Object)(object)((Component)headerTitle).GetComponent<Localize>());
		Transform val = ((Component)this).transform.Find("Content/Tabs");
		for (int i = 2; i < val.childCount - 1; i++)
		{
			Object.Destroy((Object)(object)((Component)val.GetChild(i)).gameObject);
		}
		tabsSection["Music"] = ((Component)val.GetChild(0)).GetComponent<SettingsTab>();
		tabsSection["SFX"] = ((Component)val.GetChild(1)).GetComponent<SettingsTab>();
	}

	private void CreateSection(string sectionName, SettingsTab settingsTab, List<ConfigEntryBase> entries)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = new GameObject(sectionName + " Section").AddComponent<RectTransform>();
		((Component)val).gameObject.layer = LayerMask.NameToLayer("UI");
		((Component)val).transform.SetParent(((Component)ContentLayout).transform, false);
		val.anchoredPosition = new Vector2(0f, 30f);
		scrollRectsSection[sectionName] = CreateScrollRect((Transform)(object)val);
		Traverse.Create((object)settingsTab).Field("sectionRoot").SetValue((object)((Component)val).gameObject);
		TextMeshProUGUI componentInChildren = ((Component)settingsTab).GetComponentInChildren<TextMeshProUGUI>(true);
		Object.DestroyImmediate((Object)(object)((Component)componentInChildren).GetComponent<Localize>());
		((TMP_Text)componentInChildren).text = sectionName;
		for (int i = 0; i < entries.Count; i++)
		{
			ConfigEntryBase entry = entries[i];
			soundList.Add(CreateItem(entry, scrollRectsSection[sectionName], i % 2 == 1));
		}
		CreateEmptyItem(scrollRectsSection[sectionName]);
	}

	private ScrollRect CreateScrollRect(Transform parent)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Expected O, but got Unknown
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		ScrollRect val = new GameObject("ScrollRect").AddComponent<ScrollRect>();
		((Component)val).transform.localPosition = new Vector3(0f, -20f);
		((Component)val).transform.SetParent(parent, false);
		((Component)val).gameObject.layer = LayerMask.NameToLayer("UI");
		GameObject val2 = new GameObject("Viewport", new Type[3]
		{
			typeof(RectTransform),
			typeof(Image),
			typeof(Mask)
		});
		val2.transform.SetParent(((Component)val).transform, false);
		val.viewport = val2.GetComponent<RectTransform>();
		val.viewport.anchoredPosition = new Vector2(0f, 340f);
		val.viewport.pivot = new Vector2(0.5f, 1f);
		val.viewport.sizeDelta = new Vector2(1000f, 720f);
		val2.GetComponent<Mask>().showMaskGraphic = false;
		Transform val3 = ((Component)this).transform.Find("Bg container/Image bg banner");
		val2.GetComponent<Image>().sprite = ((Component)val3).GetComponent<Image>().sprite;
		val2.GetComponent<Image>().type = (Type)1;
		AspectRatioFitter component = ((Component)val3).GetComponent<AspectRatioFitter>();
		AspectRatioFitter val4 = val2.AddComponent<AspectRatioFitter>();
		val4.aspectRatio = component.aspectRatio;
		val4.aspectMode = component.aspectMode;
		GameObject val5 = new GameObject("Content", new Type[3]
		{
			typeof(RectTransform),
			typeof(GridLayoutGroup),
			typeof(ContentSizeFitter)
		});
		val5.transform.SetParent(val2.transform, false);
		RectTransform component2 = val5.GetComponent<RectTransform>();
		component2.pivot = new Vector2(0.5f, 1f);
		val.content = component2;
		val.content.sizeDelta = val.viewport.sizeDelta;
		val.vertical = true;
		val.horizontal = false;
		val.scrollSensitivity = 80f;
		val.inertia = false;
		val.verticalScrollbarVisibility = (ScrollbarVisibility)1;
		val.movementType = (MovementType)2;
		val.decelerationRate = 0.135f;
		val.verticalScrollbar = CreateVerticalScrollbar(((Component)val).transform);
		val5.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
		GridLayoutGroup component3 = ((Component)component2).GetComponent<GridLayoutGroup>();
		component3.cellSize = new Vector2(1000f, 100f);
		((LayoutGroup)component3).childAlignment = (TextAnchor)1;
		component3.constraint = (Constraint)1;
		component3.constraintCount = 1;
		return val;
	}

	private Scrollbar CreateVerticalScrollbar(Transform parent)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Expected O, but got Unknown
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_0180: 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_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Expected O, but got Unknown
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0258: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Unknown result type (might be due to invalid IL or missing references)
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0298: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e0: Expected O, but got Unknown
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_0338: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("Vertical Scrollbar", new Type[2]
		{
			typeof(Scrollbar),
			typeof(Image)
		});
		Scrollbar component = val.GetComponent<Scrollbar>();
		component.direction = (Direction)2;
		val.GetComponent<Image>().type = (Type)1;
		val.GetComponent<Image>().sprite = Plugin.scrollbarAtlas.GetSprite("SH_Bg_Scrollbar");
		RectTransform component2 = val.GetComponent<RectTransform>();
		((Transform)component2).SetParent(parent, false);
		component2.anchoredPosition = new Vector2(460f, 285f);
		component2.anchorMin = new Vector2(1f, 0f);
		component2.anchorMax = new Vector2(1f, 1f);
		component2.pivot = new Vector2(1f, 1f);
		component2.sizeDelta = new Vector2(24f, 510f);
		GameObject val2 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) });
		RectTransform component3 = val2.GetComponent<RectTransform>();
		((Transform)component3).SetParent(val.transform, false);
		component3.anchorMin = Vector2.zero;
		component3.anchorMax = Vector2.one;
		component3.sizeDelta = Vector2.zero;
		GameObject val3 = new GameObject("Handle", new Type[1] { typeof(Image) });
		RectTransform component4 = val3.GetComponent<RectTransform>();
		((Transform)component4).SetParent(val2.transform, false);
		component4.anchorMin = new Vector2(0f, 0.6831f);
		component4.anchorMax = new Vector2(1f, 0f);
		component4.offsetMax = Vector2.zero;
		component4.offsetMin = Vector2.zero;
		component4.pivot = new Vector2(0.5f, 0.5f);
		component4.sizeDelta = Vector2.zero;
		((Component)component4).GetComponent<Image>().type = (Type)1;
		((Component)component4).GetComponent<Image>().sprite = Plugin.scrollbarAtlas.GetSprite("CMP_Scrollbar");
		GameObject val4 = new GameObject("Target Graphic", new Type[1] { typeof(Image) });
		val4.transform.SetParent(((Component)component4).transform, false);
		Image component5 = val4.GetComponent<Image>();
		((Graphic)component5).rectTransform.sizeDelta = Vector2.one * 20f;
		((Graphic)component5).rectTransform.anchorMax = Vector2.one;
		((Graphic)component5).rectTransform.anchorMin = Vector2.zero;
		((Graphic)component5).rectTransform.offsetMax = Vector2.one * 10f;
		((Graphic)component5).rectTransform.offsetMin = Vector2.one * -10f;
		component5.type = (Type)1;
		component5.sprite = Sprite.Create(new Texture2D(0, 0), Rect.zero, Vector2.zero);
		Sprite sprite = Plugin.scrollbarAtlas.GetSprite("SH_Square_Border_Highlight");
		component.handleRect = component4;
		((Selectable)component).targetGraphic = (Graphic)(object)component5;
		((Selectable)component).transition = (Transition)2;
		SpriteState spriteState = default(SpriteState);
		((SpriteState)(ref spriteState)).pressedSprite = sprite;
		((SpriteState)(ref spriteState)).highlightedSprite = sprite;
		((SpriteState)(ref spriteState)).selectedSprite = sprite;
		((Selectable)component).spriteState = spriteState;
		return component;
	}

	private GameObject CreateEmptyItem(ScrollRect scrollRect)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		ContentSizeFitter val = new GameObject("Empty", new Type[1] { typeof(RectTransform) }).AddComponent<ContentSizeFitter>();
		((Component)val).transform.SetParent((Transform)(object)scrollRect.content, false);
		val.horizontalFit = (FitMode)2;
		val.verticalFit = (FitMode)2;
		return ((Component)val).gameObject;
	}

	private SoundInfo CreateItem(ConfigEntryBase entry, ScrollRect scrollRect, bool createBG)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		SoundInfo soundInfo = new GameObject(entry.Definition.Key).AddComponent<SoundInfo>();
		((Component)soundInfo).transform.SetParent((Transform)(object)scrollRect.content, false);
		if (createBG)
		{
			Image val = new GameObject("BG").AddComponent<Image>();
			((Graphic)val).color = new Color(0f, 0f, 0f, 0.5f);
			((Graphic)val).rectTransform.anchorMin = Vector2.zero;
			((Graphic)val).rectTransform.anchorMax = Vector2.one;
			((Component)val).transform.SetParent(((Component)soundInfo).transform, false);
		}
		soundInfo.Set(SettingsScreen, entry);
		return soundInfo;
	}

	public override bool ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		if (((ScreenDialog)this).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID))
		{
			return true;
		}
		if ((Object)(object)soundChangerButton != (Object)null && soundChangerButton.TryTrigger(mapping, triggeredUI, triggeredMappingID, false, false))
		{
			((ScreenDialog)this).Open();
			return true;
		}
		foreach (KeyValuePair<string, SettingsTab> item in tabsSection)
		{
			if ((Object)(object)item.Value != (Object)null && item.Value.TryTrigger(mapping, triggeredUI, triggeredMappingID))
			{
				SetSection(item.Key, updateEntry: true);
				return true;
			}
		}
		foreach (SoundInfo sound in soundList)
		{
			if (!((Component)sound).gameObject.activeInHierarchy || !sound.TryTrigger(mapping, triggeredUI, triggeredMappingID))
			{
				continue;
			}
			return true;
		}
		return false;
	}

	public override void Close()
	{
		((ScreenDialog)this).Close();
		SoundManager.PlaySfxSignal.Dispatch("UI_Cancel");
	}

	internal static void CreateDialog(SettingsScreen settingScreen)
	{
		if (!((Object)(object)settingScreen == (Object)null))
		{
			Traverse val = Traverse.Create((object)settingScreen);
			SettingsDialog value = val.Field<SettingsDialog>("settingsDialog").Value;
			PauseDialog value2 = val.Field<PauseDialog>("pauseDialog").Value;
			SettingsDialog val2 = Object.Instantiate<SettingsDialog>(value, ((Component)value).transform.parent);
			GameObject gameObject = ((Component)val2).gameObject;
			Object.DestroyImmediate((Object)(object)val2);
			Instance = gameObject.AddComponent<SoundDialog>();
			Instance.CreateSoundChangerButton(value2);
		}
	}
}
public class NativeFileDialog
{
	[Flags]
	public enum OFN_Flags
	{
		OFN_ALLOWMULTISELECT = 0x200,
		OFN_CREATEPROMPT = 0x2000,
		OFN_DONTADDTORECENT = 0x2000000,
		OFN_ENABLEHOOK = 0x20,
		OFN_ENABLEINCLUDENOTIFY = 0x400000,
		OFN_ENABLESIZING = 0x800000,
		OFN_ENABLETEMPLATE = 0x40,
		OFN_ENABLETEMPLATEHANDLE = 0x80,
		OFN_EXPLORER = 0x80000,
		OFN_EXTENSIONDIFFERENT = 0x400,
		OFN_FILEMUSTEXIST = 0x1000,
		OFN_FORCESHOWHIDDEN = 0x10000000,
		OFN_HIDEREADONLY = 4,
		OFN_LONGNAMES = 0x200000,
		OFN_NOCHANGEDIR = 8,
		OFN_NODEREFERENCELINKS = 0x100000,
		OFN_NOLONGNAMES = 0x40000,
		OFN_NONETWORKBUTTON = 0x20000,
		OFN_NOREADONLYRETURN = 0x8000,
		OFN_NOTESTFILECREATE = 0x10000,
		OFN_NOVALIDATE = 0x100,
		OFN_OVERWRITEPROMPT = 2,
		OFN_PATHMUSTEXIST = 0x800,
		OFN_READONLY = 1,
		OFN_SHAREAWARE = 0x4000,
		OFN_SHOWHELP = 0x10
	}

	[Flags]
	public enum OFN_Flags_EX
	{
		OFN_EX_NOPLACESBAR = 1
	}

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	private struct OpenFileName
	{
		public int lStructSize;

		public IntPtr hwndOwner;

		public IntPtr hInstance;

		public string lpstrFilter;

		public string lpstrCustomFilter;

		public int nMaxCustFilter;

		public int nFilterIndex;

		public string lpstrFile;

		public int nMaxFile;

		public string lpstrFileTitle;

		public int nMaxFileTitle;

		public string lpstrInitialDir;

		public string lpstrTitle;

		public int Flags;

		public short nFileOffset;

		public short nFileExtension;

		public string lpstrDefExt;

		public IntPtr lCustData;

		public IntPtr lpfnHook;

		public string lpTemplateName;

		public IntPtr pvReserved;

		public int dwReserved;

		public int FlagsEx;
	}

	[DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	private static extern bool GetOpenFileName(ref OpenFileName ofn);

	public static void OpenSingleFile(Action<string> onComplete, string title = "Open File", string filter = "All Files\0*.*\0\0", string initialDir = "", string initialFile = "")
	{
		OpenFileName ofn = default(OpenFileName);
		ofn.lStructSize = Marshal.SizeOf(ofn);
		ofn.lpstrFilter = filter;
		char[] array = new char[260];
		if (!string.IsNullOrEmpty(initialFile))
		{
			initialFile.CopyTo(0, array, 0, Math.Min(initialFile.Length, 259));
		}
		ofn.lpstrFile = new string(array);
		ofn.nMaxFile = ofn.lpstrFile.Length;
		ofn.lpstrFileTitle = new string(new char[64]);
		ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length;
		ofn.lpstrInitialDir = initialDir;
		ofn.lpstrTitle = title;
		ofn.Flags = 530440;
		if (GetOpenFileName(ref ofn))
		{
			onComplete?.Invoke(ofn.lpstrFile);
		}
	}
}
internal class PatchList
{
	[HarmonyPostfix]
	[HarmonyPatch(typeof(AppManager), "DoesThisBuildReportErrors")]
	public static void DisableErrorReportingPatch(ref bool __result)
	{
		__result = false;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(AudioClip), "LoadAudioData")]
	public static bool LoadAudioData(AudioClip __instance, ref bool __result)
	{
		if (((Object)__instance).name.Contains("Patty_SoundChanger_MOD"))
		{
			__result = true;
			return false;
		}
		return true;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(AudioClip), "UnloadAudioData")]
	public static bool UnloadAudioData(AudioClip __instance, ref bool __result)
	{
		if (((Object)__instance).name.Contains("Patty_SoundChanger_MOD"))
		{
			__result = true;
			return false;
		}
		return true;
	}

	[HarmonyPrefix]
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	public static void CurrentTrackName_Set(SoundManager __instance, CoreAudioSystem ___audioSystem, ref string value)
	{
		string modifiedAudioName = Plugin.GetModifiedAudioName(value, ___audioSystem);
		if (!string.IsNullOrEmpty(modifiedAudioName))
		{
			value = modifiedAudioName;
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(LoadScreen), "StartLoadingScreen")]
	public static void StartLoadingScreen(LoadScreen __instance)
	{
		Plugin.CreateEntries();
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(SoundManager), "PlayMusic")]
	public static void PlayMusic(SoundManager __instance, string trackName, List<BattleMusicTrack> ___battleMusicTracks, List<BattleMusicTrack> ___bossBattleMusicTracks, CoreAudioSystem ___audioSystem)
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		string text = __instance.currentTrackName;
		string modifiedAudioName = Plugin.GetModifiedAudioName(trackName, ___audioSystem);
		if (!string.IsNullOrEmpty(modifiedAudioName))
		{
			text = modifiedAudioName;
		}
		else
		{
			IEnumerable<BattleMusicTrack> source = ___battleMusicTracks.Union(___bossBattleMusicTracks);
			BattleMusicTrack val = source.FirstOrDefault((Func<BattleMusicTrack, bool>)((BattleMusicTrack track) => track.trackNameData == trackName));
			if (!string.IsNullOrEmpty(val.trackNameData))
			{
				text = val.publicTrackNameKey;
			}
		}
		if (string.IsNullOrEmpty(text))
		{
			text = trackName;
		}
		else if (LocalizationManager.IsTranslatableTerm(text))
		{
			text = LocalizationManager.GetTranslation(text, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null);
		}
		else if (LocalizationManager.IsTranslatableTerm(trackName))
		{
			text = LocalizationManager.GetTranslation(trackName, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null);
		}
		Plugin.musicChanged.Dispatch(text);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(SoundManager), "PlayBattleMusic")]
	public static void PlayBattleMusic(SoundManager __instance)
	{
		string text = __instance.currentTrackName;
		if (LocalizationManager.IsTranslatableTerm(text))
		{
			text = LocalizationManager.GetTranslation(text, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null);
		}
		Plugin.musicChanged.Dispatch(text);
	}
}
[BepInPlugin("Patty_SoundChanger_MOD", "Sound Changer", "2.0.0")]
public class Plugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <>c__DisplayClass73_0
	{
		public SoundManager soundManager;

		public bool isBattleMusic;

		public float crossfadeTimeSeconds;

		public ConfigEntryBase entry;

		public string displayedName;

		public Action<string> onPlay;
	}

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

		private object <>2__current;

		public string filePath;

		public Action<AudioClip> onComplete;

		private UnityWebRequest <webRequest>5__1;

		private AudioClip <result>5__2;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<webRequest>5__1 = null;
			<result>5__2 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<webRequest>5__1 = UnityWebRequestMultimedia.GetAudioClip(filePath, GetAudioType(filePath));
					<>1__state = -3;
					<>2__current = <webRequest>5__1.SendWebRequest();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -3;
					if ((int)<webRequest>5__1.result == 1)
					{
						<result>5__2 = DownloadHandlerAudioClip.GetContent(<webRequest>5__1);
						((Object)<result>5__2).name = "Patty_SoundChanger_MOD_" + Path.GetFileNameWithoutExtension(filePath);
						onComplete?.Invoke(<result>5__2);
						<result>5__2 = null;
					}
					else
					{
						LogSource.LogError((object)<webRequest>5__1.error);
						onComplete?.Invoke(null);
					}
					<>m__Finally1();
					<webRequest>5__1 = null;
					return false;
				}
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

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

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<webRequest>5__1 != null)
			{
				((IDisposable)<webRequest>5__1).Dispose();
			}
		}

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

	public const string MUSIC_SECTION = "Music";

	public const string SFX_SECTION = "SFX";

	internal static Traverse configurationManagerTraverse;

	internal static Lazy<GUIStyle> centeredStyle = new Lazy<GUIStyle>((Func<GUIStyle>)(() => new GUIStyle
	{
		alignment = (TextAnchor)4
	}));

	internal static ConfigEntry<string> currentSectionEntry;

	internal static MethodInfo rebuildSettings;

	internal static SpriteAtlas scrollbarAtlas;

	internal static ConfigEntry<bool> enableIngameMenu;

	public static readonly Signal<string> musicChanged = new Signal<string>();

	public static readonly ISoundChanger soundChangerManager = new SoundChangerManager();

	public static readonly Signal onInitialize = new Signal();

	internal static bool Initialized { get; private set; }

	internal static string BasePath { get; } = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName;


	internal static Plugin Instance { get; private set; }

	internal static ManualLogSource LogSource { get; private set; }

	internal static Harmony PluginHarmony { get; private set; }

	internal static ConfigFile Config { get; private set; }

	internal static OrderedDictionary<ConfigEntryBase, SoundData<MusicDefinition>> MusicEntries { get; private set; } = new OrderedDictionary<ConfigEntryBase, SoundData<MusicDefinition>>();


	internal static OrderedDictionary<ConfigEntryBase, SoundData<SoundCueDefinition>> SFXEntries { get; private set; } = new OrderedDictionary<ConfigEntryBase, SoundData<SoundCueDefinition>>();


	internal static OrderedDictionary<MusicDefinition, List<AudioClip>> OriginalMusics { get; private set; } = new OrderedDictionary<MusicDefinition, List<AudioClip>>();


	internal static OrderedDictionary<SoundCueDefinition, List<AudioClip>> OriginalSFX { get; private set; } = new OrderedDictionary<SoundCueDefinition, List<AudioClip>>();


	internal static int LeftColumnWidth
	{
		get
		{
			if (configurationManagerTraverse == null)
			{
				return 260;
			}
			Traverse val = configurationManagerTraverse.Property("LeftColumnWidth", (object[])null);
			if (!val.PropertyExists())
			{
				return 260;
			}
			return val.GetValue<int>();
		}
	}

	private void Awake()
	{
		//IL_003f: Expected O, but got Unknown
		//IL_00af: Expected O, but got Unknown
		//IL_0079: Expected O, but got Unknown
		//IL_01c4: Expected O, but got Unknown
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Expected O, but got Unknown
		//IL_0193: Expected O, but got Unknown
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Expected O, but got Unknown
		//IL_026c: Expected O, but got Unknown
		//IL_027c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f3: Expected O, but got Unknown
		//IL_02f3: Expected O, but got Unknown
		Instance = this;
		LogSource = ((BaseUnityPlugin)this).Logger;
		Config = ((BaseUnityPlugin)this).Config;
		try
		{
			PluginHarmony = Harmony.CreateAndPatchAll(typeof(PatchList), "Patty_SoundChanger_MOD");
		}
		catch (HarmonyException val)
		{
			HarmonyException val2 = val;
			LogSource.LogError((object)((Exception)(((object)((Exception)(object)val2).InnerException) ?? ((object)val2))).Message);
		}
		try
		{
			PluginHarmony.PatchAll(typeof(TranspilerFix));
		}
		catch (HarmonyException val3)
		{
			HarmonyException val4 = val3;
			LogSource.LogError((object)((Exception)(((object)((Exception)(object)val4).InnerException) ?? ((object)val4))).Message);
			try
			{
				PluginHarmony.PatchAll(typeof(TemporaryFix));
			}
			catch (HarmonyException val5)
			{
				HarmonyException val6 = val5;
				LogSource.LogError((object)((Exception)(((object)((Exception)(object)val6).InnerException) ?? ((object)val6))).Message);
			}
		}
		if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value))
		{
			configurationManagerTraverse = Traverse.Create((object)value.Instance);
			try
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("ConfigurationManager.ConfigurationManager");
				rebuildSettings = AccessTools.DeclaredMethod(type, "BuildSettingList", (Type[])null, (Type[])null);
			}
			catch (Exception ex)
			{
				LogSource.LogError((object)(ex.InnerException ?? ex).Message);
			}
		}
		enableIngameMenu = Config.Bind<bool>(new ConfigDefinition("Basic", "Toggle in-game menu"), true, new ConfigDescription("If enabled, then create an in-game menu (recommended to disable if future game update breaks this mod). Restart to apply", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 10001
			}
		}));
		if (enableIngameMenu.Value)
		{
			try
			{
				PluginHarmony.PatchAll(typeof(MenuPatch));
			}
			catch (HarmonyException val7)
			{
				HarmonyException val8 = val7;
				LogSource.LogError((object)((Exception)(((object)((Exception)(object)val8).InnerException) ?? ((object)val8))).Message);
			}
		}
		Config.Bind<string>(new ConfigDefinition("Basic", "Currently Playing"), "", new ConfigDescription("Only for references as to what music is currently playing in game", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 10000,
				CustomDrawer = CurrentlyPlayingDrawer,
				HideDefaultButton = true,
				HideSettingName = true,
				ReadOnly = true
			}
		}));
		currentSectionEntry = Config.Bind<string>(new ConfigDefinition("Basic", "Toggled Section"), "", new ConfigDescription("Only for toggling sections", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				Order = 9999,
				CustomDrawer = ToggleSectionDrawer,
				HideDefaultButton = true,
				HideSettingName = true,
				ReadOnly = true
			}
		}));
		if (string.IsNullOrEmpty(currentSectionEntry.Value) || (currentSectionEntry.Value != "Music" && currentSectionEntry.Value != "SFX"))
		{
			currentSectionEntry.Value = "Music";
		}
		if (enableIngameMenu.Value)
		{
			AssetBundle val9 = AssetBundle.LoadFromFile(Path.Combine(BasePath, "scrollbar.bundle"));
			scrollbarAtlas = val9.LoadAsset<SpriteAtlas>("ScrollbarAtlas");
			val9.Unload(false);
		}
		musicChanged.AddListener((Action<string>)OnMusicChanged);
	}

	private void OnDestroy()
	{
		musicChanged.RemoveListener((Action<string>)OnMusicChanged);
	}

	internal static void OnMusicChanged(string trackName)
	{
		SoundManager soundManager = AllGameManagers.Instance.GetSoundManager();
		Traverse.Create((object)soundManager).Property("currentTrackName", (object[])null).SetValue((object)trackName);
	}

	internal static void CreateEntries()
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Expected O, but got Unknown
		if (Initialized)
		{
			return;
		}
		AllGameManagers instance = AllGameManagers.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.GetSoundManager() == (Object)null)
		{
			return;
		}
		Initialized = true;
		if (enableIngameMenu.Value)
		{
			SettingsScreen settingScreen = (SettingsScreen)instance.GetScreenManager().GetScreen((ScreenName)18);
			SoundDialog.CreateDialog(settingScreen);
		}
		SoundManager soundManager = instance.GetSoundManager();
		Traverse val = Traverse.Create((object)soundManager);
		CoreAudioSystem value = val.Field<CoreAudioSystem>("audioSystem").Value;
		CoreAudioSystemData value2 = Traverse.Create((object)value).Field("AudioSystemData").GetValue<CoreAudioSystemData>();
		foreach (MusicDefinition item in value2.MusicDefData.Tracks.OrderBy((MusicDefinition track) => track.Name))
		{
			CreateEntry(item);
		}
		foreach (SoundCueDefinition item2 in value2.GlobalSoundEffectData.Sounds.OrderBy((SoundCueDefinition track) => track.Name))
		{
			CreateEntry(item2);
		}
		SetBrowsableSection(currentSectionEntry.Value);
		onInitialize.Dispatch();
	}

	internal static void CreateEntry(MusicDefinition definition)
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_012b: Expected O, but got Unknown
		if (definition == null || MusicEntries.Values.Any((SoundData<MusicDefinition> data) => data?.definition == definition))
		{
			return;
		}
		if (!OriginalMusics.ContainsKey(definition))
		{
			OriginalMusics[definition] = new List<AudioClip>();
			MusicClipDefinition[] clips = definition.Clips;
			foreach (MusicClipDefinition val in clips)
			{
				OriginalMusics[definition].Add(val.Clip);
			}
		}
		ConfigEntry<string> entry = Config.Bind<string>(new ConfigDefinition("Basic", definition.Name), "", new ConfigDescription("", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				HideDefaultButton = true,
				HideSettingName = true,
				CustomDrawer = MusicDrawer
			}
		}));
		entry.SettingChanged += Entry_SettingChanged;
		MusicEntries[(ConfigEntryBase)(object)entry] = SoundData<MusicDefinition>.Create(entry, definition);
		if (MusicEntries[(ConfigEntryBase)(object)entry].IsFileExist())
		{
			((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(MusicEntries[(ConfigEntryBase)(object)entry].GetFilePath(), delegate(AudioClip audioClip)
			{
				OnAudioClipLoaded((ConfigEntryBase)(object)entry, audioClip);
			}));
		}
	}

	internal static void CreateEntry(SoundCueDefinition definition)
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Expected O, but got Unknown
		//IL_0126: Expected O, but got Unknown
		if (definition == null || SFXEntries.Values.Any((SoundData<SoundCueDefinition> data) => data?.definition == definition))
		{
			return;
		}
		if (!OriginalSFX.ContainsKey(definition))
		{
			OriginalSFX[definition] = new List<AudioClip>();
			AudioClip[] clips = definition.Clips;
			foreach (AudioClip item in clips)
			{
				OriginalSFX[definition].Add(item);
			}
		}
		ConfigEntry<string> entry = Config.Bind<string>(new ConfigDefinition("Basic", definition.Name), "", new ConfigDescription("", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				HideDefaultButton = true,
				HideSettingName = true,
				CustomDrawer = MusicDrawer
			}
		}));
		entry.SettingChanged += Entry_SettingChanged;
		SFXEntries[(ConfigEntryBase)(object)entry] = SoundData<SoundCueDefinition>.Create(entry, definition);
		if (SFXEntries[(ConfigEntryBase)(object)entry].IsFileExist())
		{
			((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(SFXEntries[(ConfigEntryBase)(object)entry].GetFilePath(), delegate(AudioClip audioClip)
			{
				OnAudioClipLoaded((ConfigEntryBase)(object)entry, audioClip);
			}));
		}
	}

	internal static void Entry_SettingChanged(object sender, EventArgs e)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		ResetEntryBase(((SettingChangedEventArgs)e).ChangedSetting);
	}

	internal static void ResetEntryBase(ConfigEntryBase entryBase, Action<string> onPlay = null)
	{
		string text = entryBase.BoxedValue as string;
		if (!string.IsNullOrEmpty(text) && File.Exists(text))
		{
			return;
		}
		AllGameManagers instance = AllGameManagers.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.GetSoundManager() == (Object)null)
		{
			return;
		}
		SoundManager soundManager = instance.GetSoundManager();
		if (MusicEntries.TryGetValue(entryBase, out var value))
		{
			string currentMusicTrackName = soundManager.GetCurrentMusicTrackName();
			foreach (KeyValuePair<MusicDefinition, List<AudioClip>> originalMusic in OriginalMusics)
			{
				if (originalMusic.Key == value.definition)
				{
					MusicClipDefinition[] clips = originalMusic.Key.Clips;
					for (int i = 0; i < clips.Length; i++)
					{
						clips[i].Clip = originalMusic.Value[i];
					}
					break;
				}
			}
			if (value.entryName == currentMusicTrackName)
			{
				ReplayMusic(entryBase, GetPlayingMusicName(), onPlay);
			}
		}
		else
		{
			if (!SFXEntries.TryGetValue(entryBase, out var value2))
			{
				return;
			}
			foreach (KeyValuePair<SoundCueDefinition, List<AudioClip>> item in OriginalSFX)
			{
				if (item.Key == value2.definition)
				{
					AudioClip[] clips2 = item.Key.Clips;
					for (int j = 0; j < clips2.Length; j++)
					{
						clips2[j] = item.Value[j];
					}
					break;
				}
			}
		}
	}

	internal static string GetPlayingMusicName()
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		AllGameManagers instance = AllGameManagers.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return "";
		}
		if ((Object)(object)instance.GetSoundManager() == (Object)null)
		{
			return "";
		}
		SoundManager soundManager = instance.GetSoundManager();
		Traverse val = Traverse.Create((object)soundManager);
		List<BattleMusicTrack> value = val.Field<List<BattleMusicTrack>>("battleMusicTracks").Value;
		List<BattleMusicTrack> value2 = val.Field<List<BattleMusicTrack>>("bossBattleMusicTracks").Value;
		value.AddRange(value2);
		string text = "";
		string musicName = soundManager.GetCurrentMusicTrackName();
		BattleMusicTrack val2 = value.Find((BattleMusicTrack track) => track.trackNameData == musicName);
		if (!string.IsNullOrEmpty(val2.publicTrackNameKey))
		{
			text = val2.publicTrackNameKey;
			if (LocalizationManager.IsTranslatableTerm(text))
			{
				text = LocalizationExtensions.Localize(text, (ILocalizationParameterContext)null);
			}
		}
		return text;
	}

	internal static string GetModifiedAudioName(string trackName, CoreAudioSystem coreAudioSystem)
	{
		if (string.IsNullOrWhiteSpace(trackName))
		{
			return "";
		}
		Traverse val = Traverse.Create((object)coreAudioSystem).Method("GetCurrentTrack", Array.Empty<object>());
		if (!val.MethodExists())
		{
			return "";
		}
		Traverse val2 = Traverse.Create(val.GetValue()).Field("MusicDefinition");
		if (!val2.FieldExists() || val2.GetValue<MusicDefinition>() == null)
		{
			return "";
		}
		MusicDefinition value = val2.GetValue<MusicDefinition>();
		if (value == null || IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)value.Clips))
		{
			return "";
		}
		if (value.Name != trackName)
		{
			if (!trackName.StartsWith("KEY>>") || !trackName.EndsWith("<<"))
			{
				return "";
			}
			trackName = trackName.Substring("KEY>>".Length, trackName.Length - ("KEY>>".Length + "<<".Length));
			if (value.Name != trackName)
			{
				return "";
			}
		}
		MusicClipDefinition val3 = ((IEnumerable<MusicClipDefinition>)value.Clips).FirstOrDefault((Func<MusicClipDefinition, bool>)((MusicClipDefinition source) => source != null && (Object)(object)source.Clip != (Object)null && ((Object)source.Clip).name.Contains("Patty_SoundChanger_MOD")));
		if (val3 != null)
		{
			return RemoveGUIDFromName(val3.Clip);
		}
		return "";
	}

	internal static string RemoveGUIDFromName(AudioClip audioClip)
	{
		int num = "Patty_SoundChanger_MOD".Length + 1;
		return ((Object)audioClip).name.Substring(num, ((Object)audioClip).name.Length - num);
	}

	internal static void ToggleSectionDrawer(ConfigEntryBase entry)
	{
		bool flag = GUILayout.Button("Toggle Music", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		bool flag2 = GUILayout.Button("Toggle SFX", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (flag)
		{
			currentSectionEntry.Value = "Music";
			SetBrowsableSection(currentSectionEntry.Value);
		}
		else if (flag2)
		{
			currentSectionEntry.Value = "SFX";
			SetBrowsableSection(currentSectionEntry.Value);
		}
	}

	internal static void SetBrowsableSection(string section, bool updateList = true)
	{
		bool browsable = section == "Music";
		bool browsable2 = section == "SFX";
		SetEntriesBrowsable(SFXEntries.Keys, browsable2);
		SetEntriesBrowsable(MusicEntries.Keys, browsable);
		if (updateList && !(rebuildSettings == null))
		{
			rebuildSettings.Invoke(configurationManagerTraverse.GetValue(), null);
		}
	}

	internal static void SetEntriesBrowsable(IEnumerable<object> entries, bool browsable)
	{
		foreach (object entry in entries)
		{
			ConfigEntry<string> val = (ConfigEntry<string>)entry;
			ConfigurationManagerAttributes configurationManagerAttributes = (ConfigurationManagerAttributes)((ConfigEntryBase)val).Description.Tags.First();
			configurationManagerAttributes.Browsable = browsable;
		}
	}

	internal static void CurrentlyPlayingDrawer(ConfigEntryBase entry)
	{
		AllGameManagers instance = AllGameManagers.Instance;
		if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null))
		{
			SoundManager soundManager = instance.GetSoundManager();
			string text = soundManager.GetCurrentMusicTrackName();
			if (!string.IsNullOrEmpty(soundManager.currentTrackName))
			{
				text = soundManager.currentTrackName;
			}
			GUILayout.Label("<color=white>Currently playing:</color> <color=yellow>" + text + "</color>", centeredStyle.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		}
	}

	internal static bool IsCurrentMusic(ConfigEntryBase entry)
	{
		bool result = false;
		AllGameManagers instance = AllGameManagers.Instance;
		if ((Object)(object)instance != (Object)null && (Object)(object)instance.GetSoundManager() != (Object)null && instance.GetSoundManager().GetCurrentMusicTrackName() == entry.Definition.Key)
		{
			result = true;
		}
		return result;
	}

	internal static void MusicDrawer(ConfigEntryBase entry)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		bool flag = IsCurrentMusic(entry);
		string text = "";
		string text2 = "";
		if (flag)
		{
			text = "<color=yellow>";
			text2 = "</color>";
		}
		GUILayout.Label(new GUIContent(text + entry.Definition.Key + text2, (Texture)null, entry.Description.Description), (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width((float)LeftColumnWidth - 20f),
			GUILayout.MaxWidth((float)LeftColumnWidth - 20f)
		});
		string text3 = entry.BoxedValue as string;
		bool flag2 = File.Exists(text3);
		if (text3 != null && flag2)
		{
			GUILayout.Label(text + Path.GetFileName(text3) + text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		}
		bool flag3 = GUILayout.Button("Load File", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (GUILayout.Button(" ▶ ", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
		{
			if (MusicEntries.ContainsKey(entry))
			{
				PlayMusic(entry);
			}
			else
			{
				PlaySFX(entry);
			}
		}
		if (flag2 && GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
		{
			entry.BoxedValue = "";
			ResetEntryBase(entry);
		}
		if (flag3)
		{
			LoadFile(entry, text3, flag2);
		}
	}

	internal static void LoadFile(ConfigEntryBase entry, string targetPath, bool existFile, Action<string, AudioClip> onComplete = null, Action<string> onPlay = null)
	{
		string filter = "Supported Files (*.wav; *.ogg; *.mp3)\0*.wav;*.ogg;*.mp3\0WAV Files (*.wav)\0*.wav\0OGG Files (*.ogg)\0*.ogg\0MP3 Files (*.mp3)\0*.mp3\0All Files\0*.*\0\0";
		string initialDir = BasePath;
		if (existFile)
		{
			initialDir = Directory.GetParent(targetPath).FullName;
		}
		NativeFileDialog.OpenSingleFile(delegate(string filePath)
		{
			((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(filePath, delegate(AudioClip audioClip)
			{
				if (!((Object)(object)audioClip == (Object)null))
				{
					entry.BoxedValue = filePath;
					OnAudioClipLoaded(entry, audioClip, replayMusic: true, onPlay);
					onComplete?.Invoke(filePath, audioClip);
				}
			}));
		}, "Select audio to replace with", filter, initialDir, targetPath);
	}

	internal static AudioType GetAudioType(string filePath)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		return (AudioType)(Path.GetExtension(filePath)?.ToUpperInvariant() switch
		{
			".MP3" => 13, 
			".OGG" => 14, 
			".WAV" => 20, 
			_ => 0, 
		});
	}

	internal static void OnAudioClipLoaded(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = false, Action<string> onPlay = null)
	{
		try
		{
			if ((Object)(object)audioClip == (Object)null)
			{
				return;
			}
			if (MusicEntries.TryGetValue(entry, out var value))
			{
				value.AudioData = audioClip;
				MusicDefinition definition = value.definition;
				if (definition != null)
				{
					MusicClipDefinition[] clips = definition.Clips;
					if (((clips != null) ? new bool?(IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)clips)) : null).GetValueOrDefault())
					{
						LogSource.LogError((object)"Definition is null, you're likely calling load before assigning a definition after creating an empty SoundData. Try to use AssignDefinitionToData before loading a file");
						return;
					}
				}
				if (replayMusic)
				{
					ReplayMusic(entry, "", onPlay);
				}
			}
			else
			{
				if (!SFXEntries.TryGetValue(entry, out var value2))
				{
					return;
				}
				value2.AudioData = audioClip;
				SoundCueDefinition definition2 = value2.definition;
				if (definition2 != null)
				{
					AudioClip[] clips2 = definition2.Clips;
					if (((clips2 != null) ? new bool?(IEnumerableUtility.IsNullOrEmpty<AudioClip>((IEnumerable<AudioClip>)clips2)) : null).GetValueOrDefault())
					{
						LogSource.LogError((object)"Definition is null, you're likely calling load before assigning a definition after creating an empty SoundData. Try to use AssignDefinitionToData before loading a file");
					}
				}
			}
		}
		catch (Exception ex)
		{
			LogSource.LogError((object)(ex.InnerException ?? ex).Message);
			LogSource.LogError((object)"You're likely loading too early before the Definition has been loaded, connect a method to Plugin.onInitialize instead");
		}
	}

	internal static void ReplayMusic(ConfigEntryBase entry, string displayedName = "", Action<string> onPlay = null)
	{
		AllGameManagers instance = AllGameManagers.Instance;
		if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null))
		{
			SoundManager soundManager = instance.GetSoundManager();
			if (soundManager.GetCurrentMusicTrackName() == entry.Definition.Key)
			{
				PlayMusic(entry, isBattleMusic: false, 0.25f, "", onPlay);
			}
		}
	}

	internal static void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null)
	{
		<>c__DisplayClass73_0 CS$<>8__locals0 = new <>c__DisplayClass73_0();
		CS$<>8__locals0.isBattleMusic = isBattleMusic;
		CS$<>8__locals0.crossfadeTimeSeconds = crossfadeTimeSeconds;
		CS$<>8__locals0.entry = entry;
		CS$<>8__locals0.displayedName = displayedName;
		CS$<>8__locals0.onPlay = onPlay;
		AllGameManagers instance = AllGameManagers.Instance;
		if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null))
		{
			CS$<>8__locals0.soundManager = instance.GetSoundManager();
			CS$<>8__locals0.soundManager.StopMusic(0.25f);
			((MonoBehaviour)Instance).StartCoroutine(WaitUntilMusicStops());
		}
		[IteratorStateMachine(typeof(<>c__DisplayClass73_0.<<PlayMusic>g__WaitUntilMusicStops|0>d))]
		IEnumerator WaitUntilMusicStops()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <>c__DisplayClass73_0.<<PlayMusic>g__WaitUntilMusicStops|0>d(0)
			{
				<>4__this = CS$<>8__locals0
			};
		}
	}

	internal static void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		AllGameManagers instance = AllGameManagers.Instance;
		if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null))
		{
			SoundManager soundManager = instance.GetSoundManager();
			SoundData<SoundCueDefinition> soundData = SFXEntries[entry];
			bool loop2 = soundData.definition.Loop;
			soundData.definition.Loop = loop;
			soundManager.PlaySfx(entry.Definition.Key, (AudioSfxPriority)0, false);
			soundData.definition.Loop = loop2;
			onPlay?.Invoke(entry.Definition.Key);
		}
	}

	[IteratorStateMachine(typeof(<LoadAudioClip>d__75))]
	internal static IEnumerator LoadAudioClip(string filePath, Action<AudioClip> onComplete = null)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <LoadAudioClip>d__75(0)
		{
			filePath = filePath,
			onComplete = onComplete
		};
	}
}
public static class PluginInfo
{
	public const string GUID = "Patty_SoundChanger_MOD";

	public const string Name = "Sound Changer";

	public const string Version = "2.0.0";
}
public class SoundInfo : MonoBehaviour
{
	internal ConfigEntryBase entry;

	internal TMP_Text titleTMP;

	internal TMP_Text replacementTMP;

	internal Dictionary<GameUISelectableButton, Action> buttons = new Dictionary<GameUISelectableButton, Action>(3);

	internal bool TryTrigger(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<GameUISelectableButton, Action> button in buttons)
		{
			if (button.Key.TryTrigger(mapping, triggeredUI, triggeredMappingID, false, false))
			{
				button.Value();
				return true;
			}
		}
		return false;
	}

	internal void Set(SettingsScreen settingsScreen, ConfigEntryBase entry)
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: 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)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: 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)
		Traverse val = Traverse.Create((object)settingsScreen);
		PauseDialog value = val.Field<PauseDialog>("pauseDialog").Value;
		GameUISelectableButton value2 = Traverse.Create((object)value).Field<GameUISelectableButton>("settingsButton").Value;
		TMP_Text value3 = Traverse.Create((object)value).Field<TMP_Text>("musicLabel").Value;
		ContentSizeFitter val2 = ((Component)this).gameObject.AddComponent<ContentSizeFitter>();
		val2.verticalFit = (FitMode)2;
		val2.horizontalFit = (FitMode)2;
		TMP_Text val3 = Object.Instantiate<TMP_Text>(value3, ((Component)val2).transform);
		Object.DestroyImmediate((Object)(object)((Component)val3).GetComponent<Localize>());
		val3.rectTransform.anchorMin = Vector2.zero;
		val3.rectTransform.pivot = new Vector2(0f, 0.5f);
		val3.rectTransform.anchoredPosition = new Vector2(0f, 0f);
		val3.rectTransform.sizeDelta = new Vector2(300f, 33f);
		((Object)val3).name = "Label";
		val3.alignment = (TextAlignmentOptions)513;
		val3.overflowMode = (TextOverflowModes)1;
		val3.fontSizeMax = 30f;
		val3.fontSizeMin = 18f;
		val3.enableAutoSizing = true;
		TMP_Text val4 = Object.Instantiate<TMP_Text>(val3, ((Component)val2).transform);
		((Object)val4).name = "Replacement Label";
		val4.rectTransform.anchoredPosition = new Vector2(320f, 0f);
		GameUISelectableButton val5 = Object.Instantiate<GameUISelectableButton>(value2, ((Component)val2).transform);
		((Component)val5).GetComponent<RectTransform>().anchorMax = new Vector2(1f, 0.5f);
		((Component)val5).GetComponent<RectTransform>().anchorMin = new Vector2(1f, 0.5f);
		((Component)val5).GetComponent<RectTransform>().anchoredPosition = new Vector2(-20f, 0f);
		((Component)val5).GetComponent<RectTransform>().pivot = new Vector2(1f, 0.5f);
		((Component)val5).GetComponent<RectTransform>().sizeDelta = new Vector2(100f, 64f);
		Object.DestroyImmediate((Object)(object)((Component)val5).GetComponentInChildren<Localize>());
		((TMP_Text)((Component)val5).GetComponentInChildren<TextMeshProUGUI>()).text = "Reset";
		((Object)val5).name = "Reset Button";
		GameUISelectableButton val6 = Object.Instantiate<GameUISelectableButton>(val5, ((Component)val2).transform);
		((Component)val6).GetComponent<RectTransform>().sizeDelta = new Vector2(120f, 64f);
		((Component)val6).GetComponent<RectTransform>().anchoredPosition = new Vector2(-150f, 0f);
		((TMP_Text)((Component)val6).GetComponentInChildren<TextMeshProUGUI>()).text = "Load File";
		((Object)val6).name = "Load File Button";
		GameUISelectableButton val7 = Object.Instantiate<GameUISelectableButton>(val6, ((Component)val2).transform);
		((Component)val7).GetComponent<RectTransform>().sizeDelta = new Vector2(50f, 64f);
		((Component)val7).GetComponent<RectTransform>().anchoredPosition = new Vector2(-300f, 0f);
		((TMP_Text)((Component)val7).GetComponentInChildren<TextMeshProUGUI>()).text = " ▶ ";
		((Object)val7).name = "Play Button";
		this.entry = entry;
		((ConfigEntry<string>)(object)this.entry).SettingChanged += SoundInfo_SettingChanged;
		titleTMP = val3;
		replacementTMP = val4;
		buttons[val7] = PlayMusic;
		buttons[val6] = LoadFile;
		buttons[val5] = ResetMusic;
		UpdateText();
		Plugin.musicChanged.AddListener((Action<string>)OnMusicChanged);
	}

	private void OnDestroy()
	{
		((ConfigEntry<string>)(object)entry).SettingChanged -= SoundInfo_SettingChanged;
		Plugin.musicChanged.RemoveListener((Action<string>)OnMusicChanged);
	}

	private void OnMusicChanged(string trackName)
	{
		UpdateText();
	}

	private void SoundInfo_SettingChanged(object sender, EventArgs e)
	{
		UpdateText();
	}

	internal void PlayMusic()
	{
		if (Plugin.MusicEntries.ContainsKey(entry))
		{
			Plugin.PlayMusic(entry, isBattleMusic: false, 0.25f, "", delegate
			{
				UpdateText();
			});
		}
		else
		{
			Plugin.PlaySFX(entry);
		}
	}

	internal void LoadFile()
	{
		string text = entry.BoxedValue as string;
		bool existFile = File.Exists(text);
		Plugin.LoadFile(entry, text, existFile, null, delegate(string trackName)
		{
			UpdateText();
			SoundDialog.Instance.UpdateCurrentMusicName(trackName);
		});
	}

	internal void ResetMusic()
	{
		entry.BoxedValue = "";
		Plugin.ResetEntryBase(entry, delegate
		{
			UpdateText();
		});
	}

	public void UpdateText()
	{
		bool flag = Plugin.IsCurrentMusic(entry);
		string text = "";
		string text2 = "";
		if (flag)
		{
			text = "<color=yellow>";
			text2 = "</color>";
		}
		titleTMP.text = text + entry.Definition.Key + text2;
		replacementTMP.text = text + Path.GetFileName(entry.BoxedValue as string) + text2;
	}
}
internal class TemporaryFix
{
	[HarmonyPrefix]
	[HarmonyPatch(typeof(MusicNotificationHandler), "OnBattleMusicChanged")]
	public static void OnBattleMusicChanged(ref string trackName)
	{
		trackName = AllGameManagers.Instance.GetSoundManager().currentTrackName;
	}
}
internal class TranspilerFix
{
	[HarmonyTranspiler]
	[HarmonyPatch(typeof(Sound

ATL.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using ATL;
using ATL.AudioData;
using ATL.AudioData.IO;
using ATL.CatalogDataReaders.BinaryLogic;
using ATL.Logging;
using ATL.Playlist.IO;
using Commons;
using HashDepot;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: InternalsVisibleTo("ATL.test")]
[assembly: AssemblyCompany("Zeugma440")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fully managed, portable and easy-to-use C# library to read and edit audio data and metadata (tags) from various audio formats, playlists and CUE sheets")]
[assembly: AssemblyFileVersion("3.25.0.0")]
[assembly: AssemblyInformationalVersion("3.25")]
[assembly: AssemblyProduct("Audio Tools Library (ATL) for .NET")]
[assembly: AssemblyTitle("ATL")]
[assembly: AssemblyVersion("3.25.0.0")]
namespace Commons
{
	public enum ImageFormat
	{
		Unsupported = 99,
		Undefined = 98,
		Jpeg = 1,
		Gif = 2,
		Png = 3,
		Bmp = 4,
		Tiff = 5
	}
	public class ImageProperties
	{
		public ImageFormat Format = ImageFormat.Undefined;

		public int Width;

		public int Height;

		public int ColorDepth;

		public int NumColorsInPalette;
	}
	public static class ImageUtils
	{
		public static string GetMimeTypeFromImageFormat(ImageFormat imageFormat)
		{
			string text = "image/";
			if (imageFormat.Equals(ImageFormat.Jpeg))
			{
				return text + "jpeg";
			}
			if (imageFormat.Equals(ImageFormat.Gif))
			{
				return text + "gif";
			}
			if (imageFormat.Equals(ImageFormat.Png))
			{
				return text + "png";
			}
			if (imageFormat.Equals(ImageFormat.Bmp))
			{
				return text + "bmp";
			}
			if (imageFormat.Equals(ImageFormat.Tiff))
			{
				return text + "tiff";
			}
			return text + "*";
		}

		public static ImageFormat GetImageFormatFromMimeType(string mimeType)
		{
			ImageFormat result = ImageFormat.Jpeg;
			if (mimeType.Contains("gif"))
			{
				result = ImageFormat.Gif;
			}
			else if (mimeType.Contains("png"))
			{
				result = ImageFormat.Png;
			}
			else if (mimeType.Contains("bmp"))
			{
				result = ImageFormat.Bmp;
			}
			else if (mimeType.Contains("tiff"))
			{
				result = ImageFormat.Tiff;
			}
			return result;
		}

		public static ImageFormat GetImageFormatFromPictureHeader(byte[] header)
		{
			if (header.Length < 3)
			{
				throw new FormatException("Header length must be at least 3");
			}
			if (byte.MaxValue == header[0] && 216 == header[1] && byte.MaxValue == header[2])
			{
				return ImageFormat.Jpeg;
			}
			if (66 == header[0] && 77 == header[1])
			{
				return ImageFormat.Bmp;
			}
			if (71 == header[0] && 73 == header[1] && 70 == header[2])
			{
				return ImageFormat.Gif;
			}
			if (137 == header[0] && 80 == header[1] && 78 == header[2])
			{
				return ImageFormat.Png;
			}
			if (73 == header[0] && 73 == header[1] && 42 == header[2])
			{
				return ImageFormat.Tiff;
			}
			if (77 == header[0] && 77 == header[1] && header[2] == 0)
			{
				return ImageFormat.Tiff;
			}
			return ImageFormat.Unsupported;
		}

		public static ImageProperties GetImageProperties(byte[] imageData, ImageFormat format = ImageFormat.Undefined)
		{
			ImageProperties imageProperties = new ImageProperties();
			if (ImageFormat.Undefined.Equals(format))
			{
				format = GetImageFormatFromPictureHeader(imageData);
			}
			if (format.Equals(ImageFormat.Unsupported))
			{
				return imageProperties;
			}
			imageProperties.NumColorsInPalette = 0;
			imageProperties.Format = format;
			using (MemoryStream memoryStream = new MemoryStream(imageData))
			{
				using BinaryReader binaryReader = new BinaryReader(memoryStream);
				long limit = (long)Math.Round((double)memoryStream.Length * 0.25);
				switch (format)
				{
				case ImageFormat.Tiff:
				{
					bool flag = 77 == binaryReader.ReadByte();
					memoryStream.Seek(3L, SeekOrigin.Current);
					long offset = readInt32(binaryReader, flag);
					memoryStream.Seek(offset, SeekOrigin.Begin);
					int num5 = readInt16(binaryReader, flag);
					int num6 = 0;
					int num2 = 0;
					int num7 = 0;
					for (int i = 0; i < num5; i++)
					{
						int num8 = readInt16(binaryReader, flag);
						readInt16(binaryReader, flag);
						readInt32(binaryReader, flag);
						byte[] array3 = binaryReader.ReadBytes(4);
						int num9 = (flag ? StreamUtils.DecodeBEInt32(array3) : StreamUtils.DecodeInt32(array3));
						int num10 = (flag ? StreamUtils.DecodeBEInt16(array3) : StreamUtils.DecodeInt16(array3));
						switch (num8)
						{
						case 256:
							imageProperties.Width = num9;
							if (array3[2] + array3[3] == 0)
							{
								imageProperties.Width = num10;
							}
							break;
						case 257:
							imageProperties.Height = num9;
							if (array3[2] + array3[3] == 0)
							{
								imageProperties.Height = num10;
							}
							break;
						case 262:
							num6 = num9;
							if (num9 < 2)
							{
								imageProperties.ColorDepth = 1;
							}
							else if (2 == num9)
							{
								imageProperties.ColorDepth = 24;
							}
							break;
						case 258:
							num2 = num10;
							break;
						case 277:
							num7 = num10;
							break;
						}
					}
					if (num6 < 2)
					{
						imageProperties.ColorDepth = num2;
					}
					else if (2 == num6)
					{
						imageProperties.ColorDepth = 8 * num7;
					}
					else if (3 == num6)
					{
						imageProperties.ColorDepth = 8 * num7;
						imageProperties.NumColorsInPalette = num2;
					}
					break;
				}
				case ImageFormat.Gif:
				{
					byte[] sequence2 = new byte[2] { 33, 249 };
					imageProperties.ColorDepth = 24;
					memoryStream.Seek(3L, SeekOrigin.Current);
					string @string = Utils.Latin1Encoding.GetString(binaryReader.ReadBytes(3));
					memoryStream.Seek(4L, SeekOrigin.Current);
					byte b2 = binaryReader.ReadByte();
					if ((b2 & 0x80) >> 7 > 0)
					{
						imageProperties.NumColorsInPalette = 2 << (b2 & 7);
					}
					if ("89a".Equals(@string))
					{
						long position = memoryStream.Position;
						if (StreamUtils.FindSequence(memoryStream, sequence2, 0L))
						{
							memoryStream.Seek(6L, SeekOrigin.Current);
						}
						else
						{
							LogDelegator.GetLogDelegate()(2, "Invalid v89a GIF file; no graphic control extension block found");
							memoryStream.Seek(position, SeekOrigin.Begin);
							if (StreamUtils.FindSequence(memoryStream, new byte[1] { 44 }, 0L))
							{
								memoryStream.Seek(-1L, SeekOrigin.Current);
							}
						}
					}
					if (44 == binaryReader.ReadByte())
					{
						memoryStream.Seek(4L, SeekOrigin.Current);
						imageProperties.Width = binaryReader.ReadInt16();
						imageProperties.Height = binaryReader.ReadInt16();
						if (imageProperties.NumColorsInPalette == 0)
						{
							imageProperties.NumColorsInPalette = (int)Math.Pow(2.0, ((b2 & 0xF) << 4) + 1);
						}
					}
					else
					{
						LogDelegator.GetLogDelegate()(2, "Error parsing GIF file; image block not found");
					}
					break;
				}
				case ImageFormat.Bmp:
					memoryStream.Seek(18L, SeekOrigin.Begin);
					imageProperties.Width = binaryReader.ReadInt32();
					imageProperties.Height = binaryReader.ReadInt32();
					memoryStream.Seek(2L, SeekOrigin.Current);
					imageProperties.ColorDepth = binaryReader.ReadInt16();
					break;
				case ImageFormat.Png:
				{
					byte[] array2 = new byte[4];
					byte[] bytes = Utils.Latin1Encoding.GetBytes("IHDR");
					byte[] bytes2 = Utils.Latin1Encoding.GetBytes("PLTE");
					memoryStream.Seek(8L, SeekOrigin.Begin);
					if (findPngChunk(memoryStream, bytes, limit) == 0)
					{
						LogDelegator.GetLogDelegate()(2, "Invalid PNG file; no IHDR chunk found");
						break;
					}
					memoryStream.Read(array2, 0, 4);
					imageProperties.Width = StreamUtils.DecodeBEInt32(array2);
					memoryStream.Read(array2, 0, 4);
					imageProperties.Height = StreamUtils.DecodeBEInt32(array2);
					imageProperties.ColorDepth = binaryReader.ReadByte();
					int num3 = binaryReader.ReadByte();
					if (3 == num3)
					{
						memoryStream.Seek(7L, SeekOrigin.Current);
						uint num4 = findPngChunk(memoryStream, bytes2, limit);
						if (num4 == 0)
						{
							LogDelegator.GetLogDelegate()(2, "Invalid PNG file; palette declared, but no PLTE chunk found");
						}
						else
						{
							imageProperties.NumColorsInPalette = (int)Math.Floor((double)num4 / 3.0);
						}
					}
					else
					{
						imageProperties.NumColorsInPalette = 0;
					}
					break;
				}
				case ImageFormat.Jpeg:
				{
					byte[] array = new byte[2];
					byte[] sequence = new byte[2] { 255, 192 };
					long num = 0L;
					while (StreamUtils.FindSequence(memoryStream, sequence, limit))
					{
						num = memoryStream.Position;
					}
					if (num == 0L)
					{
						LogDelegator.GetLogDelegate()(2, "Invalid JPEG file; no SOF0 frame found");
						break;
					}
					memoryStream.Seek(2L, SeekOrigin.Current);
					int num2 = binaryReader.ReadByte();
					memoryStream.Read(array, 0, 2);
					imageProperties.Height = StreamUtils.DecodeBEUInt16(array);
					memoryStream.Read(array, 0, 2);
					imageProperties.Width = StreamUtils.DecodeBEUInt16(array);
					byte b = binaryReader.ReadByte();
					imageProperties.ColorDepth = num2 * b;
					break;
				}
				}
			}
			return imageProperties;
		}

		private static uint findPngChunk(Stream s, byte[] chunkID, long limit)
		{
			byte[] array = new byte[4];
			while (s.Position < limit)
			{
				s.Read(array, 0, 4);
				uint num = StreamUtils.DecodeBEUInt32(array);
				s.Read(array, 0, 4);
				if (StreamUtils.ArrEqualsArr(array, chunkID))
				{
					return num;
				}
				s.Seek(num + 4, SeekOrigin.Current);
			}
			return 0u;
		}

		private static short readInt16(BinaryReader r, bool isBigEndian)
		{
			if (!isBigEndian)
			{
				return r.ReadInt16();
			}
			return StreamUtils.DecodeBEInt16(r.ReadBytes(2));
		}

		private static int readInt32(BinaryReader r, bool isBigEndian)
		{
			if (!isBigEndian)
			{
				return r.ReadInt32();
			}
			return StreamUtils.DecodeBEInt32(r.ReadBytes(4));
		}
	}
	public static class Utils
	{
		public delegate void voidDelegate();

		private static Encoding latin1Encoding = Encoding.GetEncoding("ISO-8859-1");

		public static readonly string UNICODE_INVISIBLE_EMPTY = "\ufeff";

		public static Encoding Latin1Encoding => latin1Encoding;

		public static string ProtectValue(string value)
		{
			if (value != null)
			{
				return value;
			}
			return "";
		}

		public static string ProtectYear(DateTime value)
		{
			if (!(DateTime.MinValue == value))
			{
				return value.Year.ToString();
			}
			return "";
		}

		public static string EncodeTimecode_ms(long milliseconds)
		{
			long num = Convert.ToInt64(Math.Floor((double)milliseconds / 1000.0));
			return EncodeTimecode_s(num) + "." + (milliseconds - num * 1000);
		}

		public static string EncodeTimecode_s(long seconds)
		{
			int num = Convert.ToInt32(Math.Floor((double)seconds / 3600.0));
			long num2 = Convert.ToInt64(Math.Floor(((double)seconds - 3600.0 * (double)num) / 60.0));
			long num3 = seconds - 60 * num2 - 3600 * num;
			int num4 = Convert.ToInt32(Math.Floor((double)num / 24.0));
			if (num4 > 0)
			{
				num -= 24 * num4;
			}
			string text = num.ToString();
			if (1 == text.Length)
			{
				text = "0" + text;
			}
			string text2 = num2.ToString();
			if (1 == text2.Length)
			{
				text2 = "0" + text2;
			}
			string text3 = num3.ToString();
			if (1 == text3.Length)
			{
				text3 = "0" + text3;
			}
			if (num4 > 0)
			{
				return num4 + "d " + text + ":" + text2 + ":" + text3;
			}
			if (num > 0)
			{
				return text + ":" + text2 + ":" + text3;
			}
			return text2 + ":" + text3;
		}

		public static int DecodeTimecodeToMs(string timeCode)
		{
			int result = -1;
			DateTime result2 = default(DateTime);
			bool flag = false;
			if (DateTime.TryParse(timeCode, out result2))
			{
				flag = true;
				result = result2.Millisecond;
				result += result2.Second * 1000;
				result += result2.Minute * 60 * 1000;
				result += result2.Hour * 60 * 60 * 1000;
			}
			else
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				int num5 = 0;
				if (timeCode.Contains(":"))
				{
					flag = true;
					string[] array = timeCode.Split(new char[1] { ':' });
					if (array[^1].Contains("."))
					{
						string[] array2 = array[^1].Split(new char[1] { '.' });
						array[^1] = array2[0];
						num5 = int.Parse(array2[1]);
					}
					num4 = int.Parse(array[^1]);
					num3 = int.Parse(array[^2]);
					if (array.Length >= 3)
					{
						string[] array3 = array[^3].Split(new char[1] { 'd' });
						if (array3.Length > 1)
						{
							num = int.Parse(array3[0].Trim());
							num2 = int.Parse(array3[1].Trim());
						}
						else
						{
							num2 = int.Parse(array3[0]);
						}
					}
					result = num5;
					result += num4 * 1000;
					result += num3 * 60 * 1000;
					result += num2 * 60 * 60 * 1000;
					result += num * 24 * 60 * 60 * 1000;
				}
			}
			if (!flag)
			{
				result = -1;
			}
			return result;
		}

		public static string StripEndingZeroChars(string iStr)
		{
			int num = iStr.Length;
			while (num > 0 && iStr[num - 1] == '\0')
			{
				num--;
			}
			return iStr.Substring(0, num);
		}

		public static string BuildStrictLengthString(int value, int length, char paddingChar, bool padRight = true)
		{
			return BuildStrictLengthString(value.ToString(), length, paddingChar, padRight);
		}

		public static string BuildStrictLengthString(string value, int length, char paddingChar, bool padRight = true)
		{
			string text = ((value == null) ? "" : value);
			if (text.Length > length)
			{
				text = text.Substring(0, length);
			}
			else if (text.Length < length)
			{
				text = ((!padRight) ? text.PadLeft(length, paddingChar) : text.PadRight(length, paddingChar));
			}
			return text;
		}

		public static byte[] BuildStrictLengthStringBytes(string value, int targetLength, byte paddingByte, Encoding encoding, bool padRight = true)
		{
			byte[] bytes = encoding.GetBytes(value);
			while (bytes.Length > targetLength)
			{
				value = value.Remove(value.Length - 1);
				bytes = encoding.GetBytes(value);
			}
			byte[] array;
			if (bytes.Length < targetLength)
			{
				array = new byte[targetLength];
				if (padRight)
				{
					Array.Copy(bytes, array, bytes.Length);
					for (int i = bytes.Length; i < array.Length; i++)
					{
						array[i] = paddingByte;
					}
				}
				else
				{
					Array.Copy(bytes, 0, array, array.Length - bytes.Length, bytes.Length);
					for (int j = 0; j < array.Length - bytes.Length; j++)
					{
						array[j] = paddingByte;
					}
				}
			}
			else
			{
				array = bytes;
			}
			return array;
		}

		public static bool ToBoolean(string value)
		{
			if (value != null)
			{
				value = value.Trim();
				if (value.Length > 0)
				{
					if (float.TryParse(value, out var result))
					{
						return result != 0f;
					}
					value = value.ToLower();
					return "true".Equals(value);
				}
			}
			return false;
		}

		public static byte[] DecodeFrom64(byte[] encodedData)
		{
			if (encodedData.Length % 4 > 0)
			{
				throw new FormatException("Size must me multiple of 4");
			}
			char[] array = new char[encodedData.Length];
			Latin1Encoding.GetChars(encodedData, 0, encodedData.Length, array, 0);
			return Convert.FromBase64CharArray(array, 0, array.Length);
		}

		public static byte[] EncodeTo64(byte[] data)
		{
			long num = (long)(1.3333333333333333 * (double)data.Length);
			if (num % 4 != 0L)
			{
				num += 4 - num % 4;
			}
			char[] array = new char[num];
			Convert.ToBase64CharArray(data, 0, data.Length, array, 0);
			return Latin1Encoding.GetBytes(array);
		}

		public static bool IsNumeric(string s, bool allowsOnlyIntegers = false)
		{
			if (s == null || s.Length == 0)
			{
				return false;
			}
			for (int i = 0; i < s.Length; i++)
			{
				if (s[i] == '.' || s[i] == ',')
				{
					if (allowsOnlyIntegers)
					{
						return false;
					}
				}
				else if (!char.IsDigit(s[i]) && s[i] != '-')
				{
					return false;
				}
			}
			return true;
		}

		public static bool IsDigit(char c)
		{
			if (c >= '0')
			{
				return c <= '9';
			}
			return false;
		}

		public static bool IsHex(string s)
		{
			if (s == null || s.Length == 0)
			{
				return false;
			}
			if (s.Length % 2 > 0)
			{
				return false;
			}
			for (int i = 0; i < s.Length; i++)
			{
				char c = char.ToUpper(s[i]);
				if (!char.IsDigit(c) && c != 'A' && c != 'B' && c != 'C' && c != 'D' && c != 'E' && c != 'F')
				{
					return false;
				}
			}
			return true;
		}

		public static double ParseDouble(string s)
		{
			if (!IsNumeric(s))
			{
				return 0.0;
			}
			string[] array = s.Split(',', '.');
			if (array.Length > 2)
			{
				return 0.0;
			}
			if (1 == array.Length)
			{
				return double.Parse(s);
			}
			double num = Math.Pow(10.0, array[1].Length);
			double num2 = double.Parse(array[0]);
			if (num2 >= 0.0)
			{
				return num2 + double.Parse(array[1]) / num;
			}
			return num2 - double.Parse(array[1]) / num;
		}

		public static string GetBytesReadable(long i)
		{
			long num = ((i < 0) ? (-i) : i);
			string text;
			double num2;
			if (num >= 1152921504606846976L)
			{
				text = "EB";
				num2 = i >> 50;
			}
			else if (num >= 1125899906842624L)
			{
				text = "PB";
				num2 = i >> 40;
			}
			else if (num >= 1099511627776L)
			{
				text = "TB";
				num2 = i >> 30;
			}
			else if (num >= 1073741824)
			{
				text = "GB";
				num2 = i >> 20;
			}
			else if (num >= 1048576)
			{
				text = "MB";
				num2 = i >> 10;
			}
			else
			{
				if (num < 1024)
				{
					return i.ToString("0 B");
				}
				text = "KB";
				num2 = i;
			}
			return (num2 / 1024.0).ToString("0.## ") + text;
		}
	}
}
namespace HashDepot
{
	public static class FNV1a
	{
		public static uint Hash32(byte[] buffer)
		{
			uint num = 2166136261u;
			for (uint num2 = 0u; num2 < buffer.Length; num2++)
			{
				num = 16777619 * (num ^ num2);
			}
			return num;
		}
	}
}
namespace ATL
{
	public static class OggCRC32
	{
		private static readonly uint[] CRC_TABLE = new uint[256]
		{
			0u, 79764919u, 159529838u, 222504665u, 319059676u, 398814059u, 445009330u, 507990021u, 638119352u, 583659535u,
			797628118u, 726387553u, 890018660u, 835552979u, 1015980042u, 944750013u, 1276238704u, 1221641927u, 1167319070u, 1095957929u,
			1595256236u, 1540665371u, 1452775106u, 1381403509u, 1780037320u, 1859660671u, 1671105958u, 1733955601u, 2031960084u, 2111593891u,
			1889500026u, 1952343757u, 2552477408u, 2632100695u, 2443283854u, 2506133561u, 2334638140u, 2414271883u, 2191915858u, 2254759653u,
			3190512472u, 3135915759u, 3081330742u, 3009969537u, 2905550212u, 2850959411u, 2762807018u, 2691435357u, 3560074640u, 3505614887u,
			3719321342u, 3648080713u, 3342211916u, 3287746299u, 3467911202u, 3396681109u, 4063920168u, 4143685023u, 4223187782u, 4286162673u,
			3779000052u, 3858754371u, 3904687514u, 3967668269u, 881225847u, 809987520u, 1023691545u, 969234094u, 662832811u, 591600412u,
			771767749u, 717299826u, 311336399u, 374308984u, 453813921u, 533576470u, 25881363u, 88864420u, 134795389u, 214552010u,
			2023205639u, 2086057648u, 1897238633u, 1976864222u, 1804852699u, 1867694188u, 1645340341u, 1724971778u, 1587496639u, 1516133128u,
			1461550545u, 1406951526u, 1302016099u, 1230646740u, 1142491917u, 1087903418u, 2896545431u, 2825181984u, 2770861561u, 2716262478u,
			3215044683u, 3143675388u, 3055782693u, 3001194130u, 2326604591u, 2389456536u, 2200899649u, 2280525302u, 2578013683u, 2640855108u,
			2418763421u, 2498394922u, 3769900519u, 3832873040u, 3912640137u, 3992402750u, 4088425275u, 4151408268u, 4197601365u, 4277358050u,
			3334271071u, 3263032808u, 3476998961u, 3422541446u, 3585640067u, 3514407732u, 3694837229u, 3640369242u, 1762451694u, 1842216281u,
			1619975040u, 1682949687u, 2047383090u, 2127137669u, 1938468188u, 2001449195u, 1325665622u, 1271206113u, 1183200824u, 1111960463u,
			1543535498u, 1489069629u, 1434599652u, 1363369299u, 622672798u, 568075817u, 748617968u, 677256519u, 907627842u, 853037301u,
			1067152940u, 995781531u, 51762726u, 131386257u, 177728840u, 240578815u, 269590778u, 349224269u, 429104020u, 491947555u,
			4046411278u, 4126034873u, 4172115296u, 4234965207u, 3794477266u, 3874110821u, 3953728444u, 4016571915u, 3609705398u, 3555108353u,
			3735388376u, 3664026991u, 3290680682u, 3236090077u, 3449943556u, 3378572211u, 3174993278u, 3120533705u, 3032266256u, 2961025959u,
			2923101090u, 2868635157u, 2813903052u, 2742672763u, 2604032198u, 2683796849u, 2461293480u, 2524268063u, 2284983834u, 2364738477u,
			2175806836u, 2238787779u, 1569362073u, 1498123566u, 1409854455u, 1355396672u, 1317987909u, 1246755826u, 1192025387u, 1137557660u,
			2072149281u, 2135122070u, 1912620623u, 1992383480u, 1753615357u, 1816598090u, 1627664531u, 1707420964u, 295390185u, 358241886u,
			404320391u, 483945776u, 43990325u, 106832002u, 186451547u, 266083308u, 932423249u, 861060070u, 1041341759u, 986742920u,
			613929101u, 542559546u, 756411363u, 701822548u, 3316196985u, 3244833742u, 3425377559u, 3370778784u, 3601682597u, 3530312978u,
			3744426955u, 3689838204u, 3819031489u, 3881883254u, 3928223919u, 4007849240u, 4037393693u, 4100235434u, 4180117107u, 4259748804u,
			2310601993u, 2373574846u, 2151335527u, 2231098320u, 2596047829u, 2659030626u, 2470359227u, 2550115596u, 2947551409u, 2876312838u,
			2788305887u, 2733848168u, 3165939309u, 3094707162u, 3040238851u, 2985771188u
		};

		public static uint CalculateCRC(uint CRC, byte[] data, uint size)
		{
			for (uint num = 0u; num < size; num++)
			{
				CRC = (CRC << 8) ^ CRC_TABLE[((CRC >> 24) & 0xFF) ^ data[num]];
			}
			return CRC;
		}
	}
	public class ChannelsArrangements
	{
		public class ChannelsArrangement
		{
			public string Description { get; set; }

			public int NbChannels { get; set; }

			public ChannelsArrangement(int nbChannels, string description)
			{
				NbChannels = nbChannels;
				Description = description;
			}

			public ChannelsArrangement(int nbChannels)
			{
				NbChannels = nbChannels;
				Description = nbChannels + " channels";
			}

			public override string ToString()
			{
				return Description;
			}
		}

		public static readonly ChannelsArrangement UNKNOWN = new ChannelsArrangement(0, "Unknown");

		public static readonly ChannelsArrangement ISO_1_0_0 = new ChannelsArrangement(1, "Mono (1/0.0)");

		public static readonly ChannelsArrangement MONO = ISO_1_0_0;

		public static readonly ChannelsArrangement ISO_2_0_0 = new ChannelsArrangement(2, "Stereo (2/0.0)");

		public static readonly ChannelsArrangement STEREO = ISO_2_0_0;

		public static readonly ChannelsArrangement ISO_3_0_0 = new ChannelsArrangement(3, "Center - Left - Right (3/0.0)");

		public static readonly ChannelsArrangement ISO_3_1_0 = new ChannelsArrangement(3, "Left - Right - Center - Center rear (3/1.0)");

		public static readonly ChannelsArrangement ISO_3_2_0 = new ChannelsArrangement(5, "Center - Left - Right - Left surround - Right surround (3/2.0)");

		public static readonly ChannelsArrangement ISO_3_2_1 = new ChannelsArrangement(6, "Center - Left - Right - Left surround - Right surround - Center front LFE (3/2.1) (aka 5.1)");

		public static readonly ChannelsArrangement ISO_5_2_1 = new ChannelsArrangement(6, "Center - Left center - Right center - Left - Right - Left surround - Right surround - Center front LFE (5/2.1)");

		public static readonly ChannelsArrangement ISO_1_1 = new ChannelsArrangement(2, "Dual Mono (1+1)");

		public static readonly ChannelsArrangement DUAL_MONO = ISO_1_1;

		public static readonly ChannelsArrangement ISO_2_1_0 = new ChannelsArrangement(3, "Left front - Right front - Center rear (2/1.0)");

		public static readonly ChannelsArrangement ISO_2_2_0 = new ChannelsArrangement(4, "Left front - Right front - Left rear - Right rear (2/2.0) (aka Quad)");

		public static readonly ChannelsArrangement QUAD = ISO_2_2_0;

		public static readonly ChannelsArrangement ISO_3_3_1 = new ChannelsArrangement(7, "Center front - Left front - Right front - Left surround - Right surround - Center rear - Center front LFE (3/3.1) (aka 6.1)");

		public static readonly ChannelsArrangement ISO_3_4_1 = new ChannelsArrangement(8, "Center front - Left front - Right front - Left surround - Right surround - Left rear - Right rear - Center front LFE (3/4.1)");

		public static readonly ChannelsArrangement ISO_11_11_2 = new ChannelsArrangement(24, "Center front - Left front - Right front - Left outside front - Right outside front - Left side - Right side - Left back - Right back - Center back - Left front LFE - Right front LFE - Top center front - Top left front - Top right front - Top left side - Top right side - Center Ceiling - Top left back - Top right back - Top center back - Bottom center front - Bottom left front - Bottom right front (11/11.2)");

		public static readonly ChannelsArrangement JOINT_STEREO = new ChannelsArrangement(2, "Joint Stereo");

		public static readonly ChannelsArrangement JOINT_STEREO_INTENSITY = new ChannelsArrangement(2, "Joint Stereo - intensity");

		public static readonly ChannelsArrangement JOINT_STEREO_LEFT_SIDE = new ChannelsArrangement(2, "Joint Stereo - left/side");

		public static readonly ChannelsArrangement JOINT_STEREO_RIGHT_SIDE = new ChannelsArrangement(2, "Joint Stereo - right/side");

		public static readonly ChannelsArrangement JOINT_STEREO_MID_SIDE = new ChannelsArrangement(2, "Joint Stereo - mid/side");

		public static readonly ChannelsArrangement STEREO_LEFT_RIGHT_TOTAL = new ChannelsArrangement(2, "Stereo - Left & Right Total (matrix)");

		public static readonly ChannelsArrangement LRCS = new ChannelsArrangement(4, "Left - Right - Center - Surround");

		public static readonly ChannelsArrangement LRCLFECrLssRss = new ChannelsArrangement(7, "Left front - Right front - Center front - LFE - Center rear - Left side - Right side");

		public static readonly ChannelsArrangement LRCLFELrRrLssRss = new ChannelsArrangement(8, "Left front - Right front - Center front - LFE - Left rear - Right rear - Left side - Right side");

		public static readonly ChannelsArrangement LRLcRcCS = new ChannelsArrangement(6, "Left - Right - Left center - Right center - Center - Surround");

		public static readonly ChannelsArrangement LRCLFE = new ChannelsArrangement(4, "Left - Right - Center - LFE");

		public static readonly ChannelsArrangement STEREO_SUM_DIFFERENCE = new ChannelsArrangement(2, "Stereo - Sum & Difference");

		public static readonly ChannelsArrangement CLCRLRSLSR = new ChannelsArrangement(6, "Left center - Right center - Left - Right - Left surround - Right surround");

		public static readonly ChannelsArrangement CLRLRRRO = new ChannelsArrangement(6, "Center - Left - Right - Left rear - Right rear - Overhead");

		public static readonly ChannelsArrangement CFCRLFRFLRRR = new ChannelsArrangement(6, "Center front - Center rear - Left front - Right front - Left rear - Right rear");

		public static readonly ChannelsArrangement CLCCRLRSLSR = new ChannelsArrangement(7, "Left center - Center - Right center - Left - Right - Left surround - Right surround");

		public static readonly ChannelsArrangement CLCRLRSL1SL2SR1SR2 = new ChannelsArrangement(8, "Left center - Right center - Left - Right - Left surround 1 - Left surround 2 - Right surround 1 - Right surround 2");

		public static readonly ChannelsArrangement CLCCRLRSLSSR = new ChannelsArrangement(8, "Left center - Center - Right center - Left - Right - Left surround - Surround - Right surround");

		public static readonly ChannelsArrangement STEREO_XY = new ChannelsArrangement(2, "Stereo - XY");

		public static readonly ChannelsArrangement STEREO_BINAURAL = new ChannelsArrangement(2, "Stereo - Binaural");

		public static readonly ChannelsArrangement AMBISONIC_B = new ChannelsArrangement(4, "Ambisonic B (W, X, Y, Z)");

		public static readonly ChannelsArrangement PENTAGONAL = new ChannelsArrangement(5, "Left front - Right front - Left rear - Right rear - Center");

		public static readonly ChannelsArrangement HEXAGONAL = new ChannelsArrangement(6, "Left - Right - Left rear - Right rear - Center - Rear");

		public static readonly ChannelsArrangement OCTAGONAL = new ChannelsArrangement(8, "Left front - Right front - Left rear - Right rear - Center front - Center rear - Left side - Right side");

		public static readonly ChannelsArrangement CUBE = new ChannelsArrangement(8, "Left - Right - Left rear - Right rear - Left top - Right top - Left top rear - Right top rear");

		public static readonly ChannelsArrangement MPEG_6_1 = new ChannelsArrangement(7, "Left - Right - Center - LFE - Left surround - Right surround - Center surround");

		public static readonly ChannelsArrangement MPEG_7_1 = new ChannelsArrangement(8, "Left - Right - Center - LFE - Left surround - Right surround - Left center - Right center");

		public static readonly ChannelsArrangement SMPTE_DTV = new ChannelsArrangement(8, "Left - Right - Center - LFE - Left surround - Right surround - Left top - Right top");

		public static readonly ChannelsArrangement ITU_2_1 = new ChannelsArrangement(2, "Left - Right - Center surround");

		public static readonly ChannelsArrangement ITU_2_2 = new ChannelsArrangement(4, "Left - Right - Left surround - Right surround");

		public static readonly ChannelsArrangement DVD_4 = new ChannelsArrangement(3, "Left - Right - LFE");

		public static readonly ChannelsArrangement DVD_5 = new ChannelsArrangement(4, "Left - Right - LFE - Center surround");

		public static readonly ChannelsArrangement DVD_6 = new ChannelsArrangement(5, "Left - Right - LFE - Left surround - Right surround");

		public static readonly ChannelsArrangement DVD_10 = new ChannelsArrangement(4, "Left - Right - Center - LFE");

		public static readonly ChannelsArrangement DVD_11 = new ChannelsArrangement(5, "Left - Right - Center - LFE - Center surround");

		public static readonly ChannelsArrangement DVD_18 = new ChannelsArrangement(5, "Left - Right - Left surround - Right surround - LFE");

		public static readonly ChannelsArrangement AUDIOUNIT_6_0 = new ChannelsArrangement(6, "Left - Right - Left surround - Right surround - Center - Center surround");

		public static readonly ChannelsArrangement AUDIOUNIT_7_0 = new ChannelsArrangement(7, "Left - Right - Left surround - Right surround - Center - Left rear surround - Right rear surround");

		public static readonly ChannelsArrangement AAC_6_0 = new ChannelsArrangement(6, "Center - Left - Right - Left surround - Right surround - Center surround");

		public static readonly ChannelsArrangement AAC_6_1 = new ChannelsArrangement(7, "Center - Left - Right - Left surround - Right surround - Center surround - LFE");

		public static readonly ChannelsArrangement AAC_7_0 = new ChannelsArrangement(7, "Center - Left - Right - Left surround - Right surround - Left rear surround - Right rear surround");

		public static readonly ChannelsArrangement AAC_OCTAGONAL = new ChannelsArrangement(8, "Center - Left - Right - Left surround - Right surround - Left rear surround - Right rear surround - Center surround");

		public static readonly ChannelsArrangement TMH_10_2_STD = new ChannelsArrangement(16, "Left - Right - Center - Vertical height center - Left surround direct - Right surround direct - Left surround - Right surround - Vertical height left - Vertical height right - Lw - Rw - Center surround direct - Center surround - LFE1 - LFE2");

		public static readonly ChannelsArrangement TMH_10_2_FULL = new ChannelsArrangement(16, "Left - Right - Center - Vertical height center - Left surround direct - Right surround direct - Left surround - Right surround - Vertical height left - Vertical height right - Lw - Rw - Center surround direct - Center surround - LFE1 - LFE2 - Left center - Right center - Horizontal I - Vertical I - Haptic");

		public static ChannelsArrangement GuessFromChannelNumber(int nbChannels)
		{
			return nbChannels switch
			{
				1 => MONO, 
				2 => STEREO, 
				3 => ISO_3_0_0, 
				4 => QUAD, 
				5 => ISO_3_2_0, 
				6 => ISO_3_2_1, 
				7 => ISO_3_3_1, 
				8 => ISO_3_4_1, 
				_ => new ChannelsArrangement(nbChannels), 
			};
		}
	}
	public class ChapterInfo
	{
		public class UrlInfo
		{
			public string Description { get; set; }

			public string Url { get; set; }

			public UrlInfo(UrlInfo url)
			{
				Description = url.Description;
				Url = url.Url;
			}

			public UrlInfo(string description, string url)
			{
				Description = description;
				Url = url;
			}

			public UrlInfo(string url)
			{
				Description = "";
				Url = url;
			}

			public override string ToString()
			{
				string description = Description;
				char internalValueSeparator = Settings.InternalValueSeparator;
				return description + internalValueSeparator + Url;
			}
		}

		public uint StartTime { get; set; }

		public uint EndTime { get; set; }

		public uint StartOffset { get; set; }

		public uint EndOffset { get; set; }

		public bool UseOffset { get; set; }

		public string Title { get; set; }

		public string UniqueID { get; set; }

		public string Subtitle { get; set; }

		public UrlInfo Url { get; set; }

		public PictureInfo Picture { get; set; }

		public ChapterInfo(uint startTime = 0u, string title = "")
		{
			StartTime = startTime;
			EndTime = 0u;
			StartOffset = 0u;
			EndOffset = 0u;
			UseOffset = false;
			Title = title;
			UniqueID = "";
			Subtitle = "";
			Picture = null;
		}

		public ChapterInfo(ChapterInfo chapter)
		{
			StartTime = chapter.StartTime;
			EndTime = chapter.EndTime;
			StartOffset = chapter.StartOffset;
			EndOffset = chapter.EndOffset;
			Title = chapter.Title;
			Subtitle = chapter.Subtitle;
			Url = chapter.Url;
			UniqueID = chapter.UniqueID;
			if (chapter.Url != null)
			{
				Url = new UrlInfo(chapter.Url);
			}
			if (chapter.Picture != null)
			{
				Picture = new PictureInfo(chapter.Picture);
			}
		}
	}
	public class Format : IEnumerable
	{
		protected IDictionary<string, int> mimeList;

		protected IDictionary<string, int> extList;

		public string Name { get; set; }

		public string ShortName { get; set; }

		public int ID { get; set; }

		public bool Readable { get; set; }

		public ICollection<string> MimeList => mimeList.Keys;

		public Format(int id, string name, string shortName = "")
		{
			init(id, name, (shortName.Length == 0) ? name : shortName);
		}

		public Format(Format f)
		{
			copyFrom(f);
		}

		protected virtual void copyFrom(Format iFormat)
		{
			ID = iFormat.ID;
			Name = iFormat.Name;
			ShortName = iFormat.ShortName;
			mimeList = new Dictionary<string, int>(iFormat.mimeList);
			extList = new Dictionary<string, int>(iFormat.extList);
			Readable = iFormat.Readable;
		}

		protected virtual void init(int id, string name)
		{
			init(id, name, "");
		}

		protected virtual void init(int id, string name, string shortName)
		{
			ID = id;
			Name = name;
			ShortName = ((shortName.Length == 0) ? name : shortName);
			Readable = true;
			extList = new Dictionary<string, int>();
			mimeList = new Dictionary<string, int>();
		}

		public IEnumerator GetEnumerator()
		{
			return extList.Keys.GetEnumerator();
		}

		public void AddMimeType(string mimeType)
		{
			if (!mimeList.ContainsKey(mimeType.ToLower()))
			{
				mimeList.Add(mimeType.ToLower(), 0);
			}
		}

		public bool IsValidMimeType(string mimeType)
		{
			return mimeList.ContainsKey(mimeType.ToLower());
		}

		public void AddExtension(string ext)
		{
			if (!extList.ContainsKey(ext.ToLower()))
			{
				extList.Add(ext.ToLower(), 0);
			}
		}

		public bool IsValidExtension(string ext)
		{
			return extList.ContainsKey(ext.ToLower());
		}
	}
	public class LyricsInfo
	{
		public enum LyricsType
		{
			OTHER,
			LYRICS,
			TRANSCRIPTION,
			MOVEMENT_NAME,
			EVENT,
			CHORD,
			TRIVIA,
			WEBPAGE_URL,
			IMAGE_URL
		}

		public class LyricsPhrase
		{
			public int TimestampMs { get; set; }

			public string Text { get; set; }

			public LyricsPhrase(int timestampMs, string text)
			{
				TimestampMs = timestampMs;
				Text = text;
			}

			public LyricsPhrase(string timestamp, string text)
			{
				TimestampMs = Utils.DecodeTimecodeToMs(timestamp);
				Text = text;
			}
		}

		public LyricsType ContentType { get; set; }

		public string Description { get; set; }

		public string LanguageCode { get; set; }

		public string UnsynchronizedLyrics { get; set; }

		public IList<LyricsPhrase> SynchronizedLyrics { get; set; }

		public LyricsInfo()
		{
			Description = "";
			LanguageCode = "";
			UnsynchronizedLyrics = "";
			ContentType = LyricsType.LYRICS;
			SynchronizedLyrics = new List<LyricsPhrase>();
		}

		public LyricsInfo(LyricsInfo info)
		{
			Description = info.Description;
			LanguageCode = info.LanguageCode;
			UnsynchronizedLyrics = info.UnsynchronizedLyrics;
			ContentType = info.ContentType;
			SynchronizedLyrics = new List<LyricsPhrase>(info.SynchronizedLyrics);
		}
	}
	public class MetaFieldInfo
	{
		public enum ORIGIN
		{
			Unknown,
			Standard,
			UnmappedStandard,
			Comment,
			CustomStandard,
			Custom
		}

		public int TagType;

		public string NativeFieldCode;

		public ushort StreamNumber;

		public string Language;

		public string Value;

		public string Zone;

		public ORIGIN Origin;

		public object SpecificData;

		public bool MarkedForDeletion;

		public MetaFieldInfo(int tagType, string nativeFieldCode, string value = "", ushort streamNumber = 0, string language = "", string zone = "")
		{
			TagType = tagType;
			NativeFieldCode = nativeFieldCode;
			Value = value;
			StreamNumber = streamNumber;
			Language = language;
			Zone = zone;
		}

		public MetaFieldInfo(MetaFieldInfo info)
		{
			TagType = info.TagType;
			NativeFieldCode = info.NativeFieldCode;
			Value = info.Value;
			StreamNumber = info.StreamNumber;
			Language = info.Language;
			Zone = info.Zone;
			Origin = info.Origin;
		}

		public string ToStringWithoutZone()
		{
			return 100 + TagType + NativeFieldCode + Utils.BuildStrictLengthString(StreamNumber.ToString(), 5, '0', padRight: false) + Language;
		}

		public override string ToString()
		{
			return 100 + TagType + NativeFieldCode + Utils.BuildStrictLengthString(StreamNumber.ToString(), 5, '0', padRight: false) + Language + Zone;
		}

		public override int GetHashCode()
		{
			return (int)FNV1a.Hash32(Utils.Latin1Encoding.GetBytes(ToString()));
		}

		public bool EqualsWithoutZone(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (this == obj)
			{
				return true;
			}
			if (obj.GetType() != GetType())
			{
				return false;
			}
			return ToStringWithoutZone().Equals(((MetaFieldInfo)obj).ToStringWithoutZone());
		}

		public bool EqualsApproximate(MetaFieldInfo obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (this == obj)
			{
				return true;
			}
			bool flag = 99 == obj.TagType && obj.NativeFieldCode.Equals(NativeFieldCode);
			if (obj.StreamNumber > 0)
			{
				flag = flag && obj.StreamNumber == StreamNumber;
			}
			if (obj.Language.Length > 0)
			{
				flag = flag && obj.Language.Equals(Language);
			}
			return flag;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (this == obj)
			{
				return true;
			}
			if (obj.GetType() != GetType())
			{
				return false;
			}
			return ToString().Equals(obj.ToString());
		}
	}
	public class PictureInfo
	{
		public enum PIC_TYPE
		{
			Unsupported = 99,
			Generic = 1,
			Front = 2,
			Back = 3,
			CD = 4,
			Icon = 5,
			Leaflet = 6,
			LeadArtist = 7,
			Artist = 8,
			Conductor = 9,
			Band = 10,
			Composer = 11,
			Lyricist = 12,
			RecordingLocation = 13,
			DuringRecording = 14,
			DuringPerformance = 15,
			MovieCapture = 16,
			Fishie = 17,
			Illustration = 18,
			BandLogo = 19,
			PublisherLogo = 20
		}

		public PIC_TYPE PicType;

		public ImageFormat NativeFormat;

		public int Position;

		public int TagType;

		public int NativePicCode;

		public string NativePicCodeStr;

		public string Description = "";

		public uint PictureHash;

		public bool MarkedForDeletion;

		public int TransientFlag;

		public byte[] PictureData { get; private set; }

		public string MimeType => ImageUtils.GetMimeTypeFromImageFormat(NativeFormat);

		public static PictureInfo fromBinaryData(byte[] data, PIC_TYPE picType = PIC_TYPE.Generic, int tagType = 99, object nativePicCode = null, int position = 1)
		{
			if (data == null || data.Length < 3)
			{
				throw new ArgumentException("Data should not be null and be at least 3 bytes long");
			}
			if (nativePicCode == null)
			{
				nativePicCode = 0;
			}
			return new PictureInfo(picType, tagType, nativePicCode, position, data);
		}

		public static PictureInfo fromBinaryData(Stream stream, int length, PIC_TYPE picType, int tagType, object nativePicCode, int position = 1)
		{
			if (stream == null || length < 3)
			{
				throw new ArgumentException("Stream should not be null and be at least 3 bytes long");
			}
			byte[] array = new byte[length];
			stream.Read(array, 0, length);
			return new PictureInfo(picType, tagType, nativePicCode, position, array);
		}

		public PictureInfo(PictureInfo picInfo, bool copyPictureData = true)
		{
			PicType = picInfo.PicType;
			NativeFormat = picInfo.NativeFormat;
			Position = picInfo.Position;
			TagType = picInfo.TagType;
			NativePicCode = picInfo.NativePicCode;
			NativePicCodeStr = picInfo.NativePicCodeStr;
			Description = picInfo.Description;
			if (copyPictureData && picInfo.PictureData != null)
			{
				PictureData = new byte[picInfo.PictureData.Length];
				picInfo.PictureData.CopyTo(PictureData, 0);
			}
			else
			{
				PictureData = picInfo.PictureData;
			}
			PictureHash = picInfo.PictureHash;
			MarkedForDeletion = picInfo.MarkedForDeletion;
			TransientFlag = picInfo.TransientFlag;
		}

		private PictureInfo(PIC_TYPE picType, int tagType, object nativePicCode, int position, byte[] binaryData)
		{
			PicType = picType;
			TagType = tagType;
			Position = position;
			if (nativePicCode is string nativePicCodeStr)
			{
				NativePicCodeStr = nativePicCodeStr;
				NativePicCode = -1;
			}
			else if (nativePicCode is byte)
			{
				NativePicCode = (byte)nativePicCode;
			}
			else if (nativePicCode is int)
			{
				NativePicCode = (int)nativePicCode;
			}
			else
			{
				LogDelegator.GetLogDelegate()(2, "nativePicCode type is not supported; expected byte, int or string; found " + nativePicCode.GetType().Name);
			}
			PictureData = binaryData;
			NativeFormat = ImageUtils.GetImageFormatFromPictureHeader(PictureData);
		}

		public PictureInfo(PIC_TYPE picType, int position = 1)
		{
			PicType = picType;
			NativeFormat = ImageFormat.Undefined;
			Position = position;
		}

		public PictureInfo(int tagType, object nativePicCode, int position = 1)
		{
			PicType = PIC_TYPE.Unsupported;
			NativeFormat = ImageFormat.Undefined;
			TagType = tagType;
			Position = position;
			if (nativePicCode is string nativePicCodeStr)
			{
				NativePicCodeStr = nativePicCodeStr;
				NativePicCode = -1;
			}
			else if (nativePicCode is byte)
			{
				NativePicCode = (byte)nativePicCode;
			}
			else if (nativePicCode is int)
			{
				NativePicCode = (int)nativePicCode;
			}
			else
			{
				LogDelegator.GetLogDelegate()(2, "nativePicCode type is not supported; expected byte, int or string; found " + nativePicCode.GetType().Name);
			}
		}

		public uint ComputePicHash()
		{
			uint pictureHash = 0u;
			if (PictureData != null)
			{
				pictureHash = FNV1a.Hash32(PictureData);
			}
			PictureHash = pictureHash;
			return PictureHash;
		}

		public bool EqualsProper(PictureInfo picInfo)
		{
			if (Position == picInfo.Position)
			{
				if (!equalsNative(picInfo))
				{
					return equalsGeneric(picInfo);
				}
				return true;
			}
			return false;
		}

		private bool equalsNative(PictureInfo picInfo)
		{
			if (TagType == 0 || TagType != picInfo.TagType)
			{
				return false;
			}
			if (NativePicCode > 0 && NativePicCode == picInfo.NativePicCode)
			{
				return true;
			}
			if (NativePicCodeStr != null && NativePicCodeStr.Length > 0 && NativePicCodeStr == picInfo.NativePicCodeStr)
			{
				return true;
			}
			return false;
		}

		private bool equalsGeneric(PictureInfo picInfo)
		{
			if (PIC_TYPE.Unsupported != PicType)
			{
				return PicType == picInfo.PicType;
			}
			return false;
		}

		public override string ToString()
		{
			return Utils.BuildStrictLengthString(Position.ToString(), 2, '0', padRight: false) + valueToString();
		}

		private string valueToString()
		{
			if (NativePicCode > 0 && TagType > 0)
			{
				return (10000000 * TagType + "N" + NativePicCode).ToString();
			}
			if (NativePicCodeStr != null && NativePicCodeStr.Length > 0 && TagType > 0)
			{
				return 10000000 * TagType + "N" + NativePicCodeStr;
			}
			if (PicType != PIC_TYPE.Unsupported)
			{
				int picType = (int)PicType;
				return "T" + Utils.BuildStrictLengthString(picType.ToString(), 2, '0', padRight: false);
			}
			LogDelegator.GetLogDelegate()(2, "Non-supported picture detected, but no native picture code found");
			return "";
		}

		public override int GetHashCode()
		{
			return (int)FNV1a.Hash32(Utils.Latin1Encoding.GetBytes(ToString()));
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (this == obj)
			{
				return true;
			}
			if (obj.GetType() != GetType())
			{
				return false;
			}
			return ToString().Equals(obj.ToString());
		}
	}
	public class TagData
	{
		public const byte TAG_FIELD_GENERAL_DESCRIPTION = 0;

		public const byte TAG_FIELD_TITLE = 1;

		public const byte TAG_FIELD_ARTIST = 2;

		public const byte TAG_FIELD_COMPOSER = 3;

		public const byte TAG_FIELD_COMMENT = 4;

		public const byte TAG_FIELD_GENRE = 5;

		public const byte TAG_FIELD_ALBUM = 6;

		public const byte TAG_FIELD_RECORDING_YEAR = 7;

		public const byte TAG_FIELD_RECORDING_DATE = 8;

		public const byte TAG_FIELD_RECORDING_YEAR_OR_DATE = 9;

		public const byte TAG_FIELD_RECORDING_TIME = 10;

		public const byte TAG_FIELD_RECORDING_DAYMONTH = 11;

		public const byte TAG_FIELD_TRACK_NUMBER = 12;

		public const byte TAG_FIELD_DISC_NUMBER = 13;

		public const byte TAG_FIELD_RATING = 14;

		public const byte TAG_FIELD_ORIGINAL_ARTIST = 15;

		public const byte TAG_FIELD_ORIGINAL_ALBUM = 16;

		public const byte TAG_FIELD_COPYRIGHT = 17;

		public const byte TAG_FIELD_ALBUM_ARTIST = 18;

		public const byte TAG_FIELD_PUBLISHER = 19;

		public const byte TAG_FIELD_CONDUCTOR = 20;

		public const byte TAG_FIELD_TRACK_TOTAL = 21;

		public const byte TAG_FIELD_TRACK_NUMBER_TOTAL = 22;

		public const byte TAG_FIELD_DISC_TOTAL = 23;

		public const byte TAG_FIELD_DISC_NUMBER_TOTAL = 24;

		public const byte TAG_FIELD_CHAPTERS_TOC_DESCRIPTION = 25;

		public const byte TAG_FIELD_LYRICS_UNSYNCH = 26;

		public const byte TAG_FIELD_LYRICS_SYNCH = 27;

		public const byte TAG_FIELD_PUBLISHING_DATE = 28;

		public string GeneralDescription;

		public string Title;

		public string Artist;

		public string OriginalArtist;

		public string Composer;

		public string Comment;

		public string Genre;

		public string Album;

		public string OriginalAlbum;

		public string RecordingYear;

		public string RecordingDayMonth;

		public string RecordingTime;

		public string RecordingDate;

		public string TrackNumber;

		public string DiscNumber;

		public string Rating;

		public string Copyright;

		public string AlbumArtist;

		public string Publisher;

		public string Conductor;

		public string TrackTotal;

		public string TrackNumberTotal;

		public string DiscTotal;

		public string DiscNumberTotal;

		public string ChaptersTableDescription;

		public string PublishingDate;

		public IList<ChapterInfo> Chapters;

		public LyricsInfo Lyrics;

		public IList<PictureInfo> Pictures;

		public IList<MetaFieldInfo> AdditionalFields;

		public int TrackDigitsForLeadingZeroes;

		public int DiscDigitsForLeadingZeroes;

		public long DataSizeDelta;

		public long PaddingSize = -1L;

		public double DurationMs;

		public string this[byte index] => ToMap()[index];

		public TagData()
		{
			Pictures = new List<PictureInfo>();
			AdditionalFields = new List<MetaFieldInfo>();
		}

		public TagData(TagData tagData)
		{
			Pictures = new List<PictureInfo>();
			AdditionalFields = new List<MetaFieldInfo>();
			IntegrateValues(tagData);
		}

		public void IntegrateValue(byte key, string value)
		{
			switch (key)
			{
			case 0:
				GeneralDescription = value;
				break;
			case 1:
				Title = value;
				break;
			case 2:
				Artist = value;
				break;
			case 3:
				Composer = value;
				break;
			case 4:
				Comment = value;
				break;
			case 5:
				Genre = value;
				break;
			case 6:
				Album = value;
				break;
			case 15:
				OriginalArtist = value;
				break;
			case 16:
				OriginalAlbum = value;
				break;
			case 17:
				Copyright = value;
				break;
			case 18:
				AlbumArtist = value;
				break;
			case 19:
				Publisher = value;
				break;
			case 20:
				Conductor = value;
				break;
			case 8:
				RecordingDate = emptyIfZero(value);
				break;
			case 7:
				RecordingYear = emptyIfZero(value);
				break;
			case 9:
				if (value != null)
				{
					if (value.Length < 5)
					{
						RecordingYear = emptyIfZero(value);
					}
					else
					{
						RecordingDate = emptyIfZero(value);
					}
				}
				break;
			case 11:
				RecordingDayMonth = emptyIfZero(value);
				break;
			case 10:
				RecordingTime = emptyIfZero(value);
				break;
			case 12:
				TrackNumber = emptyIfZero(value);
				break;
			case 13:
				DiscNumber = emptyIfZero(value);
				break;
			case 14:
				Rating = emptyIfZero(value);
				break;
			case 21:
				TrackTotal = emptyIfZero(value);
				break;
			case 22:
				TrackNumberTotal = emptyIfZero(value);
				break;
			case 23:
				DiscTotal = emptyIfZero(value);
				break;
			case 24:
				DiscNumberTotal = emptyIfZero(value);
				break;
			case 25:
				ChaptersTableDescription = emptyIfZero(value);
				break;
			case 26:
				if (Lyrics == null)
				{
					Lyrics = new LyricsInfo();
				}
				Lyrics.UnsynchronizedLyrics = value;
				break;
			case 28:
				PublishingDate = emptyIfZero(value);
				break;
			case 27:
				break;
			}
		}

		public void IntegrateValues(TagData targetData, bool integratePictures = true, bool mergeAdditionalData = true)
		{
			IDictionary<byte, string> dictionary = targetData.ToMap();
			foreach (byte key in dictionary.Keys)
			{
				IntegrateValue(key, dictionary[key]);
			}
			if (targetData.PaddingSize > -1)
			{
				PaddingSize = targetData.PaddingSize;
			}
			else
			{
				PaddingSize = -1L;
			}
			if (integratePictures && targetData.Pictures != null)
			{
				IList<PictureInfo> list = new List<PictureInfo>();
				foreach (PictureInfo picture in targetData.Pictures)
				{
					picture.ComputePicHash();
					int num = 0;
					bool flag = false;
					foreach (PictureInfo picture2 in Pictures)
					{
						picture2.ComputePicHash();
						if (!picture2.EqualsProper(picture))
						{
							continue;
						}
						if (picture.MarkedForDeletion)
						{
							picture2.MarkedForDeletion = true;
							flag = true;
							list.Add(picture2);
							continue;
						}
						num = Math.Max(num, picture2.Position);
						if (picture2.PictureHash == 0 || picture2.PictureHash != picture.PictureHash)
						{
							continue;
						}
						flag = true;
						PictureInfo pictureInfo = picture2;
						if (picture.Description != picture2.Description)
						{
							pictureInfo = new PictureInfo(picture2, copyPictureData: false);
							pictureInfo.Description = picture.Description;
						}
						list.Add(pictureInfo);
						break;
					}
					if (!flag)
					{
						picture.Position = num + 1;
						list.Add(picture);
					}
				}
				for (int num2 = Pictures.Count - 1; num2 >= 0; num2--)
				{
					bool flag2 = false;
					foreach (PictureInfo picture3 in targetData.Pictures)
					{
						if (picture3.EqualsProper(Pictures[num2]))
						{
							flag2 = true;
							break;
						}
					}
					if (!flag2)
					{
						list.Insert(0, Pictures[num2]);
					}
				}
				Pictures = list;
			}
			if (mergeAdditionalData)
			{
				foreach (MetaFieldInfo additionalField in targetData.AdditionalFields)
				{
					bool flag3 = false;
					foreach (MetaFieldInfo additionalField2 in AdditionalFields)
					{
						if (additionalField2.EqualsWithoutZone(additionalField) || additionalField2.EqualsApproximate(additionalField))
						{
							if (!additionalField.MarkedForDeletion)
							{
								flag3 = true;
								additionalField2.Value = additionalField.Value;
								break;
							}
							additionalField2.MarkedForDeletion = true;
						}
					}
					if (!additionalField.MarkedForDeletion && !flag3)
					{
						AdditionalFields.Add(additionalField);
					}
					else if (additionalField.MarkedForDeletion && !flag3)
					{
						LogDelegator.GetLogDelegate()(2, "Field code " + additionalField.NativeFieldCode + " cannot be deleted because it has not been found on current TagData.");
					}
				}
			}
			else
			{
				AdditionalFields = new List<MetaFieldInfo>(targetData.AdditionalFields);
			}
			if (targetData.Chapters != null)
			{
				if (Chapters != null)
				{
					Chapters.Clear();
				}
				else
				{
					Chapters = new List<ChapterInfo>();
				}
				foreach (ChapterInfo chapter in targetData.Chapters)
				{
					Chapters.Add(new ChapterInfo(chapter));
				}
			}
			if (targetData.Lyrics != null)
			{
				Lyrics = new LyricsInfo(targetData.Lyrics);
			}
			DurationMs = targetData.DurationMs;
		}

		public bool hasKey(byte id)
		{
			return ToMap().ContainsKey(id);
		}

		public IDictionary<byte, string> ToMap()
		{
			IDictionary<byte, string> dictionary = new Dictionary<byte, string>();
			addIfConsistent(Artist, 2, dictionary);
			addIfConsistent(Title, 1, dictionary);
			addIfConsistent(Album, 6, dictionary);
			addIfConsistent(RecordingDate, 8, dictionary);
			addIfConsistent(RecordingYear, 7, dictionary);
			addIfConsistent(RecordingDate, 9, dictionary);
			addIfConsistent(RecordingYear, 9, dictionary);
			addIfConsistent(RecordingDayMonth, 11, dictionary);
			addIfConsistent(RecordingTime, 10, dictionary);
			addIfConsistent(Genre, 5, dictionary);
			addIfConsistent(Composer, 3, dictionary);
			addIfConsistent(AlbumArtist, 18, dictionary);
			addIfConsistent(TrackNumber, 12, dictionary);
			addIfConsistent(TrackNumberTotal, 22, dictionary);
			addIfConsistent(TrackTotal, 21, dictionary);
			addIfConsistent(DiscNumber, 13, dictionary);
			addIfConsistent(DiscNumberTotal, 24, dictionary);
			addIfConsistent(DiscTotal, 23, dictionary);
			addIfConsistent(Comment, 4, dictionary);
			addIfConsistent(Rating, 14, dictionary);
			addIfConsistent(OriginalArtist, 15, dictionary);
			addIfConsistent(OriginalAlbum, 16, dictionary);
			addIfConsistent(Copyright, 17, dictionary);
			addIfConsistent(Publisher, 19, dictionary);
			addIfConsistent(Conductor, 20, dictionary);
			addIfConsistent(GeneralDescription, 0, dictionary);
			addIfConsistent(ChaptersTableDescription, 25, dictionary);
			if (Lyrics != null)
			{
				addIfConsistent(Lyrics.UnsynchronizedLyrics, 26, dictionary);
			}
			addIfConsistent(PublishingDate, 28, dictionary);
			return dictionary;
		}

		public void Clear()
		{
			Pictures.Clear();
			AdditionalFields.Clear();
			if (Chapters != null)
			{
				Chapters.Clear();
			}
			GeneralDescription = null;
			Title = null;
			Artist = null;
			OriginalArtist = null;
			Composer = null;
			Comment = null;
			Genre = null;
			Album = null;
			OriginalAlbum = null;
			RecordingYear = null;
			RecordingDayMonth = null;
			RecordingTime = null;
			RecordingDate = null;
			TrackNumber = null;
			DiscNumber = null;
			Rating = null;
			Copyright = null;
			AlbumArtist = null;
			Publisher = null;
			Conductor = null;
			TrackTotal = null;
			TrackNumberTotal = null;
			DiscTotal = null;
			DiscNumberTotal = null;
			ChaptersTableDescription = null;
			Lyrics = null;
			PublishingDate = null;
			TrackDigitsForLeadingZeroes = 0;
			DiscDigitsForLeadingZeroes = 0;
			PaddingSize = -1L;
			DurationMs = 0.0;
		}

		public void Cleanup()
		{
			if (TrackNumber != null)
			{
				if (TrackNumber.Contains("/"))
				{
					TrackNumberTotal = TrackNumber;
					string[] array = TrackNumber.Split(new char[1] { '/' });
					TrackNumber = array[0];
					TrackTotal = array[1];
				}
				else if (Utils.IsNumeric(TrackNumber))
				{
					TrackNumberTotal = TrackNumber;
					if (Utils.IsNumeric(TrackTotal))
					{
						TrackNumberTotal = TrackNumberTotal + "/" + TrackTotal;
					}
				}
				else
				{
					TrackNumberTotal = "";
				}
			}
			if (DiscNumber != null)
			{
				if (DiscNumber.Contains("/"))
				{
					DiscNumberTotal = DiscNumber;
					string[] array2 = DiscNumber.Split(new char[1] { '/' });
					DiscNumber = array2[0];
					DiscTotal = array2[1];
				}
				else if (Utils.IsNumeric(DiscNumber))
				{
					DiscNumberTotal = DiscNumber;
					if (Utils.IsNumeric(DiscTotal))
					{
						DiscNumberTotal = DiscNumberTotal + "/" + DiscTotal;
					}
				}
				else
				{
					DiscNumberTotal = "";
				}
			}
			if (Chapters == null || Chapters.Count <= 0)
			{
				return;
			}
			if (Chapters[0].UseOffset)
			{
				Chapters = Chapters.OrderBy((ChapterInfo chapter) => chapter.StartOffset).ToList();
			}
			else
			{
				Chapters = Chapters.OrderBy((ChapterInfo chapter) => chapter.StartTime).ToList();
			}
			ChapterInfo chapterInfo = null;
			foreach (ChapterInfo chapter in Chapters)
			{
				if (chapterInfo != null)
				{
					if (chapter.UseOffset && (chapterInfo.EndOffset == 0 || chapterInfo.EndOffset != chapter.StartOffset))
					{
						chapterInfo.EndOffset = chapter.StartOffset;
					}
					else if (chapterInfo.EndTime == 0 || chapterInfo.EndTime != chapter.StartTime)
					{
						chapterInfo.EndTime = chapter.StartTime;
					}
				}
				chapterInfo = chapter;
			}
			if (chapterInfo != null && chapterInfo.EndTime == 0)
			{
				chapterInfo.EndTime = (uint)Math.Round(DurationMs);
			}
		}

		private void addIfConsistent(string data, byte id, IDictionary<byte, string> map)
		{
			if (data != null)
			{
				map[id] = data;
			}
		}

		private string emptyIfZero(string s)
		{
			string result = s;
			if (s != null && s.Equals("0"))
			{
				result = "";
			}
			return result;
		}

		private IDictionary<PictureInfo, int> generatePicturePositions()
		{
			IDictionary<PictureInfo, int> dictionary = new Dictionary<PictureInfo, int>();
			foreach (PictureInfo picture in Pictures)
			{
				if (dictionary.ContainsKey(picture))
				{
					dictionary[picture] = Math.Max(dictionary[picture], picture.Position);
				}
				else
				{
					dictionary.Add(picture, picture.Position);
				}
			}
			return dictionary;
		}
	}
	public class TechnicalInfo
	{
		public long AudioDataOffset { get; }

		public long AudioDataSize { get; }

		public TechnicalInfo(long audioDataOffset, long audioDataSize)
		{
			AudioDataOffset = audioDataOffset;
			AudioDataSize = audioDataSize;
		}
	}
	public class Track
	{
		private const string InMemoryPath = "In-memory";

		public readonly string Path;

		private ICollection<string> initialAdditionalFields;

		private ICollection<PictureInfo> initialEmbeddedPictures;

		private readonly IProgress<float> writeProgress;

		private readonly Stream stream;

		private readonly string mimeType;

		private AudioFileIO fileIO;

		public string Title { get; set; }

		public string Artist { get; set; }

		public string Composer { get; set; }

		public string Comment { get; set; }

		public string Genre { get; set; }

		public string Album { get; set; }

		public string OriginalAlbum { get; set; }

		public string OriginalArtist { get; set; }

		public string Copyright { get; set; }

		public string Description { get; set; }

		public string Publisher { get; set; }

		public DateTime PublishingDate { get; set; }

		public string AlbumArtist { get; set; }

		public string Conductor { get; set; }

		public DateTime Date { get; set; }

		public int Year
		{
			get
			{
				if (Date == DateTime.MinValue)
				{
					return 0;
				}
				return Date.Year;
			}
			set
			{
				if (value > 0)
				{
					Date = new DateTime(value, 1, 1);
				}
				else
				{
					Date = DateTime.MinValue;
				}
			}
		}

		public int TrackNumber { get; set; }

		public int TrackTotal { get; set; }

		public int DiscNumber { get; set; }

		public int DiscTotal { get; set; }

		public float Popularity { get; set; }

		public IList<PictureInfo> PictureTokens { get; set; }

		public string ChaptersTableDescription { get; set; }

		public IList<ChapterInfo> Chapters { get; set; }

		public LyricsInfo Lyrics { get; set; }

		public IDictionary<string, string> AdditionalFields { get; set; }

		private IList<PictureInfo> currentEmbeddedPictures { get; set; }

		public int Bitrate { get; internal set; }

		public double SampleRate { get; internal set; }

		public bool IsVBR { get; internal set; }

		public int CodecFamily { get; internal set; }

		public Format AudioFormat { get; internal set; }

		public IList<Format> MetadataFormats { get; internal set; }

		public int Duration => (int)Math.Round(DurationMs / 1000.0);

		public double DurationMs { get; internal set; }

		public ChannelsArrangements.ChannelsArrangement ChannelsArrangement { get; internal set; }

		public TechnicalInfo TechnicalInformation { get; internal set; }

		public IList<PictureInfo> EmbeddedPictures => getEmbeddedPictures();

		public Track()
		{
		}

		public Track(string path, IProgress<float> writeProgress = null, bool load = true)
		{
			Path = path;
			stream = null;
			this.writeProgress = writeProgress;
			if (load)
			{
				Update();
			}
		}

		public Track(string path, bool load)
		{
			Path = path;
			stream = null;
			writeProgress = null;
			if (load)
			{
				Update();
			}
		}

		public Track(Stream stream, string mimeType, IProgress<float> writeProgress = null)
		{
			this.stream = stream;
			this.mimeType = mimeType;
			Path = "In-memory";
			this.writeProgress = writeProgress;
			Update();
		}

		private IList<PictureInfo> getEmbeddedPictures()
		{
			if (currentEmbeddedPictures == null)
			{
				currentEmbeddedPictures = new List<PictureInfo>();
				initialEmbeddedPictures = new List<PictureInfo>();
				Update(onlyReadEmbeddedPictures: true);
			}
			return currentEmbeddedPictures;
		}

		protected void Update(bool onlyReadEmbeddedPictures = false)
		{
			if (string.IsNullOrEmpty(Path))
			{
				return;
			}
			if (stream == null)
			{
				fileIO = new AudioFileIO(Path, onlyReadEmbeddedPictures, Settings.ReadAllMetaFrames, writeProgress);
			}
			else
			{
				fileIO = new AudioFileIO(stream, mimeType, onlyReadEmbeddedPictures, Settings.ReadAllMetaFrames, writeProgress);
			}
			if (onlyReadEmbeddedPictures)
			{
				foreach (PictureInfo embeddedPicture in fileIO.EmbeddedPictures)
				{
					embeddedPicture.ComputePicHash();
					currentEmbeddedPictures.Add(embeddedPicture);
					PictureInfo item = new PictureInfo(embeddedPicture, copyPictureData: false);
					initialEmbeddedPictures.Add(item);
				}
				return;
			}
			if (currentEmbeddedPictures != null)
			{
				currentEmbeddedPictures.Clear();
				initialEmbeddedPictures.Clear();
				currentEmbeddedPictures = null;
				initialEmbeddedPictures = null;
			}
			MetadataFormats = new List<Format>(fileIO.MetadataFormats);
			Title = fileIO.Title;
			if (Settings.UseFileNameWhenNoTitle && (Title == null || "" == Title) && Path != "In-memory")
			{
				Title = System.IO.Path.GetFileNameWithoutExtension(Path);
			}
			Artist = Utils.ProtectValue(fileIO.Artist);
			Composer = Utils.ProtectValue(fileIO.Composer);
			Comment = Utils.ProtectValue(fileIO.Comment);
			Genre = Utils.ProtectValue(fileIO.Genre);
			OriginalArtist = Utils.ProtectValue(fileIO.OriginalArtist);
			OriginalAlbum = Utils.ProtectValue(fileIO.OriginalAlbum);
			Description = Utils.ProtectValue(fileIO.GeneralDescription);
			Copyright = Utils.ProtectValue(fileIO.Copyright);
			Publisher = Utils.ProtectValue(fileIO.Publisher);
			PublishingDate = fileIO.PublishingDate;
			AlbumArtist = Utils.ProtectValue(fileIO.AlbumArtist);
			Conductor = Utils.ProtectValue(fileIO.Conductor);
			Date = fileIO.Date;
			Album = fileIO.Album;
			TrackNumber = fileIO.Track;
			TrackTotal = fileIO.TrackTotal;
			DiscNumber = fileIO.Disc;
			DiscTotal = fileIO.DiscTotal;
			ChaptersTableDescription = Utils.ProtectValue(fileIO.ChaptersTableDescription);
			Chapters = fileIO.Chapters;
			Lyrics = fileIO.Lyrics;
			AdditionalFields = fileIO.AdditionalFields;
			initialAdditionalFields = fileIO.AdditionalFields.Keys;
			PictureTokens = new List<PictureInfo>(fileIO.PictureTokens);
			Bitrate = fileIO.IntBitRate;
			CodecFamily = fileIO.CodecFamily;
			AudioFormat = fileIO.AudioFormat;
			DurationMs = fileIO.Duration;
			Popularity = fileIO.Popularity;
			IsVBR = fileIO.IsVBR;
			SampleRate = fileIO.SampleRate;
			ChannelsArrangement = fileIO.ChannelsArrangement;
			TechnicalInformation = new TechnicalInfo(fileIO.AudioDataOffset, fileIO.AudioDataSize);
		}

		private TagData toTagData()
		{
			TagData tagData = new TagData();
			tagData.Title = Title;
			tagData.Artist = Artist;
			tagData.Composer = Composer;
			tagData.Comment = Comment;
			tagData.Genre = Genre;
			tagData.OriginalArtist = OriginalArtist;
			tagData.OriginalAlbum = OriginalAlbum;
			tagData.GeneralDescription = Description;
			tagData.Rating = (Popularity * 5f).ToString();
			tagData.Copyright = Copyright;
			tagData.Publisher = Publisher;
			if (!PublishingDate.Equals(DateTime.MinValue))
			{
				tagData.PublishingDate = TrackUtils.FormatISOTimestamp(PublishingDate);
			}
			else
			{
				tagData.PublishingDate = "0";
			}
			tagData.AlbumArtist = AlbumArtist;
			tagData.Conductor = Conductor;
			if (!Date.Equals(DateTime.MinValue))
			{
				tagData.RecordingDate = TrackUtils.FormatISOTimestamp(Date);
			}
			else
			{
				tagData.RecordingDate = "0";
			}
			tagData.RecordingYear = Year.ToString();
			tagData.Album = Album;
			tagData.TrackNumber = TrackNumber.ToString();
			tagData.TrackTotal = TrackTotal.ToString();
			tagData.DiscNumber = DiscNumber.ToString();
			tagData.DiscTotal = DiscTotal.ToString();
			tagData.ChaptersTableDescription = ChaptersTableDescription.ToString();
			tagData.Chapters = new List<ChapterInfo>();
			foreach (ChapterInfo chapter in Chapters)
			{
				tagData.Chapters.Add(new ChapterInfo(chapter));
			}
			if (Lyrics != null)
			{
				tagData.Lyrics = new LyricsInfo(Lyrics);
			}
			foreach (string key in AdditionalFields.Keys)
			{
				tagData.AdditionalFields.Add(new MetaFieldInfo(99, key, AdditionalFields[key], 0));
			}
			foreach (string initialAdditionalField in initialAdditionalFields)
			{
				if (!AdditionalFields.ContainsKey(initialAdditionalField))
				{
					MetaFieldInfo metaFieldInfo = new MetaFieldInfo(99, initialAdditionalField, "", 0);
					metaFieldInfo.MarkedForDeletion = true;
					tagData.AdditionalFields.Add(metaFieldInfo);
				}
			}
			tagData.Pictures = new List<PictureInfo>();
			if (initialEmbeddedPictures != null && currentEmbeddedPictures != null)
			{
				foreach (PictureInfo currentEmbeddedPicture in currentEmbeddedPictures)
				{
					bool flag = false;
					foreach (PictureInfo initialEmbeddedPicture in initialEmbeddedPictures)
					{
						if (currentEmbeddedPicture.EqualsProper(initialEmbeddedPicture))
						{
							tagData.Pictures.Add(currentEmbeddedPicture);
							currentEmbeddedPicture.ComputePicHash();
							if (currentEmbeddedPicture.PictureHash != initialEmbeddedPicture.PictureHash)
							{
								PictureInfo pictureInfo = new PictureInfo(initialEmbeddedPicture);
								pictureInfo.MarkedForDeletion = true;
								tagData.Pictures.Add(pictureInfo);
							}
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						tagData.Pictures.Add(currentEmbeddedPicture);
					}
				}
				foreach (PictureInfo initialEmbeddedPicture2 in initialEmbeddedPictures)
				{
					if (!currentEmbeddedPictures.Contains(initialEmbeddedPicture2))
					{
						PictureInfo pictureInfo2 = new PictureInfo(initialEmbeddedPicture2);
						pictureInfo2.MarkedForDeletion = true;
						tagData.Pictures.Add(pictureInfo2);
					}
				}
			}
			return tagData;
		}

		public bool Save()
		{
			bool num = fileIO.Save(toTagData());
			if (num)
			{
				Update();
			}
			return num;
		}

		public bool Remove(int tagType = 99)
		{
			bool num = fileIO.Remove(tagType);
			if (num)
			{
				Update();
			}
			return num;
		}
	}
	public abstract class Factory
	{
		public static readonly Format UNKNOWN_FORMAT = new Format(-1, "Unknown");

		protected IDictionary<string, IList<Format>> formatListByExt;

		protected IDictionary<string, IList<Format>> formatListByMime;

		protected void addFormat(Format f)
		{
			foreach (string item in f)
			{
				if (!formatListByExt.ContainsKey(item))
				{
					IList<Format> list = new List<Format>();
					list.Add(f);
					formatListByExt.Add(item, list);
				}
				else
				{
					IList<Format> list = formatListByExt[item];
					list.Add(f);
				}
			}
			foreach (string mime in f.MimeList)
			{
				if (!formatListByMime.ContainsKey(mime))
				{
					IList<Format> list = new List<Format>();
					list.Add(f);
					formatListByMime.Add(mime, list);
				}
				else
				{
					IList<Format> list = formatListByMime[mime];
					list.Add(f);
				}
			}
		}

		public IList<Format> getFormatsFromPath(string path)
		{
			IList<Format> result = null;
			string key = ((!path.Contains(".")) ? path : path.Substring(path.LastIndexOf('.'), path.Length - path.LastIndexOf('.')).ToLower());
			if (formatListByExt.ContainsKey(key))
			{
				IList<Format> list = formatListByExt[key];
				if (list != null && list.Count > 0)
				{
					result = list;
				}
			}
			return result;
		}

		public IList<Format> getFormatsFromMimeType(string mimeType)
		{
			IList<Format> result = null;
			string key = mimeType.ToLower();
			if (formatListByMime.ContainsKey(key))
			{
				IList<Format> list = formatListByMime[key];
				if (list != null && list.Count > 0)
				{
					result = list;
				}
			}
			return result;
		}

		public ICollection<Format> getFormats()
		{
			Dictionary<int, Format> dictionary = new Dictionary<int, Format>();
			foreach (IList<Format> value in formatListByExt.Values)
			{
				foreach (Format item in value)
				{
					if (!dictionary.ContainsKey(item.ID))
					{
						dictionary.Add(item.ID, item);
					}
				}
			}
			return dictionary.Values;
		}
	}
	public static class Settings
	{
		public static int FileBufferSize = 512;

		public static bool ForceDiskIO = false;

		public static bool AddNewPadding = false;

		public static int PaddingSize = 2048;

		internal static readonly char InternalValueSeparator = '\u02f5';

		public static char DisplayValueSeparator = ';';

		public static bool ReadAllMetaFrames = true;

		public static Encoding DefaultTextEncoding = Encoding.UTF8;

		public static int[] DefaultTagsWhenNoMetadata = new int[2] { 1, 3 };

		public static bool UseFileNameWhenNoTitle = true;

		public static bool UseLeadingZeroes = false;

		public static bool OverrideExistingLeadingZeroesFormat = false;

		public static bool EnrichID3v1 = true;

		public static bool ID3v2_useExtendedHeaderRestrictions = false;

		public static bool ID3v2_alwaysWriteCTOCFrame = true;

		public static byte ID3v2_tagSubVersion = 4;

		public static bool ID3v2_forceAPICEncodingToLatin1 = true;

		public static bool ID3v2_forceUnsynchronization = false;

		public static bool MP4_createNeroChapters = true;

		public static bool MP4_createQuicktimeChapters = true;

		public static bool MP4_keepExistingChapters = true;

		public static int MP4_readChaptersExclusive = 0;

		public static bool ASF_keepNonWMFieldsWhenRemovingTag = false;

		public static int GYM_VGM_playbackRate = 0;

		public static bool M3U_useExtendedFormat = true;
	}
	public sealed class BufferedBinaryReader : Stream, IDisposable
	{
		private const int DEFAULT_BUFFER_SIZE = 512;

		private readonly Stream stream;

		private readonly int bufferDefaultSize;

		private readonly long streamSize;

		private byte[] buffer;

		private long bufferOffset;

		private int cursorPosition;

		private long streamPosition;

		private int bufferSize;

		public override long Position
		{
			get
			{
				return bufferOffset + cursorPosition;
			}
			set
			{
				Seek(value, SeekOrigin.Begin);
			}
		}

		public override long Length => streamSize;

		public override bool CanRead => true;

		public override bool CanSeek => true;

		public override bool CanWrite => false;

		public BufferedBinaryReader(Stream stream)
		{
			this.stream = stream;
			bufferDefaultSize = 512;
			buffer = new byte[bufferDefaultSize];
			streamSize = stream.Length;
			streamPosition = stream.Position;
			bufferOffset = streamPosition;
		}

		public BufferedBinaryReader(Stream stream, int bufferSize)
		{
			this.stream = stream;
			bufferDefaultSize = bufferSize;
			buffer = new byte[bufferSize];
			streamSize = stream.Length;
			streamPosition = stream.Position;
			bufferOffset = streamPosition;
		}

		private bool fillBuffer(int previousBytesToKeep = 0)
		{
			if (previousBytesToKeep > 0)
			{
				Array.Copy(buffer, cursorPosition, buffer, 0, previousBytesToKeep);
			}
			int num = (int)Math.Min(bufferDefaultSize - previousBytesToKeep, streamSize - streamPosition - previousBytesToKeep);
			if (num > 0)
			{
				bufferOffset = streamPosition;
				stream.Read(buffer, previousBytesToKeep, num);
				streamPosition += num;
				bufferSize = num;
				cursorPosition = 0;
				return true;
			}
			return false;
		}

		private void prepareBuffer(int bytesToRead)
		{
			if (bufferSize - cursorPosition < bytesToRead)
			{
				fillBuffer(Math.Max(0, bufferSize - cursorPosition));
			}
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			long num = 0L;
			if (origin.Equals(SeekOrigin.Current))
			{
				num = offset;
			}
			else if (origin.Equals(SeekOrigin.Begin))
			{
				num = offset - Position;
			}
			else if (origin.Equals(SeekOrigin.End))
			{
				num = streamSize + offset - Position;
			}
			if (num == 0L)
			{
				return Position;
			}
			if (num < 0)
			{
				if (cursorPosition + num < bufferSize && cursorPosition + num >= 0)
				{
					cursorPosition += (int)num;
				}
				else
				{
					streamPosition = bufferOffset + cursorPosition + num;
					stream.Position = streamPosition;
					fillBuffer();
				}
			}
			else if (cursorPosition + num < bufferSize)
			{
				cursorPosition += (int)num;
			}
			else
			{
				streamPosition = bufferOffset + cursorPosition + num;
				stream.Position = streamPosition;
				fillBuffer();
			}
			return Position;
		}

		public override int Read([In][Out] byte[] buffer, int offset, int count)
		{
			if (count <= bufferSize - cursorPosition)
			{
				prepareBuffer(count);
				Array.Copy(this.buffer, cursorPosition, buffer, offset, count);
				cursorPosition += count;
				return count;
			}
			int num = bufferSize - cursorPosition;
			if (num > 0)
			{
				Array.Copy(this.buffer, cursorPosition, buffer, offset, num);
			}
			else
			{
				num = 0;
			}
			int num2 = stream.Read(buffer, offset + num, count - num);
			streamPosition += num2;
			stream.Position = streamPosition;
			cursorPosition += num + num2;
			return num + num2;
		}

		public byte[] ReadBytes(int nbBytes)
		{
			byte[] result = new byte[nbBytes];
			Read(result, 0, nbBytes);
			return result;
		}

		public new byte ReadByte()
		{
			prepareBuffer(1);
			byte result = buffer[cursorPosition];
			cursorPosition++;
			return result;
		}

		public ushort ReadUInt16()
		{
			prepareBuffer(2);
			ushort result = (ushort)(buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8));
			cursorPosition += 2;
			return result;
		}

		public short ReadInt16()
		{
			prepareBuffer(2);
			short result = (short)(buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8));
			cursorPosition += 2;
			return result;
		}

		public uint ReadUInt32()
		{
			prepareBuffer(4);
			int result = buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8) | (buffer[cursorPosition + 2] << 16) | (buffer[cursorPosition + 3] << 24);
			cursorPosition += 4;
			return (uint)result;
		}

		public int ReadInt32()
		{
			prepareBuffer(4);
			int result = buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8) | (buffer[cursorPosition + 2] << 16) | (buffer[cursorPosition + 3] << 24);
			cursorPosition += 4;
			return result;
		}

		public ulong ReadUInt64()
		{
			prepareBuffer(8);
			ulong result = buffer[cursorPosition] | ((ulong)buffer[cursorPosition + 1] << 8) | ((ulong)buffer[cursorPosition + 2] << 16) | ((ulong)buffer[cursorPosition + 3] << 24) | ((ulong)buffer[cursorPosition + 4] << 32) | ((ulong)buffer[cursorPosition + 5] << 40) | ((ulong)buffer[cursorPosition + 6] << 48) | ((ulong)buffer[cursorPosition + 7] << 56);
			cursorPosition += 8;
			return result;
		}

		public long ReadInt64()
		{
			prepareBuffer(8);
			ulong result = buffer[cursorPosition] | ((ulong)buffer[cursorPosition + 1] << 8) | ((ulong)buffer[cursorPosition + 2] << 16) | ((ulong)buffer[cursorPosition + 3] << 24) | ((ulong)buffer[cursorPosition + 4] << 32) | ((ulong)buffer[cursorPosition + 5] << 40) | ((ulong)buffer[cursorPosition + 6] << 48) | ((ulong)buffer[cursorPosition + 7] << 56);
			cursorPosition += 8;
			return (long)result;
		}

		public new void Dispose()
		{
			Flush();
			stream.Close();
		}

		public override void Flush()
		{
			buffer = null;
		}

		public override void SetLength(long value)
		{
			throw new NotImplementedException();
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			throw new NotImplementedException();
		}
	}
	public static class StreamUtils
	{
		public delegate void StreamHandlerDelegate(ref MemoryStream stream);

		public static bool StringEqualsArr(string a, char[] b)
		{
			return ArrEqualsArr(a.ToCharArray(), b);
		}

		private static bool ArrEqualsArr(char[] a, char[] b)
		{
			if (b.Length != a.Length)
			{
				return false;
			}
			for (int i = 0; i < b.Length; i++)
			{
				if (a[i] != b[i])
				{
					return false;
				}
			}
			return true;
		}

		public static bool ArrEqualsArr(byte[] a, byte[] b)
		{
			if (b.Length != a.Length)
			{
				return false;
			}
			for (int i = 0; i < b.Length; i++)
			{
				if (a[i] != b[i])
				{
					return false;
				}
			}
			return true;
		}

		public static void CopyStream(Stream from, Stream to, int length = 0)
		{
			byte[] buffer = new byte[Settings.FileBufferSize];
			int num = 0;
			while (true)
			{
				int count = ((length <= 0) ? Settings.FileBufferSize : ((num + Settings.FileBufferSize >= length) ? (length - num) : Settings.FileBufferSize));
				int num2 = from.Read(buffer, 0, count);
				if (num2 != 0)
				{
					to.Write(buffer, 0, num2);
					num += num2;
					continue;
				}
				break;
			}
		}

		public static void CopySameStream(Stream s, long offsetFrom, long offsetTo, int length)
		{
			CopySameStream(s, offsetFrom, offsetTo, length, Settings.FileBufferSize);
		}

		public static void CopySameStream(Stream s, long offsetFrom, long offsetTo, int length, int bufferSize)
		{
			if (offsetFrom == offsetTo)
			{
				return;
			}
			byte[] buffer = new byte[bufferSize];
			int i = 0;
			bool flag = offsetTo > offsetFrom;
			int num;
			for (; i < length; i += num)
			{
				num = Math.Min(bufferSize, length - i);
				if (flag)
				{
					s.Seek(offsetFrom + length - i - num, SeekOrigin.Begin);
					s.Read(buffer, 0, num);
					s.Seek(offsetTo + length - i - num, SeekOrigin.Begin);
				}
				else
				{
					s.Seek(offsetFrom + i, SeekOrigin.Begin);
					s.Read(buffer, 0, num);
					s.Seek(offsetTo + i, SeekOrigin.Begin);
				}
				s.Write(buffer, 0, num);
			}
		}

		public static void ShortenStream(Stream s, long endOffset, uint delta)
		{
			CopySameStream(s, endOffset, endOffset - delta, (int)(s.Length - endOffset));
			s.SetLength(s.Length - delta);
		}

		public static void LengthenStream(Stream s, long oldIndex, uint delta, bool fillZeroes = false)
		{
			long num = oldIndex + delta;
			CopySameStream(s, oldIndex, oldIndex + delta, (int)(s.Length - oldIndex));
			if (fillZeroes)
			{
				s.Seek(oldIndex, SeekOrigin.Begin);
				for (long num2 = oldIndex; num2 < num; num2++)
				{
					s.WriteByte(0);
				}
			}
		}

		public static sbyte DecodeSignedByte(byte[] data)
		{
			if (data.Length < 1)
			{
				throw new InvalidDataException("Data should be at least 1 bytes long; found " + data.Length + " bytes");
			}
			return (sbyte)data[0];
		}

		public static byte DecodeUByte(byte[] data)
		{
			if (data.Length < 1)
			{
				throw new InvalidDataException("Data should be at least 1 bytes long; found " + data.Length + " bytes");
			}
			return data[0];
		}

		public static ushort DecodeBEUInt16(byte[] data)
		{
			if (data.Length < 2)
			{
				throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes");
			}
			return (ushort)((data[0] << 8) | data[1]);
		}

		public static byte[] EncodeBEUInt16(ushort value)
		{
			return new byte[2]
			{
				(byte)((value & 0xFF00) >> 8),
				(byte)(value & 0xFFu)
			};
		}

		public static ushort DecodeUInt16(byte[] data)
		{
			if (data.Length < 2)
			{
				throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes");
			}
			return (ushort)(data[0] | (data[1] << 8));
		}

		public static short DecodeInt16(byte[] data)
		{
			if (data.Length < 2)
			{
				throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes");
			}
			return (short)(data[0] | (data[1] << 8));
		}

		public static byte[] EncodeBEInt16(short value)
		{
			return new byte[2]
			{
				(byte)((value & 0xFF00) >> 8),
				(byte)((uint)value & 0xFFu)
			};
		}

		public static short DecodeBEInt16(byte[] data)
		{
			if (data.Length < 2)
			{
				throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes");
			}
			return (short)((data[0] << 8) | data[1]);
		}

		public static int DecodeBEInt24(byte[] data)
		{
			if (data.Length < 3)
			{
				throw new InvalidDataException("Data should be at least 3 bytes long; found " + data.Length + " bytes");
			}
			return (data[0] << 16) | (data[1] << 8) | data[2];
		}

		public static uint DecodeBEUInt24(byte[] data, int offset = 0)
		{
			if (data.Length - offset < 3)
			{
				throw new InvalidDataException("Value should at least contain 3 bytes after offset; actual size=" + (data.Length - offset) + " bytes");
			}
			return (uint)((data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]);
		}

		public static byte[] EncodeBEUInt24(uint value)
		{
			if (value > 16777215)
			{
				throw new InvalidDataException("Value should not be higher than " + 16777215 + "; actual value=" + value);
			}
			return new byte[3]
			{
				(byte)((value & 0xFF0000) >> 16),
				(byte)((value & 0xFF00) >> 8),
				(byte)(value & 0xFFu)
			};
		}

		public static uint DecodeBEUInt32(byte[] data)
		{
			if (data.Length < 4)
			{
				throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes");
			}
			return (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
		}

		public static uint DecodeUInt32(byte[] data)
		{
			if (data.Length < 4)
			{
				throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes");
			}
			return (uint)(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
		}

		public static byte[] EncodeBEUInt32(uint value)
		{
			return new byte[4]
			{
				(byte)((value & 0xFF000000u) >> 24),
				(byte)((value & 0xFF0000) >> 16),
				(byte)((value & 0xFF00) >> 8),
				(byte)(value & 0xFFu)
			};
		}

		public static int DecodeBEInt32(byte[] data)
		{
			if (data.Length < 4)
			{
				throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes");
			}
			return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
		}

		public static byte[] EncodeBEInt32(int value)
		{
			return new byte[4]
			{
				(byte)((value & 0xFF000000u) >> 24),
				(byte)((value & 0xFF0000) >> 16),
				(byte)((value & 0xFF00) >> 8),
				(byte)((uint)value & 0xFFu)
			};
		}

		public static int DecodeInt32(byte[] data)
		{
			if (data.Length < 4)
			{
				throw new InvalidDataException("data should be at least 4 bytes long; found " + data.Length + " bytes");
			}
			return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
		}

		public static ulong DecodeUInt64(byte[] data)
		{
			if (data.Length < 8)
			{
				throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes");
			}
			return data[0] | ((ulong)data[1] << 8) | ((ulong)data[2] << 16) | ((ulong)data[3] << 24) | ((ulong)data[4] << 32) | ((ulong)data[5] << 40) | ((ulong)data[6] << 48) | ((ulong)data[7] << 56);
		}

		public static long DecodeBEInt64(byte[] data)
		{
			if (data.Length < 8)
			{
				throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes");
			}
			return (long)(((ulong)data[0] << 56) | ((ulong)data[1] << 48) | ((ulong)data[2] << 40) | ((ulong)data[3] << 32) | ((ulong)data[4] << 24) | ((ulong)data[5] << 16) | ((ulong)data[6] << 8) | data[7]);
		}

		public static byte[] EncodeBEUInt64(ulong value)
		{
			return new byte[8]
			{
				(byte)((value & 0xFF00000000000000uL) >> 56),
				(byte)((value & 0xFF000000000000L) >> 48),
				(byte)((value & 0xFF0000000000L) >> 40),
				(byte)((value & 0xFF00000000L) >> 32),
				(byte)((value & 0xFF000000u) >> 24),
				(byte)((value & 0xFF0000) >> 16),
				(byte)((value & 0xFF00) >> 8),
				(byte)(value & 0xFF)
			};
		}

		public static double DecodeBEDouble(byte[] data)
		{
			if (data.Length < 8)
			{
				throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes");
			}
			if (BitConverter.IsLittleEndian)
			{
				Array.Reverse((Array)data);
			}
			return BitConverter.ToDouble(data, 0);
		}

		public static int ReverseInt32(int n)
		{
			byte num = (byte)(n & 0xFF);
			byte b = (byte)((n & 0xFF00) >> 8);
			byte b2 = (byte)((n & 0xFF0000) >> 16);
			byte b3 = (byte)((n & 0xFF000000u) >> 24);
			return (num << 24) | (b << 16) | (b2 << 8) | b3;
		}

		public static Encoding GetEncodingFromFileBOM(FileStream file)
		{
			byte[] array = new byte[4];
			file.Read(array, 0, 4);
			Encoding result = ((array[0] == 239 && array[1] == 187 && array[2] == 191) ? Encoding.UTF8 : ((array[0] == 254 && array[1] == byte.MaxValue) ? Encoding.BigEndianUnicode : ((array[0] == byte.MaxValue && array[1] == 254) ? Encoding.Unicode : ((array[0] != 0 || array[1] != 0 || array[2] != 254 || array[3] != byte.MaxValue) ? Settings.DefaultTextEncoding : Encoding.UTF32))));
			file.Seek(0L, SeekOrigin.Begin);
			return result;
		}

		public static string ReadNullTerminatedString(BinaryReader r, Encoding encoding)
		{
			return readNullTerminatedString(r.BaseStream, encoding, 0, moveStreamToLimit: false);
		}

		public static string ReadNullTerminatedString(Stream s, Encoding encoding)
		{
			return readNullTerminatedString(s, encoding, 0, moveStreamToLimit: false);
		}

		public static string ReadNullTerminatedStringFixed(BinaryReader r, Encoding encoding, int limit)
		{
			return readNullTerminatedString(r.BaseStream, encoding, limit, moveStreamToLimit: true);
		}

		public static string ReadNullTerminatedStringFixed(BufferedBinaryReader r, Encoding encoding, int limit)
		{
			return readNullTerminatedString(r, encoding, limit, moveStreamToLimit: true);
		}

		private static string readNullTerminatedString(Stream r, Encoding encoding, int limit, bool moveStreamToLimit)
		{
			int num = ((!encoding.Equals(Encoding.BigEndianUnicode) && !encoding.Equals(Encoding.Unicode)) ? 1 : 2);
			byte[] array = new byte[(limit > 0) ? limit : 100];
			byte[] array2 = new byte[2];
			int num2 = 0;
			long length = r.Length;
			long position = r.Position;
			for (long num3 = position; num3 < length; num3 += num)
			{
				if (limit != 0 && num2 >= limit)
				{
					break;
				}
				r.Read(array2, 0, num);
				if ((1 == num && array2[0] == 0) || (2 == num && array2[0] == 0 && array2[1] == 0))
				{
					break;
				}
				if (array.Length < num2 + num)
				{
					Array.Resize(ref array, array.Length + 100);
				}
				array[num2] = array2[0];
				if (2 == num)
				{
					array[num2 + 1] = array2[1];
				}
				num2 += num;
			}
			if (moveStreamToLimit)
			{
				r.Seek(position + limit, SeekOrigin.Begin);
			}
			return encoding.GetString(array, 0, num2);
		}

		public static int DecodeSynchSafeInt(byte[] bytes)
		{
			if (bytes.Length > 5)
			{
				throw new ArgumentException("Array too long : has to be 1 to 5 bytes; found : " + bytes.Length + " bytes");
			}
			int num = 0;
			for (int i = 0; i < bytes.Length; i++)
			{
				num += bytes[i] * (int)Math.Floor(Math.Pow(2.0, 7 * (bytes.Length - 1 - i)));
			}
			return num;
		}

		public static int DecodeSynchSafeInt32(byte[] data)
		{
			if (data.Length != 4)
			{
				throw new ArgumentException("Array length has to be 4 bytes; found : " + data.Length + " bytes");
			}
			return data[0] * 2097152 + data[1] * 16384 + data[2] * 128 + data[3];
		}

		public static byte[] EncodeSynchSafeInt(int value, int nbBytes)
		{
			if (nbBytes < 1 || nbBytes > 5)
			{
				throw new ArgumentException("nbBytes has to be 1 to 5; found : " + nbBytes);
			}
			byte[] array = new byte[nbBytes];
			for (int i = 0; i < nbBytes; i++)
			{
				int num = 7 * (nbBytes - 1 - i);
				array[i] = (byte)((value & (127 << num)) >> num);
			}
			return array;
		}

		public static byte[] EncodeSynchSafeInt32(int value)
		{
			return new byte[4]
			{
				(byte)((value & 0xFE00000) >> 21),
				(byte)((value & 0x1FC000) >> 14),
				(byte)((value & 0x3F80) >> 7),
				(byte)((uint)value & 0x7Fu)
			};
		}

		public static bool FindSequence(Stream stream, byte[] sequence, long limit = 0L)
		{
			int num = 512;
			byte[] array = new byte[num];
			int num2 = 0;
			int num3 = 0;
			long position = stream.Position;
			int num4 = (int)((limit > 0) ? Math.Min(stream.Length - stream.Position, limit) : (stream.Length - stream.Position));
			while (num4 > 0)
			{
				int num5 = Math.Min(num4, num);
				stream.Read(array, 0, num5);
				for (int i = 0; i < num5; i++)
				{
					if (sequence[num2] == array[i])
					{
						num2++;
					}
					else if (num2 > 0)
					{
						num2 = 0;
					}
					if (sequence.Length == num2)
					{
						stream.Position = position + num3 + i + 1;
						return true;
					}
				}
				num4 -= num5;
				num3 += num5;
			}
			stream.Position = position;
			return false;
		}

		public static uint ReadBits(BinaryReader source, int bitPosition, int bitCount)
		{
			if (bitCount < 1 || bitCount > 32)
			{
				throw new NotSupportedException("Bit count must be between 1 and 32");
			}
			source.BaseStream.Seek(bitPosition / 8, SeekOrigin.Begin);
			byte[] array = source.ReadBytes(4);
			return (uint)((array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3] << bitPosition % 8) >> 32 - bitCount;
		}

		public static double ExtendedToDouble(byte[] extended)
		{
			int s = extended[9] >> 7;
			int num = ((extended[9] & 0x7F) << 8) | extended[8];
			int num2 = extended[7] >> 7;
			long num3 = extended[7] & 0x7F;
			for (int num4 = 6; num4 >= 0; num4--)
			{
				num3 = (num3 << 8) | extended[num4];
			}
			if (num2 == 1)
			{
				switch (num)
				{
				case 0:
					return FromComponents(s, 0, 0L);
				default:
					num3 >>= 11;
					num += -15360;
					if (num > 2047)
					{
						return double.NaN;
					}
					if (num < 0)
					{
						if (num >= -51)
						{
							num3 |= 0x100000;
							num3 >>= 1 - num;
							return FromComponents(s, 0, num3);
						}
						return FromComponents(s, 0, 0L);
					}
					return FromComponents(s, num, num3);
				case 32767:
					if (num3 == 0L)
					{
						return FromComponents(s, 2047, 0L);
					}
					return double.NaN;
				}
			}
			if (num == 0)
			{
				return FromComponents(s, 0, 0L);
			}
			return double.NaN;
		}

		private static double FromComponents(int s, int e, long f)
		{
			byte[] array = new byte[8];
			if (BitConverter.IsLittleEndian)
			{
				array[7] = (byte)((s << 7) | (e >> 4));
				array[6] = (byte)(((e & 0xF) << 4) | (int)(f >> 48));
				array[5] = (byte)((f & 0xFF0000000000L) >> 40);
				array[4] = (byte)((f & 0xFF00000000L) >> 32);
				array[3] = (byte)((f & 0xFF000000u) >> 24);
				array[2] = (byte)((f & 0xFF0000) >> 16);
				array[1] = (byte)((f & 0xFF00) >> 8);
				array[0] = (byte)(f & 0xFF);
			}
			else
			{
				array[0] = (byte)((s << 7) | (e >> 4));
				array[1] = (byte)(((e & 0xF) << 4) | (int)(f >> 48));
				array[2] = (byte)((f & 0xFF0000000000L) >> 40);
				array[3] = (byte)((f & 0xFF00000000L) >> 32);
				array[4] = (byte)((f & 0xFF000000u) >> 24);
				array[5] = (byte)((f & 0xFF0000) >> 16);
				array[6] = (byte)((f & 0xFF00) >> 8);
				array[7] = (byte)(f & 0xFF);
			}
			return BitConverter.ToDouble(array, 0);
		}

		public static long TraversePadding(Stream source)
		{
			byte[] array = new byte[Settings.FileBufferSize];
			long position = source.Position;
			int num = 0;
			for (int num2 = source.Read(array, 0, Settings.FileBufferSize); num2 > 0; num2 = source.Read(array, 0, Settings.FileBufferSize))
			{
				for (int i = 0; i < num2; i++)
				{
					if (array[i] > 0)
					{
						return position + num + i;
					}
				}
				num += num2;
			}
			return position + num;
		}
	}
	public static class Version
	{
		public static string getVersion()
		{
			return Assembly.GetExecutingAssembly().GetName().Version.ToString();
		}
	}
}
namespace ATL.Playlist
{
	public interface IPlaylistIO
	{
		string Path { get; set; }

		PlaylistFormat.LocationFormatting LocationFormatting { get; set; }

		PlaylistFormat.FileEncoding Encoding { get; set; }

		IList<string> FilePaths { get; set; }

		IList<Track> Tracks { get; set; }
	}
	public class PlaylistFormat : Format
	{
		public enum LocationFormatting
		{
			Undefined = -1,
			FilePath,
			Winamp_URI,
			MS_URI,
			RFC_URI
		}

		public enum FileEncoding
		{
			Undefined = -1,
			UTF8_BOM,
			UTF8_NO_BOM,
			ANSI
		}

		public LocationFormatting LocationFormat { get; set; }

		public FileEncoding Encoding { get; set; }

		public PlaylistFormat(int ID, string iName)
			: base(ID, iName)
		{
		}

		public PlaylistFormat(PlaylistFormat f)
			: base(f)
		{
		}

		protected override void copyFrom(Format iFormat)
		{
			base.copyFrom(iFormat);
			LocationFormat = ((PlaylistFormat)iFormat).LocationFormat;
			Encoding = ((PlaylistFormat)iFormat).Encoding;
		}

		protected override void init(int id, string name)
		{
			base.init(id, name);
			LocationFormat = LocationFormatting.FilePath;
			Encoding = FileEncoding.UTF8_BOM;
		}
	}
	public abstract class PlaylistIO : IPlaylistIO
	{
		public static readonly byte[] BOM_UTF8 = new byte[3] { 239, 187, 191 };

		protected static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

		protected static readonly Encoding ANSI = Utils.Latin1Encoding;

		public string Path { get; set; }

		public PlaylistFormat.LocationFormatting LocationFormatting { get; set; }

		public PlaylistFormat.FileEncoding Encoding { get; set; }

		public IList<string> FilePaths
		{
			get
			{
				return getFiles();
			}
			set
			{
				setFiles(value);
			}
		}

		public IList<Track> Tracks
		{
			get
			{
				return getTracks();
			}
			set
			{
				setTracks(value);
			}
		}

		protected abstract void getFiles(FileStream fs, IList<string> result);

		protected abstract void setTracks(FileStream fs, IList<Track> result);

		public IList<string> getFiles()
		{
			IList<string> result = new List<string>();
			LogDelegator.GetLocateDelegate()(Path);
			try
			{
				using FileStream fs = new FileStream(Path, FileMode.Open, FileAccess.Read);
				getFiles(fs, result);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.StackTrace);
				LogDelegator.GetLogDelegate()(1, ex.Message);
			}
			return result;
		}

		public IList<Track> getTracks()
		{
			IList<Track> list = new List<Track>();
			try
			{
				foreach (string file in getFiles())
				{
					list.Add(new Track(file));
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.StackTrace);
				LogDelegator.GetLogDelegate()(1, ex.Message);
			}
			return list;
		}

		public void setFiles(IList<string> fileList)
		{
			IList<Track> list = new List<Track>();
			foreach (string file in fileList)
			{
				Track item = new Track(file, null, load: false);
				list.Add(item);
			}
			setTracks(list);
		}

		public void setTracks(IList<Track> trackList)
		{
			LogDelegator.GetLocateDelegate()(Path);
			try
			{
				using FileStream fileStream = new FileStream(Path, FileMode.Create, FileAccess.ReadWrite);
				if (Encoding.Equals(PlaylistFormat.FileEncoding.UTF8_BOM))
				{
					fileStream.Write(BOM_UTF8, 0, 3);
				}
				setTracks(fileStream, trackList);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.StackTrace);
				LogDelegator.GetLogDelegate()(1, ex.Message);
			}
		}

		protected XmlWriterSettings generateWriterSettings()
		{
			XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
			xmlWriterSettings.CloseOutput = true;
			if (Encoding == PlaylistFormat.FileEncoding.ANSI)
			{
				xmlWriterSettings.Encoding = ANSI;
			}
			else
			{
				xmlWriterSettings.Encoding = UTF8_NO_BOM;
			}
			xmlWriterSettings.OmitXmlDeclaration = true;
			xmlWriterSettings.ConformanceLevel = ConformanceLevel.Fragment;
			xmlWriterSettings.Indent = true;
			xmlWriterSettings.DoNotEscapeUriAttributes = false;
			return xmlWriterSettings;
		}

		protected string encodeLocation(string location)
		{
			switch (LocationFormatting)
			{
			case PlaylistFormat.LocationFormatting.RFC_URI:
			{
				Uri uri = new Uri(location, UriKind.RelativeOrAbsolute);
				if (!uri.IsAbsoluteUri)
				{
					return uri.OriginalString;
				}
				return uri.AbsoluteUri;
			}
			case PlaylistFormat.LocationFormatting.MS_URI:
				return "file://" + location;
			case PlaylistFormat.LocationFormatting.Winamp_URI:
				return "file:" + location;
			default:
				return location;
			}
		}

		protected void decodeLocation(XmlReader source, string attributeName, IList<string> result)
		{
			string text = decodeLocation(source.GetAttribute(attributeName));
			if (text != null)
			{
				result.Add(text);
			}
		}

		protected string decodeLocation(string href)
		{
			string text = href.Replace('\\', '/');
			if (text.Contains("://"))
			{
				try
				{
					Uri uri = new Uri(text);
					if (uri.IsFile)
					{
						if (!System.IO.Path.IsPathRooted(uri.LocalPath))
						{
							return System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), uri.LocalPath);
						}
						string localPath = uri.LocalPath;
						char directorySeparatorChar = System.IO.Path.DirectorySeparatorChar;
						string text2 = directorySeparatorChar.ToString();
						directorySeparatorChar = System.IO.Path.DirectorySeparatorChar;
						string oldValue = text2 + directorySeparatorChar;
						directorySeparatorChar = System.IO.Path.DirectorySeparatorChar;
						return localPath.Replace(oldValue, directorySeparatorChar.ToString() ?? "");
					}
				}
				catch (UriFormatException)
				{
					LogDelegator.GetLogDelegate()(2, text + " is not a valid URI [" + Path + "]");
				}
			}
			href = href.Replace("file:///", "").Replace("file://", "").Replace("file:", "");
			if (!System.IO.Path.IsPathRooted(href))
			{
				href = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), href);
			}
			return href;
		}
	}
	public class PlaylistIOFactory : Factory
	{
		public const int PL_M3U = 0;

		public const int PL_PLS = 1;

		public const int PL_FPL = 2;

		public const int PL_XSPF = 3;

		public const int PL_SMIL = 4;

		public const int PL_ASX = 5;

		public const int PL_B4S = 6;

		private static PlaylistIOFactory theFactory = null;

		private static readonly object _lockable = new object();

		public static PlaylistIOFactory GetInstance()
		{
			lock (_lockable)
			{
				if (theFactory == null)
				{
					theFactory = new PlaylistIOFactory();
					theFactory.formatListByExt = new Dictionary<string, IList<Format>>();
					PlaylistFormat playlistFormat = new PlaylistFormat(0, "M3U");
					playlistFormat.AddExtension(".m3u");
					playlistFormat.AddExtension(".m3u8");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(1, "PLS");
					playlistFormat.AddExtension(".pls");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(2, "FPL (experimental)");
					playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.MS_URI;
					playlistFormat.AddExtension(".fpl");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(3, "XSPF (spiff)");
					playlistFormat.AddExtension(".xspf");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(4, "SMIL");
					playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.RFC_URI;
					playlistFormat.AddExtension(".smil");
					playlistFormat.AddExtension(".smi");
					playlistFormat.AddExtension(".zpl");
					playlistFormat.AddExtension(".wpl");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(5, "ASX");
					playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.FilePath;
					playlistFormat.AddExtension(".asx");
					playlistFormat.AddExtension(".wax");
					playlistFormat.AddExtension(".wvx");
					theFactory.addFormat(playlistFormat);
					playlistFormat = new PlaylistFormat(6, "B4S");
					playlistFormat.