/// <summary>
        /// Serializes a data reference composed of raw bytes.
        /// </summary>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="data">The data.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private static void SerializeDataReference(MemoryStream tagStream, IDataBlock block, byte[] data, TagFieldAttribute valueInfo)
        {
            var writer = block.Writer;
            uint offset = 0;
            uint size = 0;
            if (data != null && data.Length > 0)
            {
                // Ensure the block is aligned correctly
                var align = Math.Max(DefaultBlockAlign, (valueInfo != null) ? valueInfo.DataAlign : 0);
                StreamUtil.Align(tagStream, (int)align);

                // Write its data
                offset = (uint)tagStream.Position;
                size = (uint)data.Length;
                tagStream.Write(data, 0, data.Length);
                StreamUtil.Align(tagStream, DefaultBlockAlign);
            }

            // Write the reference data
            writer.Write(size);
            writer.Write(0);
            writer.Write(0);
            if (size > 0)
                block.WritePointer(offset, typeof(byte[]));
            else
                writer.Write(0);
            writer.Write(0);
        }
示例#2
0
        /// <summary>
        /// Serializes a string.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="str">The string to serialize.</param>
        /// <param name="valueInfo">Information about the value.</param>
        private static void SerializeString(BinaryWriter writer, string str, TagFieldAttribute valueInfo)
        {
            if (valueInfo == null || valueInfo.Length == 0)
            {
                throw new ArgumentException("Cannot serialize a string with no length set");
            }
            var clampedLength = 0;

            if (str != null)
            {
                var bytes = Encoding.ASCII.GetBytes(str);
                clampedLength = Math.Min(valueInfo.Length - 1, bytes.Length);
                writer.Write(bytes, 0, clampedLength);
            }
            for (var i = clampedLength; i < valueInfo.Length; i++)
            {
                writer.Write((byte)0);
            }
        }
        /// <summary>
        /// Deserializes a null-terminated ASCII string.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="valueInfo">The value information.</param>
        /// <returns>The deserialized string.</returns>
        private static string DeserializeString(BinaryReader reader, TagFieldAttribute valueInfo)
        {
            if (valueInfo == null || valueInfo.Length == 0)
            {
                throw new ArgumentException("Cannot deserialize a string with no length set");
            }

            // Keep reading until a null terminator is found
            var result   = new StringBuilder();
            var startPos = reader.BaseStream.Position;

            while (true)
            {
                var ch = reader.ReadByte();
                if (ch == 0)
                {
                    break;
                }
                result.Append((char)ch);
            }
            reader.BaseStream.Position = startPos + valueInfo.Length;
            return(result.ToString());
        }
示例#4
0
            public object PreSerialize(TagFieldAttribute info, object obj)
            {
                if (obj == null)
                {
                    return(null);
                }

                // When serializing a resource address, just add a fixup for it and serialize a null pointer
                if (obj is ResourceAddress)
                {
                    _fixups.Add(MakeDefinitionFixup((ResourceAddress)obj));
                    return(0U);
                }

                var type = obj.GetType();

                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(D3DPointer <>))
                {
                    // Add a D3D fixup for D3DPointers based on the type of object being pointed to
                    var d3dType = GetD3DObjectType(type.GenericTypeArguments[0]);
                    _d3dFixups.Add(MakeD3DFixup((uint)Stream.Position, d3dType));
                }
                return(obj);
            }
