Add Gecko and AR codes to the Patch Allowlist Test
This commit is contained in:
parent
8447ce99f4
commit
81098433c8
|
@ -18,7 +18,10 @@
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
#include "Common/JsonUtil.h"
|
#include "Common/JsonUtil.h"
|
||||||
|
#include "Core/ActionReplay.h"
|
||||||
#include "Core/CheatCodes.h"
|
#include "Core/CheatCodes.h"
|
||||||
|
#include "Core/GeckoCode.h"
|
||||||
|
#include "Core/GeckoCodeConfig.h"
|
||||||
#include "Core/PatchEngine.h"
|
#include "Core/PatchEngine.h"
|
||||||
|
|
||||||
struct GameHashes
|
struct GameHashes
|
||||||
|
@ -27,6 +30,11 @@ struct GameHashes
|
||||||
std::map<std::string /*hash*/, std::string /*patch name*/> hashes;
|
std::map<std::string /*hash*/, std::string /*patch name*/> hashes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using AllowList = std::map<std::string /*ID*/, GameHashes>;
|
||||||
|
|
||||||
|
void CheckHash(const std::string& game_id, GameHashes* game_hashes, const std::string& hash,
|
||||||
|
const std::string& patch_name);
|
||||||
|
|
||||||
TEST(PatchAllowlist, VerifyHashes)
|
TEST(PatchAllowlist, VerifyHashes)
|
||||||
{
|
{
|
||||||
// Load allowlist
|
// Load allowlist
|
||||||
|
@ -42,9 +50,9 @@ TEST(PatchAllowlist, VerifyHashes)
|
||||||
const auto& list_filepath = fmt::format("{}{}{}", sys_directory, DIR_SEP, APPROVED_LIST_FILENAME);
|
const auto& list_filepath = fmt::format("{}{}{}", sys_directory, DIR_SEP, APPROVED_LIST_FILENAME);
|
||||||
ASSERT_TRUE(JsonFromFile(list_filepath, &json_tree, &error))
|
ASSERT_TRUE(JsonFromFile(list_filepath, &json_tree, &error))
|
||||||
<< "Failed to open file at " << list_filepath;
|
<< "Failed to open file at " << list_filepath;
|
||||||
// Parse allowlist - Map<game id, Map<hash, name>
|
// Parse allowlist - Map<game id, Map<hash, name>>
|
||||||
ASSERT_TRUE(json_tree.is<picojson::object>());
|
ASSERT_TRUE(json_tree.is<picojson::object>());
|
||||||
std::map<std::string /*ID*/, GameHashes> allow_list;
|
AllowList allow_list;
|
||||||
for (const auto& entry : json_tree.get<picojson::object>())
|
for (const auto& entry : json_tree.get<picojson::object>())
|
||||||
{
|
{
|
||||||
ASSERT_TRUE(entry.second.is<picojson::object>());
|
ASSERT_TRUE(entry.second.is<picojson::object>());
|
||||||
|
@ -69,12 +77,25 @@ TEST(PatchAllowlist, VerifyHashes)
|
||||||
std::string game_id = file.virtualName.substr(0, file.virtualName.find_first_of('.'));
|
std::string game_id = file.virtualName.substr(0, file.virtualName.find_first_of('.'));
|
||||||
std::vector<PatchEngine::Patch> patches;
|
std::vector<PatchEngine::Patch> patches;
|
||||||
PatchEngine::LoadPatchSection("OnFrame", &patches, ini_file, Common::IniFile());
|
PatchEngine::LoadPatchSection("OnFrame", &patches, ini_file, Common::IniFile());
|
||||||
|
std::vector<Gecko::GeckoCode> geckos = Gecko::LoadCodes(Common::IniFile(), ini_file);
|
||||||
|
std::vector<ActionReplay::ARCode> action_replays =
|
||||||
|
ActionReplay::LoadCodes(Common::IniFile(), ini_file);
|
||||||
// Filter patches for RetroAchievements approved
|
// Filter patches for RetroAchievements approved
|
||||||
ReadEnabledOrDisabled<PatchEngine::Patch>(ini_file, "OnFrame", false, &patches);
|
for (auto& patch : patches)
|
||||||
|
patch.enabled = false;
|
||||||
ReadEnabledOrDisabled<PatchEngine::Patch>(ini_file, "Patches_RetroAchievements_Verified", true,
|
ReadEnabledOrDisabled<PatchEngine::Patch>(ini_file, "Patches_RetroAchievements_Verified", true,
|
||||||
&patches);
|
&patches);
|
||||||
|
for (auto& code : geckos)
|
||||||
|
code.enabled = false;
|
||||||
|
ReadEnabledOrDisabled<Gecko::GeckoCode>(ini_file, "Gecko_RetroAchievements_Verified", true,
|
||||||
|
&geckos);
|
||||||
|
for (auto& code : action_replays)
|
||||||
|
code.enabled = false;
|
||||||
|
ReadEnabledOrDisabled<ActionReplay::ARCode>(ini_file, "AR_RetroAchievements_Verified", true,
|
||||||
|
&action_replays);
|
||||||
// Get game section from allow list
|
// Get game section from allow list
|
||||||
auto game_itr = allow_list.find(game_id);
|
auto game_itr = allow_list.find(game_id);
|
||||||
|
bool itr_end = (game_itr == allow_list.end());
|
||||||
// Iterate over approved patches
|
// Iterate over approved patches
|
||||||
for (const auto& patch : patches)
|
for (const auto& patch : patches)
|
||||||
{
|
{
|
||||||
|
@ -92,38 +113,51 @@ TEST(PatchAllowlist, VerifyHashes)
|
||||||
context->Update(Common::BitCastToArray<u8>(entry.conditional));
|
context->Update(Common::BitCastToArray<u8>(entry.conditional));
|
||||||
}
|
}
|
||||||
auto digest = context->Finish();
|
auto digest = context->Finish();
|
||||||
std::string hash = Common::SHA1::DigestToString(digest);
|
CheckHash(game_id, itr_end ? nullptr : &game_itr->second,
|
||||||
// Check patch in list
|
Common::SHA1::DigestToString(digest), patch.name);
|
||||||
if (game_itr == allow_list.end())
|
}
|
||||||
|
// Iterate over approved geckos
|
||||||
|
for (const auto& code : geckos)
|
||||||
{
|
{
|
||||||
// Report: no patches in game found in list
|
if (!code.enabled)
|
||||||
ADD_FAILURE() << "Approved hash missing from list." << std::endl
|
|
||||||
<< "Game ID: " << game_id << std::endl
|
|
||||||
<< "Patch: \"" << hash << "\" : \"" << patch.name << "\"";
|
|
||||||
continue;
|
continue;
|
||||||
}
|
// Hash patch
|
||||||
auto hash_itr = game_itr->second.hashes.find(hash);
|
auto context = Common::SHA1::CreateContext();
|
||||||
if (hash_itr == game_itr->second.hashes.end())
|
context->Update(Common::BitCastToArray<u8>(static_cast<u64>(code.codes.size())));
|
||||||
|
for (const auto& entry : code.codes)
|
||||||
{
|
{
|
||||||
// Report: patch not found in list
|
context->Update(Common::BitCastToArray<u8>(entry.address));
|
||||||
ADD_FAILURE() << "Approved hash missing from list." << std::endl
|
context->Update(Common::BitCastToArray<u8>(entry.data));
|
||||||
<< "Game ID: " << game_id << ":" << game_itr->second.game_title << std::endl
|
|
||||||
<< "Patch: \"" << hash << "\" : \"" << patch.name << "\"";
|
|
||||||
}
|
}
|
||||||
else
|
auto digest = context->Finish();
|
||||||
|
CheckHash(game_id, itr_end ? nullptr : &game_itr->second,
|
||||||
|
Common::SHA1::DigestToString(digest), code.name);
|
||||||
|
}
|
||||||
|
// Iterate over approved AR codes
|
||||||
|
for (const auto& code : action_replays)
|
||||||
{
|
{
|
||||||
// Remove patch from map if found
|
if (!code.enabled)
|
||||||
game_itr->second.hashes.erase(hash_itr);
|
continue;
|
||||||
|
// Hash patch
|
||||||
|
auto context = Common::SHA1::CreateContext();
|
||||||
|
context->Update(Common::BitCastToArray<u8>(static_cast<u64>(code.ops.size())));
|
||||||
|
for (const auto& entry : code.ops)
|
||||||
|
{
|
||||||
|
context->Update(Common::BitCastToArray<u8>(entry.cmd_addr));
|
||||||
|
context->Update(Common::BitCastToArray<u8>(entry.value));
|
||||||
}
|
}
|
||||||
|
auto digest = context->Finish();
|
||||||
|
CheckHash(game_id, itr_end ? nullptr : &game_itr->second,
|
||||||
|
Common::SHA1::DigestToString(digest), code.name);
|
||||||
}
|
}
|
||||||
// Report missing patches in map
|
// Report missing patches in map
|
||||||
if (game_itr == allow_list.end())
|
if (itr_end)
|
||||||
continue;
|
continue;
|
||||||
for (auto& remaining_hashes : game_itr->second.hashes)
|
for (auto& remaining_hashes : game_itr->second.hashes)
|
||||||
{
|
{
|
||||||
ADD_FAILURE() << "Hash in list not approved in ini." << std::endl
|
ADD_FAILURE() << "Hash in list not approved in ini." << std::endl
|
||||||
<< "Game ID: " << game_id << ":" << game_itr->second.game_title << std::endl
|
<< "Game ID: " << game_id << ":" << game_itr->second.game_title << std::endl
|
||||||
<< "Patch: " << remaining_hashes.second << ":" << remaining_hashes.first;
|
<< "Code: " << remaining_hashes.second << ":" << remaining_hashes.first;
|
||||||
}
|
}
|
||||||
// Remove section from map
|
// Remove section from map
|
||||||
allow_list.erase(game_itr);
|
allow_list.erase(game_itr);
|
||||||
|
@ -136,3 +170,30 @@ TEST(PatchAllowlist, VerifyHashes)
|
||||||
<< remaining_games.second.game_title;
|
<< remaining_games.second.game_title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckHash(const std::string& game_id, GameHashes* game_hashes, const std::string& hash,
|
||||||
|
const std::string& patch_name)
|
||||||
|
{
|
||||||
|
// Check patch in list
|
||||||
|
if (game_hashes == nullptr)
|
||||||
|
{
|
||||||
|
// Report: no patches in game found in list
|
||||||
|
ADD_FAILURE() << "Approved hash missing from list." << std::endl
|
||||||
|
<< "Game ID: " << game_id << std::endl
|
||||||
|
<< "Code: \"" << hash << "\": \"" << patch_name << "\"";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto hash_itr = game_hashes->hashes.find(hash);
|
||||||
|
if (hash_itr == game_hashes->hashes.end())
|
||||||
|
{
|
||||||
|
// Report: patch not found in list
|
||||||
|
ADD_FAILURE() << "Approved hash missing from list." << std::endl
|
||||||
|
<< "Game ID: " << game_id << ":" << game_hashes->game_title << std::endl
|
||||||
|
<< "Code: \"" << hash << "\": \"" << patch_name << "\"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove patch from map if found
|
||||||
|
game_hashes->hashes.erase(hash_itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue