mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
Closes out Phase 1e: every CLI metadata table now has its own typed leaf. Bytes-level table walking goes through MetadataReader.AsBlobReader (public API) instead of the WPF Helpers' AsReadOnlySpan path; coded-token columns are decoded by the new MetadataReaderHelpers shim, which reflects against the same private TypeDefOrRefTag / HasFieldMarshalTag / MemberForwardedTag.ConvertToHandle methods + ComputeCodedTokenSize that the WPF host uses (a known forward-compatibility risk per the plan's risk register). Assisted-by: Claude:claude-opus-4-7:Claude Codepull/3755/head
14 changed files with 1103 additions and 0 deletions
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the ClassLayout table — explicit field-layout overrides on TypeDefs marked
|
||||
/// Sequential or Explicit (e.g. <c>[StructLayout(LayoutKind.Explicit)]</c>). System.Reflection.Metadata
|
||||
/// doesn't surface these rows through a typed enumeration so we walk the table bytes
|
||||
/// directly via a BlobReader.
|
||||
/// </summary>
|
||||
public sealed class ClassLayoutTableTreeNode : MetadataTableTreeNode<ClassLayoutTableTreeNode.ClassLayoutEntry> |
||||
{ |
||||
public ClassLayoutTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.ClassLayout, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<ClassLayoutEntry> LoadTable() |
||||
{ |
||||
var list = new List<ClassLayoutEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.ClassLayout); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.ClassLayout); |
||||
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
ushort packingSize = reader.ReadUInt16(); |
||||
uint classSize = reader.ReadUInt32(); |
||||
int parentRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new ClassLayoutEntry(rid, packingSize, classSize, MetadataTokens.TypeDefinitionHandle(parentRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class ClassLayoutEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x0F000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Parent => MetadataTokens.GetToken(parent); |
||||
|
||||
public ushort PackingSize { get; } |
||||
|
||||
public uint ClassSize { get; } |
||||
|
||||
readonly TypeDefinitionHandle parent; |
||||
|
||||
public ClassLayoutEntry(int rid, ushort packingSize, uint classSize, TypeDefinitionHandle parent) |
||||
{ |
||||
RID = rid; |
||||
PackingSize = packingSize; |
||||
ClassSize = classSize; |
||||
this.parent = parent; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the EventMap table — pairs each TypeDef that declares events with the first
|
||||
/// row of its event list (later rows belong to the same type until the next EventMap row).
|
||||
/// </summary>
|
||||
public sealed class EventMapTableTreeNode : MetadataTableTreeNode<EventMapTableTreeNode.EventMapEntry> |
||||
{ |
||||
public EventMapTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.EventMap, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<EventMapEntry> LoadTable() |
||||
{ |
||||
var list = new List<EventMapEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.EventMap); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.EventMap); |
||||
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4; |
||||
int eventDefSize = metadata.GetTableRowCount(TableIndex.Event) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int parentRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
int eventListRow = eventDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new EventMapEntry(rid, MetadataTokens.TypeDefinitionHandle(parentRow), MetadataTokens.EventDefinitionHandle(eventListRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class EventMapEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x12000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Parent => MetadataTokens.GetToken(parent); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int EventList => MetadataTokens.GetToken(eventList); |
||||
|
||||
readonly TypeDefinitionHandle parent; |
||||
readonly EventDefinitionHandle eventList; |
||||
|
||||
public EventMapEntry(int rid, TypeDefinitionHandle parent, EventDefinitionHandle eventList) |
||||
{ |
||||
RID = rid; |
||||
this.parent = parent; |
||||
this.eventList = eventList; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the FieldLayout table — explicit per-field byte offsets for fields whose
|
||||
/// owning TypeDef has <see cref="System.Reflection.TypeAttributes.ExplicitLayout"/> set.
|
||||
/// </summary>
|
||||
public sealed class FieldLayoutTableTreeNode : MetadataTableTreeNode<FieldLayoutTableTreeNode.FieldLayoutEntry> |
||||
{ |
||||
public FieldLayoutTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.FieldLayout, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<FieldLayoutEntry> LoadTable() |
||||
{ |
||||
var list = new List<FieldLayoutEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.FieldLayout); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.FieldLayout); |
||||
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int offset = reader.ReadInt32(); |
||||
int fieldRow = fieldDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new FieldLayoutEntry(rid, offset, MetadataTokens.FieldDefinitionHandle(fieldRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class FieldLayoutEntry |
||||
{ |
||||
// Use a verbatim fieldHandle local because C# 14 made `field` contextual inside property
|
||||
// accessors — referencing it without `@` would name the auto-property's hidden
|
||||
// backing field instead of this member.
|
||||
readonly FieldDefinitionHandle fieldHandle; |
||||
|
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x10000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Field => MetadataTokens.GetToken(fieldHandle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int FieldOffset { get; } |
||||
|
||||
public FieldLayoutEntry(int rid, int fieldOffset, FieldDefinitionHandle field) |
||||
{ |
||||
RID = rid; |
||||
FieldOffset = fieldOffset; |
||||
fieldHandle = field; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the FieldMarshal table — native-marshalling descriptors attached to fields
|
||||
/// or parameters. Parent is a HasFieldMarshal coded token (Field / Param); NativeType
|
||||
/// is the heap-offset of a marshal-spec blob.
|
||||
/// </summary>
|
||||
public sealed class FieldMarshalTableTreeNode : MetadataTableTreeNode<FieldMarshalTableTreeNode.FieldMarshalEntry> |
||||
{ |
||||
public FieldMarshalTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.FieldMarshal, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<FieldMarshalEntry> LoadTable() |
||||
{ |
||||
var list = new List<FieldMarshalEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.FieldMarshal); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.FieldMarshal); |
||||
int hasFieldMarshalRefSize = metadata.ComputeCodedTokenSize(32768, TableMask.Field | TableMask.Param); |
||||
int blobHeapSize = metadata.GetHeapSize(HeapIndex.Blob) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
uint parentTag = (uint)(hasFieldMarshalRefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32()); |
||||
int blobOffset = blobHeapSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new FieldMarshalEntry(rid, |
||||
MetadataReaderHelpers.FromHasFieldMarshalTag(parentTag), |
||||
MetadataTokens.BlobHandle(blobOffset))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class FieldMarshalEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x0D000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Parent => MetadataTokens.GetToken(parent); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)] |
||||
public int NativeType => MetadataTokens.GetHeapOffset(nativeType); |
||||
|
||||
readonly EntityHandle parent; |
||||
readonly BlobHandle nativeType; |
||||
|
||||
public FieldMarshalEntry(int rid, EntityHandle parent, BlobHandle nativeType) |
||||
{ |
||||
RID = rid; |
||||
this.parent = parent; |
||||
this.nativeType = nativeType; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the FieldRVA table — for static fields backed by a fixed PE-image RVA, the
|
||||
/// table maps each FieldDef to its data location. Common with <c>fixed</c> array initializers
|
||||
/// (the compiler emits a synthesised type whose static fields point at the .rdata bytes).
|
||||
/// </summary>
|
||||
public sealed class FieldRVATableTreeNode : MetadataTableTreeNode<FieldRVATableTreeNode.FieldRVAEntry> |
||||
{ |
||||
public FieldRVATableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.FieldRva, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<FieldRVAEntry> LoadTable() |
||||
{ |
||||
var list = new List<FieldRVAEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.FieldRva); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.FieldRva); |
||||
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int rva = reader.ReadInt32(); |
||||
int fieldRow = fieldDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new FieldRVAEntry(rid, rva, MetadataTokens.FieldDefinitionHandle(fieldRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class FieldRVAEntry |
||||
{ |
||||
// Verbatim fieldHandle — see FieldLayoutTableTreeNode for the C# 14 keyword note.
|
||||
readonly FieldDefinitionHandle fieldHandle; |
||||
|
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x1D000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Field => MetadataTokens.GetToken(fieldHandle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int RVA { get; } |
||||
|
||||
public FieldRVAEntry(int rid, int rva, FieldDefinitionHandle field) |
||||
{ |
||||
RID = rid; |
||||
RVA = rva; |
||||
fieldHandle = field; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,95 @@
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the ImplMap table — P/Invoke linkage. Each row maps a managed MethodDef (or
|
||||
/// Field, in legacy CIL) to its native entry point: the <c>extern</c> name plus the
|
||||
/// ModuleRef holding the DLL identifier.
|
||||
/// </summary>
|
||||
public sealed class ImplMapTableTreeNode : MetadataTableTreeNode<ImplMapTableTreeNode.ImplMapEntry> |
||||
{ |
||||
public ImplMapTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.ImplMap, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<ImplMapEntry> LoadTable() |
||||
{ |
||||
var list = new List<ImplMapEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.ImplMap); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.ImplMap); |
||||
int moduleRefSize = metadata.GetTableRowCount(TableIndex.ModuleRef) < ushort.MaxValue ? 2 : 4; |
||||
int memberForwardedTagSize = metadata.ComputeCodedTokenSize(32768, TableMask.MethodDef | TableMask.Field); |
||||
int stringHandleSize = metadata.GetHeapSize(HeapIndex.String) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
MethodImportAttributes mappingFlags = (MethodImportAttributes)reader.ReadUInt16(); |
||||
uint memberForwardedTag = (uint)(memberForwardedTagSize == 2 ? reader.ReadUInt16() : reader.ReadInt32()); |
||||
int importNameOffset = stringHandleSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
int importScopeRow = moduleRefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new ImplMapEntry(rid, mappingFlags, |
||||
MetadataReaderHelpers.FromMemberForwardedTag(memberForwardedTag), |
||||
metadata.GetString(MetadataTokens.StringHandle(importNameOffset)), |
||||
MetadataTokens.ModuleReferenceHandle(importScopeRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class ImplMapEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x1C000000 | RID; |
||||
|
||||
[ColumnInfo("X8")] |
||||
public MethodImportAttributes MappingFlags { get; } |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int MemberForwarded => MetadataTokens.GetToken(memberForwarded); |
||||
|
||||
public string ImportName { get; } |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int ImportScope => MetadataTokens.GetToken(importScope); |
||||
|
||||
readonly EntityHandle memberForwarded; |
||||
readonly ModuleReferenceHandle importScope; |
||||
|
||||
public ImplMapEntry(int rid, MethodImportAttributes mappingFlags, EntityHandle memberForwarded, string importName, ModuleReferenceHandle importScope) |
||||
{ |
||||
RID = rid; |
||||
MappingFlags = mappingFlags; |
||||
this.memberForwarded = memberForwarded; |
||||
ImportName = importName; |
||||
this.importScope = importScope; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the InterfaceImpl table — every type/interface implementation pair. Class is
|
||||
/// a TypeDef row; Interface is a TypeDefOrRef coded token (TypeDef / TypeRef / TypeSpec).
|
||||
/// </summary>
|
||||
public sealed class InterfaceImplTableTreeNode : MetadataTableTreeNode<InterfaceImplTableTreeNode.InterfaceImplEntry> |
||||
{ |
||||
public InterfaceImplTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.InterfaceImpl, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<InterfaceImplEntry> LoadTable() |
||||
{ |
||||
var list = new List<InterfaceImplEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.InterfaceImpl); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.InterfaceImpl); |
||||
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4; |
||||
int interfaceTagSize = metadata.ComputeCodedTokenSize(32768, TableMask.TypeDef | TableMask.TypeRef | TableMask.TypeSpec); |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int classRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
uint interfaceTag = (uint)(interfaceTagSize == 2 ? reader.ReadUInt16() : reader.ReadInt32()); |
||||
list.Add(new InterfaceImplEntry(rid, |
||||
MetadataTokens.TypeDefinitionHandle(classRow), |
||||
MetadataReaderHelpers.FromTypeDefOrRefTag(interfaceTag))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class InterfaceImplEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x09000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Class => MetadataTokens.GetToken(@class); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Interface => MetadataTokens.GetToken(@interface); |
||||
|
||||
readonly TypeDefinitionHandle @class; |
||||
readonly EntityHandle @interface; |
||||
|
||||
public InterfaceImplEntry(int rid, TypeDefinitionHandle @class, EntityHandle @interface) |
||||
{ |
||||
RID = rid; |
||||
this.@class = @class; |
||||
this.@interface = @interface; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the MethodImpl table — explicit interface implementations and method-body
|
||||
/// overrides where the declared signature differs from the impl signature. Each row
|
||||
/// pairs a Type, a MethodDeclaration (the override target), and a MethodBody (the impl).
|
||||
/// </summary>
|
||||
public sealed class MethodImplTableTreeNode : MetadataTableTreeNode<MethodImplTableTreeNode.MethodImplEntry> |
||||
{ |
||||
public MethodImplTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.MethodImpl, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<MethodImplEntry> LoadTable() |
||||
{ |
||||
var list = new List<MethodImplEntry>(); |
||||
for (int row = 1; row <= metadataFile.Metadata.GetTableRowCount(TableIndex.MethodImpl); row++) |
||||
list.Add(new MethodImplEntry(metadataFile, MetadataTokens.MethodImplementationHandle(row))); |
||||
return list; |
||||
} |
||||
|
||||
public sealed class MethodImplEntry |
||||
{ |
||||
readonly MetadataFile metadataFile; |
||||
readonly MethodImplementationHandle handle; |
||||
readonly MethodImplementation methodImpl; |
||||
|
||||
public int RID => MetadataTokens.GetToken(handle) & 0xFFFFFF; |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Type => MetadataTokens.GetToken(methodImpl.Type); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int MethodDeclaration => MetadataTokens.GetToken(methodImpl.MethodDeclaration); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int MethodBody => MetadataTokens.GetToken(methodImpl.MethodBody); |
||||
|
||||
public MethodImplEntry(MetadataFile metadataFile, MethodImplementationHandle handle) |
||||
{ |
||||
this.metadataFile = metadataFile; |
||||
this.handle = handle; |
||||
methodImpl = metadataFile.Metadata.GetMethodImplementation(handle); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,77 @@
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the MethodSemantics table — links accessor methods (get/set/add/remove/raise)
|
||||
/// to the property or event they implement. <see cref="MetadataReader.GetMethodSemantics"/>
|
||||
/// returns a typed enumeration so byte-level reading isn't required.
|
||||
/// </summary>
|
||||
public sealed class MethodSemanticsTableTreeNode : MetadataTableTreeNode<MethodSemanticsTableTreeNode.MethodSemanticsEntry> |
||||
{ |
||||
public MethodSemanticsTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.MethodSemantics, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<MethodSemanticsEntry> LoadTable() |
||||
{ |
||||
var list = new List<MethodSemanticsEntry>(); |
||||
foreach (var row in metadataFile.Metadata.GetMethodSemantics()) |
||||
list.Add(new MethodSemanticsEntry(row.Handle, row.Semantics, row.Method, row.Association)); |
||||
return list; |
||||
} |
||||
|
||||
public sealed class MethodSemanticsEntry |
||||
{ |
||||
public int RID => MetadataTokens.GetToken(handle) & 0xFFFFFF; |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public MethodSemanticsAttributes Semantics { get; } |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Method => MetadataTokens.GetToken(method); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Association => MetadataTokens.GetToken(association); |
||||
|
||||
readonly Handle handle; |
||||
readonly MethodDefinitionHandle method; |
||||
readonly EntityHandle association; |
||||
|
||||
public MethodSemanticsEntry(Handle handle, MethodSemanticsAttributes semantics, MethodDefinitionHandle method, EntityHandle association) |
||||
{ |
||||
this.handle = handle; |
||||
Semantics = semantics; |
||||
this.method = method; |
||||
this.association = association; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the NestedClass table — pairs each nested type with its enclosing type. Walked
|
||||
/// directly from the table bytes because System.Reflection.Metadata only exposes
|
||||
/// nested-type discovery as a per-typedef enumeration.
|
||||
/// </summary>
|
||||
public sealed class NestedClassTableTreeNode : MetadataTableTreeNode<NestedClassTableTreeNode.NestedClassEntry> |
||||
{ |
||||
public NestedClassTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.NestedClass, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<NestedClassEntry> LoadTable() |
||||
{ |
||||
var list = new List<NestedClassEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.NestedClass); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.NestedClass); |
||||
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int nestedRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
int enclosingRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new NestedClassEntry(rid, MetadataTokens.TypeDefinitionHandle(nestedRow), MetadataTokens.TypeDefinitionHandle(enclosingRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class NestedClassEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x29000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int NestedClass => MetadataTokens.GetToken(nested); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int EnclosingClass => MetadataTokens.GetToken(enclosing); |
||||
|
||||
readonly TypeDefinitionHandle nested; |
||||
readonly TypeDefinitionHandle enclosing; |
||||
|
||||
public NestedClassEntry(int rid, TypeDefinitionHandle nested, TypeDefinitionHandle enclosing) |
||||
{ |
||||
RID = rid; |
||||
this.nested = nested; |
||||
this.enclosing = enclosing; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026 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.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the PropertyMap table — pairs each TypeDef that declares properties with the
|
||||
/// first row of its property list. Same shape as EventMap but for properties.
|
||||
/// </summary>
|
||||
public sealed class PropertyMapTableTreeNode : MetadataTableTreeNode<PropertyMapTableTreeNode.PropertyMapEntry> |
||||
{ |
||||
public PropertyMapTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.PropertyMap, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<PropertyMapEntry> LoadTable() |
||||
{ |
||||
var list = new List<PropertyMapEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(TableIndex.PropertyMap); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(TableIndex.PropertyMap); |
||||
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4; |
||||
int propertyDefSize = metadata.GetTableRowCount(TableIndex.Property) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int parentRow = typeDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
int propertyListRow = propertyDefSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new PropertyMapEntry(rid, MetadataTokens.TypeDefinitionHandle(parentRow), MetadataTokens.PropertyDefinitionHandle(propertyListRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class PropertyMapEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => 0x15000000 | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Parent => MetadataTokens.GetToken(parent); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int PropertyList => MetadataTokens.GetToken(propertyList); |
||||
|
||||
readonly TypeDefinitionHandle parent; |
||||
readonly PropertyDefinitionHandle propertyList; |
||||
|
||||
public PropertyMapEntry(int rid, TypeDefinitionHandle parent, PropertyDefinitionHandle propertyList) |
||||
{ |
||||
RID = rid; |
||||
this.parent = parent; |
||||
this.propertyList = propertyList; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2026 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.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the five Ptr tables (FieldPtr / MethodPtr / ParamPtr / EventPtr / PropertyPtr).
|
||||
/// Present only in metadata produced with #~ + indirection (rare; mostly EnC or some
|
||||
/// custom emitters), and each row carries a single handle into the table the Ptr points
|
||||
/// at. One node type drives all five since the row shape is identical.
|
||||
/// </summary>
|
||||
public sealed class PtrTableTreeNode : MetadataTableTreeNode<PtrTableTreeNode.PtrEntry> |
||||
{ |
||||
readonly TableIndex referencedTableKind; |
||||
|
||||
public PtrTableTreeNode(TableIndex kind, MetadataFile metadataFile) |
||||
: base(kind, metadataFile) |
||||
{ |
||||
referencedTableKind = kind switch { |
||||
TableIndex.EventPtr => TableIndex.Event, |
||||
TableIndex.FieldPtr => TableIndex.Field, |
||||
TableIndex.MethodPtr => TableIndex.MethodDef, |
||||
TableIndex.ParamPtr => TableIndex.Param, |
||||
TableIndex.PropertyPtr => TableIndex.Property, |
||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), $"PtrTable does not support {kind}"), |
||||
}; |
||||
} |
||||
|
||||
protected override IReadOnlyList<PtrEntry> LoadTable() |
||||
{ |
||||
var list = new List<PtrEntry>(); |
||||
var metadata = metadataFile.Metadata; |
||||
var length = metadata.GetTableRowCount(Kind); |
||||
var reader = metadata.AsBlobReader(); |
||||
reader.Offset = metadata.GetTableMetadataOffset(Kind); |
||||
int handleSize = metadata.GetTableRowCount(referencedTableKind) < ushort.MaxValue ? 2 : 4; |
||||
for (int rid = 1; rid <= length; rid++) |
||||
{ |
||||
int handleRow = handleSize == 2 ? reader.ReadUInt16() : reader.ReadInt32(); |
||||
list.Add(new PtrEntry(rid, Kind, MetadataTokens.EntityHandle(((int)referencedTableKind << 24) | handleRow))); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
public sealed class PtrEntry |
||||
{ |
||||
public int RID { get; } |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => ((int)kind << 24) | RID; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int Handle => MetadataTokens.GetToken(handle); |
||||
|
||||
readonly TableIndex kind; |
||||
readonly EntityHandle handle; |
||||
|
||||
public PtrEntry(int rid, TableIndex kind, EntityHandle handle) |
||||
{ |
||||
RID = rid; |
||||
this.kind = kind; |
||||
this.handle = handle; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue