private void WritePropertyValue(TagIndexEntry tagInfo, ResolvedTagPropertyInfo info, TagPropertyPatch patch) { if (info.RelativeOffset < 0) { Debugger.Break(); } var propType = info.PropertyType; if (propType.IsGenericType) { propType = propType.GetGenericTypeDefinition(); } if (propType.IsEnum) { propType = propType.GetEnumUnderlyingType(); } if (this.DataWriters.TryGetValue(propType, out var writer)) { writer(this.mapToPatch, tagInfo.Offset.Value + info.RelativeOffset, patch.Value); } else { Console.WriteLine($"Writing '{info.PropertyType}' values is not configured, skipping"); } }
public void PatchProperty(TagIndexEntry tagInfo, TagPropertyPatch patch) { var propertyInfo = ResolvePropertyInfo(tagInfo, patch.PropertySelector); Logger.Log(propertyInfo.PropertyType.ToString() + " @ " + propertyInfo.RelativeOffset, Logger.Color.Magenta); WritePropertyValue(tagInfo, propertyInfo, patch); }
public void PatchBinaryData(TagIndexEntry tagInfo, TagBinaryPatch bin) { var patchOffset = tagInfo.Offset.Value + bin.RelativeOffset; Logger.Log(bin.Data.Length + "bytes @ " + bin.RelativeOffset, Logger.Color.Cyan); this.mapToPatch.Position = patchOffset; this.mapToPatch.Write(bin.Data); }
public static BaseTag CreateTag(uint id, string name, TagIndexEntry index, IH2Map map, MapStream reader) { var tagType = GetTypeForTag(index.Tag); BaseTag tag; if (tagType == null) { tag = new UnknownTag(id, index.Tag.ToString()) { Name = name, Length = (uint)index.DataSize, Offset = (uint)index.Offset.Value, InternalSecondaryMagic = map.SecondaryMagic + index.Offset.Value }; } else { BaseTag instance; // PERF: check ctor existence ahead of time try { //var ctor = tagType.GetConstructor(new[] { typeof(uint) }); //instance = (BaseTag)ctor.Invoke(new object[] { id }); instance = Activator.CreateInstance(tagType, new object[] { id }) as BaseTag; } catch { instance = (BaseTag)FormatterServices.GetUninitializedObject(tagType); } tag = (BaseTag)BlamSerializer.DeserializeInto(instance, tagType, reader.GetStream(map.OriginFile), index.Offset.Value, map.SecondaryMagic, map); } tag.Name = name; tag.TagIndexEntry = index; tag.DataFile = map.OriginFile; tag.PopulateExternalData(reader); return(tag); }
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 }); }