obfuz/Plugins/dnlib/DotNet/Pdb/Portable/ImportScopeBlobReader.cs

134 lines
4.7 KiB
C#
Raw Normal View History

// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using System.Diagnostics;
using dnlib.DotNet.MD;
namespace dnlib.DotNet.Pdb.Portable {
// https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PortablePdb-Metadata.md#imports-blob
readonly struct ImportScopeBlobReader {
readonly ModuleDef module;
readonly BlobStream blobStream;
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Module that resolves assembly and type references</param>
/// <param name="blobStream">Portable PDB blob stream</param>
public ImportScopeBlobReader(ModuleDef module, BlobStream blobStream) {
this.module = module;
this.blobStream = blobStream;
}
public void Read(uint imports, IList<PdbImport> result) {
if (imports == 0)
return;
if (!blobStream.TryCreateReader(imports, out var reader))
return;
while (reader.Position < reader.Length) {
var kind = ImportDefinitionKindUtils.ToPdbImportDefinitionKind(reader.ReadCompressedUInt32());
string targetNamespace, alias;
AssemblyRef targetAssembly;
PdbImport import;
ITypeDefOrRef targetType;
switch (kind) {
case PdbImportDefinitionKind.ImportNamespace:
// <import> ::= ImportNamespace <target-namespace>
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportNamespace(targetNamespace);
break;
case PdbImportDefinitionKind.ImportAssemblyNamespace:
// <import> ::= ImportAssemblyNamespace <target-assembly> <target-namespace>
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportAssemblyNamespace(targetAssembly, targetNamespace);
break;
case PdbImportDefinitionKind.ImportType:
// <import> ::= ImportType <target-type>
targetType = TryReadType(reader.ReadCompressedUInt32());
import = new PdbImportType(targetType);
break;
case PdbImportDefinitionKind.ImportXmlNamespace:
// <import> ::= ImportXmlNamespace <alias> <target-namespace>
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportXmlNamespace(alias, targetNamespace);
break;
case PdbImportDefinitionKind.ImportAssemblyReferenceAlias:
// <import> ::= ImportReferenceAlias <alias>
alias = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportAssemblyReferenceAlias(alias);
break;
case PdbImportDefinitionKind.AliasAssemblyReference:
// <import> ::= AliasAssemblyReference <alias> <target-assembly>
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
import = new PdbAliasAssemblyReference(alias, targetAssembly);
break;
case PdbImportDefinitionKind.AliasNamespace:
// <import> ::= AliasNamespace <alias> <target-namespace>
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbAliasNamespace(alias, targetNamespace);
break;
case PdbImportDefinitionKind.AliasAssemblyNamespace:
// <import> ::= AliasAssemblyNamespace <alias> <target-assembly> <target-namespace>
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbAliasAssemblyNamespace(alias, targetAssembly, targetNamespace);
break;
case PdbImportDefinitionKind.AliasType:
// <import> ::= AliasType <alias> <target-type>
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetType = TryReadType(reader.ReadCompressedUInt32());
import = new PdbAliasType(alias, targetType);
break;
case ImportDefinitionKindUtils.UNKNOWN_IMPORT_KIND:
import = null;
break;
default:
Debug.Fail($"Unknown import definition kind: {kind}");
import = null;
break;
}
if (import is not null)
result.Add(import);
}
Debug.Assert(reader.Position == reader.Length);
}
ITypeDefOrRef TryReadType(uint codedToken) {
bool b = CodedToken.TypeDefOrRef.Decode(codedToken, out uint token);
Debug.Assert(b);
if (!b)
return null;
var type = module.ResolveToken(token) as ITypeDefOrRef;
Debug.Assert(type is not null);
return type;
}
AssemblyRef TryReadAssemblyRef(uint rid) {
var asmRef = module.ResolveToken(0x23000000 + rid) as AssemblyRef;
Debug.Assert(asmRef is not null);
return asmRef;
}
string ReadUTF8(uint offset) {
if (!blobStream.TryCreateReader(offset, out var reader))
return string.Empty;
return reader.ReadUtf8String((int)reader.BytesLeft);
}
}
}