~ 10x performance optimization
This commit is contained in:
@@ -4,15 +4,14 @@
|
||||
#include <vector>
|
||||
|
||||
// TODO compression.
|
||||
// TODO allow the user to pass in the file table if they already have it to avoid de-serializing it over and over.
|
||||
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.
|
||||
@@ -24,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.
|
||||
@@ -34,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);
|
||||
}
|
25
main.cpp
25
main.cpp
@@ -84,16 +84,18 @@ void DisplayArchiveContents(const std::filesystem::path& archive) {
|
||||
}
|
||||
|
||||
auto file_table = result.second;
|
||||
std::cout << "path" << " | " << "size (bytes)" << std::endl;
|
||||
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) {
|
||||
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;
|
||||
@@ -105,7 +107,7 @@ void AddFileToArchive(const std::filesystem::path& file_to_add, const std::files
|
||||
}
|
||||
|
||||
auto file_data = ReadFileFromDisk(file_to_add);
|
||||
auto result = ReArchive::WriteFile(archive, file_to_add, file_data.data(), file_data.size());
|
||||
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;
|
||||
@@ -127,10 +129,16 @@ void AddDirectoryToArchive(const std::filesystem::path& directory_to_add, const
|
||||
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);
|
||||
AddFileToArchive(entry_relative_path, archive, &result.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +148,6 @@ void NewArchiveFromDirectory(const std::filesystem::path& directory_to_add, cons
|
||||
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;
|
||||
@@ -159,13 +166,19 @@ void ExtractArchive(const std::filesystem::path& archive) {
|
||||
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),std::filesystem::current_path() / entry.first))
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -88,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;
|
||||
|
||||
@@ -107,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);
|
||||
@@ -118,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;
|
||||
|
||||
@@ -141,9 +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);
|
||||
|
||||
if (file_table.Contains(file_path))
|
||||
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();
|
||||
@@ -155,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);
|
||||
@@ -166,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;
|
||||
|
||||
@@ -200,7 +209,11 @@ 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();
|
||||
@@ -224,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())
|
||||
@@ -232,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 {};
|
||||
|
||||
@@ -255,10 +271,14 @@ std::vector<unsigned char> ReArchive::ReadFile(const std::filesystem::path& arch
|
||||
return {};
|
||||
|
||||
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())
|
||||
@@ -272,11 +292,14 @@ std::vector<unsigned char> ReArchive::ReadFile(const std::filesystem::path& arch
|
||||
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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user