/// <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(); } }