public void ReplaceSelectedNodesWithType(Type type) { Contract.Requires(type != null); Contract.Requires(type.IsSubclassOf(typeof(BaseNode))); var selectedNodes = memoryViewControl.GetSelectedNodes(); var newSelected = new List <MemoryViewControl.SelectedNodeInfo>(selectedNodes.Count); var hotSpotPartitions = selectedNodes .WhereNot(s => s.Node is ClassNode) .GroupBy(s => s.Node.GetParentContainer()) .SelectMany(g => g .OrderBy(s => s.Node.Offset) .GroupWhile((h1, h2) => h1.Node.Offset + h1.Node.MemorySize == h2.Node.Offset) ); foreach (var selectedPartition in hotSpotPartitions) { var hotSpotsToReplace = new Queue <MemoryViewControl.SelectedNodeInfo>(selectedPartition); while (hotSpotsToReplace.Count > 0) { var selected = hotSpotsToReplace.Dequeue(); var node = BaseNode.CreateInstanceFromType(type); var createdNodes = new List <BaseNode>(); selected.Node.GetParentContainer().ReplaceChildNode(selected.Node, node, ref createdNodes); node.IsSelected = true; var info = new MemoryViewControl.SelectedNodeInfo(node, selected.Memory, selected.Address, selected.Level); newSelected.Add(info); // If more than one node is selected I assume the user wants to replace the complete range with the desired node type. if (selectedNodes.Count > 1) { foreach (var createdNode in createdNodes) { hotSpotsToReplace.Enqueue(new MemoryViewControl.SelectedNodeInfo(createdNode, selected.Memory, selected.Address + createdNode.Offset - node.Offset, selected.Level)); } } } } memoryViewControl.ClearSelection(); if (newSelected.Count > 0) { memoryViewControl.SetSelectedNodes(newSelected); } }
public BaseNode CreateNodeFromElement(XElement element, BaseNode parent, IEnumerable <ClassNode> classes, ILogger logger, CreateNodeFromElementHandler createNodeFromElement) { if (!stringToTypeMap.TryGetValue(element.Attribute(ReClassNetFile.XmlTypeAttribute)?.Value ?? string.Empty, out var nodeType)) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {element.Attribute(ReClassNetFile.XmlTypeAttribute)?.Value}"); logger.Log(LogLevel.Warning, element.ToString()); return(null); } return(BaseNode.CreateInstanceFromType(nodeType, false)); }
private static void GetNodeInfoFromType(Type nodeType, out string label, out Image icon) { Contract.Requires(nodeType != null); var node = BaseNode.CreateInstanceFromType(nodeType, false); if (node == null) { throw new InvalidOperationException($"'{nodeType}' is not a valid node type."); } node.GetUserInterfaceInfo(out label, out icon); }
private void memoryViewControl_ChangeWrappedTypeClick(object sender, NodeClickEventArgs e) { if (e.Node is BaseWrapperNode wrapperNode) { var items = NodeTypesBuilder.CreateToolStripMenuItems(t => { var node = BaseNode.CreateInstanceFromType(t); if (wrapperNode.CanChangeInnerNodeTo(node)) { wrapperNode.ChangeInnerNode(node); } }, wrapperNode.CanChangeInnerNodeTo(null)); var menu = new ContextMenuStrip(); menu.Items.AddRange(items.ToArray()); menu.Show(this, e.Location); } }
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 IEnumerable <BaseNode> ReadNodeElements(IEnumerable <XElement> elements, ClassNode parent, IReadOnlyDictionary <string, ClassNode> classes, Type[] typeMap, ILogger logger) { Contract.Requires(elements != null); Contract.Requires(parent != null); Contract.Requires(classes != null); Contract.Requires(typeMap != null); Contract.Requires(logger != null); foreach (var element in elements) { Type nodeType = null; if (int.TryParse(element.Attribute("Type")?.Value, out var typeVal)) { if (typeVal >= 0 && typeVal < typeMap.Length) { nodeType = typeMap[typeVal]; } } if (nodeType == null) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {element.Attribute("Type")?.Value}"); logger.Log(LogLevel.Warning, element.ToString()); continue; } var node = BaseNode.CreateInstanceFromType(nodeType, false); if (node == null) { logger.Log(LogLevel.Error, $"Could not create node of type: {nodeType}"); continue; } node.Name = element.Attribute("Name")?.Value ?? string.Empty; node.Comment = element.Attribute("Comment")?.Value ?? string.Empty; node.IsHidden = element.Attribute("bHidden")?.Value.Equals("1") ?? false; // Convert the Custom node into normal hex nodes. if (node is CustomNode customNode) { int.TryParse(element.Attribute("Size")?.Value, out var size); foreach (var paddingNode in customNode.GetEquivalentNodes(size)) { yield return(paddingNode); } continue; } // ClassInstanceNode, ClassPointerNode, ClassInstanceArrayNode, ClassPointerArrayNode if (node is BaseWrapperNode baseWrapperNode) { string reference; int arrayCount = 0; if (node is BaseClassArrayNode) // ClassInstanceArrayNode, ClassPointerArrayNode { reference = element.Element("Array")?.Attribute("Name")?.Value; if (node is ClassInstanceArrayNode) { TryGetAttributeValue(element, "Total", out arrayCount, logger); } else { TryGetAttributeValue(element, "Count", out arrayCount, logger); } } else // ClassInstanceNode, ClassPointerNode { reference = element.Attribute("Pointer")?.Value ?? element.Attribute("Instance")?.Value; } if (reference == null || !classes.ContainsKey(reference)) { logger.Log(LogLevel.Error, $"Skipping node with unknown reference: {reference}"); logger.Log(LogLevel.Warning, element.ToString()); continue; } var innerClassNode = classes[reference]; if (baseWrapperNode.ShouldPerformCycleCheckForInnerNode() && !ClassUtil.IsCyclicIfClassIsAccessibleFromParent(parent, innerClassNode, project.Classes)) { logger.Log(LogLevel.Error, $"Skipping node with cycle reference: {parent.Name}->{node.Name}"); continue; } // ClassPointerNode, ClassInstanceArrayNode and ClassPointerArrayNode need to be converted to supported nodes. if (node is BaseClassArrayNode classArrayNode) // ClassInstanceArrayNode, ClassPointerArrayNode { node = classArrayNode.GetEquivalentNode(arrayCount, innerClassNode); } else if (node is ClassPointerNode classPointerNode) // ClassPointerNode { node = classPointerNode.GetEquivalentNode(innerClassNode); } else // ClassInstanceNode, ClassPointerNode { baseWrapperNode.ChangeInnerNode(innerClassNode); } } switch (node) { case VirtualMethodTableNode vtableNode: element .Elements("Function") .Select(e => new VirtualMethodNode { Name = e.Attribute("Name")?.Value ?? string.Empty, Comment = e.Attribute("Comment")?.Value ?? string.Empty, IsHidden = e.Attribute("bHidden")?.Value.Equals("1") ?? false }) .ForEach(vtableNode.AddNode); break; case BaseTextNode textNode: { TryGetAttributeValue(element, "Size", out var length, logger); textNode.Length = textNode is Utf16TextNode ? length / 2 : length; break; } case BitFieldNode bitFieldNode: { TryGetAttributeValue(element, "Size", out var bits, logger); bitFieldNode.Bits = bits * 8; break; } } yield return(node); } }
private static IEnumerable <BaseNode> ReadNodeRows(IEnumerable <DataRow> rows, ClassNode parent, IReadOnlyDictionary <int, ClassNode> classes, IReadOnlyDictionary <int, VirtualMethodTableNode> vtables, ILogger logger) { Contract.Requires(rows != null); Contract.Requires(parent != null); Contract.Requires(logger != null); foreach (var row in rows) { Type nodeType = null; var typeVal = Convert.ToInt32(row["type"]); if (typeVal >= 0 && typeVal < typeMap.Length) { nodeType = typeMap[typeVal]; } if (nodeType == null) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {row["type"]}"); logger.Log(LogLevel.Warning, string.Join(",", row.ItemArray)); continue; } var node = BaseNode.CreateInstanceFromType(nodeType, false); if (node == null) { logger.Log(LogLevel.Error, $"Could not create node of type: {nodeType}"); continue; } node.Name = Convert.ToString(row["variable"]); node.Comment = Convert.ToString(row["comment"]); // ClassInstanceNode, ClassPointerNode if (node is BaseWrapperNode wrapperNode) { var reference = Convert.ToInt32(row["ref"]); if (!classes.ContainsKey(reference)) { if (!vtables.TryGetValue(reference, out var vtableNode)) { logger.Log(LogLevel.Error, $"Skipping node with unknown reference: {row["ref"]}"); logger.Log(LogLevel.Warning, string.Join(",", row.ItemArray)); continue; } yield return(vtableNode); continue; } var innerClassNode = classes[reference]; if (wrapperNode.ShouldPerformCycleCheckForInnerNode() && !ClassUtil.IsCyclicIfClassIsAccessibleFromParent(parent, innerClassNode, classes.Values)) { logger.Log(LogLevel.Error, $"Skipping node with cycle reference: {parent.Name}->{node.Name}"); continue; } if (node is ClassPointerNode classPointerNode) { node = classPointerNode.GetEquivalentNode(innerClassNode); } else { wrapperNode.ChangeInnerNode(innerClassNode); } } if (node is BaseTextNode textNode) { textNode.Length = Math.Max(IntPtr.Size, Convert.ToInt32(row["length"])); } yield return(node); } }
private IEnumerable <BaseNode> ReadNodeElements(IEnumerable <XElement> elements, ClassNode parent, IReadOnlyDictionary <string, ClassNode> classes, ILogger logger) { Contract.Requires(elements != null); Contract.Requires(Contract.ForAll(elements, e => e != null)); Contract.Requires(parent != null); Contract.Requires(logger != null); foreach (var element in elements) { Type nodeType = null; if (int.TryParse(element.Attribute("Type")?.Value, out var typeVal)) { if (typeVal >= 0 && typeVal < typeMap.Length) { nodeType = typeMap[typeVal]; } } if (nodeType == null) { logger.Log(LogLevel.Error, $"Skipping node with unknown type: {element.Attribute("Type")?.Value}"); logger.Log(LogLevel.Warning, element.ToString()); continue; } var node = BaseNode.CreateInstanceFromType(nodeType, false); if (node == null) { logger.Log(LogLevel.Error, $"Could not create node of type: {nodeType}"); continue; } node.Name = element.Attribute("Name")?.Value ?? string.Empty; node.Comment = element.Attribute("Comments")?.Value ?? string.Empty; // ClassInstanceNode, ClassPointerNode if (node is BaseWrapperNode wrapperNode) { var pointToClassId = element.Attribute("PointToClass")?.Value; if (pointToClassId == null || !classes.ContainsKey(pointToClassId)) { logger.Log(LogLevel.Error, $"Skipping node with unknown reference: {pointToClassId}"); logger.Log(LogLevel.Warning, element.ToString()); continue; } var innerClassNode = classes[pointToClassId]; if (wrapperNode.ShouldPerformCycleCheckForInnerNode() && !ClassUtil.IsCyclicIfClassIsAccessibleFromParent(parent, innerClassNode, project.Classes)) { logger.Log(LogLevel.Error, $"Skipping node with cycle reference: {parent.Name}->{node.Name}"); continue; } if (node is ClassPointerNode classPointerNode) { node = classPointerNode.GetEquivalentNode(innerClassNode); } else // ClassInstanceNode { wrapperNode.ChangeInnerNode(innerClassNode); } } yield return(node); } }