| File: Compiler\DependencyAnalysis\ResourceDataNode.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using Internal.Text; using Internal.TypeSystem.Ecma; namespace ILCompiler.DependencyAnalysis { /// <summary> /// Blob of data containing resources for all assemblies generated into the image. /// Resources are simply copied from the inputs and concatenated into this blob. /// All format information is provided by <see cref="ResourceIndexNode"/> /// </summary> internal sealed class ResourceDataNode : ObjectNode, ISymbolDefinitionNode { /// <summary> /// Resource index information generated while extracting resources into the data blob /// </summary> private List<ResourceIndexData> _indexData; private int _totalLength; public override bool IsShareable => false; public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection; public override bool StaticDependenciesAreComputed => true; public int Offset => 0; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix).Append("__embedded_resourcedata"u8); } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node has no relocations. if (relocsOnly) return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); byte[] blob = GenerateResourceBlob(factory); return new ObjectData( blob, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); } public IReadOnlyList<ResourceIndexData> GetOrCreateIndexData(NodeFactory factory) { if (_indexData != null) { return _indexData; } _totalLength = 0; _indexData = new List<ResourceIndexData>(); // Build up index information foreach (EcmaAssembly module in factory.MetadataManager.GetCompilationModulesWithMetadata().OfType<EcmaAssembly>()) { PEMemoryBlock resourceDirectory = module.PEReader.GetSectionData(module.PEReader.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress); try { checked { foreach (var resourceHandle in module.MetadataReader.ManifestResources) { ManifestResource resource = module.MetadataReader.GetManifestResource(resourceHandle); // Don't try to embed linked resources or resources in other assemblies if (!resource.Implementation.IsNil) { continue; } string resourceName = module.MetadataReader.GetString(resource.Name); // Check if emitting the manifest resource is blocked by policy. if (factory.MetadataManager.IsManifestResourceBlocked(factory, module, resourceName)) continue; BlobReader reader = resourceDirectory.GetReader((int)resource.Offset, resourceDirectory.Length - (int)resource.Offset); int length = (int)reader.ReadUInt32(); ResourceIndexData indexData = new ResourceIndexData(module, resourceName, _totalLength, (int)resource.Offset + sizeof(int), module, length); _indexData.Add(indexData); _totalLength += length; } } } catch (OverflowException) { throw new BadImageFormatException(); } } return _indexData; } /// <summary> /// Extracts resources from all modules being compiled into a single blob and saves /// the information needed to create an index into that blob. /// </summary> private byte[] GenerateResourceBlob(NodeFactory factory) { GetOrCreateIndexData(factory); // Read resources into the blob byte[] resourceBlob = new byte[_totalLength]; int currentPos = 0; foreach (ResourceIndexData indexData in _indexData) { EcmaModule module = indexData.EcmaModule; PEMemoryBlock resourceDirectory = module.PEReader.GetSectionData(module.PEReader.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress); Debug.Assert(currentPos == indexData.NativeOffset); BlobReader reader = resourceDirectory.GetReader(indexData.EcmaOffset, indexData.Length); byte[] resourceData = reader.ReadBytes(indexData.Length); Buffer.BlockCopy(resourceData, 0, resourceBlob, currentPos, resourceData.Length); currentPos += resourceData.Length; } return resourceBlob; } protected internal override int Phase => (int)ObjectNodePhase.Ordered; public override int ClassCode => (int)ObjectNodeOrder.ResourceDataNode; } /// <summary> /// Data about individual manifest resources /// </summary> internal sealed class ResourceIndexData { public ResourceIndexData(EcmaAssembly assembly, string resourceName, int nativeOffset, int ecmaOffset, EcmaModule ecmaModule, int length) { Assembly = assembly; ResourceName = resourceName; NativeOffset = nativeOffset; EcmaOffset = ecmaOffset; EcmaModule = ecmaModule; Length = length; } /// <summary> /// Assembly that contains the resource /// </summary> public EcmaAssembly Assembly { get; } /// <summary> /// Name of the resource /// </summary> public string ResourceName { get; } /// <summary> /// Offset of the resource within the native resource blob /// </summary> public int NativeOffset { get; } /// <summary> /// Offset of the resource within the .mresources section of the ECMA module /// </summary> public int EcmaOffset { get; } /// <summary> /// Module the resource is defined in /// </summary> public EcmaModule EcmaModule { get; } /// <summary> /// Length of the resource /// </summary> public int Length { get; } } }