/* 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 . */ // from dnlib using System; using System.Collections.ObjectModel; namespace dnSpy.Contracts.Hex.Files.DotNet { /// /// Contains all possible coded token classes /// public sealed class CodedToken { /// TypeDefOrRef coded token public static readonly CodedToken TypeDefOrRef = new CodedToken(2, new Table[3] { Table.TypeDef, Table.TypeRef, Table.TypeSpec, }); /// HasConstant coded token public static readonly CodedToken HasConstant = new CodedToken(2, new Table[3] { Table.Field, Table.Param, Table.Property, }); /// HasCustomAttribute coded token public static readonly CodedToken HasCustomAttribute = new CodedToken(5, new Table[24] { Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef, Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef, Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType, Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec, 0, 0, }); /// HasFieldMarshal coded token public static readonly CodedToken HasFieldMarshal = new CodedToken(1, new Table[2] { Table.Field, Table.Param, }); /// HasDeclSecurity coded token public static readonly CodedToken HasDeclSecurity = new CodedToken(2, new Table[3] { Table.TypeDef, Table.Method, Table.Assembly, }); /// MemberRefParent coded token public static readonly CodedToken MemberRefParent = new CodedToken(3, new Table[5] { Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method, Table.TypeSpec, }); /// HasSemantic coded token public static readonly CodedToken HasSemantic = new CodedToken(1, new Table[2] { Table.Event, Table.Property, }); /// MethodDefOrRef coded token public static readonly CodedToken MethodDefOrRef = new CodedToken(1, new Table[2] { Table.Method, Table.MemberRef, }); /// MemberForwarded coded token public static readonly CodedToken MemberForwarded = new CodedToken(1, new Table[2] { Table.Field, Table.Method, }); /// Implementation coded token public static readonly CodedToken Implementation = new CodedToken(2, new Table[3] { Table.File, Table.AssemblyRef, Table.ExportedType, }); /// CustomAttributeType coded token public static readonly CodedToken CustomAttributeType = new CodedToken(3, new Table[4] { 0, 0, Table.Method, Table.MemberRef, }); /// ResolutionScope coded token public static readonly CodedToken ResolutionScope = new CodedToken(2, new Table[4] { Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef, }); /// TypeOrMethodDef coded token public static readonly CodedToken TypeOrMethodDef = new CodedToken(1, new Table[2] { Table.TypeDef, Table.Method, }); /// HasCustomDebugInformation coded token public static readonly CodedToken HasCustomDebugInformation = new CodedToken(5, new Table[27] { Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef, Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef, Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType, Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec, Table.Document, Table.LocalScope, Table.LocalVariable, Table.LocalConstant, Table.ImportScope, }); readonly int mask; /// /// Returns all types of tables /// public ReadOnlyCollection TableTypes { get; } /// /// Returns the number of bits that is used to encode table type /// public int Bits { get; } /// /// Constructor /// /// Number of bits used to encode token type /// All table types public CodedToken(int bits, Table[] tableTypes) { if (tableTypes is null) throw new ArgumentNullException(nameof(tableTypes)); Bits = bits; mask = (1 << bits) - 1; TableTypes = new ReadOnlyCollection
(tableTypes); } /// /// Encodes a token /// /// The token /// Coded token /// public uint Encode(MDToken token) => Encode(token.Raw); /// /// Encodes a token /// /// The token /// Coded token /// public uint Encode(uint token) { Encode(token, out uint codedToken); return codedToken; } /// /// Encodes a token /// /// The token /// Coded token /// true if successful public bool Encode(MDToken token, out uint codedToken) => Encode(token.Raw, out codedToken); /// /// Encodes a token /// /// The token /// Coded token /// true if successful public bool Encode(uint token, out uint codedToken) { int index = TableTypes.IndexOf(MDToken.ToTable(token)); if (index < 0) { codedToken = uint.MaxValue; return false; } // This shift can never overflow a uint since bits < 8 (it's at most 5), and // ToRid() returns an integer <= 0x00FFFFFF. codedToken = (MDToken.ToRID(token) << Bits) | (uint)index; return true; } /// /// Decodes a coded token /// /// The coded token /// Decoded token or 0 on failure /// public MDToken Decode2(uint codedToken) { Decode(codedToken, out uint token); return new MDToken(token); } /// /// Decodes a coded token /// /// The coded token /// Decoded token or 0 on failure /// public uint Decode(uint codedToken) { Decode(codedToken, out uint token); return token; } /// /// Decodes a coded token /// /// The coded token /// Decoded token /// true if successful public bool Decode(uint codedToken, out MDToken token) { bool result = Decode(codedToken, out uint decodedToken); token = new MDToken(decodedToken); return result; } /// /// Decodes a coded token /// /// The coded token /// Decoded token /// true if successful public bool Decode(uint codedToken, out uint token) { uint rid = codedToken >> Bits; int index = (int)(codedToken & mask); if (rid > MDToken.RID_MAX || index >= TableTypes.Count) { token = 0; return false; } token = ((uint)TableTypes[index] << MDToken.TABLE_SHIFT) | rid; return true; } } }