7 Commits

Author SHA1 Message Date
f36652ad67 Make sudo make install work how it should. 2025-03-27 17:29:11 -04:00
f89cbb96cc ~ 10x performance optimization 2025-03-27 17:03:33 -04:00
79b9e546ee Performance optimization
Avoid copying around the entire file table so that the speed doesn't decrease as the archive has more files.
2025-03-27 01:11:17 -04:00
021ca575d1 Performance optimization
use try_emplace to avoid two lookups.
2025-03-27 00:30:51 -04:00
29bfd46843 Performance optimization 2025-03-27 00:14:12 -04:00
5a88cb6296 Update main.cpp 2025-03-22 15:05:18 -04:00
70d44d069a First iteration of the linux program. 2025-03-22 00:09:46 -04:00
6 changed files with 319 additions and 104 deletions

View File

@@ -11,5 +11,14 @@ add_library(ReArchive SHARED ${SOURCES})
set_target_properties(ReArchive PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(ReArchive PUBLIC ${PROJECT_SOURCE_DIR}/include)
add_executable(ReArchive_Demo main.cpp)
target_link_libraries(ReArchive_Demo PUBLIC ReArchive)
add_executable(rsarchive main.cpp)
target_link_libraries(rsarchive PUBLIC ReArchive)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the build type" FORCE)
endif()
include(GNUInstallDirs)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Install path prefix" FORCE)
install(TARGETS ReArchive DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS rsarchive DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@@ -8,10 +8,10 @@ namespace ReArchive {
/// Creates a new empty archive.
/// @param filesystem_path where the archive is to be created.
/// @param use_compression whether you'd like the file to use compression.
/// @param running_tally If you're keeping track of the file table in your program, Providing it here will update it to reflect our changes.
/// @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 use_compression currently does nothing.
/// @returns True if success.
[[nodiscard]] bool CreateArchive(const std::filesystem::path& archive, bool use_compression = false, FileTable* running_tally = nullptr);
[[nodiscard]] bool CreateArchive(const std::filesystem::path& archive, bool use_compression = false, FileTable* file_table = nullptr);
/// @param archive The archive on the disk.
/// @returns std::pair bool, FileTable. bool is success, FileTable is only valid if success.
@@ -23,9 +23,9 @@ namespace ReArchive {
/// @param file_data The raw data of the file to be written.
/// @param file_path The std::filesystem::path you would use to retrieve the file from the archive.
/// @param byte_count The length of the file in bytes.
/// @param running_tally If you're keeping track of the file table in your program, Providing it here will update it to reflect our changes.
/// @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.
/// @returns True if success.
[[nodiscard]] bool WriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* running_tally = nullptr);
[[nodiscard]] bool WriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* file_table = nullptr);
/// Overwrite a file which already exists in the archive.
/// @param archive The archive on the disk.
@@ -33,19 +33,22 @@ namespace ReArchive {
/// @param file_path The std::filesystem::path file in the archive to be overwritten.
/// @param byte_count The length of the file in bytes.
/// @note It is expected that byte_count will the the same as the file size.
/// @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.
/// @returns True if success.
[[nodiscard]] bool OverwriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count);
[[nodiscard]] bool OverwriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* file_table = nullptr);
/// Remove a file from the archive.
/// @param archive The archive on the disk.
/// @param file_path The std::filesystem::path file in the archive to be removed.
/// @param running_tally If you're keeping track of the file table in your program, Providing it here will update it to reflect our changes.
/// @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.
/// @returns True if success.
[[nodiscard]] bool EraseFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* running_tally = nullptr);
[[nodiscard]] bool EraseFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* file_table = nullptr);
/// Read a file from a given archive
/// @param archive The archive on the disk.
/// @param file_path The std::filesystem::path you specified for the given file.
/// @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);
std::vector<unsigned char> ReadFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* file_table = nullptr);
}

View File

