Exemple #1
0
        /// <summary>Creates a node from the xml element. This method gets only called if <see cref="CanHandleElement(XElement)"/> returned true.</summary>
        /// <param name="element">The element to create the node from.</param>
        /// <param name="parent">The parent of the node.</param>
        /// <param name="classes">The list of classes which correspond to the node.</param>
        /// <param name="logger">The logger used to output messages.</param>
        /// <param name="node">[out] The node for the xml element.</param>
        /// <returns>True if a node was created, otherwise false.</returns>
        public bool TryCreateNodeFromElement(XElement element, ClassNode parent, IEnumerable <ClassNode> classes, ILogger logger, out BaseNode node)
        {
            node = null;

            var reference  = NodeUuid.FromBase64String(element.Attribute(ReClassNetFile.XmlReferenceAttribute)?.Value, false);
            var innerClass = classes.FirstOrDefault(c => c.Uuid.Equals(reference));

            if (innerClass == null)
            {
                logger.Log(LogLevel.Warning, $"Skipping node with unknown reference: {reference}");
                logger.Log(LogLevel.Warning, element.ToString());

                return(false);
            }

            var weakPtrNode = new WeakPtrNode
            {
                Name    = element.Attribute(ReClassNetFile.XmlNameAttribute)?.Value ?? string.Empty,
                Comment = element.Attribute(ReClassNetFile.XmlCommentAttribute)?.Value ?? string.Empty
            };

            weakPtrNode.ChangeInnerNode(innerClass);

            node = weakPtrNode;

            return(true);
        }
        public bool TryCreateNodeFromElement(XElement element, ClassNode parent, IEnumerable <ClassNode> classes, ILogger logger, out BaseNode node)
        {
            node = null;

            var type = element.Attribute(ReClassNetFile.XmlTypeAttribute)?.Value;

            switch (type)
            {
            case XmlTypePrefix + "FDateTime":
                node = new FDateTimeNode();
                break;

            case XmlTypePrefix + "FGuid":
                node = new FGuidNode();
                break;

            case XmlTypePrefix + "FQWord":
                node = new FQWordNode();
                break;

            case XmlTypePrefix + "FString":
                node = new FStringNode();
                break;

            case XmlTypePrefix + "TArray":
            case XmlTypePrefix + "TSharedPtr":
            {
                var reference  = NodeUuid.FromBase64String(element.Attribute(ReClassNetFile.XmlReferenceAttribute)?.Value, false);
                var innerClass = classes.FirstOrDefault(c => c.Uuid.Equals(reference));
                if (innerClass == null)
                {
                    logger.Log(LogLevel.Warning, $"Skipping node with unknown reference: {reference}");
                    logger.Log(LogLevel.Warning, element.ToString());

                    return(false);
                }

                if (type == XmlTypePrefix + "TArray")
                {
                    node = new TArrayNode();
                }
                else
                {
                    node = new TSharedPtrNode();
                }
                ((BaseReferenceNode)node).ChangeInnerNode(innerClass);

                break;
            }

            default:
                throw new InvalidOperationException("Can not handle node type: " + type);
            }

            node.Name    = element.Attribute(ReClassNetFile.XmlNameAttribute)?.Value ?? string.Empty;
            node.Comment = element.Attribute(ReClassNetFile.XmlCommentAttribute)?.Value ?? string.Empty;

            return(true);
        }
        public void Load(Stream input, ILogger logger)
        {
            Contract.Requires(input != null);
            Contract.Requires(logger != null);

            using (var archive = new ZipArchive(input, ZipArchiveMode.Read))
            {
                var dataEntry = archive.GetEntry(DataFileName);
                if (dataEntry == null)
                {
                    throw new FormatException();
                }
                using (var entryStream = dataEntry.Open())
                {
                    var document = XDocument.Load(entryStream);

                    var version  = document.Root.Attribute(XmlVersionAttribute)?.Value;
                    var platform = document.Root.Attribute(XmlTypeAttribute)?.Value;
                    if (platform != Constants.Platform)
                    {
                        logger.Log(LogLevel.Warning, $"The platform of the file ({platform}) doesn't match the program platform ({Constants.Platform}).");
                    }

                    var classes = new List <Tuple <XElement, ClassNode> >();

                    foreach (var element in document.Root
                             .Element(XmlClassesElement)
                             .Elements(XmlClassElement)
                             .DistinctBy(e => e.Attribute(XmlUuidAttribute)?.Value))
                    {
                        var node = new ClassNode(false)
                        {
                            Uuid           = NodeUuid.FromBase64String(element.Attribute(XmlUuidAttribute)?.Value, true),
                            Name           = element.Attribute(XmlNameAttribute)?.Value ?? string.Empty,
                            Comment        = element.Attribute(XmlCommentAttribute)?.Value ?? string.Empty,
                            AddressFormula = element.Attribute(XmlAddressAttribute)?.Value ?? string.Empty
                        };

                        if (!project.ContainsClass(node.Uuid))
                        {
                            project.AddClass(node);

                            classes.Add(Tuple.Create(element, node));
                        }
                    }

                    foreach (var t in classes)
                    {
                        ReadNodeElements(
                            t.Item1.Elements(XmlNodeElement),
                            t.Item2,
                            logger
                            ).ForEach(t.Item2.AddNode);
                    }
                }
            }
        }
        public ClassNode GetClassByUuid(NodeUuid uuid)
        {
            Contract.Requires(uuid != null);

            return(classes.First(c => c.Uuid.Equals(uuid)));
        }
        public bool ContainsClass(NodeUuid uuid)
        {
            Contract.Requires(uuid != null);

            return(classes.Any(c => c.Uuid.Equals(uuid)));
        }
