/// <summary>
        /// Converts a native array into a <see cref="MotionPackage"/>
        /// </summary>
        /// <param name="data">An array containing the entire MTP file.</param>
        /// <param name="sizeOfData">Size of the provided array.</param>
        public static MotionPackage FromMtp(byte *data, int sizeOfData)
        {
            var entries = new List <ManagedAnimationEntry>();

            using (var stream = new UnmanagedMemoryStream(data, sizeOfData))
                using (var streamReader = new BufferedStreamReader(stream, 8192))
                {
                    streamReader.ReadBigEndianStruct(out MotionPackageHeader header);
                    streamReader.Seek(header.EntryOffset, SeekOrigin.Begin);

                    for (int x = 0; x < header.NumberOfFiles; x++)
                    {
                        streamReader.ReadBigEndianStruct(out AnimationEntry animationEntry);
                        entries.Add(ManagedAnimationEntry.FromAnimationEntry(data, animationEntry));
                    }

                    return(new MotionPackage(entries.ToArray()));
                }
        }
        /// <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);
        }
 /* Generated by R# */
 public bool Equals(ManagedAnimationEntry other) => string.Equals(FileName, other.FileName) && SequenceEqualWithNullSupport(FileData, other.FileData) && SequenceEqualWithNullSupport(Tuples, other.Tuples);