mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.6 KiB
303 lines
9.6 KiB
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.ComponentModel; |
|
using System.Globalization; |
|
using System.Linq; |
|
using System.Reflection; |
|
using System.Reflection.Metadata; |
|
using System.Reflection.Metadata.Ecma335; |
|
using System.Runtime.CompilerServices; |
|
using System.Text; |
|
using System.Threading.Tasks; |
|
using System.Windows; |
|
using System.Windows.Controls; |
|
using System.Windows.Data; |
|
using System.Windows.Media; |
|
|
|
using DataGridExtensions; |
|
|
|
using ICSharpCode.Decompiler.Util; |
|
using ICSharpCode.ILSpy.Controls; |
|
using ICSharpCode.ILSpy.TextView; |
|
using ICSharpCode.ILSpy.TreeNodes; |
|
using ICSharpCode.ILSpy.ViewModels; |
|
|
|
namespace ICSharpCode.ILSpy.Metadata |
|
{ |
|
static class Helpers |
|
{ |
|
public static DataGrid PrepareDataGrid(TabPageModel tabPage, ILSpyTreeNode selectedNode) |
|
{ |
|
if (!(tabPage.Content is DataGrid view && view.Name == "MetadataView")) |
|
{ |
|
view = new MetaDataGrid() { |
|
Name = "MetadataView", |
|
GridLinesVisibility = DataGridGridLinesVisibility.None, |
|
CanUserAddRows = false, |
|
CanUserDeleteRows = false, |
|
CanUserReorderColumns = false, |
|
HeadersVisibility = DataGridHeadersVisibility.Column, |
|
EnableColumnVirtualization = true, |
|
EnableRowVirtualization = true, |
|
RowHeight = 20, |
|
IsReadOnly = true, |
|
SelectionMode = DataGridSelectionMode.Single, |
|
SelectionUnit = DataGridSelectionUnit.FullRow, |
|
SelectedTreeNode = selectedNode, |
|
CellStyle = (Style)MetadataTableViews.Instance["DataGridCellStyle"], |
|
}; |
|
ContextMenuProvider.Add(view); |
|
DataGridFilter.SetIsAutoFilterEnabled(view, true); |
|
DataGridFilter.SetContentFilterFactory(view, new RegexContentFilterFactory()); |
|
} |
|
DataGridFilter.GetFilter(view).Clear(); |
|
view.RowDetailsTemplateSelector = null; |
|
view.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed; |
|
((MetaDataGrid)view).SelectedTreeNode = selectedNode; |
|
if (!view.AutoGenerateColumns) |
|
view.Columns.Clear(); |
|
view.AutoGenerateColumns = true; |
|
|
|
view.AutoGeneratingColumn += View_AutoGeneratingColumn; |
|
view.AutoGeneratedColumns += View_AutoGeneratedColumns; |
|
|
|
return view; |
|
} |
|
|
|
internal static void View_AutoGeneratedColumns(object sender, EventArgs e) |
|
{ |
|
((DataGrid)sender).AutoGeneratedColumns -= View_AutoGeneratedColumns; |
|
((DataGrid)sender).AutoGeneratingColumn -= View_AutoGeneratingColumn; |
|
} |
|
|
|
internal static void View_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) |
|
{ |
|
var binding = new Binding(e.PropertyName) { Mode = BindingMode.OneWay }; |
|
e.Column = new DataGridTextColumn() { |
|
Header = e.PropertyName, |
|
Binding = binding |
|
}; |
|
switch (e.PropertyName) |
|
{ |
|
case "RID": |
|
case "Meaning": |
|
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["DefaultFilter"]); |
|
break; |
|
case "Token": |
|
case "Offset": |
|
case "RVA": |
|
case "StartOffset": |
|
case "Length": |
|
binding.StringFormat = "X8"; |
|
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["HexFilter"]); |
|
break; |
|
case "RowDetails": |
|
e.Cancel = true; |
|
break; |
|
default: |
|
e.Cancel = e.PropertyName.Contains("Tooltip"); |
|
if (!e.Cancel) |
|
{ |
|
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["DefaultFilter"]); |
|
} |
|
break; |
|
} |
|
if (!e.Cancel) |
|
{ |
|
ApplyAttributes((PropertyDescriptor)e.PropertyDescriptor, binding, e.Column); |
|
} |
|
} |
|
|
|
static void ApplyAttributes(PropertyDescriptor descriptor, Binding binding, DataGridColumn column) |
|
{ |
|
if (descriptor.PropertyType.IsEnum) |
|
{ |
|
binding.Converter = new UnderlyingEnumValueConverter(); |
|
string key = descriptor.PropertyType.Name + "Filter"; |
|
column.SetTemplate((ControlTemplate)MetadataTableViews.Instance[key]); |
|
} |
|
var stringFormat = descriptor.Attributes.OfType<StringFormatAttribute>().FirstOrDefault(); |
|
if (stringFormat != null) |
|
{ |
|
binding.StringFormat = stringFormat.Format; |
|
if (!descriptor.PropertyType.IsEnum |
|
&& stringFormat.Format.StartsWith("X", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["HexFilter"]); |
|
} |
|
} |
|
} |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
public static unsafe int GetValue(byte* ptr, int size) |
|
{ |
|
int result = 0; |
|
for (int i = 0; i < size; i += 2) |
|
{ |
|
result |= ptr[i] << 8 * i; |
|
result |= ptr[i + 1] << 8 * (i + 1); |
|
} |
|
return result; |
|
} |
|
|
|
static Helpers() |
|
{ |
|
rowCounts = typeof(MetadataReader) |
|
.GetField("TableRowCounts", BindingFlags.NonPublic | BindingFlags.Instance); |
|
computeCodedTokenSize = typeof(MetadataReader) |
|
.GetMethod("ComputeCodedTokenSize", BindingFlags.Instance | BindingFlags.NonPublic); |
|
fromTypeDefOrRefTag = typeof(TypeDefinitionHandle).Assembly |
|
.GetType("System.Reflection.Metadata.Ecma335.TypeDefOrRefTag") |
|
.GetMethod("ConvertToHandle", BindingFlags.Static | BindingFlags.NonPublic); |
|
fromHasFieldMarshalTag = typeof(TypeDefinitionHandle).Assembly |
|
.GetType("System.Reflection.Metadata.Ecma335.HasFieldMarshalTag") |
|
.GetMethod("ConvertToHandle", BindingFlags.Static | BindingFlags.NonPublic); |
|
fromMemberForwardedTag = typeof(TypeDefinitionHandle).Assembly |
|
.GetType("System.Reflection.Metadata.Ecma335.MemberForwardedTag") |
|
.GetMethod("ConvertToHandle", BindingFlags.Static | BindingFlags.NonPublic); |
|
} |
|
|
|
readonly static FieldInfo rowCounts; |
|
readonly static MethodInfo computeCodedTokenSize; |
|
readonly static MethodInfo fromTypeDefOrRefTag; |
|
readonly static MethodInfo fromHasFieldMarshalTag; |
|
readonly static MethodInfo fromMemberForwardedTag; |
|
|
|
public static EntityHandle FromHasFieldMarshalTag(uint tag) |
|
{ |
|
return (EntityHandle)fromHasFieldMarshalTag.Invoke(null, new object[] { tag }); |
|
} |
|
|
|
public static EntityHandle FromMemberForwardedTag(uint tag) |
|
{ |
|
return (EntityHandle)fromMemberForwardedTag.Invoke(null, new object[] { tag }); |
|
} |
|
|
|
public static EntityHandle FromTypeDefOrRefTag(uint tag) |
|
{ |
|
return (EntityHandle)fromTypeDefOrRefTag.Invoke(null, new object[] { tag }); |
|
} |
|
|
|
public static int ComputeCodedTokenSize(this MetadataReader metadata, int largeRowSize, |
|
TableMask mask) |
|
{ |
|
return (int)computeCodedTokenSize.Invoke(metadata, new object[] { |
|
largeRowSize, rowCounts.GetValue(metadata), (ulong)mask } |
|
); |
|
} |
|
|
|
class UnderlyingEnumValueConverter : IValueConverter |
|
{ |
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
|
{ |
|
var t = value.GetType(); |
|
if (t.IsEnum) |
|
{ |
|
return (int)CSharpPrimitiveCast.Cast(TypeCode.Int32, value, false); |
|
} |
|
return value; |
|
} |
|
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
} |
|
|
|
public static string ReadUTF8StringNullTerminated(this ref BlobReader reader) |
|
{ |
|
int length = reader.IndexOf(0); |
|
string s = reader.ReadUTF8(length); |
|
reader.ReadByte(); |
|
return s; |
|
} |
|
} |
|
|
|
class StringFormatAttribute : Attribute |
|
{ |
|
public string Format { get; } |
|
|
|
public StringFormatAttribute(string format) |
|
{ |
|
this.Format = format; |
|
} |
|
} |
|
|
|
[Flags] |
|
internal enum TableMask : ulong |
|
{ |
|
Module = 0x1, |
|
TypeRef = 0x2, |
|
TypeDef = 0x4, |
|
FieldPtr = 0x8, |
|
Field = 0x10, |
|
MethodPtr = 0x20, |
|
MethodDef = 0x40, |
|
ParamPtr = 0x80, |
|
Param = 0x100, |
|
InterfaceImpl = 0x200, |
|
MemberRef = 0x400, |
|
Constant = 0x800, |
|
CustomAttribute = 0x1000, |
|
FieldMarshal = 0x2000, |
|
DeclSecurity = 0x4000, |
|
ClassLayout = 0x8000, |
|
FieldLayout = 0x10000, |
|
StandAloneSig = 0x20000, |
|
EventMap = 0x40000, |
|
EventPtr = 0x80000, |
|
Event = 0x100000, |
|
PropertyMap = 0x200000, |
|
PropertyPtr = 0x400000, |
|
Property = 0x800000, |
|
MethodSemantics = 0x1000000, |
|
MethodImpl = 0x2000000, |
|
ModuleRef = 0x4000000, |
|
TypeSpec = 0x8000000, |
|
ImplMap = 0x10000000, |
|
FieldRva = 0x20000000, |
|
EnCLog = 0x40000000, |
|
EnCMap = 0x80000000, |
|
Assembly = 0x100000000, |
|
AssemblyRef = 0x800000000, |
|
File = 0x4000000000, |
|
ExportedType = 0x8000000000, |
|
ManifestResource = 0x10000000000, |
|
NestedClass = 0x20000000000, |
|
GenericParam = 0x40000000000, |
|
MethodSpec = 0x80000000000, |
|
GenericParamConstraint = 0x100000000000, |
|
Document = 0x1000000000000, |
|
MethodDebugInformation = 0x2000000000000, |
|
LocalScope = 0x4000000000000, |
|
LocalVariable = 0x8000000000000, |
|
LocalConstant = 0x10000000000000, |
|
ImportScope = 0x20000000000000, |
|
StateMachineMethod = 0x40000000000000, |
|
CustomDebugInformation = 0x80000000000000, |
|
PtrTables = 0x4800A8, |
|
EncTables = 0xC0000000, |
|
TypeSystemTables = 0x1FC9FFFFFFFF, |
|
DebugTables = 0xFF000000000000, |
|
AllTables = 0xFF1FC9FFFFFFFF, |
|
ValidPortablePdbExternalTables = 0x1FC93FB7FF57 |
|
} |
|
}
|
|
|