// 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;
///
/// Constructor
///
/// Module that resolves assembly and type references
/// Portable PDB blob stream
public ImportScopeBlobReader(ModuleDef module, BlobStream blobStream) {
this.module = module;
this.blobStream = blobStream;
}
public void Read(uint imports, IList 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:
// ::= ImportNamespace
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportNamespace(targetNamespace);
break;
case PdbImportDefinitionKind.ImportAssemblyNamespace:
// ::= ImportAssemblyNamespace
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportAssemblyNamespace(targetAssembly, targetNamespace);
break;
case PdbImportDefinitionKind.ImportType:
// ::= ImportType
targetType = TryReadType(reader.ReadCompressedUInt32());
import = new PdbImportType(targetType);
break;
case PdbImportDefinitionKind.ImportXmlNamespace:
// ::= ImportXmlNamespace
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportXmlNamespace(alias, targetNamespace);
break;
case PdbImportDefinitionKind.ImportAssemblyReferenceAlias:
// ::= ImportReferenceAlias
alias = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbImportAssemblyReferenceAlias(alias);
break;
case PdbImportDefinitionKind.AliasAssemblyReference:
// ::= AliasAssemblyReference
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
import = new PdbAliasAssemblyReference(alias, targetAssembly);
break;
case PdbImportDefinitionKind.AliasNamespace:
// ::= AliasNamespace
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbAliasNamespace(alias, targetNamespace);
break;
case PdbImportDefinitionKind.AliasAssemblyNamespace:
// ::= AliasAssemblyNamespace
alias = ReadUTF8(reader.ReadCompressedUInt32());
targetAssembly = TryReadAssemblyRef(reader.ReadCompressedUInt32());
targetNamespace = ReadUTF8(reader.ReadCompressedUInt32());
import = new PdbAliasAssemblyNamespace(alias, targetAssembly, targetNamespace);
break;
case PdbImportDefinitionKind.AliasType:
// ::= AliasType
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);
}
}
}