Beispiel #1
0
    /// <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("A CNT archive is being repacked...");

        // Get the archive data
        var data = (CNT)archive;

        // Create the file generator
        using ArchiveFileGenerator <CNT_File> fileGenerator = new();

        // Get files and entries
        var archiveFiles = files.Select(x => new
        {
            Entry    = (CNT_File)x.ArchiveEntry,
            FileItem = x
        }).ToArray();

        // Set files and directories
        data.Directories = files.Select(x => x.Directory).Distinct().Where(x => !x.IsNullOrWhiteSpace()).ToArray();
        data.Files       = archiveFiles.Select(x => x.Entry).ToArray();

        // Set the directory indexes
        foreach (var file in archiveFiles)
        {
            // Set the directory index
            file.Entry.DirectoryIndex = file.FileItem.Directory == String.Empty ? -1 : data.Directories.FindItemIndex(x => x == file.FileItem.Directory);
        }

        BinaryFile binaryFile = new StreamFile(Context, outputFileStream.Name, outputFileStream.Stream, leaveOpen: true);

        try
        {
            Context.AddFile(binaryFile);

            // Initialize the data
            data.Init(binaryFile.StartPointer);

            // Set the current pointer position to the header size
            data.RecalculateSize();
            uint pointer = (uint)data.Size;

            // Disable checksum
            data.IsChecksumUsed = false;

            // NOTE: We can't disable the XOR key entirely as that would disable it for the file bytes too, which would require them all to be decrypted
            // Reset XOR keys
            data.StringsXORKey = 0;

            // Load each file
            foreach (var file in archiveFiles)
            {
                // Get the file entry
                CNT_File entry = file.Entry;

                // Reset checksum and XOR key
                entry.FileChecksum       = 0;
                entry.Pre_FileNameXORKey = 0;

                // Add to the generator
                fileGenerator.Add(entry, () =>
                {
                    // Get the file stream to write to the archive
                    Stream fileStream = file.FileItem.GetFileData(generator).Stream;

                    // Set the pointer
                    entry.FileOffset = pointer;

                    // Update the pointer by the file size
                    pointer += entry.FileSize;

                    // Invoke event
                    OnWritingFileToArchive?.Invoke(this, new ValueEventArgs <ArchiveFileItem>(file.FileItem));

                    return(fileStream);
                });
            }

            // Make sure we have a generator for each file
            if (fileGenerator.Count != data.Files.Length)
            {
                throw new Exception("The .cnt file can't be serialized without a file generator for each file");
            }

            // Write the file contents
            foreach (CNT_File file in data.Files)
            {
                // Get the file stream
                using Stream fileStream = fileGenerator.GetFileStream(file);

                // Set the position to the pointer
                outputFileStream.Stream.Position = file.FileOffset;

                // Write the contents from the generator
                fileStream.CopyTo(outputFileStream.Stream);
            }

            outputFileStream.Stream.Position = 0;

            // Serialize the data
            FileFactory.Write(Context, binaryFile.FilePath, data);

            Logger.Info("The CNT archive has been repacked");
        }
        finally
        {
            Context.RemoveFile(binaryFile);
        }
    }
Beispiel #2
0
    /// <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 R1 PC archive is being repacked...");

        // Get the archive data
        var data = (PC_FileArchive)archive;

        // Create the file generator
        using ArchiveFileGenerator <PC_FileArchiveEntry> fileGenerator = new();

        // Get files and entries
        var archiveFiles = files.Select(x => new
        {
            Entry    = (PC_FileArchiveEntry)x.ArchiveEntry,
            FileItem = x
        }).ToArray();

        // Set files and directories
        data.Entries = archiveFiles.Select(x => x.Entry).ToArray();

        BinaryFile binaryFile = new StreamFile(Context, outputFileStream.Name, outputFileStream.Stream, leaveOpen: true);

        try
        {
            Context.AddFile(binaryFile);

            // Initialize the data
            data.Init(binaryFile.StartPointer);

            // Set the current pointer position to the header size
            data.RecalculateSize();
            uint pointer = (uint)data.Size;

            // Load each file
            foreach (var file in archiveFiles)
            {
                // Process the file name
                file.Entry.FileName = ProcessFileName(file.Entry.FileName);

                // Get the file entry
                PC_FileArchiveEntry entry = file.Entry;

                // Add to the generator
                fileGenerator.Add(entry, () =>
                {
                    // Get the file stream to write to the archive
                    Stream fileStream = file.FileItem.GetFileData(generator).Stream;

                    // Set the pointer
                    entry.FileOffset = pointer;

                    // Update the pointer by the file size
                    pointer += entry.FileSize;

                    // Invoke event
                    OnWritingFileToArchive?.Invoke(this, new ValueEventArgs <ArchiveFileItem>(file.FileItem));

                    return(fileStream);
                });
            }

            // Make sure we have a generator for each file
            if (fileGenerator.Count != data.Entries.Length)
            {
                throw new Exception("The .dat file can't be serialized without a file generator for each file");
            }

            // Write the file contents
            foreach (PC_FileArchiveEntry file in data.Entries)
            {
                // Get the file stream
                using Stream fileStream = fileGenerator.GetFileStream(file);

                // Set the position to the pointer
                outputFileStream.Stream.Position = file.FileOffset;

                // Write the contents from the generator
                fileStream.CopyTo(outputFileStream.Stream);
            }

            outputFileStream.Stream.Position = 0;

            // Serialize the data
            FileFactory.Write(Context, binaryFile.FilePath, data);

            Logger.Info("The R1 PC archive has been repacked");
        }
        finally
        {
            Context.RemoveFile(binaryFile);
        }
    }
    /// <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);
        }
    }