/// <summary> /// Reads an existing BAML using BamlReaderWrapper. After reading each node, it calls the given /// callback function, providing the function with the data in the node just read. /// </summary> /// <param name="bamlIn">Path of the BAML to read</param> /// <param name="callback">Function to be called after reading each node</param> public static void ReadBaml(String bamlIn, BamlNodeCallback callback) { // Since we want to reuse the EditBaml function, we need to have an output BAML // file. So we create a temporary file, use the EditBaml function, and then // discard the temporary file. String tempFile = Path.GetTempFileName(); EditBaml(bamlIn, tempFile, callback); File.Delete(tempFile); }
/// <summary> /// Reads an existing BAML using BamlReaderWrapper, allows editing of the contents /// and writes the (possibly modified) contents to a new BAML using BamlWriterWrapper. /// /// After each node is read from the BamlReaderWrapper, it calls the given callback function, /// passing the data in the node just read. The callback function can then modify the /// data. The callback function is also passed the BamlWriterWrapper, so that it can add /// nodes, if it wants. /// /// The callback function is supposed to return a BamlNodeAction, specifiying /// whether the current BAML node should be written to the output BAML file. /// By returning BamlNodeAction.Skip, the callback function can specify to delete nodes. /// /// If the callback function returns BamlNodeAction.Continue, then the (possibly modified) /// contents will be written into the new BAML. /// </summary> /// <param name="bamlIn">Path of the Original BAML</param> /// <param name="bamlOut">Path of the BAML to be written</param> /// <param name="callback">EditBamlNode callback. Can be null.</param> public static void EditBaml(string bamlIn, string bamlOut, BamlNodeCallback callback) { Stream bamlInStream = File.OpenRead(bamlIn); Stream bamlOutStream = File.OpenWrite(bamlOut); try { EditBaml(bamlInStream, bamlOutStream, callback); } finally { bamlInStream.Close(); bamlOutStream.Close(); } }
/// <summary> /// Reads an existing BAML using BamlReaderWrapper, allows editing of the contents /// and writes the (possibly modified) contents to a new BAML using BamlWriterWrapper. /// /// After each node is read from the BamlReaderWrapper, it calls the given callback function, /// passing the data in the node just read. The callback function can then modify the /// data. The callback function is also passed the BamlWriterWrapper, so that it can add /// nodes, if it wants. /// /// The callback function is supposed to return a BamlNodeAction, specifiying /// whether the current BAML node should be written to the output BAML file. /// By returning BamlNodeAction.Skip, the callback function can specify to delete nodes. /// /// If the callback function returns BamlNodeAction.Continue, then the (possibly modified) /// contents will be written into the new BAML. /// </summary> /// <param name="bamlIn">Path of the Original BAML</param> /// <param name="bamlOut">Path of the BAML to be written</param> /// <param name="callback">EditBamlNode callback. Can be null.</param> public static void EditBaml(Stream bamlIn, Stream bamlOut, BamlNodeCallback callback) { BamlReaderWrapper reader = new BamlReaderWrapper(bamlIn); BamlWriterWrapper writer = new BamlWriterWrapper(bamlOut); // Stack for verifying matching BAML nodes Stack matchingStack = new Stack(); BamlNodeData expectedData; // Default action, in case there is no callback specified. BamlNodeAction action = BamlNodeAction.Continue; // Go through the input BAML, reading different types of records and // writing them to the output BAML while (reader.Read()) { // Copy the significant fields from BamlReaderWrapper to BamlNodeData // This nodeData can be then passed to a BamlNodeCallback delegate BamlNodeData nodeData = new BamlNodeData(); PopulateBamlNodeData(reader, nodeData); // Make another copy for pushing to stack, in case of those nodes // which we are checking for node matching // We cannot work with the previous copy, since that may be modified by the // callback. BamlNodeData stackData = new BamlNodeData(); PopulateBamlNodeData(reader, stackData); switch (reader.NodeType) { case "StartDocument": matchingStack.Push(stackData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteStartDocument(); } break; case "EndDocument": // Test for matching BAML nodes. // Try to match the data with StartDocument's data if (matchingStack.Count <= 0) { throw new Exception("Unmatched BAML nodes found"); } expectedData = matchingStack.Pop() as BamlNodeData; if (expectedData.NodeType != "StartDocument") { throw new Exception("Unmatched BAML nodes found"); } CompareBamlNodes(stackData, expectedData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteEndDocument(); } break; case "StartElement": matchingStack.Push(stackData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteStartElement(nodeData.AssemblyName, nodeData.Name, nodeData.IsInjected, nodeData.CreateUsingTypeConverter); } break; case "EndElement": // Test for matching BAML nodes. // Try to match the data with StartElement's data if (matchingStack.Count <= 0) { throw new Exception("Unmatched BAML nodes found"); } expectedData = matchingStack.Pop() as BamlNodeData; if (expectedData.NodeType != "StartElement") { throw new Exception("Unmatched BAML nodes found"); } CompareBamlNodes(stackData, expectedData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteEndElement(); } break; case "StartConstructor": matchingStack.Push(stackData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteStartConstructor(); } break; case "EndConstructor": // Test for matching BAML nodes. // Try to match the data with StartConstructor's data if (matchingStack.Count <= 0) { throw new Exception("Unmatched BAML nodes found"); } expectedData = matchingStack.Pop() as BamlNodeData; if (expectedData.NodeType != "StartConstructor") { throw new Exception("Unmatched BAML nodes found"); } CompareBamlNodes(stackData, expectedData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteEndConstructor(); } break; case "StartComplexProperty": matchingStack.Push(stackData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteStartComplexProperty(nodeData.AssemblyName, nodeData.Name.Substring(0, nodeData.Name.LastIndexOf('.')), nodeData.LocalName); } break; case "EndComplexProperty": // Test for matching BAML nodes. // Try to match the data with StartComplexProperty's data if (matchingStack.Count <= 0) { throw new Exception("Unmatched BAML nodes found"); } expectedData = matchingStack.Pop() as BamlNodeData; if (expectedData.NodeType != "StartComplexProperty") { throw new Exception("Unmatched BAML nodes found"); } CompareBamlNodes(stackData, expectedData); if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteEndComplexProperty(); } break; case "LiteralContent": if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteLiteralContent(nodeData.Value); } break; case "Text": if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteText(nodeData.Value, nodeData.TypeConverterAssemblyName, nodeData.TypeConverterName); } break; case "RoutedEvent": if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteRoutedEvent(nodeData.AssemblyName, nodeData.Name.Substring(0, nodeData.Name.LastIndexOf('.')), nodeData.LocalName, nodeData.Value); } break; case "Event": if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteEvent(nodeData.LocalName, nodeData.Value); } break; case "IncludeReference": if (callback != null) { action = callback(nodeData, writer); } break; case "PIMapping": if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WritePIMapping(nodeData.XmlNamespace, nodeData.ClrNamespace, nodeData.AssemblyName); } break; default: throw new Exception("Unexpected NodeType read from BamlReaderWrapper"); } // Property nodes are not provided by BamlReaderWrapper when Read() is called // We need to go through them separately. if (reader.HasProperties) { reader.MoveToFirstProperty(); do { // This has to be present in this loop, because reader values // keep changing as we move thru the properties PopulateBamlNodeData(reader, nodeData); if (reader.NodeType == "Property") { if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteProperty(nodeData.AssemblyName, nodeData.Name.Substring(0, nodeData.Name.LastIndexOf('.')), nodeData.LocalName, nodeData.Value, nodeData.AttributeUsage); } } else if (reader.NodeType == "ContentProperty") { if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteContentProperty(nodeData.AssemblyName, nodeData.Name.Substring(0, nodeData.Name.LastIndexOf('.')), nodeData.LocalName); } } else if (reader.NodeType == "DefAttribute") { if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteDefAttribute(nodeData.Name, nodeData.Value); } } else if (reader.NodeType == "XmlnsProperty") { if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteXmlnsProperty(nodeData.LocalName, nodeData.Value); } } else if (reader.NodeType == "ConnectionId") { if (callback != null) { action = callback(nodeData, writer); } if (BamlNodeAction.Continue == action) { writer.WriteConnectionId(Int32.Parse(nodeData.Value)); } } else { throw new Exception("Unexpected NodeType read from BamlReaderWrapper while trying to read properties on an element"); } } while (reader.MoveToNextProperty()); } } // Check that matching stack is empty if (matchingStack.Count != 0) { throw new Exception("Unmatched BAML nodes found"); } }