@@ -15,8 +15,9 @@ protected:
public:
void Append(const FileEntry& file_entry);
void Remove(const FileEntry& file_entry);
[[nodiscard]] bool Contains(std::filesystem::path& entry ) const { return entries.contains(entry); }
[[nodiscard]] std::unordered_map<std::filesystem::path, FileEntry> GetEntries() const { return entries; }
[[nodiscard]] bool Contains(const std::filesystem::path& entry ) const { return entries.contains(entry); }
[[nodiscard]] std::unordered_map<std::filesystem::path, FileEntry>* GetEntries() { return &entries; }
[[nodiscard]] const std::unordered_map<std::filesystem::path, FileEntry>* GetEntries() const { return &entries; }
[[nodiscard]] int64_t Count() const { return entries.size(); }
public:
[[nodiscard]] static std::vector<unsigned char> Serialize(const FileTable& file_table);

242
main.cpp
View File

@@ -1,34 +1,232 @@
#include <ReArchive/ReArchive.h>
#include <iostream>
#include <fstream>
int main() {
ReArchive::FileTable running_tally;
bool GetConfirmation(const std::string& message) {
std::string user_input;
while (true) {
std::cout << message << "(Y/N)"<< std::endl;
std::cin >> user_input;
if(std::filesystem::exists("test.rsa"))
std::filesystem::remove("test.rsa");
if (!ReArchive::CreateArchive("test.rsa"))
return -1;
std::string some_string = "some other string0.";
if (!ReArchive::WriteFile("test.rsa", "assets/test0.png", reinterpret_cast<const unsigned char *>(some_string.data()), some_string.size(), &running_tally))
return -1;
if (user_input == "y" || user_input == "Y")
return true;
some_string = "some other string1.";
if (!ReArchive::WriteFile("test.rsa", "assets/test1.png", reinterpret_cast<const unsigned char *>(some_string.data()), some_string.size(), &running_tally))
return -1;
if (user_input == "n" || user_input == "N")
return false;
}
}
std::vector<unsigned char> ReadFileFromDisk(const std::filesystem::path& file_to_read) {
std::ifstream file(file_to_read, std::ios::binary | std::ios::ate);
if (!file)
throw std::runtime_error("Failed to open file: " + file_to_read.string());
auto retrieved = ReArchive::ReadFile("test.rsa", "assets/test0.png");
std::cout << std::string( retrieved.begin(), retrieved.end()) << std::endl;
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
if (!ReArchive::EraseFile("test.rsa", "assets/test0.png", &running_tally))
return -1;
std::vector<unsigned char> buffer(size);
auto retrieved2 = ReArchive::ReadFile("test.rsa", "assets/test1.png");
std::cout << std::string( retrieved2.begin(), retrieved2.end()) << std::endl;
if (!file.read(reinterpret_cast<char*>(buffer.data()), size))
throw std::runtime_error("Error reading file: " + file_to_read.string());
for (auto& e : running_tally.GetEntries())
std::cout << e.second.Path() << std::endl;
return buffer;
}
ReArchive::FileTable copy = running_tally;
bool WriteFileToDisk(const std::vector<unsigned char>& file_data, const std::filesystem::path& destination) {
std::ofstream file(destination, std::ios::binary);
if (!file)
return false;
file.write(reinterpret_cast<const char*>(file_data.data()), file_data.size());
return file.good();
}
void DisplayLicense() {
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;
std::cout << "distribute this software, either in source code form or as a compiled" << std::endl;
std::cout << "binary, for any purpose, commercial or non-commercial, and by any" << std::endl;
std::cout << "means." << std::endl;
std::cout << std::endl;
std::cout << "In jurisdictions that recognize copyright laws, the author or authors" << std::endl;
std::cout << "of this software dedicate any and all copyright interest in the" << std::endl;
std::cout << "software to the public domain. We make this dedication for the benefit" << std::endl;
std::cout << "of the public at large and to the detriment of our heirs and" << std::endl;
std::cout << "successors. We intend this dedication to be an overt act of" << std::endl;
std::cout << "relinquishment in perpetuity of all present and future rights to this" << std::endl;
std::cout << "software under copyright law." << std::endl;
std::cout << std::endl;
std::cout << "THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND," << std::endl;
std::cout << "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF" << std::endl;
std::cout << "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT." << std::endl;
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;
}
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;
}
void DisplayArchiveContents(const std::filesystem::path& archive) {
auto result = ReArchive::ReadFileTable(archive);
if (!result.first) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
auto file_table = result.second;
std::cout << "path | size (bytes)" << std::endl;
for (const auto& e : *file_table.GetEntries())
std::cout << e.second.Path() << " " << e.second.Size() << std::endl;
std::cout << file_table.Count() << " files" << std::endl;
}
void DisplayInvalidParameters() {
std::cerr << "Invalid parameters received. Use -h or 'man rsarchive' for a complete guide." << std::endl;
}
void AddFileToArchive(const std::filesystem::path& file_to_add, const std::filesystem::path& archive, ReArchive::FileTable* file_table = nullptr) {
if (!std::filesystem::exists(file_to_add)) {
std::cerr << "The specified path for the file to be added is inaccessible." << std::endl;
return;
}
if (std::filesystem::is_directory(file_to_add)) {
std::cerr << "The specified path for the file(s) to be added is a directory." << std::endl;
return;
}
auto file_data = ReadFileFromDisk(file_to_add);
auto result = ReArchive::WriteFile(archive, file_to_add, file_data.data(), file_data.size(), file_table);
if (!result)
std::cerr << "The specified path for the file to be added already exists within the archive." << std::endl;
}
void AddDirectoryToArchive(const std::filesystem::path& directory_to_add, const std::filesystem::path& archive) {
if (!std::filesystem::exists(directory_to_add)) {
std::cerr << "The specified path for the file(s) to add is inaccessible or does not exist." << std::endl;
return;
}
if (!std::filesystem::is_directory(directory_to_add)) {
std::cerr << "The specified path for the file(s) to add is not a directory." << std::endl;
return;
}
if (!std::filesystem::exists(archive)) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
auto result = ReArchive::ReadFileTable(archive);
if (!result.first) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory_to_add)) {
if (std::filesystem::is_regular_file(entry) && !std::filesystem::is_directory(entry)) {
auto entry_relative_path = std::filesystem::relative(entry.path(), std::filesystem::current_path());
AddFileToArchive(entry_relative_path, archive, &result.second);
}
}
}
void NewArchiveFromDirectory(const std::filesystem::path& directory_to_add, const std::filesystem::path& archive) {
if (std::filesystem::exists(archive)) {
std::cerr << "The specified path for the new archive already exists." << std::endl;
return;
}
auto result = ReArchive::CreateArchive(archive, false);
if (!result)
std::cerr << "The specified path for the new archive already exists." << std::endl;
AddDirectoryToArchive(directory_to_add, archive);
}
void ExtractArchive(const std::filesystem::path& archive) {
if (!std::filesystem::exists(archive)) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
auto file_table_result = ReArchive::ReadFileTable(archive);
if (!file_table_result.first) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
auto result = ReArchive::ReadFileTable(archive);
if (!result.first) {
std::cerr << "The specified path is inaccessible or not a valid archive." << std::endl;
return;
}
for (const auto& entry : *file_table_result.second.GetEntries()) {
if (std::filesystem::exists(entry.first))
if (!GetConfirmation("File " + entry.first.string() + " already exists, overwrite?"))
continue;
std::filesystem::create_directories(std::filesystem::current_path() / entry.first.parent_path());
if (!WriteFileToDisk(ReArchive::ReadFile(archive, entry.first, &result.second),std::filesystem::current_path() / entry.first))
std::cerr << "The path for writing is inaccessible." << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc == 1)
DisplayInvalidParameters();
if (argc == 2) {
if (std::string(argv[1]) == "-v")
std::cout << "Redacted Software Archive version 1.0" << std::endl;
else if (std::string(argv[1]) == "-h")
DisplayHelp();
else if (std::string(argv[1]) == "-L")
DisplayLicense();
else
DisplayInvalidParameters();
}
else if (argc == 3) {
if (std::string(argv[1]) == "-l")
DisplayArchiveContents(argv[2]);
else if (std::string(argv[1]) == "-c") {
if(!ReArchive::CreateArchive(argv[2], false))
std::cerr << "The specified path for the new archive is inaccessible or already exists." << std::endl;
}
else if (std::string(argv[1]) == "-x") {
ExtractArchive(argv[2]);
}
else
DisplayInvalidParameters();
}
else if (argc == 4) {
if (std::string(argv[1]) == "-a")
AddFileToArchive(argv[2], argv[3]);
else if (std::string(argv[1]) == "-ar")
AddDirectoryToArchive(argv[2], argv[3]);
else if (std::string(argv[1]) == "-r")
NewArchiveFromDirectory(argv[2], argv[3]);
else
DisplayInvalidParameters();
}
}

