/// <summary>
 ///  Constructs a KIFINT entry with the specified file name, entry data, parent KIFINT archive.
 /// </summary>
 /// <param name="fileName">
 ///  The cached name of the file. Calling <see cref="KifintArchive.KIFENTRY.FileName"/> is wasteful.
 /// </param>
 /// <param name="kifEntry">The decrypted data for the entry.</param>
 /// <param name="kifint">The parent KIFINT arhive.</param>
 internal KifintEntry(string fileName, KIFENTRY kifEntry, KifintArchive kifint)
 {
     Kifint   = kifint;
     FileName = fileName;
     Offset   = kifEntry.Offset;
     Length   = kifEntry.Length;
 }
        private static void DecryptArchiveSave(KIFHDR hdr, List <KIFENTRY> entries, uint tocSeed, uint fileKey,
                                               Blowfish blowfish, int keyIndex, Stream inStream, Stream outStream, KifintProgressArgs progress,
                                               KifintProgressCallback callback)
        {
            BinaryReader reader = new BinaryReader(inStream);
            BinaryWriter writer = new BinaryWriter(outStream);

            const int ProgressThreshold = 1;

            progress.EntryName  = null;
            progress.EntryIndex = 0;
            progress.EntryCount = entries.Count;

            // Decrypt the KIFINT entries using the file key
            for (uint i = 0; i < hdr.EntryCount; i++, progress.EntryIndex++)
            {
                if (unchecked ((int)i) == keyIndex)
                {
                    continue;
                }

                KIFENTRY entry = entries[unchecked ((int)i)];

                // Give the entry the correct name
                UnobfuscateFileName(entry.FileNameRaw, unchecked (tocSeed + i));
                // Apply the extra offset to be decrypted
                entry.Offset += i;
                // Decrypt the entry's length and offset
                blowfish.Decrypt(ref entry.Info);

                progress.EntryName = entry.FileName;
                if (i % ProgressThreshold == 0 || i + 1 == hdr.EntryCount)
                {
                    callback?.Invoke(progress);
                }

                // Goto the entry's decrypted offset, read the buffer, then decrypt it
                inStream.Position = entry.Offset;
                byte[] buffer = reader.ReadBytes(entry.Length);
                blowfish.Decrypt(buffer, entry.Length & ~7);

                // Move to the entry's offset in the output stream and write the buffer
                outStream.Position = entry.Offset;
                writer.Write(buffer);

                // Make sure to reassign the entry to the list, because
                // it's not an array and does not return struct references.
                entries[unchecked ((int)i)] = entry;
            }

            entries.RemoveAt(keyIndex);
            hdr.EntryCount--;

            outStream.Position = 0;
            writer.WriteUnmanaged(hdr);
            writer.WriteUnmanagedArray(entries);
        }