Dnspy/Extensions/dnSpy.AsmEditor/Assembly/AssemblyOptionsVM.cs
2021-09-20 18:20:01 +02:00

262 lines
10 KiB
C#

/*
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);
VersionMinor.Value = checked((ushort)options.Version.Minor);
VersionBuild.Value = checked((ushort)options.Version.Build);
VersionRevision.Value = checked((ushort)options.Version.Revision);
Flags = options.Attributes;
ProcessArchitecture.SelectedItem = (AsmProcArch)((uint)(options.Attributes & AssemblyAttributes.PA_Mask) >> (int)AssemblyAttributes.PA_Shift);
ContentType.SelectedItem = (AsmContType)((uint)(options.Attributes & AssemblyAttributes.ContentType_Mask) >> 9);
Name = options.Name;
Culture = options.Culture;
ClrVersion.SelectedItem = options.ClrVersion;
CustomAttributesVM.InitializeFrom(options.CustomAttributes);
DeclSecuritiesVM.InitializeFrom(options.DeclSecurities);
}
AssemblyOptions CopyTo(AssemblyOptions options) {
options.HashAlgorithm = (AssemblyHashAlgorithm)HashAlgorithm.SelectedItem!;
options.Version = new Version(VersionMajor.Value, VersionMinor.Value, VersionBuild.Value, VersionRevision.Value);
options.Attributes = Flags;
options.PublicKey = new PublicKey(PublicKey.Value.ToArray());
options.Name = Name;
options.Culture = Culture;
options.ClrVersion = (Module.ClrVersion)ClrVersion.SelectedItem!;
options.CustomAttributes.Clear();
options.CustomAttributes.AddRange(CustomAttributesVM.Collection.Select(a => a.CreateCustomAttributeOptions().Create()));
options.DeclSecurities.Clear();
options.DeclSecurities.AddRange(DeclSecuritiesVM.Collection.Select(a => a.CreateDeclSecurityOptions().Create(ownerModule)));
return options;
}
void OnOpenPublicKeyFile() {
if (openPublicKeyFile is null)
throw new InvalidOperationException();
var newPublicKey = openPublicKeyFile.Open();
if (newPublicKey is null)
return;
PublicKey.Value = newPublicKey.Data;
}
public override bool HasError {
get {
return VersionMajor.HasError ||
VersionMinor.HasError ||
VersionBuild.HasError ||
VersionRevision.HasError ||
PublicKey.HasError;
}
}
}
}