File: XamlTask.cs
Web Access
Project: src\src\Controls\src\Build.Tasks\Controls.Build.Tasks.csproj (Microsoft.Maui.Controls.Build.Tasks)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Maui.Controls.Xaml;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Mdb;
using Mono.Cecil.Pdb;
 
namespace Microsoft.Maui.Controls.Build.Tasks
{
	public abstract class XamlTask : MarshalByRefObject, ITask
	{
		[Required]
		public string Assembly { get; set; }
		public string[] ReferencePath { get; set; }
		public bool DebugSymbols { get; set; }
		public string DebugType { get; set; }
 
		internal TaskLoggingHelper LoggingHelper { get; }
 
		internal XamlTask()
		{
			LoggingHelper = new TaskLoggingHelper(this);
		}
 
		public IBuildEngine BuildEngine { get; set; }
		public ITaskHost HostObject { get; set; }
 
		public bool Execute()
		{
			IList<Exception> _;
			return Execute(out _);
		}
 
		public abstract bool Execute(out IList<Exception> thrownExceptions);
 
		internal static ILRootNode ParseXaml(Stream stream, TypeReference typeReference)
		{
			using (var reader = XmlReader.Create(stream))
			{
				while (reader.Read())
				{
					//Skip until element
					if (reader.NodeType == XmlNodeType.Whitespace)
						continue;
					if (reader.NodeType != XmlNodeType.Element)
					{
						Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
						continue;
					}
 
					var xmlType = new XmlType(reader.NamespaceURI, reader.Name, XamlParser.GetTypeArguments(reader));
					var rootnode = new ILRootNode(xmlType, typeReference, reader as IXmlNamespaceResolver, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition);
					XamlParser.ParseXaml(rootnode, reader);
					return rootnode;
				}
			}
			return null;
		}
	}
 
	static class CecilExtensions
	{
		public static bool IsXaml(this EmbeddedResource resource, XamlCache cache, ModuleDefinition module, out string classname)
		{
			classname = null;
			if (!resource.Name.EndsWith(".xaml", StringComparison.InvariantCulture))
				return false;
 
			using (var resourceStream = resource.GetResourceStream())
			using (var reader = XmlReader.Create(resourceStream))
			{
				// Read to the first Element
				while (reader.Read() && reader.NodeType != XmlNodeType.Element)
					;
 
				if (reader.NodeType != XmlNodeType.Element)
					return false;
 
				classname = reader.GetAttribute("Class", XamlParser.X2009Uri) ??
							reader.GetAttribute("Class", XamlParser.X2006Uri);
				if (classname != null)
					return true;
 
				//no x:Class, but it might be a RD without x:Class and with <?xaml-comp compile="true" ?>
				//in that case, it has a XamlResourceIdAttribute
				var typeRef = GetTypeForResourceId(cache, module, resource.Name);
				if (typeRef != null)
				{
					classname = typeRef.FullName;
					return true;
				}
 
				return false;
			}
		}
 
		static TypeReference GetTypeForResourceId(XamlCache cache, ModuleDefinition module, string resourceId)
		{
			foreach (var ca in module.GetCustomAttributes())
			{
				if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "XamlResourceIdAttribute"))))
					continue;
				if (ca.ConstructorArguments[0].Value as string != resourceId)
					continue;
				return ca.ConstructorArguments[2].Value as TypeReference;
			}
			return null;
		}
	}
}