public TagBlock(int count, CacheAddress address) : base(count, address) { if (typeof(T) == typeof(TagBlock)) { throw new NotSupportedException($"Type parameter must not be `{nameof(TagBlock)}`: `{nameof(TagBlock<T>)}`."); } }
/// <summary> /// Deserializes a value which is pointed to by an address. /// </summary> /// <param name="reader">The reader.</param> /// <param name="context">The serialization context to use.</param> /// <param name="valueType">The type of the value to deserialize.</param> /// <returns>The deserialized value.</returns> public override object DeserializeD3DStructure(EndianReader reader, ISerializationContext context, Type valueType) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } var resourceContext = context as ResourceDefinitionSerializationContext; var result = Activator.CreateInstance(valueType); var elementType = valueType.GenericTypeArguments[0]; // Read the pointer var startOffset = reader.BaseStream.Position; var address = new CacheAddress(reader.ReadUInt32()); var definitionAddress = reader.ReadUInt32(); // unused var runtimeAddress = reader.ReadUInt32(); // unused var nextReader = resourceContext.GetReader(address.Type); // Seek to it and read the object nextReader.BaseStream.Position = address.Offset; var definition = DeserializeValue(nextReader, context, null, elementType); valueType.GetField("Definition").SetValue(result, definition); valueType.GetField("AddressType").SetValue(result, address.Type); reader.BaseStream.Position = startOffset + 0xC; return(result); }
/// <summary> /// Deserializes a tag block (list of values). /// </summary> /// <param name="reader">The reader.</param> /// <param name="context">The serialization context to use.</param> /// <param name="valueType">The type of the value to deserialize.</param> /// <returns>The deserialized tag block.</returns> public object DeserializeTagBlockAsList(EndianReader reader, ISerializationContext context, Type valueType) { var result = Activator.CreateInstance(valueType); var elementType = valueType.GenericTypeArguments[0]; // Read count and offset var startOffset = reader.BaseStream.Position; var count = reader.ReadInt32(); var pointer = new CacheAddress(reader.ReadUInt32()); if (count == 0) { // Null tag block reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); } // // Read each value // var addMethod = valueType.GetMethod("Add"); reader.BaseStream.Position = context.AddressToOffset((uint)startOffset + 4, pointer.Value); for (var i = 0; i < count; i++) { var element = DeserializeValue(reader, context, null, elementType); addMethod.Invoke(result, new[] { element }); } reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); }
public void EndSerialize(TagStructureInfo info, byte[] data, uint mainStructOffset) { var writer = GetWriter(InitialAddressType); var definitionOffset = writer.BaseStream.Position; writer.Write(data); MainStructOffset = new CacheAddress(InitialAddressType, (int)definitionOffset); }
public uint AddressToOffset(uint currentOffset, uint address) { var resourceAddress = new CacheAddress(address); if (resourceAddress.Type != CacheAddressType.Definition) { throw new InvalidOperationException("Cannot dereference a resource address of type " + resourceAddress.Type); } return((uint)resourceAddress.Offset); }
public override object DeserializeTagBlock(EndianReader reader, ISerializationContext context, Type valueType) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } var resourceContext = context as ResourceDefinitionSerializationContext; var result = Activator.CreateInstance(valueType); var elementType = valueType.GenericTypeArguments[0]; // Read count and offset var startOffset = reader.BaseStream.Position; var count = reader.ReadInt32(); var pointer = new CacheAddress(reader.ReadUInt32()); // Set block address type valueType.GetField("AddressType").SetValue(result, pointer.Type); if (count == 0) { // Null tag block reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); } // // Read each value // var nextReader = resourceContext.GetReader(pointer.Type); nextReader.BaseStream.Position = pointer.Offset; var methods = valueType.GetMethods(); // select the add method from IList<T> and not IList interfaces var addMethod = methods.FirstOrDefault(method => method.Name == "Add" & method.ReturnType == typeof(void)); for (var i = 0; i < count; i++) { var element = DeserializeValue(nextReader, resourceContext, null, elementType); addMethod.Invoke(result, new[] { element }); } reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); }
public override TagData DeserializeTagData(EndianReader reader, ISerializationContext context) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } var resourceContext = context as ResourceDefinitionSerializationContext; // Read size and pointer var startOffset = reader.BaseStream.Position; var size = reader.ReadInt32(); if (Version > CacheVersion.Halo2Vista) { reader.BaseStream.Position = startOffset + 0xC; } var pointer = reader.ReadUInt32(); if (pointer == 0) { // Null data reference reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0x14 : 0x8); return(new TagData()); } var address = new CacheAddress(pointer); var nextReader = resourceContext.GetReader(address.Type); nextReader.BaseStream.Position = address.Offset; // Read the data var result = new byte[size]; nextReader.Read(result, 0, size); reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0x14 : 0x8); // instantiate tagdata and return it var tagData = new TagData { Data = result, AddressType = address.Type }; return(tagData); }
/// <summary> /// Deserializes a tag block /// </summary> /// <param name="reader">The reader.</param> /// <param name="context">The serialization context to use.</param> /// <param name="valueType">The type of the value to deserialize.</param> /// <returns>The deserialized tag block.</returns> public virtual object DeserializeTagBlock(EndianReader reader, ISerializationContext context, Type valueType) { var result = Activator.CreateInstance(valueType); var elementType = valueType.GenericTypeArguments[0]; // Read count and offset var startOffset = reader.BaseStream.Position; var count = reader.ReadInt32(); var pointer = new CacheAddress(reader.ReadUInt32()); if (count == 0) { // Null tag block reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); } // // Read each value // var methods = valueType.GetMethods(); // select the add method from IList<T> and not IList interfaces var addMethod = methods.FirstOrDefault(method => method.Name == "Add" & method.ReturnType == typeof(void)); reader.BaseStream.Position = context.AddressToOffset((uint)startOffset + 4, pointer.Value); for (var i = 0; i < count; i++) { var element = DeserializeValue(reader, context, null, elementType); addMethod.Invoke(result, new[] { element }); } reader.BaseStream.Position = startOffset + (Version > CacheVersion.Halo2Vista ? 0xC : 0x8); return(result); }
public void AddResourceBlock(int count, CacheAddress address, IList block) { throw new NotImplementedException(); }
public TagBlock(int count, CacheAddress address) { Count = count; Address = address; Elements = new List <TagStructure>(count); }
public uint AddressToOffset(uint currentOffset, uint address) { var resourceAddress = new CacheAddress(address); return((uint)resourceAddress.Offset); }
public TagData(int size, CacheAddress address) { Size = size; Address = address; }
public override void SerializeTagData(ISerializationContext context, MemoryStream tagStream, IDataBlock block, TagData tagData, TagFieldAttribute valueInfo) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } if (block.GetType() != typeof(ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock)) { throw new Exception($"Invalid block type given resource deserialization"); } var resourceBlock = block as ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock; var resourceContext = context as ResourceDefinitionSerializationContext; var writer = block.Writer; if (tagData == null || tagData.Data == null || tagData.Data.Length == 0) { writer.Write(0); writer.Write(0); writer.Write(0); writer.Write(0); writer.Write(0); return; } CacheAddressType addressType = tagData.AddressType; int dataOffset = 0; // offset in the data stream to the start of the data uint blockOffset = (uint)writer.BaseStream.Position + 0xC; // offset to the address pointing to the above relative to the current block. uint size = 0; // stream where the byte[] in the data should be written to: var dataStream = (MemoryStream)resourceContext.GetWriter(addressType).BaseStream; var data = tagData.Data; if (data != null && data.Length > 0) { // Ensure the block is aligned correctly var align = Math.Max(DefaultResourceAlign, (valueInfo != null) ? valueInfo.Align : 0); StreamUtil.Align(dataStream, (int)align); // Write its data dataOffset = (int)dataStream.Position; size = (uint)data.Length; dataStream.Write(data, 0, data.Length); StreamUtil.Align(dataStream, DefaultResourceAlign); } var dataAddress = new CacheAddress(addressType, dataOffset); var dataFixup = new ResourceFixupLocation { BlockOffset = blockOffset, Address = dataAddress }; resourceBlock.FixupLocations.Add(dataFixup); // this fixup will need to be adjusted when we move the block // Write the reference data writer.Write(size); writer.Write(0); writer.Write(0); writer.Write(dataAddress.Value); writer.Write(0); }
public override void SerializeD3DStructure(CacheVersion version, ISerializationContext context, MemoryStream tagStream, IDataBlock block, object val, Type valueType) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } if (block.GetType() != typeof(ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock)) { throw new Exception($"Invalid block type given resource deserialization"); } var resourceBlock = block as ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock; var resourceContext = context as ResourceDefinitionSerializationContext; var writer = block.Writer; if (val == null) { writer.Write(0); writer.Write(0); writer.Write(0); return; } var addressType = (CacheAddressType)valueType.GetField("AddressType").GetValue(val); var nextStream = (MemoryStream)resourceContext.GetWriter(addressType).BaseStream; var genericType = valueType.GenericTypeArguments[0]; var def = valueType.GetField("Definition").GetValue(val); // Serialize the value to a temporary block var resourceBlock2 = (ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock)context.CreateBlock(); resourceBlock2.BlockType = addressType; SerializeValue(version, context, tagStream, resourceBlock2, def, null, genericType); // Finalize the block and write the pointer var offset = (int)resourceBlock2.Finalize(nextStream); // find where in the stream the d3dstructure pointer will be written var blockOffset = (int)writer.BaseStream.Position; var address = new CacheAddress(addressType, blockOffset); int structureTypeIndex; if (genericType == typeof(BitmapDefinition)) { structureTypeIndex = 2; } else if (genericType == typeof(BitmapInterleavedDefinition)) { structureTypeIndex = 3; } else if (genericType == typeof(VertexBufferDefinition)) { structureTypeIndex = 0; } else if (genericType == typeof(IndexBufferDefinition)) { structureTypeIndex = 1; } else { throw new Exception(); } var interopLocation = new ResourceInteropLocation { ResourceStructureTypeIndex = structureTypeIndex, Address = address }; var fixupLocation = new ResourceFixupLocation { Address = new CacheAddress(addressType, offset), BlockOffset = (uint)blockOffset }; foreach (var fixup in resourceBlock2.FixupLocations) { fixup.BlockOffset += (uint)offset; resourceContext.FixupLocations.Add(fixup); } resourceBlock.FixupLocations.Add(fixupLocation); resourceBlock.InteropLocations.Add(interopLocation); writer.Write(address.Value); writer.Write(0); writer.Write(0); }
public override void SerializeTagBlock(CacheVersion version, ISerializationContext context, MemoryStream tagStream, IDataBlock block, object list, Type listType, TagFieldAttribute valueInfo) { if (context.GetType() != typeof(ResourceDefinitionSerializationContext)) { throw new Exception($"Invalid context type given resource deserialization"); } if (block.GetType() != typeof(ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock)) { throw new Exception($"Invalid block type given resource deserialization"); } var resourceBlock = block as ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock; var resourceContext = context as ResourceDefinitionSerializationContext; var writer = block.Writer; var count = 0; if (list != null) { // Use reflection to get the number of elements in the list var countProperty = listType.GetProperty("Count"); count = (int)countProperty.GetValue(list); } if (count == 0) { writer.Write(0); writer.Write(0); writer.Write(0); return; } var elementType = listType.GenericTypeArguments[0]; CacheAddressType addressType = (CacheAddressType)listType.GetField("AddressType").GetValue(list); // Serialize each value in the list to a data block var resourceBlock2 = (ResourceDefinitionSerializationContext.ResourceDefinitionDataBlock)resourceContext.CreateBlock(); resourceBlock2.BlockType = addressType; var addressTypeStream = (MemoryStream)resourceContext.GetWriter(addressType).BaseStream; var enumerableList = (System.Collections.IEnumerable)list; foreach (var val in enumerableList) { SerializeValue(version, resourceContext, tagStream, resourceBlock2, val, null, elementType); } // Ensure the block is aligned correctly var align = 0x10; StreamUtil.Align(resourceBlock2.Stream, align); // Finalize the block and write the tag block reference using a cache address var offset = resourceBlock2.Finalize(addressTypeStream); // offset of the data in the tagblock on the actual stream //var blockOffset = addressTypeStream.Position; // no need to fix that particular fixup later var address = new CacheAddress(addressType, (int)offset); var resourceFixup = new ResourceFixupLocation { Address = address, BlockOffset = (uint)writer.BaseStream.Position + 0x4 }; foreach (var fixup in resourceBlock2.FixupLocations) { fixup.BlockOffset += offset; resourceContext.FixupLocations.Add(fixup); } foreach (var location in resourceBlock2.InteropLocations) { location.Address = new CacheAddress(location.Address.Type, (int)(location.Address.Offset + offset)); resourceContext.InteropLocations.Add(location); } resourceBlock.FixupLocations.Add(resourceFixup); writer.Write(count); writer.Write(address.Value); // write address as 0, we use the fixups writer.Write(0); }