private BaseNode CreateNodeFromElement(XElement element, BaseNode parent, ILogger logger) { Contract.Requires(element != null); Contract.Requires(logger != null); BaseNode CreateNode() { var converter = CustomNodeSerializer.GetReadConverter(element); if (converter != null) { return(converter.CreateNodeFromElement(element, parent, project.Classes, logger, CreateNodeFromElement)); } if (!buildInStringToTypeMap.TryGetValue(element.Attribute(XmlTypeAttribute)?.Value ?? string.Empty, out var nodeType)) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {element.Attribute(XmlTypeAttribute)?.Value}"); logger.Log(LogLevel.Warning, element.ToString()); return(null); } return(BaseNode.CreateInstanceFromType(nodeType, false)); } var node = CreateNode(); if (node == null) { logger.Log(LogLevel.Error, "Could not create node."); return(null); } node.ParentNode = parent; node.Name = element.Attribute(XmlNameAttribute)?.Value ?? string.Empty; node.Comment = element.Attribute(XmlCommentAttribute)?.Value ?? string.Empty; node.IsHidden = bool.TryParse(element.Attribute(XmlHiddenAttribute)?.Value, out var val) && val; if (node is BaseWrapperNode wrapperNode) { ClassNode GetClassNodeFromElementReference() { var reference = NodeUuid.FromBase64String(element.Attribute(XmlReferenceAttribute)?.Value, false); if (!project.ContainsClass(reference)) { logger.Log(LogLevel.Error, $"Skipping node with unknown reference: {reference}"); logger.Log(LogLevel.Warning, element.ToString()); return(null); } return(project.GetClassByUuid(reference)); } // Legacy Support if (node is ClassPointerNode || node is ClassInstanceArrayNode || node is ClassPointerArrayNode) { var innerClass = GetClassNodeFromElementReference(); if (innerClass == null) { return(null); } switch (node) { case BaseClassArrayNode classArrayNode: node = classArrayNode.GetEquivalentNode(0, innerClass); break; case ClassPointerNode classPointerNode: node = classPointerNode.GetEquivalentNode(innerClass); break; } } else { BaseNode innerNode = null; if (node is BaseClassWrapperNode) { innerNode = GetClassNodeFromElementReference(); if (innerNode == null) { return(null); } } else { var innerElement = element.Elements().FirstOrDefault(); if (innerElement != null) { innerNode = CreateNodeFromElement(innerElement, node, logger); } } if (wrapperNode.CanChangeInnerNodeTo(innerNode)) { var rootWrapperNode = node.GetRootWrapperNode(); if (rootWrapperNode.ShouldPerformCycleCheckForInnerNode() && innerNode is ClassNode classNode && ClassUtil.IsCyclicIfClassIsAccessibleFromParent(node.GetParentClass(), classNode, project.Classes)) { logger.Log(LogLevel.Error, $"Skipping node with cyclic class reference: {node.GetParentClass().Name}->{rootWrapperNode.Name}"); return(null); } wrapperNode.ChangeInnerNode(innerNode); } else { logger.Log(LogLevel.Error, $"The node {innerNode} is not a valid child for {node}."); } } } switch (node) { case VirtualMethodTableNode vtableNode: { var nodes = element .Elements(XmlMethodElement) .Select(e => new VirtualMethodNode { Name = e.Attribute(XmlNameAttribute)?.Value ?? string.Empty, Comment = e.Attribute(XmlCommentAttribute)?.Value ?? string.Empty, IsHidden = e.Attribute(XmlHiddenAttribute)?.Value.Equals("True") ?? false }); foreach (var vmethodNode in nodes) { vtableNode.AddNode(vmethodNode); } break; } case BaseWrapperArrayNode arrayNode: { TryGetAttributeValue(element, XmlCountAttribute, out var count, logger); arrayNode.Count = count; break; } case BaseTextNode textNode: { TryGetAttributeValue(element, XmlLengthAttribute, out var length, logger); textNode.Length = length; break; } case BitFieldNode bitFieldNode: { TryGetAttributeValue(element, XmlBitsAttribute, out var bits, logger); bitFieldNode.Bits = bits; break; } case FunctionNode functionNode: { functionNode.Signature = element.Attribute(XmlSignatureAttribute)?.Value ?? string.Empty; var reference = NodeUuid.FromBase64String(element.Attribute(XmlReferenceAttribute)?.Value, false); if (project.ContainsClass(reference)) { functionNode.BelongsToClass = project.GetClassByUuid(reference); } break; } } return(node); }
private static XElement CreateElementFromNode(BaseNode node, ILogger logger) { Contract.Requires(node != null); Contract.Requires(logger != null); XElement CreateElement() { var converter = CustomNodeSerializer.GetWriteConverter(node); if (converter != null) { return(converter.CreateElementFromNode(node, logger, CreateElementFromNode)); } if (!buildInTypeToStringMap.TryGetValue(node.GetType(), out var typeString)) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {node.Name}"); logger.Log(LogLevel.Warning, node.GetType().ToString()); return(null); } return(new XElement( XmlNodeElement, new XAttribute(XmlTypeAttribute, typeString) )); } var element = CreateElement(); if (element == null) { logger.Log(LogLevel.Error, "Could not create element."); return(null); } element.SetAttributeValue(XmlNameAttribute, node.Name ?? string.Empty); element.SetAttributeValue(XmlCommentAttribute, node.Comment ?? string.Empty); element.SetAttributeValue(XmlHiddenAttribute, node.IsHidden); if (node is BaseWrapperNode wrapperNode) { if (node is BaseClassWrapperNode classWrapperNode) { element.SetAttributeValue(XmlReferenceAttribute, ((ClassNode)classWrapperNode.InnerNode).Uuid); } else if (wrapperNode.InnerNode != null) { element.Add(CreateElementFromNode(wrapperNode.InnerNode, logger)); } } switch (node) { case VirtualMethodTableNode vtableNode: { element.Add(vtableNode.Nodes.Select(n => new XElement( XmlMethodElement, new XAttribute(XmlNameAttribute, n.Name ?? string.Empty), new XAttribute(XmlCommentAttribute, n.Comment ?? string.Empty), new XAttribute(XmlHiddenAttribute, n.IsHidden) ))); break; } case UnionNode unionNode: { element.Add(unionNode.Nodes.Select(n => CreateElementFromNode(n, logger))); break; } case BaseWrapperArrayNode arrayNode: { element.SetAttributeValue(XmlCountAttribute, arrayNode.Count); break; } case BaseTextNode textNode: { element.SetAttributeValue(XmlLengthAttribute, textNode.Length); break; } case BitFieldNode bitFieldNode: { element.SetAttributeValue(XmlBitsAttribute, bitFieldNode.Bits); break; } case FunctionNode functionNode: { var uuid = functionNode.BelongsToClass?.Uuid ?? Guid.Empty; element.SetAttributeValue(XmlReferenceAttribute, uuid); element.SetAttributeValue(XmlSignatureAttribute, functionNode.Signature); break; } case EnumNode enumNode: { element.SetAttributeValue(XmlReferenceAttribute, enumNode.Enum.Name); break; } } return(element); }