GameFile: Calculate a sensible sync hash for mod descriptors.

This commit is contained in:
Admiral H. Curtiss 2021-11-13 21:15:45 +01:00
parent 005e850ad6
commit 418bb0b087
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
1 changed files with 66 additions and 5 deletions

View File

@ -22,6 +22,7 @@
#include <mbedtls/sha1.h>
#include <pugixml.hpp>
#include "Common/BitUtils.h"
#include "Common/ChunkFile.h"
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
@ -624,15 +625,75 @@ std::string GameFile::GetNetPlayName(const Core::TitleDatabase& title_database)
return name + " (" + ss.str() + ")";
}
static std::array<u8, 20> GetHash(u32 value)
{
auto data = Common::BitCastToArray<u8>(value);
std::array<u8, 20> hash;
mbedtls_sha1_ret(reinterpret_cast<const unsigned char*>(data.data()), data.size(), hash.data());
return hash;
}
static std::array<u8, 20> GetHash(std::string_view str)
{
std::array<u8, 20> hash;
mbedtls_sha1_ret(reinterpret_cast<const unsigned char*>(str.data()), str.size(), hash.data());
return hash;
}
static std::optional<std::array<u8, 20>> GetFileHash(const std::string& path)
{
std::string buffer;
if (!File::ReadFileToString(path, buffer))
return std::nullopt;
return GetHash(buffer);
}
static std::optional<std::array<u8, 20>> MixHash(const std::optional<std::array<u8, 20>>& lhs,
const std::optional<std::array<u8, 20>>& rhs)
{
if (!lhs && !rhs)
return std::nullopt;
if (!lhs || !rhs)
return !rhs ? lhs : rhs;
std::array<u8, 20> result;
for (size_t i = 0; i < result.size(); ++i)
result[i] = (*lhs)[i] ^ (*rhs)[(i + 1) % result.size()];
return result;
}
std::array<u8, 20> GameFile::GetSyncHash() const
{
std::array<u8, 20> hash{};
std::optional<std::array<u8, 20>> hash;
if (m_platform == DiscIO::Platform::ELFOrDOL)
{
std::string buffer;
if (File::ReadFileToString(m_file_path, buffer))
mbedtls_sha1_ret(reinterpret_cast<unsigned char*>(buffer.data()), buffer.size(), hash.data());
hash = GetFileHash(m_file_path);
}
else if (m_blob_type == DiscIO::BlobType::MOD_DESCRIPTOR)
{
auto descriptor = DiscIO::ParseGameModDescriptorFile(m_file_path);
if (descriptor)
{
GameFile proxy(descriptor->base_file);
if (proxy.IsValid())
hash = proxy.GetSyncHash();
// add patches to hash if they're enabled
if (descriptor->riivolution)
{
for (const auto& patch : descriptor->riivolution->patches)
{
hash = MixHash(hash, GetFileHash(patch.xml));
for (const auto& option : patch.options)
{
hash = MixHash(hash, GetHash(option.section_name));
hash = MixHash(hash, GetHash(option.option_id));
hash = MixHash(hash, GetHash(option.option_name));
hash = MixHash(hash, GetHash(option.choice));
}
}
}
}
}
else
{
@ -640,7 +701,7 @@ std::array<u8, 20> GameFile::GetSyncHash() const
hash = volume->GetSyncHash();
}
return hash;
return hash.value_or(std::array<u8, 20>{});
}
NetPlay::SyncIdentifier GameFile::GetSyncIdentifier() const