/// <summary> /// Gets a value indicating if the file should be compressed /// </summary> /// <param name="entry">The file entry to check</param> /// <returns>True if the file should be compressed, otherwise false</returns> public bool ShouldCompress(BundleFile_FileEntry entry) { return(CompressionMode switch { FileCompressionMode.Never => false, FileCompressionMode.Always => true, FileCompressionMode.MatchesSetting => !CompressEntireBlock && CompressedFileExtensions.Any(x => x == new FileExtension(entry.Path.FileName, multiple: true)), FileCompressionMode.WasCompressed => entry.IsCompressed, _ => throw new ArgumentOutOfRangeException(nameof(CompressionMode), CompressionMode, null) });
/// <summary> /// Writes the files to the archive /// </summary> /// <param name="generator">The generator</param> /// <param name="archive">The loaded archive data</param> /// <param name="outputFileStream">The file output stream for the archive</param> /// <param name="files">The files to include</param> public void WriteArchive(IDisposable?generator, object archive, ArchiveFileStream outputFileStream, IList <ArchiveFileItem> files) { Logger.Info("An IPK archive is being repacked..."); // Get the archive data var data = (BundleFile)archive; // Create the file generator using ArchiveFileGenerator <BundleFile_FileEntry> fileGenerator = new(); // Get files and entries var archiveFiles = files.Select(x => new { Entry = (BundleFile_FileEntry)x.ArchiveEntry, FileItem = x }).ToArray(); // Set the files data.FilePack.Files = archiveFiles.Select(x => x.Entry).ToArray(); data.BootHeader.FilesCount = (uint)data.FilePack.Files.Length; // Save the old base offset uint oldBaseOffset = data.BootHeader.BaseOffset; // Keep track of the current pointer position ulong currentOffset = 0; // Handle each file foreach (var file in archiveFiles) { // Get the file BundleFile_FileEntry entry = file.Entry; // Reset the offset array to always contain 1 item entry.Offsets = new ulong[] { entry.Offsets?.FirstOrDefault() ?? 0 }; // Set the count entry.OffsetsCount = (uint)entry.Offsets.Length; // Add to the generator fileGenerator.Add(entry, () => { // When reading the original file we need to use the old base offset uint newBaseOffset = data.BootHeader.BaseOffset; data.BootHeader.BaseOffset = oldBaseOffset; // Get the file bytes to write to the archive Stream fileStream = file.FileItem.GetFileData(generator).Stream; data.BootHeader.BaseOffset = newBaseOffset; // Set the offset entry.Offsets[0] = currentOffset; // Increase by the file size currentOffset += entry.ArchiveSize; // Invoke event OnWritingFileToArchive?.Invoke(this, new ValueEventArgs <ArchiveFileItem>(file.FileItem)); return(fileStream); }); } BinaryFile binaryFile = new StreamFile(Context, outputFileStream.Name, outputFileStream.Stream, leaveOpen: true); try { Context.AddFile(binaryFile); // Initialize the data data.Init(binaryFile.StartPointer); // Set the base offset data.RecalculateSize(); data.BootHeader.BaseOffset = (uint)data.Size; // Write the files WriteArchiveContent(data, outputFileStream.Stream, fileGenerator, Config.ShouldCompress(data.BootHeader)); outputFileStream.Stream.Position = 0; // Serialize the data FileFactory.Write(Context, binaryFile.FilePath, data); Logger.Info("The IPK archive has been repacked"); } finally { Context.RemoveFile(binaryFile); } }