System: Hash executable for game code when system.cnf missing

This commit is contained in:
Connor McLaughlin 2021-03-07 02:44:09 +10:00
parent ac4dd11fa0
commit 6bbb1128b6
4 changed files with 44 additions and 25 deletions

View File

@ -32,6 +32,7 @@
#include "spu.h" #include "spu.h"
#include "texture_replacements.h" #include "texture_replacements.h"
#include "timers.h" #include "timers.h"
#include "xxhash.h"
#include <cctype> #include <cctype>
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
@ -385,21 +386,20 @@ std::string_view GetTitleForPath(const char* path)
return path_view.substr(0, path_view.find_last_of('.')); return path_view.substr(0, path_view.find_last_of('.'));
} }
std::string GetGameCodeForPath(const char* image_path) std::string GetGameCodeForPath(const char* image_path, bool fallback_to_hash)
{ {
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path); std::unique_ptr<CDImage> cdi = CDImage::Open(image_path);
if (!cdi) if (!cdi)
return {}; return {};
return GetGameCodeForImage(cdi.get()); return GetGameCodeForImage(cdi.get(), fallback_to_hash);
} }
std::string GetGameCodeForImage(CDImage* cdi) std::string GetGameCodeForImage(CDImage* cdi, bool fallback_to_hash)
{ {
std::string code(GetExecutableNameForImage(cdi)); std::string code(GetExecutableNameForImage(cdi));
if (code.empty()) if (!code.empty())
return {}; {
// SCES_123.45 -> SCES-12345 // SCES_123.45 -> SCES-12345
for (std::string::size_type pos = 0; pos < code.size();) for (std::string::size_type pos = 0; pos < code.size();)
{ {
@ -420,6 +420,25 @@ std::string GetGameCodeForImage(CDImage* cdi)
return code; return code;
} }
if (!fallback_to_hash)
return {};
std::string exe_name;
std::vector<u8> exe_buffer;
if (!ReadExecutableFromImage(cdi, &exe_name, &exe_buffer))
return {};
XXH64_state_t* state = XXH64_createState();
XXH64_reset(state, 0x4242D00C);
XXH64_update(state, exe_name.c_str(), exe_name.size());
XXH64_update(state, exe_buffer.data(), exe_buffer.size());
const u64 hash = XXH64_digest(state);
XXH64_freeState(state);
Log_InfoPrintf("Hash for '%s' - %" PRIX64, exe_name.c_str(), hash);
return StringUtil::StdStringFromFormat("HASH-%" PRIX64, hash);
}
static std::string GetExecutableNameForImage(CDImage* cdi, ISOReader& iso, bool strip_subdirectories) static std::string GetExecutableNameForImage(CDImage* cdi, ISOReader& iso, bool strip_subdirectories)
{ {
// Read SYSTEM.CNF // Read SYSTEM.CNF
@ -601,7 +620,7 @@ DiscRegion GetRegionForImage(CDImage* cdi)
if (system_area_region != DiscRegion::Other) if (system_area_region != DiscRegion::Other)
return system_area_region; return system_area_region;
std::string code = GetGameCodeForImage(cdi); std::string code = GetGameCodeForImage(cdi, false);
if (code.empty()) if (code.empty())
return DiscRegion::Other; return DiscRegion::Other;

View File

@ -78,8 +78,8 @@ ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region);
std::string GetExecutableNameForImage(CDImage* cdi); std::string GetExecutableNameForImage(CDImage* cdi);
bool ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name, std::vector<u8>* out_executable_data); bool ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name, std::vector<u8>* out_executable_data);
std::string GetGameCodeForImage(CDImage* cdi); std::string GetGameCodeForImage(CDImage* cdi, bool fallback_to_hash);
std::string GetGameCodeForPath(const char* image_path); std::string GetGameCodeForPath(const char* image_path, bool fallback_to_hash);
DiscRegion GetRegionForCode(std::string_view code); DiscRegion GetRegionForCode(std::string_view code);
DiscRegion GetRegionFromSystemArea(CDImage* cdi); DiscRegion GetRegionFromSystemArea(CDImage* cdi);
DiscRegion GetRegionForImage(CDImage* cdi); DiscRegion GetRegionForImage(CDImage* cdi);

View File

@ -415,7 +415,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[],
else else
{ {
// find the game id, and get its save state path // find the game id, and get its save state path
std::string game_code = System::GetGameCodeForPath(boot_filename.c_str()); std::string game_code = System::GetGameCodeForPath(boot_filename.c_str(), true);
if (game_code.empty()) if (game_code.empty())
{ {
Log_WarningPrintf("Could not identify game code for '%s', cannot load save state %d.", boot_filename.c_str(), Log_WarningPrintf("Could not identify game code for '%s', cannot load save state %d.", boot_filename.c_str(),
@ -2867,7 +2867,7 @@ void CommonHostInterface::GetGameInfo(const char* path, CDImage* image, std::str
else else
{ {
if (image) if (image)
*code = System::GetGameCodeForImage(image); *code = System::GetGameCodeForImage(image, true);
const GameListDatabaseEntry* db_entry = (!code->empty()) ? m_game_list->GetDatabaseEntryForCode(*code) : nullptr; const GameListDatabaseEntry* db_entry = (!code->empty()) ? m_game_list->GetDatabaseEntryForCode(*code) : nullptr;
if (db_entry) if (db_entry)

View File

@ -181,7 +181,7 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
if (entry->compatibility_rating == GameListCompatibilityRating::Unknown) if (entry->compatibility_rating == GameListCompatibilityRating::Unknown)
{ {
std::string code = System::GetGameCodeForImage(entry_image.get()); std::string code = System::GetGameCodeForImage(entry_image.get(), true);
const GameListCompatibilityEntry* compatibility_entry = GetCompatibilityEntryForCode(entry->code); const GameListCompatibilityEntry* compatibility_entry = GetCompatibilityEntryForCode(entry->code);
if (compatibility_entry) if (compatibility_entry)
entry->compatibility_rating = compatibility_entry->compatibility_rating; entry->compatibility_rating = compatibility_entry->compatibility_rating;
@ -206,7 +206,7 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
if (!cdi) if (!cdi)
return false; return false;
std::string code = System::GetGameCodeForImage(cdi.get()); std::string code = System::GetGameCodeForImage(cdi.get(), true);
DiscRegion region = System::GetRegionFromSystemArea(cdi.get()); DiscRegion region = System::GetRegionFromSystemArea(cdi.get());
if (region == DiscRegion::Other) if (region == DiscRegion::Other)
region = System::GetRegionForCode(code); region = System::GetRegionForCode(code);