Compare commits
3 Commits
f36652ad67
...
main
Author | SHA1 | Date | |
---|---|---|---|
1970342ae0 | |||
8edd019ca8 | |||
a49108c4d2 |
@@ -1,18 +1,57 @@
|
||||
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)
|
||||
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp")
|
||||
|
||||
add_library(ReArchive SHARED ${SOURCES})
|
||||
if(UNIX)
|
||||
add_library(ReArchive SHARED ${SOURCES})
|
||||
endif()
|
||||
|
||||
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)
|
||||
|
||||
CPMAddPackage(NAME Endianness
|
||||
URL https://git.redacted.cc/josh/Endianness/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)
|
||||
target_include_directories(ReArchive PRIVATE ${Endianness_SOURCE_DIR}/include)
|
||||
target_link_libraries(ReArchive PRIVATE Endianness)
|
||||
|
||||
add_executable(rsarchive main.cpp)
|
||||
|
||||
target_compile_definitions(rsarchive PRIVATE ARCHIVE_APP_VERSION=${ArchiveAppVersion})
|
||||
|
||||
target_link_libraries(rsarchive PUBLIC ReArchive)
|
||||
target_include_directories(rsarchive PRIVATE ${mcolor_SOURCE_DIR}/include)
|
||||
target_link_libraries(rsarchive PRIVATE mcolor)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the build type" FORCE)
|
||||
|
35
README.md
Normal file
35
README.md
Normal file
@@ -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
|
||||
|
24
cmake/CPM.cmake
Normal file
24
cmake/CPM.cmake
Normal file
@@ -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})
|
@@ -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<unsigned char> ReadFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* file_table = nullptr);
|
||||
}
|
||||
|
||||
|
||||
/// Returns the rsa format version this library is compiled to support.
|
||||
/// @note Future versions of this library may support backward-compatibility.
|
||||
double ArchiveFormatProtocolVersion();
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <Endianness.hpp>
|
||||
|
||||
|
||||
namespace ReArchive {
|
||||
|
40
main.cpp
40
main.cpp
@@ -1,6 +1,9 @@
|
||||
#include <ReArchive/ReArchive.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <mcolor.h>
|
||||
|
||||
|
||||
|
||||
bool GetConfirmation(const std::string& message) {
|
||||
std::string user_input;
|
||||
@@ -32,6 +35,11 @@ std::vector<unsigned char> 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<unsigned char>& 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<unsigned char>& 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();
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <ReArchive/types/FileTable.h>
|
||||
#include <ReArchive/types/FileEntry.h>
|
||||
#include <cassert>
|
||||
#include <Endianness.hpp>
|
||||
|
||||
using ReArchive::Header;
|
||||
using ReArchive::FileTable;
|
||||
@@ -29,7 +30,9 @@ FileTable GetFileTable(const Header& header, std::ifstream& in) {
|
||||
in.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
|
||||
|
||||
unsigned char* ptr = buffer.data();
|
||||
int64_t file_table_entry_count = be64toh(*reinterpret_cast<int64_t*>(ptr));
|
||||
Endianness::NetworkToHostOrder(128u);
|
||||
s64 wtf = *reinterpret_cast<const int64_t*>(ptr);
|
||||
int64_t file_table_entry_count = Endianness::NetworkToHostOrder<s64>(wtf);
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
FileTable result;
|
||||
@@ -37,16 +40,16 @@ FileTable GetFileTable(const Header& header, std::ifstream& in) {
|
||||
// Out of bounds.
|
||||
assert(ptr < (buffer.data() + buffer.size()));
|
||||
|
||||
int64_t string_size = be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
int64_t string_size = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr)); //be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
std::string path(reinterpret_cast<const char*>(ptr), string_size);
|
||||
ptr += string_size;
|
||||
|
||||
int64_t data_size = be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
int64_t data_size = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
int64_t data_offset = be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
int64_t data_offset = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
result.Append({ data_size, data_offset, path });
|
||||
@@ -303,6 +306,8 @@ std::vector<unsigned char> 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) {
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <ReArchive/types/FileEntry.h>
|
||||
#include <cstring>
|
||||
#include <Endianness.hpp>
|
||||
|
||||
|
||||
using namespace ReArchive;
|
||||
@@ -11,18 +12,18 @@ std::vector<unsigned char> FileEntry::Serialize(const FileEntry& file) {
|
||||
std::vector<unsigned char> result(sizeof(int64_t) + path_size + 2 * sizeof(int64_t));
|
||||
unsigned char* ptr = result.data();
|
||||
|
||||
auto network_path_size = htobe64(path_size);
|
||||
auto network_path_size = Endianness::HostToNetworkOrder(path_size);
|
||||
memcpy(ptr, &network_path_size, sizeof(int64_t));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
memcpy(ptr, path_string.data(), path_size);
|
||||
ptr += path_size;
|
||||
|
||||
auto network_data_size = htobe64(file.data_size);
|
||||
auto network_data_size = Endianness::HostToNetworkOrder(file.data_size);
|
||||
memcpy(ptr, &network_data_size, sizeof(int64_t));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
auto network_data_offset = htobe64(file.data_offset);
|
||||
auto network_data_offset = Endianness::HostToNetworkOrder(file.data_offset);
|
||||
memcpy(ptr, &network_data_offset, sizeof(int64_t));
|
||||
return result;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <ReArchive/types/FileTable.h>
|
||||
#include <cstring>
|
||||
#include <Endianness.hpp>
|
||||
|
||||
using namespace ReArchive;
|
||||
|
||||
@@ -19,7 +20,7 @@ void FileTable::Remove(const FileEntry& file_entry) {
|
||||
std::vector<unsigned char> FileTable::Serialize(const FileTable& file_table) {
|
||||
auto files = file_table.GetEntries();
|
||||
int64_t count = files->size();
|
||||
auto network_count = htobe64(count);
|
||||
auto network_count = Endianness::HostToNetworkOrder(count);
|
||||
std::vector<unsigned char> result(reinterpret_cast<unsigned char*>(&network_count), reinterpret_cast<unsigned char*>(&network_count) + sizeof(network_count));
|
||||
|
||||
if (files->empty())
|
||||
|
@@ -10,7 +10,7 @@ std::vector<unsigned char> ReArchive::Header::Serialize(const ReArchive::Header&
|
||||
|
||||
size_t current_size = result.size();
|
||||
result.resize(current_size + sizeof(int64_t));
|
||||
auto network_file_table_offset = htobe64(header.file_table_offset);
|
||||
auto network_file_table_offset = Endianness::HostToNetworkOrder(header.file_table_offset);//htobe64(header.file_table_offset);
|
||||
memcpy(result.data() + current_size, &network_file_table_offset, sizeof(int64_t));
|
||||
|
||||
return result;
|
||||
@@ -22,5 +22,5 @@ ReArchive::Header ReArchive::Header::DeSerialize(const unsigned char* serialized
|
||||
use_c = serialized_header[ReArchive::magic.size()];
|
||||
memcpy(&file_table_off, serialized_header + ReArchive::Header::Size() - sizeof(int64_t), sizeof(int64_t));
|
||||
|
||||
return { use_c, (int64_t) be64toh(file_table_off)};
|
||||
return { use_c, (int64_t) Endianness::HostToNetworkOrder(file_table_off)};//be64toh(file_table_off)};
|
||||
}
|
||||
|
Reference in New Issue
Block a user