Ejemplo n.º 1
0
        private ResolvedTagPropertyInfo ResolvePropertyInfo(TagIndexEntry tagInfo, string propertyPath)
        {
            var topTagType = TagFactory.GetTypeForTag(tagInfo.Tag);

            var steps = PropertyAccessorParser.ExtractProperties(propertyPath);

            var offset = 0;

            var stepType = topTagType;

            foreach (var step in steps)
            {
                var prop = stepType.GetProperty(step.PropertyName);

                if (prop == null)
                {
                    throw new Exception($"Couldn't find property '{step.PropertyName}' on type '{stepType}'");
                }

                if (step.AccessType == PropertyAccessorParser.PropertyAccessType.Normal)
                {
                    offset  += BlamSerializer.StartsAt(stepType, step.PropertyName);
                    stepType = prop.PropertyType;
                }
                else if (step.AccessType == PropertyAccessorParser.PropertyAccessType.ElementAccess)
                {
                    if (prop.PropertyType.IsArray == false || step.ElementArgument is not int)
                    {
                        throw new NotSupportedException("Only arrays are currently supported for element access");
                    }

                    var elementSize   = BlamSerializer.SizeOf(prop.PropertyType.GetElementType());
                    var elementOffset = (elementSize * ((int)step.ElementArgument));

                    if (prop.GetCustomAttribute <ReferenceArrayAttribute>() != null)
                    {
                        var startsAt = BlamSerializer.StartsAt(stepType, step.PropertyName);

                        // Read element array base offset
                        var baseOffset = new SecondaryOffset(this.originalMap, this.mapToPatch.ReadInt32At(tagInfo.Offset.Value + offset + startsAt + 4));

                        // baseOffset is the absolute offset, need to subtract tag offset and prior property offsets to get relative
                        offset += baseOffset.Value - tagInfo.Offset.Value - offset + elementOffset;
                    }
                    else if (prop.GetCustomAttribute <PrimitiveArrayAttribute>() != null)
                    {
                        offset += elementOffset;
                    }
                    else
                    {
                        throw new Exception("Only primitive and reference arrays are supported");
                    }

                    stepType = prop.PropertyType.GetElementType();
                }
            }

            return(new ResolvedTagPropertyInfo()
            {
                RelativeOffset = offset,
                PropertyType = stepType
            });
        }