diff --git a/include/vpkpp/PackFile.h b/include/vpkpp/PackFile.h index 9bd1afde6..f0857cfc7 100644 --- a/include/vpkpp/PackFile.h +++ b/include/vpkpp/PackFile.h @@ -104,6 +104,12 @@ class PackFile { /// Add a new entry from a buffer void addEntry(const std::string& path, const std::byte* buffer, uint64_t bufferLen, EntryOptions options_); + /// Rename an existing entry + virtual bool renameEntry(const std::string& oldPath_, const std::string& newPath_); // NOLINT(*-use-nodiscard) + + /// Rename an existing directory + virtual bool renameDirectory(const std::string& oldDir_, const std::string& newDir_); // NOLINT(*-use-nodiscard) + /// Remove an entry virtual bool removeEntry(const std::string& path_); diff --git a/lang/c/include/vpkppc/PackFile.h b/lang/c/include/vpkppc/PackFile.h index 67b9c2dc5..777ae5ccf 100644 --- a/lang/c/include/vpkppc/PackFile.h +++ b/lang/c/include/vpkppc/PackFile.h @@ -74,6 +74,10 @@ SOURCEPP_API void vpkpp_add_entry_from_mem(vpkpp_pack_file_handle_t handle, cons SOURCEPP_API void vpkpp_add_entry_from_mem_with_options(vpkpp_pack_file_handle_t handle, const char* path, const unsigned char* buffer, size_t bufferLen, vpkpp_entry_options_t options); +SOURCEPP_API int vpkpp_rename_entry(vpkpp_pack_file_handle_t handle, const char* oldPath, const char* newPath); + +SOURCEPP_API int vpkpp_rename_directory(vpkpp_pack_file_handle_t handle, const char* oldDir, const char* newDir); + SOURCEPP_API int vpkpp_remove_entry(vpkpp_pack_file_handle_t handle, const char* path); SOURCEPP_API int vpkpp_remove_directory(vpkpp_pack_file_handle_t handle, const char* dirName); diff --git a/lang/c/src/vpkppc/PackFile.cpp b/lang/c/src/vpkppc/PackFile.cpp index 8b25c9c42..db6ff8460 100644 --- a/lang/c/src/vpkppc/PackFile.cpp +++ b/lang/c/src/vpkppc/PackFile.cpp @@ -189,6 +189,22 @@ SOURCEPP_API void vpkpp_add_entry_from_mem_with_options(vpkpp_pack_file_handle_t Convert::packFile(handle)->addEntry(path, reinterpret_cast(buffer), bufferLen, Convert::optionsFromC(options)); } +SOURCEPP_API int vpkpp_rename_entry(vpkpp_pack_file_handle_t handle, const char* oldPath, const char* newPath) { + SOURCEPP_EARLY_RETURN_VAL(handle, false); + SOURCEPP_EARLY_RETURN_VAL(oldPath, false); + SOURCEPP_EARLY_RETURN_VAL(newPath, false); + + return Convert::packFile(handle)->renameEntry(oldPath, newPath); +} + +SOURCEPP_API int vpkpp_rename_directory(vpkpp_pack_file_handle_t handle, const char* oldDir, const char* newDir) { + SOURCEPP_EARLY_RETURN_VAL(handle, false); + SOURCEPP_EARLY_RETURN_VAL(oldDir, false); + SOURCEPP_EARLY_RETURN_VAL(newDir, false); + + return Convert::packFile(handle)->renameEntry(oldDir, newDir); +} + SOURCEPP_API int vpkpp_remove_entry(vpkpp_pack_file_handle_t handle, const char* path) { SOURCEPP_EARLY_RETURN_VAL(handle, false); SOURCEPP_EARLY_RETURN_VAL(path, false); diff --git a/lang/csharp/src/vpkpp/PackFile.cs b/lang/csharp/src/vpkpp/PackFile.cs index a3300feec..ee28dbaae 100644 --- a/lang/csharp/src/vpkpp/PackFile.cs +++ b/lang/csharp/src/vpkpp/PackFile.cs @@ -76,6 +76,12 @@ internal static unsafe partial class Extern [DllImport("vpkppc")] public static extern void vpkpp_add_entry_from_mem(void* handle, [MarshalAs(UnmanagedType.LPStr)] string path, byte* buffer, ulong bufferLen); + [DllImport("vpkppc")] + public static extern int vpkpp_rename_entry(void* handle, [MarshalAs(UnmanagedType.LPStr)] string oldPath, [MarshalAs(UnmanagedType.LPStr)] string newPath); + + [DllImport("vpkppc")] + public static extern int vpkpp_rename_directory(void* handle, [MarshalAs(UnmanagedType.LPStr)] string oldDir, [MarshalAs(UnmanagedType.LPStr)] string newDir); + [DllImport("vpkppc")] public static extern int vpkpp_remove_entry(void* handle, [MarshalAs(UnmanagedType.LPStr)] string path); @@ -329,6 +335,22 @@ public void AddEntry(string path, IEnumerable buffer) } } + public bool RenameEntry(string oldPath, string newPath) + { + unsafe + { + return Convert.ToBoolean(Extern.vpkpp_rename_entry(Handle, oldPath, newPath)); + } + } + + public bool RenameDirectory(string oldDir, string newDir) + { + unsafe + { + return Convert.ToBoolean(Extern.vpkpp_rename_directory(Handle, oldDir, newDir)); + } + } + public bool RemoveEntry(string path) { unsafe diff --git a/src/vpkpp/PackFile.cpp b/src/vpkpp/PackFile.cpp index ea9a44cd7..9897527fa 100644 --- a/src/vpkpp/PackFile.cpp +++ b/src/vpkpp/PackFile.cpp @@ -230,6 +230,54 @@ void PackFile::addEntry(const std::string& path, const std::byte* buffer, uint64 this->addEntry(path, std::move(data), options_); } +bool PackFile::renameEntry(const std::string& oldPath_, const std::string& newPath_) { + auto oldPath = this->cleanEntryPath(oldPath_); + auto newPath = this->cleanEntryPath(newPath_); + if (this->entries.count(oldPath)) { + // Currently there is no pack file format that relies on file path to access data. + // If there ever is one, we're in trouble! (Well, no, just override the method.) + auto entry = this->entries.at(oldPath); + this->entries.erase(oldPath); + this->entries.emplace(newPath, entry); + return true; + } else if (this->unbakedEntries.count(oldPath)) { + auto entry = this->unbakedEntries.at(oldPath); + this->unbakedEntries.erase(oldPath); + this->unbakedEntries.emplace(newPath, entry); + return true; + } + return false; +} + +bool PackFile::renameDirectory(const std::string& oldDir_, const std::string& newDir_) { + auto oldDir = this->cleanEntryPath(oldDir_) + '/'; + auto newDir = this->cleanEntryPath(newDir_) + '/'; + + std::vector entryPaths; + std::vector unbakedEntryPaths; + this->runForAllEntries([&oldDir, &entryPaths, &unbakedEntryPaths](const std::string& path, const Entry& entry) { + if (path.starts_with(oldDir)) { + if (entry.unbaked) { + unbakedEntryPaths.push_back(path); + } else { + entryPaths.push_back(path); + } + } + }); + + for (const auto& entryPath : entryPaths) { + auto entry = this->entries.at(entryPath); + this->entries.erase(entryPath); + this->entries.emplace(newDir + entryPath.substr(oldDir.length()), entry); + } + for (const auto& entryPath : unbakedEntryPaths) { + auto entry = this->unbakedEntries.at(entryPath); + this->unbakedEntries.erase(entryPath); + this->unbakedEntries.emplace(newDir + entryPath.substr(oldDir.length()), entry); + } + return !entryPaths.empty() || !unbakedEntryPaths.empty(); +} + bool PackFile::removeEntry(const std::string& path_) { if (this->isReadOnly()) { return false;