t8-mod/source/proxy-dll/component/hashes.cpp
2024-01-09 06:26:31 -08:00

256 lines
4.7 KiB
C++

#include <std_include.hpp>
#include "hashes.hpp"
#include "gsc_funcs.hpp"
#include "definitions/variables.hpp"
#include "loader/component_loader.hpp"
#include <utilities/json_config.hpp>
namespace hashes
{
namespace
{
bool enabled = true;
std::unordered_map<uint64_t, std::string>& hash_storage()
{
static std::unordered_map<uint64_t, std::string> storage{};
return storage;
}
const char* hff_names[]
{
"COMMON",
"STRING",
"SERIOUS_COMPILER"
};
bool is_valid_h32(const char* str)
{
const char* s = str;
while (*s)
{
char c = *(s++);
if (!(
(c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| c == '_'))
{
return false;
}
}
return true; // [A-Za-z0-9_]+
}
}
const char* lookup(uint64_t hash)
{
auto& hs = hash_storage();
auto it = hs.find(hash);
if (it == hs.end())
{
return nullptr;
}
return it->second.c_str();
}
const char* lookup_tmp(const char* type, uint64_t hash)
{
static char tmp_buffer[0x50];
const char* val = lookup(hash);
if (val)
{
return val;
}
sprintf_s(tmp_buffer, "%s_%llx", type, hash);
return tmp_buffer;
}
void add_hash(uint64_t hash, const char* value)
{
if (!enabled)
{
return;
}
hash_storage()[hash] = value;
}
const char* get_format_name(hashes_file_format format)
{
if (format >= 0 && format < HFF_COUNT)
{
return hff_names[format];
}
return "<invalid>";
}
hashes_file_format get_format_idx(const char* name)
{
for (size_t i = 0; i < HFF_COUNT; i++)
{
if (!_strcmpi(name, hff_names[i]))
{
return (hashes_file_format)i;
}
}
return HFF_COUNT;
}
bool load_file(std::filesystem::path& file, hashes_file_format format)
{
if (!enabled)
{
return true;
}
logger::write(logger::LOG_TYPE_DEBUG, std::format("loading hash file {}", file.string()));
switch (format)
{
case HFF_STRING:
{
// basic format, each line is a string, allows fast updates
std::ifstream s(file);
if (!s)
{
logger::write(logger::LOG_TYPE_ERROR, std::format("can't read hash file {}", file.string()));
return false; // nothing to read
}
std::string line;
while (s.good() && std::getline(s, line))
{
const char* str = line.c_str();
if (is_valid_h32(str))
{
add_hash(gsc_funcs::canon_hash(str), str);
}
add_hash(fnv1a::generate_hash(str), str);
}
s.close();
return true;
}
case HFF_COMMON:
{
// common precomputed format used by greyhound index and other tools
// each line: <hash>,<string>
std::ifstream s(file);
if (!s)
{
logger::write(logger::LOG_TYPE_ERROR, std::format("can't read hash file {}", file.string()));
return false; // nothing to read
}
std::string line;
while (s.good() && std::getline(s, line))
{
auto idx = line.rfind(", ", 18);
if (idx == std::string::npos)
{
continue; // bad line
}
char value[18] = {};
const char* str = line.c_str();
memcpy(value, str, idx);
add_hash(std::strtoull(value, nullptr, 16), str + idx + 1);
}
s.close();
return false;
}
case HFF_SERIOUS_COMPILER:
{
// precomputed format generated by the serious compiler
// each line: 0x<hash>, <string>
std::ifstream s(file);
if (!s)
{
logger::write(logger::LOG_TYPE_ERROR, std::format("can't read hash file {}", file.string()));
return false; // nothing to read
}
std::string line;
while (s.good() && std::getline(s, line))
{
if (!line.starts_with("0x"))
{
continue; // bad line
}
auto idx = line.rfind(", ", 18);
if (idx == std::string::npos)
{
continue; // bad line
}
char value[18] = {};
const char* str = line.c_str();
memcpy(value, str + 2, idx - 2);
add_hash(std::strtoull(value, nullptr, 16), str + idx + 2);
}
s.close();
return true;
}
default:
logger::write(logger::LOG_TYPE_ERROR, std::format("bad format type {} for file {}", (int)format, file.string()));
return false;
}
}
class component final : public component_interface
{
public:
void pre_start() override
{
enabled = utilities::json_config::ReadBoolean("gsc", "hashes", true);
if (!enabled)
{
return;
}
// load default files
std::filesystem::path default_file_name_str = "project-bo4/strings.txt";
if (std::filesystem::exists(default_file_name_str))
{
load_file(default_file_name_str, HFF_STRING);
}
std::filesystem::path default_file_name_common = "project-bo4/hashes.csv";
if (std::filesystem::exists(default_file_name_common))
{
load_file(default_file_name_common, HFF_COMMON);
}
}
};
}
REGISTER_COMPONENT(hashes::component)