File: Linker\EmbeddedXmlInfo.cs
Web Access
Project: src\src\tools\illink\src\linker\Mono.Linker.csproj (illink)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System;
using System.Linq;
using System.Xml;
using ILLink.Shared;
using Mono.Cecil;
using Mono.Linker.Steps;
 
namespace Mono.Linker
{
	public class EmbeddedXmlInfo
	{
		static EmbeddedResource? GetEmbeddedXml (AssemblyDefinition assembly, Func<Resource, bool> predicate)
		{
			return assembly.Modules
				.SelectMany (mod => mod.Resources)
				.Where (res => res.ResourceType == ResourceType.Embedded)
				.Where (res => res.Name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase))
				.Where (res => predicate (res))
				.SingleOrDefault () as EmbeddedResource;
		}
 
		public void ProcessDescriptors (AssemblyDefinition assembly, LinkContext context)
		{
			if (context.Annotations.GetAction (assembly) == AssemblyAction.Skip)
				return;
 
			var rsc = GetEmbeddedXml (assembly, res => ShouldProcessRootDescriptorResource (assembly, context, res.Name));
			if (rsc == null)
				return;
 
			DescriptorMarker? marker = null;
			try {
				context.LogMessage ($"Processing embedded trimming descriptor '{rsc.Name}' from '{assembly.Name}'.");
				marker = GetExternalResolveStep (context, rsc, assembly);
			} catch (XmlException ex) {
				/* This could happen if some broken XML file is embedded. */
				context.LogError (null, DiagnosticId.XmlException, rsc.Name, ex.ToString ());
			}
 
			marker?.Mark ();
		}
 
		public SubstitutionInfo? ProcessSubstitutions (AssemblyDefinition assembly, LinkContext context)
		{
			if (context.Annotations.GetAction (assembly) == AssemblyAction.Skip)
				return null;
 
			var rsc = GetEmbeddedXml (assembly, res => res.Name.Equals ("ILLink.Substitutions.xml", StringComparison.OrdinalIgnoreCase));
			if (rsc == null)
				return null;
 
			BodySubstitutionParser? parser = null;
			try {
				context.LogMessage ($"Processing embedded substitution descriptor '{rsc.Name}' from '{assembly.Name}'.");
				parser = GetExternalSubstitutionParser (context, rsc, assembly);
			} catch (XmlException ex) {
				context.LogError (null, DiagnosticId.XmlException, rsc.Name, ex.ToString ());
			}
 
			if (parser == null)
				return null;
 
			var substitutionInfo = new SubstitutionInfo ();
			parser.Parse (substitutionInfo);
			return substitutionInfo;
		}
 
		public AttributeInfo? ProcessAttributes (AssemblyDefinition assembly, LinkContext context)
		{
			if (context.Annotations.GetAction (assembly) == AssemblyAction.Skip)
				return null;
 
			var rsc = GetEmbeddedXml (assembly, res => res.Name.Equals ("ILLink.LinkAttributes.xml", StringComparison.OrdinalIgnoreCase));
			if (rsc == null)
				return null;
 
			LinkAttributesParser? parser = null;
			try {
				context.LogMessage ($"Processing embedded '{rsc.Name}' from '{assembly.Name}'.");
				parser = GetExternalLinkAttributesParser (context, rsc, assembly);
			} catch (XmlException ex) {
				context.LogError (null, DiagnosticId.XmlException, rsc.Name, ex.ToString ());
			}
 
			if (parser == null)
				return null;
 
			var attributeInfo = new AttributeInfo ();
			parser.Parse (attributeInfo);
			return attributeInfo;
		}
 
		static string GetAssemblyName (string descriptor)
		{
			int pos = descriptor.LastIndexOf ('.');
			if (pos == -1)
				return descriptor;
 
			return descriptor.Substring (0, pos);
		}
 
		static bool ShouldProcessRootDescriptorResource (AssemblyDefinition assembly, LinkContext context, string resourceName)
		{
			if (resourceName.Equals ("ILLink.Descriptors.xml", StringComparison.OrdinalIgnoreCase))
				return true;
 
			if (GetAssemblyName (resourceName) != assembly.Name.Name)
				return false;
 
			switch (context.Annotations.GetAction (assembly)) {
			case AssemblyAction.Link:
			case AssemblyAction.AddBypassNGen:
			case AssemblyAction.AddBypassNGenUsed:
			case AssemblyAction.Copy:
				return true;
			default:
				return false;
			}
		}
 
		protected virtual DescriptorMarker GetExternalResolveStep (LinkContext context, EmbeddedResource resource, AssemblyDefinition assembly)
		{
			return new DescriptorMarker (context, resource.GetResourceStream (), resource, assembly, "resource " + resource.Name + " in " + assembly.FullName);
		}
 
		protected virtual BodySubstitutionParser GetExternalSubstitutionParser (LinkContext context, EmbeddedResource resource, AssemblyDefinition assembly)
		{
			return new BodySubstitutionParser (context, resource.GetResourceStream (), resource, assembly, "resource " + resource.Name + " in " + assembly.FullName);
		}
 
		protected virtual LinkAttributesParser GetExternalLinkAttributesParser (LinkContext context, EmbeddedResource resource, AssemblyDefinition assembly)
		{
			return new LinkAttributesParser (context, resource.GetResourceStream (), resource, assembly, "resource " + resource.Name + " in " + assembly.FullName);
		}
	}
}