/// <summary>
        ///  Extracts the KIFINT entry to a fixed stream of <paramref name="kifintStream"/>.
        /// </summary>
        /// <param name="kifintStream">The stream to the open KIFINT archive.</param>
        /// <param name="entry">The KIFINT entry used to locate the file.</param>
        /// <param name="leaveOpen">
        ///  True if the KIFINT archive stream should be left open even after closing the returned stream.
        /// </param>
        /// <returns>
        ///  A fixed stream containing the data of the decrypted entry. This stream must always be disposed of, because
        ///  it's not guaranteed to be a fixed stream of <paramref name="kifintStream"/>. This is the case when the
        ///  length is small enough for extracting bytes to be more efficient.
        /// </returns>
        ///
        /// <exception cref="ArgumentNullException">
        ///  <paramref name="kifintStream"/> or <paramref name="entry"/> is null.
        /// </exception>
        internal static Stream ExtractToStream(KifintStream kifintStream, KifintEntry entry, bool leaveOpen)
        {
            if (kifintStream == null)
            {
                throw new ArgumentNullException(nameof(kifintStream));
            }
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }
            var kifint = entry.Kifint;

            // Smaller streams will be faster as reading a big chunk of data all at once.
            if (kifint.IsEncrypted && entry.Length < 131072 * 2)               // Some arbitrary power of 2 cutoff length
            {
                try {
                    return(new MemoryStream(ExtractToBytes(kifintStream, entry)));
                } finally {
                    // We need to make sure the the stream is closed by us if we're not
                    // relying on the fixed streams to close the KIFINT archive stream.
                    if (!leaveOpen)
                    {
                        kifintStream.Close();
                    }
                }
            }

            kifintStream.Open(kifint);
            kifintStream.Position = entry.Offset;

            if (kifint.IsEncrypted)
            {
                return(new BlowfishInputStream(kifint.Blowfish, kifintStream, entry.Length, leaveOpen));
            }
            return(new FixedStream(kifintStream, entry.Length, leaveOpen));
        }
        /// <summary>
        ///  Extracts the KIFINT entry file from the the entry's KIFINT archive.
        /// </summary>
        /// <param name="kifintStream">The stream to the open KIFINT archive.</param>
        /// <param name="entry">The KIFINT entry used to locate the file.</param>
        /// <returns>A byte array containing the extracted KIFINT entry's file data.</returns>
        ///
        /// <exception cref="ArgumentNullException">
        ///  <paramref name="kifintStream"/> or <paramref name="entry"/> is null.
        /// </exception>
        internal static byte[] ExtractToBytes(KifintStream kifintStream, KifintEntry entry)
        {
            if (kifintStream == null)
            {
                throw new ArgumentNullException(nameof(kifintStream));
            }
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }
            var kifint = entry.Kifint;

            kifintStream.Open(kifint);
            BinaryReader reader = new BinaryReader(kifintStream);

            kifintStream.Position = entry.Offset;
            byte[] buffer = reader.ReadBytes(entry.Length);

            if (kifint.IsEncrypted)
            {
                kifint.Blowfish.Decrypt(buffer, entry.Length & ~7);
            }
            return(buffer);
        }