|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Reflection.Metadata.Ecma335
{
public static class MetadataTokens
{
/// <summary>
/// Maximum number of tables that can be present in Ecma335 metadata.
/// </summary>
public static readonly int TableCount = 64; // headers use 64bit table masks
/// <summary>
/// Maximum number of tables that can be present in Ecma335 metadata.
/// </summary>
public static readonly int HeapCount = HeapIndexExtensions.Count;
/// <summary>
/// Returns the row number of a metadata table entry that corresponds
/// to the specified <paramref name="handle"/> in the context of <paramref name="reader"/>.
/// </summary>
/// <returns>One based row number.</returns>
/// <exception cref="ArgumentException">The <paramref name="handle"/> is not a valid metadata table handle.</exception>
public static int GetRowNumber(this MetadataReader reader, EntityHandle handle)
{
if (handle.IsVirtual)
{
return MapVirtualHandleRowId(reader, handle);
}
return handle.RowId;
}
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/> in the context of <paramref name="reader"/>.
/// </summary>
/// <returns>Zero based offset, or -1 if <paramref name="handle"/> isn't a metadata heap handle.</returns>
/// <exception cref="NotSupportedException">The operation is not supported for the specified <paramref name="handle"/>.</exception>
/// <exception cref="ArgumentException">The <paramref name="handle"/> is invalid.</exception>
public static int GetHeapOffset(this MetadataReader reader, Handle handle)
{
if (!handle.IsHeapHandle)
{
Throw.HeapHandleRequired();
}
if (handle.IsVirtual)
{
return MapVirtualHandleRowId(reader, handle);
}
return handle.Offset;
}
/// <summary>
/// Returns the metadata token of the specified <paramref name="handle"/> in the context of <paramref name="reader"/>.
/// </summary>
/// <returns>Metadata token.</returns>
/// <exception cref="NotSupportedException">The operation is not supported for the specified <paramref name="handle"/>.</exception>
public static int GetToken(this MetadataReader reader, EntityHandle handle)
{
if (handle.IsVirtual)
{
return (int)handle.Type | MapVirtualHandleRowId(reader, handle);
}
return handle.Token;
}
/// <summary>
/// Returns the metadata token of the specified <paramref name="handle"/> in the context of <paramref name="reader"/>.
/// </summary>
/// <returns>Metadata token.</returns>
/// <exception cref="ArgumentException">
/// Handle represents a metadata entity that doesn't have a token.
/// A token can only be retrieved for a metadata table handle or a heap handle of type <see cref="HandleKind.UserString"/>.
/// </exception>
/// <exception cref="NotSupportedException">The operation is not supported for the specified <paramref name="handle"/>.</exception>
public static int GetToken(this MetadataReader reader, Handle handle)
{
if (!handle.IsEntityOrUserStringHandle)
{
Throw.EntityOrUserStringHandleRequired();
}
if (handle.IsVirtual)
{
return (int)handle.EntityHandleType | MapVirtualHandleRowId(reader, handle);
}
return handle.Token;
}
private static int MapVirtualHandleRowId(MetadataReader reader, Handle handle)
{
switch (handle.Kind)
{
case HandleKind.AssemblyReference:
// pretend that virtual rows immediately follow real rows:
return reader.AssemblyRefTable.NumberOfNonVirtualRows + 1 + handle.RowId;
case HandleKind.String:
case HandleKind.Blob:
// We could precalculate offsets for virtual strings and blobs as we are creating them
// if we wanted to implement this.
throw new NotSupportedException(SR.CantGetOffsetForVirtualHeapHandle);
default:
Throw.InvalidArgument_UnexpectedHandleKind(handle.Kind);
return 0;
}
}
/// <summary>
/// Returns the row number of a metadata table entry that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// One based row number, or -1 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/>.
/// See <see cref="GetRowNumber(MetadataReader, EntityHandle)"/>.
/// </returns>
public static int GetRowNumber(EntityHandle handle)
{
return handle.IsVirtual ? -1 : handle.RowId;
}
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// An offset in the corresponding heap, or -1 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/> or <see cref="MetadataBuilder"/>.
/// See <see cref="GetHeapOffset(MetadataReader, Handle)"/>.
/// </returns>
public static int GetHeapOffset(Handle handle)
{
if (!handle.IsHeapHandle)
{
Throw.HeapHandleRequired();
}
if (handle.IsVirtual)
{
return -1;
}
return handle.Offset;
}
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// Zero based offset, or -1 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/> or <see cref="MetadataBuilder"/>.
/// See <see cref="GetHeapOffset(MetadataReader, Handle)"/>.
/// </returns>
public static int GetHeapOffset(BlobHandle handle) => handle.IsVirtual ? -1 : handle.GetHeapOffset();
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// 1-based index into the #Guid heap. Unlike other heaps, which are essentially byte arrays, the #Guid heap is an array of 16-byte GUIDs.
/// </returns>
public static int GetHeapOffset(GuidHandle handle) => handle.Index;
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// Zero based offset.
/// </returns>
public static int GetHeapOffset(UserStringHandle handle) => handle.GetHeapOffset();
/// <summary>
/// Returns the offset of metadata heap data that corresponds
/// to the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// Zero based offset, or -1 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/> or <see cref="MetadataBuilder"/>.
/// See <see cref="GetHeapOffset(MetadataReader, Handle)"/>.
/// </returns>
public static int GetHeapOffset(StringHandle handle) => handle.IsVirtual ? -1 : handle.GetHeapOffset();
/// <summary>
/// Returns the metadata token of the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// Metadata token, or 0 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/>.
/// See <see cref="GetToken(MetadataReader, Handle)"/>.
/// </returns>
/// <exception cref="ArgumentException">
/// Handle represents a metadata entity that doesn't have a token.
/// A token can only be retrieved for a metadata table handle or a heap handle of type <see cref="HandleKind.UserString"/>.
/// </exception>
public static int GetToken(Handle handle)
{
if (!handle.IsEntityOrUserStringHandle)
{
Throw.EntityOrUserStringHandleRequired();
}
if (handle.IsVirtual)
{
return 0;
}
return handle.Token;
}
/// <summary>
/// Returns the metadata token of the specified <paramref name="handle"/>.
/// </summary>
/// <returns>
/// Metadata token, or 0 if <paramref name="handle"/> can only be interpreted in a context of a specific <see cref="MetadataReader"/>.
/// See <see cref="GetToken(MetadataReader, EntityHandle)"/>.
/// </returns>
public static int GetToken(EntityHandle handle)
{
return handle.IsVirtual ? 0 : handle.Token;
}
/// <summary>
/// Gets the <see cref="TableIndex"/> of the table corresponding to the specified <see cref="HandleKind"/>.
/// </summary>
/// <param name="type">Handle type.</param>
/// <param name="index">Table index.</param>
/// <returns>True if the handle type corresponds to an Ecma335 or Portable PDB table, false otherwise.</returns>
public static bool TryGetTableIndex(HandleKind type, out TableIndex index)
{
// We don't have a HandleKind for PropertyMap, EventMap, MethodSemantics, *Ptr, AssemblyOS, etc. tables,
// but one can get ahold of one by creating a handle from a token and getting its Kind.
if ((int)type < TableCount && ((1UL << (int)type) & (ulong)TableMask.AllTables) != 0)
{
index = (TableIndex)type;
return true;
}
index = 0;
return false;
}
/// <summary>
/// Gets the <see cref="HeapIndex"/> of the heap corresponding to the specified <see cref="HandleKind"/>.
/// </summary>
/// <param name="type">Handle type.</param>
/// <param name="index">Heap index.</param>
/// <returns>True if the handle type corresponds to an Ecma335 heap, false otherwise.</returns>
public static bool TryGetHeapIndex(HandleKind type, out HeapIndex index)
{
switch (type)
{
case HandleKind.UserString:
index = HeapIndex.UserString;
return true;
case HandleKind.String:
case HandleKind.NamespaceDefinition:
index = HeapIndex.String;
return true;
case HandleKind.Blob:
index = HeapIndex.Blob;
return true;
case HandleKind.Guid:
index = HeapIndex.Guid;
return true;
default:
index = 0;
return false;
}
}
#region Handle Factories
/// <summary>
/// Creates a handle from a token value.
/// </summary>
/// <exception cref="ArgumentException">
/// <paramref name="token"/> is not a valid metadata token.
/// It must encode a metadata table entity or an offset in <see cref="HandleKind.UserString"/> heap.
/// </exception>
public static Handle Handle(int token)
{
if (!TokenTypeIds.IsEntityOrUserStringToken(unchecked((uint)token)))
{
Throw.InvalidToken();
}
return Metadata.Handle.FromVToken((uint)token);
}
/// <summary>
/// Creates an entity handle from a token value.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="token"/> is not a valid metadata entity token.</exception>
public static EntityHandle EntityHandle(int token)
{
if (!TokenTypeIds.IsEntityToken(unchecked((uint)token)))
{
Throw.InvalidToken();
}
return new EntityHandle((uint)token);
}
/// <summary>
/// Creates an <see cref="Metadata.EntityHandle"/> from a token value.
/// </summary>
/// <exception cref="ArgumentException">
/// <paramref name="tableIndex"/> is not a valid table index.</exception>
public static EntityHandle EntityHandle(TableIndex tableIndex, int rowNumber)
{
return Handle(tableIndex, rowNumber);
}
/// <summary>
/// Creates an <see cref="Metadata.EntityHandle"/> from a token value.
/// </summary>
/// <exception cref="ArgumentException">
/// <paramref name="tableIndex"/> is not a valid table index.</exception>
public static EntityHandle Handle(TableIndex tableIndex, int rowNumber)
{
int token = ((int)tableIndex << TokenTypeIds.RowIdBitCount) | rowNumber;
if (!TokenTypeIds.IsEntityOrUserStringToken(unchecked((uint)token)))
{
Throw.TableIndexOutOfRange();
}
return new EntityHandle((uint)token);
}
private static int ToRowId(int rowNumber)
{
return rowNumber & (int)TokenTypeIds.RIDMask;
}
public static MethodDefinitionHandle MethodDefinitionHandle(int rowNumber)
{
return Metadata.MethodDefinitionHandle.FromRowId(ToRowId(rowNumber));
}
public static MethodImplementationHandle MethodImplementationHandle(int rowNumber)
{
return Metadata.MethodImplementationHandle.FromRowId(ToRowId(rowNumber));
}
public static MethodSpecificationHandle MethodSpecificationHandle(int rowNumber)
{
return Metadata.MethodSpecificationHandle.FromRowId(ToRowId(rowNumber));
}
public static TypeDefinitionHandle TypeDefinitionHandle(int rowNumber)
{
return Metadata.TypeDefinitionHandle.FromRowId(ToRowId(rowNumber));
}
public static ExportedTypeHandle ExportedTypeHandle(int rowNumber)
{
return Metadata.ExportedTypeHandle.FromRowId(ToRowId(rowNumber));
}
public static TypeReferenceHandle TypeReferenceHandle(int rowNumber)
{
return Metadata.TypeReferenceHandle.FromRowId(ToRowId(rowNumber));
}
public static TypeSpecificationHandle TypeSpecificationHandle(int rowNumber)
{
return Metadata.TypeSpecificationHandle.FromRowId(ToRowId(rowNumber));
}
public static InterfaceImplementationHandle InterfaceImplementationHandle(int rowNumber)
{
return Metadata.InterfaceImplementationHandle.FromRowId(ToRowId(rowNumber));
}
public static MemberReferenceHandle MemberReferenceHandle(int rowNumber)
{
return Metadata.MemberReferenceHandle.FromRowId(ToRowId(rowNumber));
}
public static FieldDefinitionHandle FieldDefinitionHandle(int rowNumber)
{
return Metadata.FieldDefinitionHandle.FromRowId(ToRowId(rowNumber));
}
public static EventDefinitionHandle EventDefinitionHandle(int rowNumber)
{
return Metadata.EventDefinitionHandle.FromRowId(ToRowId(rowNumber));
}
public static PropertyDefinitionHandle PropertyDefinitionHandle(int rowNumber)
{
return Metadata.PropertyDefinitionHandle.FromRowId(ToRowId(rowNumber));
}
public static StandaloneSignatureHandle StandaloneSignatureHandle(int rowNumber)
{
return Metadata.StandaloneSignatureHandle.FromRowId(ToRowId(rowNumber));
}
public static ParameterHandle ParameterHandle(int rowNumber)
{
return Metadata.ParameterHandle.FromRowId(ToRowId(rowNumber));
}
public static GenericParameterHandle GenericParameterHandle(int rowNumber)
{
return Metadata.GenericParameterHandle.FromRowId(ToRowId(rowNumber));
}
public static GenericParameterConstraintHandle GenericParameterConstraintHandle(int rowNumber)
{
return Metadata.GenericParameterConstraintHandle.FromRowId(ToRowId(rowNumber));
}
public static ModuleReferenceHandle ModuleReferenceHandle(int rowNumber)
{
return Metadata.ModuleReferenceHandle.FromRowId(ToRowId(rowNumber));
}
public static AssemblyReferenceHandle AssemblyReferenceHandle(int rowNumber)
{
return Metadata.AssemblyReferenceHandle.FromRowId(ToRowId(rowNumber));
}
public static CustomAttributeHandle CustomAttributeHandle(int rowNumber)
{
return Metadata.CustomAttributeHandle.FromRowId(ToRowId(rowNumber));
}
public static DeclarativeSecurityAttributeHandle DeclarativeSecurityAttributeHandle(int rowNumber)
{
return Metadata.DeclarativeSecurityAttributeHandle.FromRowId(ToRowId(rowNumber));
}
public static ConstantHandle ConstantHandle(int rowNumber)
{
return Metadata.ConstantHandle.FromRowId(ToRowId(rowNumber));
}
public static ManifestResourceHandle ManifestResourceHandle(int rowNumber)
{
return Metadata.ManifestResourceHandle.FromRowId(ToRowId(rowNumber));
}
public static AssemblyFileHandle AssemblyFileHandle(int rowNumber)
{
return Metadata.AssemblyFileHandle.FromRowId(ToRowId(rowNumber));
}
// debug
public static DocumentHandle DocumentHandle(int rowNumber)
{
return Metadata.DocumentHandle.FromRowId(ToRowId(rowNumber));
}
public static MethodDebugInformationHandle MethodDebugInformationHandle(int rowNumber)
{
return Metadata.MethodDebugInformationHandle.FromRowId(ToRowId(rowNumber));
}
public static LocalScopeHandle LocalScopeHandle(int rowNumber)
{
return Metadata.LocalScopeHandle.FromRowId(ToRowId(rowNumber));
}
public static LocalVariableHandle LocalVariableHandle(int rowNumber)
{
return Metadata.LocalVariableHandle.FromRowId(ToRowId(rowNumber));
}
public static LocalConstantHandle LocalConstantHandle(int rowNumber)
{
return Metadata.LocalConstantHandle.FromRowId(ToRowId(rowNumber));
}
public static ImportScopeHandle ImportScopeHandle(int rowNumber)
{
return Metadata.ImportScopeHandle.FromRowId(ToRowId(rowNumber));
}
public static CustomDebugInformationHandle CustomDebugInformationHandle(int rowNumber)
{
return Metadata.CustomDebugInformationHandle.FromRowId(ToRowId(rowNumber));
}
// heaps
public static UserStringHandle UserStringHandle(int offset)
{
return Metadata.UserStringHandle.FromOffset(offset & (int)TokenTypeIds.RIDMask);
}
public static StringHandle StringHandle(int offset)
{
return Metadata.StringHandle.FromOffset(offset);
}
public static BlobHandle BlobHandle(int offset)
{
return Metadata.BlobHandle.FromOffset(offset);
}
public static GuidHandle GuidHandle(int offset)
{
return Metadata.GuidHandle.FromIndex(offset);
}
public static DocumentNameBlobHandle DocumentNameBlobHandle(int offset)
{
return Metadata.DocumentNameBlobHandle.FromOffset(offset);
}
#endregion
}
}
|