Example #1
0
 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>)}`.");
     }
 }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        /// <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);
        }
Example #9
0
 public void AddResourceBlock(int count, CacheAddress address, IList block)
 {
     throw new NotImplementedException();
 }
Example #10
0
 public TagBlock(int count, CacheAddress address)
 {
     Count    = count;
     Address  = address;
     Elements = new List <TagStructure>(count);
 }
Example #11
0
        public uint AddressToOffset(uint currentOffset, uint address)
        {
            var resourceAddress = new CacheAddress(address);

            return((uint)resourceAddress.Offset);
        }
Example #12
0
 public TagData(int size, CacheAddress address)
 {
     Size    = size;
     Address = address;
 }
Example #13
0
        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);
        }
Example #14
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);
        }
Example #15
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);
        }