/*
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 .
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using dnlib.DotNet;
using dnSpy.AsmEditor.Properties;
using dnSpy.Contracts.Decompiler;
using dnSpy.Contracts.MVVM;
namespace dnSpy.AsmEditor.DnlibDialogs {
sealed class CAArgumentVM : ViewModelBase {
public ConstantTypeVM ConstantTypeVM { get; }
public bool IsEnabled {
get => isEnabled;
set {
if (isEnabled != value) {
isEnabled = value;
OnPropertyChanged(nameof(IsEnabled));
HasErrorUpdated();
}
}
}
bool isEnabled = true;
static readonly ConstantType[] ConstantTypes = new ConstantType[] {
ConstantType.Null,
ConstantType.Boolean,
ConstantType.Char,
ConstantType.SByte,
ConstantType.Byte,
ConstantType.Int16,
ConstantType.UInt16,
ConstantType.Int32,
ConstantType.UInt32,
ConstantType.Int64,
ConstantType.UInt64,
ConstantType.Single,
ConstantType.Double,
ConstantType.String,
ConstantType.Enum,
ConstantType.Type,
ConstantType.ObjectArray,
ConstantType.BooleanArray,
ConstantType.CharArray,
ConstantType.SByteArray,
ConstantType.ByteArray,
ConstantType.Int16Array,
ConstantType.UInt16Array,
ConstantType.Int32Array,
ConstantType.UInt32Array,
ConstantType.Int64Array,
ConstantType.UInt64Array,
ConstantType.SingleArray,
ConstantType.DoubleArray,
ConstantType.StringArray,
ConstantType.EnumArray,
ConstantType.TypeArray,
};
bool modified;
readonly CAArgument originalArg;
readonly ModuleDef module;
public TypeSig? StorageType {
get => storageType;
set {
if (storageType != value) {
storageType = value;
OnPropertyChanged(nameof(StorageType));
}
}
}
TypeSig? storageType;
public CAArgumentVM(ModuleDef ownerModule, CAArgument arg, TypeSigCreatorOptions options, TypeSig? storageType) {
module = options.OwnerModule;
originalArg = arg.Clone();
ConstantTypeVM = new DnlibDialogs.ConstantTypeVM(ownerModule, null, ConstantTypes, true, true, options);
ConstantTypeVM.PropertyChanged += ConstantTypeVM_PropertyChanged;
InitializeFrom(arg, storageType);
modified = false;
}
void ConstantTypeVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Modified") {
OnPropertyChanged("Modified");
modified = true;
}
HasErrorUpdated();
}
void InitializeFrom(CAArgument arg, TypeSig? storageType) {
StorageType = storageType;
ConstantTypeVM.Value = ConvertFromModel(arg.Type, arg.Value);
}
object? ConvertFromModel(TypeSig valueType, object? value) {
var type = valueType.RemovePinnedAndModifiers();
var et = type.GetElementType();
ITypeDefOrRef tdr;
TypeDef td;
switch (et) {
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
if (ModelUtils.GetElementType(value?.GetType()) == et)
return value;
break;
case ElementType.String:
if (value is null)
return Null.Instance;
else if (value is string)
return value;
else if (value is UTF8String)
return ((UTF8String)value).String;
break;
case ElementType.ValueType:
case ElementType.Class:
tdr = ((ClassOrValueTypeSig)type).TypeDefOrRef;
if (tdr.IsSystemType()) {
if (value is null)
return Null.Instance;
return value;
}
td = tdr.ResolveTypeDef();
if (td is not null && !td.IsEnum)
break;
return new EnumInfo() {
EnumType = tdr,
Value = value,
IsArray = false,
};
case ElementType.SZArray:
var elemType = type.Next.RemovePinnedAndModifiers();
if (value is null) {
switch (elemType.GetElementType()) {
case ElementType.Boolean: return Null.Instance;
case ElementType.Char: return Null.Instance;
case ElementType.I1: return Null.Instance;
case ElementType.U1: return Null.Instance;
case ElementType.I2: return Null.Instance;
case ElementType.U2: return Null.Instance;
case ElementType.I4: return Null.Instance;
case ElementType.U4: return Null.Instance;
case ElementType.I8: return Null.Instance;
case ElementType.U8: return Null.Instance;
case ElementType.R4: return Null.Instance;
case ElementType.R8: return Null.Instance;
case ElementType.String: return Null.Instance;
case ElementType.Object: return Null