Exemple #6
0
        public void Load(Stream input, ILogger logger)
        {
            Contract.Requires(input != null);
            Contract.Requires(logger != null);

            using (var archive = new ZipArchive(input, ZipArchiveMode.Read))
            {
                var dataEntry = archive.GetEntry(DataFileName);
                if (dataEntry == null)
                {
                    throw new FormatException();
                }
                using (var entryStream = dataEntry.Open())
                {
                    var document = XDocument.Load(entryStream);
                    if (document.Root?.Element(XmlClassesElement) == null)
                    {
                        throw new FormatException("The data has not the correct format.");
                    }

                    uint.TryParse(document.Root.Attribute(XmlVersionAttribute)?.Value, out var fileVersion);
                    if ((fileVersion & FileVersionCriticalMask) > (FileVersion & FileVersionCriticalMask))
                    {
                        throw new FormatException($"The file version is unsupported. A newer {Constants.ApplicationName} version is required to read it.");
                    }

                    var platform = document.Root.Attribute(XmlPlatformAttribute)?.Value;
                    if (platform != Constants.Platform)
                    {
                        logger.Log(LogLevel.Warning, $"The platform of the file ({platform}) doesn't match the program platform ({Constants.Platform}).");
                    }

                    var customDataElement = document.Root.Element(XmlCustomDataElement);
                    if (customDataElement != null)
                    {
                        project.CustomData.Deserialize(customDataElement);
                    }

                    var typeMappingElement = document.Root.Element(XmlTypeMappingElement);
                    if (typeMappingElement != null)
                    {
                        project.TypeMapping.Deserialize(typeMappingElement);
                    }

                    var classes = new List <Tuple <XElement, ClassNode> >();

                    foreach (var element in document.Root
                             .Element(XmlClassesElement)
                             .Elements(XmlClassElement)
                             .DistinctBy(e => e.Attribute(XmlUuidAttribute)?.Value))
                    {
                        var node = new ClassNode(false)
                        {
                            Uuid           = NodeUuid.FromBase64String(element.Attribute(XmlUuidAttribute)?.Value, true),
                            Name           = element.Attribute(XmlNameAttribute)?.Value ?? string.Empty,
                            Comment        = element.Attribute(XmlCommentAttribute)?.Value ?? string.Empty,
                            AddressFormula = element.Attribute(XmlAddressAttribute)?.Value ?? string.Empty
                        };

                        if (!project.ContainsClass(node.Uuid))
                        {
                            project.AddClass(node);

                            classes.Add(Tuple.Create(element, node));
                        }
                    }

                    foreach (var t in classes)
                    {
                        var nodes = t.Item1.Elements(XmlNodeElement)
                                    .Select(e => CreateNodeFromElement(e, t.Item2, logger))
                                    .Where(n => n != null);

                        foreach (var node in nodes)
                        {
                            t.Item2.AddNode(node);
                        }
                    }
                }
            }
        }