示例#5
0
 /// <summary>
 /// Serializes a complex value.
 /// </summary>
 /// <param name="context">The serialization context to use.</param>
 /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
 /// <param name="block">The temporary block to write incomplete tag data to.</param>
 /// <param name="val">The value.</param>
 /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
 /// <param name="valueType">Type of the value.</param>
 private void SerializeComplexValue(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object val, TagFieldAttribute valueInfo, Type valueType)
 {
     if (valueInfo != null && ((valueInfo.Flags & TagFieldFlags.Indirect) != 0 || valueType == typeof(ResourceReference)))
     {
         SerializeIndirectValue(context, tagStream, block, val, valueType);
     }
     else if (valueType.IsEnum)
     {
         SerializePrimitiveValue(block.Writer, val, valueType.GetEnumUnderlyingType());
     }
     else if (valueType == typeof(string))
     {
         SerializeString(block.Writer, (string)val, valueInfo);
     }
     else if (valueType == typeof(TagInstance))
     {
         SerializeTagReference(block.Writer, (TagInstance)val, valueInfo);
     }
     else if (valueType == typeof(ResourceAddress))
     {
         block.Writer.Write(((ResourceAddress)val).Value);
     }
     else if (valueType == typeof(byte[]))
     {
         SerializeDataReference(tagStream, block, (byte[])val, valueInfo);
     }
     else if (valueType == typeof(Euler2))
     {
         SerializeEulerAngles(block, (Euler2)val);
     }
     else if (valueType == typeof(Euler3))
     {
         SerializeEulerAngles(block, (Euler3)val);
     }
     else if (valueType == typeof(Vector2))
     {
         SerializeVector(block, (Vector2)val);
     }
     else if (valueType == typeof(Vector3))
     {
         SerializeVector(block, (Vector3)val);
     }
     else if (valueType == typeof(Vector4))
     {
         SerializeVector(block, (Vector4)val);
     }
     else if (valueType == typeof(StringId))
     {
         block.Writer.Write(((StringId)val).Value);
     }
     else if (valueType == typeof(Angle))
     {
         block.Writer.Write(((Angle)val).Radians);
     }
     else if (valueType.IsArray)
     {
         SerializeInlineArray(context, tagStream, block, (Array)val, valueInfo);
     }
     else if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List <>))
     {
         SerializeTagBlock(context, tagStream, block, val, valueType, valueInfo);
     }
     else if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Range <>))
     {
         SerializeRange(block, val);
     }
     else
     {
         SerializeStruct(context, tagStream, block, new TagStructureInfo(val.GetType(), _version), val);
     }
 }
示例#6
0
 /// <summary>
 /// Serializes a value.
 /// </summary>
 /// <param name="context">The serialization context to use.</param>
 /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
 /// <param name="block">The temporary block to write incomplete tag data to.</param>
 /// <param name="val">The value.</param>
 /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
 /// <param name="valueType">Type of the value.</param>
 private void SerializeValue(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object val, TagFieldAttribute valueInfo, Type valueType)
 {
     // Call the data block's PreSerialize callback to determine if the value should be mutated
     val = block.PreSerialize(valueInfo, val);
     if (val != null)
     {
         valueType = val.GetType(); // TODO: Fix hax
     }
     if (valueType.IsPrimitive)
     {
         SerializePrimitiveValue(block.Writer, val, valueType);
     }
     else
     {
         SerializeComplexValue(context, tagStream, block, val, valueInfo, valueType);
     }
 }
        /// <summary>
        /// Deserializes a complex value.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="valueInfo">The value information. Can be <c>null</c>.</param>
        /// <param name="valueType">The type of the value to deserialize.</param>
        /// <returns>The deserialized value.</returns>
        private object DeserializeComplexValue(BinaryReader reader, ISerializationContext context, TagFieldAttribute valueInfo, Type valueType)
        {
            // Indirect objects
            // TODO: Remove ResourceReference hax, the Indirect flag wasn't available when I generated the tag structures
            if (valueInfo != null && ((valueInfo.Flags & TagFieldFlags.Indirect) != 0 || valueType == typeof(ResourceReference)))
            {
                return(DeserializeIndirectValue(reader, context, valueType));
            }

            // enum = Enum type
            if (valueType.IsEnum)
            {
                return(DeserializePrimitiveValue(reader, valueType.GetEnumUnderlyingType()));
            }

            // string = ASCII string
            if (valueType == typeof(string))
            {
                return(DeserializeString(reader, valueInfo));
            }

            // TagInstance = Tag reference
            if (valueType == typeof(TagInstance))
            {
                return(DeserializeTagReference(reader, context, valueInfo));
            }

            // ResourceAddress = Resource address
            if (valueType == typeof(ResourceAddress))
            {
                return(new ResourceAddress(reader.ReadUInt32()));
            }

            // Byte array = Data reference
            // TODO: Allow other types to be in data references, since sometimes they can point to a structure
            if (valueType == typeof(byte[]))
            {
                return(DeserializeDataReference(reader, context));
            }

            // Euler Angles types
            if (valueType == typeof(Euler2))
            {
                var i = Angle.FromRadians(reader.ReadSingle());
                var j = Angle.FromRadians(reader.ReadSingle());
                return(new Euler2(i, j));
            }
            else if (valueType == typeof(Euler3))
            {
                var i = Angle.FromRadians(reader.ReadSingle());
                var j = Angle.FromRadians(reader.ReadSingle());
                var k = Angle.FromRadians(reader.ReadSingle());
                return(new Euler3(i, j, k));
            }

            // Vector types
            if (valueType == typeof(Vector2))
            {
                return(new Vector2(reader.ReadSingle(), reader.ReadSingle()));
            }
            if (valueType == typeof(Vector3))
            {
                return(new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
            }
            if (valueType == typeof(Vector4))
            {
                return(new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
            }

            // StringID
            if (valueType == typeof(StringId))
            {
                return(new StringId(reader.ReadUInt32()));
            }

            // Angle (radians)
            if (valueType == typeof(Angle))
            {
                return(Angle.FromRadians(reader.ReadSingle()));
            }

            // Non-byte array = Inline array
            // TODO: Define more clearly in general what constitutes a data reference and what doesn't
            if (valueType.IsArray)
            {
                return(DeserializeInlineArray(reader, context, valueInfo, valueType));
            }

            // List = Tag block
            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List <>))
            {
                return(DeserializeTagBlock(reader, context, valueType));
            }

            // Ranges
            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Range <>))
            {
                return(DeserializeRange(reader, context, valueType));
            }

            // Assume the value is a structure
            return(DeserializeStruct(reader, context, new TagStructureInfo(valueType, _version)));
        }
示例#8
0
        /// <summary>
        /// Serializes a tag block.
        /// </summary>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="list">The list of values in the tag block.</param>
        /// <param name="listType">Type of the list.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private void SerializeTagBlock(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object list, Type listType, TagFieldAttribute valueInfo)
        {
            var writer    = block.Writer;
            var listCount = 0;

            if (list != null)
            {
                // Use reflection to get the number of elements in the list
                var countProperty = listType.GetProperty("Count");
                listCount = (int)countProperty.GetValue(list);
            }
            if (listCount == 0)
            {
                writer.Write(0);
                writer.Write(0);
                writer.Write(0);
                return;
            }

            // Serialize each value in the list to a data block
            var tagBlock       = context.CreateBlock();
            var enumerableList = (System.Collections.IEnumerable)list;
            var valueType      = listType.GenericTypeArguments[0];

            foreach (var val in enumerableList)
            {
                SerializeValue(context, tagStream, tagBlock, val, null, valueType);
            }

            // Ensure the block is aligned correctly
            var align = Math.Max(DefaultBlockAlign, (valueInfo != null) ? valueInfo.DataAlign : 0);

            StreamUtil.Align(tagStream, (int)align);

            // Finalize the block and write the tag block reference
            writer.Write(listCount);
            block.WritePointer(tagBlock.Finalize(tagStream), listType);
            writer.Write(0);
        }
示例#9
0
        /// <summary>
        /// Serializes a data reference composed of raw bytes.
        /// </summary>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="data">The data.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private static void SerializeDataReference(MemoryStream tagStream, IDataBlock block, byte[] data, TagFieldAttribute valueInfo)
        {
            var  writer = block.Writer;
            uint offset = 0;
            uint size   = 0;

            if (data != null && data.Length > 0)
            {
                // Ensure the block is aligned correctly
                var align = Math.Max(DefaultBlockAlign, (valueInfo != null) ? valueInfo.DataAlign : 0);
                StreamUtil.Align(tagStream, (int)align);

                // Write its data
                offset = (uint)tagStream.Position;
                size   = (uint)data.Length;
                tagStream.Write(data, 0, data.Length);
                StreamUtil.Align(tagStream, DefaultBlockAlign);
            }

            // Write the reference data
            writer.Write(size);
            writer.Write(0);
            writer.Write(0);
            if (size > 0)
            {
                block.WritePointer(offset, typeof(byte[]));
            }
            else
            {
                writer.Write(0);
            }
            writer.Write(0);
        }
 /// <summary>
 /// Serializes a complex value.
 /// </summary>
 /// <param name="context">The serialization context to use.</param>
 /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
 /// <param name="block">The temporary block to write incomplete tag data to.</param>
 /// <param name="val">The value.</param>
 /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
 /// <param name="valueType">Type of the value.</param>
 private void SerializeComplexValue(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object val, TagFieldAttribute valueInfo, Type valueType)
 {
     if (valueInfo != null && ((valueInfo.Flags & TagFieldFlags.Indirect) != 0 || valueType == typeof(ResourceReference)))
         SerializeIndirectValue(context, tagStream, block, val, valueType);
     else if (valueType.IsEnum)
         SerializePrimitiveValue(block.Writer, val, valueType.GetEnumUnderlyingType());
     else if (valueType == typeof(string))
         SerializeString(block.Writer, (string)val, valueInfo);
     else if (valueType == typeof(TagInstance))
         SerializeTagReference(block.Writer, (TagInstance)val, valueInfo);
     else if (valueType == typeof(ResourceAddress))
         block.Writer.Write(((ResourceAddress)val).Value);
     else if (valueType == typeof(byte[]))
         SerializeDataReference(tagStream, block, (byte[])val, valueInfo);
     else if (valueType == typeof(Euler2))
         SerializeEulerAngles(block, (Euler2)val);
     else if (valueType == typeof(Euler3))
         SerializeEulerAngles(block, (Euler3)val);
     else if (valueType == typeof(Vector2))
         SerializeVector(block, (Vector2)val);
     else if (valueType == typeof(Vector3))
         SerializeVector(block, (Vector3)val);
     else if (valueType == typeof(Vector4))
         SerializeVector(block, (Vector4)val);
     else if (valueType == typeof(StringId))
         block.Writer.Write(((StringId)val).Value);
     else if (valueType == typeof(Angle))
         block.Writer.Write(((Angle)val).Radians);
     else if (valueType.IsArray)
         SerializeInlineArray(context, tagStream, block, (Array)val, valueInfo);
     else if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>))
         SerializeTagBlock(context, tagStream, block, val, valueType, valueInfo);
     else if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Range<>))
         SerializeRange(block, val);
     else
         SerializeStruct(context, tagStream, block, new TagStructureInfo(val.GetType(), _version), val);
 }
 /// <summary>
 /// Serializes a tag reference.
 /// </summary>
 /// <param name="writer">The writer to write to.</param>
 /// <param name="referencedTag">The referenced tag.</param>
 /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
 private static void SerializeTagReference(BinaryWriter writer, TagInstance referencedTag, TagFieldAttribute valueInfo)
 {
     // Write the reference out
     if (valueInfo == null || (valueInfo.Flags & TagFieldFlags.Short) == 0)
     {
         writer.Write((referencedTag != null) ? referencedTag.GroupTag.Value : -1);
         writer.Write(0);
         writer.Write(0);
     }
     writer.Write((referencedTag != null) ? referencedTag.Index : -1);
 }
 /// <summary>
 /// Serializes a string.
 /// </summary>
 /// <param name="writer">The writer to write to.</param>
 /// <param name="str">The string to serialize.</param>
 /// <param name="valueInfo">Information about the value.</param>
 private static void SerializeString(BinaryWriter writer, string str, TagFieldAttribute valueInfo)
 {
     if (valueInfo == null || valueInfo.Length == 0)
         throw new ArgumentException("Cannot serialize a string with no length set");
     var clampedLength = 0;
     if (str != null)
     {
         var bytes = Encoding.ASCII.GetBytes(str);
         clampedLength = Math.Min(valueInfo.Length - 1, bytes.Length);
         writer.Write(bytes, 0, clampedLength);
     }
     for (var i = clampedLength; i < valueInfo.Length; i++)
         writer.Write((byte)0);
 }
            public object PreSerialize(TagFieldAttribute info, object obj)
            {
                if (obj == null)
                    return null;

                // Get the object type and make sure it's supported
                var type = obj.GetType();
                if (type == typeof(ResourceDataReference) ||
                    (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(D3DPointer<>)))
                    throw new InvalidOperationException(type + " cannot be serialized as tag data");

                // HACK: If the object is a ResourceReference, fix the Owner property
                var resource = obj as ResourceReference;
                if (resource != null)
                    resource.Owner = _context.Tag;

                if (type == typeof(TagInstance))
                {
                    // Object is a tag reference - add it as a dependency
                    var referencedTag = obj as TagInstance;
                    if (referencedTag != null && referencedTag != _context.Tag)
                        _context._data.Dependencies.Add(referencedTag.Index);
                }
                return obj;
            }
        /// <summary>
        /// Deserializes an inline array.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="valueInfo">The value information. Can be <c>null</c>.</param>
        /// <param name="valueType">The type of the value to deserialize.</param>
        /// <returns>The deserialized array.</returns>
        private Array DeserializeInlineArray(BinaryReader reader, ISerializationContext context, TagFieldAttribute valueInfo, Type valueType)
        {
            if (valueInfo == null || valueInfo.Count == 0)
            {
                throw new ArgumentException("Cannot deserialize an inline array with no count set");
            }

            // Create the array and read the elements in order
            var elementCount = valueInfo.Count;
            var elementType  = valueType.GetElementType();
            var result       = Array.CreateInstance(elementType, elementCount);

            for (var i = 0; i < elementCount; i++)
            {
                result.SetValue(DeserializeValue(reader, context, null, elementType), i);
            }
            return(result);
        }
        /// <summary>
        /// Deserializes a tag reference.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="valueInfo">The value information. Can be <c>null</c>.</param>
        /// <returns>The deserialized tag reference.</returns>
        private static TagInstance DeserializeTagReference(BinaryReader reader, ISerializationContext context, TagFieldAttribute valueInfo)
        {
            if (valueInfo == null || (valueInfo.Flags & TagFieldFlags.Short) == 0)
            {
                reader.BaseStream.Position += 0xC; // Skip the class name and zero bytes, it's not important
            }
            var index = reader.ReadInt32();

            return(context.GetTagByIndex(index));
        }
        /// <summary>
        /// Serializes an inline array.
        /// </summary>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="data">The array.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private void SerializeInlineArray(ISerializationContext context, MemoryStream tagStream, IDataBlock block, Array data, TagFieldAttribute valueInfo)
        {
            if (valueInfo == null || valueInfo.Count == 0)
                throw new ArgumentException("Cannot serialize an inline array with no count set");
            if (data == null || data.Length != valueInfo.Count)
                throw new ArgumentException("Array length does not match the fixed count of " + valueInfo.Count);

            // Serialize each element into the current block
            var elementType = data.GetType().GetElementType();
            foreach (var elem in data)
                SerializeValue(context, tagStream, block, elem, null, elementType);
        }
示例#17
0
 /// <summary>
 /// Serializes a tag reference.
 /// </summary>
 /// <param name="writer">The writer to write to.</param>
 /// <param name="referencedTag">The referenced tag.</param>
 /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
 private static void SerializeTagReference(BinaryWriter writer, TagInstance referencedTag, TagFieldAttribute valueInfo)
 {
     // Write the reference out
     if (valueInfo == null || (valueInfo.Flags & TagFieldFlags.Short) == 0)
     {
         writer.Write((referencedTag != null) ? referencedTag.Group.Tag.Value : -1);
         writer.Write(0);
         writer.Write(0);
     }
     writer.Write((referencedTag != null) ? referencedTag.Index : -1);
 }
        /// <summary>
        /// Serializes a tag block.
        /// </summary>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="list">The list of values in the tag block.</param>
        /// <param name="listType">Type of the list.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private void SerializeTagBlock(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object list, Type listType, TagFieldAttribute valueInfo)
        {
            var writer = block.Writer;
            var listCount = 0;
            if (list != null)
            {
                // Use reflection to get the number of elements in the list
                var countProperty = listType.GetProperty("Count");
                listCount = (int)countProperty.GetValue(list);
            }
            if (listCount == 0)
            {
                writer.Write(0);
                writer.Write(0);
                writer.Write(0);
                return;
            }

            // Serialize each value in the list to a data block
            var tagBlock = context.CreateBlock();
            var enumerableList = (System.Collections.IEnumerable)list;
            var valueType = listType.GenericTypeArguments[0];
            foreach (var val in enumerableList)
                SerializeValue(context, tagStream, tagBlock, val, null, valueType);

            // Ensure the block is aligned correctly
            var align = Math.Max(DefaultBlockAlign, (valueInfo != null) ? valueInfo.DataAlign : 0);
            StreamUtil.Align(tagStream, (int)align);

            // Finalize the block and write the tag block reference
            writer.Write(listCount);
            block.WritePointer(tagBlock.Finalize(tagStream), listType);
            writer.Write(0);
        }
示例#19
0
        /// <summary>
        /// Serializes an inline array.
        /// </summary>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="data">The array.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        private void SerializeInlineArray(ISerializationContext context, MemoryStream tagStream, IDataBlock block, Array data, TagFieldAttribute valueInfo)
        {
            if (valueInfo == null || valueInfo.Count == 0)
            {
                throw new ArgumentException("Cannot serialize an inline array with no count set");
            }
            if (data == null || data.Length != valueInfo.Count)
            {
                throw new ArgumentException("Array length does not match the fixed count of " + valueInfo.Count);
            }

            // Serialize each element into the current block
            var elementType = data.GetType().GetElementType();

            foreach (var elem in data)
            {
                SerializeValue(context, tagStream, block, elem, null, elementType);
            }
        }
        /// <summary>
        /// Serializes a value.
        /// </summary>
        /// <param name="context">The serialization context to use.</param>
        /// <param name="tagStream">The stream to write completed blocks of tag data to.</param>
        /// <param name="block">The temporary block to write incomplete tag data to.</param>
        /// <param name="val">The value.</param>
        /// <param name="valueInfo">Information about the value. Can be <c>null</c>.</param>
        /// <param name="valueType">Type of the value.</param>
        private void SerializeValue(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object val, TagFieldAttribute valueInfo, Type valueType)
        {
            // Call the data block's PreSerialize callback to determine if the value should be mutated
            val = block.PreSerialize(valueInfo, val);
            if (val != null)
                valueType = val.GetType(); // TODO: Fix hax

            if (valueType.IsPrimitive)
                SerializePrimitiveValue(block.Writer, val, valueType);
            else
                SerializeComplexValue(context, tagStream, block, val, valueInfo, valueType);
        }
            public object PreSerialize(TagFieldAttribute info, object obj)
            {
                if (obj == null)
                    return null;

                // When serializing a resource address, just add a fixup for it and serialize a null pointer
                if (obj is ResourceAddress)
                {
                    _fixups.Add(MakeDefinitionFixup((ResourceAddress)obj));
                    return 0U;
                }

                var type = obj.GetType();
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(D3DPointer<>))
                {
                    // Add a D3D fixup for D3DPointers based on the type of object being pointed to
                    var d3dType = GetD3DObjectType(type.GenericTypeArguments[0]);
                    _d3dFixups.Add(MakeD3DFixup((uint)Stream.Position, d3dType));
                }
                return obj;
            }
 /// <summary>
 /// Deserializes a value.
 /// </summary>
 /// <param name="reader">The reader.</param>
 /// <param name="context">The serialization context to use.</param>
 /// <param name="valueInfo">The value information. Can be <c>null</c>.</param>
 /// <param name="valueType">The type of the value to deserialize.</param>
 /// <returns>The deserialized value.</returns>
 private object DeserializeValue(BinaryReader reader, ISerializationContext context, TagFieldAttribute valueInfo, Type valueType)
 {
     if (valueType.IsPrimitive)
     {
         return(DeserializePrimitiveValue(reader, valueType));
     }
     return(DeserializeComplexValue(reader, context, valueInfo, valueType));
 }