diff --git a/src/core/system.cpp b/src/core/system.cpp index fc91ff7e4..0dcab2e75 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -32,6 +32,7 @@ #include "spu.h" #include "texture_replacements.h" #include "timers.h" +#include "xxhash.h" #include #include #include @@ -385,39 +386,57 @@ std::string_view GetTitleForPath(const char* path) 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 cdi = CDImage::Open(image_path); if (!cdi) 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)); - if (code.empty()) - return {}; - - // SCES_123.45 -> SCES-12345 - for (std::string::size_type pos = 0; pos < code.size();) + if (!code.empty()) { - if (code[pos] == '.') + // SCES_123.45 -> SCES-12345 + for (std::string::size_type pos = 0; pos < code.size();) { - code.erase(pos, 1); - continue; + if (code[pos] == '.') + { + code.erase(pos, 1); + continue; + } + + if (code[pos] == '_') + code[pos] = '-'; + else + code[pos] = static_cast(std::toupper(code[pos])); + + pos++; } - if (code[pos] == '_') - code[pos] = '-'; - else - code[pos] = static_cast(std::toupper(code[pos])); - - pos++; + return code; } - return code; + if (!fallback_to_hash) + return {}; + + std::string exe_name; + std::vector 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) @@ -601,7 +620,7 @@ DiscRegion GetRegionForImage(CDImage* cdi) if (system_area_region != DiscRegion::Other) return system_area_region; - std::string code = GetGameCodeForImage(cdi); + std::string code = GetGameCodeForImage(cdi, false); if (code.empty()) return DiscRegion::Other; diff --git a/src/core/system.h b/src/core/system.h index 4829f9b6f..84446b425 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -78,8 +78,8 @@ ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region); std::string GetExecutableNameForImage(CDImage* cdi); bool ReadExecutableFromImage(CDImage* cdi, std::string* out_executable_name, std::vector* out_executable_data); -std::string GetGameCodeForImage(CDImage* cdi); -std::string GetGameCodeForPath(const char* image_path); +std::string GetGameCodeForImage(CDImage* cdi, bool fallback_to_hash); +std::string GetGameCodeForPath(const char* image_path, bool fallback_to_hash); DiscRegion GetRegionForCode(std::string_view code); DiscRegion GetRegionFromSystemArea(CDImage* cdi); DiscRegion GetRegionForImage(CDImage* cdi); diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 130fa2e2c..100089bb7 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -415,7 +415,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[], else { // 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()) { 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 { if (image) - *code = System::GetGameCodeForImage(image); + *code = System::GetGameCodeForImage(image, true); const GameListDatabaseEntry* db_entry = (!code->empty()) ? m_game_list->GetDatabaseEntryForCode(*code) : nullptr; if (db_entry) diff --git a/src/frontend-common/game_list.cpp b/src/frontend-common/game_list.cpp index 2849d8418..f5f37752e 100644 --- a/src/frontend-common/game_list.cpp +++ b/src/frontend-common/game_list.cpp @@ -181,7 +181,7 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry) 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); if (compatibility_entry) entry->compatibility_rating = compatibility_entry->compatibility_rating; @@ -206,7 +206,7 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry) if (!cdi) return false; - std::string code = System::GetGameCodeForImage(cdi.get()); + std::string code = System::GetGameCodeForImage(cdi.get(), true); DiscRegion region = System::GetRegionFromSystemArea(cdi.get()); if (region == DiscRegion::Other) region = System::GetRegionForCode(code);