/// <summary> /// It seems like BamlReader will always output 'x:Key' as last property. However, it must be specified as attribute in valid .xaml, so we move it to the front /// of the attribute list. /// </summary> void MoveXKeyToFront(XamlNode node) { foreach (XamlNode child in node.Children) { MoveXKeyToFront(child); } XamlObjectNode obj = node as XamlObjectNode; if (obj != null && obj.Children.Count > 0) { XamlMemberNode memberNode = obj.Children[obj.Children.Count - 1] as XamlMemberNode; if (memberNode != null && memberNode.Member == XamlLanguage.Key) { // move memberNode in front of the first member node: for (int i = 0; i < obj.Children.Count; i++) { if (obj.Children[i] is XamlMemberNode) { obj.Children.Insert(i, memberNode); obj.Children.RemoveAt(obj.Children.Count - 1); break; } } } } }
private static void CloseTag(string name, SymbolScanner scanner, Stack <XamlObjectNode> objStack) { XamlObjectNode objectNode = null; List <XamlObjectNode> children = new List <XamlObjectNode>(); while (objStack.Count > 0) { objectNode = objStack.Peek(); if (objectNode.Name == name) { objectNode.LineNumberEnd = scanner.LineNumber + 1; // it must be point to the next symbol so '-1' objectNode.LinePositionEnd = scanner.CharPosition; foreach (XamlObjectNode node in children) { objectNode.AddChild(node); } objectNode.SetState(XamlNodeBase.EState.Closed); //remove found node from stack objStack.Pop(); break; } children.Add(objectNode); objectNode = objStack.Pop(); } }
static List <XamlNode> Parse(XamlReader reader) { List <XamlNode> currentList = new List <XamlNode>(); Stack <List <XamlNode> > stack = new Stack <List <XamlNode> >(); while (reader.Read()) { switch (reader.NodeType) { case XamlNodeType.None: break; case XamlNodeType.StartObject: XamlObjectNode obj = new XamlObjectNode(reader.Type); currentList.Add(obj); stack.Push(currentList); currentList = obj.Children; break; case XamlNodeType.GetObject: XamlGetObjectNode getObject = new XamlGetObjectNode(); currentList.Add(getObject); stack.Push(currentList); currentList = getObject.Children; break; case XamlNodeType.StartMember: XamlMemberNode member = new XamlMemberNode(reader.Member); currentList.Add(member); stack.Push(currentList); currentList = member.Children; break; case XamlNodeType.Value: currentList.Add(new XamlValueNode(reader.Value)); break; case XamlNodeType.NamespaceDeclaration: currentList.Add(new XamlNamespaceDeclarationNode(reader.Namespace)); break; case XamlNodeType.EndObject: case XamlNodeType.EndMember: currentList = stack.Pop(); break; default: throw new InvalidOperationException("Invalid value for XamlNodeType"); } } if (stack.Count != 0) { throw new InvalidOperationException("Imbalanced stack"); } return(currentList); }
void RemoveConnectionIds(XamlNode node, Dictionary <int, EventRegistration[]> eventMappings, XamlSchemaContext context) { foreach (XamlNode child in node.Children) { RemoveConnectionIds(child, eventMappings, context); } XamlObjectNode obj = node as XamlObjectNode; if (obj != null && obj.Children.Count > 0) { var removableNodes = new List <XamlMemberNode>(); var addableNodes = new List <XamlMemberNode>(); foreach (XamlMemberNode memberNode in obj.Children.OfType <XamlMemberNode>()) { if (memberNode.Member == XamlLanguage.ConnectionId && memberNode.Children.Single() is XamlValueNode) { var value = memberNode.Children.Single() as XamlValueNode; int id; if (value.Value is string && int.TryParse(value.Value as string, out id) && eventMappings.ContainsKey(id)) { var map = eventMappings[id]; foreach (var entry in map) { if (entry.IsAttached) { var type = context.GetXamlType(Type.GetType(entry.AttachSourceType)); var member = new XamlMemberNode(new XamlMember(entry.EventName, type, true)); member.Children.Add(new XamlValueNode(entry.MethodName)); addableNodes.Add(member); } else { var member = new XamlMemberNode(obj.Type.GetMember(entry.EventName)); member.Children.Add(new XamlValueNode(entry.MethodName)); addableNodes.Add(member); } } removableNodes.Add(memberNode); } } } foreach (var rnode in removableNodes) { node.Children.Remove(rnode); } node.Children.InsertRange(node.Children.Count > 1 ? node.Children.Count - 1 : 0, addableNodes); } }
void AvoidContentProperties(XamlNode node) { foreach (XamlNode child in node.Children) { AvoidContentProperties(child); } XamlObjectNode obj = node as XamlObjectNode; if (obj != null) { // Visit all except for the last child: for (int i = 0; i < obj.Children.Count - 1; i++) { // Avoids using content property syntax for simple string values, if the content property is not the last member. // Without this, we cannot decompile <GridViewColumn Header="Culture" DisplayMemberBinding="{Binding Culture}" />, // because the Header property is the content property, but there is no way to represent the Binding as an element. XamlMemberNode memberNode = obj.Children[i] as XamlMemberNode; if (memberNode != null && memberNode.Member == obj.Type.ContentProperty) { if (memberNode.Children.Count == 1 && memberNode.Children[0] is XamlValueNode) { // By creating a clone of the XamlMember, we prevent WPF from knowing that it's the content property. XamlMember member = memberNode.Member; memberNode.Member = new XamlMember(member.Name, member.DeclaringType, member.IsAttachable); } } } // We also need to avoid using content properties that have a markup extension as value, as the XamlXmlWriter would always expand those: for (int i = 0; i < obj.Children.Count; i++) { XamlMemberNode memberNode = obj.Children[i] as XamlMemberNode; if (memberNode != null && memberNode.Member == obj.Type.ContentProperty && memberNode.Children.Count == 1) { XamlObjectNode me = memberNode.Children[0] as XamlObjectNode; if (me != null && me.Type.IsMarkupExtension) { // By creating a clone of the XamlMember, we prevent WPF from knowing that it's the content property. XamlMember member = memberNode.Member; memberNode.Member = new XamlMember(member.Name, member.DeclaringType, member.IsAttachable); } } } } }
private void Visit(XamlNodeBase node, IXamlNodeVisitor visitor) { if (visitor.IsAllowedToVisit(node)) { visitor.Visit(node, this); } XamlObjectNode objectNode = node as XamlObjectNode; if (objectNode != null) { foreach (XamlAttribute attribute in objectNode.Attributes) { Visit(attribute, visitor); } foreach (XamlNodeBase child in objectNode.Children) { Visit(child, visitor); } } }
static List<XamlNode> Parse(XamlReader reader) { List<XamlNode> currentList = new List<XamlNode>(); Stack<List<XamlNode>> stack = new Stack<List<XamlNode>>(); while (reader.Read()) { switch (reader.NodeType) { case XamlNodeType.None: break; case XamlNodeType.StartObject: XamlObjectNode obj = new XamlObjectNode(reader.Type); currentList.Add(obj); stack.Push(currentList); currentList = obj.Children; break; case XamlNodeType.GetObject: XamlGetObjectNode getObject = new XamlGetObjectNode(); currentList.Add(getObject); stack.Push(currentList); currentList = getObject.Children; break; case XamlNodeType.StartMember: XamlMemberNode member = new XamlMemberNode(reader.Member); currentList.Add(member); stack.Push(currentList); currentList = member.Children; break; case XamlNodeType.Value: currentList.Add(new XamlValueNode(reader.Value)); break; case XamlNodeType.NamespaceDeclaration: currentList.Add(new XamlNamespaceDeclarationNode(reader.Namespace)); break; case XamlNodeType.EndObject: case XamlNodeType.EndMember: currentList = stack.Pop(); break; default: throw new InvalidOperationException("Invalid value for XamlNodeType"); } } if (stack.Count != 0) throw new InvalidOperationException("Imbalanced stack"); return currentList; }
public XamlMainObjectNode Parse(StreamReader fileStream) { if (fileStream == null) { throw new ArgumentNullException(nameof(fileStream)); } Stack <XamlObjectNode> objStack = new Stack <XamlObjectNode>(); XamlObjectNode currentNode = null; XamlMainObjectNode mainObject = null; SymbolScanner scanner = new SymbolScanner(fileStream); int lineNumberStart = 0; int linePositionStart = 0; //long newLineStreamPosition = fileStream.BaseStream.Position; string ident; //bool tagBracketClosed = false; while (!fileStream.EndOfStream) { scanner.SkipSpaces(); char ch = scanner.GetSymbol(); if (ch == '\0') { break; } if (ch == SymbolScanner.SymbolStartTag) { //tagBracketClosed = false; lineNumberStart = scanner.LineNumber; //open tag symbol must be start not the next symbol linePositionStart = scanner.CharPosition - 1; char chNext = scanner.NextSymbol; if (chNext == SymbolScanner.SymbolCloseTag) { scanner.SkipSymbol(); ident = scanner.GetName(); if (DoEndTag(ident, scanner)) { CloseTag(ident, scanner, objStack); } } else if (chNext == SymbolScanner.SymbolStartComment) { string comment = scanner.ReadComment(); Trace.WriteLine($"{lineNumberStart + 1}:{linePositionStart + 1} Comment:{comment}"); XamlCommentNode commentNode = new XamlCommentNode { LineNumberStart = lineNumberStart + 1, LinePositionStart = linePositionStart + 1, Comment = comment }; commentNode.LineNumberEnd = scanner.LineNumber + 1; //end position is outside comment tag commentNode.LinePositionEnd = scanner.CharPosition; objStack.Push(commentNode); } else { char breakSymbol; ident = scanner.GetName(); breakSymbol = scanner.NextSymbol; //ident = GetIdent(fileStream, out breakSymbol); Trace.WriteLine($"{lineNumberStart + 1}:{linePositionStart + 1} Start Tag:{ident}"); if (mainObject == null) { mainObject = new XamlMainObjectNode { LineNumberStart = lineNumberStart + 1, LinePositionStart = linePositionStart + 1 }; mainObject.Name = ident; currentNode = mainObject; //root.MainObject = mainObject; objStack.Push(mainObject); } else { currentNode = new XamlObjectNode { LineNumberStart = lineNumberStart + 1, LinePositionStart = linePositionStart + 1 }; currentNode.Name = ident; objStack.Push(currentNode); } if (breakSymbol != SymbolScanner.SymbolEndTag) { scanner.SkipSpaces(); breakSymbol = scanner.NextSymbol; } if (breakSymbol == SymbolScanner.SymbolCloseTag) { //end of tag if (DoEndTag(ident, scanner)) { CloseTag(ident, scanner, objStack); } } else if (breakSymbol != SymbolScanner.SymbolEndTag) { XamlObjectNode objectNode = null; if (objStack.Count > 0) { objectNode = objStack.Peek(); } bool isClosed = ReadAttributes(objectNode, scanner, breakSymbol); if (isClosed) { //tagBracketClosed = true; if (objectNode != null) { objectNode.SetState(XamlNodeBase.EState.EndTagPresent); //objectNode.IsTagBracketClosed = true; } Trace.WriteLine("Tag end symbol for:" + ident); } if (scanner.NextSymbol == SymbolScanner.SymbolCloseTag) { //end of tag if (DoEndTag(ident, scanner)) { CloseTag(ident, scanner, objStack); } } } else { // skip '>' scanner.SkipSymbol(); XamlObjectNode objectNode = objStack.Peek(); objectNode.SetState(XamlNodeBase.EState.EndTagPresent); Trace.WriteLine("Tag end symbol for:" + ident); } //chNext = scanner.NextSymbol; } } else { if (objStack.Count > 0) { XamlObjectNode objectNode = objStack.Peek(); if (objectNode.IsState(XamlNodeBase.EState.EndTagPresent)) { lineNumberStart = scanner.LineNumber; //text symbol must be current not the next symbol linePositionStart = scanner.CharPosition - 1; string text = scanner.ReadText(ch); Trace.WriteLine("Text node:" + text); XamlTextNode textNode = new XamlTextNode(text) { LineNumberStart = lineNumberStart + 1, LinePositionStart = linePositionStart + 1 }; textNode.LineNumberEnd = scanner.LastTextLineNumberEnd + 1; // it must be the next symbol textNode.LinePositionEnd = scanner.LastTextCharPositionEnd; objectNode.SetState(XamlNodeBase.EState.TextNodePresent); objectNode.AddChild(textNode); } else { //Trace.Write(ch); _errorHandler?.Error($"Not expected symbol :'{ch}'", scanner); } } else { //Trace.Write(ch); _errorHandler?.Error($"Not expected symbol, no tag found :'{ch}'", scanner); } } char chNext1 = scanner.CheckEndOfLine(scanner.NextSymbol); } if (objStack.Count > 0) { //ignore exception by non closed main state. Temporary if (mainObject != null && objStack.Count == 1) { if (!mainObject.IsState(XamlNodeBase.EState.Closed)) { return(mainObject); } } _errorHandler?.Error($"unused {objStack.Count} nodes", scanner); } return(mainObject); }
private static bool ReadAttributes(XamlObjectNode xamlObjectNode, SymbolScanner scanner, char chNext) { bool ret = false; char breakSymbol; string attributeName = string.Empty; string attributeValue = string.Empty; while (chNext != SymbolScanner.SymbolEndTag) { scanner.SkipSpaces(); XamlAttribute attribute = null; int lineNumberValue = -1; int linePositionValue = -1; int lineNumberAttrName = scanner.LineNumber; int linePositionAttrName = scanner.CharPosition; if (scanner.NextSymbol == SymbolScanner.SymbolCloseTag || scanner.NextSymbol == SymbolScanner.SymbolEndTag) { if (attribute != null) { attribute.LineNumberEnd = scanner.LineNumber; attribute.LinePositionEnd = scanner.CharPosition; } chNext = scanner.NextSymbol; break; } attributeName = scanner.GetName(); scanner.SkipSpaces(); breakSymbol = scanner.NextSymbol; if (breakSymbol == SymbolScanner.SymbolEq) { //skip '=' scanner.SkipSymbol(); scanner.SkipSpaces(); lineNumberValue = scanner.LineNumber; linePositionValue = scanner.CharPosition; attributeValue = scanner.ReadString(); chNext = scanner.CheckEndOfLine(scanner.NextSymbol); } else if (breakSymbol == SymbolScanner.SymbolEndTag) { if (attribute != null) { attribute.LineNumberEnd = scanner.LineNumber; attribute.LinePositionEnd = scanner.CharPosition; } chNext = breakSymbol; } else if (breakSymbol == SymbolScanner.SymbolCloseTag) { chNext = scanner.GetSymbol(); chNext = scanner.NextSymbol; } else { scanner.SkipSpaces(); chNext = scanner.NextSymbol; } attribute = new XamlAttribute(attributeName, attributeValue) { LineNumberStart = lineNumberAttrName + 1, LineNumberEnd = scanner.LineNumber + 1, LinePositionStart = linePositionAttrName + 1, LinePositionEnd = scanner.CharPosition, LineNumberValueStart = lineNumberValue + 1, LineNumberValueEnd = scanner.LineNumber + 1, LinePositionValueStart = linePositionValue + 1, LinePositionValueEnd = scanner.CharPosition }; xamlObjectNode.Attributes.Add(attribute); Trace.WriteLine( string.Format( "\t{0}:{1} Attribute Name:{2}, {3}:{4} Value:{5}", lineNumberAttrName + 1, linePositionAttrName + 1, attributeName, lineNumberValue + 1, linePositionValue + 1, attributeValue)); } ret = chNext == SymbolScanner.SymbolEndTag; chNext = scanner.CheckEndOfLine(scanner.NextSymbol); if (ret) { chNext = scanner.GetSymbol(); //chNext = TestNextSymbol(fileStream); chNext = scanner.CheckEndOfLine(chNext); } return(ret); }