context: /*
      Copyright (C) 2014-2019 de4dot@gmail.com
  
      This file is part of dnSpy
  
      dnSpy is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      dnSpy is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with dnSpy.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  using System;
  using System.Linq;
  using System.Windows.Input;
  using dnlib.DotNet;
  using dnSpy.AsmEditor.DnlibDialogs;
  using dnSpy.AsmEditor.ViewHelpers;
  using dnSpy.Contracts.Decompiler;
  using dnSpy.Contracts.MVVM;
  
  namespace dnSpy.AsmEditor.Assembly {
  	enum AsmProcArch {
  		None = (int)((uint)AssemblyAttributes.PA_None >> (int)AssemblyAttributes.PA_Shift),
  		MSIL = (int)((uint)AssemblyAttributes.PA_MSIL >> (int)AssemblyAttributes.PA_Shift),
  		x86 = (int)((uint)AssemblyAttributes.PA_x86 >> (int)AssemblyAttributes.PA_Shift),
  		IA64 = (int)((uint)AssemblyAttributes.PA_IA64 >> (int)AssemblyAttributes.PA_Shift),
  		AMD64 = (int)((uint)AssemblyAttributes.PA_AMD64 >> (int)AssemblyAttributes.PA_Shift),
  		ARM = (int)((uint)AssemblyAttributes.PA_ARM >> (int)AssemblyAttributes.PA_Shift),
  		Reserved = 6,
  		NoPlatform = (int)((uint)AssemblyAttributes.PA_NoPlatform >> (int)AssemblyAttributes.PA_Shift),
  	}
  
  	enum AsmContType {
  		Default = (int)((uint)AssemblyAttributes.ContentType_Default >> 9),
  		WindowsRuntime = (int)((uint)AssemblyAttributes.ContentType_WindowsRuntime >> 9),
  	}
  
  	sealed class AssemblyOptionsVM : ViewModelBase {
  		readonly AssemblyOptions origOptions;
  
  		public IOpenPublicKeyFile OpenPublicKeyFile {
  			set => openPublicKeyFile = value;
  		}
  		IOpenPublicKeyFile? openPublicKeyFile;
  
  		public ICommand OpenPublicKeyFileCommand => new RelayCommand(a => OnOpenPublicKeyFile());
  		public ICommand ReinitializeCommand => new RelayCommand(a => Reinitialize());
  
  		public bool CanShowClrVersion {
  			get => canShowClrVersion;
  			set {
  				if (canShowClrVersion != value) {
  					canShowClrVersion = value;
  					OnPropertyChanged(nameof(CanShowClrVersion));
  				}
  			}
  		}
  		bool canShowClrVersion;
  
  		public EnumListVM ClrVersion => clrVersionVM;
  		readonly EnumListVM clrVersionVM = new EnumListVM(Module.NetModuleOptionsVM.clrVersionList);
  
  		static readonly EnumVM[] hashAlgorithmList = EnumVM.Create(typeof(AssemblyHashAlgorithm));
  		public EnumListVM HashAlgorithm => hashAlgorithmVM;
  		readonly EnumListVM hashAlgorithmVM;
  
  		public UInt16VM VersionMajor { get; }
  		public UInt16VM VersionMinor { get; }
  		public UInt16VM VersionBuild { get; }
  		public UInt16VM VersionRevision { get; }
  
  		public AssemblyAttributes Flags {
  			get => (flags & ~(AssemblyAttributes.PA_Mask | AssemblyAttributes.ContentType_Mask) |
  					((AssemblyAttributes)((uint)(AsmProcArch)ProcessArchitecture.SelectedItem! << (int)AssemblyAttributes.PA_Shift) & AssemblyAttributes.PA_Mask) |
  					((AssemblyAttributes)((uint)(AsmContType)ContentType.SelectedItem! << 9) & AssemblyAttributes.ContentType_Mask));
  			set {
  				if (flags != value) {
  					flags = value;
  					OnPropertyChanged(nameof(AssemblyFullName));
  					OnPropertyChanged(nameof(Flags));
  					OnPropertyChanged(nameof(FlagsPublicKey));
  					OnPropertyChanged(nameof(PA_Specified));
  					OnPropertyChanged(nameof(Retargetable));
  					OnPropertyChanged(nameof(EnableJITcompileTracking));
  					OnPropertyChanged(nameof(DisableJITcompileOptimizer));
  					ProcessArchitecture.SelectedItem = (AsmProcArch)((uint)(flags & AssemblyAttributes.PA_Mask) >> (int)AssemblyAttributes.PA_Shift);
  					ContentType.SelectedItem = (AsmContType)((uint)(flags & AssemblyAttributes.ContentType_Mask) >> 9);
  				}
  			}
  		}
  		AssemblyAttributes flags;
  
  		public bool FlagsPublicKey {
  			get => GetFlagValue(AssemblyAttributes.PublicKey);
  			set => SetFlagValue(AssemblyAttributes.PublicKey, value);
  		}
  
  		public bool PA_Specified {
  			get => GetFlagValue(AssemblyAttributes.PA_Specified);
  			set => SetFlagValue(AssemblyAttributes.PA_Specified, value);
  		}
  
  		public bool Retargetable {
  			get => GetFlagValue(AssemblyAttributes.Retargetable);
  			set => SetFlagValue(AssemblyAttributes.Retargetable, value);
  		}
  
  		public bool EnableJITcompileTracking {
  			get => GetFlagValue(AssemblyAttributes.EnableJITcompileTracking);
  			set => SetFlagValue(AssemblyAttributes.EnableJITcompileTracking, value);
  		}
  
  		public bool DisableJITcompileOptimizer {
  			get => GetFlagValue(AssemblyAttributes.DisableJITcompileOptimizer);
  			set => SetFlagValue(AssemblyAttributes.DisableJITcompileOptimizer, value);
  		}
  
  		bool GetFlagValue(AssemblyAttributes flag) => (Flags & flag) != 0;
  
  		void SetFlagValue(AssemblyAttributes flag, bool value) {
  			if (value)
  				Flags |= flag;
  			else
  				Flags &= ~flag;
  		}
  
  		internal static readonly EnumVM[] processArchList = EnumVM.Create(typeof(AsmProcArch));
  		public EnumListVM ProcessArchitecture => processArchitectureVM;
  		readonly EnumListVM processArchitectureVM = new EnumListVM(processArchList);
  
  		internal static readonly EnumVM[] contentTypeList = EnumVM.Create(typeof(AsmContType));
  		public EnumListVM ContentType => contentTypeVM;
  		readonly EnumListVM contentTypeVM;
  
  		public HexStringVM PublicKey { get; }
  
  		public string? Name {
  			get => name;
  			set {
  				if (name != value) {
  					name = value;
  					OnPropertyChanged(nameof(Name));
  					OnPropertyChanged(nameof(AssemblyFullName));
  				}
  			}
  		}
  		UTF8String? name;
  
  		public string? Culture {
  			get => culture;
  			set {
  				if (culture != value) {
  					culture = value;
  					OnPropertyChanged(nameof(Culture));
  					OnPropertyChanged(nameof(AssemblyFullName));
  				}
  			}
  		}
  		string? culture;
  
  		public string AssemblyFullName {
  			get {
  				var asm = new AssemblyNameInfo();
  				asm.HashAlgId = (AssemblyHashAlgorithm)HashAlgorithm.SelectedItem!;
  				int major = VersionMajor.HasError ? 0 : VersionMajor.Value;
  				int minor = VersionMinor.HasError ? 0 : VersionMinor.Value;
  				int build = VersionBuild.HasError ? 0 : VersionBuild.Value;
  				int revision = VersionRevision.HasError ? 0 : VersionRevision.Value;
  				asm.Version = new Version(major, minor, build, revision);
  				asm.Attributes = Flags;
  				asm.PublicKeyOrToken = new PublicKey(PublicKey.HasError ? Array.Empty<byte>() : PublicKey.Value.ToArray());
  				asm.Name = Name;
  				asm.Culture = Culture;
  				return asm.ToString();
  			}
  		}
  
  		public CustomAttributesVM CustomAttributesVM { get; }
  		public DeclSecuritiesVM DeclSecuritiesVM { get; }
  
  		readonly ModuleDef ownerModule;
  
  		public AssemblyOptionsVM(AssemblyOptions options, ModuleDef ownerModule, IDecompilerService decompilerService) {
  			this.ownerModule = ownerModule;
  			origOptions = options;
  			hashAlgorithmVM = new EnumListVM(hashAlgorithmList, (a, b) => OnPropertyChanged(nameof(AssemblyFullName)));
  			contentTypeVM = new EnumListVM(contentTypeList, (a, b) => OnPropertyChanged(nameof(AssemblyFullName)));
  			VersionMajor = new UInt16VM(a => { HasErrorUpdated(); OnPropertyChanged(nameof(AssemblyFullName)); }, true);
  			VersionMinor = new UInt16VM(a => { HasErrorUpdated(); OnPropertyChanged(nameof(AssemblyFullName)); }, true);
  			VersionBuild = new UInt16VM(a => { HasErrorUpdated(); OnPropertyChanged(nameof(AssemblyFullName)); }, true);
  			VersionRevision = new UInt16VM(a => { HasErrorUpdated(); OnPropertyChanged(nameof(AssemblyFullName)); }, true);
  			PublicKey = new HexStringVM(a => { HasErrorUpdated(); OnPropertyChanged(nameof(AssemblyFullName)); UpdatePublicKeyFlag(); }) { UpperCaseHex = false };
  			CustomAttributesVM = new CustomAttributesVM(ownerModule, decompilerService);
  			DeclSecuritiesVM = new DeclSecuritiesVM(ownerModule, decompilerService, null, null);
  			Reinitialize();
  		}
  
  		void UpdatePublicKeyFlag() => FlagsPublicKey = !PublicKey.IsNull;
  		void Reinitialize() => InitializeFrom(origOptions);
  		public AssemblyOptions CreateAssemblyOptions() => CopyTo(new AssemblyOptions());
  
  		void InitializeFrom(AssemblyOptions options) {
  			PublicKey.Value = options.PublicKey.Data;
  			HashAlgorithm.SelectedItem = options.HashAlgorithm;
  			VersionMajor.Value = checked((ushort)options.Version.Major);
  
gt: 			VersionMinor.Value = checked((ushort)options.Version.Minor);