iw4x-sp/src/client/component/filesystem.cpp

133 lines
3.5 KiB
C++

#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include "filesystem.hpp"
#include "game_module.hpp"
namespace filesystem {
namespace {
const char* sys_default_install_path_stub() {
static auto current_path = std::filesystem::current_path().string();
return current_path.c_str();
}
} // namespace
bool file_wrapper_rotate(const char* ospath) {
constexpr auto MAX_BACKUPS = 20;
char renamed_path[game::MAX_OSPATH]{};
struct _stat64i32 stat_buf;
auto oldest_index = -1;
auto current_index = 0;
time_t oldest_time = 0;
// Check if the original file exists
if (_stat64i32(ospath, &stat_buf)) {
return true; // Return true if the file does not exist (no file to rotate)
}
for (; current_index < MAX_BACKUPS; ++current_index) {
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
if (_stat64i32(renamed_path, &stat_buf)) {
break; // Stop if an available slot is found
}
if (oldest_index == -1 || stat_buf.st_mtime < oldest_time) {
oldest_time = stat_buf.st_mtime;
oldest_index = current_index;
}
}
if (current_index == MAX_BACKUPS) {
(void)sprintf_s(renamed_path, "%s.%03i", ospath, oldest_index);
(void)std::remove(renamed_path); // Remove the oldest backup file
} else {
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
}
// Rename the original file to the selected backup slot
return std::rename(ospath, renamed_path) == 0;
}
bool file_rotate(const char* filename) {
char ospath[game::MAX_OSPATH]{};
const auto* basepath = (*dvars::fs_homepath)->current.string;
game::FS_BuildOSPath(basepath, reinterpret_cast<char*>(0x1956038), filename,
ospath);
return file_wrapper_rotate(ospath);
}
std::vector<std::string> vectored_file_list(const std::string& path,
const std::string& extension) {
std::vector<std::string> file_list;
auto num_files = 0;
const auto** files = game::FS_ListFiles(path.c_str(), extension.c_str(),
game::FS_LIST_ALL, &num_files, 10);
if (files) {
for (auto i = 0; i < num_files; ++i) {
if (files[i]) {
file_list.emplace_back(files[i]);
}
}
game::FS_FreeFileList(files, 10);
}
return file_list;
}
std::string get_binary_directory() {
const auto dir = game_module::get_host_module().get_folder();
return utils::string::replace(dir, "/", "\\");
}
file::file(std::string name, game::FsThread thread) : name_(std::move(name)) {
assert(!this->name_.empty());
auto handle = 0;
const auto len =
game::FS_FOpenFileReadForThread(name_.c_str(), &handle, thread);
if (!handle) {
this->valid_ = false;
return;
}
auto* buf = static_cast<char*>(game::Hunk_AllocateTempMemory(len + 1));
game::FS_Read(buf, len, handle);
buf[len] = '\0';
game::FS_FCloseFile(handle);
this->valid_ = true;
this->buffer_.append(buf, len);
}
bool file::exists() const { return this->valid_; }
const std::string& file::get_buffer() const { return this->buffer_; }
const std::string& file::get_name() const { return this->name_; }
class component final : public component_interface {
public:
void post_load() override {
utils::hook(0x465B90, sys_default_install_path_stub, HOOK_CALL)
.install() // hook*
->quick(); // Sys_CreateFile
}
};
} // namespace filesystem
REGISTER_COMPONENT(filesystem::component)