View File

@@ -4,6 +4,7 @@
#include <ReArchive/types/Header.h>
#include <ReArchive/types/FileTable.h>
#include <ReArchive/types/FileEntry.h>
#include <cassert>
using ReArchive::Header;
using ReArchive::FileTable;
@@ -20,39 +21,35 @@ Header GetHeader(const unsigned char* archive) {
/// @param in Our input stream to the file.
/// @note Does not close the input stream.
FileTable GetFileTable(const Header& header, std::ifstream& in) {
FileTable result;
std::vector<unsigned char> buffer;
in.seekg(0, std::ios::end);
int64_t file_table_size = in.tellg() - header.FileTableOffset();
in.seekg(header.FileTableOffset(), std::ios::beg);
buffer.resize(sizeof(int64_t));
in.read(reinterpret_cast<char *>(buffer.data()), (int64_t) buffer.size());
int64_t file_table_entry_count = be64toh(*reinterpret_cast<int64_t*>(buffer.data()));
std::vector<unsigned char> buffer(file_table_size);
in.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
if (file_table_entry_count) {
// To put us at the first "string size" for each FileEntry.
in.seekg(header.FileTableOffset() + 8, std::ios::beg);
unsigned char* ptr = buffer.data();
int64_t file_table_entry_count = be64toh(*reinterpret_cast<int64_t*>(ptr));
ptr += sizeof(int64_t);
// for each file entry,
for (int64_t i = 0; i < file_table_entry_count; i++) {
in.read(reinterpret_cast<char *>(buffer.data()), (int64_t) buffer.size());
int64_t string_size = be64toh(*reinterpret_cast<int64_t*>(buffer.data()));
FileTable result;
for (int64_t i = 0; i < file_table_entry_count; i++) {
// Out of bounds.
assert(ptr < (buffer.data() + buffer.size()));
buffer.resize(string_size);
in.read(reinterpret_cast<char *>(buffer.data()), (int64_t) buffer.size());
std::string path(buffer.begin(), buffer.end());
int64_t string_size = be64toh(*reinterpret_cast<const int64_t*>(ptr));
ptr += sizeof(int64_t);
buffer.resize(sizeof(int64_t));
std::string path(reinterpret_cast<const char*>(ptr), string_size);
ptr += string_size;
in.read(reinterpret_cast<char *>(buffer.data()), (int64_t) buffer.size());
int64_t data_size = be64toh(*reinterpret_cast<int64_t*>(buffer.data()));
int64_t data_size = be64toh(*reinterpret_cast<const int64_t*>(ptr));
ptr += sizeof(int64_t);
in.read(reinterpret_cast<char *>(buffer.data()), (int64_t) buffer.size());
int64_t data_offset = be64toh(*reinterpret_cast<int64_t*>(buffer.data()));
int64_t data_offset = be64toh(*reinterpret_cast<const int64_t*>(ptr));
ptr += sizeof(int64_t);
result.Append(FileEntry(data_size, data_offset, path));
}
result.Append({ data_size, data_offset, path });
}
return result;
}
@@ -91,7 +88,7 @@ std::pair<bool, FileTable> ReArchive::ReadFileTable(const std::filesystem::path&
return {true, file_table};
}
bool ReArchive::CreateArchive(const std::filesystem::path& filesystem_path, bool use_compression, FileTable* running_tally) {
bool ReArchive::CreateArchive(const std::filesystem::path& filesystem_path, bool use_compression, FileTable* current_file_table) {
if (std::filesystem::exists(filesystem_path))
return false;
@@ -110,8 +107,8 @@ bool ReArchive::CreateArchive(const std::filesystem::path& filesystem_path, bool
file.write(reinterpret_cast<const char*>(serialized_file_table.data()), (int64_t) serialized_file_table.size());
file.close();
if (running_tally)
*running_tally = file_table;
if (current_file_table)
*current_file_table = file_table;
// Remove lock.
auto position = locked.find(filesystem_path);
@@ -121,7 +118,7 @@ bool ReArchive::CreateArchive(const std::filesystem::path& filesystem_path, bool
return true;
}
bool ReArchive::WriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* running_tally) {
bool ReArchive::WriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* current_file_table) {
if (!std::filesystem::exists(archive))
return false;
@@ -144,11 +141,14 @@ bool ReArchive::WriteFile(const std::filesystem::path& archive, const std::files
return false;
auto header = GetHeader(buffer.data());
auto file_table = GetFileTable(header, in);
auto file_entries = file_table.GetEntries();
auto value = file_entries.find(file_path);
if (value != file_entries.end())
FileTable* file_table;
if (current_file_table == nullptr)
file_table = new FileTable(GetFileTable(header, in));
else
file_table = current_file_table;
if (file_table->Contains(file_path))
return false;
in.close();
@@ -160,10 +160,10 @@ bool ReArchive::WriteFile(const std::filesystem::path& archive, const std::files
out.seekp(header.FileTableOffset(), std::ios::beg);
out.write(reinterpret_cast<const char *>(file_data), byte_count);
file_table.Append(FileEntry(byte_count, header.FileTableOffset(), file_path));
file_table->Append(FileEntry(byte_count, header.FileTableOffset(), file_path));
header.FileTableOffset(out.tellp());
auto new_file_table = FileTable::Serialize(file_table);
auto new_file_table = FileTable::Serialize(*file_table);
out.write(reinterpret_cast<const char *>(new_file_table.data()), (int64_t) new_file_table.size());
auto new_header = Header::Serialize(header);
@@ -171,18 +171,22 @@ bool ReArchive::WriteFile(const std::filesystem::path& archive, const std::files
out.write(reinterpret_cast<const char *>(new_header.data()), (int64_t) new_header.size());
out.close();
if (current_file_table)
*current_file_table = *file_table;
if (current_file_table == nullptr)
delete file_table;
// Remove lock.
auto position = locked.find(archive);
if (position != locked.end())
locked.erase(position);
if (running_tally)
*running_tally = file_table;
return true;
}
bool ReArchive::OverwriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count) {
bool ReArchive::OverwriteFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, const unsigned char* file_data, const int64_t& byte_count, FileTable* current_file_table) {
if (!std::filesystem::exists(archive))
return false;
@@ -205,17 +209,19 @@ bool ReArchive::OverwriteFile(const std::filesystem::path& archive, const std::f
return false;
auto header = GetHeader(buffer.data());
auto file_table = GetFileTable(header, in);
FileTable* file_table;
if (current_file_table == nullptr)
file_table = new FileTable(GetFileTable(header, in));
else
file_table = current_file_table;
const FileEntry* target = nullptr;
auto file_entries = file_table.GetEntries();
auto file_entries = file_table->GetEntries();
auto value = file_entries.find(file_path);
if (value != file_entries.end())
auto value = file_entries->find(file_path);
if (value != file_entries->end())
target = &value->second;
if (!target)
return false;
@@ -231,6 +237,9 @@ bool ReArchive::OverwriteFile(const std::filesystem::path& archive, const std::f
out.write(reinterpret_cast<const char *>(file_data), byte_count);
out.close();
if (current_file_table == nullptr)
delete file_table;
// Remove lock.
auto position = locked.find(archive);
if (position != locked.end())
@@ -239,7 +248,7 @@ bool ReArchive::OverwriteFile(const std::filesystem::path& archive, const std::f
return true;
}
std::vector<unsigned char> ReArchive::ReadFile(const std::filesystem::path& archive, const std::filesystem::path& file_path) {
std::vector<unsigned char> ReArchive::ReadFile(const std::filesystem::path& archive, const std::filesystem::path& file_path, FileTable* current_file_table) {
if (!std::filesystem::exists(archive))
return {};
@@ -262,23 +271,19 @@ std::vector<unsigned char> ReArchive::ReadFile(const std::filesystem::path& arch
return {};
auto header = GetHeader(buffer.data());
auto file_table = GetFileTable(header, in);
/*
for (const auto& e : file_table.GetEntries())
if (e.Path() == file_path)
target = &e;
*/
FileTable* file_table;
if (current_file_table == nullptr)
file_table = new FileTable(GetFileTable(header, in));
else
file_table = current_file_table;
const FileEntry* target = nullptr;
auto file_entries = file_table.GetEntries();
auto file_entries = file_table->GetEntries();
auto value = file_entries.find(file_path);
if (value != file_entries.end())
auto value = file_entries->find(file_path);
if (value != file_entries->end())
target = &value->second;
if (!target)
return {};
@@ -287,11 +292,14 @@ for (const auto& e : file_table.GetEntries())
in.read(reinterpret_cast<char*>(result.data()), (int64_t) result.size());
in.close();
// delete the one we allocated if one was not passed in.
if (current_file_table == nullptr)
delete file_table;
// Remove lock.
auto position = locked.find(archive);
if (position != locked.end())
locked.erase(position);
return result;
}
@@ -327,11 +335,11 @@ bool ReArchive::EraseFile(const std::filesystem::path& archive, const std::files
return false;
auto file_entries = current_file_table.GetEntries();
auto value = file_entries.find(file_path);
if (value != file_entries.end())
file_entries.erase(value);
auto value = file_entries->find(file_path);
if (value != file_entries->end())
file_entries->erase(value);
for (auto& e : file_entries) {
for (auto& e : *file_entries) {
auto file_buffer = ReadFile(archive, e.first);
if (!WriteFile(archive.string() + ".tmp", e.first, file_buffer.data(), (int64_t) file_buffer.size())) {
std::filesystem::remove(archive.string() + ".tmp");

View File

@@ -4,10 +4,7 @@
using namespace ReArchive;
void FileTable::Append(const FileEntry& file_entry) {
if (entries.contains(file_entry.Path()))
return;
entries.insert(std::make_pair(file_entry.Path(), file_entry));
entries.try_emplace(file_entry.Path(), file_entry);
}
void FileTable::Remove(const FileEntry& file_entry) {
@@ -21,15 +18,14 @@ 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();
int64_t count = files->size();
auto network_count = htobe64(count);
std::vector<unsigned char> result(reinterpret_cast<unsigned char*>(&network_count),
reinterpret_cast<unsigned char*>(&network_count) + sizeof(network_count));
std::vector<unsigned char> result(reinterpret_cast<unsigned char*>(&network_count), reinterpret_cast<unsigned char*>(&network_count) + sizeof(network_count));
if (files.empty())
if (files->empty())
return result;
for (const auto& file : files) {
for (const auto& file : *files) {
size_t current_size = result.size();
auto serialization = FileEntry::Serialize(file.second);