ac56ec2400f88700dd1ad07da9878556ec5dd6c7
[platform/core/csapi/xsf.git] / src / XSF.Build.Tasks / XamlTask.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Xml;
6
7 using Microsoft.Build.Framework;
8 using Microsoft.Build.Utilities;
9
10 using Mono.Cecil;
11
12 using Xamarin.Forms.Xaml;
13 using Mono.Cecil.Cil;
14 using Mono.Cecil.Pdb;
15 using Mono.Cecil.Mdb;
16 using System.ComponentModel;
17
18 namespace Xamarin.Forms.Build.Tasks
19 {
20         [LoadInSeparateAppDomain]
21         public abstract class XamlTask : MarshalByRefObject, ITask
22         {
23                 [Required]
24                 public string Assembly { get; set; }
25                 public string DependencyPaths { get; set; }
26                 public string ReferencePath { get; set; }
27                 [Obsolete("this is no longer used")]
28                 [EditorBrowsable(EditorBrowsableState.Never)]
29                 public int Verbosity { get; set; }
30                 public bool DebugSymbols { get; set; }
31                 public string DebugType { get; set; }
32
33                 protected TaskLoggingHelper LoggingHelper { get; }
34
35                 internal XamlTask()
36                 {
37                         LoggingHelper = new TaskLoggingHelper(this);
38                 }
39
40                 public IBuildEngine BuildEngine { get; set; }
41                 public ITaskHost HostObject { get; set; }
42
43                 public bool Execute()
44                 {
45                         IList<Exception> _;
46                         return Execute(out _);
47                 }
48
49                 public abstract bool Execute(out IList<Exception> thrownExceptions);
50
51                 internal static ILRootNode ParseXaml(Stream stream, TypeReference typeReference)
52                 {
53                         ILRootNode rootnode = null;
54                         using (var reader = XmlReader.Create(stream)) {
55                                 while (reader.Read()) {
56                                         //Skip until element
57                                         if (reader.NodeType == XmlNodeType.Whitespace)
58                                                 continue;
59                                         if (reader.NodeType != XmlNodeType.Element) {
60                                                 Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
61                                                 continue;
62                                         }
63
64                                         XamlParser.ParseXaml(
65                                                 rootnode = new ILRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), typeReference, reader as IXmlNamespaceResolver, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition), reader);
66                                         break;
67                                 }
68                         }
69                         return rootnode;
70                 }
71         }
72
73         static class CecilExtensions
74         {
75                 public static bool IsXaml(this EmbeddedResource resource, ModuleDefinition module, out string classname)
76                 {
77                         classname = null;
78                         if (!resource.Name.EndsWith(".xaml", StringComparison.InvariantCulture))
79                                 return false;
80
81                         using (var resourceStream = resource.GetResourceStream()) {
82                                 var xmlDoc = new XmlDocument();
83                                 xmlDoc.Load(resourceStream);
84
85                                 var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
86
87                                 var root = xmlDoc.SelectSingleNode("/*", nsmgr);
88                                 if (root == null)
89                                         return false;
90
91                                 var rootClass = root.Attributes["Class", XamlParser.X2006Uri] ??
92                                                                 root.Attributes["Class", XamlParser.X2009Uri];
93                                 if (rootClass != null) {
94                                         classname = rootClass.Value;
95                                         return true;
96                                 }
97
98                                 //no x:Class, but it might be a RD without x:Class and with <?xaml-comp compile="true" ?>
99                                 //in that case, it has a XamlResourceIdAttribute
100                                 var typeRef = GetTypeForResourceId(module, resource.Name);
101                                 if (typeRef != null) {
102                                         classname = typeRef.FullName;
103                                         return true;
104                                 }
105
106                                 return false;
107                         }
108                 }
109
110                 static TypeReference GetTypeForResourceId(ModuleDefinition module, string resourceId)
111                 {
112                         foreach (var ca in module.GetCustomAttributes()) {
113                                 if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(("XSF", "Xamarin.Forms.Xaml", "XamlResourceIdAttribute"))))
114                                         continue;
115                                 if (ca.ConstructorArguments[0].Value as string != resourceId)
116                                         continue;
117                                 return ca.ConstructorArguments[2].Value as TypeReference;
118                         }
119                         return null;
120                 }
121         }
122 }