summaryrefslogtreecommitdiff
path: root/Source/Core/UICommon/GameFile.cpp
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2021-11-13 21:15:45 +0100
committerAdmiral H. Curtiss <pikachu025@gmail.com>2021-12-12 21:26:09 +0100
commit418bb0b0878063876579e1ed142dcad64a243c0a (patch)
tree0aa1caee58d81f9ffc6a7e3f9aeec8fbc3b1137b /Source/Core/UICommon/GameFile.cpp
parent005e850ad6064f3ef6344678e4019ca940d56b72 (diff)
GameFile: Calculate a sensible sync hash for mod descriptors.
Diffstat (limited to 'Source/Core/UICommon/GameFile.cpp')
-rw-r--r--Source/Core/UICommon/GameFile.cpp71
1 files changed, 66 insertions, 5 deletions
diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp
index 3417051a54..c575d4018b 100644
--- a/Source/Core/UICommon/GameFile.cpp
+++ b/Source/Core/UICommon/GameFile.cpp
@@ -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