diff --git a/.gitignore b/.gitignore index 37bef6b4..b0fc0f61 100644 --- a/.gitignore +++ b/.gitignore @@ -8,15 +8,3 @@ CMakeSettings.json build/ cmake-build-*/ out/ - -# CSharp -/src/lib/lang/csharp/**/bin -/src/lib/lang/csharp/**/obj -/src/lib/lang/csharp/**/TestResults -/src/lib/lang/csharp/**/*.DotSettings.user - -# Generated -generated/ -/include/vpkedit/Version.h -/include/vpkeditc/Version.h -/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj diff --git a/.gitmodules b/.gitmodules index 70aaa93f..2f60a12a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,27 +1,15 @@ [submodule "src/cli/thirdparty/argparse"] path = src/cli/thirdparty/argparse url = https://github.com/p-ranav/argparse -[submodule "src/gui/thirdparty/sapp"] - path = src/gui/thirdparty/sapp - url = https://github.com/craftablescience/SteamAppPathProvider -[submodule "src/gui/thirdparty/speedykeyv"] - path = src/gui/thirdparty/speedykeyv - url = https://github.com/ozxybox/SpeedyKeyV -[submodule "src/gui/thirdparty/sourcepp"] - path = src/gui/thirdparty/sourcepp - url = https://github.com/craftablescience/sourcepp -[submodule "src/lib/thirdparty/minizip-ng"] - path = src/lib/thirdparty/minizip-ng - url = https://github.com/zlib-ng/minizip-ng -[submodule "src/gui/thirdparty/miniaudio"] - path = src/gui/thirdparty/miniaudio - url = https://github.com/mackron/miniaudio -[submodule "src/gui/thirdparty/discord"] - path = src/gui/thirdparty/discord - url = https://github.com/craftablescience/discord-rpc-clean [submodule "src/cli/thirdparty/indicators"] path = src/cli/thirdparty/indicators url = https://github.com/p-ranav/indicators -[submodule "src/lib/thirdparty/cryptopp"] - path = src/lib/thirdparty/cryptopp - url = https://github.com/abdes/cryptopp-cmake +[submodule "src/gui/thirdparty/discord"] + path = src/gui/thirdparty/discord + url = https://github.com/craftablescience/discord-rpc-clean +[submodule "src/gui/thirdparty/miniaudio"] + path = src/gui/thirdparty/miniaudio + url = https://github.com/mackron/miniaudio +[submodule "src/shared/thirdparty/sourcepp"] + path = src/shared/thirdparty/sourcepp + url = https://github.com/craftablescience/sourcepp diff --git a/CMakeLists.txt b/CMakeLists.txt index 28df0f32..f3ee91fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25 FATAL_ERROR) # Create project project(vpkedit - DESCRIPTION "A library and CLI/GUI tool to create, read, and write several pack file formats." + DESCRIPTION "A CLI/GUI tool to create, read, and write several pack file formats." VERSION "4.2.2" HOMEPAGE_URL "https://github.com/craftablescience/VPKEdit") set(CMAKE_CXX_STANDARD 20) @@ -31,12 +31,7 @@ set(PROJECT_ORGANIZATION_NAME "craftablescience" CACHE STRING "" FORCE) set(PROJECT_HOMEPAGE_URL_API "https://api.github.com/repos/craftablescience/VPKEdit" CACHE STRING "" FORCE) # Options -option(VPKEDIT_BUILD_LIBC "Build VPKEdit C wrapper library" OFF) -option(VPKEDIT_BUILD_CLI "Build VPKEdit CLI application" ON) -option(VPKEDIT_BUILD_GUI "Build VPKEdit GUI application" ON) option(VPKEDIT_BUILD_INSTALLER "Build installer for VPKEdit GUI application" ON) -option(VPKEDIT_BUILD_EXAMPLE "Build library examples" OFF) -option(VPKEDIT_BUILD_TESTS "Run library tests" OFF) option(VPKEDIT_BUILD_FOR_STRATA_SOURCE "Build VPKEdit with the intent of the CLI/GUI going into the bin folder of a Strata Source game" OFF) option(VPKEDIT_USE_LTO "Build VPKEdit with link-time optimization enabled" OFF) @@ -109,46 +104,22 @@ function(vpkedit_configure_target TARGET) # Don't show the console when running the executable if(MSVC AND TARGET_IS_GUI) target_link_options( - ${PROJECT_NAME} PRIVATE + ${TARGET} PRIVATE "/ENTRY:mainCRTStartup") endif() endif() endfunction() -# libvpkedit -include("${CMAKE_CURRENT_SOURCE_DIR}/src/lib/_lib.cmake") - -# libvpkeditc -if(VPKEDIT_BUILD_LIBC) - include("${CMAKE_CURRENT_SOURCE_DIR}/src/lib/lang/c/_c.cmake") - - # libvpkeditcs - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj.in" - "${CMAKE_CURRENT_SOURCE_DIR}/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj") -endif() +# Shared +include("${CMAKE_CURRENT_SOURCE_DIR}/src/shared/_shared.cmake") # vpkeditcli -if(VPKEDIT_BUILD_CLI) - include("${CMAKE_CURRENT_SOURCE_DIR}/src/cli/_cli.cmake") -endif() +include("${CMAKE_CURRENT_SOURCE_DIR}/src/cli/_cli.cmake") # vpkedit -if(VPKEDIT_BUILD_GUI) - include("${CMAKE_CURRENT_SOURCE_DIR}/src/gui/_gui.cmake") -endif() +include("${CMAKE_CURRENT_SOURCE_DIR}/src/gui/_gui.cmake") -# Installer (GUI only, or CLI+GUI) -if(VPKEDIT_BUILD_GUI AND VPKEDIT_BUILD_INSTALLER) +# Installer +if(VPKEDIT_BUILD_INSTALLER) include("${CMAKE_CURRENT_SOURCE_DIR}/src/installer/_installer.cmake") endif() - -# vpkedit_example -if (VPKEDIT_BUILD_EXAMPLE) - include("${CMAKE_CURRENT_SOURCE_DIR}/example/_example.cmake") -endif() - -# vpkedit_test -if(VPKEDIT_BUILD_TESTS) - include("${CMAKE_CURRENT_SOURCE_DIR}/test/_test.cmake") -endif() diff --git a/README.md b/README.md index 33a25b2f..3a0f7f47 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,4 @@ Any contributors will be added to the credits in the form of a text file shipped ## Backend -This tool is powered by an open-source pack file editing library, `libvpkedit`. This library's code is stored in this same repository, -written in C++20 and also under the MIT license. Its code was initially based off of [ValvePak](https://github.com/SteamDatabase/ValvePak) -and the Valve Developer Wiki (see [the credits](https://github.com/craftablescience/VPKEdit/blob/main/CREDITS.md) for more information). - -A C wrapper library, `libvpkeditc`, is also present in this repository, and its compilation can be enabled in the CMake options. It translates the C++ library -into a C interface with largely minimal to no overhead. +This tool is powered by a collection of open-source C++20 Source engine parsers called [sourcepp](https://github.com/craftablescience/sourcepp). diff --git a/example/Example.cpp b/example/Example.cpp deleted file mode 100644 index 0afbc695..00000000 --- a/example/Example.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include - -#include "SamplePackFileImpl.h" - -int main() { - std::cout << "Supported file types:" << std::endl; - for (const auto& ext : vpkedit::PackFile::getSupportedFileTypes()) { - std::cout << ext << std::endl; - } - - // This won't work lol - (void) vpkedit::PackFile::open("file.example", {}); -} diff --git a/example/SamplePackFileImpl.cpp b/example/SamplePackFileImpl.cpp deleted file mode 100644 index 86982712..00000000 --- a/example/SamplePackFileImpl.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "SamplePackFileImpl.h" - -#include -#include - -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -EXAMPLE::EXAMPLE(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - // Add a new type in the PackFileType enum for this file type, and set it here - this->type = PackFileType::UNKNOWN; -} - -std::unique_ptr EXAMPLE::open(const std::string& path, PackFileOptions options, const Callback& callback) { - // Check if the file exists - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - // Create the pack file - auto* example = new EXAMPLE{path, options}; - auto packFile = std::unique_ptr(example); - - // Here is where you add entries to the entries member variable - // It's a map between a directory and a vector of entries - // Every time an entry is added, the callback should be called if the callback exists - std::vector> samplePaths{ - {"a/b/c", "skibidi_toilet.png"}, - {"d/c", "boykisser.mdl"}, - {"", "megamind.txt"}, - }; - for (auto& [dir, name] : samplePaths) { - // The path needs to be normalized, and respect case sensitivity - ::normalizeSlashes(dir); - if (!example->isCaseSensitive()) { - ::toLowerCase(dir); - ::toLowerCase(name); - } - - // Create the list if it doesn't exist - if (!example->entries.contains(dir)) { - example->entries[dir] = {}; - } - - // Use the createNewEntry function to avoid Entry having to friend every single damn class - Entry entry = createNewEntry(); - - // The path should be the full path to the file - entry.path = dir; - entry.path += dir.empty() ? "" : "/"; - entry.path += name; - - // We already did it at the start, but this is how it's usually done - //::normalizeSlashes(entry.path); - //if (!options.allowUppercaseLettersInFilenames) { - // ::toLowerCase(entry.path); - //} - - // The length should be the full uncompressed length of the file data in bytes - entry.length = 42; - - // The compressed length will be non-zero if the file is compressed, the length is in bytes - // This can be omitted if unused, 0 is the default - entry.compressedLength = 0; - - // This is the CRC32 of the file - a helper function to compute it is in - // This can also be omitted if unused, 0 is the default - entry.crc32 = 0; - - // Add the entry to the entries map - example->entries[dir].push_back(std::move(entry)); - - // Call the callback - if (callback) { - callback(dir, entry); - } - } - - return packFile; -} - -std::optional> EXAMPLE::readEntry(const Entry& entry) const { - // Include this code verbatim - will likely be moved to a utility method soon - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - - // Use the contents of the entry to access the file data and return it - // Return std::nullopt if there was an error during any step of this process - not an empty buffer! - return std::nullopt; -} - -Entry& EXAMPLE::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - // Include this verbatim - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - // Initialize the entry - set the entry properties just like in EXAMPLE::open - entry.path = filename; - // ... - - // Include this verbatim - if (!this->unbakedEntries.contains(dir)) { - this->unbakedEntries[dir] = {}; - } - this->unbakedEntries.at(dir).push_back(entry); - return this->unbakedEntries.at(dir).back(); -} - -bool EXAMPLE::bake(const std::string& outputDir_, const PackFile::Callback& callback) { - // Get the proper file output folder (include this verbatim) - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Loop over all entries and save them - for (const auto& [entryDir, entries] : this->getBakedEntries()) { - for (const Entry& entry : entries) { - auto binData = this->readEntry(entry); - if (!binData) { - continue; - } - - // Write data here - // ... - - // Call the callback - if (callback) { - callback(entry.getParentPath(), entry); - } - } - } - // Yes this is copy-paste, you could probably turn this into a lambda and call it on both maps - for (const auto& [entryDir, entries] : this->getUnbakedEntries()) { - for (const Entry& entry : entries) { - auto binData = this->readEntry(entry); - if (!binData) { - continue; - } - - // Write data here - // ... - - // Call the callback - if (callback) { - callback(entry.getParentPath(), entry); - } - } - } - - // Call this when all the entries have been written to disk - this->mergeUnbakedEntries(); - - // Include this verbatim at the end of the function - PackFile::setFullFilePath(outputDir); - // Return false before this if it encounters an error - return true; -} diff --git a/example/SamplePackFileImpl.h b/example/SamplePackFileImpl.h deleted file mode 100644 index 2a4b5193..00000000 --- a/example/SamplePackFileImpl.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -/* - * --- Example Pack File Implementation --- - * - * This code is a template for adding a new file format to libvpkedit. Copy these two files and follow the comments! - * - * Any methods marked as "[OPTIONAL]" can be deleted if the file format does not support them. - * - * Note that if you are writing a read-only parser, you will need to make the following deviations: - * - Inherit from PackFileReadOnly instead of PackFile - * - Don't implement the bake and addEntryInternal methods (marked with "[WRITE]") - * - * If these instructions are followed, you should see your format appear in the VPKEdit GUI automatically. - */ - -namespace vpkedit { - -// Define the accepted extension(s) as constant(s) -constexpr std::string_view EXAMPLE_EXTENSION = ".example"; - -// All file formats need a static open method, and need to derive four methods at minimum from PackFile -class EXAMPLE : public PackFile { -public: - // Always return a unique_ptr to PackFile so it has a uniform return type - // If your type needs any new options, add them to PackFileOptions - it was the cleanest way to do it without messing with variants or std::any - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - // [OPTIONAL] Implement this and return true if your file format is case-sensitive - [[nodiscard]] constexpr bool isCaseSensitive() const noexcept override { - return PackFile::isCaseSensitive(); - } - - // Returns the raw data the Entry points to - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - // [WRITE] Save any changes made to the opened file(s) - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - // [OPTIONAL] Returns any attributes your file format's entries have (refer to the other file formats for more info) - [[nodiscard]] std::vector getSupportedEntryAttributes() const override { - return PackFile::getSupportedEntryAttributes(); - } - - // [OPTIONAL] Add any custom file info here (refer to the other file formats for how to structure this) - [[nodiscard]] explicit operator std::string() const override { - return PackFile::operator std::string(); - } - -protected: - EXAMPLE(const std::string& fullFilePath_, PackFileOptions options_); - - // [WRITE] Adds a new entry from either a filename or a buffer - // Again, if your type needs any new options specific to entries, add them to EntryOptions - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - -private: - // Finally, register the open method with the extension - // Remember since C++ is STUPID you need to add this header to PackFile.cpp as well, or this will get optimized away - VPKEDIT_REGISTER_PACKFILE_OPEN(EXAMPLE_EXTENSION, &EXAMPLE::open); -}; - -} // namespace vpkedit diff --git a/example/_example.cmake b/example/_example.cmake deleted file mode 100644 index a738da8d..00000000 --- a/example/_example.cmake +++ /dev/null @@ -1,10 +0,0 @@ -add_executable(${PROJECT_NAME}_example - "${CMAKE_CURRENT_LIST_DIR}/Example.cpp" - "${CMAKE_CURRENT_LIST_DIR}/SamplePackFileImpl.h" - "${CMAKE_CURRENT_LIST_DIR}/SamplePackFileImpl.cpp") - -target_link_libraries(${PROJECT_NAME}_example PUBLIC lib${PROJECT_NAME}) - -target_include_directories( - ${PROJECT_NAME}_example PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/include/vpkedit/Attribute.h b/include/vpkedit/Attribute.h deleted file mode 100644 index 70e31b79..00000000 --- a/include/vpkedit/Attribute.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -namespace vpkedit { - -enum class Attribute : int { - //PATH, // Not included because its implied - LENGTH = 0, - VPK_PRELOADED_DATA_LENGTH, - VPK_ARCHIVE_INDEX, - CRC32, - PCK_MD5, - ATTRIBUTE_COUNT, -}; - -} // namespace vpkedit diff --git a/include/vpkedit/Entry.h b/include/vpkedit/Entry.h deleted file mode 100644 index 7b627e5e..00000000 --- a/include/vpkedit/Entry.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -namespace vpkedit { - -/// This class represents the metadata that a file has inside a PackFile. -/// It is used to access the file's data and read its properties -class Entry { - friend class PackFile; - -public: - /// Path to this entry (e.g. "materials/cable.vmt") - std::string path; - /// Format-specific flags (PCK: File flags, VPK: Internal parser state) - std::uint32_t flags = 0; - /// Length in bytes (in formats with compression, this is the uncompressed length) - std::uint64_t length = 0; - /// Offset, format-specific meaning - may be unused - std::uint64_t offset = 0; - /// If the format supports compression, this is the compressed length - /// If compression is not supported or unused, this will remain 0 - std::uint64_t compressedLength = 0; - /// CRC32 checksum - 0 if unused. - /// Note that for GCF, this is actually an index into a checksum array and NOT a checksum - std::uint32_t crc32 = 0; - /// Used to check if entry is saved to disk - bool unbaked = false; - - /// PCK - Each file has a 16-byte MD5 hash - std::array pck_md5{}; - - /// VPK - Which VPK this entry is in - std::uint16_t vpk_archiveIndex = 0; - /// VPK - Preloaded data - std::vector vpk_preloadedData; - - /// Returns the parent directory's path (e.g. "materials/cable.vmt" -> "materials") - [[nodiscard]] std::string getParentPath() const; - - /// Returns the filename (e.g. "materials/cable.vmt" -> "cable.vmt") - [[nodiscard]] std::string getFilename() const; - - /// Returns the file stem (e.g. "materials/cable.vmt" -> "cable") - [[nodiscard]] std::string getStem() const; - - /// Returns the file extension without a period (e.g. "materials/cable.vmt" -> "vmt") - [[nodiscard]] std::string getExtension() const; - -private: - /// The data attached to the unbaked entry, or the path to the file containing the unbaked entry's data - std::variant> unbakedData; - /// Which one? - bool unbakedUsingByteBuffer = false; - - Entry() = default; -}; - -struct VirtualEntry { - /// Filename of this entry (e.g. "cable.vmt") - std::string name; - - /// Read-only, or writable? - bool writable; -}; - -} // namespace vpkedit diff --git a/include/vpkedit/Options.h b/include/vpkedit/Options.h deleted file mode 100644 index aae8cfe4..00000000 --- a/include/vpkedit/Options.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -#include - -namespace vpkedit { - -/// VPK - Maximum preload data size in bytes -constexpr std::uint32_t VPK_MAX_PRELOAD_BYTES = 1024; - -/// VPK - Chunk size in bytes (default is 200mb) -constexpr std::uint32_t VPK_DEFAULT_CHUNK_SIZE = 200 * 1024 * 1024; - -struct PackFileOptions { - /// GMA - Write CRCs for files and the overall GMA file when baking - bool gma_writeCRCs = true; - - /// VPK - Version (ignored when opening an existing VPK) - std::uint32_t vpk_version = 2; - - /// VPK - If this value is 0, chunks have an unlimited size (not controlled by the library) - /// Chunk size is max 4gb, but since its not useful to have large chunks, try to keep the - /// preferred chunk size around the default - std::uint32_t vpk_preferredChunkSize = VPK_DEFAULT_CHUNK_SIZE; - - /// VPK - Controls generation of per-file MD5 hashes (only for VPK v2) - bool vpk_generateMD5Entries = false; - - /// ZIP/BSP - The compression method. Check the MZ_COMPRESS_METHOD definitions for valid values. Only accepts STORE currently - std::uint16_t zip_compressionMethod = MZ_COMPRESS_METHOD_STORE; -}; - -struct EntryOptions { - /// VPK - Save this entry to the directory VPK - bool vpk_saveToDirectory = false; - - /// VPK - The amount in bytes of the file to preload. Maximum is controlled by VPK_MAX_PRELOAD_BYTES - std::uint32_t vpk_preloadBytes = 0; -}; - -} // namespace vpkedit diff --git a/include/vpkedit/PackFile.h b/include/vpkedit/PackFile.h deleted file mode 100644 index a4485b54..00000000 --- a/include/vpkedit/PackFile.h +++ /dev/null @@ -1,229 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "Attribute.h" -#include "Entry.h" -#include "Options.h" -#include "PackFileType.h" - -namespace vpkedit { - -// Executable extensions - mostly just for Godot exports -constexpr std::string_view EXECUTABLE_EXTENSION0 = ".exe"; // - Windows -constexpr std::string_view EXECUTABLE_EXTENSION1 = ".bin"; // - Linux + Godot 3 and below (and Generic) -constexpr std::string_view EXECUTABLE_EXTENSION2 = ".x86"; // | Godot 4 (32-bit) -constexpr std::string_view EXECUTABLE_EXTENSION3 = ".x86_32"; // | Godot 4 (32-bit) -constexpr std::string_view EXECUTABLE_EXTENSION4 = ".x86_64"; // | Godot 4 (64-bit) - -class PackFile { -public: - PackFile(const PackFile& other) = delete; - PackFile& operator=(const PackFile& other) = delete; - PackFile(PackFile&& other) noexcept = default; - PackFile& operator=(PackFile&& other) noexcept = default; - - virtual ~PackFile() = default; - - // Accepts the entry parent directory and the entry metadata - using Callback = std::function; - - /// Open a generic pack file. The parser is selected based on the file extension - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - /// Get the file type of the pack file - [[nodiscard]] PackFileType getType() const; - - /// Get the current options of the pack file - [[nodiscard]] PackFileOptions getOptions() const; - - /// Returns true if the format has a checksum for each entry - [[nodiscard]] virtual constexpr bool hasEntryChecksums() const { - return false; - } - - /// Verify the checksums of each file, if a file fails the check its filename will be added to the vector - /// If there is no checksum ability in the format, it will return an empty vector - [[nodiscard]] virtual std::vector verifyEntryChecksums() const; - - /// Returns true if the entire file has a checksum - [[nodiscard]] virtual bool hasFileChecksum() const; - - /// Verify the checksum of the entire file, returns true on success - /// Will return true if there is no checksum ability in the format - [[nodiscard]] virtual bool verifyFileChecksum() const; - - /// Returns true if the file is signed - [[nodiscard]] virtual bool hasFileSignature() const; - - /// Verify the file signature, returns true on success - /// Will return true if there is no signature ability in the format - [[nodiscard]] virtual bool verifyFileSignature() const; - - /// Does the format support case-sensitive file names? - [[nodiscard]] virtual constexpr bool isCaseSensitive() const noexcept { - return false; - } - - /// Try to find an entry given the file path - [[nodiscard]] std::optional findEntry(const std::string& filename_, bool includeUnbaked = true) const; - - /// Try to read the entry's data to a bytebuffer - [[nodiscard]] virtual std::optional> readEntry(const Entry& entry) const = 0; - - /// Try to read the entry's data to a string - [[nodiscard]] std::optional readEntryText(const Entry& entry) const; - - [[nodiscard]] virtual constexpr bool isReadOnly() const noexcept { - return false; - } - - /// Add a new entry from a file path - the first parameter is the path in the PackFile, the second is the path on disk - void addEntry(const std::string& filename_, const std::string& pathToFile, EntryOptions options_); - - /// Add a new entry from a buffer - void addEntry(const std::string& filename_, std::vector&& buffer, EntryOptions options_); - - /// Add a new entry from a buffer - void addEntry(const std::string& filename_, const std::byte* buffer, std::uint64_t bufferLen, EntryOptions options_); - - /// Remove an entry - virtual bool removeEntry(const std::string& filename_); - - /// If output folder is unspecified, it will overwrite the original - virtual bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) = 0; - - /// Extract the given entry to disk at the given file path - bool extractEntry(const Entry& entry, const std::string& filePath) const; // NOLINT(*-use-nodiscard) - - /// Extract the given directory to disk under the given output directory - bool extractDir(const std::string& dir, const std::string& outputDir) const; // NOLINT(*-use-nodiscard) - - /// Extract the contents of the pack file to disk at the given directory - bool extractAll(const std::string& outputDir, bool createUnderPackFileDir = true) const; // NOLINT(*-use-nodiscard) - - /// Extract the contents of the pack file to disk at the given directory - only entries which match the predicate are extracted - bool extractAll(const std::string& outputDir, const std::function& predicate) const; // NOLINT(*-use-nodiscard) - - /// Get entries saved to disk - [[nodiscard]] const std::unordered_map>& getBakedEntries() const; - - /// Get entries that have been added but not yet baked - [[nodiscard]] const std::unordered_map>& getUnbakedEntries() const; - - /// Get the number of entries in the pack file - [[nodiscard]] std::size_t getEntryCount(bool includeUnbaked = true) const; - - /// Get the data associated with a virtual entry - [[nodiscard]] virtual std::optional> readVirtualEntry(const VirtualEntry& entry) const; - - /// Write data to a virtual entry - will fail if the entry is not writable - bool overwriteVirtualEntry(const VirtualEntry& entry, const std::string& pathToFile); - - /// Write data to a virtual entry - will fail if the entry is not writable - virtual bool overwriteVirtualEntry(const VirtualEntry& entry, const std::vector& data); - - /// Get virtual entries contained within the pack file (for example, lumps in a BSP) - [[nodiscard]] virtual std::vector getVirtualEntries() const; - - /// /home/user/pak01_dir.vpk - [[nodiscard]] std::string_view getFilepath() const; - - /// /home/user/pak01_dir.vpk -> /home/user/pak01 - [[nodiscard]] std::string getTruncatedFilepath() const; - - /// /home/user/pak01_dir.vpk -> pak01_dir.vpk - [[nodiscard]] std::string getFilename() const; - - /// /home/user/pak01_dir.vpk -> pak01.vpk - [[nodiscard]] std::string getTruncatedFilename() const; - - /// /home/user/pak01_dir.vpk -> pak01_dir - [[nodiscard]] std::string getFilestem() const; - - /// /home/user/pak01_dir.vpk -> pak01 - [[nodiscard]] virtual std::string getTruncatedFilestem() const; - - /// Returns a list of supported entry attributes - /// Mostly for GUI programs that show entries and their metadata in a table ;) - [[nodiscard]] virtual std::vector getSupportedEntryAttributes() const; - - [[nodiscard]] virtual explicit operator std::string() const; - - /// On Windows, some characters and file names are invalid - this escapes the given entry path - [[nodiscard]] static std::string escapeEntryPath(const std::string& path); - - /// Returns a list of supported extensions, e.g. {".vpk", ".bsp"} - [[nodiscard]] static std::vector getSupportedFileTypes(); - -protected: - PackFile(std::string fullFilePath_, PackFileOptions options_); - - [[nodiscard]] std::vector verifyEntryChecksumsUsingCRC32() const; - - virtual Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) = 0; - - [[nodiscard]] std::string getBakeOutputDir(const std::string& outputDir) const; - - void mergeUnbakedEntries(); - - void setFullFilePath(const std::string& outputDir); - - [[nodiscard]] static Entry createNewEntry(); - - [[nodiscard]] static const std::variant>& getEntryUnbakedData(const Entry& entry); - - [[nodiscard]] static bool isEntryUnbakedUsingByteBuffer(const Entry& entry); - - std::string fullFilePath; - - PackFileType type = PackFileType::UNKNOWN; - PackFileOptions options; - - std::unordered_map> entries; - std::unordered_map> unbakedEntries; - - using FactoryFunction = std::function(const std::string& path, PackFileOptions options, const Callback& callback)>; - - static std::unordered_map>& getOpenExtensionRegistry(); - - static const FactoryFunction& registerOpenExtensionForTypeFactory(std::string_view extension, const FactoryFunction& factory); -}; - -class PackFileReadOnly : public PackFile { -public: - [[nodiscard]] constexpr bool isReadOnly() const noexcept final { - return true; - } - - [[nodiscard]] explicit operator std::string() const override; - -protected: - PackFileReadOnly(std::string fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) final; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) final; -}; - -} // namespace vpkedit - -#define VPKEDIT_HELPER_CONCAT_INNER(a, b) a ## b -#define VPKEDIT_HELPER_CONCAT(a, b) VPKEDIT_HELPER_CONCAT_INNER(a, b) -#define VPKEDIT_HELPER_UNIQUE_NAME(base) VPKEDIT_HELPER_CONCAT(base, __LINE__) - -#define VPKEDIT_REGISTER_PACKFILE_OPEN(extension, function) \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenTypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(extension, function) - -#define VPKEDIT_REGISTER_PACKFILE_OPEN_EXECUTABLE(function) \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenExecutable0TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkedit::EXECUTABLE_EXTENSION0, function); \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenExecutable1TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkedit::EXECUTABLE_EXTENSION1, function); \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenExecutable2TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkedit::EXECUTABLE_EXTENSION2, function); \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenExecutable3TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkedit::EXECUTABLE_EXTENSION3, function); \ - static inline const FactoryFunction& VPKEDIT_HELPER_UNIQUE_NAME(packFileOpenExecutable4TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkedit::EXECUTABLE_EXTENSION4, function); diff --git a/include/vpkedit/PackFileType.h b/include/vpkedit/PackFileType.h deleted file mode 100644 index 108680dc..00000000 --- a/include/vpkedit/PackFileType.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -namespace vpkedit { - -enum class PackFileType { - UNKNOWN, - BSP, - FPX, - GCF, - GMA, - GRP, - PAK, - PCK, - VPK, - ZIP, -}; - -} // namespace vpkedit diff --git a/include/vpkedit/detail/Adler32.h b/include/vpkedit/detail/Adler32.h deleted file mode 100644 index 3f7a184d..00000000 --- a/include/vpkedit/detail/Adler32.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace vpkedit::detail { - -std::uint32_t computeAdler32(const std::vector& buffer); - -std::uint32_t computeAdler32(const std::byte* buffer, std::size_t len); - -} // namespace vpkedit::detail diff --git a/include/vpkedit/detail/CRC32.h b/include/vpkedit/detail/CRC32.h deleted file mode 100644 index cd93d722..00000000 --- a/include/vpkedit/detail/CRC32.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace vpkedit::detail { - -std::uint32_t computeCRC32(const std::vector& buffer); - -std::uint32_t computeCRC32(const std::byte* buffer, std::size_t len); - -} // namespace vpkedit::detail diff --git a/include/vpkedit/detail/FileStream.h b/include/vpkedit/detail/FileStream.h deleted file mode 100644 index ce633b35..00000000 --- a/include/vpkedit/detail/FileStream.h +++ /dev/null @@ -1,189 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace vpkedit::detail { - -enum FileStreamOptions { - FILESTREAM_OPT_READ = 1 << 0, - FILESTREAM_OPT_WRITE = 1 << 1, - FILESTREAM_OPT_APPEND = 1 << 2, - FILESTREAM_OPT_TRUNCATE = 1 << 3, - FILESTREAM_OPT_CREATE_IF_NONEXISTENT = 1 << 4, -}; - -template -concept PODType = std::is_trivial_v && std::is_standard_layout_v; - -class FileStream { -public: - explicit FileStream(const std::string& filepath, int options = FILESTREAM_OPT_READ); - FileStream(const FileStream& other) = delete; - FileStream& operator=(const FileStream& other) = delete; - FileStream(FileStream&& other) noexcept = default; - FileStream& operator=(FileStream&& other) noexcept = default; - - explicit operator bool() const; - - void seekInput(std::size_t offset, std::ios::seekdir offsetFrom = std::ios::beg); - - void seekOutput(std::size_t offset, std::ios::seekdir offsetFrom = std::ios::beg); - - template - void skipInput(std::size_t n = 1) { - if (!n) { - return; - } - this->seekInput(sizeof(T) * n, std::ios::cur); - } - - template - void skipOutput(std::size_t n = 1) { - if (!n) { - return; - } - this->seekOutput(sizeof(T) * n, std::ios::cur); - } - - [[nodiscard]] std::size_t tellInput(); - - [[nodiscard]] std::size_t tellOutput(); - - template - [[nodiscard]] T read() { - static_assert(!std::is_pointer_v, "Trying to read a pointer!"); - T obj{}; - this->read(obj); - return obj; - } - - template - [[nodiscard]] std::array readBytes() { - std::array out; - this->streamFile.read(reinterpret_cast(out.data()), L); - return out; - } - - [[nodiscard]] std::vector readBytes(std::size_t length); - - [[nodiscard]] std::string readString(); - - [[nodiscard]] std::string readString(std::size_t n, bool stopOnNullTerminator = true); - - template - void read(T& obj) { - this->streamFile.read(reinterpret_cast(&obj), sizeof(T)); - } - - template - void read(T(&obj)[N]) { - this->streamFile.read(reinterpret_cast(&obj[0]), sizeof(T) * N); - } - - template - void read(std::array& obj) { - for (int i = 0; i < N; i++) { - obj[i] = this->read(); - } - } - - template - void read(std::vector& obj, std::size_t n) { - obj.clear(); - if (!n) { - return; - } - obj.reserve(n); - for (int i = 0; i < n; i++) { - obj.push_back(this->read()); - } - } - - void read(std::string& obj) { - obj.clear(); - char temp = this->read(); - while (temp != '\0') { - obj += temp; - temp = this->read(); - } - } - - void read(std::string& obj, std::size_t n, bool stopOnNullTerminator = true) { - obj.clear(); - if (!n) { - return; - } - obj.reserve(n); - for (int i = 0; i < n; i++) { - char temp = this->read(); - if (temp == '\0' && stopOnNullTerminator) { - // Read the required number of characters and exit - this->skipInput(n - i - 1); - break; - } - obj += temp; - } - } - - template - void write(T obj) { - static_assert(!std::is_pointer_v, "Trying to write a pointer!"); - this->streamFile.write(reinterpret_cast(&obj), sizeof(T)); - } - - template - void writeBytes(const std::array obj) { - this->streamFile.write(reinterpret_cast(obj.data()), L); - } - - void writeBytes(const std::vector& buffer); - - template - void write(T(&obj)[N]) { - this->streamFile.write(reinterpret_cast(&obj[0]), sizeof(T) * N); - } - - template - void write(const std::array& obj) { - for (int i = 0; i < N; i++) { - this->write(obj[i]); - } - } - - template - void write(const std::vector& obj) { - for (T item : obj) { - this->write(item); - } - } - - void write(const std::string& obj, bool includeTerminator = true) { - this->streamFile.write(obj.data(), static_cast(obj.length())); - if (includeTerminator) { - this->write('\0'); - } - } - - void write(const std::string& obj, std::size_t n, bool forceIncludeTerminator) { - for (int i = 0; i < n; i++) { - if (i >= obj.length() || (i == n - 1 && forceIncludeTerminator)) { - this->write('\0'); - } else { - this->write(obj[i]); - } - } - } - - void flush(); - -protected: - std::fstream streamFile; -}; - -} // namespace vpkedit::detail diff --git a/include/vpkedit/detail/MD5.h b/include/vpkedit/detail/MD5.h deleted file mode 100644 index e03ff95a..00000000 --- a/include/vpkedit/detail/MD5.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace vpkedit::detail { - -std::array computeMD5(const std::vector& buffer); - -std::array computeMD5(const std::byte* buffer, std::size_t len); - -} // namespace vpkedit::detail diff --git a/include/vpkedit/detail/Misc.h b/include/vpkedit/detail/Misc.h deleted file mode 100644 index 17ea1250..00000000 --- a/include/vpkedit/detail/Misc.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace vpkedit::detail { - -void toLowerCase(std::string& input); - -void normalizeSlashes(std::string& path, bool stripSlashes = true); - -std::pair splitFilenameAndParentDir(const std::string& filename); - -std::vector readFileData(const std::string& filepath, std::size_t preloadBytesOffset = 0); - -std::string readFileText(const std::string& filepath, std::size_t preloadBytesOffset = 0); - -} // namespace vpkedit::detail diff --git a/include/vpkedit/detail/RSA.h b/include/vpkedit/detail/RSA.h deleted file mode 100644 index 3ce8271a..00000000 --- a/include/vpkedit/detail/RSA.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace vpkedit::detail { - -std::pair computeSHA256KeyPair(std::uint16_t size = 2048); - -bool verifySHA256Key(const std::vector& buffer, const std::vector& publicKey, const std::vector& signature); - -std::vector signDataWithSHA256Key(const std::vector& buffer, const std::vector& privateKey); - -std::vector decodeHexString(std::string_view hex); - -} // namespace vpkedit::detail diff --git a/include/vpkedit/format/BSP.h b/include/vpkedit/format/BSP.h deleted file mode 100644 index b8d4dec1..00000000 --- a/include/vpkedit/format/BSP.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include -#include - -#include "ZIP.h" - -namespace vpkedit { - -constexpr std::int32_t BSP_SIGNATURE = 'V' + ('B' << 8) + ('S' << 16) + ('P' << 24); -constexpr std::int32_t BSP_LUMP_COUNT = 64; -constexpr std::int32_t BSP_LUMP_ENTITY_INDEX = 0; -constexpr std::int32_t BSP_LUMP_PAKFILE_INDEX = 40; -constexpr std::string_view BSP_EXTENSION = ".bsp"; - -class BSP : public ZIP { -#pragma pack(push, 1) - struct Lump { - /// Byte offset into file - std::int32_t offset; - /// Length of lump data - std::int32_t length; - /// Lump format version - std::int32_t version; - /// Uncompressed size, or 0 - std::int32_t fourCC; - }; - - struct Header { - /// BSP_ID - std::int32_t signature; - /// Version of the BSP file - std::int32_t version; - /// Lump metadata - std::array lumps; - /// Map version number - std::int32_t mapRevision; - }; -#pragma pack(pop) - -public: - /// Open a BSP file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool isCaseSensitive() const noexcept override { - return false; - } - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::optional> readVirtualEntry(const VirtualEntry& entry) const override; - - bool overwriteVirtualEntry(const VirtualEntry& entry, const std::vector& data) override; - - [[nodiscard]] std::vector getVirtualEntries() const override; - - [[nodiscard]] explicit operator std::string() const override; - -protected: - BSP(const std::string& fullFilePath_, PackFileOptions options_); - - [[nodiscard]] std::vector readLump(int lumpToRead) const; - - void writeLump(int lumpToMove, const std::vector& data); - - /// If the lump is too big where it is, shift it to the end of the file, otherwise its fine - void moveLumpToWritableSpace(int lumpToMove, int newSize); - - static const std::string TEMP_ZIP_PATH; - - Header header{}; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(BSP_EXTENSION, &BSP::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/FPX.h b/include/vpkedit/format/FPX.h deleted file mode 100644 index d7e25180..00000000 --- a/include/vpkedit/format/FPX.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "VPK.h" - -namespace vpkedit { - -constexpr std::uint32_t FPX_SIGNATURE = 0x3241ff33; -constexpr std::string_view FPX_DIR_SUFFIX = "_fdr"; -constexpr std::string_view FPX_EXTENSION = ".fpx"; - -class FPX : public VPK { -public: - /// Open a directory VPK file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - -protected: - FPX(const std::string& fullFilePath_, PackFileOptions options_); - - [[nodiscard]] static std::unique_ptr openInternal(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - -private: - using VPK::generateKeyPairFiles; - using VPK::sign; - using VPK::getVersion; - using VPK::setVersion; - - VPKEDIT_REGISTER_PACKFILE_OPEN(FPX_EXTENSION, &FPX::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/GCF.h b/include/vpkedit/format/GCF.h deleted file mode 100644 index 3d350ce7..00000000 --- a/include/vpkedit/format/GCF.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#include -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::string_view GCF_EXTENSION = ".gcf"; - -class GCF : public PackFileReadOnly { -protected: -#pragma pack(push, 1) - struct Header { - std::uint32_t dummy1; - std::uint32_t dummy2; - std::uint32_t gcfversion; - std::uint32_t appid; - std::uint32_t appversion; - std::uint32_t dummy3; - std::uint32_t dummy4; - std::uint32_t filesize; - std::uint32_t blocksize; - std::uint32_t blockcount; - std::uint32_t dummy5; - }; - - // second header with info about blocks inside the file - // appears only ONCE not before every block! - struct BlockHeader { - std::uint32_t count; - std::uint32_t used; - std::uint32_t dummy1; - std::uint32_t dummy2; - std::uint32_t dummy3; - std::uint32_t dummy4; - std::uint32_t dummy5; - std::uint32_t checksum; - }; - - struct Block { - std::uint32_t entry_type; - std::uint32_t file_data_offset; - std::uint32_t file_data_size; - std::uint32_t first_data_block_index; - std::uint32_t next_block_entry_index; - std::uint32_t prev_block_entry_index; - std::uint32_t dir_index; - }; - - struct DirectoryHeader { - std::uint32_t dummy1; - std::uint32_t cacheid; - std::uint32_t gcfversion; - std::uint32_t itemcount; - std::uint32_t filecount; - std::uint32_t dummy2; - std::uint32_t dirsize; - std::uint32_t namesize; - std::uint32_t info1count; - std::uint32_t copycount; - std::uint32_t localcount; - std::uint32_t dummy3; - std::uint32_t dummy4; - std::uint32_t checksum; - }; - - struct DirectoryEntry { - std::uint32_t nameoffset; - std::uint32_t itemsize; - std::uint32_t fileid; - std::uint32_t dirtype; - std::uint32_t parentindex; - std::uint32_t nextindex; - std::uint32_t firstindex; - }; - - struct DirectoryEntry2 { - DirectoryEntry entry_real{}; - std::string filename; - }; - - struct DirectoryMapHeader { - std::uint32_t dummy1; - std::uint32_t dummy2; - }; - - struct DirectoryMapEntry { - std::uint32_t firstblockindex; - }; - - struct DataBlockHeader { - std::uint32_t appversion; - std::uint32_t blockcount; - std::uint32_t blocksize; - std::uint32_t firstblockoffset; - std::uint32_t used; - std::uint32_t checksum; - }; - - struct ChecksumMapHeader { - std::uint32_t dummy1; - std::uint32_t dummy2; - std::uint32_t item_count; - std::uint32_t checksum_count; - }; - - struct ChecksumMapEntry { - std::uint32_t count; - std::uint32_t firstindex; - }; -#pragma pack(pop) - -public: - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool hasEntryChecksums() const override { - return true; - } - - [[nodiscard]] std::vector verifyEntryChecksums() const override; - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - - [[nodiscard]] explicit operator std::string() const override; - -protected: - GCF(const std::string& fullFilePath_, PackFileOptions options_); - - Header header{}; - BlockHeader blockheader{}; - std::vector blockdata{}; - std::vector fragmap{}; - DirectoryHeader dirheader{}; - //std::vector direntries{}; - std::vector dirmap_entries{}; - DataBlockHeader datablockheader{}; - std::vector chksum_map{}; - std::vector checksums{}; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(GCF_EXTENSION, &GCF::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/GMA.h b/include/vpkedit/format/GMA.h deleted file mode 100644 index 231b3c18..00000000 --- a/include/vpkedit/format/GMA.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::int32_t GMA_SIGNATURE = 'G' + ('M' << 8) + ('A' << 16) + ('D' << 24); -constexpr std::string_view GMA_EXTENSION = ".gma"; - -class GMA : public PackFile { -protected: - struct Header { - std::uint32_t signature; - std::uint8_t version; - std::uint64_t steamID; - std::uint64_t timestamp; - std::string requiredContent; - std::string addonName; - std::string addonDescription; - std::string addonAuthor; - std::int32_t addonVersion; - }; - -public: - /// Open a GMA file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool hasEntryChecksums() const override { - return true; - } - - [[nodiscard]] std::vector verifyEntryChecksums() const override; - - [[nodiscard]] bool hasFileChecksum() const override; - - [[nodiscard]] bool verifyFileChecksum() const override; - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - - [[nodiscard]] explicit operator std::string() const override; - -protected: - GMA(const std::string& fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - - Header header{}; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(GMA_EXTENSION, &GMA::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/GRP.h b/include/vpkedit/format/GRP.h deleted file mode 100644 index a72c27e2..00000000 --- a/include/vpkedit/format/GRP.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::int8_t GRP_FILENAME_MAX_SIZE = 12; -constexpr std::string_view GRP_SIGNATURE = "KenSilverman"; -constexpr std::string_view GRP_EXTENSION = ".grp"; - -class GRP : public PackFile { -public: - /// Open a GRP file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - -protected: - GRP(const std::string& fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(GRP_EXTENSION, &GRP::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/PAK.h b/include/vpkedit/format/PAK.h deleted file mode 100644 index 9978cde8..00000000 --- a/include/vpkedit/format/PAK.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::int8_t PAK_FILENAME_MAX_SIZE = 56; -constexpr std::int32_t PAK_SIGNATURE = 'P' + ('A' << 8) + ('C' << 16) + ('K' << 24); -constexpr std::string_view PAK_EXTENSION = ".pak"; - -class PAK : public PackFile { -public: - /// Open a PAK file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - -protected: - PAK(const std::string& fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(PAK_EXTENSION, &PAK::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/PCK.h b/include/vpkedit/format/PCK.h deleted file mode 100644 index eb83f988..00000000 --- a/include/vpkedit/format/PCK.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::int32_t PCK_SIGNATURE = 0x43504447; -constexpr std::string_view PCK_PATH_PREFIX = "res://"; -constexpr std::string_view PCK_EXTENSION = ".pck"; - -class PCK : public PackFile { -protected: - enum FlagsV2 : std::uint32_t { - FLAG_NONE = 0, - FLAG_ENCRYPTED = 1 << 0, - FLAG_RELATIVE_FILE_DATA = 1 << 1, - }; - - struct Header { - std::uint32_t packVersion; - std::uint32_t godotVersionMajor; - std::uint32_t godotVersionMinor; - std::uint32_t godotVersionPatch; - FlagsV2 flags; // packVersion >= 2 - }; - -public: - /// Open a PCK file (potentially embedded in an executable) - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool isCaseSensitive() const noexcept override { - return true; - } - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - - [[nodiscard]] explicit operator std::string() const override; - -protected: - PCK(const std::string& fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - - Header header{}; - - std::size_t startOffset = 0; - std::size_t dataOffset = 0; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(PCK_EXTENSION, &PCK::open); - VPKEDIT_REGISTER_PACKFILE_OPEN_EXECUTABLE(&PCK::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/VPK.h b/include/vpkedit/format/VPK.h deleted file mode 100644 index ffbd1048..00000000 --- a/include/vpkedit/format/VPK.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::uint32_t VPK_SIGNATURE = 0x55aa1234; -constexpr std::uint16_t VPK_DIR_INDEX = 0x7fff; -constexpr std::uint16_t VPK_ENTRY_TERM = 0xffff; -constexpr std::string_view VPK_DIR_SUFFIX = "_dir"; -constexpr std::string_view VPK_EXTENSION = ".vpk"; - -constexpr std::string_view VPK_KEYPAIR_PUBLIC_KEY_TEMPLATE = "public_key\n{\n\ttype \"rsa\"\n\trsa_public_key \"%s\"\n}\n"; -constexpr std::string_view VPK_KEYPAIR_PRIVATE_KEY_TEMPLATE = "private_key\n{\n\ttype \"rsa\"\n\trsa_private_key \"%s\"\n\tprivate_key_encrypted 0\n\tpublic_key\n\t{\n\t\ttype \"rsa\"\n\t\trsa_public_key \"%s\"\n\t}\n}\n"; - -class VPK : public PackFile { -protected: -#pragma pack(push, 1) - struct Header1 { - std::uint32_t signature; - std::uint32_t version; - std::uint32_t treeSize; - }; - - struct Header2 { - std::uint32_t fileDataSectionSize; - std::uint32_t archiveMD5SectionSize; - std::uint32_t otherMD5SectionSize; - std::uint32_t signatureSectionSize; - }; - - struct Footer2 { - std::array treeChecksum{}; - std::array md5EntriesChecksum{}; - std::array wholeFileChecksum{}; - std::vector publicKey{}; - std::vector signature{}; - }; - - struct MD5Entry { - /// The archive index of the file - std::uint32_t archiveIndex; - /// The offset in the archive - std::uint32_t offset; - /// The length in bytes - std::uint32_t length; - /// The CRC32 checksum of this entry - std::array checksum; - }; -#pragma pack(pop) - - struct FreedChunk { - std::uint64_t offset; - std::uint64_t length; - std::uint16_t archiveIndex; - }; - -public: - // Accepts the full entry path (parent directory + filename), returns saveToDir and preloadBytes - using EntryCreationCallback = std::function(const std::string& fullEntryPath)>; - - /// Create a new directory VPK file - must end in "_dir.vpk"! This is not enforced but STRONGLY recommended - [[nodiscard]] static std::unique_ptr createEmpty(const std::string& path, PackFileOptions options = {}); - - /// Create a new directory VPK file from a directory, the contents of the directory will be present in the root VPK directory. (See above comment) - [[nodiscard]] static std::unique_ptr createFromDirectory(const std::string& vpkPath, const std::string& contentPath, bool saveToDir = false, PackFileOptions options = {}, const Callback& bakeCallback = nullptr); - - /// Create a new directory VPK file from a directory, the contents of the directory will be present in the root VPK directory. Each entry's properties is determined by a callback. (See above comment) - [[nodiscard]] static std::unique_ptr createFromDirectoryProcedural(const std::string& vpkPath, const std::string& contentPath, const EntryCreationCallback& creationCallback, PackFileOptions options = {}, const Callback& bakeCallback = nullptr); - - /// Open a directory VPK file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool hasEntryChecksums() const override { - return true; - } - - [[nodiscard]] std::vector verifyEntryChecksums() const override; - - [[nodiscard]] bool hasFileChecksum() const override; - - [[nodiscard]] bool verifyFileChecksum() const override; - - [[nodiscard]] bool hasFileSignature() const override; - - [[nodiscard]] bool verifyFileSignature() const override; - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool removeEntry(const std::string& filename_) override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::string getTruncatedFilestem() const override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - - [[nodiscard]] explicit operator std::string() const override; - - /// Generate keypair files, which can be used to sign a VPK - /// Input is a truncated file path, e.g. "/x/y/z/key" or just "key" for the CWD - /// It will append ".publickey.vdf" and ".privatekey.vdf" to the input and save those files - static bool generateKeyPairFiles(const std::string& name); - - /// Sign the VPK with the given private key KeyValues file. (See below comment) - bool sign(const std::string& filename_); - - /// Sign the VPK with the given keypair. Run this after VPK::bake if modifying the VPK file contents - bool sign(const std::vector& privateKey, const std::vector& publicKey); - - /// Returns 1 for v1, 2 for v2 - [[nodiscard]] std::uint32_t getVersion() const; - - /// Change the version of the VPK. Valid values are 1 and 2 - void setVersion(std::uint32_t version); - -protected: - VPK(const std::string& fullFilePath_, PackFileOptions options_); - - [[nodiscard]] static std::unique_ptr openInternal(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - - [[nodiscard]] std::uint32_t getHeaderLength() const; - - int numArchives = -1; - std::uint32_t currentlyFilledChunkSize = 0; - - std::vector freedChunks; - - Header1 header1{}; // Present in all VPK versions - Header2 header2{}; // Present in VPK v2 - Footer2 footer2{}; // Present in VPK v2 - - std::vector md5Entries; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(VPK_EXTENSION, &VPK::open); -}; - -} // namespace vpkedit diff --git a/include/vpkedit/format/ZIP.h b/include/vpkedit/format/ZIP.h deleted file mode 100644 index 8bb4e65f..00000000 --- a/include/vpkedit/format/ZIP.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "../PackFile.h" - -namespace vpkedit { - -constexpr std::string_view BMZ_EXTENSION = ".bmz"; -constexpr std::string_view ZIP_EXTENSION = ".zip"; - -class ZIP : public PackFile { -public: - ~ZIP() override; - - /// Open a ZIP file - [[nodiscard]] static std::unique_ptr open(const std::string& path, PackFileOptions options = {}, const Callback& callback = nullptr); - - [[nodiscard]] constexpr bool hasEntryChecksums() const override { - return true; - } - - [[nodiscard]] std::vector verifyEntryChecksums() const override; - - [[nodiscard]] constexpr bool isCaseSensitive() const noexcept override { - return true; - } - - [[nodiscard]] std::optional> readEntry(const Entry& entry) const override; - - bool bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) override; - - [[nodiscard]] std::vector getSupportedEntryAttributes() const override; - -#ifdef VPKEDIT_ZIP_COMPRESSION - [[nodiscard]] std::uint16_t getCompressionMethod() const; - - void setCompressionMethod(std::uint16_t compressionMethod); -#endif - -protected: - ZIP(const std::string& fullFilePath_, PackFileOptions options_); - - Entry& addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) override; - - bool bakeTempZip(const std::string& writeZipPath, const Callback& callback); - - bool openZIP(std::string_view path); - - void closeZIP(); - - static const std::string TEMP_ZIP_PATH; - - void* streamHandle = nullptr; - bool streamOpen = false; - - void* zipHandle = nullptr; - bool zipOpen = false; - -private: - VPKEDIT_REGISTER_PACKFILE_OPEN(BMZ_EXTENSION, &ZIP::open); - VPKEDIT_REGISTER_PACKFILE_OPEN(ZIP_EXTENSION, &ZIP::open); -}; - -} // namespace vpkedit diff --git a/include/vpkeditc/API.h b/include/vpkeditc/API.h deleted file mode 100644 index 14347f68..00000000 --- a/include/vpkeditc/API.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#if defined(_WIN32) || defined(__CYGWIN__) - #define VPKEDIT_EXPORT __declspec(dllexport) -#elif defined(__GNUC__) - #define VPKEDIT_EXPORT __attribute__((__visibility__("default"))) -#else - #define VPKEDIT_EXPORT -#endif - -#ifdef __cplusplus - #define VPKEDIT_API extern "C" VPKEDIT_EXPORT - #include - #include - using std::size_t; - using std::int64_t; - using std::uint64_t; - using std::uint32_t; - using std::uint16_t; - using std::uint8_t; -#else - #define VPKEDIT_API VPKEDIT_EXPORT - #include - #include -#endif diff --git a/include/vpkeditc/Attribute.h b/include/vpkeditc/Attribute.h deleted file mode 100644 index 821ec850..00000000 --- a/include/vpkeditc/Attribute.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - VPKEDIT_ATTRIBUTE_NONE = -1, - VPKEDIT_ATTRIBUTE_LENGTH = 0, - VPKEDIT_ATTRIBUTE_VPK_PRELOADED_DATA_LENGTH, - VPKEDIT_ATTRIBUTE_VPK_ARCHIVE_INDEX, - VPKEDIT_ATTRIBUTE_CRC32, - VPKEDIT_ATTRIBUTE_PCK_MD5, - VPKEDIT_ATTRIBUTE_COUNT, -} VPKEdit_Attribute_e; - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/include/vpkeditc/Buffer.h b/include/vpkeditc/Buffer.h deleted file mode 100644 index 56278486..00000000 --- a/include/vpkeditc/Buffer.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "API.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int64_t size; - uint8_t* data; -} VPKEdit_Buffer_t; - -#define VPKEDIT_BUFFER_INVALID (VPKEdit_Buffer_t{.size = -1, .data = NULL}) - -#ifdef __cplusplus -} // extern "C" -#endif - -VPKEDIT_API VPKEdit_Buffer_t vpkedit_buffer_new(size_t size); - -VPKEDIT_API void vpkedit_buffer_free(VPKEdit_Buffer_t* buffer); diff --git a/include/vpkeditc/Entry.h b/include/vpkeditc/Entry.h deleted file mode 100644 index 084625ea..00000000 --- a/include/vpkeditc/Entry.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "API.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void* VPKEdit_EntryHandle_t; - -typedef struct { - int64_t size; - VPKEdit_EntryHandle_t* data; -} VPKEdit_EntryHandleArray_t; - -typedef void* VPKEdit_VirtualEntryHandle_t; - -#define VPKEDIT_ENTRY_HANDLE_ARRAY_INVALID (VPKEdit_EntryHandleArray_t{.size = -1, .data = NULL}) - -typedef struct { - int64_t size; - VPKEdit_VirtualEntryHandle_t* data; -} VPKEdit_VirtualEntryHandleArray_t; - -#define VPKEDIT_VIRTUAL_ENTRY_HANDLE_ARRAY_INVALID (VPKEdit_VirtualEntryHandleArray_t{.size = -1, .data = NULL}) - -#ifdef __cplusplus -} // extern "C" -#endif - -VPKEDIT_API size_t vpkedit_entry_get_path(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_entry_get_parent_path(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_entry_get_filename(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_entry_get_stem(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_entry_get_extension(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API void vpkedit_entry_free(VPKEdit_EntryHandle_t* handle); - -VPKEDIT_API void vpkedit_entry_array_free(VPKEdit_EntryHandleArray_t* array); - -VPKEDIT_API size_t vpkedit_virtual_entry_get_name(VPKEdit_VirtualEntryHandle_t* handle, char* buffer, size_t bufferLen); - -VPKEDIT_API bool vpkedit_virtual_entry_is_writable(VPKEdit_VirtualEntryHandle_t* handle); - -VPKEDIT_API void vpkedit_virtual_entry_free(VPKEdit_VirtualEntryHandle_t* handle); - -VPKEDIT_API void vpkedit_virtual_entry_array_free(VPKEdit_VirtualEntryHandleArray_t* array); diff --git a/include/vpkeditc/Options.h b/include/vpkeditc/Options.h deleted file mode 100644 index 9e43944f..00000000 --- a/include/vpkeditc/Options.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "API.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - bool gma_writeCRCs; - uint32_t vpk_version; - uint32_t vpk_preferredChunkSize; - bool vpk_generateMD5Entries; - uint16_t zip_compressionMethod; -} VPKEdit_PackFileOptions_t; - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/include/vpkeditc/PackFile.h b/include/vpkeditc/PackFile.h deleted file mode 100644 index 9c60c028..00000000 --- a/include/vpkeditc/PackFile.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include "Attribute.h" -#include "Buffer.h" -#include "Entry.h" -#include "Options.h" -#include "PackFileType.h" -#include "String.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void* VPKEdit_PackFileHandle_t; - -#ifdef __cplusplus -} // extern "C" -#endif - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); - -VPKEDIT_API VPKEdit_PackFileType_e vpkedit_get_type(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API VPKEdit_PackFileOptions_t vpkedit_get_options(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_has_entry_checksums(VPKEdit_PackFileHandle_t handle); - -// REQUIRES MANUAL FREE: vpkedit_string_array_free -VPKEDIT_API VPKEdit_StringArray_t vpkedit_verify_entry_checksums(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_has_file_checksum(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_verify_file_checksum(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_has_file_signature(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_verify_file_signature(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API bool vpkedit_is_case_sensitive(VPKEdit_PackFileHandle_t handle); - -// REQUIRES MANUAL FREE: vpkedit_entry_free -VPKEDIT_API VPKEdit_EntryHandle_t vpkedit_find_entry(VPKEdit_PackFileHandle_t handle, const char* filename, bool includeUnbaked); - -// REQUIRES MANUAL FREE: vpkedit_buffer_free -VPKEDIT_API VPKEdit_Buffer_t vpkedit_read_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry); - -// REQUIRES MANUAL FREE: vpkedit_string_free -VPKEDIT_API VPKEdit_String_t vpkedit_read_entry_text(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry); - -VPKEDIT_API bool vpkedit_is_read_only(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API void vpkedit_add_entry_from_file(VPKEdit_PackFileHandle_t handle, const char* filename, const char* pathToFile); - -VPKEDIT_API void vpkedit_add_entry_from_mem(VPKEdit_PackFileHandle_t handle, const char* filename, const unsigned char* buffer, size_t bufferLen); - -VPKEDIT_API bool vpkedit_remove_entry(VPKEdit_PackFileHandle_t handle, const char* filename); - -VPKEDIT_API bool vpkedit_bake(VPKEdit_PackFileHandle_t handle, const char* outputDir); - -VPKEDIT_API bool vpkedit_extract_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry, const char* filePath); - -VPKEDIT_API bool vpkedit_extract_dir(VPKEdit_PackFileHandle_t handle, const char* dir, const char* outputDir); - -VPKEDIT_API bool vpkedit_extract_all(VPKEdit_PackFileHandle_t handle, const char* outputDir, bool createUnderPackFileDir); - -VPKEDIT_API bool vpkedit_extract_all_if(VPKEdit_PackFileHandle_t handle, const char* outputDir, bool(*predicate)(VPKEdit_EntryHandle_t)); - -// REQUIRES MANUAL FREE: vpkedit_entry_array_free -VPKEDIT_API VPKEdit_EntryHandleArray_t vpkedit_get_baked_entries(VPKEdit_PackFileHandle_t handle); - -// REQUIRES MANUAL FREE: vpkedit_entry_array_free -VPKEDIT_API VPKEdit_EntryHandleArray_t vpkedit_get_unbaked_entries(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API size_t vpkedit_get_entry_count(VPKEdit_PackFileHandle_t handle, bool includeUnbaked); - -VPKEDIT_API VPKEdit_Buffer_t vpkedit_read_virtual_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry); - -VPKEDIT_API bool vpkedit_overwrite_virtual_entry_from_file(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry, const char* pathToFile); - -VPKEDIT_API bool vpkedit_overwrite_virtual_entry_from_mem(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry, const unsigned char* buffer, size_t bufferLen); - -// REQUIRES MANUAL FREE: vpkedit_virtual_entry_array_free -VPKEDIT_API VPKEdit_VirtualEntryHandleArray_t vpkedit_get_virtual_entries(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API size_t vpkedit_get_filepath(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_truncated_filepath(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_filename(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_truncated_filename(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_filestem(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_truncated_filestem(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_get_supported_entry_attributes(VPKEdit_PackFileHandle_t handle, VPKEdit_Attribute_e* buffer, size_t bufferLen); - -VPKEDIT_API size_t vpkedit_to_string(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen); - -VPKEDIT_API void vpkedit_close(VPKEdit_PackFileHandle_t* handle); - -// REQUIRES MANUAL FREE: vpkedit_string_free -VPKEDIT_API VPKEdit_String_t vpkedit_escape_entry_path(const char* path); - -// REQUIRES MANUAL FREE: vpkedit_string_array_free -VPKEDIT_API VPKEdit_StringArray_t vpkedit_get_supported_file_types(); diff --git a/include/vpkeditc/PackFileType.h b/include/vpkeditc/PackFileType.h deleted file mode 100644 index d72671c2..00000000 --- a/include/vpkeditc/PackFileType.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - VPKEDIT_PACK_FILE_TYPE_UNKNOWN, - VPKEDIT_PACK_FILE_TYPE_BSP, - VPKEDIT_PACK_FILE_TYPE_FPX, - VPKEDIT_PACK_FILE_TYPE_GCF, - VPKEDIT_PACK_FILE_TYPE_GMA, - VPKEDIT_PACK_FILE_TYPE_GRP, - VPKEDIT_PACK_FILE_TYPE_PAK, - VPKEDIT_PACK_FILE_TYPE_PCK, - VPKEDIT_PACK_FILE_TYPE_VPK, - VPKEDIT_PACK_FILE_TYPE_ZIP, -} VPKEdit_PackFileType_e; - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/include/vpkeditc/String.h b/include/vpkeditc/String.h deleted file mode 100644 index c98bee5a..00000000 --- a/include/vpkeditc/String.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "API.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int64_t size; - char* data; -} VPKEdit_String_t; - -#define VPKEDIT_STRING_INVALID (VPKEdit_String_t{.size = -1, .data = NULL}) - -typedef struct { - int64_t size; - char** data; -} VPKEdit_StringArray_t; - -#define VPKEDIT_STRING_ARRAY_INVALID (VPKEdit_StringArray_t{.size = -1, .data = NULL}) - -#ifdef __cplusplus -} // extern "C" -#endif - -VPKEDIT_API VPKEdit_String_t vpkedit_string_new(size_t size); - -VPKEDIT_API void vpkedit_string_free(VPKEdit_String_t* str); - -VPKEDIT_API VPKEdit_StringArray_t vpkedit_string_array_new(size_t size); - -VPKEDIT_API void vpkedit_string_array_free(VPKEdit_StringArray_t* array); diff --git a/include/vpkeditc/Version.h.in b/include/vpkeditc/Version.h.in deleted file mode 100644 index 23b75dba..00000000 --- a/include/vpkeditc/Version.h.in +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#define VPKEDIT_PROJECT_NAME = "${PROJECT_NAME}"; -#define VPKEDIT_PROJECT_NAME_PRETTY = "${PROJECT_NAME_PRETTY}"; -#define VPKEDIT_PROJECT_VERSION = "${PROJECT_VERSION}"; -#define VPKEDIT_PROJECT_VERSION_PRETTY = "${PROJECT_VERSION_PRETTY}"; -#define VPKEDIT_PROJECT_HOMEPAGE = "${PROJECT_HOMEPAGE_URL}"; -#define VPKEDIT_PROJECT_HOMEPAGE_API = "${PROJECT_HOMEPAGE_URL_API}"; -#define VPKEDIT_ORGANIZATION_NAME = "${PROJECT_ORGANIZATION_NAME}"; -#define VPKEDIT_PROJECT_TITLE = "${PROJECT_NAME_PRETTY} v${PROJECT_VERSION_PRETTY}"; diff --git a/include/vpkeditc/format/BSP.h b/include/vpkeditc/format/BSP.h deleted file mode 100644 index 7ea2ac07..00000000 --- a/include/vpkeditc/format/BSP.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_bsp_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_bsp_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/FPX.h b/include/vpkeditc/format/FPX.h deleted file mode 100644 index c8dbaef0..00000000 --- a/include/vpkeditc/format/FPX.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_fpx_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_fpx_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/GCF.h b/include/vpkeditc/format/GCF.h deleted file mode 100644 index 4e52f4d1..00000000 --- a/include/vpkeditc/format/GCF.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gcf_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gcf_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/GMA.h b/include/vpkeditc/format/GMA.h deleted file mode 100644 index 506a77fe..00000000 --- a/include/vpkeditc/format/GMA.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gma_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gma_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/GRP.h b/include/vpkeditc/format/GRP.h deleted file mode 100644 index e824611a..00000000 --- a/include/vpkeditc/format/GRP.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_grp_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_grp_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/PAK.h b/include/vpkeditc/format/PAK.h deleted file mode 100644 index 41f81458..00000000 --- a/include/vpkeditc/format/PAK.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pak_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pak_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/PCK.h b/include/vpkeditc/format/PCK.h deleted file mode 100644 index 057b83f9..00000000 --- a/include/vpkeditc/format/PCK.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pck_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pck_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/include/vpkeditc/format/VPK.h b/include/vpkeditc/format/VPK.h deleted file mode 100644 index 4cb1c5e2..00000000 --- a/include/vpkeditc/format/VPK.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_empty(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_empty_with_options(const char* path, VPKEdit_PackFileOptions_t options); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_from_directory(const char* vpkPath, const char* contentPath, bool saveToDir); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_from_directory_with_options(const char* vpkPath, const char* contentPath, bool saveToDir, VPKEdit_PackFileOptions_t options); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); - -VPKEDIT_API bool vpkedit_vpk_generate_keypair_files(const char* path); - -VPKEDIT_API bool vpkedit_vpk_sign_from_file(VPKEdit_PackFileHandle_t handle, const char* filename); - -VPKEDIT_API bool vpkedit_vpk_sign_from_mem(VPKEdit_PackFileHandle_t handle, const unsigned char* privateKeyBuffer, size_t privateKeyLen, const unsigned char* publicKeyBuffer, size_t publicKeyLen); - -VPKEDIT_API uint32_t vpkedit_vpk_get_version(VPKEdit_PackFileHandle_t handle); - -VPKEDIT_API void vpkedit_vpk_set_version(VPKEdit_PackFileHandle_t handle, uint32_t version); diff --git a/include/vpkeditc/format/ZIP.h b/include/vpkeditc/format/ZIP.h deleted file mode 100644 index e3f227f6..00000000 --- a/include/vpkeditc/format/ZIP.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../PackFile.h" - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_zip_open(const char* path); - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_zip_open_with_options(const char* path, VPKEdit_PackFileOptions_t options); diff --git a/src/cli/Main.cpp b/src/cli/Main.cpp index 66b54a72..e0ce76d3 100644 --- a/src/cli/Main.cpp +++ b/src/cli/Main.cpp @@ -4,13 +4,12 @@ #include #include -#include -#include -#include +#include + +#include using namespace std::literals::string_literals; -using namespace vpkedit::detail; -using namespace vpkedit; +using namespace vpkpp; #define ARG_S(name, short_, long_) \ constexpr std::string_view ARG_##name##_SHORT = short_; \ diff --git a/src/cli/_cli.cmake b/src/cli/_cli.cmake index 93d5d6e7..9108cdc0 100644 --- a/src/cli/_cli.cmake +++ b/src/cli/_cli.cmake @@ -15,6 +15,10 @@ vpkedit_configure_target(${PROJECT_NAME}cli) target_link_libraries( ${PROJECT_NAME}cli PUBLIC - lib${PROJECT_NAME} argparse::argparse - indicators::indicators) + indicators::indicators + vpkpp) + +target_include_directories( + ${PROJECT_NAME}cli PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/src/shared/config") diff --git a/src/gui/EntryTree.cpp b/src/gui/EntryTree.cpp index 68e4b6c5..dc749028 100644 --- a/src/gui/EntryTree.cpp +++ b/src/gui/EntryTree.cpp @@ -29,7 +29,7 @@ #include #endif -using namespace vpkedit; +using namespace vpkpp; namespace { diff --git a/src/gui/EntryTree.h b/src/gui/EntryTree.h index d8d23d5d..de2a8780 100644 --- a/src/gui/EntryTree.h +++ b/src/gui/EntryTree.h @@ -4,7 +4,7 @@ #include -#include +#include class QKeyEvent; class QMouseEvent; @@ -21,7 +21,7 @@ class EntryTree : public QTreeWidget { public: explicit EntryTree(Window* window_, QWidget* parent = nullptr); - void loadPackFile(vpkedit::PackFile& packFile, QProgressBar* progressBar, const std::function& finishCallback); + void loadPackFile(vpkpp::PackFile& packFile, QProgressBar* progressBar, const std::function& finishCallback); [[nodiscard]] bool hasEntry(const QString& path) const; @@ -81,7 +81,7 @@ class LoadPackFileWorker : public QObject { public: LoadPackFileWorker() = default; - void run(EntryTree* tree, const vpkedit::PackFile& packFile); + void run(EntryTree* tree, const vpkpp::PackFile& packFile); signals: void progressUpdated(int value); diff --git a/src/gui/FileViewer.cpp b/src/gui/FileViewer.cpp index 8924adb1..094e5e16 100644 --- a/src/gui/FileViewer.cpp +++ b/src/gui/FileViewer.cpp @@ -19,7 +19,7 @@ #include "utility/ThemedIcon.h" #include "Window.h" -using namespace vpkedit; +using namespace vpkpp; static QString stripSlashes(QString input) { while (input.startsWith('/')) { @@ -318,7 +318,7 @@ void FileViewer::displayDir(const QString& path, const QList& subfolder this->showPreview(); } -void FileViewer::addEntry(const vpkedit::PackFile& packFile, const QString& path) { +void FileViewer::addEntry(const PackFile& packFile, const QString& path) { this->getPreview()->addEntry(packFile, path); } diff --git a/src/gui/FileViewer.h b/src/gui/FileViewer.h index ed1489c2..dcc49b4a 100644 --- a/src/gui/FileViewer.h +++ b/src/gui/FileViewer.h @@ -9,11 +9,11 @@ class QAction; class QLineEdit; class QToolButton; -namespace vpkedit { +namespace vpkpp { class PackFile; -} // namespace vpkedit +} // namespace vpkpp class Window; @@ -74,11 +74,11 @@ class FileViewer : public QWidget { void requestNavigateNext(); - void displayEntry(const QString& path, const vpkedit::PackFile& packFile); + void displayEntry(const QString& path, const vpkpp::PackFile& packFile); - void displayDir(const QString& path, const QList& subfolders, const QList& entryPaths, const vpkedit::PackFile& packFile); + void displayDir(const QString& path, const QList& subfolders, const QList& entryPaths, const vpkpp::PackFile& packFile); - void addEntry(const vpkedit::PackFile& packFile, const QString& path); + void addEntry(const vpkpp::PackFile& packFile, const QString& path); void removeFile(const QString& path); diff --git a/src/gui/Main.cpp b/src/gui/Main.cpp index f4dedaf4..bdcad31e 100644 --- a/src/gui/Main.cpp +++ b/src/gui/Main.cpp @@ -5,13 +5,11 @@ #include #include -#include +#include #include "utility/Options.h" #include "Window.h" -using namespace vpkedit; - int main(int argc, char** argv) { QSurfaceFormat format; format.setDepthBufferSize(24); diff --git a/src/gui/Window.cpp b/src/gui/Window.cpp index 7055a03e..40d8c7e6 100644 --- a/src/gui/Window.cpp +++ b/src/gui/Window.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -29,12 +29,13 @@ #include #include #include -#include -#include +#include +#include #ifdef VPKEDIT_ZIP_COMPRESSION -#include +#include #endif -#include + +#include #include "dialogs/ControlsDialog.h" #include "dialogs/EntryOptionsDialog.h" @@ -49,7 +50,9 @@ #include "EntryTree.h" #include "FileViewer.h" -using namespace vpkedit; +using namespace kvpp; +using namespace steampp; +using namespace vpkpp; Window::Window(QWidget* parent) : QMainWindow(parent) @@ -1435,23 +1438,23 @@ void ScanSteamGamesWorker::run() { return; } - SAPP sapp; - if (!sapp) { + Steam steam; + if (!steam) { emit this->taskFinished(sourceGames); return; } // Add Steam games - for (auto appID : sapp.getInstalledApps()) { - if (!sapp.isAppUsingSourceEngine(appID) && !sapp.isAppUsingSource2Engine(appID)) { + for (auto appID : steam.getInstalledApps()) { + if (!steam.isAppUsingSourceEngine(appID) && !steam.isAppUsingSource2Engine(appID)) { continue; } - auto iconPath = sapp.getAppIconPath(appID); - sourceGames.emplace_back(sapp.getAppName(appID).data(), iconPath.empty() ? QIcon(":/icons/missing_app.png") : QIcon(iconPath.c_str()), sapp.getAppInstallDir(appID).c_str()); + auto iconPath = steam.getAppIconPath(appID); + sourceGames.emplace_back(steam.getAppName(appID).data(), iconPath.empty() ? QIcon(":/icons/missing_app.png") : QIcon(iconPath.c_str()), steam.getAppInstallDir(appID).c_str()); } // Add mods in the sourcemods directory - for (const auto& modDir : std::filesystem::directory_iterator{sapp.getSteamSourceModDir()}) { + for (const auto& modDir : std::filesystem::directory_iterator{steam.getSourceModDir()}) { if (!modDir.is_directory()) { continue; } @@ -1467,29 +1470,29 @@ void ScanSteamGamesWorker::run() { gameInfoData.resize(gameInfoSize); gameInfoFile.read(gameInfoData.data(), static_cast(gameInfoSize)); - KeyValueRoot gameInfoRoot{gameInfoData.c_str()}; - if (!gameInfoRoot.IsValid()) { + KV1 gameInfoRoot{gameInfoData}; + if (gameInfoRoot.isInvalid()) { continue; } - auto& gameInfo = gameInfoRoot.Get("GameInfo"); - if (!gameInfo.IsValid()) { + const auto& gameInfo = gameInfoRoot["GameInfo"]; + if (gameInfo.isInvalid()) { continue; } - auto& gameInfoName = gameInfo.Get("game"); - auto& gameInfoIconPath = gameInfo.Get("icon"); + const auto& gameInfoName = gameInfo["game"]; + const auto& gameInfoIconPath = gameInfo["icon"]; std::string modName; - if (gameInfoName.IsValid()) { - modName = gameInfoName.Value().string; + if (!gameInfoName.isInvalid()) { + modName = gameInfoName.getValue(); } else { modName = std::filesystem::path{gameInfoPath}.parent_path().filename().string(); } std::string modIconPath; - if (gameInfoIconPath.IsValid()) { - if (auto modIconBigPath = (modDir.path() / (std::string{gameInfoIconPath.Value().string} + "_big.tga")); std::filesystem::exists(modIconBigPath)) { + if (!gameInfoIconPath.isInvalid()) { + if (auto modIconBigPath = (modDir.path() / (std::string{gameInfoIconPath.getValue()} + "_big.tga")); std::filesystem::exists(modIconBigPath)) { modIconPath = modIconBigPath.string(); - } else if (auto modIconRegularPath = (modDir.path() / (std::string{gameInfoIconPath.Value().string} + ".tga")); std::filesystem::exists(modIconRegularPath)) { + } else if (auto modIconRegularPath = (modDir.path() / (std::string{gameInfoIconPath.getValue()} + ".tga")); std::filesystem::exists(modIconRegularPath)) { modIconPath = modIconRegularPath.string(); } } diff --git a/src/gui/Window.h b/src/gui/Window.h index c7060cf7..947919f5 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -5,7 +5,7 @@ #include #include -#include +#include class QAction; class QLabel; @@ -142,7 +142,7 @@ class Window : public QMainWindow { QThread* extractPackFileWorkerThread = nullptr; QThread* scanSteamGamesWorkerThread = nullptr; - std::unique_ptr packFile; + std::unique_ptr packFile; bool modified; bool dropEnabled; @@ -159,7 +159,7 @@ class Window : public QMainWindow { void checkForUpdatesReply(QNetworkReply* reply); - bool writeEntryToFile(const QString& path, const vpkedit::Entry& entry); + bool writeEntryToFile(const QString& path, const vpkpp::Entry& entry); void resetStatusBar(); }; diff --git a/src/gui/_gui.cmake b/src/gui/_gui.cmake index 6d61925a..0ab29e1e 100644 --- a/src/gui/_gui.cmake +++ b/src/gui/_gui.cmake @@ -1,17 +1,6 @@ # discord-rpc add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/discord") -# sourcepp -set(SOURCEPP_USE_FGDPP OFF CACHE BOOL "" FORCE) -set(SOURCEPP_USE_VMFPP OFF CACHE BOOL "" FORCE) -add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/sourcepp") - -# SpeedyKeyV -add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/speedykeyv") - -# SAPP -add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/sapp") - # Qt if(WIN32 AND NOT DEFINED QT_BASEDIR) message(FATAL_ERROR "Please define your QT install dir with -DQT_BASEDIR=\"C:/your/qt6/here\"") @@ -124,15 +113,15 @@ qt_add_translations(${PROJECT_NAME} target_link_libraries( ${PROJECT_NAME} PRIVATE - lib${PROJECT_NAME} ${CMAKE_DL_LIBS} discord-rpc dmxpp + kvpp mdlpp + steampp vicepp + vpkpp vtfpp - keyvalues - SAPP Qt::Core Qt::Gui Qt::Widgets @@ -142,6 +131,7 @@ target_link_libraries( target_include_directories( ${PROJECT_NAME} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src/shared/config" "${CMAKE_CURRENT_LIST_DIR}/thirdparty/miniaudio" "${QT_INCLUDE}" "${QT_INCLUDE}/QtCore" diff --git a/src/gui/dialogs/EntryOptionsDialog.cpp b/src/gui/dialogs/EntryOptionsDialog.cpp index e2e38a8a..f1fbabe2 100644 --- a/src/gui/dialogs/EntryOptionsDialog.cpp +++ b/src/gui/dialogs/EntryOptionsDialog.cpp @@ -7,11 +7,11 @@ #include #include #include -#include +#include #include "../utility/Options.h" -using namespace vpkedit; +using namespace vpkpp; EntryOptionsDialog::EntryOptionsDialog(bool edit, bool isDir, const QString& prefilledPath, PackFileType type, EntryOptions options, QWidget* parent) : QDialog(parent) { @@ -100,7 +100,7 @@ EntryOptions EntryOptionsDialog::getEntryOptions() const { }; } -std::optional> EntryOptionsDialog::getEntryOptions(bool edit, bool isDir, const QString& prefilledPath, vpkedit::PackFileType type, vpkedit::EntryOptions options, QWidget* parent) { +std::optional> EntryOptionsDialog::getEntryOptions(bool edit, bool isDir, const QString& prefilledPath, PackFileType type, EntryOptions options, QWidget* parent) { auto* dialog = new EntryOptionsDialog(edit, isDir, prefilledPath, type, options, parent); int ret = dialog->exec(); dialog->deleteLater(); diff --git a/src/gui/dialogs/EntryOptionsDialog.h b/src/gui/dialogs/EntryOptionsDialog.h index aade7f5a..961a980f 100644 --- a/src/gui/dialogs/EntryOptionsDialog.h +++ b/src/gui/dialogs/EntryOptionsDialog.h @@ -5,8 +5,8 @@ #include #include -#include -#include +#include +#include class QCheckBox; class QLineEdit; @@ -16,11 +16,11 @@ class EntryOptionsDialog : public QDialog { Q_OBJECT; public: - explicit EntryOptionsDialog(bool edit, bool isDir, const QString& prefilledPath, vpkedit::PackFileType type, vpkedit::EntryOptions options, QWidget* parent = nullptr); + explicit EntryOptionsDialog(bool edit, bool isDir, const QString& prefilledPath, vpkpp::PackFileType type, vpkpp::EntryOptions options, QWidget* parent = nullptr); - [[nodiscard]] vpkedit::EntryOptions getEntryOptions() const; + [[nodiscard]] vpkpp::EntryOptions getEntryOptions() const; - static std::optional> getEntryOptions(bool edit, bool isDir, const QString& prefilledPath, vpkedit::PackFileType type, vpkedit::EntryOptions options, QWidget* parent = nullptr); + static std::optional> getEntryOptions(bool edit, bool isDir, const QString& prefilledPath, vpkpp::PackFileType type, vpkpp::EntryOptions options, QWidget* parent = nullptr); private: QLineEdit* path; diff --git a/src/gui/dialogs/NewUpdateDialog.cpp b/src/gui/dialogs/NewUpdateDialog.cpp index 8613a4a1..6902dba6 100644 --- a/src/gui/dialogs/NewUpdateDialog.cpp +++ b/src/gui/dialogs/NewUpdateDialog.cpp @@ -2,11 +2,10 @@ #include #include -#include -#include "../utility/Options.h" +#include -using namespace vpkedit; +#include "../utility/Options.h" NewUpdateDialog::NewUpdateDialog(const QString& releaseLink, const QString& version, const QString& details, QWidget* parent) : QMessageBox(parent) { diff --git a/src/gui/dialogs/NewVPKOptionsDialog.cpp b/src/gui/dialogs/NewVPKOptionsDialog.cpp index 15621e0a..0bd371c1 100644 --- a/src/gui/dialogs/NewVPKOptionsDialog.cpp +++ b/src/gui/dialogs/NewVPKOptionsDialog.cpp @@ -6,11 +6,11 @@ #include #include #include -#include +#include #include "../utility/Options.h" -using namespace vpkedit; +using namespace vpkpp; NewVPKOptionsDialog::NewVPKOptionsDialog(bool fromDirectory, PackFileOptions options, bool singleFile, QWidget* parent) : QDialog(parent) { diff --git a/src/gui/dialogs/NewVPKOptionsDialog.h b/src/gui/dialogs/NewVPKOptionsDialog.h index a7ab5444..c5e90d46 100644 --- a/src/gui/dialogs/NewVPKOptionsDialog.h +++ b/src/gui/dialogs/NewVPKOptionsDialog.h @@ -4,7 +4,7 @@ #include #include -#include +#include class QCheckBox; class QComboBox; @@ -14,11 +14,11 @@ class NewVPKOptionsDialog : public QDialog { Q_OBJECT; public: - explicit NewVPKOptionsDialog(bool fromDirectory, vpkedit::PackFileOptions options, bool singleFile, QWidget* parent = nullptr); + explicit NewVPKOptionsDialog(bool fromDirectory, vpkpp::PackFileOptions options, bool singleFile, QWidget* parent = nullptr); - [[nodiscard]] vpkedit::PackFileOptions getPackFileOptions() const; + [[nodiscard]] vpkpp::PackFileOptions getPackFileOptions() const; - static std::optional> getNewVPKOptions(bool fromDirectory, vpkedit::PackFileOptions options, bool singleFile, QWidget* parent = nullptr); + static std::optional> getNewVPKOptions(bool fromDirectory, vpkpp::PackFileOptions options, bool singleFile, QWidget* parent = nullptr); private: QComboBox* version; diff --git a/src/gui/dialogs/PackFileOptionsDialog.cpp b/src/gui/dialogs/PackFileOptionsDialog.cpp index f90f903c..96724baf 100644 --- a/src/gui/dialogs/PackFileOptionsDialog.cpp +++ b/src/gui/dialogs/PackFileOptionsDialog.cpp @@ -5,9 +5,9 @@ #include #include #include -#include +#include -using namespace vpkedit; +using namespace vpkpp; PackFileOptionsDialog::PackFileOptionsDialog(PackFileType type, PackFileOptions options_, QWidget* parent) : QDialog(parent) @@ -55,7 +55,7 @@ PackFileOptions PackFileOptionsDialog::getPackFileOptions() { #ifdef VPKEDIT_ZIP_COMPRESSION this->zip_useCompression ? MZ_COMPRESS_METHOD_LZMA : #endif - MZ_COMPRESS_METHOD_STORE; + 0; // MZ_COMPRESS_METHOD_STORE return this->options; } diff --git a/src/gui/dialogs/PackFileOptionsDialog.h b/src/gui/dialogs/PackFileOptionsDialog.h index adc04d1d..83a0d78f 100644 --- a/src/gui/dialogs/PackFileOptionsDialog.h +++ b/src/gui/dialogs/PackFileOptionsDialog.h @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include class QCheckBox; class QComboBox; @@ -14,14 +14,14 @@ class PackFileOptionsDialog : public QDialog { Q_OBJECT; public: - explicit PackFileOptionsDialog(vpkedit::PackFileType type, vpkedit::PackFileOptions options_, QWidget* parent = nullptr); + explicit PackFileOptionsDialog(vpkpp::PackFileType type, vpkpp::PackFileOptions options_, QWidget* parent = nullptr); - [[nodiscard]] vpkedit::PackFileOptions getPackFileOptions(); + [[nodiscard]] vpkpp::PackFileOptions getPackFileOptions(); - static std::optional getPackFileOptions(vpkedit::PackFileType type, vpkedit::PackFileOptions options, QWidget* parent = nullptr); + static std::optional getPackFileOptions(vpkpp::PackFileType type, vpkpp::PackFileOptions options, QWidget* parent = nullptr); private: - vpkedit::PackFileOptions options; + vpkpp::PackFileOptions options; QComboBox* vpk_version; #ifdef VPKEDIT_ZIP_COMPRESSION diff --git a/src/gui/dialogs/VerifyChecksumsDialog.cpp b/src/gui/dialogs/VerifyChecksumsDialog.cpp index a9a06383..5d0e251a 100644 --- a/src/gui/dialogs/VerifyChecksumsDialog.cpp +++ b/src/gui/dialogs/VerifyChecksumsDialog.cpp @@ -1,8 +1,8 @@ #include "VerifyChecksumsDialog.h" -#include +#include -using namespace vpkedit; +using namespace vpkpp; VerifyChecksumsDialog::VerifyChecksumsDialog(PackFile& packFile, QWidget* parent) : QMessageBox(parent) { diff --git a/src/gui/dialogs/VerifyChecksumsDialog.h b/src/gui/dialogs/VerifyChecksumsDialog.h index 01893e10..adfd39c0 100644 --- a/src/gui/dialogs/VerifyChecksumsDialog.h +++ b/src/gui/dialogs/VerifyChecksumsDialog.h @@ -2,17 +2,17 @@ #include -namespace vpkedit { +namespace vpkpp { class PackFile; -} // namespace vpkedit +} // namespace vpkpp class VerifyChecksumsDialog : public QMessageBox { Q_OBJECT; public: - explicit VerifyChecksumsDialog(vpkedit::PackFile& packFile, QWidget* parent = nullptr); + explicit VerifyChecksumsDialog(vpkpp::PackFile& packFile, QWidget* parent = nullptr); - static void showDialog(vpkedit::PackFile& packFile, QWidget* parent = nullptr); + static void showDialog(vpkpp::PackFile& packFile, QWidget* parent = nullptr); }; diff --git a/src/gui/dialogs/VerifySignatureDialog.cpp b/src/gui/dialogs/VerifySignatureDialog.cpp index 5529aa33..2fc46f0e 100644 --- a/src/gui/dialogs/VerifySignatureDialog.cpp +++ b/src/gui/dialogs/VerifySignatureDialog.cpp @@ -1,8 +1,8 @@ #include "VerifySignatureDialog.h" -#include +#include -using namespace vpkedit; +using namespace vpkpp; VerifySignatureDialog::VerifySignatureDialog(PackFile& packFile, QWidget* parent) : QMessageBox(parent) { diff --git a/src/gui/dialogs/VerifySignatureDialog.h b/src/gui/dialogs/VerifySignatureDialog.h index a8ddfb06..56f42938 100644 --- a/src/gui/dialogs/VerifySignatureDialog.h +++ b/src/gui/dialogs/VerifySignatureDialog.h @@ -2,17 +2,17 @@ #include -namespace vpkedit { +namespace vpkpp { class PackFile; -} // namespace vpkedit +} // namespace vpkpp class VerifySignatureDialog : public QMessageBox { Q_OBJECT; public: - explicit VerifySignatureDialog(vpkedit::PackFile& packFile, QWidget* parent = nullptr); + explicit VerifySignatureDialog(vpkpp::PackFile& packFile, QWidget* parent = nullptr); - static void showDialog(vpkedit::PackFile& packFile, QWidget* parent = nullptr); + static void showDialog(vpkpp::PackFile& packFile, QWidget* parent = nullptr); }; diff --git a/src/gui/previews/DirPreview.cpp b/src/gui/previews/DirPreview.cpp index aa8c7247..9088f446 100644 --- a/src/gui/previews/DirPreview.cpp +++ b/src/gui/previews/DirPreview.cpp @@ -7,13 +7,13 @@ #include #include #include -#include +#include #include "../EntryContextMenuData.h" #include "../FileViewer.h" #include "../Window.h" -using namespace vpkedit; +using namespace vpkpp; constexpr int KB_SIZE = 1024; diff --git a/src/gui/previews/DirPreview.h b/src/gui/previews/DirPreview.h index cb56ceb5..e9396e6e 100644 --- a/src/gui/previews/DirPreview.h +++ b/src/gui/previews/DirPreview.h @@ -2,11 +2,11 @@ #include -namespace vpkedit { +namespace vpkpp { class PackFile; -} // namespace vpkedit +} // namespace vpkpp class QKeyEvent; class QMouseEvent; @@ -20,9 +20,9 @@ class DirPreview : public QTableWidget { public: DirPreview(FileViewer* fileViewer_, Window* window_, QWidget* parent = nullptr); - void setPath(const QString& currentDir, const QList& subfolders, const QList& entryPaths, const vpkedit::PackFile& packFile); + void setPath(const QString& currentDir, const QList& subfolders, const QList& entryPaths, const vpkpp::PackFile& packFile); - void addEntry(const vpkedit::PackFile& packFile, const QString& path); + void addEntry(const vpkpp::PackFile& packFile, const QString& path); void removeFile(const QString& path); @@ -40,7 +40,7 @@ class DirPreview : public QTableWidget { void mouseMoveEvent(QMouseEvent* event) override; private: - void addRowForFile(const vpkedit::PackFile& packFile, const QString& path); + void addRowForFile(const vpkpp::PackFile& packFile, const QString& path); void addRowForDir(const QString& name); diff --git a/src/gui/previews/EmptyPreview.cpp b/src/gui/previews/EmptyPreview.cpp index b87c164a..38fda104 100644 --- a/src/gui/previews/EmptyPreview.cpp +++ b/src/gui/previews/EmptyPreview.cpp @@ -1,8 +1,6 @@ #include "EmptyPreview.h" -#include - -using namespace vpkedit; +#include EmptyPreview::EmptyPreview(QWidget* parent) : InfoPreview({":/logo.png"}, PROJECT_TITLE.data(), parent) { diff --git a/src/gui/previews/MDLPreview.cpp b/src/gui/previews/MDLPreview.cpp index 3f722d51..74315f98 100644 --- a/src/gui/previews/MDLPreview.cpp +++ b/src/gui/previews/MDLPreview.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -19,40 +19,53 @@ #include #include #include -#include -#include +#include +#include #include #include "../utility/ThemedIcon.h" #include "../FileViewer.h" #include "../Window.h" +using namespace kvpp; using namespace mdlpp; +using namespace sourcepp; using namespace std::literals; -using namespace vpkedit::detail; -using namespace vpkedit; +using namespace vpkpp; using namespace vtfpp; namespace { std::unique_ptr getTextureDataForMaterial(const PackFile& packFile, const std::string& materialPath) { auto materialEntry = packFile.findEntry(materialPath); - if (!materialEntry) return nullptr; + if (!materialEntry) { + return nullptr; + } auto materialFile = packFile.readEntryText(*materialEntry); - if (!materialFile) return nullptr; + if (!materialFile) { + return nullptr; + } - KeyValueRoot materialKV; - if (materialKV.Parse(materialFile->c_str()) != KeyValueErrorCode::NONE || !materialKV.HasChildren()) return nullptr; + KV1 materialKV{*materialFile}; + if (materialKV.getChildCount() == 0) { + return nullptr; + } - auto& baseTexturePathKV = materialKV.At(0).Get("$basetexture"); - if (!baseTexturePathKV.IsValid()) return nullptr; + auto& baseTexturePathKV = materialKV[0]["$basetexture"]; + if (baseTexturePathKV.isInvalid()) { + return nullptr; + } - auto textureEntry = packFile.findEntry("materials/" + std::string{baseTexturePathKV.Value().string, baseTexturePathKV.Value().length} + ".vtf"); - if (!textureEntry) return nullptr; + auto textureEntry = packFile.findEntry("materials/" + std::string{baseTexturePathKV.getValue()} + ".vtf"); + if (!textureEntry) { + return nullptr; + } auto textureFile = packFile.readEntry(*textureEntry); - if (!textureFile) return nullptr; + if (!textureFile) { + return nullptr; + } VTF vtf{*textureFile}; return std::make_unique( @@ -654,7 +667,7 @@ void MDLPreview::setMesh(const QString& path, const PackFile& packFile) const { bool foundMaterial = false; for (int materialDirIndex = 0; materialDirIndex < mdlParser.mdl.materialDirectories.size(); materialDirIndex++) { std::string vmtPath = "materials/"s + mdlParser.mdl.materialDirectories.at(materialDirIndex) + mdlParser.mdl.materials.at(materialIndex).name + ".vmt"; - ::normalizeSlashes(vmtPath); + string::normalizeSlashes(vmtPath); if (auto data = getTextureDataForMaterial(packFile, vmtPath)) { vtfs.push_back(std::move(data)); diff --git a/src/gui/previews/MDLPreview.h b/src/gui/previews/MDLPreview.h index a7c0ce73..96d6145a 100644 --- a/src/gui/previews/MDLPreview.h +++ b/src/gui/previews/MDLPreview.h @@ -12,11 +12,11 @@ #include #include -namespace vpkedit { +namespace vpkpp { class PackFile; -} // namespace vpkedit +} // namespace vpkpp class QCheckBox; class QKeyEvent; @@ -177,7 +177,7 @@ class MDLPreview : public QWidget { explicit MDLPreview(FileViewer* fileViewer_, Window* window, QWidget* parent = nullptr); - void setMesh(const QString& path, const vpkedit::PackFile& packFile) const; + void setMesh(const QString& path, const vpkpp::PackFile& packFile) const; private: void setShadingMode(MDLShadingMode mode) const; diff --git a/src/gui/thirdparty/sapp b/src/gui/thirdparty/sapp deleted file mode 160000 index 1e510b10..00000000 --- a/src/gui/thirdparty/sapp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1e510b10c863dd803cdaceb87d443e472d229629 diff --git a/src/gui/thirdparty/sourcepp b/src/gui/thirdparty/sourcepp deleted file mode 160000 index 19fcbdec..00000000 --- a/src/gui/thirdparty/sourcepp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 19fcbdecb7e3f93afe74215b851158cd2b575535 diff --git a/src/gui/thirdparty/speedykeyv b/src/gui/thirdparty/speedykeyv deleted file mode 160000 index e4a1535c..00000000 --- a/src/gui/thirdparty/speedykeyv +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e4a1535c42dce9980ab874d3a797b6d283a06a5a diff --git a/src/installer/_installer.cmake b/src/installer/_installer.cmake index 5d617c97..8596598a 100644 --- a/src/installer/_installer.cmake +++ b/src/installer/_installer.cmake @@ -1,11 +1,9 @@ # Set up install rules -install(TARGETS ${PROJECT_NAME} +install(TARGETS ${PROJECT_NAME}cli DESTINATION .) -if(VPKEDIT_BUILD_CLI) - install(TARGETS ${PROJECT_NAME}cli - DESTINATION .) -endif() +install(TARGETS ${PROJECT_NAME} + DESTINATION .) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/CREDITS.md" @@ -162,15 +160,12 @@ else() set(CPACK_DEBIAN_COMPRESSION_TYPE "zstd") # Add symlinks so it can be ran from anywhere - if(VPKEDIT_BUILD_CLI) - install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink /opt/${PROJECT_NAME}/${PROJECT_NAME}cli ${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}cli)") - install(FILES - "${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}cli" - DESTINATION "/usr/bin") - endif() + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink /opt/${PROJECT_NAME}/${PROJECT_NAME}cli ${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}cli)") + install(FILES "${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}cli" + DESTINATION "/usr/bin") + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink /opt/${PROJECT_NAME}/${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME})") - install(FILES - "${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}" + install(FILES "${CMAKE_CURRENT_LIST_DIR}/deb/generated/${PROJECT_NAME}" DESTINATION "/usr/bin") endif() include(CPack) diff --git a/src/lib/Entry.cpp b/src/lib/Entry.cpp deleted file mode 100644 index 23274c84..00000000 --- a/src/lib/Entry.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include - -using namespace vpkedit; - -std::string Entry::getParentPath() const { - return std::filesystem::path{this->path}.parent_path().string(); -} - -std::string Entry::getFilename() const { - return std::filesystem::path{this->path}.filename().string(); -} - -std::string Entry::getStem() const { - return std::filesystem::path{this->path}.stem().string(); -} - -std::string Entry::getExtension() const { - auto ext = std::filesystem::path{this->path}.extension().string(); - if (!ext.empty() && ext.at(0) == '.') { - ext = ext.substr(1); - } - return ext; -} diff --git a/src/lib/PackFile.cpp b/src/lib/PackFile.cpp deleted file mode 100644 index 4d196c40..00000000 --- a/src/lib/PackFile.cpp +++ /dev/null @@ -1,657 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -namespace { - -std::string joinPath(const std::vector& list) { - if (list.empty()) { - return ""; - } - std::string result = list.front(); - for (int i = 1; i < list.size(); ++i) { - result += '/' + list[i]; - } - return result; -} - -std::vector splitPath(const std::string& string) { - std::vector result; - std::stringstream stream{string}; - std::string segment; - while (std::getline(stream, segment, '/')) { - result.push_back(segment); - } - return result; -} - -#ifdef _WIN32 - -void replace(std::string& line, const std::string& oldString, const std::string& newString) { - const auto oldSize = oldString.length(); - if (oldSize > line.length()) { - return; - } - - const auto newSize = newString.length(); - std::size_t pos = 0; - while (true) { - pos = line.find(oldString, pos); - if (pos == std::string::npos) { - break; - } - if (oldSize == newSize) { - line.replace(pos, oldSize, newString); - } else { - line.erase(pos, oldSize); - line.insert(pos, newString); - } - pos += newSize; - } -} - -void toUpper(std::string& line) { - for (char& c : line) { - c = static_cast(std::toupper(c)); - } -} - -void fixFilePathForWindows(std::string& filePath) { - // Remove invalid characters - ::replace(filePath, "<", "_LT_"); - ::replace(filePath, "<", "_LT_"); - ::replace(filePath, ">", "_GT_"); - ::replace(filePath, ":", "_COLON_"); - ::replace(filePath, "\"", "_QUOT_"); - ::replace(filePath, "|", "_BAR_"); - ::replace(filePath, "?", "_QMARK_"); - ::replace(filePath, "*", "_AST_"); - - std::filesystem::path path{filePath}; - auto filename = path.filename().string(); - auto extension = path.extension().string(); - auto stem = path.stem().string(); - ::toUpper(stem); - - // Replace bad filenames - if (stem == "CON") { - filename = "_CON_" + extension; - } else if (stem == "PRN") { - filename = "_PRN_" + extension; - } else if (stem == "AUX") { - filename = "_AUX_" + extension; - } else if (stem == "NUL") { - filename = "_NUL_" + extension; - } else if (stem.starts_with("COM") && stem.length() == 4 && std::isdigit(stem[3]) && stem[3] != '0') { - filename = "_COM"; - filename += stem[3]; - filename += '_'; - filename += extension; - } else if (stem.starts_with("LPT") && stem.length() == 4 && std::isdigit(stem[3]) && stem[3] != '0') { - filename = "_LPT"; - filename += stem[3]; - filename += '_'; - filename += extension; - } - - // Files cannot end with a period - weird - if (extension == ".") { - filename.pop_back(); - } - - filePath = (path.parent_path() / filename).string(); -} - -#endif - -} // namespace - -PackFile::PackFile(std::string fullFilePath_, PackFileOptions options_) - : fullFilePath(std::move(fullFilePath_)) - , options(options_) {} - -std::unique_ptr PackFile::open(const std::string& path, PackFileOptions options, const Callback& callback) { - auto extension = std::filesystem::path{path}.extension().string(); - ::toLowerCase(extension); - const auto& registry = PackFile::getOpenExtensionRegistry(); - if (registry.contains(extension)) { - for (const auto& func : registry.at(extension)) { - if (auto packFile = func(path, options, callback)) { - return packFile; - } - } - } - return nullptr; -} - -PackFileType PackFile::getType() const { - return this->type; -} - -PackFileOptions PackFile::getOptions() const { - return this->options; -} - -std::vector PackFile::verifyEntryChecksums() const { - return {}; -} - -bool PackFile::hasFileChecksum() const { - return false; -} - -bool PackFile::verifyFileChecksum() const { - return true; -} - -bool PackFile::hasFileSignature() const { - return false; -} - -bool PackFile::verifyFileSignature() const { - return true; -} - -std::optional PackFile::findEntry(const std::string& filename_, bool includeUnbaked) const { - auto filename = filename_; - ::normalizeSlashes(filename); - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - if (this->entries.contains(dir)) { - for (const Entry& entry : this->entries.at(dir)) { - if (entry.path == filename) { - return entry; - } - } - } - if (includeUnbaked && this->unbakedEntries.contains(dir)) { - for (const Entry& unbakedEntry : this->unbakedEntries.at(dir)) { - if (unbakedEntry.path == filename) { - return unbakedEntry; - } - } - } - return std::nullopt; -} - -std::optional PackFile::readEntryText(const Entry& entry) const { - auto bytes = this->readEntry(entry); - if (!bytes) { - return std::nullopt; - } - std::string out; - for (auto byte : *bytes) { - if (byte == static_cast(0)) - break; - out += static_cast(byte); - } - return out; -} - -void PackFile::addEntry(const std::string& filename_, const std::string& pathToFile, EntryOptions options_) { - if (this->isReadOnly()) { - return; - } - - auto buffer = ::readFileData(pathToFile, 0); - - Entry entry{}; - entry.unbaked = true; - entry.unbakedUsingByteBuffer = false; - entry.unbakedData = pathToFile; - - Entry& finalEntry = this->addEntryInternal(entry, filename_, buffer, options_); - finalEntry.unbakedData = pathToFile; -} - -void PackFile::addEntry(const std::string& filename_, std::vector&& buffer, EntryOptions options_) { - if (this->isReadOnly()) { - return; - } - - Entry entry{}; - entry.unbaked = true; - entry.unbakedUsingByteBuffer = true; - - Entry& finalEntry = this->addEntryInternal(entry, filename_, buffer, options_); - finalEntry.unbakedData = std::move(buffer); -} - -void PackFile::addEntry(const std::string& filename_, const std::byte* buffer, std::uint64_t bufferLen, EntryOptions options_) { - std::vector data; - if (buffer && bufferLen > 0) { - data.resize(bufferLen); - std::memcpy(data.data(), buffer, bufferLen); - } - this->addEntry(filename_, std::move(data), options_); -} - -bool PackFile::removeEntry(const std::string& filename_) { - if (this->isReadOnly()) { - return false; - } - - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - // Check unbaked entries first - if (this->unbakedEntries.contains(dir)) { - for (auto& [preexistingDir, unbakedEntryVec] : this->unbakedEntries) { - if (preexistingDir != dir) { - continue; - } - for (auto it = unbakedEntryVec.begin(); it != unbakedEntryVec.end(); ++it) { - if (it->path == filename) { - unbakedEntryVec.erase(it); - return true; - } - } - } - } - - // If it's not in regular entries either you can't remove it! - if (!this->entries.contains(dir)) { - return false; - } - - for (auto it = this->entries.at(dir).begin(); it != this->entries.at(dir).end(); ++it) { - if (it->path == filename) { - this->entries.at(dir).erase(it); - return true; - } - } - return false; -} - -bool PackFile::extractEntry(const Entry& entry, const std::string& filePath) const { - if (filePath.empty()) { - return false; - } - - auto data = this->readEntry(entry); - if (!data) { - return false; - } - - FileStream stream{filePath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - if (!stream) { - return false; - } - - stream.writeBytes(*data); - return true; -} - -bool PackFile::extractDir(const std::string& dir, const std::string& outputDir) const { - if (dir.empty() || dir == "/") { - return this->extractAll(outputDir, false); - } - - auto testDir = dir; - if (testDir.starts_with('/')) { - testDir = testDir.substr(1); - } - if (testDir.ends_with('/')) { - testDir.pop_back(); - } - auto outputDirPath = std::filesystem::path{outputDir} / std::filesystem::path{testDir}.filename(); - bool noneFailed = true; - for (const auto& [dir_, bakedEntries_] : this->getBakedEntries()) { - if (!dir_.starts_with(testDir)) { - continue; - } - for (const auto& entry : bakedEntries_) { - std::string entryPath = entry.path.substr(testDir.length() + 1); -#ifdef _WIN32 - ::fixFilePathForWindows(entryPath); -#endif - if (!this->extractEntry(entry, (outputDirPath / entryPath).string())) { - noneFailed = false; - } - } - } - for (const auto& [dir_, unbakedEntries_] : this->getUnbakedEntries()) { - if (!dir_.starts_with(testDir)) { - continue; - } - for (const auto& entry : unbakedEntries_) { - std::string entryPath = entry.path.substr(testDir.length() + 1); -#ifdef _WIN32 - ::fixFilePathForWindows(entryPath); -#endif - if (!this->extractEntry(entry, (outputDirPath / entryPath).string())) { - noneFailed = false; - } - } - } - return noneFailed; -} - -bool PackFile::extractAll(const std::string& outputDir, bool createUnderPackFileDir) const { - if (outputDir.empty()) { - return false; - } - - std::filesystem::path outputDirPath{outputDir}; - if (createUnderPackFileDir) { - outputDirPath /= this->getTruncatedFilestem(); - } - bool noneFailed = true; - for (const auto& [dir, bakedEntries_] : this->getBakedEntries()) { - for (const auto& entry : bakedEntries_) { - std::string entryPath = entry.path; -#ifdef _WIN32 - ::fixFilePathForWindows(entryPath); -#endif - if (!this->extractEntry(entry, (outputDirPath / entryPath).string())) { - noneFailed = false; - } - } - } - for (const auto& [dir, unbakedEntries_] : this->getUnbakedEntries()) { - for (const auto& entry : unbakedEntries_) { - std::string entryPath = entry.path; -#ifdef _WIN32 - ::fixFilePathForWindows(entryPath); -#endif - if (!this->extractEntry(entry, (outputDirPath / entryPath).string())) { - noneFailed = false; - } - } - } - return noneFailed; -} - -bool PackFile::extractAll(const std::string& outputDir, const std::function& predicate) const { - if (outputDir.empty() || !predicate) { - return false; - } - - // Get list of paths - std::vector saveEntries; - for (const auto& [dir, bakedEntries_] : this->getBakedEntries()) { - for (const auto& entry : bakedEntries_) { - if (predicate(entry)) { - saveEntries.push_back(entry); - } - } - } - for (const auto& [dir, unbakedEntries_] : this->getUnbakedEntries()) { - for (const auto& entry : unbakedEntries_) { - if (predicate(entry)) { - saveEntries.push_back(entry); - } - } - } - if (saveEntries.empty()) { - return false; - } - - // Strip shared directories until we have a root folder - std::vector rootDirList; - { - std::vector> pathSplits; - for (const auto& entry : saveEntries) { - pathSplits.push_back(::splitPath(entry.path)); - } - while (true) { - bool allTheSame = true; - const std::string& first = pathSplits[0][0]; - for (const auto& path : pathSplits) { - if (path.size() == 1) { - allTheSame = false; - break; - } - if (path[0] != first) { - allTheSame = false; - break; - } - } - if (!allTheSame) { - break; - } - rootDirList.push_back(first); - for (auto& path : pathSplits) { - path.erase(path.begin()); - } - } - } - auto rootDirLen = ::joinPath(rootDirList).length() + 1; - - // Extract - std::filesystem::path outputDirPath{outputDir}; - bool noneFailed = true; - for (const auto& entry : saveEntries) { - std::string entryPath = entry.path.substr(rootDirLen); -#ifdef _WIN32 - ::fixFilePathForWindows(entryPath); -#endif - if (!this->extractEntry(entry, (outputDirPath / entryPath).string())) { - noneFailed = false; - } - } - return noneFailed; -} - -const std::unordered_map>& PackFile::getBakedEntries() const { - return this->entries; -} - -const std::unordered_map>& PackFile::getUnbakedEntries() const { - return this->unbakedEntries; -} - -std::size_t PackFile::getEntryCount(bool includeUnbaked) const { - std::size_t count = 0; - for (const auto& [directory, entries_] : this->entries) { - count += entries_.size(); - } - if (includeUnbaked) { - for (const auto& [directory, entries_] : this->unbakedEntries) { - count += entries_.size(); - } - } - return count; -} - -std::optional> PackFile::readVirtualEntry(const VirtualEntry& entry) const { - return std::nullopt; -} - -bool PackFile::overwriteVirtualEntry(const VirtualEntry& entry, const std::string& pathToFile) { - return this->overwriteVirtualEntry(entry, ::readFileData(pathToFile)); -} - -bool PackFile::overwriteVirtualEntry(const VirtualEntry& entry, const std::vector& data) { - return false; -} - -std::vector PackFile::getVirtualEntries() const { - return {}; -} - -std::string_view PackFile::getFilepath() const { - return this->fullFilePath; -} - -std::string PackFile::getTruncatedFilepath() const { - return (std::filesystem::path{this->fullFilePath}.parent_path() / this->getTruncatedFilestem()).string(); -} - -std::string PackFile::getFilename() const { - return std::filesystem::path{this->fullFilePath}.filename().string(); -} - -std::string PackFile::getTruncatedFilename() const { - const std::filesystem::path path{this->fullFilePath}; - return this->getTruncatedFilestem() + path.extension().string(); -} - -std::string PackFile::getFilestem() const { - return std::filesystem::path{this->fullFilePath}.stem().string(); -} - -std::string PackFile::getTruncatedFilestem() const { - return this->getFilestem(); -} - -std::vector PackFile::getSupportedEntryAttributes() const { - return {}; -} - -PackFile::operator std::string() const { - return this->getFilename(); -} - -std::string PackFile::escapeEntryPath(const std::string& path) { -#ifdef _WIN32 - auto copy = path; - ::fixFilePathForWindows(copy); - return copy; -#else - return path; -#endif -} - -std::vector PackFile::getSupportedFileTypes() { - std::vector out; - for (const auto& [extension, factoryFunctions] : PackFile::getOpenExtensionRegistry()) { - out.push_back(extension); - } - std::sort(out.begin(), out.end()); - return out; -} - -std::vector PackFile::verifyEntryChecksumsUsingCRC32() const { - std::vector out; - for (const auto& [dir, entryList] : this->entries) { - for (const auto& entry : entryList) { - if (!entry.crc32) { - continue; - } - if (auto data = this->readEntry(entry); !data || ::computeCRC32(*data) != entry.crc32) { - out.push_back(entry.path); - } - } - } - for (const auto& [dir, entryList] : this->unbakedEntries) { - for (const auto& entry : entryList) { - if (!entry.crc32) { - continue; - } - if (auto data = this->readEntry(entry); !data || ::computeCRC32(*data) != entry.crc32) { - out.push_back(entry.path); - } - } - } - return out; -} - -std::string PackFile::getBakeOutputDir(const std::string& outputDir) const { - std::string out = outputDir; - if (!out.empty()) { - ::normalizeSlashes(out, false); - } else { - out = this->fullFilePath; - auto lastSlash = out.rfind('/'); - if (lastSlash != std::string::npos) { - out = this->getFilepath().substr(0, lastSlash); - } else { - out = "."; - } - } - return out; -} - -void PackFile::mergeUnbakedEntries() { - for (auto& [dir, unbakedEntriesAndData] : this->unbakedEntries) { - for (Entry& unbakedEntry : unbakedEntriesAndData) { - if (!this->entries.contains(dir)) { - this->entries[dir] = {}; - } - - unbakedEntry.unbaked = false; - - // Clear any data that might be stored in it - unbakedEntry.unbakedUsingByteBuffer = false; - unbakedEntry.unbakedData = ""; - - this->entries.at(dir).push_back(unbakedEntry); - } - } - this->unbakedEntries.clear(); -} - -void PackFile::setFullFilePath(const std::string& outputDir) { - // Assumes PackFile::getBakeOutputDir is the input for outputDir - this->fullFilePath = outputDir + '/' + this->getFilename(); -} - -Entry PackFile::createNewEntry() { - return {}; -} - -const std::variant>& PackFile::getEntryUnbakedData(const Entry& entry) { - return entry.unbakedData; -} - -bool PackFile::isEntryUnbakedUsingByteBuffer(const Entry& entry) { - return entry.unbakedUsingByteBuffer; -} - -std::unordered_map>& PackFile::getOpenExtensionRegistry() { - static std::unordered_map> extensionRegistry; - return extensionRegistry; -} - -const PackFile::FactoryFunction& PackFile::registerOpenExtensionForTypeFactory(std::string_view extension, const FactoryFunction& factory) { - std::string extensionStr{extension}; - auto& registry = PackFile::getOpenExtensionRegistry(); - if (!registry.contains(extensionStr)) { - registry[extensionStr] = {}; - } - registry[extensionStr].push_back(factory); - return factory; -} - -PackFileReadOnly::PackFileReadOnly(std::string fullFilePath_, PackFileOptions options_) - : PackFile(std::move(fullFilePath_), options_) {} - -PackFileReadOnly::operator std::string() const { - return PackFile::operator std::string() + " (Read-Only)"; -} - -Entry& PackFileReadOnly::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - return entry; // Stubbed -} - -bool PackFileReadOnly::bake(const std::string& outputDir_ /*= ""*/, const Callback& callback /*= nullptr*/) { - return false; // Stubbed -} diff --git a/src/lib/_lib.cmake b/src/lib/_lib.cmake deleted file mode 100644 index 1f3fa10d..00000000 --- a/src/lib/_lib.cmake +++ /dev/null @@ -1,90 +0,0 @@ -# For various cryptographic algorithms -if (NOT TARGET cryptopp::cryptopp) - set(CRYPTOPP_BUILD_TESTING OFF CACHE INTERNAL "") - set(CRYPTOPP_INSTALL OFF CACHE INTERNAL "") - add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/cryptopp") -endif() - -# For parsing BSP pack lumps and very basic uncompressed/LZMA-compressed ZIP files -if (NOT TARGET MINIZIP::minizip) - set(MZ_COMPAT OFF CACHE INTERNAL "") - set(MZ_ZLIB OFF CACHE INTERNAL "") - set(MZ_BZIP2 OFF CACHE INTERNAL "") - set(MZ_LZMA OFF CACHE INTERNAL "") - set(MZ_ZSTD OFF CACHE INTERNAL "") - set(MZ_LIBCOMP OFF CACHE INTERNAL "") - set(MZ_PKCRYPT OFF CACHE INTERNAL "") - set(MZ_WZAES OFF CACHE INTERNAL "") - set(MZ_OPENSSL OFF CACHE INTERNAL "") - set(MZ_FETCH_LIBS ON CACHE INTERNAL "") - set(MZ_FORCE_FETCH_LIBS ON CACHE INTERNAL "") - set(SKIP_INSTALL_ALL ON CACHE INTERNAL "") - add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/thirdparty/minizip-ng") -endif() - -# Configure version header -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Version.h.in" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Version.h") - -# Create library -add_library( - lib${PROJECT_NAME} STATIC - - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/Adler32.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/CRC32.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/FileStream.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/MD5.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/Misc.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/detail/RSA.h" - - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/BSP.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/FPX.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/GCF.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/GMA.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/GRP.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/PAK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/PCK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/VPK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/format/ZIP.h" - - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Attribute.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Entry.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Options.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/PackFile.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/PackFileType.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkedit/Version.h" - - "${CMAKE_CURRENT_LIST_DIR}/detail/Adler32.cpp" - "${CMAKE_CURRENT_LIST_DIR}/detail/CRC32.cpp" - "${CMAKE_CURRENT_LIST_DIR}/detail/FileStream.cpp" - "${CMAKE_CURRENT_LIST_DIR}/detail/MD5.cpp" - "${CMAKE_CURRENT_LIST_DIR}/detail/Misc.cpp" - "${CMAKE_CURRENT_LIST_DIR}/detail/RSA.cpp" - - "${CMAKE_CURRENT_LIST_DIR}/format/BSP.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/FPX.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GCF.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GMA.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GRP.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/PAK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/PCK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/VPK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/ZIP.cpp" - - "${CMAKE_CURRENT_LIST_DIR}/Entry.cpp" - "${CMAKE_CURRENT_LIST_DIR}/PackFile.cpp") - -vpkedit_configure_target(lib${PROJECT_NAME}) - -set_target_properties(lib${PROJECT_NAME} PROPERTIES PREFIX "") - -target_link_libraries(lib${PROJECT_NAME} PUBLIC cryptopp::cryptopp MINIZIP::minizip) - -target_include_directories( - lib${PROJECT_NAME} PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/include") - -if(VPKEDIT_BUILD_FOR_STRATA_SOURCE) - target_compile_definitions(lib${PROJECT_NAME} PUBLIC -DVPKEDIT_BUILD_FOR_STRATA_SOURCE) -endif() diff --git a/src/lib/detail/Adler32.cpp b/src/lib/detail/Adler32.cpp deleted file mode 100644 index 790465b2..00000000 --- a/src/lib/detail/Adler32.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright notice: - * - * (C) 1995-2024 Jean-loup Gailly and Mark Adler - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Jean-loup Gailly Mark Adler - * jloup@gzip.org madler@alumni.caltech.edu - */ - -#include - -using namespace vpkedit; - -constexpr std::uint32_t BASE = 65521u; /* largest prime smaller than 65536 */ -constexpr std::size_t NMAX = 5552u; - -#define DO1(buffer,i) {adler += static_cast((buffer)[i]); sum2 += adler;} -#define DO2(buffer,i) DO1(buffer,i) DO1(buffer,i+1) -#define DO4(buffer,i) DO2(buffer,i) DO2(buffer,i+2) -#define DO8(buffer,i) DO4(buffer,i) DO4(buffer,i+4) -#define DO16(buffer) DO8(buffer,0) DO8(buffer,8) - -std::uint32_t detail::computeAdler32(const std::vector& buffer) { - return computeAdler32(buffer.data(), buffer.size()); -} - -std::uint32_t detail::computeAdler32(const std::byte* buffer, std::size_t len) { - std::uint32_t adler = 0; - std::uint32_t sum2; - std::uint32_t n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += static_cast(buffer[0]); - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (!buffer) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += static_cast(*buffer++); - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - sum2 %= BASE; /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buffer) /* 16 sums unrolled */ - buffer += 16; - } while (--n); - adler %= BASE; - sum2 %= BASE; - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buffer) - buffer += 16; - } - while (len--) { - adler += static_cast(*buffer++); - sum2 += adler; - } - adler %= BASE; - sum2 %= BASE; - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} diff --git a/src/lib/detail/CRC32.cpp b/src/lib/detail/CRC32.cpp deleted file mode 100644 index 5d12a15f..00000000 --- a/src/lib/detail/CRC32.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include - -using namespace vpkedit; - -std::uint32_t detail::computeCRC32(const std::vector& buffer) { - return computeCRC32(buffer.data(), buffer.size()); -} - -std::uint32_t detail::computeCRC32(const std::byte* buffer, std::size_t len) { - // Make sure this is right - static_assert(CryptoPP::CRC32::DIGESTSIZE == sizeof(std::uint32_t)); - - CryptoPP::CRC32 crc32; - crc32.Update(reinterpret_cast(buffer), len); - - std::uint32_t final; - crc32.Final(reinterpret_cast(&final)); - return final; -} diff --git a/src/lib/detail/FileStream.cpp b/src/lib/detail/FileStream.cpp deleted file mode 100644 index 295f5556..00000000 --- a/src/lib/detail/FileStream.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include - -#include - -using namespace vpkedit::detail; - -FileStream::FileStream(const std::string& filepath, int options) { - if ((options & FILESTREAM_OPT_CREATE_IF_NONEXISTENT) && !std::filesystem::exists(filepath)) { - if (!std::filesystem::exists(std::filesystem::path{filepath}.parent_path())) { - std::error_code ec; - std::filesystem::create_directories(std::filesystem::path{filepath}.parent_path(), ec); - ec.clear(); - } - std::ofstream create(filepath, std::ios::trunc); - } - std::ios::openmode openMode = std::ios::binary; - if (options & FILESTREAM_OPT_READ) { - openMode |= std::ios::in; - } - if (options & FILESTREAM_OPT_WRITE) { - openMode |= std::ios::out; - } - if (options & FILESTREAM_OPT_APPEND) { - openMode |= std::ios::out; - openMode |= std::ios::app; - } - if (options & FILESTREAM_OPT_TRUNCATE) { - openMode |= std::ios::out; - openMode |= std::ios::trunc; - } - this->streamFile.open(filepath, openMode); - this->streamFile.unsetf(std::ios::skipws); -} - -FileStream::operator bool() const { - return static_cast(this->streamFile); -} - -void FileStream::seekInput(std::size_t offset, std::ios::seekdir offsetFrom) { - this->streamFile.seekg(static_cast(offset), offsetFrom); -} - -void FileStream::seekOutput(std::size_t offset, std::ios::seekdir offsetFrom) { - this->streamFile.seekp(static_cast(offset), offsetFrom); -} - -std::size_t FileStream::tellInput() { - return this->streamFile.tellg(); -} - -std::size_t FileStream::tellOutput() { - return this->streamFile.tellp(); -} - -std::vector FileStream::readBytes(std::size_t length) { - std::vector out; - out.resize(length); - this->streamFile.read(reinterpret_cast(out.data()), static_cast(length)); - return out; -} - -std::string FileStream::readString() { - std::string out; - this->read(out); - return out; -} - -std::string FileStream::readString(std::size_t n, bool stopOnNullTerminator) { - std::string out; - this->read(out, n, stopOnNullTerminator); - return out; -} - -void FileStream::writeBytes(const std::vector& buffer) { - this->streamFile.write(reinterpret_cast(buffer.data()), static_cast(buffer.size())); -} - -void FileStream::flush() { - this->streamFile.flush(); -} diff --git a/src/lib/detail/MD5.cpp b/src/lib/detail/MD5.cpp deleted file mode 100644 index b10cf9d7..00000000 --- a/src/lib/detail/MD5.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include - -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include - -using namespace vpkedit; - -std::array detail::computeMD5(const std::vector& buffer) { - return computeMD5(buffer.data(), buffer.size()); -} - -std::array detail::computeMD5(const std::byte* buffer, std::size_t len) { - // Make sure this is right - static_assert(CryptoPP::Weak::MD5::DIGESTSIZE == sizeof(std::array)); - - CryptoPP::Weak::MD5 md5; - md5.Update(reinterpret_cast(buffer), len); - - std::array final{}; - md5.Final(reinterpret_cast(final.data())); - return final; -} diff --git a/src/lib/detail/Misc.cpp b/src/lib/detail/Misc.cpp deleted file mode 100644 index 57c1cc39..00000000 --- a/src/lib/detail/Misc.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -#include -#include -#include - -#include - -using namespace vpkedit; - -void detail::toLowerCase(std::string& input) { - std::transform(input.begin(), input.end(), input.begin(), [](unsigned char c){ return std::tolower(c); }); -} - -void detail::normalizeSlashes(std::string& path, bool stripSlashes) { - std::replace(path.begin(), path.end(), '\\', '/'); - if (stripSlashes) { - if (path.starts_with('/')) { - path = path.substr(1); - } - if (path.ends_with('/')) { - path.pop_back(); - } - } -} - -std::pair detail::splitFilenameAndParentDir(const std::string& filename) { - auto name = filename; - normalizeSlashes(name); - - auto lastSeparator = name.rfind('/'); - auto dir = lastSeparator != std::string::npos ? name.substr(0, lastSeparator) : ""; - name = filename.substr(lastSeparator + 1); - - return {dir, name}; -} - -std::vector detail::readFileData(const std::string& filepath, std::size_t preloadBytesOffset) { - FileStream stream{filepath}; - if (!stream) { - return {}; - } - stream.seekInput(preloadBytesOffset); - return stream.readBytes(std::filesystem::file_size(filepath) - preloadBytesOffset); -} - -std::string detail::readFileText(const std::string& filepath, std::size_t preloadBytesOffset) { - auto data = readFileData(filepath, preloadBytesOffset); - std::string out; - for (std::byte b : data) { - out.push_back(static_cast(b)); - } - while (!out.empty() && out[out.size() - 1] == '\0') { - out.pop_back(); - } - return out; -} diff --git a/src/lib/detail/RSA.cpp b/src/lib/detail/RSA.cpp deleted file mode 100644 index 1cb46bbf..00000000 --- a/src/lib/detail/RSA.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include -#include -#include - -using namespace vpkedit; - -std::pair detail::computeSHA256KeyPair(std::uint16_t size) { - CryptoPP::AutoSeededRandomPool rng; - - CryptoPP::RSAES_OAEP_SHA256_Decryptor privateKey{rng, size}; - CryptoPP::RSAES_OAEP_SHA256_Encryptor publicKey{privateKey}; - - std::vector privateKeyData; - CryptoPP::VectorSink privateKeyDataSink{privateKeyData}; - privateKey.AccessMaterial().Save(privateKeyDataSink); - std::string privateKeyStr; - CryptoPP::StringSource privateKeyStringSource{privateKeyData.data(), privateKeyData.size(), true, new CryptoPP::HexEncoder{new CryptoPP::StringSink{privateKeyStr}}}; - - std::vector publicKeyData; - CryptoPP::VectorSink publicKeyDataArraySink{publicKeyData}; - publicKey.AccessMaterial().Save(publicKeyDataArraySink); - std::string publicKeyStr; - CryptoPP::StringSource publicKeyStringSource{publicKeyData.data(), publicKeyData.size(), true, new CryptoPP::HexEncoder{new CryptoPP::StringSink{publicKeyStr}}}; - - return std::make_pair(std::move(privateKeyStr), std::move(publicKeyStr)); -} - -bool detail::verifySHA256Key(const std::vector& buffer, const std::vector& publicKey, const std::vector& signature) { - CryptoPP::RSASS::Verifier verifier{ - CryptoPP::VectorSource(reinterpret_cast&>(publicKey), true).Ref() - }; - return verifier.VerifyMessage(reinterpret_cast(buffer.data()), buffer.size(), - reinterpret_cast(signature.data()), signature.size()); -} - -std::vector detail::signDataWithSHA256Key(const std::vector& buffer, const std::vector& privateKey) { - CryptoPP::AutoSeededRandomPool rng; - - CryptoPP::RSASS::Signer signer{ - CryptoPP::VectorSource(reinterpret_cast&>(privateKey), true).Ref() - }; - - std::vector out; - CryptoPP::VectorSource signData{ - reinterpret_cast &>(buffer), true, - new CryptoPP::SignerFilter{rng, signer, new CryptoPP::VectorSink{reinterpret_cast &>(out)}} - }; - return out; -} - -std::vector detail::decodeHexString(std::string_view hex) { - std::string hexBin; - CryptoPP::StringSource hexSource{hex.data(), true, new CryptoPP::HexDecoder{new CryptoPP::StringSink{hexBin}}}; - - std::vector out; - for (char c : hexBin) { - out.push_back(static_cast(c)); - } - return out; -} diff --git a/src/lib/format/BSP.cpp b/src/lib/format/BSP.cpp deleted file mode 100644 index 089c412a..00000000 --- a/src/lib/format/BSP.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -constexpr std::string_view BSP_ENTITY_LUMP_NAME = "entities.kv"; -constexpr std::string_view BSP_LUMP_NAME_FORMAT = "lmp_%d.bin"; - -namespace { - -// Convert virtual filename to lump ID -int virtualLumpNameToID(std::string_view lumpName) { - if (lumpName == BSP_ENTITY_LUMP_NAME) { - return 0; - } - int lumpID = -1; -#ifdef _WIN32 - sscanf_s(lumpName.data(), BSP_LUMP_NAME_FORMAT.data(), &lumpID); -#else - sscanf(lumpName.data(), BSP_LUMP_NAME_FORMAT.data(), &lumpID); -#endif - if (lumpID < 0 || lumpID >= BSP_LUMP_COUNT) { - return -1; - } - return lumpID; -} - -} // namespace - -const std::string BSP::TEMP_ZIP_PATH = (std::filesystem::temp_directory_path() / "tmp_bsp_paklump.zip").string(); - -BSP::BSP(const std::string& fullFilePath_, PackFileOptions options_) - : ZIP(fullFilePath_, options_) { - this->type = PackFileType::BSP; -} - -std::unique_ptr BSP::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* bsp = new BSP{path, options}; - auto packFile = std::unique_ptr(bsp); - - FileStream reader{bsp->fullFilePath}; - reader.seekInput(0); - - reader.read(bsp->header.signature); - if (bsp->header.signature != BSP_SIGNATURE) { - // File is not a BSP - return nullptr; - } - reader.read(bsp->header.version); - reader.read(bsp->header.lumps); - reader.read(bsp->header.mapRevision); - - if (bsp->header.lumps[BSP_LUMP_PAKFILE_INDEX].offset == 0 || bsp->header.lumps[BSP_LUMP_PAKFILE_INDEX].length == 0) { - // No paklump, create an empty zip - void* writeStreamHandle = mz_stream_os_create(); - if (mz_stream_os_open(writeStreamHandle, BSP::TEMP_ZIP_PATH.c_str(), MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE)) { - return nullptr; - } - void* writeZipHandle = mz_zip_writer_create(); - if (mz_zip_writer_open(writeZipHandle, writeStreamHandle, 0)) { - return nullptr; - } - if (mz_zip_writer_close(writeZipHandle)) { - return nullptr; - } - mz_zip_writer_delete(&writeZipHandle); - if (mz_stream_os_close(writeStreamHandle)) { - return nullptr; - } - mz_stream_os_delete(&writeStreamHandle); - } else { - // Extract the paklump to a temp dir - reader.seekInput(bsp->header.lumps[BSP_LUMP_PAKFILE_INDEX].offset); - auto binData = reader.readBytes(bsp->header.lumps[BSP_LUMP_PAKFILE_INDEX].length); - - FileStream writer{BSP::TEMP_ZIP_PATH, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - writer.writeBytes(binData); - } - - if (!bsp->openZIP(BSP::TEMP_ZIP_PATH)) { - return nullptr; - } - - for (auto code = mz_zip_goto_first_entry(bsp->zipHandle); code == MZ_OK; code = mz_zip_goto_next_entry(bsp->zipHandle)) { - mz_zip_file* fileInfo = nullptr; - if (mz_zip_entry_get_info(bsp->zipHandle, &fileInfo)) { - return nullptr; - } - if (mz_zip_entry_is_dir(bsp->zipHandle) == MZ_OK) { - continue; - } - - Entry entry = createNewEntry(); - entry.path = fileInfo->filename; - ::normalizeSlashes(entry.path); - if (!bsp->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.flags = fileInfo->compression_method; - entry.length = fileInfo->uncompressed_size; - entry.compressedLength = fileInfo->compressed_size; - entry.crc32 = fileInfo->crc; - - auto parentDir = std::filesystem::path{entry.path}.parent_path().string(); - ::normalizeSlashes(parentDir); - if (!bsp->isCaseSensitive()) { - ::toLowerCase(parentDir); - } - - if (!bsp->entries.contains(parentDir)) { - bsp->entries[parentDir] = {}; - } - bsp->entries[parentDir].push_back(entry); - - if (callback) { - callback(parentDir, entry); - } - } - - return packFile; -} - -bool BSP::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Use temp folder so we can read from the current ZIP - if (!this->bakeTempZip(ZIP::TEMP_ZIP_PATH, callback)) { - return false; - } - this->mergeUnbakedEntries(); - - // Close the ZIP - this->closeZIP(); - - // Write the pakfile lump - this->writeLump(BSP_LUMP_PAKFILE_INDEX, ::readFileData(ZIP::TEMP_ZIP_PATH)); - - // If the output path is different, copy the entire BSP there - if (outputPath != this->fullFilePath) { - std::filesystem::copy_file(this->fullFilePath, outputPath, std::filesystem::copy_options::overwrite_existing); - } - - // Rename and reopen the ZIP - std::filesystem::rename(ZIP::TEMP_ZIP_PATH, BSP::TEMP_ZIP_PATH); - if (!this->openZIP(BSP::TEMP_ZIP_PATH)) { - return false; - } - PackFile::setFullFilePath(outputDir); - return true; -} - -std::optional> BSP::readVirtualEntry(const VirtualEntry& entry) const { - int lumpID = ::virtualLumpNameToID(entry.name); - if (lumpID < 0) { - return std::nullopt; - } - return this->readLump(lumpID); -} - -bool BSP::overwriteVirtualEntry(const VirtualEntry& entry, const std::vector& data) { - if (!entry.writable) { - return false; - } - - int lumpID = ::virtualLumpNameToID(entry.name); - if (lumpID < 0) { - return false; - } - - this->writeLump(lumpID, data); - return true; -} - -std::vector BSP::getVirtualEntries() const { - std::vector out; - out.push_back({BSP_ENTITY_LUMP_NAME.data(), true}); - for (int i = 1; i < BSP_LUMP_COUNT; i++) { - char temp[BSP_LUMP_NAME_FORMAT.length() + 1] = {0}; - snprintf(temp, sizeof(temp), BSP_LUMP_NAME_FORMAT.data(), i); - out.push_back({temp, true}); - } - return out; -} - -BSP::operator std::string() const { - return PackFile::operator std::string() + - " | Version v" + std::to_string(this->header.version) + - " | Map Revision " + std::to_string(this->header.mapRevision); -} - -std::vector BSP::readLump(int lumpToRead) const { - if (this->header.lumps[lumpToRead].length == 0 || this->header.lumps[lumpToRead].offset == 0) { - return {}; - } - FileStream reader{this->fullFilePath}; - reader.seekInput(this->header.lumps[lumpToRead].offset); - return reader.readBytes(this->header.lumps[lumpToRead].length); -} - -void BSP::writeLump(int lumpToMove, const std::vector& data) { - this->moveLumpToWritableSpace(lumpToMove, static_cast(data.size())); - - FileStream writer{this->fullFilePath, FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE}; - writer.seekOutput(0); - - writer.write(this->header.signature); - writer.write(this->header.version); - writer.write(this->header.lumps); - writer.write(this->header.mapRevision); - writer.seekOutput(this->header.lumps[lumpToMove].offset); - writer.writeBytes(data); -} - -void BSP::moveLumpToWritableSpace(int lumpToMove, int newSize) { - this->header.lumps[lumpToMove].length = newSize; - - // If the zip is at the end of the file we just overwrite it, otherwise we have to shift some lumps over - std::vector lumpsAfterPaklumpIndices; - for (int i = 0; i < this->header.lumps.size(); i++) { - if (this->header.lumps[i].offset > this->header.lumps[lumpToMove].offset) { - lumpsAfterPaklumpIndices.push_back(i); - } - } - if (lumpsAfterPaklumpIndices.empty()) { - return; - } - - // Get the exact area to move - int moveOffsetStart = INT_MAX, moveOffsetEnd = 0; - for (int lumpIndex : lumpsAfterPaklumpIndices) { - if (this->header.lumps[lumpIndex].offset < moveOffsetStart) { - moveOffsetStart = this->header.lumps[lumpIndex].offset; - } - if (auto offsetAndLength = this->header.lumps[lumpIndex].offset + this->header.lumps[lumpIndex].length; offsetAndLength > moveOffsetEnd) { - moveOffsetEnd = offsetAndLength; - } - } - - // Get where to move it - int lastLumpBeforePaklumpOffset = 0, lastLumpBeforePaklumpLength = 0; - for (const Lump& lump : this->header.lumps) { - if (lump.offset < this->header.lumps[lumpToMove].offset && lump.offset > lastLumpBeforePaklumpOffset) { - lastLumpBeforePaklumpOffset = lump.offset; - lastLumpBeforePaklumpLength = lump.length; - } - } - - // Move all the lumps after paklump back - FileStream bsp{this->fullFilePath, FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE}; - bsp.seekInput(moveOffsetStart); - auto lumpsData = bsp.readBytes(moveOffsetEnd - moveOffsetStart); - bsp.seekOutput(lastLumpBeforePaklumpOffset + lastLumpBeforePaklumpLength); - bsp.writeBytes(lumpsData); - - // Fix the offsets - for (int lumpIndex : lumpsAfterPaklumpIndices) { - this->header.lumps[lumpIndex].offset -= newSize; - } - this->header.lumps[lumpToMove].offset = lastLumpBeforePaklumpOffset + lastLumpBeforePaklumpLength + static_cast(lumpsData.size()); -} diff --git a/src/lib/format/FPX.cpp b/src/lib/format/FPX.cpp deleted file mode 100644 index d2b0562c..00000000 --- a/src/lib/format/FPX.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include - -#include - -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -FPX::FPX(const std::string& fullFilePath_, PackFileOptions options_) - : VPK(fullFilePath_, options_) { - this->type = PackFileType::FPX; -} - -std::unique_ptr FPX::open(const std::string& path, PackFileOptions options, const Callback& callback) { - auto fpx = FPX::openInternal(path, options, callback); - if (!fpx && path.length() > 8) { - // If it just tried to load a numbered archive, let's try to load the directory FPX - if (auto dirPath = path.substr(0, path.length() - 8) + FPX_DIR_SUFFIX.data() + std::filesystem::path{path}.extension().string(); std::filesystem::exists(dirPath)) { - fpx = FPX::openInternal(dirPath, options, callback); - } - } - return fpx; -} - -std::unique_ptr FPX::openInternal(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* fpx = new FPX{path, options}; - auto packFile = std::unique_ptr(fpx); - - FileStream reader{fpx->fullFilePath}; - reader.seekInput(0); - reader.read(fpx->header1); - if (fpx->header1.signature != FPX_SIGNATURE) { - // File is not an FPX - return nullptr; - } - if (fpx->header1.version != 10) { - // Only support v10 FPX files - return nullptr; - } - fpx->options.vpk_version = fpx->header1.version; - - // Extensions - while (true) { - std::string extension; - reader.read(extension); - if (extension.empty()) - break; - - // Directories - while (true) { - std::string directory; - reader.read(directory); - if (directory.empty()) - break; - - std::string fullDir; - if (directory == " ") { - fullDir = ""; - } else { - fullDir = directory; - } - if (!fpx->entries.contains(fullDir)) { - fpx->entries[fullDir] = {}; - } - - // Files - while (true) { - std::string entryName; - reader.read(entryName); - if (entryName.empty()) - break; - - Entry entry = createNewEntry(); - - if (extension == " ") { - entry.path = fullDir.empty() ? "" : fullDir + '/'; - entry.path += entryName; - } else { - entry.path = fullDir.empty() ? "" : fullDir + '/'; - entry.path += entryName + '.'; - entry.path += extension; - } - - reader.read(entry.crc32); - auto preloadedDataSize = reader.read(); - reader.read(entry.vpk_archiveIndex); - entry.offset = reader.read(); - entry.length = reader.read(); - - if (reader.read() != VPK_ENTRY_TERM) { - // Invalid terminator! - return nullptr; - } - - if (preloadedDataSize > 0) { - entry.vpk_preloadedData = reader.readBytes(preloadedDataSize); - entry.length += preloadedDataSize; - } - - fpx->entries[fullDir].push_back(entry); - - if (entry.vpk_archiveIndex != VPK_DIR_INDEX && entry.vpk_archiveIndex > fpx->numArchives) { - fpx->numArchives = entry.vpk_archiveIndex; - } - - if (callback) { - callback(fullDir, entry); - } - } - } - } - - // If there are no archives, -1 will be incremented to 0 - fpx->numArchives++; - - return packFile; -} diff --git a/src/lib/format/GCF.cpp b/src/lib/format/GCF.cpp deleted file mode 100644 index 31a93675..00000000 --- a/src/lib/format/GCF.cpp +++ /dev/null @@ -1,315 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -GCF::GCF(const std::string& fullFilePath_, PackFileOptions options_) - : PackFileReadOnly(fullFilePath_, options_) { - this->type = PackFileType::GCF; -} - -std::unique_ptr GCF::open(const std::string& path, PackFileOptions options, const Callback& callback) { - // TODO: Add v5 and perhaps v4 support - - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - // Create the pack file - auto* gcf = new GCF{path, options}; - auto packFile = std::unique_ptr(gcf); - - // open file - FileStream reader(gcf->fullFilePath); - reader.seekInput(0); - - // we read the main header here (not the block header) - reader.read(gcf->header); - - if (gcf->header.dummy1 != 1 && gcf->header.dummy2 != 1 && gcf->header.gcfversion != 6) { - /** - * This should NEVER occur when reading a "normal" gcf file. - * It will only be false if - * a) the gcf file isn't a gcf file - * b) the gcf file is from a beta steam version that used a different format that there are no public docs for (v6 was used throughout 2004-2013) - */ - return nullptr; - } - - uintmax_t real_size = std::filesystem::file_size(gcf->fullFilePath); - if (real_size != gcf->header.filesize) { - // again, this should never occur with a valid gcf file - return nullptr; - } - - reader.read(gcf->blockheader); - if (gcf->blockheader.count != gcf->header.blockcount) { - return nullptr; - } - - // if you're having a headache reading the if statement below heres a quick explaination of what it actually does - // it just adds all blockheader entries together and compares it against the checksum - // if it's not the same then we bail out with a nullptr - if (gcf->blockheader.count + - gcf->blockheader.used + - gcf->blockheader.dummy1 + - gcf->blockheader.dummy2 + - gcf->blockheader.dummy3 + - gcf->blockheader.dummy4 + - gcf->blockheader.dummy5 != gcf->blockheader.checksum) { - return nullptr; - } - - // block headers!!!!!! - for (int i = 0; i < gcf->header.blockcount; i++) { - Block& block = gcf->blockdata.emplace_back(); - reader.read(block); - } - - // Fragmentation Map header - // not worth keeping around after verifying stuff so no struct def - // if you want one this is how one should look like - /// struct FragMapHeader { - /// std::uint32_t blockcount; - /// std::uint32_t dummy0; - /// std::uint32_t dummy1; - /// std::uint32_t checksum; - /// }; - // actually if we want to implement writing later this might be a better idea - // if anyone wants to touch this piece of shit format again anyways - - auto blkcount = reader.read(); - auto d1 = reader.read(); - auto d2 = reader.read(); - auto checksum = reader.read(); - - if (blkcount + d1 + d2 != checksum || blkcount != gcf->blockheader.count) { - return nullptr; - } - - // Fragmentation Map (list of dwords) - - for (int i = 0; i < blkcount; i++) { - gcf->fragmap.push_back(reader.read()); - } - - // Directory stuff starts here - - //Reading the header - std::uint64_t temp = reader.tellInput(); - reader.read(gcf->dirheader); - - std::uint64_t diroffset = reader.tellInput() + (gcf->dirheader.itemcount * 28); - std::uint64_t currentoffset; - - std::vector direntries{}; - - for (int i = 0; i < gcf->dirheader.itemcount; i++) { - DirectoryEntry2& entry = direntries.emplace_back(); - reader.read(entry.entry_real); - currentoffset = reader.tellInput(); - reader.seekInput(diroffset + entry.entry_real.nameoffset); - reader.read(entry.filename); - if (entry.entry_real.dirtype != 0) { // if not directory - std::string dirname; - DirectoryEntry2 current_filename_entry = entry; - while (current_filename_entry.entry_real.parentindex != 0xffffffff) { - current_filename_entry = direntries[current_filename_entry.entry_real.parentindex]; - dirname.insert(0, "/"); - dirname.insert(0, current_filename_entry.filename); - } - Entry gcfEntry = createNewEntry(); - ::normalizeSlashes(dirname); - if (!gcf->isCaseSensitive()) { - ::toLowerCase(dirname); - ::toLowerCase(entry.filename); - } - if (!gcf->entries.contains(dirname)) { - //printf("dirname creation: %s\n", dirname.c_str()); - gcf->entries[dirname] = {}; - } - gcfEntry.length = entry.entry_real.itemsize; - gcfEntry.path = dirname; - gcfEntry.path += dirname.empty() ? "" : "/"; - gcfEntry.path += entry.filename; - gcfEntry.crc32 = entry.entry_real.fileid; // INDEX INTO THE CHECKSUM MAP VECTOR NOT CRC32!!! - gcfEntry.offset = i; // THIS IS THE STRUCT INDEX NOT SOME OFFSET!!! - //printf("%s\n", vpkedit_entry.path.c_str()); - gcf->entries[dirname].push_back(gcfEntry); - //printf("dir %s file %s\n", dirname.c_str(), entry.filename.c_str()); - - if (callback) { - callback(dirname, gcfEntry); - } - } - reader.seekInput(currentoffset); - } - - // Directory Map - - // Directory Map header - reader.seekInput(temp + gcf->dirheader.dirsize); - - //auto dmap = reader.read(); - reader.skipInput(); - - // Directory Map entries - for (int i = 0; i < gcf->dirheader.itemcount; i++) { - DirectoryMapEntry& entry = gcf->dirmap_entries.emplace_back(); - reader.read(entry); - } - - // Checksum header - //auto dummy0 = reader.read(); - reader.skipInput(); - auto checksumsize = reader.read(); - std::size_t checksums_start = reader.tellInput(); - - //printf("checksums start: %llu\n", checksums_start); - //printf("%lu %lu %lu %lu\n", gcf->header.blockcount, gcf->blockheader.used, gcf->header.appid, gcf->header.appversion); - // map header - - ChecksumMapHeader chksummapheader = reader.read(); - if (chksummapheader.dummy1 != 0x14893721 || chksummapheader.dummy2 != 0x1) { - return nullptr; - } - - //printf("%lu %lu\n", chksummapheader.checksum_count, chksummapheader.item_count); - - for (int i = 0; i < chksummapheader.item_count; i++) { - auto& cur_entry = gcf->chksum_map.emplace_back(); - reader.read(cur_entry); - } - - for (int i = 0; i < chksummapheader.checksum_count; i++) { - auto& currentChecksum = gcf->checksums.emplace_back(); - reader.read(currentChecksum); - } - //printf("current pos: %llu, block header: %llu should be: %llu", reader.tellInput(), reader.tellInput() + 0x80, checksums_start + checksumsize); - // TODO: check the checksum RSA signature... later.. if ever... - - reader.seekInput(checksums_start + checksumsize); - - reader.read(gcf->datablockheader); - return packFile; -} - -std::vector GCF::verifyEntryChecksums() const { - std::vector bad; - for (const auto& entryList : this->entries) { - for (const auto& entry : entryList.second) { - auto bytes = this->readEntry(entry); - if (!bytes || bytes->empty()) { - continue; - } - std::size_t tocheck = bytes->size(); - std::uint32_t idx = entry.crc32; - std::uint32_t count = this->chksum_map[idx].count; - std::uint32_t checksumstart = this->chksum_map[idx].firstindex; - for (int i = 0; i < count; i++) { - std::uint32_t csum = this->checksums[checksumstart + i]; - std::size_t toread = std::min(static_cast(0x8000), tocheck); - const auto* data = bytes->data() + (i * 0x8000); - std::uint32_t checksum = ::computeCRC32(data, toread) ^ ::computeAdler32(data, toread); - if (checksum != csum) { - bad.push_back(entry.path); - } - tocheck -= toread; - } - } - } - return bad; -} - -std::optional> GCF::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } - else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - - std::vector filedata; - if (entry.length == 0) { - // don't bother - return filedata; - } - - std::uint32_t dir_index = entry.offset; - //printf(" extracting file: %s\n", entry.path.c_str()); - - std::vector toread; - for (const auto& v : this->blockdata) { - if (v.dir_index == dir_index) { - toread.push_back(v); - } - } - - std::sort(toread.begin(), toread.end(), [](Block lhs, Block rhs) { - return (lhs.file_data_offset < rhs.file_data_offset); - } - ); - - if (toread.empty()) { - //printf("could not find any directory index for %lu", entry.vpk_offset); - return std::nullopt; - } - - FileStream stream{this->fullFilePath}; - if (!stream) { - //printf("!stream\n"); - return std::nullopt; - } - - std::uint64_t remaining = entry.length; - - for (const auto& block : toread) { - std::uint32_t currindex = block.first_data_block_index; - while (currindex <= this->blockheader.count) { - std::uint64_t curfilepos = static_cast(this->datablockheader.firstblockoffset) + (static_cast(0x2000) * static_cast(currindex)); - stream.seekInput(curfilepos); - //printf("off %lli block %lu toread %lli should be %llu\n", stream.tellInput(), currindex, remaining, curfilepos); - std::uint32_t toreadAmt = std::min(remaining, static_cast(0x2000)); - auto streamvec = stream.readBytes(toreadAmt); - filedata.insert(filedata.end(), streamvec.begin(), streamvec.end()); - remaining -= toreadAmt; - currindex = this->fragmap[currindex]; - //printf("curridx now: %lu\n", currindex); - } - } - - return filedata; -} - -std::vector GCF::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH}; -} - -GCF::operator std::string() const { - return PackFileReadOnly::operator std::string() + - " | Version v" + std::to_string(this->header.gcfversion) + - " | AppID " + std::to_string(this->header.appid) + - " | App Version v" + std::to_string(this->header.appversion); -} diff --git a/src/lib/format/GMA.cpp b/src/lib/format/GMA.cpp deleted file mode 100644 index f538df7a..00000000 --- a/src/lib/format/GMA.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include - -#include - -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -GMA::GMA(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::GMA; -} - -std::unique_ptr GMA::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* gma = new GMA{path, options}; - auto packFile = std::unique_ptr(gma); - - FileStream reader{gma->fullFilePath}; - reader.seekInput(0); - - reader.read(gma->header.signature); - if (gma->header.signature != GMA_SIGNATURE) { - // File is not a GMA - return nullptr; - } - reader.read(gma->header.version); - reader.read(gma->header.steamID); - reader.read(gma->header.timestamp); - reader.read(gma->header.requiredContent); - reader.read(gma->header.addonName); - reader.read(gma->header.addonDescription); - reader.read(gma->header.addonAuthor); - reader.read(gma->header.addonVersion); - - std::vector entries; - while (reader.read() > 0) { - Entry entry = createNewEntry(); - - reader.read(entry.path); - ::normalizeSlashes(entry.path); - if (!gma->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.length = reader.read(); - reader.read(entry.crc32); - - entries.push_back(entry); - } - - // At this point we've reached the file data section, calculate the offsets and then add the entries - std::size_t offset = reader.tellInput(); - for (auto& entry : entries) { - entry.offset = offset; - offset += entry.length; - } - for (const auto& entry : entries) { - auto parentDir = std::filesystem::path{entry.path}.parent_path().string(); - ::normalizeSlashes(parentDir); - if (!gma->isCaseSensitive()) { - ::toLowerCase(parentDir); - } - - if (!gma->entries.contains(parentDir)) { - gma->entries[parentDir] = {}; - } - gma->entries[parentDir].push_back(entry); - - if (callback) { - callback(parentDir, entry); - } - } - - return packFile; -} - -std::vector GMA::verifyEntryChecksums() const { - return this->verifyEntryChecksumsUsingCRC32(); -} - -bool GMA::hasFileChecksum() const { - return true; -} - -bool GMA::verifyFileChecksum() const { - auto data = ::readFileData(this->fullFilePath); - if (data.size() <= 4) { - return true; - } - - auto checksum = *(reinterpret_cast(data.data() + data.size()) - 1); - data.pop_back(); - data.pop_back(); - data.pop_back(); - data.pop_back(); - return checksum == ::computeCRC32(data); -} - -std::optional> GMA::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - // It's baked into the file on disk - FileStream stream{this->fullFilePath}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(entry.offset); - return stream.readBytes(entry.length); -} - -Entry& GMA::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - entry.path = filename; - entry.length = buffer.size(); - if (this->options.gma_writeCRCs) { - entry.crc32 = ::computeCRC32(buffer); - } - - // Offset will be reset when it's baked - entry.offset = 0; - - if (!this->unbakedEntries.contains(dir)) { - this->unbakedEntries[dir] = {}; - } - this->unbakedEntries.at(dir).push_back(entry); - return this->unbakedEntries.at(dir).back(); -} - -bool GMA::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Reconstruct data for ease of access - std::vector entriesToBake; - for (auto& [entryDir, entryList] : this->entries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - for (auto& [entryDir, entryList] : this->unbakedEntries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - - // Read data before overwriting, we don't know if we're writing to ourself - std::vector fileData; - for (auto* entry : entriesToBake) { - if (auto binData = this->readEntry(*entry)) { - fileData.insert(fileData.end(), binData->begin(), binData->end()); - } else { - entry->length = 0; - } - } - - { - FileStream stream{outputPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.seekOutput(0); - - // Header - stream.write(this->header.signature); - stream.write(this->header.version); - stream.write(this->header.steamID); - stream.write(this->header.timestamp); - stream.write(this->header.requiredContent); - stream.write(this->header.addonName); - stream.write(this->header.addonDescription); - stream.write(this->header.addonAuthor); - stream.write(this->header.addonVersion); - - // File tree - for (std::uint32_t i = 1; i <= entriesToBake.size(); i++) { - stream.write(i); - auto* entry = entriesToBake[i - 1]; - stream.write(entry->path); - stream.write(entry->length); - stream.write(this->options.gma_writeCRCs ? entry->crc32 : 0); - - if (callback) { - callback(entry->getParentPath(), *entry); - } - } - stream.write(static_cast(0)); - - // Fix offsets - std::size_t offset = stream.tellOutput(); - for (auto* entry : entriesToBake) { - entry->offset = offset; - offset += entry->length; - } - - // File data - stream.writeBytes(fileData); - } - - // CRC of everything that's been written - std::uint32_t crc = 0; - if (this->options.gma_writeCRCs) { - auto fileSize = std::filesystem::file_size(outputPath); - FileStream stream{outputPath}; - stream.seekInput(0); - crc = ::computeCRC32(stream.readBytes(fileSize)); - } - { - FileStream stream{outputPath, FILESTREAM_OPT_APPEND}; - stream.write(crc); - } - - // Clean up - this->mergeUnbakedEntries(); - PackFile::setFullFilePath(outputDir); - return true; -} - -std::vector GMA::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH, CRC32}; -} - -GMA::operator std::string() const { - return PackFile::operator std::string() + - " | Version v" + std::to_string(this->header.version) + - " | Addon Name: \"" + this->header.addonName + "\""; -} diff --git a/src/lib/format/GRP.cpp b/src/lib/format/GRP.cpp deleted file mode 100644 index 845dc337..00000000 --- a/src/lib/format/GRP.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include - -#include - -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -GRP::GRP(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::GRP; -} - -std::unique_ptr GRP::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* grp = new GRP{path, options}; - auto packFile = std::unique_ptr(grp); - - FileStream reader{grp->fullFilePath}; - reader.seekInput(0); - - auto signature = reader.readBytes(); - for (int i = 0; i < signature.size(); i++) { - if (static_cast(signature[i]) != GRP_SIGNATURE[i]) { - // File is not a GRP - return nullptr; - } - } - - auto fileCount = reader.read(); - - std::vector entries; - for (int i = 0; i < fileCount; i++) { - Entry entry = createNewEntry(); - - reader.read(entry.path, GRP_FILENAME_MAX_SIZE); - ::normalizeSlashes(entry.path); - if (!grp->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.length = reader.read(); - - entries.push_back(entry); - } - - // At this point we've reached the file data section, calculate the offsets and then add the entries - std::size_t offset = reader.tellInput(); - if (!grp->entries.contains("")) { - grp->entries[""] = {}; - } - for (auto& entry : entries) { - entry.offset = offset; - offset += entry.length; - - grp->entries[""].push_back(entry); - - if (callback) { - callback("", entry); - } - } - - return packFile; -} - -std::optional> GRP::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - // It's baked into the file on disk - FileStream stream{this->fullFilePath}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(entry.offset); - return stream.readBytes(entry.length); -} - -Entry& GRP::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - - entry.path = filename; - entry.length = buffer.size(); - - // Offset will be reset when it's baked - entry.offset = 0; - - if (!this->unbakedEntries.contains("")) { - this->unbakedEntries[""] = {}; - } - this->unbakedEntries.at("").push_back(entry); - return this->unbakedEntries.at("").back(); -} - -bool GRP::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Reconstruct data for ease of access - std::vector entriesToBake; - for (auto& [entryDir, entryList] : this->entries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - for (auto& [entryDir, entryList] : this->unbakedEntries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - - // Read data before overwriting, we don't know if we're writing to ourself - std::vector fileData; - for (auto* entry : entriesToBake) { - if (auto binData = this->readEntry(*entry)) { - fileData.insert(fileData.end(), binData->begin(), binData->end()); - } else { - entry->length = 0; - } - } - - { - FileStream stream{outputPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.seekOutput(0); - - // Signature - stream.write(std::string{GRP_SIGNATURE}, false); - - // Number of files - stream.write(static_cast(entriesToBake.size())); - - // File tree - for (auto entry : entriesToBake) { - stream.write(entry->path, GRP_FILENAME_MAX_SIZE, false); - stream.write(static_cast(entry->length)); - - if (callback) { - callback(entry->getParentPath(), *entry); - } - } - - // Fix offsets - std::size_t offset = stream.tellOutput(); - for (auto* entry : entriesToBake) { - entry->offset = offset; - offset += entry->length; - } - - // File data - stream.writeBytes(fileData); - } - - // Clean up - this->mergeUnbakedEntries(); - PackFile::setFullFilePath(outputDir); - return true; -} - -std::vector GRP::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH}; -} diff --git a/src/lib/format/PAK.cpp b/src/lib/format/PAK.cpp deleted file mode 100644 index d5e7824e..00000000 --- a/src/lib/format/PAK.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include - -#include - -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -PAK::PAK(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::PAK; -} - -std::unique_ptr PAK::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* pak = new PAK{path, options}; - auto packFile = std::unique_ptr(pak); - - FileStream reader{pak->fullFilePath}; - reader.seekInput(0); - - if (auto signature = reader.read(); signature != PAK_SIGNATURE) { - // File is not a PAK - return nullptr; - } - - auto directoryOffset = reader.read(); - // Directory size / file entry size - auto fileCount = reader.read() / 64; - - reader.seekInput(directoryOffset); - for (int i = 0; i < fileCount; i++) { - Entry entry = createNewEntry(); - - reader.read(entry.path, PAK_FILENAME_MAX_SIZE); - ::normalizeSlashes(entry.path); - if (!pak->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.offset = reader.read(); - entry.length = reader.read(); - - auto parentDir = std::filesystem::path{entry.path}.parent_path().string(); - ::normalizeSlashes(parentDir); - if (!pak->isCaseSensitive()) { - ::toLowerCase(parentDir); - } - - if (!pak->entries.contains(parentDir)) { - pak->entries[parentDir] = {}; - } - pak->entries[parentDir].push_back(entry); - - if (callback) { - callback(parentDir, entry); - } - } - - return packFile; -} - -std::optional> PAK::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - // It's baked into the file on disk - FileStream stream{this->fullFilePath}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(entry.offset); - return stream.readBytes(entry.length); -} - -Entry& PAK::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - - entry.path = filename; - entry.length = buffer.size(); - - // Offset will be reset when it's baked - entry.offset = 0; - - if (!this->unbakedEntries.contains("")) { - this->unbakedEntries[""] = {}; - } - this->unbakedEntries.at("").push_back(entry); - return this->unbakedEntries.at("").back(); -} - -bool PAK::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename() + "_test.pak"; - - // Reconstruct data for ease of access - std::vector entriesToBake; - for (auto& [entryDir, entryList] : this->entries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - for (auto& [entryDir, entryList] : this->unbakedEntries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - - // Read data before overwriting, we don't know if we're writing to ourself - std::vector fileData; - for (auto* entry : entriesToBake) { - if (auto binData = this->readEntry(*entry)) { - entry->offset = fileData.size(); - - fileData.insert(fileData.end(), binData->begin(), binData->end()); - } else { - entry->offset = 0; - entry->length = 0; - } - } - - { - FileStream stream{outputPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.seekOutput(0); - - // Signature - stream.write(PAK_SIGNATURE); - - // Index and size of directory - const std::uint32_t directoryIndex = sizeof(PAK_SIGNATURE) + sizeof(std::uint32_t) * 2; - stream.write(directoryIndex); - const std::uint32_t directorySize = entriesToBake.size() * 64; - stream.write(directorySize); - - // Directory - for (auto entry : entriesToBake) { - stream.write(entry->path, PAK_FILENAME_MAX_SIZE, false); - stream.write(static_cast(entry->offset + directoryIndex + directorySize)); - stream.write(static_cast(entry->length)); - - if (callback) { - callback(entry->getParentPath(), *entry); - } - } - - // File data - stream.writeBytes(fileData); - } - - // Clean up - this->mergeUnbakedEntries(); - PackFile::setFullFilePath(outputDir); - return true; -} - -std::vector PAK::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH}; -} diff --git a/src/lib/format/PCK.cpp b/src/lib/format/PCK.cpp deleted file mode 100644 index 91fee1c1..00000000 --- a/src/lib/format/PCK.cpp +++ /dev/null @@ -1,330 +0,0 @@ -#include - -#include - -#include -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -constexpr int PCK_DIRECTORY_STRING_PADDING = 4; -constexpr int PCK_FILE_DATA_PADDING = 16; - -namespace { - -/* - * This function is modified from Godot Engine code, licensed under the MIT License. - * Copyright (c) 2014-present Godot Engine contributors. - * Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. - * https://github.com/godotengine/godot/blob/99ff024f78f65ba0bc54fb409cfeca43ba2008fe/core/io/pck_packer.cpp#L39 - */ -std::size_t getPadding(int alignment, int n) { - if (const int rest = n % alignment; rest > 0) { - return alignment - rest; - } - return 0; -} - -} // namespace - -PCK::PCK(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::PCK; -} - -std::unique_ptr PCK::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* pck = new PCK{path, options}; - auto packFile = std::unique_ptr(pck); - - FileStream reader{pck->fullFilePath}; - reader.seekInput(0); - - if (auto signature = reader.read(); signature != PCK_SIGNATURE) { - // PCK might be embedded - reader.seekInput(-sizeof(std::uint32_t), std::ios::end); - if (auto endSignature = reader.read(); endSignature != PCK_SIGNATURE) { - return nullptr; - } - - reader.seekInput(-(sizeof(std::uint32_t) + sizeof(std::uint64_t)), std::ios::cur); - auto distanceIntoFile = reader.read(); - - reader.seekInput(-(distanceIntoFile + sizeof(std::uint64_t)), std::ios::cur); - if (auto startSignature = reader.read(); startSignature != PCK_SIGNATURE) { - return nullptr; - } - - pck->startOffset = reader.tellInput() - sizeof(std::uint32_t); - } - - reader.read(pck->header.packVersion); - reader.read(pck->header.godotVersionMajor); - reader.read(pck->header.godotVersionMinor); - reader.read(pck->header.godotVersionPatch); - - pck->header.flags = FLAG_NONE; - std::size_t extraEntryContentsOffset = 0; - if (pck->header.packVersion > 1) { - pck->header.flags = reader.read(); - extraEntryContentsOffset = reader.read(); - } - - if (pck->header.flags & FLAG_ENCRYPTED) { - // File directory is encrypted - return nullptr; - } - if (pck->header.flags & FLAG_RELATIVE_FILE_DATA) { - extraEntryContentsOffset += pck->startOffset; - pck->header.flags = static_cast(pck->header.flags & ~FLAG_RELATIVE_FILE_DATA); - } - - // Reserved - reader.skipInput(16); - - // Directory - auto fileCount = reader.read(); - for (std::uint32_t i = 0; i < fileCount; i++) { - Entry entry = createNewEntry(); - - entry.path = reader.readString(reader.read()); - if (entry.path.starts_with(PCK_PATH_PREFIX)) { - entry.path = entry.path.substr(PCK_PATH_PREFIX.length()); - } - ::normalizeSlashes(entry.path); - if (!pck->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.offset = reader.read() + extraEntryContentsOffset; - entry.length = reader.read(); - entry.pck_md5 = reader.readBytes<16>(); - - if (pck->header.packVersion > 1) { - entry.flags = reader.read(); - } - - auto parentDir = std::filesystem::path{entry.path}.parent_path().string(); - ::normalizeSlashes(parentDir); - if (!pck->entries.contains(parentDir)) { - pck->entries[parentDir] = {}; - } - pck->entries[parentDir].push_back(entry); - - if (callback) { - callback(parentDir, entry); - } - } - - // File data - pck->dataOffset = reader.tellInput(); - - return packFile; -} - -std::optional> PCK::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - - // It's baked into the file on disk - if (entry.flags & FLAG_ENCRYPTED) { - // File is encrypted - return std::nullopt; - } - - FileStream stream{this->fullFilePath}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(entry.offset); - return stream.readBytes(entry.length); -} - -Entry& PCK::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - entry.path = filename; - entry.length = buffer.size(); - entry.pck_md5 = ::computeMD5(buffer); - - // Offset will be reset when it's baked - entry.offset = 0; - - if (!this->unbakedEntries.contains(dir)) { - this->unbakedEntries[dir] = {}; - } - this->unbakedEntries.at(dir).push_back(entry); - return this->unbakedEntries.at(dir).back(); -} - -bool PCK::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Reconstruct data for ease of access - std::vector entriesToBake; - for (auto& [entryDir, entryList] : this->entries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - for (auto& [entryDir, entryList] : this->unbakedEntries) { - for (auto& entry : entryList) { - entriesToBake.push_back(&entry); - } - } - - // Read data before overwriting, we don't know if we're writing to ourself - std::vector fileData; - for (auto* entry : entriesToBake) { - if (auto binData = this->readEntry(*entry)) { - entry->offset = fileData.size(); - - fileData.insert(fileData.end(), binData->begin(), binData->end()); - const auto padding = ::getPadding(PCK_FILE_DATA_PADDING, static_cast(entry->length)); - for (int i = 0; i < padding; i++) { - fileData.push_back(static_cast(0)); - } - } else { - entry->offset = 0; - entry->length = 0; - } - } - - // If this is an embedded pck, read the executable data first - std::vector exeData; - if (this->startOffset > 0) { - FileStream stream{this->fullFilePath}; - if (!stream) { - return false; - } - stream.seekInput(0); - exeData = stream.readBytes(this->startOffset); - } - - // Write data - { - FileStream stream{outputPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.seekOutput(0); - - if (!exeData.empty()) { - stream.writeBytes(exeData); - } - - // Signature - stream.write(PCK_SIGNATURE); - - // Header - stream.write(this->header.packVersion); - stream.write(this->header.godotVersionMajor); - stream.write(this->header.godotVersionMinor); - stream.write(this->header.godotVersionPatch); - - if (this->header.packVersion > 1) { - stream.write(this->header.flags); - stream.write(0); - } - - // Reserved - stream.write(std::array{}); - - // Directory start - stream.write(static_cast(entriesToBake.size())); - - // Dry-run to get the length of the directory section - this->dataOffset = stream.tellOutput(); - for (auto* entry : entriesToBake) { - const auto entryPath = std::string{PCK_PATH_PREFIX} + entry->path; - const auto padding = ::getPadding(PCK_DIRECTORY_STRING_PADDING, static_cast(entryPath.length())); - this->dataOffset += - sizeof(std::uint32_t) + // Path length - entryPath.length() + padding + // Path - (sizeof(std::size_t) * 2) + // Offset, Length - (sizeof(std::byte) * 16); // MD5 - - if (this->header.packVersion > 1) { - this->dataOffset += sizeof(std::uint32_t); // Flags - } - } - - // Directory - for (auto* entry : entriesToBake) { - const auto entryPath = std::string{PCK_PATH_PREFIX} + entry->path; - const auto padding = ::getPadding(PCK_DIRECTORY_STRING_PADDING, static_cast(entryPath.length())); - stream.write(static_cast(entryPath.length() + padding)); - stream.write(entryPath, entryPath.length() + padding, false); - - entry->offset += this->dataOffset; - stream.write(entry->offset); - stream.write(entry->length); - stream.writeBytes(entry->pck_md5); - - if (this->header.packVersion > 1) { - stream.write(entry->flags); - } - - if (callback) { - callback(entry->getParentPath(), *entry); - } - } - - // File data - stream.writeBytes(fileData); - - // Write offset to start - if (this->startOffset > 0) { - stream.write(stream.tellOutput() - startOffset); - stream.write(PCK_SIGNATURE); - } - } - - // Clean up - this->mergeUnbakedEntries(); - PackFile::setFullFilePath(outputDir); - return true; -} - -std::vector PCK::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH, PCK_MD5}; -} - -PCK::operator std::string() const { - auto out = PackFile::operator std::string() + - " | Version v" + std::to_string(this->header.packVersion) + - " | Godot Version v" + std::to_string(this->header.godotVersionMajor) + '.' + std::to_string(this->header.godotVersionMinor) + '.' + std::to_string(this->header.godotVersionPatch); - if (this->startOffset > 0) { - out += " | Embedded"; - } - if (this->header.flags & FLAG_ENCRYPTED) { - out += " | Encrypted"; - } - return out; -} diff --git a/src/lib/format/VPK.cpp b/src/lib/format/VPK.cpp deleted file mode 100644 index f799a678..00000000 --- a/src/lib/format/VPK.cpp +++ /dev/null @@ -1,854 +0,0 @@ -#include - -#include -#include - -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include - -#include -#include -#include -#include -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -/// Runtime-only flag that indicates a file is going to be written to an existing archive file -constexpr std::uint32_t VPK_FLAG_REUSING_CHUNK = 0x1; - -namespace { - -std::string removeVPKAndOrDirSuffix(const std::string& path, bool isFPX) { - std::string filename = path; - if (filename.length() >= 4 && filename.substr(filename.length() - 4) == (isFPX ? FPX_EXTENSION : VPK_EXTENSION)) { - filename = filename.substr(0, filename.length() - 4); - } - - // This indicates it's a dir VPK, but some people ignore this convention... - // It should fail later if it's not a proper dir VPK - if (filename.length() >= 4 && filename.substr(filename.length() - 4) == (isFPX ? FPX_DIR_SUFFIX : VPK_DIR_SUFFIX)) { - filename = filename.substr(0, filename.length() - 4); - } - - return filename; -} - -std::string padArchiveIndex(int num) { - static constexpr int WIDTH = 3; - auto numStr = std::to_string(num); - return std::string(WIDTH - std::min(WIDTH, numStr.length()), '0') + numStr; -} - -bool isFPX(const VPK* vpk) { - return vpk->getType() == PackFileType::FPX; -} - -/// Very rudimentary, doesn't handle escapes, but works fine for reading private/public key files -std::string_view readValueForKeyInKV(std::string_view key, std::string_view kv) { - auto index = kv.find(key); - if (index == std::string_view::npos) { - return ""; - } - while (kv.size() > index && kv[index] != '\"') { - index++; - } - if (index >= kv.size()) { - return ""; - } - while (kv.size() > index && kv[index] != '\"') { - index++; - } - if (++index >= kv.size()) { - return ""; - } - auto beginIndex = index; - while (kv.size() > index && kv[index] != '\"') { - index++; - } - if (index >= kv.size()) { - return ""; - } - return std::string_view{kv.data() + beginIndex, index - beginIndex}; -} - -} // namespace - -VPK::VPK(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::VPK; -} - -std::unique_ptr VPK::createEmpty(const std::string& path, PackFileOptions options) { - { - FileStream stream{path, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - - Header1 header1{}; - header1.signature = VPK_SIGNATURE; - header1.version = options.vpk_version; - header1.treeSize = 1; - stream.write(header1); - - if (options.vpk_version != 1) { - Header2 header2{}; - header2.fileDataSectionSize = 0; - header2.archiveMD5SectionSize = 0; - header2.otherMD5SectionSize = 0; - header2.signatureSectionSize = 0; - stream.write(header2); - } - - stream.write('\0'); - } - return VPK::open(path, options); -} - -std::unique_ptr VPK::createFromDirectory(const std::string& vpkPath, const std::string& contentPath, bool saveToDir, PackFileOptions options, const Callback& bakeCallback) { - return VPK::createFromDirectoryProcedural(vpkPath, contentPath, [saveToDir](const std::string&) { - return std::make_tuple(saveToDir, 0); - }, options, bakeCallback); -} - -std::unique_ptr VPK::createFromDirectoryProcedural(const std::string& vpkPath, const std::string& contentPath, const EntryCreationCallback& creationCallback, PackFileOptions options, const Callback& bakeCallback) { - auto vpk = VPK::createEmpty(vpkPath, options); - if (!std::filesystem::exists(contentPath) || std::filesystem::status(contentPath).type() != std::filesystem::file_type::directory) { - return vpk; - } - for (const auto& file : std::filesystem::recursive_directory_iterator(contentPath, std::filesystem::directory_options::skip_permission_denied)) { - if (!file.is_regular_file()) { - continue; - } - std::string entryPath; - try { - entryPath = std::filesystem::absolute(file.path()).string().substr(std::filesystem::absolute(contentPath).string().length()); - ::normalizeSlashes(entryPath); - } catch (const std::exception&) { - continue; // Likely a Unicode error, unsupported filename - } - if (entryPath.empty()) { - continue; - } - if (creationCallback) { - auto [saveToDir, preloadBytes] = creationCallback(entryPath); - vpk->addEntry(entryPath, file.path().string(), { .vpk_saveToDirectory = saveToDir, .vpk_preloadBytes = preloadBytes }); - } else { - vpk->addEntry(entryPath, file.path().string(), {}); - } - } - vpk->bake("", bakeCallback); - return vpk; -} - -std::unique_ptr VPK::open(const std::string& path, PackFileOptions options, const Callback& callback) { - auto vpk = VPK::openInternal(path, options, callback); - if (!vpk && path.length() > 8) { - // If it just tried to load a numbered archive, let's try to load the directory VPK - if (auto dirPath = path.substr(0, path.length() - 8) + VPK_DIR_SUFFIX.data() + std::filesystem::path{path}.extension().string(); std::filesystem::exists(dirPath)) { - vpk = VPK::openInternal(dirPath, options, callback); - } - } - return vpk; -} - -std::unique_ptr VPK::openInternal(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* vpk = new VPK{path, options}; - auto packFile = std::unique_ptr(vpk); - - FileStream reader{vpk->fullFilePath}; - reader.seekInput(0); - reader.read(vpk->header1); - if (vpk->header1.signature != VPK_SIGNATURE) { - // File is not a VPK - return nullptr; - } - if (vpk->header1.version == 2) { - reader.read(vpk->header2); - } else if (vpk->header1.version != 1) { - // Apex Legends, Titanfall, etc. are not supported - return nullptr; - } - vpk->options.vpk_version = vpk->header1.version; - - // Extensions - while (true) { - std::string extension; - reader.read(extension); - if (extension.empty()) - break; - - // Directories - while (true) { - std::string directory; - reader.read(directory); - if (directory.empty()) - break; - - std::string fullDir; - if (directory == " ") { - fullDir = ""; - } else { - fullDir = directory; - } - if (!vpk->entries.contains(fullDir)) { - vpk->entries[fullDir] = {}; - } - - // Files - while (true) { - std::string entryName; - reader.read(entryName); - if (entryName.empty()) - break; - - Entry entry = createNewEntry(); - - if (extension == " ") { - entry.path = fullDir.empty() ? "" : fullDir + '/'; - entry.path += entryName; - } else { - entry.path = fullDir.empty() ? "" : fullDir + '/'; - entry.path += entryName + '.'; - entry.path += extension; - } - - reader.read(entry.crc32); - auto preloadedDataSize = reader.read(); - reader.read(entry.vpk_archiveIndex); - entry.offset = reader.read(); - entry.length = reader.read(); - - if (reader.read() != VPK_ENTRY_TERM) { - // Invalid terminator! - return nullptr; - } - - if (preloadedDataSize > 0) { - entry.vpk_preloadedData = reader.readBytes(preloadedDataSize); - entry.length += preloadedDataSize; - } - - vpk->entries[fullDir].push_back(entry); - - if (entry.vpk_archiveIndex != VPK_DIR_INDEX && entry.vpk_archiveIndex > vpk->numArchives) { - vpk->numArchives = entry.vpk_archiveIndex; - } - - if (callback) { - callback(fullDir, entry); - } - } - } - } - - // If there are no archives, -1 will be incremented to 0 - vpk->numArchives++; - - // Read VPK2-specific data - if (vpk->header1.version != 2) - return packFile; - - // Skip over file data, if any - reader.seekInput(vpk->header2.fileDataSectionSize, std::ios_base::cur); - - if (vpk->header2.archiveMD5SectionSize % sizeof(MD5Entry) != 0) - return nullptr; - - vpk->md5Entries.clear(); - unsigned int entryNum = vpk->header2.archiveMD5SectionSize / sizeof(MD5Entry); - for (unsigned int i = 0; i < entryNum; i++) - vpk->md5Entries.push_back(reader.read()); - - if (vpk->header2.otherMD5SectionSize != 48) - // This should always be 48 - return packFile; - - vpk->footer2.treeChecksum = reader.readBytes<16>(); - vpk->footer2.md5EntriesChecksum = reader.readBytes<16>(); - vpk->footer2.wholeFileChecksum = reader.readBytes<16>(); - - if (!vpk->header2.signatureSectionSize) { - return packFile; - } - - auto publicKeySize = reader.read(); - if (vpk->header2.signatureSectionSize == 20 && publicKeySize == VPK_SIGNATURE) { - // CS2 beta VPK, ignore it - return packFile; - } - - vpk->footer2.publicKey = reader.readBytes(publicKeySize); - vpk->footer2.signature = reader.readBytes(reader.read()); - - return packFile; -} - -std::vector VPK::verifyEntryChecksums() const { - return this->verifyEntryChecksumsUsingCRC32(); -} - -bool VPK::hasFileChecksum() const { - return this->header1.version == 2; -} - -bool VPK::verifyFileChecksum() const { - // File checksums are only in v2 - if (this->header1.version != 2) { - return true; - } - - FileStream stream{this->getFilepath().data()}; - - stream.seekInput(this->getHeaderLength()); - if (this->footer2.treeChecksum != ::computeMD5(stream.readBytes(this->header1.treeSize))) { - return false; - } - - stream.seekInput(this->getHeaderLength() + this->header1.treeSize + this->header2.fileDataSectionSize); - if (this->footer2.md5EntriesChecksum != ::computeMD5(stream.readBytes(this->header2.archiveMD5SectionSize))) { - return false; - } - - stream.seekInput(0); - if (this->footer2.wholeFileChecksum != ::computeMD5(stream.readBytes(this->getHeaderLength() + this->header1.treeSize + this->header2.fileDataSectionSize + this->header2.archiveMD5SectionSize + this->header2.otherMD5SectionSize - sizeof(this->footer2.wholeFileChecksum)))) { - return false; - } - - return true; -} - -bool VPK::hasFileSignature() const { - if (this->header1.version != 2) { - return false; - } - if (this->footer2.publicKey.empty() || this->footer2.signature.empty()) { - return false; - } - return true; -} - -bool VPK::verifyFileSignature() const { - // Signatures are only in v2 - if (this->header1.version != 2) { - return true; - } - - if (this->footer2.publicKey.empty() || this->footer2.signature.empty()) { - return true; - } - auto dirFileBuffer = ::readFileData(this->getFilepath().data()); - const auto signatureSectionSize = this->footer2.publicKey.size() + this->footer2.signature.size() + sizeof(std::uint32_t) * 2; - if (dirFileBuffer.size() <= signatureSectionSize) { - return false; - } - for (int i = 0; i < signatureSectionSize; i++) { - dirFileBuffer.pop_back(); - } - return ::verifySHA256Key(dirFileBuffer, this->footer2.publicKey, this->footer2.signature); -} - -std::optional> VPK::readEntry(const Entry& entry) const { - std::vector output(entry.length, static_cast(0)); - - if (!entry.vpk_preloadedData.empty()) { - std::copy(entry.vpk_preloadedData.begin(), entry.vpk_preloadedData.end(), output.begin()); - } - - if (entry.length == entry.vpk_preloadedData.size()) { - return output; - } - - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry)), unbakedEntry.vpk_preloadedData.size()); - } - std::copy(unbakedData.begin(), unbakedData.end(), output.begin() + static_cast(entry.vpk_preloadedData.size())); - return output; - } - } - } - return std::nullopt; - } else if (entry.vpk_archiveIndex != VPK_DIR_INDEX) { - // Stored in a numbered archive - FileStream stream{this->getTruncatedFilepath() + '_' + ::padArchiveIndex(entry.vpk_archiveIndex) + (::isFPX(this) ? FPX_EXTENSION : VPK_EXTENSION).data()}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(entry.offset); - auto bytes = stream.readBytes(entry.length - entry.vpk_preloadedData.size()); - std::copy(bytes.begin(), bytes.end(), output.begin() + static_cast(entry.vpk_preloadedData.size())); - } else { - // Stored in this directory VPK - FileStream stream{this->fullFilePath}; - if (!stream) { - return std::nullopt; - } - stream.seekInput(this->getHeaderLength() + this->header1.treeSize + entry.offset); - auto bytes = stream.readBytes(entry.length - entry.vpk_preloadedData.size()); - std::copy(bytes.begin(), bytes.end(), output.begin() + static_cast(entry.vpk_preloadedData.size())); - } - - return output; -} - -Entry& VPK::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - entry.path = filename; - entry.crc32 = ::computeCRC32(buffer); - entry.length = buffer.size(); - - // Offset will be reset when it's baked, assuming we're not replacing an existing chunk (when flags = 1) - entry.flags = 0; - entry.offset = 0; - entry.vpk_archiveIndex = options_.vpk_saveToDirectory ? VPK_DIR_INDEX : this->numArchives; - if (!options_.vpk_saveToDirectory && !this->freedChunks.empty()) { - std::int64_t bestChunkIndex = -1; - std::size_t currentChunkGap = SIZE_MAX; - for (std::int64_t i = 0; i < this->freedChunks.size(); i++) { - if ( - (bestChunkIndex < 0 && this->freedChunks[i].length >= entry.length) || - (bestChunkIndex >= 0 && this->freedChunks[i].length >= entry.length && (this->freedChunks[i].length - entry.length) < currentChunkGap) - ) { - bestChunkIndex = i; - currentChunkGap = this->freedChunks[i].length - entry.length; - } - } - if (bestChunkIndex >= 0) { - entry.flags |= VPK_FLAG_REUSING_CHUNK; - entry.offset = this->freedChunks[bestChunkIndex].offset; - entry.vpk_archiveIndex = this->freedChunks[bestChunkIndex].archiveIndex; - this->freedChunks.erase(this->freedChunks.begin() + bestChunkIndex); - if (currentChunkGap < SIZE_MAX && currentChunkGap > 0) { - // Add the remaining free space as a free chunk - this->freedChunks.push_back({entry.offset + entry.length, currentChunkGap, entry.vpk_archiveIndex}); - } - } - } - - if (options_.vpk_preloadBytes > 0) { - auto clampedPreloadBytes = std::clamp(options_.vpk_preloadBytes, 0u, buffer.size() > VPK_MAX_PRELOAD_BYTES ? VPK_MAX_PRELOAD_BYTES : static_cast(buffer.size())); - entry.vpk_preloadedData.resize(clampedPreloadBytes); - std::memcpy(entry.vpk_preloadedData.data(), buffer.data(), clampedPreloadBytes); - buffer.erase(buffer.begin(), buffer.begin() + clampedPreloadBytes); - } - - // Now that archive index is calculated for this entry, check if it needs to be incremented - if (!options_.vpk_saveToDirectory && !(entry.flags & VPK_FLAG_REUSING_CHUNK)) { - entry.offset = this->currentlyFilledChunkSize; - this->currentlyFilledChunkSize += static_cast(buffer.size()); - if (this->options.vpk_preferredChunkSize) { - if (this->currentlyFilledChunkSize > this->options.vpk_preferredChunkSize) { - this->currentlyFilledChunkSize = 0; - this->numArchives++; - } - } - } - - if (!this->unbakedEntries.contains(dir)) { - this->unbakedEntries[dir] = {}; - } - this->unbakedEntries.at(dir).push_back(entry); - return this->unbakedEntries.at(dir).back(); -} - -bool VPK::removeEntry(const std::string& filename_) { - if (auto entry = this->findEntry(filename_); entry && (!entry->unbaked || entry->flags & VPK_FLAG_REUSING_CHUNK)) { - this->freedChunks.push_back({entry->offset, entry->length, entry->vpk_archiveIndex}); - } - return PackFile::removeEntry(filename_); -} - -bool VPK::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Reconstruct data so we're not looping over it a ton of times - std::unordered_map>> temp; - - for (auto& [tDir, tEntries] : this->entries) { - for (auto& tEntry : tEntries) { - std::string extension = tEntry.getExtension(); - if (extension.empty()) { - extension = " "; - } - if (!temp.contains(extension)) { - temp[extension] = {}; - } - if (!temp.at(extension).contains(tDir)) { - temp.at(extension)[tDir] = {}; - } - temp.at(extension).at(tDir).push_back(&tEntry); - } - } - for (auto& [tDir, tEntries]: this->unbakedEntries) { - for (auto& tEntry : tEntries) { - std::string extension = tEntry.getExtension(); - if (extension.empty()) { - extension = " "; - } - if (!temp.contains(extension)) { - temp[extension] = {}; - } - if (!temp.at(extension).contains(tDir)) { - temp.at(extension)[tDir] = {}; - } - temp.at(extension).at(tDir).push_back(&tEntry); - } - } - - // Temporarily store baked file data that's stored in the directory VPK since it's getting overwritten - std::vector dirVPKEntryData; - std::size_t newDirEntryOffset = 0; - for (auto& [tDir, tEntries] : this->entries) { - for (Entry& tEntry : tEntries) { - if (!tEntry.unbaked && tEntry.vpk_archiveIndex == VPK_DIR_INDEX && tEntry.length != tEntry.vpk_preloadedData.size()) { - auto binData = this->readEntry(tEntry); - if (!binData) { - continue; - } - dirVPKEntryData.reserve(dirVPKEntryData.size() + tEntry.length - tEntry.vpk_preloadedData.size()); - dirVPKEntryData.insert(dirVPKEntryData.end(), binData->begin() + static_cast::difference_type>(tEntry.vpk_preloadedData.size()), binData->end()); - - tEntry.offset = newDirEntryOffset; - newDirEntryOffset += tEntry.length - tEntry.vpk_preloadedData.size(); - } - } - } - - // Helper - const auto getArchiveFilename = [this](const std::string& filename_, int archiveIndex) { - std::string out{filename_ + '_' + ::padArchiveIndex(archiveIndex) + (::isFPX(this) ? FPX_EXTENSION : VPK_EXTENSION).data()}; - ::normalizeSlashes(out, false); - return out; - }; - - // Copy external binary blobs to the new dir - if (!outputDir.empty()) { - for (int archiveIndex = 0; archiveIndex < this->numArchives; archiveIndex++) { - std::string from = getArchiveFilename(this->getTruncatedFilepath(), archiveIndex); - if (!std::filesystem::exists(from)) { - continue; - } - std::string dest = getArchiveFilename(outputDir + '/' + this->getTruncatedFilestem(), archiveIndex); - if (from == dest) { - continue; - } - std::filesystem::copy_file(from, dest, std::filesystem::copy_options::overwrite_existing); - } - } - - FileStream outDir{outputPath, FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - outDir.seekInput(0); - outDir.seekOutput(0); - - // Dummy header - outDir.write(this->header1); - if (this->header1.version == 2) { - outDir.write(this->header2); - } - - // File tree data - for (auto& [ext, tDirs] : temp) { - outDir.write(ext); - - for (auto& [dir, tEntries] : tDirs) { - outDir.write(!dir.empty() ? dir : " "); - - for (auto* entry : tEntries) { - // Calculate entry offset if it's unbaked and upload the data - if (entry->unbaked) { - std::vector entryData; - if (isEntryUnbakedUsingByteBuffer(*entry)) { - entryData = std::get>(getEntryUnbakedData(*entry)); - } else { - entryData = ::readFileData(std::get(getEntryUnbakedData(*entry)), entry->vpk_preloadedData.size()); - } - - if (entry->length == entry->vpk_preloadedData.size()) { - // Override the archive index, no need for an archive VPK - entry->vpk_archiveIndex = VPK_DIR_INDEX; - entry->offset = dirVPKEntryData.size(); - } else if (entry->vpk_archiveIndex != VPK_DIR_INDEX && (entry->flags & VPK_FLAG_REUSING_CHUNK)) { - // The entry is replacing pre-existing data in a VPK archive - auto archiveFilename = getArchiveFilename(::removeVPKAndOrDirSuffix(outputPath, ::isFPX(this)), entry->vpk_archiveIndex); - FileStream stream{archiveFilename, FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.seekOutput(entry->offset); - stream.writeBytes(entryData); - } else if (entry->vpk_archiveIndex != VPK_DIR_INDEX) { - // The entry is being appended to a newly created VPK archive - auto archiveFilename = getArchiveFilename(::removeVPKAndOrDirSuffix(outputPath, ::isFPX(this)), entry->vpk_archiveIndex); - entry->offset = std::filesystem::exists(archiveFilename) ? std::filesystem::file_size(archiveFilename) : 0; - FileStream stream{archiveFilename, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_APPEND | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - stream.writeBytes(entryData); - } else { - // The entry will be added to the directory VPK - entry->offset = dirVPKEntryData.size(); - dirVPKEntryData.insert(dirVPKEntryData.end(), entryData.data(), entryData.data() + entryData.size()); - } - - // Clear flags - entry->flags = 0; - } - - outDir.write(entry->getStem()); - outDir.write(entry->crc32); - outDir.write(static_cast(entry->vpk_preloadedData.size())); - outDir.write(entry->vpk_archiveIndex); - outDir.write(static_cast(entry->offset)); - outDir.write(static_cast(entry->length - entry->vpk_preloadedData.size())); - outDir.write(VPK_ENTRY_TERM); - - if (!entry->vpk_preloadedData.empty()) { - outDir.writeBytes(entry->vpk_preloadedData); - } - - if (callback) { - callback(dir, *entry); - } - } - outDir.write('\0'); - } - outDir.write('\0'); - } - outDir.write('\0'); - - // Put files copied from the dir archive back - if (!dirVPKEntryData.empty()) { - outDir.writeBytes(dirVPKEntryData); - } - - // Merge unbaked into baked entries - this->mergeUnbakedEntries(); - - // Calculate Header1 - this->header1.treeSize = outDir.tellOutput() - dirVPKEntryData.size() - this->getHeaderLength(); - - // VPK v2 stuff - if (this->header1.version == 2) { - // Calculate hashes for all entries - this->md5Entries.clear(); - if (this->options.vpk_generateMD5Entries) { - for (const auto& [tDir, tEntries] : this->entries) { - for (const auto& tEntry : tEntries) { - // Believe it or not this should be safe to call by now - auto binData = this->readEntry(tEntry); - if (!binData) { - continue; - } - MD5Entry md5Entry{}; - md5Entry.archiveIndex = tEntry.vpk_archiveIndex; - md5Entry.length = tEntry.length - tEntry.vpk_preloadedData.size(); - md5Entry.offset = tEntry.offset; - md5Entry.checksum = ::computeMD5(*binData); - this->md5Entries.push_back(md5Entry); - } - } - } - - // Calculate Header2 - this->header2.fileDataSectionSize = dirVPKEntryData.size(); - this->header2.archiveMD5SectionSize = this->md5Entries.size() * sizeof(MD5Entry); - this->header2.otherMD5SectionSize = 48; - this->header2.signatureSectionSize = 0; - - // Calculate Footer2 - CryptoPP::Weak::MD5 wholeFileChecksumMD5; - { - // Only the tree is updated in the file right now - wholeFileChecksumMD5.Update(reinterpret_cast(&this->header1), sizeof(Header1)); - wholeFileChecksumMD5.Update(reinterpret_cast(&this->header2), sizeof(Header2)); - } - { - outDir.seekInput(sizeof(Header1) + sizeof(Header2)); - std::vector treeData = outDir.readBytes(this->header1.treeSize); - wholeFileChecksumMD5.Update(reinterpret_cast(treeData.data()), treeData.size()); - this->footer2.treeChecksum = ::computeMD5(treeData); - } - if (!dirVPKEntryData.empty()) { - wholeFileChecksumMD5.Update(reinterpret_cast(dirVPKEntryData.data()), dirVPKEntryData.size()); - } - { - wholeFileChecksumMD5.Update(reinterpret_cast(this->md5Entries.data()), this->md5Entries.size() * sizeof(MD5Entry)); - CryptoPP::Weak::MD5 md5EntriesChecksumMD5; - md5EntriesChecksumMD5.Update(reinterpret_cast(this->md5Entries.data()), this->md5Entries.size() * sizeof(MD5Entry)); - md5EntriesChecksumMD5.Final(reinterpret_cast(this->footer2.md5EntriesChecksum.data())); - } - wholeFileChecksumMD5.Update(reinterpret_cast(this->footer2.treeChecksum.data()), this->footer2.treeChecksum.size()); - wholeFileChecksumMD5.Update(reinterpret_cast(this->footer2.md5EntriesChecksum.data()), this->footer2.md5EntriesChecksum.size()); - wholeFileChecksumMD5.Final(reinterpret_cast(this->footer2.wholeFileChecksum.data())); - - // We can't recalculate the signature without the private key - this->footer2.publicKey.clear(); - this->footer2.signature.clear(); - } - - // Write new headers - outDir.seekOutput(0); - outDir.write(this->header1); - - // v2 adds the MD5 hashes and file signature - if (this->header1.version != 2) { - PackFile::setFullFilePath(outputDir); - return true; - } - - outDir.write(this->header2); - - // Add MD5 hashes - outDir.seekOutput(sizeof(Header1) + sizeof(Header2) + this->header1.treeSize + dirVPKEntryData.size()); - outDir.write(this->md5Entries); - outDir.writeBytes(this->footer2.treeChecksum); - outDir.writeBytes(this->footer2.md5EntriesChecksum); - outDir.writeBytes(this->footer2.wholeFileChecksum); - - // The signature section is not present - PackFile::setFullFilePath(outputDir); - return true; -} - -std::string VPK::getTruncatedFilestem() const { - std::string filestem = this->getFilestem(); - // This indicates it's a dir VPK, but some people ignore this convention... - if (filestem.length() >= 4 && filestem.substr(filestem.length() - 4) == (::isFPX(this) ? FPX_DIR_SUFFIX : VPK_DIR_SUFFIX)) { - filestem = filestem.substr(0, filestem.length() - 4); - } - return filestem; -} - -std::vector VPK::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH, VPK_PRELOADED_DATA_LENGTH, VPK_ARCHIVE_INDEX, CRC32}; -} - -VPK::operator std::string() const { - return PackFile::operator std::string() + - " | Version v" + std::to_string(this->header1.version); -} - -bool VPK::generateKeyPairFiles(const std::string& name) { - auto keys = ::computeSHA256KeyPair(1024); - { - auto privateKeyPath = name + ".privatekey.vdf"; - FileStream stream{privateKeyPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - - std::string output; - // Template size, remove %s and %s, add key sizes, add null terminator size - output.resize(VPK_KEYPAIR_PRIVATE_KEY_TEMPLATE.size() - 4 + keys.first.size() + keys.second.size() + 1); - if (std::sprintf(output.data(), VPK_KEYPAIR_PRIVATE_KEY_TEMPLATE.data(), keys.first.data(), keys.second.data()) < 0) { - return false; - } else { - output.pop_back(); - stream.write(output, false); - } - } - { - auto publicKeyPath = name + ".publickey.vdf"; - FileStream stream{publicKeyPath, FILESTREAM_OPT_WRITE | FILESTREAM_OPT_TRUNCATE | FILESTREAM_OPT_CREATE_IF_NONEXISTENT}; - - std::string output; - // Template size, remove %s, add key size, add null terminator size - output.resize(VPK_KEYPAIR_PUBLIC_KEY_TEMPLATE.size() - 2 + keys.second.size() + 1); - if (std::sprintf(output.data(), VPK_KEYPAIR_PUBLIC_KEY_TEMPLATE.data(), keys.second.data()) < 0) { - return false; - } else { - output.pop_back(); - stream.write(output, false); - } - } - return true; -} - -bool VPK::sign(const std::string& filename_) { - if (this->header1.version != 2 || !std::filesystem::exists(filename_) || std::filesystem::is_directory(filename_)) { - return false; - } - - auto fileData = ::readFileText(filename_); - - auto privateKeyHex = ::readValueForKeyInKV("rsa_private_key", fileData); - if (privateKeyHex.empty()) { - return false; - } - auto publicKeyHex = ::readValueForKeyInKV("rsa_public_key", fileData); - if (publicKeyHex.empty()) { - return false; - } - - return this->sign(::decodeHexString(privateKeyHex), ::decodeHexString(publicKeyHex)); -} - -bool VPK::sign(const std::vector& privateKey, const std::vector& publicKey) { - if (this->header1.version != 2) { - return false; - } - - this->header2.signatureSectionSize = this->footer2.publicKey.size() + this->footer2.signature.size() + sizeof(std::uint32_t) * 2; - { - FileStream stream{this->getFilepath().data(), FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE}; - stream.seekOutput(sizeof(Header1)); - stream.write(this->header2); - } - - auto dirFileBuffer = ::readFileData(this->getFilepath().data()); - if (dirFileBuffer.size() <= this->header2.signatureSectionSize) { - return false; - } - for (int i = 0; i < this->header2.signatureSectionSize; i++) { - dirFileBuffer.pop_back(); - } - this->footer2.publicKey = publicKey; - this->footer2.signature = ::signDataWithSHA256Key(dirFileBuffer, privateKey); - - { - FileStream stream{this->getFilepath().data(), FILESTREAM_OPT_READ | FILESTREAM_OPT_WRITE}; - stream.seekOutput(this->getHeaderLength() + this->header1.treeSize + this->header2.fileDataSectionSize + this->header2.archiveMD5SectionSize + this->header2.otherMD5SectionSize); - stream.write(static_cast(this->footer2.publicKey.size())); - stream.writeBytes(this->footer2.publicKey); - stream.write(static_cast(this->footer2.signature.size())); - stream.writeBytes(this->footer2.signature); - } - return true; -} - -std::uint32_t VPK::getVersion() const { - return this->header1.version; -} - -void VPK::setVersion(std::uint32_t version) { - if (::isFPX(this) || version == this->header1.version) { - return; - } - this->header1.version = version; - this->options.vpk_version = version; - - // Clearing these isn't necessary, but might as well - this->header2 = Header2{}; - this->footer2 = Footer2{}; - this->md5Entries.clear(); -} - -std::uint32_t VPK::getHeaderLength() const { - if (this->header1.version != 2) { - return sizeof(Header1); - } - return sizeof(Header1) + sizeof(Header2); -} diff --git a/src/lib/format/ZIP.cpp b/src/lib/format/ZIP.cpp deleted file mode 100644 index faddc2f6..00000000 --- a/src/lib/format/ZIP.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include - -#include -#include - -#include -#include -#ifdef VPKEDIT_ZIP_COMPRESSION -#include -#endif -#include -#include -#include - -#include -#include - -using namespace vpkedit; -using namespace vpkedit::detail; - -const std::string ZIP::TEMP_ZIP_PATH = (std::filesystem::temp_directory_path() / "tmp.zip").string(); - -ZIP::ZIP(const std::string& fullFilePath_, PackFileOptions options_) - : PackFile(fullFilePath_, options_) { - this->type = PackFileType::ZIP; -} - -ZIP::~ZIP() { - this->closeZIP(); -} - -std::unique_ptr ZIP::open(const std::string& path, PackFileOptions options, const Callback& callback) { - if (!std::filesystem::exists(path)) { - // File does not exist - return nullptr; - } - - auto* zip = new ZIP{path, options}; - auto packFile = std::unique_ptr(zip); - - if (!zip->openZIP(zip->fullFilePath)) { - return nullptr; - } - - for (auto code = mz_zip_goto_first_entry(zip->zipHandle); code == MZ_OK; code = mz_zip_goto_next_entry(zip->zipHandle)) { - mz_zip_file* fileInfo = nullptr; - if (mz_zip_entry_get_info(zip->zipHandle, &fileInfo)) { - return nullptr; - } - if (mz_zip_entry_is_dir(zip->zipHandle) == MZ_OK) { - continue; - } - - Entry entry = createNewEntry(); - entry.path = fileInfo->filename; - ::normalizeSlashes(entry.path); - if (!zip->isCaseSensitive()) { - ::toLowerCase(entry.path); - } - - entry.flags = fileInfo->compression_method; - entry.length = fileInfo->uncompressed_size; - entry.compressedLength = fileInfo->compressed_size; - entry.crc32 = fileInfo->crc; - - auto parentDir = std::filesystem::path{entry.path}.parent_path().string(); - ::normalizeSlashes(parentDir); - if (!zip->isCaseSensitive()) { - ::toLowerCase(parentDir); - } - if (!zip->entries.contains(parentDir)) { - zip->entries[parentDir] = {}; - } - zip->entries[parentDir].push_back(entry); - - if (callback) { - callback(parentDir, entry); - } - } - - return packFile; -} - -std::vector ZIP::verifyEntryChecksums() const { - return this->verifyEntryChecksumsUsingCRC32(); -} - -std::optional> ZIP::readEntry(const Entry& entry) const { - if (entry.unbaked) { - // Get the stored data - for (const auto& [unbakedEntryDir, unbakedEntryList] : this->unbakedEntries) { - for (const Entry& unbakedEntry : unbakedEntryList) { - if (unbakedEntry.path == entry.path) { - std::vector unbakedData; - if (isEntryUnbakedUsingByteBuffer(unbakedEntry)) { - unbakedData = std::get>(getEntryUnbakedData(unbakedEntry)); - } else { - unbakedData = ::readFileData(std::get(getEntryUnbakedData(unbakedEntry))); - } - return unbakedData; - } - } - } - return std::nullopt; - } - // It's baked into the file on disk - if (!this->streamOpen || !this->zipOpen) { - return std::nullopt; - } - if (mz_zip_locate_entry(this->zipHandle, entry.path.c_str(), !this->isCaseSensitive()) != MZ_OK) { - return std::nullopt; - } - if (mz_zip_entry_read_open(this->zipHandle, 0, nullptr) != MZ_OK) { - return std::nullopt; - } - std::vector out; - out.resize(entry.length); - mz_zip_entry_read(this->zipHandle, out.data(), static_cast(entry.length)); - mz_zip_entry_close(this->zipHandle); - return out; -} - -Entry& ZIP::addEntryInternal(Entry& entry, const std::string& filename_, std::vector& buffer, EntryOptions options_) { - auto filename = filename_; - if (!this->isCaseSensitive()) { - ::toLowerCase(filename); - } - auto [dir, name] = ::splitFilenameAndParentDir(filename); - - entry.path = filename; - entry.length = buffer.size(); - entry.compressedLength = 0; - entry.crc32 = ::computeCRC32(buffer); - - if (!this->unbakedEntries.contains(dir)) { - this->unbakedEntries[dir] = {}; - } - this->unbakedEntries.at(dir).push_back(entry); - return this->unbakedEntries.at(dir).back(); -} - -bool ZIP::bake(const std::string& outputDir_, const Callback& callback) { - // Get the proper file output folder - std::string outputDir = this->getBakeOutputDir(outputDir_); - std::string outputPath = outputDir + '/' + this->getFilename(); - - // Use temp folder so we can read from the current ZIP - if (!this->bakeTempZip(ZIP::TEMP_ZIP_PATH, callback)) { - return false; - } - this->mergeUnbakedEntries(); - - // Close our ZIP and reopen it - this->closeZIP(); - std::filesystem::rename(ZIP::TEMP_ZIP_PATH, outputPath); - if (!this->openZIP(outputPath)) { - return false; - } - PackFile::setFullFilePath(outputDir); - return true; -} - -std::vector ZIP::getSupportedEntryAttributes() const { - using enum Attribute; - return {LENGTH, CRC32}; -} - -#ifdef VPKEDIT_ZIP_COMPRESSION -std::uint16_t ZIP::getCompressionMethod() const { - return this->options.zip_compressionMethod; -} - -void ZIP::setCompressionMethod(std::uint16_t compressionMethod) { - this->options.zip_compressionMethod = compressionMethod; -} -#endif - -bool ZIP::bakeTempZip(const std::string& writeZipPath, const Callback& callback) { - void* writeStreamHandle; -#ifdef VPKEDIT_ZIP_COMPRESSION - if (this->options.zip_compressionMethod != MZ_COMPRESS_METHOD_STORE) { - writeStreamHandle = mz_stream_lzma_create(); - } else { -#endif - writeStreamHandle = mz_stream_os_create(); -#ifdef VPKEDIT_ZIP_COMPRESSION - } -#endif - if (mz_stream_open(writeStreamHandle, writeZipPath.c_str(), MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE)) { - return false; - } - - void* writeZipHandle = mz_zip_writer_create(); - if (mz_zip_writer_open(writeZipHandle, writeStreamHandle, 0)) { - return false; - } - -#ifdef VPKEDIT_ZIP_COMPRESSION - if (this->options.zip_compressionMethod != MZ_COMPRESS_METHOD_STORE) { - mz_zip_writer_set_compress_level(writeZipHandle, MZ_COMPRESS_LEVEL_DEFAULT); - mz_zip_writer_set_compress_method(writeZipHandle, MZ_COMPRESS_METHOD_LZMA); - } -#endif - - for (const auto& [entryDir, entries] : this->getBakedEntries()) { - for (const Entry& entry : entries) { - auto binData = this->readEntry(entry); - if (!binData) { - continue; - } - - mz_zip_file fileInfo; - std::memset(&fileInfo, 0, sizeof(mz_zip_entry)); - fileInfo.flag = MZ_ZIP_FLAG_DATA_DESCRIPTOR; - fileInfo.filename = entry.path.c_str(); - fileInfo.filename_size = entry.path.length(); - fileInfo.uncompressed_size = static_cast(entry.length); - fileInfo.compressed_size = static_cast(entry.compressedLength); - fileInfo.crc = entry.crc32; - fileInfo.compression_method = this->options.zip_compressionMethod; - if (mz_zip_writer_add_buffer(writeZipHandle, binData->data(), static_cast(binData->size()), &fileInfo)) { - return false; - } - - if (callback) { - callback(entry.getParentPath(), entry); - } - } - } - for (const auto& [entryDir, entries] : this->getUnbakedEntries()) { - for (const Entry& entry : entries) { - auto binData = this->readEntry(entry); - if (!binData) { - continue; - } - - mz_zip_entry fileInfo; - std::memset(&fileInfo, 0, sizeof(mz_zip_entry)); - fileInfo.filename = entry.path.c_str(); - fileInfo.filename_size = entry.path.length(); - fileInfo.uncompressed_size = static_cast(entry.length); - fileInfo.compressed_size = static_cast(entry.compressedLength); - fileInfo.crc = entry.crc32; - fileInfo.compression_method = this->options.zip_compressionMethod; - if (mz_zip_writer_add_buffer(writeZipHandle, binData->data(), static_cast(binData->size()), &fileInfo)) { - return false; - } - - if (callback) { - callback(entry.getParentPath(), entry); - } - } - } - - if (mz_zip_writer_close(writeZipHandle)) { - return false; - } - mz_zip_writer_delete(&writeZipHandle); - - if (mz_stream_close(writeStreamHandle)) { - return false; - } - mz_stream_delete(&writeStreamHandle); - - return true; -} - -bool ZIP::openZIP(std::string_view path) { - this->streamHandle = mz_stream_os_create(); - if (mz_stream_open(this->streamHandle, path.data(), MZ_OPEN_MODE_READ) != MZ_OK) { - return false; - } - this->streamOpen = true; - - this->zipHandle = mz_zip_create(); - if (mz_zip_open(this->zipHandle, this->streamHandle, MZ_OPEN_MODE_READ) != MZ_OK) { - return false; // No need to delete the stream, it's done when we destruct - } - this->zipOpen = true; - - return true; -} - -void ZIP::closeZIP() { - if (this->zipOpen) { - mz_zip_close(this->zipHandle); - mz_zip_delete(&this->zipHandle); - } - if (this->streamOpen) { - mz_stream_close(this->streamHandle); - mz_stream_delete(&this->streamHandle); - } -} diff --git a/src/lib/lang/c/Buffer.cpp b/src/lib/lang/c/Buffer.cpp deleted file mode 100644 index 4f87c93e..00000000 --- a/src/lib/lang/c/Buffer.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#include - -VPKEDIT_API VPKEdit_Buffer_t vpkedit_buffer_new(size_t size) { - VPKEdit_Buffer_t buffer; - if (size > 0) { - buffer.size = static_cast(size); - buffer.data = static_cast(std::malloc(sizeof(uint8_t) * size)); - } else { - buffer.size = 0; - buffer.data = nullptr; - } - return buffer; -} - -VPKEDIT_API void vpkedit_buffer_free(VPKEdit_Buffer_t* buffer) { - if (buffer->data) { - std::free(buffer->data); - buffer->data = nullptr; - } - buffer->size = 0; -} diff --git a/src/lib/lang/c/Entry.cpp b/src/lib/lang/c/Entry.cpp deleted file mode 100644 index c4088d8d..00000000 --- a/src/lib/lang/c/Entry.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include - -#include - -#include "Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API size_t vpkedit_entry_get_path(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getEntry(handle)->path, buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_entry_get_parent_path(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getEntry(handle)->getParentPath(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_entry_get_filename(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getEntry(handle)->getFilename(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_entry_get_stem(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getEntry(handle)->getStem(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_entry_get_extension(VPKEdit_EntryHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getEntry(handle)->getExtension(), buffer, bufferLen); -} - -VPKEDIT_API void vpkedit_entry_free(VPKEdit_EntryHandle_t* handle) { - VPKEDIT_EARLY_RETURN(handle); - - delete ::getEntry(*handle); - *handle = nullptr; -} - -VPKEDIT_API void vpkedit_entry_array_free(VPKEdit_EntryHandleArray_t* array) { - VPKEDIT_EARLY_RETURN(array); - - if (array->data) { - for (size_t i = 0; i < array->size; i++) { - if (auto*& entry = array->data[i]) { - vpkedit_entry_free(&entry); - } - } - std::free(array->data); - array->data = nullptr; - } - array->size = 0; -} - -VPKEDIT_API size_t vpkedit_virtual_entry_get_name(VPKEdit_VirtualEntryHandle_t* handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getVirtualEntry(handle)->name, buffer, bufferLen); -} - -VPKEDIT_API bool vpkedit_virtual_entry_is_writable(VPKEdit_VirtualEntryHandle_t* handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getVirtualEntry(handle)->writable; -} - -VPKEDIT_API void vpkedit_virtual_entry_free(VPKEdit_VirtualEntryHandle_t* handle) { - VPKEDIT_EARLY_RETURN(handle); - - delete ::getEntry(*handle); - *handle = nullptr; -} - -VPKEDIT_API void vpkedit_virtual_entry_array_free(VPKEdit_VirtualEntryHandleArray_t* array) { - VPKEDIT_EARLY_RETURN(array); - - if (array->data) { - for (size_t i = 0; i < array->size; i++) { - if (auto*& entry = array->data[i]) { - vpkedit_virtual_entry_free(&entry); - } - } - std::free(array->data); - array->data = nullptr; - } - array->size = 0; -} diff --git a/src/lib/lang/c/Helpers.cpp b/src/lib/lang/c/Helpers.cpp deleted file mode 100644 index 981f204e..00000000 --- a/src/lib/lang/c/Helpers.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "Helpers.hpp" - -#include - -#include - -using namespace vpkedit; - -PackFile* getPackFile(VPKEdit_PackFileHandle_t handle) { - return static_cast(handle); -} - -Entry* getEntry(VPKEdit_EntryHandle_t handle) { - return static_cast(handle); -} - -VirtualEntry* getVirtualEntry(VPKEdit_VirtualEntryHandle_t handle) { - return static_cast(handle); -} - -size_t writeStringToBuffer(std::string_view str, char* buffer, size_t bufferLen) { - if (str.length() >= bufferLen) { - std::memcpy(buffer, str.data(), bufferLen); - buffer[bufferLen - 1] = '\0'; - return bufferLen; - } - std::memcpy(buffer, str.data(), str.length()); - buffer[str.length()] = '\0'; - return str.length() - 1; -} - -size_t writeVectorToBuffer(const std::vector& vec, unsigned char* buffer, size_t bufferLen) { - if (vec.size() >= bufferLen) { - std::memcpy(buffer, vec.data(), bufferLen); - return bufferLen; - } - std::memcpy(buffer, vec.data(), vec.size()); - return vec.size(); -} - -VPKEdit_String_t createString(std::string_view str) { - auto newStr = vpkedit_string_new(str.size()); - std::memcpy(newStr.data, str.data(), str.size()); - return newStr; -} - -VPKEdit_Buffer_t createBuffer(const std::vector& vec) { - auto buf = vpkedit_buffer_new(vec.size()); - std::memcpy(buf.data, vec.data(), vec.size()); - return buf; -} - -VPKEdit_StringArray_t convertStringVector(const std::vector& stringVec) { - auto array = vpkedit_string_array_new(stringVec.size()); - for (size_t i = 0; i < stringVec.size(); i++) { - array.data[i] = static_cast(std::malloc(sizeof(char) * (stringVec[i].length() + 1))); - std::memcpy(array.data[i], stringVec[i].c_str(), stringVec[i].length()); - array.data[i][stringVec[i].length()] = '\0'; - } - return array; -} - -vpkedit::PackFileOptions convertOptionsFromC(VPKEdit_PackFileOptions_t options) { - return { - .gma_writeCRCs = options.gma_writeCRCs, - .vpk_version = options.vpk_version, - .vpk_preferredChunkSize = options.vpk_preferredChunkSize, - .vpk_generateMD5Entries = options.vpk_generateMD5Entries, - .zip_compressionMethod = options.zip_compressionMethod, - }; -} - -VPKEdit_PackFileOptions_t convertOptionsToC(vpkedit::PackFileOptions options) { - return { - .gma_writeCRCs = options.gma_writeCRCs, - .vpk_version = options.vpk_version, - .vpk_preferredChunkSize = options.vpk_preferredChunkSize, - .vpk_generateMD5Entries = options.vpk_generateMD5Entries, - .zip_compressionMethod = options.zip_compressionMethod, - }; -} diff --git a/src/lib/lang/c/Helpers.hpp b/src/lib/lang/c/Helpers.hpp deleted file mode 100644 index 7d01ad33..00000000 --- a/src/lib/lang/c/Helpers.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include - -namespace vpkedit { - -class Entry; -class PackFile; -class VirtualEntry; - -} // namespace vpkedit - -#define VPKEDIT_EARLY_RETURN(var) \ - do { \ - if (!var) { \ - return; \ - } \ - } while (0) - -#define VPKEDIT_EARLY_RETURN_VALUE(var, value) \ - do { \ - if (!var) { \ - return value; \ - } \ - } while (0) - -vpkedit::PackFile* getPackFile(VPKEdit_PackFileHandle_t handle); - -vpkedit::Entry* getEntry(VPKEdit_EntryHandle_t handle); - -vpkedit::VirtualEntry* getVirtualEntry(VPKEdit_VirtualEntryHandle_t handle); - -size_t writeStringToBuffer(std::string_view str, char* buffer, size_t bufferLen); - -size_t writeVectorToBuffer(const std::vector& vec, unsigned char* buffer, size_t bufferLen); - -VPKEdit_String_t createString(std::string_view str); - -VPKEdit_Buffer_t createBuffer(const std::vector& vec); - -VPKEdit_StringArray_t convertStringVector(const std::vector& stringVec); - -vpkedit::PackFileOptions convertOptionsFromC(VPKEdit_PackFileOptions_t options); - -VPKEdit_PackFileOptions_t convertOptionsToC(vpkedit::PackFileOptions options); diff --git a/src/lib/lang/c/PackFile.cpp b/src/lib/lang/c/PackFile.cpp deleted file mode 100644 index 0311a22b..00000000 --- a/src/lib/lang/c/PackFile.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include - -#include -#include -#include -#include - -#include - -#include "Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PackFile::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PackFile::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileType_e vpkedit_get_type(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_PACK_FILE_TYPE_UNKNOWN); - - return static_cast(::getPackFile(handle)->getType()); -} - -VPKEDIT_API VPKEdit_PackFileOptions_t vpkedit_get_options(VPKEdit_PackFileHandle_t handle) { - return ::convertOptionsToC(::getPackFile(handle)->getOptions()); -} - -VPKEDIT_API bool vpkedit_has_entry_checksums(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->hasEntryChecksums(); -} - -VPKEDIT_API VPKEdit_StringArray_t vpkedit_verify_entry_checksums(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_STRING_ARRAY_INVALID); - - return ::convertStringVector(::getPackFile(handle)->verifyEntryChecksums()); -} - -VPKEDIT_API bool vpkedit_has_file_checksum(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->hasFileChecksum(); -} - -VPKEDIT_API bool vpkedit_verify_file_checksum(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->verifyFileChecksum(); -} - -VPKEDIT_API bool vpkedit_has_file_signature(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->hasFileSignature(); -} - -VPKEDIT_API bool vpkedit_verify_file_signature(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->verifyFileSignature(); -} - -VPKEDIT_API bool vpkedit_is_case_sensitive(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->isCaseSensitive(); -} - -VPKEDIT_API VPKEdit_EntryHandle_t vpkedit_find_entry(VPKEdit_PackFileHandle_t handle, const char* filename, bool includeUnbaked) { - VPKEDIT_EARLY_RETURN_VALUE(handle, nullptr); - VPKEDIT_EARLY_RETURN_VALUE(filename, nullptr); - - auto entry = ::getPackFile(handle)->findEntry(filename, includeUnbaked); - if (!entry) { - return nullptr; - } - return new Entry(std::move(*entry)); -} - -VPKEDIT_API VPKEdit_Buffer_t vpkedit_read_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_BUFFER_INVALID); - VPKEDIT_EARLY_RETURN_VALUE(entry, VPKEDIT_BUFFER_INVALID); - - if (auto binary = ::getPackFile(handle)->readEntry(*::getEntry(entry))) { - return ::createBuffer(*binary); - } - return VPKEDIT_BUFFER_INVALID; -} - -VPKEDIT_API VPKEdit_String_t vpkedit_read_entry_text(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_STRING_INVALID); - VPKEDIT_EARLY_RETURN_VALUE(entry, VPKEDIT_STRING_INVALID); - - if (auto text = ::getPackFile(handle)->readEntryText(*::getEntry(entry))) { - return ::createString(*text); - } - return VPKEDIT_STRING_INVALID; -} - -VPKEDIT_API bool vpkedit_is_read_only(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - - return ::getPackFile(handle)->isReadOnly(); -} - -VPKEDIT_API void vpkedit_add_entry_from_file(VPKEdit_PackFileHandle_t handle, const char* filename, const char* pathToFile) { - VPKEDIT_EARLY_RETURN(handle); - VPKEDIT_EARLY_RETURN(filename); - VPKEDIT_EARLY_RETURN(pathToFile); - - ::getPackFile(handle)->addEntry(filename, pathToFile, {}); -} - -VPKEDIT_API void vpkedit_add_entry_from_mem(VPKEdit_PackFileHandle_t handle, const char* filename, const unsigned char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN(handle); - VPKEDIT_EARLY_RETURN(filename); - - ::getPackFile(handle)->addEntry(filename, reinterpret_cast(buffer), bufferLen, {}); -} - -VPKEDIT_API bool vpkedit_remove_entry(VPKEdit_PackFileHandle_t handle, const char* filename) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(filename, false); - - return ::getPackFile(handle)->removeEntry(filename); -} - -VPKEDIT_API bool vpkedit_bake(VPKEdit_PackFileHandle_t handle, const char* outputDir) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(outputDir, false); - - return ::getPackFile(handle)->bake(outputDir, nullptr); -} - -VPKEDIT_API bool vpkedit_extract_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_EntryHandle_t entry, const char* filePath) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(entry, false); - VPKEDIT_EARLY_RETURN_VALUE(filePath, false); - - return ::getPackFile(handle)->extractEntry(*::getEntry(entry), filePath); -} - -VPKEDIT_API bool vpkedit_extract_dir(VPKEdit_PackFileHandle_t handle, const char* dir, const char* outputDir) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(dir, false); - VPKEDIT_EARLY_RETURN_VALUE(outputDir, false); - - return ::getPackFile(handle)->extractDir(dir, outputDir); -} - -VPKEDIT_API bool vpkedit_extract_all(VPKEdit_PackFileHandle_t handle, const char* outputDir, bool createUnderPackFileDir) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(outputDir, false); - - return ::getPackFile(handle)->extractAll(outputDir, createUnderPackFileDir); -} - -VPKEDIT_API bool vpkedit_extract_all_if(VPKEdit_PackFileHandle_t handle, const char* outputDir, bool(*predicate)(VPKEdit_EntryHandle_t)) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(outputDir, false); - VPKEDIT_EARLY_RETURN_VALUE(predicate, false); - - return ::getPackFile(handle)->extractAll(outputDir, [predicate](const Entry& entry) { - return predicate(reinterpret_cast(const_cast(&entry))); - }); -} - -VPKEDIT_API VPKEdit_EntryHandleArray_t vpkedit_get_baked_entries(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_ENTRY_HANDLE_ARRAY_INVALID); - - std::vector heapEntries; - for (const auto& [dir, entries] : ::getPackFile(handle)->getBakedEntries()) { - for (const auto& entry : entries) { - heapEntries.push_back(new Entry{entry}); - } - } - - VPKEdit_EntryHandleArray_t array; - array.size = static_cast(heapEntries.size()); - array.data = static_cast(std::malloc(sizeof(VPKEdit_EntryHandle_t) * array.size)); - - for (size_t i = 0; i < array.size; i++) { - array.data[i] = heapEntries[i]; - } - return array; -} - -VPKEDIT_API VPKEdit_EntryHandleArray_t vpkedit_get_unbaked_entries(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_ENTRY_HANDLE_ARRAY_INVALID); - - std::vector heapEntries; - for (const auto& [dir, entries] : ::getPackFile(handle)->getUnbakedEntries()) { - for (const auto& entry : entries) { - heapEntries.push_back(new Entry{entry}); - } - } - - VPKEdit_EntryHandleArray_t array; - array.size = static_cast(heapEntries.size()); - array.data = static_cast(std::malloc(sizeof(VPKEdit_EntryHandle_t) * array.size)); - - for (size_t i = 0; i < array.size; i++) { - array.data[i] = heapEntries[i]; - } - return array; -} - -VPKEDIT_API size_t vpkedit_get_entry_count(VPKEdit_PackFileHandle_t handle, bool includeUnbaked) { - return ::getPackFile(handle)->getEntryCount(includeUnbaked); -} - -VPKEDIT_API VPKEdit_Buffer_t vpkedit_read_virtual_entry(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_BUFFER_INVALID); - VPKEDIT_EARLY_RETURN_VALUE(entry, VPKEDIT_BUFFER_INVALID); - - if (auto data = ::getPackFile(handle)->readVirtualEntry(*::getVirtualEntry(entry))) { - return ::createBuffer(*data); - } - return VPKEDIT_BUFFER_INVALID; -} - -VPKEDIT_API bool vpkedit_overwrite_virtual_entry_from_file(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry, const char* pathToFile) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(entry, false); - VPKEDIT_EARLY_RETURN_VALUE(pathToFile, false); - - return ::getPackFile(handle)->overwriteVirtualEntry(*::getVirtualEntry(entry), pathToFile); -} - -VPKEDIT_API bool vpkedit_overwrite_virtual_entry_from_mem(VPKEdit_PackFileHandle_t handle, VPKEdit_VirtualEntryHandle_t entry, const unsigned char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(entry, false); - - return ::getPackFile(handle)->overwriteVirtualEntry(*::getVirtualEntry(entry), buffer && bufferLen > 0 ? std::vector{reinterpret_cast(buffer), reinterpret_cast(buffer + bufferLen)} : std::vector{}); -} - -VPKEDIT_API VPKEdit_VirtualEntryHandleArray_t vpkedit_get_virtual_entries(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, VPKEDIT_VIRTUAL_ENTRY_HANDLE_ARRAY_INVALID); - - std::vector heapEntries; - for (const auto& entry : ::getPackFile(handle)->getVirtualEntries()) { - heapEntries.push_back(new VirtualEntry{entry}); - } - - VPKEdit_VirtualEntryHandleArray_t array; - array.size = static_cast(heapEntries.size()); - array.data = static_cast(std::malloc(sizeof(VPKEdit_VirtualEntryHandle_t) * array.size)); - - for (size_t i = 0; i < array.size; i++) { - array.data[i] = heapEntries[i]; - } - return array; -} - -VPKEDIT_API size_t vpkedit_get_filepath(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getFilepath(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_truncated_filepath(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getTruncatedFilepath(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_filename(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getFilename(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_truncated_filename(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getTruncatedFilename(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_filestem(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getFilestem(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_truncated_filestem(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(::getPackFile(handle)->getTruncatedFilestem(), buffer, bufferLen); -} - -VPKEDIT_API size_t vpkedit_get_supported_entry_attributes(VPKEdit_PackFileHandle_t handle, VPKEdit_Attribute_e* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - auto attrs = ::getPackFile(handle)->getSupportedEntryAttributes(); - for (size_t i = 0; i < bufferLen; i++) { - if (i < attrs.size()) { - buffer[i] = static_cast(attrs[i]); - } else { - buffer[i] = VPKEDIT_ATTRIBUTE_NONE; - } - } - return std::min(attrs.size(), bufferLen); -} - -VPKEDIT_API size_t vpkedit_to_string(VPKEdit_PackFileHandle_t handle, char* buffer, size_t bufferLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - VPKEDIT_EARLY_RETURN_VALUE(buffer, 0); - VPKEDIT_EARLY_RETURN_VALUE(bufferLen, 0); - - return ::writeStringToBuffer(std::string{*::getPackFile(handle)}, buffer, bufferLen); -} - -VPKEDIT_API void vpkedit_close(VPKEdit_PackFileHandle_t* handle) { - VPKEDIT_EARLY_RETURN(handle); - - std::default_delete()(::getPackFile(*handle)); - *handle = nullptr; -} - -VPKEDIT_API VPKEdit_String_t vpkedit_escape_entry_path(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, VPKEDIT_STRING_INVALID); - - return ::createString(PackFile::escapeEntryPath(path)); -} - -VPKEDIT_API VPKEdit_StringArray_t vpkedit_get_supported_file_types() { - return ::convertStringVector(PackFile::getSupportedFileTypes()); -} diff --git a/src/lib/lang/c/String.cpp b/src/lib/lang/c/String.cpp deleted file mode 100644 index 1625a1e4..00000000 --- a/src/lib/lang/c/String.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include - -#include - -VPKEDIT_API VPKEdit_String_t vpkedit_string_new(size_t size) { - VPKEdit_String_t str; - if (size > 0) { - str.size = static_cast(size); - str.data = static_cast(std::malloc(sizeof(char) * (size + 1))); - str.data[size] = '\0'; - } else { - str.size = 0; - str.data = nullptr; - } - return str; -} - -VPKEDIT_API void vpkedit_string_free(VPKEdit_String_t* str) { - if (str->data) { - std::free(str->data); - str->data = nullptr; - } - str->size = 0; -} - -VPKEDIT_API VPKEdit_StringArray_t vpkedit_string_array_new(size_t size) { - VPKEdit_StringArray_t array; - if (size > 0) { - array.size = static_cast(size); - array.data = static_cast(std::malloc(sizeof(char*) * size)); - } else { - array.size = 0; - array.data = nullptr; - } - return array; -} - -VPKEDIT_API void vpkedit_string_array_free(VPKEdit_StringArray_t* array) { - if (array->data) { - for (size_t i = 0; i < array->size; i++) { - if (char* str = array->data[i]) { - std::free(str); - array->data[i] = nullptr; - } - } - std::free(array->data); - array->data = nullptr; - } - array->size = 0; -} diff --git a/src/lib/lang/c/_c.cmake b/src/lib/lang/c/_c.cmake deleted file mode 100644 index 372715ce..00000000 --- a/src/lib/lang/c/_c.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# Configure version header -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Version.h.in" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Version.h") - -add_library( - lib${PROJECT_NAME}c SHARED - - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/BSP.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/FPX.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/GCF.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/GMA.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/GRP.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/PAK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/PCK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/VPK.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/format/ZIP.h" - - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/API.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Attribute.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Buffer.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Entry.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Options.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/PackFile.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/PackFileType.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/String.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vpkeditc/Version.h" - - "${CMAKE_CURRENT_LIST_DIR}/format/BSP.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/FPX.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GCF.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GMA.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/GRP.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/PAK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/PCK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/VPK.cpp" - "${CMAKE_CURRENT_LIST_DIR}/format/ZIP.cpp" - - "${CMAKE_CURRENT_LIST_DIR}/Buffer.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Entry.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Helpers.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Helpers.hpp" - "${CMAKE_CURRENT_LIST_DIR}/PackFile.cpp" - "${CMAKE_CURRENT_LIST_DIR}/String.cpp") - -vpkedit_configure_target(lib${PROJECT_NAME}c) - -set_target_properties(lib${PROJECT_NAME}c PROPERTIES PREFIX "") - -target_link_libraries(lib${PROJECT_NAME}c PUBLIC lib${PROJECT_NAME}) diff --git a/src/lib/lang/c/format/BSP.cpp b/src/lib/lang/c/format/BSP.cpp deleted file mode 100644 index a73dc570..00000000 --- a/src/lib/lang/c/format/BSP.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_bsp_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = BSP::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_bsp_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = BSP::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/FPX.cpp b/src/lib/lang/c/format/FPX.cpp deleted file mode 100644 index 6da38aa6..00000000 --- a/src/lib/lang/c/format/FPX.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_fpx_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = FPX::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_fpx_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = FPX::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/GCF.cpp b/src/lib/lang/c/format/GCF.cpp deleted file mode 100644 index 80f13949..00000000 --- a/src/lib/lang/c/format/GCF.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gcf_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GCF::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gcf_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GCF::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/GMA.cpp b/src/lib/lang/c/format/GMA.cpp deleted file mode 100644 index f35f33d6..00000000 --- a/src/lib/lang/c/format/GMA.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gma_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GMA::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_gma_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GMA::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/GRP.cpp b/src/lib/lang/c/format/GRP.cpp deleted file mode 100644 index 2e84aaf1..00000000 --- a/src/lib/lang/c/format/GRP.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_grp_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GRP::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_grp_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = GRP::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/PAK.cpp b/src/lib/lang/c/format/PAK.cpp deleted file mode 100644 index 9ea8e319..00000000 --- a/src/lib/lang/c/format/PAK.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pak_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PAK::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pak_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PAK::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/PCK.cpp b/src/lib/lang/c/format/PCK.cpp deleted file mode 100644 index 2efbfb17..00000000 --- a/src/lib/lang/c/format/PCK.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pck_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PCK::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_pck_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PCK::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/c/format/VPK.cpp b/src/lib/lang/c/format/VPK.cpp deleted file mode 100644 index 7e2b8d3d..00000000 --- a/src/lib/lang/c/format/VPK.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_empty(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = VPK::createEmpty(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_empty_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = PackFile::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_from_directory(const char* vpkPath, const char* contentPath, bool saveToDir) { - VPKEDIT_EARLY_RETURN_VALUE(vpkPath, nullptr); - VPKEDIT_EARLY_RETURN_VALUE(contentPath, nullptr); - - auto packFile = VPK::createFromDirectory(vpkPath, contentPath, saveToDir); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_create_from_directory_with_options(const char* vpkPath, const char* contentPath, bool saveToDir, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(vpkPath, nullptr); - VPKEDIT_EARLY_RETURN_VALUE(contentPath, nullptr); - - auto packFile = VPK::createFromDirectory(vpkPath, contentPath, saveToDir, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = VPK::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_vpk_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = VPK::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API bool vpkedit_vpk_generate_keypair_files(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, false); - - return VPK::generateKeyPairFiles(path); -} - -VPKEDIT_API bool vpkedit_vpk_sign_from_file(VPKEdit_PackFileHandle_t handle, const char* filename) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(filename, false); - - auto* vpk = ::getPackFile(handle); - if (vpk->getType() != PackFileType::VPK) { - return false; - } - return dynamic_cast(vpk)->sign(filename); -} - -VPKEDIT_API bool vpkedit_vpk_sign_from_mem(VPKEdit_PackFileHandle_t handle, const unsigned char* privateKeyBuffer, size_t privateKeyLen, const unsigned char* publicKeyBuffer, size_t publicKeyLen) { - VPKEDIT_EARLY_RETURN_VALUE(handle, false); - VPKEDIT_EARLY_RETURN_VALUE(privateKeyBuffer, false); - VPKEDIT_EARLY_RETURN_VALUE(privateKeyLen, false); - VPKEDIT_EARLY_RETURN_VALUE(publicKeyBuffer, false); - VPKEDIT_EARLY_RETURN_VALUE(publicKeyLen, false); - - auto* vpk = ::getPackFile(handle); - if (vpk->getType() != PackFileType::VPK) { - return false; - } - return dynamic_cast(vpk)->sign( - {reinterpret_cast(privateKeyBuffer), reinterpret_cast(privateKeyBuffer + privateKeyLen)}, - {reinterpret_cast(publicKeyBuffer), reinterpret_cast(publicKeyBuffer + publicKeyLen)}); -} - -VPKEDIT_API uint32_t vpkedit_vpk_get_version(VPKEdit_PackFileHandle_t handle) { - VPKEDIT_EARLY_RETURN_VALUE(handle, 0); - - auto* vpk = ::getPackFile(handle); - if (vpk->getType() != PackFileType::VPK) { - return 0; - } - return dynamic_cast(vpk)->getVersion(); -} - -VPKEDIT_API void vpkedit_vpk_set_version(VPKEdit_PackFileHandle_t handle, uint32_t version) { - VPKEDIT_EARLY_RETURN(handle); - - auto* vpk = ::getPackFile(handle); - if (vpk->getType() != PackFileType::VPK) { - return; - } - dynamic_cast(vpk)->setVersion(version); -} diff --git a/src/lib/lang/c/format/ZIP.cpp b/src/lib/lang/c/format/ZIP.cpp deleted file mode 100644 index ab852fcd..00000000 --- a/src/lib/lang/c/format/ZIP.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -#include "../Helpers.hpp" - -using namespace vpkedit; - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_zip_open(const char* path) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = ZIP::open(path); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} - -VPKEDIT_API VPKEdit_PackFileHandle_t vpkedit_zip_open_with_options(const char* path, VPKEdit_PackFileOptions_t options) { - VPKEDIT_EARLY_RETURN_VALUE(path, nullptr); - - auto packFile = ZIP::open(path, ::convertOptionsFromC(options)); - if (!packFile) { - return nullptr; - } - return packFile.release(); -} diff --git a/src/lib/lang/csharp/libvpkedit.sln b/src/lib/lang/csharp/libvpkedit.sln deleted file mode 100644 index 852f3ebf..00000000 --- a/src/lib/lang/csharp/libvpkedit.sln +++ /dev/null @@ -1,33 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.9.34622.214 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libvpkedit", "libvpkedit\libvpkedit.csproj", "{EA9C7AA7-6C04-433B-8F64-E38462E88CA6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libvpkedit.test", "libvpkedit.test\libvpkedit.test.csproj", "{3BCD0725-785C-41E6-956F-39E25AAA5D4E}" - ProjectSection(ProjectDependencies) = postProject - {EA9C7AA7-6C04-433B-8F64-E38462E88CA6} = {EA9C7AA7-6C04-433B-8F64-E38462E88CA6} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EA9C7AA7-6C04-433B-8F64-E38462E88CA6}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {EA9C7AA7-6C04-433B-8F64-E38462E88CA6}.Debug|Any CPU.Build.0 = Release|Any CPU - {EA9C7AA7-6C04-433B-8F64-E38462E88CA6}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {EA9C7AA7-6C04-433B-8F64-E38462E88CA6}.Release|Any CPU.Build.0 = Debug|Any CPU - {3BCD0725-785C-41E6-956F-39E25AAA5D4E}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {3BCD0725-785C-41E6-956F-39E25AAA5D4E}.Debug|Any CPU.Build.0 = Release|Any CPU - {3BCD0725-785C-41E6-956F-39E25AAA5D4E}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {3BCD0725-785C-41E6-956F-39E25AAA5D4E}.Release|Any CPU.Build.0 = Debug|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {834412F6-B5A0-43C5-A2E2-71B8352629B9} - EndGlobalSection -EndGlobal diff --git a/src/lib/lang/csharp/libvpkedit.test/PackFileTest.cs b/src/lib/lang/csharp/libvpkedit.test/PackFileTest.cs deleted file mode 100644 index accfd78d..00000000 --- a/src/lib/lang/csharp/libvpkedit.test/PackFileTest.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.test -{ - [TestClass] - public class PackFileTest - { - [TestMethod] - public void Open() - { - var vpk = PackFile.Open(BasePortalPath + "portal_pak_dir.vpk"); - Assert.IsNotNull(vpk); - Assert.AreEqual(vpk.Type, PackFileType.VPK); - - Assert.IsFalse(vpk.CaseSensitive); - - var entry = vpk.FindEntry("materials/console/background1.vmt"); - Assert.IsNotNull(entry); - Assert.AreEqual(vpk.ReadEntryText(entry), "\"UnlitGeneric\"\r\n{\r\n\t\"$basetexture\" \"console/background1\"\r\n\t\"$vertexcolor\" 1\r\n\t\"$vertexalpha\" 1\r\n\t\"$ignorez\" 1\r\n\t\"$no_fullbright\" \"1\"\r\n\t\"$nolod\" \"1\"\r\n}"); - - Assert.IsFalse(vpk.ReadOnly); - - foreach(var baked in vpk.GetBakedEntries()) - { - Console.WriteLine(baked.Path); - } - - Assert.AreEqual(vpk.GetEntryCount(), 3509u); - - Assert.AreEqual(vpk.FilePath, BasePortalPath + "portal_pak_dir.vpk"); - Assert.AreEqual(vpk.TruncatedFilePath, BasePortalPath + "portal_pak"); - Assert.AreEqual(vpk.FileName, "portal_pak_dir.vpk"); - Assert.AreEqual(vpk.TruncatedFileName, "portal_pak.vpk"); - Assert.AreEqual(vpk.FileStem, "portal_pak_dir"); - Assert.AreEqual(vpk.TruncatedFileStem, "portal_pak"); - - CollectionAssert.AreEqual(vpk.SupportedEntryAttributes, new List - { - Attribute.LENGTH, Attribute.VPK_PRELOADED_DATA_LENGTH, Attribute.VPK_ARCHIVE_INDEX, Attribute.CRC32 - }); - - Assert.AreEqual(vpk.ToString(), "portal_pak_dir.vpk | Version v2"); - } - - [TestMethod] - public void VerifyChecksums() - { - var vpk = PackFile.Open(BasePortalPath + "portal_pak_dir.vpk"); - Assert.IsNotNull(vpk); - Assert.AreEqual(vpk.VerifyEntryChecksums().Count(), 0); - Assert.IsTrue(vpk.VerifyFileChecksum()); - } - - [TestMethod] - public void GetSupportedFileTypes() - { - // 15 as of v4.1.2 - Assert.AreEqual(PackFile.GetSupportedFileTypes().Count, 15); - } - - [TestMethod] - public void GetVPKVersion() - { - var vpk = Format.VPK.Open(BasePortalPath + "portal_pak_dir.vpk"); - Assert.IsNotNull(vpk); - Assert.AreEqual(vpk.Version, 2u); - } - - private static string BasePortalPath - { - get - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return @"C:\Program Files (x86)\Steam\steamapps\common\Portal\portal\"; - } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return Environment.GetEnvironmentVariable("HOME") + "/.steam/steam/steamapps/common/Portal/portal/"; - } - throw new FileLoadException("Unable to find Steam install directory!"); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit.test/libvpkedit.test.csproj b/src/lib/lang/csharp/libvpkedit.test/libvpkedit.test.csproj deleted file mode 100644 index 47e5fffc..00000000 --- a/src/lib/lang/csharp/libvpkedit.test/libvpkedit.test.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - net8.0 - enable - enable - - false - true - - - - - - - - - - - - - - - - - - diff --git a/src/lib/lang/csharp/libvpkedit/Attribute.cs b/src/lib/lang/csharp/libvpkedit/Attribute.cs deleted file mode 100644 index 5be7a660..00000000 --- a/src/lib/lang/csharp/libvpkedit/Attribute.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace libvpkedit -{ - public enum Attribute - { - NONE = -1, - LENGTH = 0, - VPK_PRELOADED_DATA_LENGTH, - VPK_ARCHIVE_INDEX, - CRC32, - PCK_MD5, - COUNT, - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Buffer.cs b/src/lib/lang/csharp/libvpkedit/Buffer.cs deleted file mode 100644 index 5344bf2f..00000000 --- a/src/lib/lang/csharp/libvpkedit/Buffer.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace libvpkedit -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern Buffer vpkedit_buffer_new(ulong size); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_buffer_free(Buffer* str); - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Buffer - { - public long size; - public unsafe byte* data; - } - - internal static unsafe class BufferUtils - { - public static byte[] ConvertToArrayAndDelete(ref Buffer buffer) - { - var result = new Span(buffer.data, (int) buffer.size).ToArray(); - - fixed (Buffer* bufferPtr = &buffer) - { - Extern.vpkedit_buffer_free(bufferPtr); - } - - return result; - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Constants.cs b/src/lib/lang/csharp/libvpkedit/Constants.cs deleted file mode 100644 index 19ceb95a..00000000 --- a/src/lib/lang/csharp/libvpkedit/Constants.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace libvpkedit -{ - internal static class Constants - { - public const int MaxPath = 4096; // This seems reasonable - - public const int MaxFilename = 1024; // Again, seems reasonable - - public const int MaxPackFileString = 256; // Definitely works - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Entry.cs b/src/lib/lang/csharp/libvpkedit/Entry.cs deleted file mode 100644 index cff2a789..00000000 --- a/src/lib/lang/csharp/libvpkedit/Entry.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace libvpkedit -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_entry_get_path(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_entry_get_parent_path(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_entry_get_filename(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_entry_get_stem(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_entry_get_extension(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_entry_free(void** handle); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_entry_array_free(EntryHandleArray* array); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_virtual_entry_get_name(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_virtual_entry_is_writable(void* handle); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_virtual_entry_free(void** handle); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_virtual_entry_array_free(VirtualEntryHandleArray* array); - } - - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct EntryHandleArray - { - internal long size; - internal void** data; - } - - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct VirtualEntryHandleArray - { - internal long size; - internal void** data; - } - - public class Entry - { - internal unsafe Entry(void* handle, bool inArray) - { - Handle = handle; - _inArray = inArray; - } - - ~Entry() - { - if (!_inArray) - { - unsafe - { - fixed (void** handlePtr = &Handle) - { - Extern.vpkedit_entry_free(handlePtr); - } - } - } - } - - public string Path - { - get - { - Span stringArray = new sbyte[Constants.MaxPath]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_entry_get_path(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string ParentPath - { - get - { - Span stringArray = new sbyte[Constants.MaxPath]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_entry_get_parent_path(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string FileName - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_entry_get_filename(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string Stem - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_entry_get_stem(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string Extension - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_entry_get_extension(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - internal unsafe void* Handle; - - private readonly bool _inArray; - } - - public class EntryEnumerable : IEnumerable - { - internal EntryEnumerable(EntryHandleArray array) - { - _array = array; - } - - ~EntryEnumerable() - { - unsafe - { - fixed (EntryHandleArray* arrayPtr = &_array) - { - Extern.vpkedit_entry_array_free(arrayPtr); - } - } - } - - private Entry GetEntryAtPosition(ulong pos) - { - unsafe - { - return new Entry(_array.data[pos], true); - } - } - - private IEnumerator GetEnumerator() - { - for (long i = 0; i < _array.size; i++) - { - yield return GetEntryAtPosition((ulong) i); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - private EntryHandleArray _array; - } - - public class VirtualEntry - { - internal unsafe VirtualEntry(void* handle, bool inArray) - { - Handle = handle; - _inArray = inArray; - } - - ~VirtualEntry() - { - if (!_inArray) - { - unsafe - { - fixed (void** handlePtr = &Handle) - { - Extern.vpkedit_virtual_entry_free(handlePtr); - } - } - } - } - - public string Name - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_virtual_entry_get_name(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public bool Writable - { - get - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_virtual_entry_is_writable(Handle)); - } - } - } - - internal unsafe void* Handle; - - private readonly bool _inArray; - } - - public class VirtualEntryEnumerable : IEnumerable - { - internal VirtualEntryEnumerable(VirtualEntryHandleArray array) - { - _array = array; - } - - ~VirtualEntryEnumerable() - { - unsafe - { - fixed (VirtualEntryHandleArray* arrayPtr = &_array) - { - Extern.vpkedit_virtual_entry_array_free(arrayPtr); - } - } - } - - private VirtualEntry GetVirtualEntryAtPosition(ulong pos) - { - unsafe - { - return new VirtualEntry(_array.data[pos], true); - } - } - - private IEnumerator GetEnumerator() - { - for (long i = 0; i < _array.size; i++) - { - yield return GetVirtualEntryAtPosition((ulong) i); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - private VirtualEntryHandleArray _array; - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/BSP.cs b/src/lib/lang/csharp/libvpkedit/Format/BSP.cs deleted file mode 100644 index 42ef26db..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/BSP.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_bsp_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_bsp_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class BSP : PackFile - { - private protected unsafe BSP(void* handle) : base(handle) {} - - public new static BSP? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_bsp_open(path); - return handle == null ? null : new BSP(handle); - } - } - - public new static BSP? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_bsp_open_with_options(path, options); - return handle == null ? null : new BSP(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/FPX.cs b/src/lib/lang/csharp/libvpkedit/Format/FPX.cs deleted file mode 100644 index 94faacb7..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/FPX.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_fpx_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_fpx_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class FPX : PackFile - { - private protected unsafe FPX(void* handle) : base(handle) {} - - public new static FPX? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_fpx_open(path); - return handle == null ? null : new FPX(handle); - } - } - - public new static FPX? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_fpx_open_with_options(path, options); - return handle == null ? null : new FPX(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/GCF.cs b/src/lib/lang/csharp/libvpkedit/Format/GCF.cs deleted file mode 100644 index 05ba03ec..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/GCF.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_gcf_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_gcf_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class GCF : PackFile - { - private protected unsafe GCF(void* handle) : base(handle) {} - - public new static GCF? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_gcf_open(path); - return handle == null ? null : new GCF(handle); - } - } - - public new static GCF? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_gcf_open_with_options(path, options); - return handle == null ? null : new GCF(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/GMA.cs b/src/lib/lang/csharp/libvpkedit/Format/GMA.cs deleted file mode 100644 index 5e6ee378..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/GMA.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_gma_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_gma_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class GMA : PackFile - { - private protected unsafe GMA(void* handle) : base(handle) {} - - public new static GMA? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_gma_open(path); - return handle == null ? null : new GMA(handle); - } - } - - public new static GMA? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_gma_open_with_options(path, options); - return handle == null ? null : new GMA(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/GRP.cs b/src/lib/lang/csharp/libvpkedit/Format/GRP.cs deleted file mode 100644 index 6f623394..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/GRP.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_grp_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_grp_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class GRP : PackFile - { - private protected unsafe GRP(void* handle) : base(handle) {} - - public new static GRP? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_grp_open(path); - return handle == null ? null : new GRP(handle); - } - } - - public new static GRP? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_grp_open_with_options(path, options); - return handle == null ? null : new GRP(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/PAK.cs b/src/lib/lang/csharp/libvpkedit/Format/PAK.cs deleted file mode 100644 index 6beb9ba4..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/PAK.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_pak_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_pak_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class PAK : PackFile - { - private protected unsafe PAK(void* handle) : base(handle) {} - - public new static PAK? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_pak_open(path); - return handle == null ? null : new PAK(handle); - } - } - - public new static PAK? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_pak_open_with_options(path, options); - return handle == null ? null : new PAK(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/PCK.cs b/src/lib/lang/csharp/libvpkedit/Format/PCK.cs deleted file mode 100644 index c0fe6414..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/PCK.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_pck_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_pck_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class PCK : PackFile - { - private protected unsafe PCK(void* handle) : base(handle) {} - - public new static PCK? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_pck_open(path); - return handle == null ? null : new PCK(handle); - } - } - - public new static PCK? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_pck_open_with_options(path, options); - return handle == null ? null : new PCK(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/VPK.cs b/src/lib/lang/csharp/libvpkedit/Format/VPK.cs deleted file mode 100644 index 14ec758f..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/VPK.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_create_empty([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_create_empty_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_create_from_directory([MarshalAs(UnmanagedType.LPStr)] string vpkPath, [MarshalAs(UnmanagedType.LPStr)] string contentPath, byte saveToDir); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_create_from_directory_with_options([MarshalAs(UnmanagedType.LPStr)] string vpkPath, [MarshalAs(UnmanagedType.LPStr)] string contentPath, byte saveToDir, PackFileOptions options); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_vpk_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_vpk_generate_keypair_files([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_vpk_sign_from_file(void* handle, [MarshalAs(UnmanagedType.LPStr)] string filepath); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_vpk_sign_from_mem(void* handle, byte* privateKeyBuffer, ulong privateKeyLen, byte* publicKeyBuffer, ulong publicKeyLen); - - [DllImport("libvpkeditc")] - public static extern uint vpkedit_vpk_get_version(void* handle); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_vpk_set_version(void* handle, uint version); - } - - public class VPK : PackFile - { - private unsafe VPK(void* handle) : base(handle) {} - - public static VPK? CreateEmpty(string path) - { - unsafe - { - var handle = Extern.vpkedit_vpk_create_empty(path); - return handle == null ? null : new VPK(handle); - } - } - - public static VPK? CreateEmpty(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_vpk_create_empty_with_options(path, options); - return handle == null ? null : new VPK(handle); - } - } - - public static VPK? CreateFromDirectory(string vpkPath, string contentPath, bool saveToDir = false) - { - unsafe - { - var handle = Extern.vpkedit_vpk_create_from_directory(vpkPath, contentPath, Convert.ToByte(saveToDir)); - return handle == null ? null : new VPK(handle); - } - } - - public static VPK? CreateFromDirectory(string vpkPath, string contentPath, PackFileOptions options, bool saveToDir = false) - { - unsafe - { - var handle = Extern.vpkedit_vpk_create_from_directory_with_options(vpkPath, contentPath, Convert.ToByte(saveToDir), options); - return handle == null ? null : new VPK(handle); - } - } - - public new static VPK? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_vpk_open(path); - return handle == null ? null : new VPK(handle); - } - } - - public new static VPK? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_vpk_open_with_options(path, options); - return handle == null ? null : new VPK(handle); - } - } - - public static bool GenerateKeyPairFiles(string path) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_vpk_generate_keypair_files(path)); - } - } - - public bool Sign(string filepath) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_vpk_sign_from_file(Handle, filepath)); - } - } - - public bool Sign(byte[] privateKey, byte[] publicKey) - { - unsafe - { - fixed (byte* privateKeyBufferPtr = privateKey) - { - fixed (byte* publicKeyBufferPtr = publicKey) - { - return Convert.ToBoolean(Extern.vpkedit_vpk_sign_from_mem(Handle, privateKeyBufferPtr, (ulong) privateKey.LongLength, publicKeyBufferPtr, (ulong) publicKey.LongLength)); - } - } - } - } - - public bool Sign(IEnumerable privateKey, IEnumerable publicKey) - { - var privateKeyData = privateKey.ToArray(); - var publicKeyData = publicKey.ToArray(); - unsafe - { - fixed (byte* privateKeyBufferPtr = privateKeyData) - { - fixed (byte* publicKeyBufferPtr = publicKeyData) - { - return Convert.ToBoolean(Extern.vpkedit_vpk_sign_from_mem(Handle, privateKeyBufferPtr, (ulong) privateKeyData.LongLength, publicKeyBufferPtr, (ulong) publicKeyData.LongLength)); - } - } - } - } - - public uint Version - { - get - { - unsafe - { - return Extern.vpkedit_vpk_get_version(Handle); - } - } - set - { - unsafe - { - Extern.vpkedit_vpk_set_version(Handle, Math.Clamp(value, 1, 2)); - } - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Format/ZIP.cs b/src/lib/lang/csharp/libvpkedit/Format/ZIP.cs deleted file mode 100644 index 3180bfbf..00000000 --- a/src/lib/lang/csharp/libvpkedit/Format/ZIP.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit.Format -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_zip_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_zip_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - } - - public class ZIP : PackFile - { - private protected unsafe ZIP(void* handle) : base(handle) {} - - public new static ZIP? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_zip_open(path); - return handle == null ? null : new ZIP(handle); - } - } - - public new static ZIP? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_zip_open_with_options(path, options); - return handle == null ? null : new ZIP(handle); - } - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/Options.cs b/src/lib/lang/csharp/libvpkedit/Options.cs deleted file mode 100644 index 7d44c33d..00000000 --- a/src/lib/lang/csharp/libvpkedit/Options.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.InteropServices; - -namespace libvpkedit -{ - [StructLayout(LayoutKind.Sequential)] - public struct PackFileOptions - { - public byte gma_writeCRCs; - - public uint vpk_version; - - public uint vpk_preferredChunkSize; - - public byte vpk_generateMD5Entries; - - public ushort zip_compressionMethod; - } -} diff --git a/src/lib/lang/csharp/libvpkedit/PackFile.cs b/src/lib/lang/csharp/libvpkedit/PackFile.cs deleted file mode 100644 index c8d5f4d4..00000000 --- a/src/lib/lang/csharp/libvpkedit/PackFile.cs +++ /dev/null @@ -1,587 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; - -namespace libvpkedit -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern void* vpkedit_open([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_open_with_options([MarshalAs(UnmanagedType.LPStr)] string path, PackFileOptions options); - - [DllImport("libvpkeditc")] - public static extern PackFileType vpkedit_get_type(void* handle); - - [DllImport("libvpkeditc")] - public static extern PackFileOptions vpkedit_get_options(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_has_entry_checksums(void* handle); - - [DllImport("libvpkeditc")] - public static extern StringArray vpkedit_verify_entry_checksums(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_has_file_checksum(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_verify_file_checksum(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_has_file_signature(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_verify_file_signature(void* handle); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_is_case_sensitive(void* handle); - - [DllImport("libvpkeditc")] - public static extern void* vpkedit_find_entry(void* handle, [MarshalAs(UnmanagedType.LPStr)] string filename, byte includeUnbaked); - - [DllImport("libvpkeditc")] - public static extern Buffer vpkedit_read_entry(void* handle, void* entry); - - [DllImport("libvpkeditc")] - public static extern String vpkedit_read_entry_text(void* handle, void* entry); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_is_read_only(void* handle); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_add_entry_from_file(void* handle, [MarshalAs(UnmanagedType.LPStr)] string filename, [MarshalAs(UnmanagedType.LPStr)] string pathToFile); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_add_entry_from_mem(void* handle, [MarshalAs(UnmanagedType.LPStr)] string filename, byte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_remove_entry(void* handle, [MarshalAs(UnmanagedType.LPStr)] string filename); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_bake(void* handle, [MarshalAs(UnmanagedType.LPStr)] string outputDir); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_extract_entry(void* handle, void* entry, [MarshalAs(UnmanagedType.LPStr)] string filePath); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_extract_dir(void* handle, [MarshalAs(UnmanagedType.LPStr)] string dir, [MarshalAs(UnmanagedType.LPStr)] string outputDir); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_extract_all(void* handle, [MarshalAs(UnmanagedType.LPStr)] string outputDir, byte createUnderPackFileDir); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_extract_all_if(void* handle, [MarshalAs(UnmanagedType.LPStr)] string outputDir, IntPtr predicate); - - [DllImport("libvpkeditc")] - public static extern EntryHandleArray vpkedit_get_baked_entries(void* handle); - - [DllImport("libvpkeditc")] - public static extern EntryHandleArray vpkedit_get_unbaked_entries(void* handle); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_entry_count(void* handle, byte includeUnbaked); - - [DllImport("libvpkeditc")] - public static extern Buffer vpkedit_read_virtual_entry(void* handle, void* entry); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_overwrite_virtual_entry_from_file(void* handle, void* entry, [MarshalAs(UnmanagedType.LPStr)] string pathToFile); - - [DllImport("libvpkeditc")] - public static extern byte vpkedit_overwrite_virtual_entry_from_mem(void* handle, void* entry, byte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern VirtualEntryHandleArray vpkedit_get_virtual_entries(void* handle); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_filepath(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_truncated_filepath(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_filename(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_truncated_filename(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_filestem(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_truncated_filestem(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_get_supported_entry_attributes(void* handle, Attribute* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern ulong vpkedit_to_string(void* handle, sbyte* buffer, ulong bufferLen); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_close(void** handle); - - [DllImport("libvpkeditc")] - public static extern String vpkedit_escape_entry_path([MarshalAs(UnmanagedType.LPStr)] string path); - - [DllImport("libvpkeditc")] - public static extern StringArray vpkedit_get_supported_file_types(); - } - - public class PackFile - { - private protected unsafe PackFile(void* handle) - { - Handle = handle; - } - - ~PackFile() - { - unsafe - { - fixed (void** handlePtr = &Handle) - { - Extern.vpkedit_close(handlePtr); - } - } - } - - public static PackFile? Open(string path) - { - unsafe - { - var handle = Extern.vpkedit_open(path); - return handle == null ? null : new PackFile(handle); - } - } - - public static PackFile? Open(string path, PackFileOptions options) - { - unsafe - { - var handle = Extern.vpkedit_open_with_options(path, options); - return handle == null ? null : new PackFile(handle); - } - } - - public static string EscapeEntryPath(string path) - { - var str = Extern.vpkedit_escape_entry_path(path); - return StringUtils.ConvertToStringAndDelete(ref str); - } - - public static List GetSupportedFileTypes() - { - var stringArray = Extern.vpkedit_get_supported_file_types(); - return StringUtils.ConvertToListAndDelete(ref stringArray); - } - - public bool HasEntryChecksums() - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_has_entry_checksums(Handle)); - } - } - - public IEnumerable VerifyEntryChecksums() - { - unsafe - { - var stringArray = Extern.vpkedit_verify_entry_checksums(Handle); - return StringUtils.ConvertToListAndDelete(ref stringArray); - } - } - - public bool HasFileChecksum() - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_has_file_checksum(Handle)); - } - } - - public bool VerifyFileChecksum() - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_verify_file_checksum(Handle)); - } - } - - public bool HasFileSignature() - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_has_file_signature(Handle)); - } - } - - public bool VerifyFileSignature() - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_verify_file_signature(Handle)); - } - } - - public Entry? FindEntry(string filename, bool includeUnbaked = true) - { - unsafe - { - var entry = Extern.vpkedit_find_entry(Handle, filename, Convert.ToByte(includeUnbaked)); - return entry == null ? null : new Entry(entry, false); - } - } - - public byte[]? ReadEntry(Entry entry) - { - unsafe - { - var buffer = Extern.vpkedit_read_entry(Handle, entry.Handle); - return buffer.size < 0 ? null : BufferUtils.ConvertToArrayAndDelete(ref buffer); - } - } - - public string? ReadEntryText(Entry entry) - { - unsafe - { - var str = Extern.vpkedit_read_entry_text(Handle, entry.Handle); - return str.size < 0 ? null : StringUtils.ConvertToStringAndDelete(ref str); - } - } - - public void AddEntry(string filename, string pathToFile) - { - unsafe - { - Extern.vpkedit_add_entry_from_file(Handle, filename, pathToFile); - } - } - - public void AddEntry(string filename, byte[] buffer) - { - unsafe - { - fixed (byte* bufferPtr = buffer) - { - Extern.vpkedit_add_entry_from_mem(Handle, filename, bufferPtr, (ulong) buffer.LongLength); - } - } - } - - public void AddEntry(string filename, IEnumerable buffer) - { - unsafe - { - var data = buffer.ToArray(); - fixed (byte* bufferPtr = data) - { - Extern.vpkedit_add_entry_from_mem(Handle, filename, bufferPtr, (ulong) data.LongLength); - } - } - } - - public bool RemoveEntry(string filename) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_remove_entry(Handle, filename)); - } - } - - public bool Bake(string outputDir) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_bake(Handle, outputDir)); - } - } - - public bool ExtractEntry(Entry entry, string filePath) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_extract_entry(Handle, entry.Handle, filePath)); - } - } - - public bool ExtractDir(string dir, string outputDir) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_extract_dir(Handle, dir, outputDir)); - } - } - - public bool ExtractAll(string outputDir, bool createUnderPackFileDir = true) - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_extract_all(Handle, outputDir, Convert.ToByte(createUnderPackFileDir))); - } - } - - private unsafe delegate byte ExtractAllPredicateNative(void* entry); - - public bool ExtractAll(string outputDir, Func predicate) - { - unsafe - { - ExtractAllPredicateNative predicateWrapper = (entry) => - { - // HACK: tell the entry its in an array so it doesn't kill itself - return Convert.ToByte(predicate(new Entry(entry, true))); - }; - return Convert.ToBoolean(Extern.vpkedit_extract_all_if(Handle, outputDir, Marshal.GetFunctionPointerForDelegate(predicateWrapper))); - } - } - - public EntryEnumerable GetBakedEntries() - { - unsafe - { - return new EntryEnumerable(Extern.vpkedit_get_baked_entries(Handle)); - } - } - - public EntryEnumerable GetUnbakedEntries() - { - unsafe - { - return new EntryEnumerable(Extern.vpkedit_get_unbaked_entries(Handle)); - } - } - - public ulong GetEntryCount(bool includeUnbaked = true) - { - unsafe - { - return Extern.vpkedit_get_entry_count(Handle, Convert.ToByte(includeUnbaked)); - } - } - - public byte[]? ReadVirtualEntry(VirtualEntry entry) - { - unsafe - { - var buffer = Extern.vpkedit_read_virtual_entry(Handle, entry.Handle); - return buffer.size < 0 ? null : BufferUtils.ConvertToArrayAndDelete(ref buffer); - } - } - - public void OverwriteVirtualEntry(VirtualEntry entry, string pathToFile) - { - unsafe - { - Extern.vpkedit_overwrite_virtual_entry_from_file(Handle, entry.Handle, pathToFile); - } - } - - public bool OverwriteVirtualEntry(VirtualEntry entry, byte[] buffer) - { - unsafe - { - fixed (byte* bufferPtr = buffer) - { - return Convert.ToBoolean(Extern.vpkedit_overwrite_virtual_entry_from_mem(Handle, entry.Handle, bufferPtr, (ulong) buffer.LongLength)); - } - } - } - - public bool OverwriteVirtualEntry(VirtualEntry entry, IEnumerable buffer) - { - unsafe - { - var data = buffer.ToArray(); - fixed (byte* dataPtr = data) - { - return Convert.ToBoolean(Extern.vpkedit_overwrite_virtual_entry_from_mem(Handle, entry.Handle, dataPtr, (ulong) data.LongLength)); - } - } - } - - public VirtualEntryEnumerable GetVirtualEntries() - { - unsafe - { - return new VirtualEntryEnumerable(Extern.vpkedit_get_virtual_entries(Handle)); - } - } - - public override string ToString() - { - unsafe - { - var stringPtr = stackalloc sbyte[Constants.MaxPackFileString]; - Extern.vpkedit_to_string(Handle, stringPtr, Convert.ToUInt64(Constants.MaxPackFileString)); - return new string(stringPtr); - } - } - - public PackFileType Type - { - get - { - unsafe - { - return Extern.vpkedit_get_type(Handle); - } - } - } - - public PackFileOptions Options - { - get - { - unsafe - { - return Extern.vpkedit_get_options(Handle); - } - } - } - - public bool CaseSensitive - { - get - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_is_case_sensitive(Handle)); - } - } - } - - public bool ReadOnly - { - get - { - unsafe - { - return Convert.ToBoolean(Extern.vpkedit_is_read_only(Handle)); - } - } - } - - public string FilePath - { - get - { - Span stringArray = new sbyte[Constants.MaxPath]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_filepath(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string TruncatedFilePath - { - get - { - Span stringArray = new sbyte[Constants.MaxPath]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_truncated_filepath(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string FileName - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_filename(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string TruncatedFileName - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_truncated_filename(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string FileStem - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_filestem(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public string TruncatedFileStem - { - get - { - Span stringArray = new sbyte[Constants.MaxFilename]; - unsafe - { - fixed (sbyte* stringPtr = stringArray) - { - Extern.vpkedit_get_truncated_filestem(Handle, stringPtr, Convert.ToUInt64(stringArray.Length)); - return new string(stringPtr); - } - } - } - } - - public List SupportedEntryAttributes - { - get - { - unsafe - { - var attrArray = stackalloc Attribute[(int) Attribute.COUNT]; - var numAttributes = Extern.vpkedit_get_supported_entry_attributes(Handle, attrArray, (ulong) Attribute.COUNT); - - var result = new List(); - for (ulong i = 0; i < numAttributes; i++) - { - result.Add(attrArray[i]); - } - return result; - } - } - } - - private protected readonly unsafe void* Handle; - } -} diff --git a/src/lib/lang/csharp/libvpkedit/PackFileType.cs b/src/lib/lang/csharp/libvpkedit/PackFileType.cs deleted file mode 100644 index 1e082413..00000000 --- a/src/lib/lang/csharp/libvpkedit/PackFileType.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace libvpkedit -{ - public enum PackFileType - { - UNKNOWN, - BSP, - FPX, - GCF, - GMA, - GRP, - PAK, - PCK, - VPK, - ZIP, - } -} diff --git a/src/lib/lang/csharp/libvpkedit/String.cs b/src/lib/lang/csharp/libvpkedit/String.cs deleted file mode 100644 index 3fbf41ba..00000000 --- a/src/lib/lang/csharp/libvpkedit/String.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace libvpkedit -{ - internal static unsafe partial class Extern - { - [DllImport("libvpkeditc")] - public static extern String vpkedit_string_new(ulong size); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_string_free(String* str); - - [DllImport("libvpkeditc")] - public static extern StringArray vpkedit_string_array_new(ulong size); - - [DllImport("libvpkeditc")] - public static extern void vpkedit_string_array_free(StringArray* array); - } - - [StructLayout(LayoutKind.Sequential)] - internal struct String - { - public long size; - public unsafe sbyte* data; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct StringArray - { - public long size; - public unsafe sbyte** data; - } - - internal static unsafe class StringUtils - { - public static string ConvertToStringAndDelete(ref String str) - { - var result = new string(str.data); - - fixed (String* strPtr = &str) - { - Extern.vpkedit_string_free(strPtr); - } - - return result; - } - - public static List ConvertToListAndDelete(ref StringArray array) - { - var strings = new List(); - - for (long i = 0; i < array.size; i++) - { - strings.Add(new string(array.data[i])); - } - - fixed (StringArray* arrayPtr = &array) - { - Extern.vpkedit_string_array_free(arrayPtr); - } - - return strings; - } - } -} diff --git a/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj.in b/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj.in deleted file mode 100644 index 6c77e298..00000000 --- a/src/lib/lang/csharp/libvpkedit/libvpkedit.csproj.in +++ /dev/null @@ -1,20 +0,0 @@ - - - - net8.0 - enable - true - - - - - PreserveNewest - lib${PROJECT_NAME}c${CMAKE_SHARED_LIBRARY_SUFFIX} - - - - - - - - diff --git a/src/lib/thirdparty/cryptopp b/src/lib/thirdparty/cryptopp deleted file mode 160000 index 19cd13af..00000000 --- a/src/lib/thirdparty/cryptopp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 19cd13af5f7fa4904b174b81e98852283dbe8c1f diff --git a/src/lib/thirdparty/minizip-ng b/src/lib/thirdparty/minizip-ng deleted file mode 160000 index 5aec551b..00000000 --- a/src/lib/thirdparty/minizip-ng +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5aec551bf78ed79f6bec3160a5c7ce7fdac66776 diff --git a/src/shared/_shared.cmake b/src/shared/_shared.cmake new file mode 100644 index 00000000..762b478e --- /dev/null +++ b/src/shared/_shared.cmake @@ -0,0 +1,8 @@ +# Configure version header +configure_file( + "${CMAKE_CURRENT_LIST_DIR}/config/Version.h.in" + "${CMAKE_CURRENT_LIST_DIR}/config/Version.h") + + +# sourcepp +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/shared/thirdparty/sourcepp") diff --git a/src/shared/config/.gitignore b/src/shared/config/.gitignore new file mode 100644 index 00000000..38ba24e2 --- /dev/null +++ b/src/shared/config/.gitignore @@ -0,0 +1 @@ +Version.h diff --git a/include/vpkedit/Version.h.in b/src/shared/config/Version.h.in similarity index 93% rename from include/vpkedit/Version.h.in rename to src/shared/config/Version.h.in index 5c1dce70..4396c73b 100644 --- a/include/vpkedit/Version.h.in +++ b/src/shared/config/Version.h.in @@ -2,8 +2,6 @@ #include -namespace vpkedit { - constexpr std::string_view PROJECT_NAME = "${PROJECT_NAME}"; constexpr std::string_view PROJECT_NAME_PRETTY = "${PROJECT_NAME_PRETTY}"; constexpr std::string_view PROJECT_VERSION = "${PROJECT_VERSION}"; @@ -12,5 +10,3 @@ constexpr std::string_view PROJECT_HOMEPAGE = "${PROJECT_HOMEPAGE_URL}"; constexpr std::string_view PROJECT_HOMEPAGE_API = "${PROJECT_HOMEPAGE_URL_API}"; constexpr std::string_view ORGANIZATION_NAME = "${PROJECT_ORGANIZATION_NAME}"; constexpr std::string_view PROJECT_TITLE = "${PROJECT_NAME_PRETTY} v${PROJECT_VERSION_PRETTY}"; - -} // namespace vpkedit diff --git a/src/shared/thirdparty/sourcepp b/src/shared/thirdparty/sourcepp new file mode 160000 index 00000000..cc545609 --- /dev/null +++ b/src/shared/thirdparty/sourcepp @@ -0,0 +1 @@ +Subproject commit cc545609102da97c63005e521cd8ee597729bee3 diff --git a/test/_test.cmake b/test/_test.cmake deleted file mode 100644 index 103db43a..00000000 --- a/test/_test.cmake +++ /dev/null @@ -1,22 +0,0 @@ -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1) -FetchContent_MakeAvailable(googletest) -enable_testing() - -list(APPEND ${PROJECT_NAME}_test_SOURCES - "${CMAKE_CURRENT_LIST_DIR}/lib/format/VPK.cpp") - -add_executable(${PROJECT_NAME}_test ${${PROJECT_NAME}_test_SOURCES}) - -target_link_libraries(${PROJECT_NAME}_test PUBLIC lib${PROJECT_NAME} gtest_main) -if(VPKEDIT_BUILD_LIBC) - target_link_libraries(${PROJECT_NAME}_test PUBLIC lib${PROJECT_NAME}c) -endif() - -target_include_directories(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") - -include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME}_test) diff --git a/test/lib/format/VPK.cpp b/test/lib/format/VPK.cpp deleted file mode 100644 index 8e651819..00000000 --- a/test/lib/format/VPK.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include - -#include -#include -#include - -// These tests will need Portal 2 installed on your main drive -// Modify this on Linux (I'm the only one running these tests right now) -#define USERNAME "craftablescience" - -constexpr auto PORTAL2_PAK_PATH = -#ifdef _WIN32 - R"(C:\Program Files (x86)\Steam\steamapps\common\Portal 2\portal2\pak01_dir.vpk)"; -#else // __linux__ - "/home/" USERNAME "/.steam/steam/steamapps/common/Portal 2/portal2/pak01_dir.vpk"; -#endif - -using namespace vpkedit; - -TEST(VPK, read) { - auto vpk = VPK::open(PORTAL2_PAK_PATH); - ASSERT_TRUE(vpk); - - for (const auto& [directory, files] : vpk->getBakedEntries()) { - for (const auto& file : files) { - // Terminal explosion - std::cout << file.path << '\n'; - } - } -} - -TEST(VPK, readContents) { - // Ditto - auto vpk = VPK::open(PORTAL2_PAK_PATH); - ASSERT_TRUE(vpk); - - auto cableVMT = vpk->findEntry("materials/cable/cable.vmt"); - ASSERT_TRUE(cableVMT); - - ASSERT_EQ(cableVMT->length, 46); - - std::string_view expectedContents = "SplineRope\r\n{\r\n$basetexture \"cable\\black\"\r\n}\r\n"; - auto actualContents = vpk->readEntryText(*cableVMT); - ASSERT_TRUE(actualContents); - ASSERT_STREQ(actualContents->c_str(), expectedContents.data()); -}