Exemple #7
0
        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, 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)
            {
                var converter = CustomNodeConvert.GetReadConverter(element);
                if (converter != null)
                {
                    if (converter.TryCreateNodeFromElement(element, parent, project.Classes, logger, out var customNode))
                    {
                        yield return(customNode);
                    }

                    continue;
                }

                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());

                    continue;
                }

                var node = Activator.CreateInstance(nodeType) as BaseNode;
                if (node == null)
                {
                    logger.Log(LogLevel.Error, $"Could not create node of type: {nodeType}");

                    continue;
                }

                node.Name    = element.Attribute(XmlNameAttribute)?.Value ?? string.Empty;
                node.Comment = element.Attribute(XmlCommentAttribute)?.Value ?? string.Empty;

                if (node is BaseReferenceNode referenceNode)
                {
                    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());

                        continue;
                    }

                    var innerClassNode = project.GetClassByUuid(reference);
                    if (referenceNode.PerformCycleCheck && !ClassUtil.IsCycleFree(parent, innerClassNode, project.Classes))
                    {
                        logger.Log(LogLevel.Error, $"Skipping node with cycle reference: {parent.Name}->{node.Name}");

                        continue;
                    }

                    referenceNode.ChangeInnerNode(innerClassNode);
                }

                switch (node)
                {
                case VTableNode vtableNode:
                {
                    element
                    .Elements(XmlMethodElement)
                    .Select(e => new VMethodNode
                        {
                            Name    = e.Attribute(XmlNameAttribute)?.Value ?? string.Empty,
                            Comment = e.Attribute(XmlCommentAttribute)?.Value ?? string.Empty
                        })
                    .ForEach(vtableNode.AddNode);
                    break;
                }

                case BaseArrayNode 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;
                }
                }

                yield return(node);
            }
        }
        public void Load(Stream input, ILogger logger)
        {
            Contract.Requires(input != null);
            Contract.Requires(logger != null);

            using var archive = new ZipArchive(input, ZipArchiveMode.Read);
            var dataEntry = archive.GetEntry(DataFileName);

            if (dataEntry == null)
            {
                throw new FormatException();
            }

            using var entryStream = dataEntry.Open();
            var document = XDocument.Load(entryStream);

            if (document.Root?.Element(XmlClassesElement) == null)
            {
                throw new FormatException("The data has not the correct format.");
            }

            uint.TryParse(document.Root.Attribute(XmlVersionAttribute)?.Value, out var fileVersion);
            if ((fileVersion & FileVersionCriticalMask) > (FileVersion & FileVersionCriticalMask))
            {
                throw new FormatException($"The file version is unsupported. A newer {Constants.ApplicationName} version is required to read it.");
            }

            var platform = document.Root.Attribute(XmlPlatformAttribute)?.Value;

            if (platform != Constants.Platform)
            {
                logger.Log(LogLevel.Warning, $"The platform of the file ({platform}) doesn't match the program platform ({Constants.Platform}).");
            }

            var customDataElement = document.Root.Element(XmlCustomDataElement);

            if (customDataElement != null)
            {
                project.CustomData.Deserialize(customDataElement);
            }

            var typeMappingElement = document.Root.Element(XmlTypeMappingElement);

            if (typeMappingElement != null)
            {
                project.TypeMapping.Deserialize(typeMappingElement);
            }

            var enumsElement = document.Root.Element(XmlEnumsElement);

            if (enumsElement != null)
            {
                foreach (var enumElement in enumsElement.Elements(XmlEnumElement))
                {
                    var name         = enumElement.Attribute(XmlNameAttribute)?.Value ?? string.Empty;
                    var useFlagsMode = (bool?)enumElement.Attribute(XmlFlagsAttribute) ?? false;
                    var size         = enumElement.Attribute(XmlSizeAttribute).GetEnumValue <EnumDescription.UnderlyingTypeSize>();

                    var values = new Dictionary <string, long>();
                    foreach (var itemElement in enumElement.Elements(XmlItemElement))
                    {
                        var itemName  = itemElement.Attribute(XmlNameAttribute)?.Value ?? string.Empty;
                        var itemValue = (long?)itemElement.Attribute(XmlValueAttribute) ?? 0L;

                        values.Add(itemName, itemValue);
                    }

                    var @enum = new EnumDescription
                    {
                        Name = name
                    };
                    @enum.SetData(useFlagsMode, size, values);

                    project.AddEnum(@enum);
                }
            }

            var classes = new List <(XElement, ClassNode)>();

            var classesElement = document.Root.Element(XmlClassesElement);

            if (classesElement != null)
            {
                foreach (var element in classesElement
                         .Elements(XmlClassElement)
                         .DistinctBy(e => e.Attribute(XmlUuidAttribute)?.Value))
                {
                    var node = new ClassNode(false)
                    {
                        Uuid           = NodeUuid.FromBase64String(element.Attribute(XmlUuidAttribute)?.Value, true),
                        Name           = element.Attribute(XmlNameAttribute)?.Value ?? string.Empty,
                        Comment        = element.Attribute(XmlCommentAttribute)?.Value ?? string.Empty,
                        AddressFormula = element.Attribute(XmlAddressAttribute)?.Value ?? string.Empty
                    };

                    if (!project.ContainsClass(node.Uuid))
                    {
                        project.AddClass(node);

                        classes.Add((element, node));
                    }
                }
            }

            foreach (var(element, classNode) in classes)
            {
                var nodes = element.Elements(XmlNodeElement)
                            .Select(e => CreateNodeFromElement(e, classNode, logger))
                            .Where(n => n != null);

                classNode.BeginUpdate();
                classNode.AddNodes(nodes);
                classNode.EndUpdate();
            }
        }