/// <summary>
    /// Decodes the file data from the input stream, or nothing if the data is not encoded
    /// </summary>
    /// <param name="inputStream">The input data stream to decode</param>
    /// <param name="outputStream">The output data stream for the decoded data</param>
    /// <param name="fileEntry">The file entry for the file to decode</param>
    public void DecodeFile(Stream inputStream, Stream outputStream, object fileEntry)
    {
        var entry = (BundleFile_FileEntry)fileEntry;

        // Decompress the data if compressed
        if (entry.IsCompressed)
        {
            BundleBootHeader.GetEncoder(entry.Pre_BundleVersion, entry.FileSize).DecodeStream(inputStream, outputStream);
        }
    }
    /// <summary>
    /// Encodes the file data from the input stream, or nothing if the data does not need to be encoded
    /// </summary>
    /// <param name="inputStream">The input data stream to encode</param>
    /// <param name="outputStream">The output data stream for the encoded data</param>
    /// <param name="fileEntry">The file entry for the file to encode</param>
    public void EncodeFile(Stream inputStream, Stream outputStream, object fileEntry)
    {
        // Get the file entry
        var entry = (BundleFile_FileEntry)fileEntry;

        // Set the file size
        entry.FileSize = (uint)inputStream.Length;

        // Return the data as is if the file should not be compressed
        if (!Config.ShouldCompress(entry))
        {
            return;
        }

        // Compress the bytes
        BundleBootHeader.GetEncoder(entry.Pre_BundleVersion, entry.FileSize).EncodeStream(inputStream, outputStream);

        Logger.Trace("The file {0} has been compressed", entry.Path.FileName);

        // Set the compressed file size
        entry.CompressedSize = (uint)outputStream.Length;
    }
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="ipkData">The .ipk file data</param>
        /// <param name="archiveStream">The archive file stream</param>
        public IPKFileGenerator(BundleFile ipkData, Stream archiveStream)
        {
            // Get the .ipk data
            IPKData = ipkData;

            // If the block is compressed, decompress it to a temporary file
            if (ipkData.BootHeader.IsBlockCompressed)
            {
                // Get the temp path and create the file
                TempFile = new TempFile(true);

                // Set the stream to the temp file
                Stream = File.Open(TempFile.TempPath, FileMode.Open, FileAccess.ReadWrite);

                // Set the archive stream position
                archiveStream.Position = ipkData.BootHeader.BaseOffset;

                byte[] buffer = new byte[IPKData.BootHeader.BlockCompressedSize];
                archiveStream.Read(buffer, 0, buffer.Length);

                // Create a memory stream
                using var memStream = new MemoryStream(buffer);

                // Decompress the block
                BundleBootHeader.GetEncoder(IPKData.BootHeader.Version, IPKData.BootHeader.BlockSize).DecodeStream(memStream, Stream);

                // Set the stream to be disposed
                DisposeStream = true;
            }
            else
            {
                // Set the stream to the .ipk archive
                Stream = archiveStream;

                // Set the stream not to be disposed
                DisposeStream = false;
            }
        }
    private void WriteArchiveContent(BundleFile bundle, Stream stream, IArchiveFileGenerator <BundleFile_FileEntry> fileGenerator, bool compressBlock)
    {
        // Make sure we have a generator for each file
        if (fileGenerator.Count != bundle.FilePack.Files.Length)
        {
            throw new Exception("The .ipk file can't be serialized without a file generator for each file");
        }

        TempFile?  tempDecompressedBlockFile       = null;
        FileStream?tempDecompressedBlockFileStream = null;

        try
        {
            // Create a temporary file to use if the block should be compressed
            if (compressBlock)
            {
                tempDecompressedBlockFile       = new TempFile(true);
                tempDecompressedBlockFileStream = new FileStream(tempDecompressedBlockFile.TempPath, FileMode.Open);
            }

            // Get the stream to write the files to
            Stream currentStream = compressBlock ? tempDecompressedBlockFileStream ! : stream;

            // Write the file contents
            foreach (BundleFile_FileEntry file in bundle.FilePack.Files)
            {
                // Get the file stream from the generator
                using Stream fileStream = fileGenerator.GetFileStream(file);

                // Make sure the size matches
                if (fileStream.Length != file.ArchiveSize)
                {
                    throw new Exception("The archived file size does not match the bytes retrieved from the generator");
                }

                // Handle every file offset
                foreach (ulong offset in file.Offsets)
                {
                    // Set the position
                    currentStream.Position = (long)(compressBlock ? offset : (offset + bundle.BootHeader.BaseOffset));

                    // Write the bytes
                    fileStream.CopyTo(currentStream);
                    fileStream.Position = 0;
                }
            }

            // Handle the data if it should be compressed
            if (compressBlock)
            {
                // Get the length
                long decompressedSize = tempDecompressedBlockFileStream !.Length;

                // Create a temporary file for the final compressed data
                using TempFile tempCompressedBlockFile         = new(true);
                using FileStream tempCompressedBlockFileStream = new(tempCompressedBlockFile.TempPath, FileMode.Open);

                tempDecompressedBlockFileStream.Position = 0;

                // Compress the data
                BundleBootHeader.GetEncoder(bundle.BootHeader.Version, -1).EncodeStream(tempDecompressedBlockFileStream, tempCompressedBlockFileStream);

                tempCompressedBlockFileStream.Position = 0;

                // Set the .ipk stream position
                stream.Position = bundle.BootHeader.BaseOffset;

                // Write the data to main stream
                tempCompressedBlockFileStream.CopyTo(stream);

                // Update the size
                bundle.BootHeader.BlockCompressedSize = (uint)tempCompressedBlockFileStream.Length;
                bundle.BootHeader.BlockSize           = (uint)decompressedSize;
            }
            else
            {
                // Reset the size
                bundle.BootHeader.BlockCompressedSize = 0;
                bundle.BootHeader.BlockSize           = 0;
            }
        }
        finally
        {
            tempDecompressedBlockFile?.Dispose();
            tempDecompressedBlockFileStream?.Dispose();
        }
    }