Index: visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/XamlParser.cs |
diff --git a/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/XamlParser.cs b/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/XamlParser.cs |
new file mode 100644 |
index 0000000000000000000000000000000000000000..099d4dfe816826ee68d8b923c14725ada6270734 |
--- /dev/null |
+++ b/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/XamlParser.cs |
@@ -0,0 +1,152 @@ |
+using System; |
+using System.Collections.Generic; |
+using System.Linq; |
+using System.Text; |
+ |
+using Microsoft.Build.Framework; |
+using System.Xaml; |
+using Microsoft.Build.Framework.XamlTypes; |
+using Microsoft.Build.Utilities; |
+ |
+namespace NaCl.Build.CPPTasks |
+{ |
+ class XamlParser |
+ { |
+ public XamlParser(string path) |
+ { |
+ // load and store properties from xaml file |
+ m_parsedBuildRule = (Rule)XamlServices.Load(path); |
+ |
+ // NOTE: |
+ // There are MSBuild classes which support command line building, |
+ // argument switch encapsulation and more. Code within VCToolTask, |
+ // a hidden interface, uses some these classes to generate command line |
+ // switches given project settings. As the VCToolTask class is a hidden |
+ // class and the MSBuild documentation is very sparse, we are going |
+ // with a small custom solution. For reference see the |
+ // Microsoft.Build.Tasks.Xaml, Microsoft.Build.Framework.XamlTypes namespaces. |
+ |
+ // move the properties to a property name keyed dictionary for faster lookup |
+ ToolProperties = new Dictionary<string, PropertyWrapper>(); |
+ ToolProperties = m_parsedBuildRule.Properties.ToDictionary(x => x.Name, x => (new PropertyWrapper(x.GetType(), x))); |
+ |
+ InitFunctionMap(); |
+ } |
+ |
+ private void InitFunctionMap() |
+ { |
+ m_typeFunctionMap = new Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>> |
+ { |
+ { typeof(StringListProperty), GenerateArgumentStringList }, |
+ { typeof(StringProperty), GenerateArgumentString }, |
+ { typeof(IntProperty), GenerateArgumentString }, |
+ { typeof(BoolProperty), GenerateArgumentBool }, |
+ { typeof(EnumProperty), GenerateArgumentEnum } |
+ }; |
+ } |
+ |
+ public string Parse(ITaskItem taskItem) |
+ { |
+ CommandLineBuilder builder = new CommandLineBuilder(); |
+ |
+ foreach (string name in taskItem.MetadataNames) |
+ { |
+ string value = taskItem.GetMetadata(name); |
+ AppendArgumentForProperty(builder, name, value); |
+ } |
+ |
+ string result = builder.ToString(); |
+ result = result.Replace('\\', '/'); // posix paths |
+ return result; |
+ } |
+ |
+ private string AppendArgumentForProperty(CommandLineBuilder builder, string name, string value) |
+ { |
+ PropertyWrapper current; |
+ ToolProperties.TryGetValue(name, out current); |
+ if (current != null && value.Length > 0) |
+ { |
+ // call appropriate function for type |
+ m_typeFunctionMap[current.PropertyType](builder, current.Property, value); |
+ } |
+ return string.Empty; |
+ } |
+ |
+ private void GenerateArgumentEnum(CommandLineBuilder builder, BaseProperty property, string value) |
+ { |
+ var result = ((EnumProperty)property).AdmissibleValues.Find(x => (x.Name == value)); |
+ if (result != null) |
+ { |
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, result.Switch); |
+ } |
+ } |
+ |
+ // helper for string-based properties |
+ private void AppendStringValue(CommandLineBuilder builder, BaseProperty property, string subtype, string value) |
+ { |
+ value = value.Trim(); |
+ |
+ // could cache this SubType test off in property wrapper or somewhere if performance were an issue |
+ if (subtype == "file" || subtype == "folder") |
+ { |
+ builder.AppendSwitchIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value); |
+ } |
+ else |
+ { |
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix + property.Switch + property.Separator, value); |
+ } |
+ } |
+ |
+ private void GenerateArgumentStringList(CommandLineBuilder builder, BaseProperty property, string value) |
+ { |
+ string [] arguments = value.Split(';'); |
+ |
+ foreach (string argument in arguments) |
+ { |
+ if (argument.Length > 0) |
+ { |
+ StringListProperty casted = (StringListProperty)property; |
+ AppendStringValue(builder, property, casted.Subtype, argument); |
+ } |
+ } |
+ } |
+ |
+ private void GenerateArgumentString(CommandLineBuilder builder, BaseProperty property, string value) |
+ { |
+ // could cache this SubType test off in property wrapper or somewhere if performance were an issue |
+ StringProperty casted = (StringProperty)property; |
+ AppendStringValue(builder, property, casted.Subtype, value); |
+ } |
+ |
+ private void GenerateArgumentBool(CommandLineBuilder builder, BaseProperty property, string value) |
+ { |
+ if (value == "true") |
+ { |
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, property.Switch); |
+ } |
+ else if (value == "false" && ((BoolProperty)property).ReverseSwitch != null) |
+ { |
+ builder.AppendSwitchUnquotedIfNotNull(m_parsedBuildRule.SwitchPrefix, ((BoolProperty)property).ReverseSwitch); |
+ } |
+ } |
+ |
+ // to store off MSBuild property type and allow faster searching on them |
+ private class PropertyWrapper |
+ { |
+ public PropertyWrapper(Type newType, BaseProperty newProperty) |
+ { |
+ PropertyType = newType; |
+ Property = newProperty; |
+ } |
+ public Type PropertyType { get; set; } |
+ public BaseProperty Property { get; set; } |
+ } // class |
+ |
+ private Rule m_parsedBuildRule; |
+ private Dictionary<string, PropertyWrapper> ToolProperties { get; set; } |
+ |
+ // function mapping for easy property function calling |
+ private Dictionary<Type, Action<CommandLineBuilder, BaseProperty, string>> m_typeFunctionMap; |
+ } // XamlParser |
+} // namespace NaCl.Build.CPPTasks |
+ |