mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 21:01:37 +00:00
achievement_data: added checksum and format verification
This commit is contained in:
parent
6151be142e
commit
f1448b12e2
2 changed files with 117 additions and 16 deletions
|
|
@ -3,10 +3,29 @@
|
||||||
#include <ui/achievement_overlay.h>
|
#include <ui/achievement_overlay.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
|
|
||||||
|
#define NUM_RECORDS sizeof(Data.Records) / sizeof(Record)
|
||||||
|
|
||||||
|
time_t AchievementData::GetTimestamp(uint16_t id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_RECORDS; i++)
|
||||||
|
{
|
||||||
|
if (!Data.Records[i].ID)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (Data.Records[i].ID == id)
|
||||||
|
return Data.Records[i].Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool AchievementData::IsUnlocked(uint16_t id)
|
bool AchievementData::IsUnlocked(uint16_t id)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sizeof(Data.Records) / sizeof(Record); i++)
|
for (int i = 0; i < NUM_RECORDS; i++)
|
||||||
{
|
{
|
||||||
|
if (!Data.Records[i].ID)
|
||||||
|
break;
|
||||||
|
|
||||||
if (Data.Records[i].ID == id)
|
if (Data.Records[i].ID == id)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +38,7 @@ void AchievementData::Unlock(uint16_t id)
|
||||||
if (IsUnlocked(id))
|
if (IsUnlocked(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(Data.Records) / sizeof(Record); i++)
|
for (int i = 0; i < NUM_RECORDS; i++)
|
||||||
{
|
{
|
||||||
if (Data.Records[i].ID == 0)
|
if (Data.Records[i].ID == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -33,15 +52,39 @@ void AchievementData::Unlock(uint16_t id)
|
||||||
AchievementOverlay::Open(id);
|
AchievementOverlay::Open(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t AchievementData::GetTimestamp(uint16_t id)
|
uint32_t AchievementData::CalculateChecksum()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sizeof(Data.Records) / sizeof(Record); i++)
|
auto result = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_RECORDS; i++)
|
||||||
{
|
{
|
||||||
if (Data.Records[i].ID == id)
|
auto& record = Data.Records[i];
|
||||||
return Data.Records[i].Timestamp;
|
|
||||||
|
for (size_t j = 0; j < sizeof(Record); j++)
|
||||||
|
result ^= ((uint8_t*)(&record))[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AchievementData::VerifySignature()
|
||||||
|
{
|
||||||
|
char sig[4] = ACH_SIGNATURE;
|
||||||
|
|
||||||
|
return Data.Signature[0] == sig[0] &&
|
||||||
|
Data.Signature[1] == sig[1] &&
|
||||||
|
Data.Signature[2] == sig[2] &&
|
||||||
|
Data.Signature[3] == sig[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AchievementData::VerifyVersion()
|
||||||
|
{
|
||||||
|
return Data.Version == Version ACH_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AchievementData::VerifyChecksum()
|
||||||
|
{
|
||||||
|
return Data.Checksum == CalculateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementData::Load()
|
void AchievementData::Load()
|
||||||
|
|
@ -55,11 +98,48 @@ void AchievementData::Load()
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
printf("[*] Failed to parse achievement data.\n");
|
printf("[*] ERROR: failed to read achievement data.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file.read((char*)&Data.Signature, sizeof(Data.Signature));
|
||||||
|
|
||||||
|
if (!VerifySignature())
|
||||||
|
{
|
||||||
|
printf("[*] ERROR: invalid achievement data signature.\n");
|
||||||
|
|
||||||
|
char sig[4] = ACH_SIGNATURE;
|
||||||
|
|
||||||
|
Data.Signature[0] = sig[0];
|
||||||
|
Data.Signature[1] = sig[1];
|
||||||
|
Data.Signature[2] = sig[2];
|
||||||
|
Data.Signature[3] = sig[3];
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.read((char*)&Data.Version, sizeof(Data.Version));
|
||||||
|
|
||||||
|
if (!VerifyVersion())
|
||||||
|
{
|
||||||
|
printf("[*] ERROR: unsupported achievement data version.\n");
|
||||||
|
Data.Version = ACH_VERSION;
|
||||||
|
file.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.seekg(0);
|
||||||
file.read((char*)&Data, sizeof(Data));
|
file.read((char*)&Data, sizeof(Data));
|
||||||
|
|
||||||
|
// TODO: display error message to user before wiping data?
|
||||||
|
if (!VerifyChecksum())
|
||||||
|
{
|
||||||
|
printf("[*] ERROR: achievement data checksum mismatch.\n");
|
||||||
|
memset(&Data.Records, 0, sizeof(Data.Records));
|
||||||
|
}
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,10 +149,12 @@ void AchievementData::Save()
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
printf("[*] Failed to write achievement data.\n");
|
printf("[*] ERROR: failed to write achievement data.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data.Checksum = CalculateChecksum();
|
||||||
|
|
||||||
file.write((const char*)&Data, sizeof(Data));
|
file.write((const char*)&Data, sizeof(Data));
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <user/paths.h>
|
#include <user/paths.h>
|
||||||
|
|
||||||
#define ACH_SIGNATURE 'ACH '
|
#define ACH_SIGNATURE { 'A', 'C', 'H', ' ' }
|
||||||
#define ACH_VERSION 0x01000000
|
#define ACH_VERSION { 1, 0, 0 }
|
||||||
|
|
||||||
class AchievementData
|
class AchievementData
|
||||||
{
|
{
|
||||||
|
|
@ -18,12 +17,28 @@ public:
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct Version
|
||||||
|
{
|
||||||
|
uint8_t Major;
|
||||||
|
uint8_t Minor;
|
||||||
|
uint8_t Revision;
|
||||||
|
uint8_t Reserved;
|
||||||
|
|
||||||
|
bool operator==(const Version& other) const
|
||||||
|
{
|
||||||
|
return Major == other.Major &&
|
||||||
|
Minor == other.Minor &&
|
||||||
|
Revision == other.Revision;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Data
|
class Data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t Signature{};
|
char Signature[4];
|
||||||
uint32_t Version{};
|
Version Version{};
|
||||||
uint32_t Reserved[2];
|
uint32_t Checksum;
|
||||||
|
uint32_t Reserved;
|
||||||
Record Records[50];
|
Record Records[50];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -34,9 +49,13 @@ public:
|
||||||
return GetSavePath() / "ACH-DATA";
|
return GetSavePath() / "ACH-DATA";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static time_t GetTimestamp(uint16_t id);
|
||||||
static bool IsUnlocked(uint16_t id);
|
static bool IsUnlocked(uint16_t id);
|
||||||
static void Unlock(uint16_t id);
|
static void Unlock(uint16_t id);
|
||||||
static time_t GetTimestamp(uint16_t id);
|
static uint32_t CalculateChecksum();
|
||||||
|
static bool VerifySignature();
|
||||||
|
static bool VerifyVersion();
|
||||||
|
static bool VerifyChecksum();
|
||||||
static void Load();
|
static void Load();
|
||||||
static void Save();
|
static void Save();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue