/// <summary>
        /// Creates a managed animation entry given a native entry.
        /// </summary>
        /// <param name="mtpFileAddress">Address of the first byte of the MTP file in memory.</param>
        /// <param name="entry">The native animation entry.</param>
        public static unsafe ManagedAnimationEntry FromAnimationEntry(byte *mtpFileAddress, AnimationEntry entry)
        {
            var managedAnimationEntry = new ManagedAnimationEntry();

            byte *         fileNamePtr = entry.FileNamePtr + mtpFileAddress;
            byte *         fileDataPtr = entry.FileDataPtr + mtpFileAddress;
            PropertyTuple *tuplePtr    = (PropertyTuple *)(entry.PropertyTuplePtr + mtpFileAddress);

            // Get File Name
            managedAnimationEntry.FileName = String.Win1252Encoder.GetString(fileNamePtr, String.Strlen(fileNamePtr));

            // Get File Data
            var header = MotionHeader.FromPointer(fileDataPtr);

            Memory.CurrentProcess.ReadRaw((IntPtr)fileDataPtr, out managedAnimationEntry._fileData, header.FileSize);

            // Get File Tuples
            if (entry.HasProperties)
            {
                var           tuples = new List <PropertyTuple>(32);
                PropertyTuple tuple;

                void AddTuple()
                {
                    tuple = *tuplePtr;
                    tuple.SwapEndian();
                    tuples.Add(tuple);
                }

                while (!tuplePtr->Equals(PropertyTuple.Terminator))
                {
                    AddTuple();
                    tuplePtr++;
                }

                AddTuple();
                managedAnimationEntry.Tuples = tuples.ToArray();
            }

            return(managedAnimationEntry);
        }
        /// <summary>
        /// Converts a <see cref="MotionPackage"/> into a native .MTP file.
        /// </summary>
        public byte[] ToMtp()
        {
            var bytes = new List <byte>(1000000);

            var header = Header;

            header.SwapEndian();
            bytes.AddRange(Struct.GetBytes(ref header));

            // Write entries
            var dummyAnimationEntry      = new AnimationEntry();
            var dummyAnimationEntryBytes = Struct.GetBytes(ref dummyAnimationEntry);

            int[] entryOffsets = Entries.Select(x => AddRange(bytes, dummyAnimationEntryBytes)).ToArray();

            // Write file names.
            int[] fileNameOffsets = Entries.Select(x =>
            {
                int firstRef = AddRange(bytes, String.GetNullTerminatedBytes(String.Win1252Encoder, x.FileName));
                // Must pad to next group of 4-bytes, otherwise game will fail to parse
                while (bytes.Count % 4 > 0)
                {
                    bytes.Add(0x00);
                }
                return(firstRef);
            }).ToArray();

            // Write file data.
            int[] fileDataOffsets = Entries.Select(x => AddRange(bytes, x.FileData)).ToArray();

            // Write extra properties.
            int[] filePropertyOffsets = Entries.Select(x =>
            {
                if (x.Tuples != null)
                {
                    // Temporarily swap out the endian of all tuples before writing to array, then swap back.
                    for (int i = 0; i < x.Tuples.Length; i++)
                    {
                        x.Tuples[i].SwapEndian();
                    }

                    var result = AddRange(bytes, StructArray.GetBytes(x.Tuples));

                    for (int i = 0; i < x.Tuples.Length; i++)
                    {
                        x.Tuples[i].SwapEndian();
                    }

                    return(result);
                }

                return(0);
            }).ToArray();

            // Fix Offsets
            var byteArray = bytes.ToArray();

            fixed(byte *byteArrayPtr = byteArray)
            {
                for (int x = 0; x < Entries.Length; x++)
                {
                    ref var entry = ref Unsafe.AsRef <AnimationEntry>(byteArrayPtr + entryOffsets[x]);
                    Endian.Reverse(ref fileNameOffsets[x]);
                    Endian.Reverse(ref fileDataOffsets[x]);
                    Endian.Reverse(ref filePropertyOffsets[x]);

                    entry.FileNamePtr      = fileNameOffsets[x];
                    entry.FileDataPtr      = fileDataOffsets[x];
                    entry.PropertyTuplePtr = filePropertyOffsets[x];
                }
            }