// 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); } } }