diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fc8fca..814752a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,18 @@ cmake_minimum_required(VERSION 3.18..3.28) -project(ReArchive) + +set(ArchiveProjectVersion 1.1) # The current revision of the project. +set(ArchiveFormatVersion 1.0) # The current version of Redacted Software Archive specification. +set(ArchiveAppVersion 1.1) # The current version of rsarchive.exe + + +project(ReArchive + VERSION ${ArchiveProjectVersion} + LANGUAGES CXX) + + +if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not allowed") +endif() set(CMAKE_CXX_STANDARD 20) @@ -14,11 +27,25 @@ if(WIN32) add_library(ReArchive STATIC ${SOURCES}) endif() +include(cmake/CPM.cmake) + +CPMAddPackage(NAME mcolor + URL https://git.redacted.cc/maxine/mcolor/archive/Release-1.zip) + + +target_compile_definitions(ReArchive PUBLIC ARCHIVE_PROJECT_VERSION=${ArchiveProjectVersion}) +target_compile_definitions(ReArchive PUBLIC ARCHIVE_FORMAT_VERSION=${ArchiveFormatVersion}) + + set_target_properties(ReArchive PROPERTIES LINKER_LANGUAGE CXX) target_include_directories(ReArchive PUBLIC ${PROJECT_SOURCE_DIR}/include) add_executable(rsarchive main.cpp) -target_link_libraries(rsarchive PUBLIC ReArchive) + +target_compile_definitions(rsarchive PRIVATE ARCHIVE_APP_VERSION=${ArchiveAppVersion}) + +target_include_directories(rsarchive PUBLIC ${mcolor_SOURCE_DIR}/include) +target_link_libraries(rsarchive PUBLIC ReArchive mcolor) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the build type" FORCE) diff --git a/README.md b/README.md new file mode 100644 index 0000000..55a40e7 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Redacted Software Archive + +Yet Another Archival Format :D + +The ReArchive project is a lightweight C++ library designed for creating, managing, and extracting archive files. It provides a foundation for bundling multiple files and directories into a single archive, ideal for game assets (mod distribution), application deployments, and many more tasks. Included with the library is `rsarchive`, a command-line application demonstrating ReArchive's capabilities and providing a general-purpose archive management tool. + +## Features + +* General + * Custom bespoke archive format. + * Included CLI archive program. + * C++20 API for integrating archives into your project. + * Public Domain Source Code, Format, & Application. + * **ZERO** dependencies. Just C++ and CMake. +* Library API Features + * Bundle files together for easier distribution. + * Integrate easily into your C++ project. + * Cross-platform: Designed with Redacted Software signature portability, simplicity, and +* Archive Format + * Custom, stream-friendly archive format. + * Designed for efficiency and extensibility. + * Efficient file retrieval even from large archives. + * Lightning fast. (See Benchmarks.) +* rsarchive Application: + * Robust command-line utility. + * Create, Extract, Inspect, Modify, and Validate archive files. + * Append and remove files individually. + * Supported on Windows & Linux. + * Designed to be extended and modified. + + + + +## Acknowledgements + diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 0000000..d866ad7 --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.38.7) +set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) \ No newline at end of file diff --git a/include/ReArchive/ReArchive.h b/include/ReArchive/ReArchive.h index 6ada212..e0bdd6e 100644 --- a/include/ReArchive/ReArchive.h +++ b/include/ReArchive/ReArchive.h @@ -51,4 +51,9 @@ namespace ReArchive { /// @param file_table If you're keeping track of the file table in your program, Providing it here will update it to reflect our changes and speed things up. /// @note An empty vector is returned in the event that no such file exists or there was an error reading it back. std::vector ReadFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* file_table = nullptr); -} \ No newline at end of file + + + /// Returns the rsa format version this library is compiled to support. + /// @note Future versions of this library may support backward-compatibility. + double ArchiveFormatProtocolVersion(); +} diff --git a/main.cpp b/main.cpp index e3a207c..14ff062 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,9 @@ #include #include #include +#include + + bool GetConfirmation(const std::string& message) { std::string user_input; @@ -32,6 +35,11 @@ std::vector ReadFileFromDisk(const std::filesystem::path& file_to return buffer; } +std::string PrettyVersionString() +{ + return std::format("{}Redacted Software Archive Project v{} (rsarchive v{}) (RSA Format v{}){}", Colors::Browns::GoldenRod.ToEscapeCode(), ARCHIVE_PROJECT_VERSION, ARCHIVE_APP_VERSION, ARCHIVE_FORMAT_VERSION, mcolor::AnsiEscapeCodes::ResetAll); +} + bool WriteFileToDisk(const std::vector& file_data, const std::filesystem::path& destination) { std::ofstream file(destination, std::ios::binary); if (!file) @@ -42,6 +50,7 @@ bool WriteFileToDisk(const std::vector& file_data, const std::fil } void DisplayLicense() { + std::cout << Colors::Oranges::Gold.ToEscapeCode(); std::cout << "This is free and unencumbered software released into the public domain." << std::endl; std::cout << std::endl; std::cout << "Anyone is free to copy, modify, publish, use, compile, sell, or" << std::endl; @@ -63,16 +72,23 @@ void DisplayLicense() { std::cout << "IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR" << std::endl; std::cout << "OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE," << std::endl; std::cout << "ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR" << std::endl; - std::cout << "OTHER DEALINGS IN THE SOFTWARE." << std::endl; + std::cout << "OTHER DEALINGS IN THE SOFTWARE." << mcolor::AnsiEscapeCodes::ResetAll << std::endl; } void DisplayHelp() { - std::cout << "Redacted Software Archive version 1.0" << std::endl; - std::cout << "-v version: show the version string -h help: shows this listing" << std::endl; - std::cout << "-L license: show software license -l list: show all files in-to an archive" << std::endl; - std::cout << "-x extract: retrieve files from an archive -a add: put a file in-to an archive" << std::endl; - std::cout << "-c create: make a new, empty archive -r create an archive from a directory" << std::endl; - std::cout << "-ar add recursive: put all files in a directory in-to an archive" << std::endl; + std::string sep = Colors::DarkGray.ToEscapeCode() + mcolor::AnsiEscapeCodes::Bold + ">>> " + mcolor::AnsiEscapeCodes::ResetAll; + std::cout << PrettyVersionString() << std::endl; + int col = 45; + std::cout.width(col); + std::cout << std::left << "-v version: show the version string " << sep << std::left << "-h help: shows this listing" << std::endl; + std::cout.width(col); + std::cout << std::left << "-L license: show software license " << sep << std::right << "-l list: show all files in-to an archive" << std::endl; + std::cout.width(col); + std::cout << std::left <<"-x extract: retrieve files from an archive " << sep << std::right << "-a add: put a file in-to an archive" << std::endl; + std::cout.width(col); + std::cout << std::left << "-c create: make a new, empty archive " << sep << std::right << "-r create an archive from a directory" << std::endl; + std::cout.width(col); + std::cout << std::left << "-ar add recursive: put all files in a directory in-to an archive" << std::endl; } void DisplayArchiveContents(const std::filesystem::path& archive) { @@ -92,7 +108,8 @@ void DisplayArchiveContents(const std::filesystem::path& archive) { } void DisplayInvalidParameters() { - std::cerr << "Invalid parameters received. Use -h or 'man rsarchive' for a complete guide." << std::endl; + //std::cerr << "Invalid parameters received. Use -h or 'man rsarchive' for a complete guide." << std::endl; + std::cout << Colors::Reds::LightCoral.ToEscapeCode() << "Invalid parameters received." << Colors::White.ToEscapeCode() << " Use -h or 'man rsarchive' for a complete guide." << mcolor::AnsiEscapeCodes::ResetAll << std::endl; } void AddFileToArchive(const std::filesystem::path& file_to_add, const std::filesystem::path& archive, ReArchive::FileTable* file_table = nullptr) { @@ -183,13 +200,18 @@ void ExtractArchive(const std::filesystem::path& archive) { } } + + int main(int argc, char* argv[]) { + + mcolor::windowsSaneify(); + if (argc == 1) DisplayInvalidParameters(); if (argc == 2) { if (std::string(argv[1]) == "-v") - std::cout << "Redacted Software Archive version 1.0" << std::endl; + std::cout << PrettyVersionString() << std::endl; else if (std::string(argv[1]) == "-h") DisplayHelp(); diff --git a/src/ReArchive.cpp b/src/ReArchive.cpp index 467bc56..8550484 100644 --- a/src/ReArchive.cpp +++ b/src/ReArchive.cpp @@ -306,6 +306,8 @@ std::vector ReArchive::ReadFile(const std::filesystem::path& arch return result; } +double ReArchive::ArchiveFormatProtocolVersion() { return ARCHIVE_FORMAT_VERSION; } + // I tried to do this several different ways but this seems to be the best approach - Redacted. bool ReArchive::EraseFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* running_tally) {