fixed high scores hashing

This commit is contained in:
thrust26 2021-01-04 10:45:47 +01:00
parent ba8132b10d
commit 4d2edc2922
3 changed files with 43 additions and 24 deletions

View File

@ -564,6 +564,24 @@ Int32 HighScoresManager::fromBCD(uInt8 bcd) const
return (bcd >> 4) * 10 + bcd % 16; return (bcd >> 4) * 10 + bcd % 16;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string HighScoresManager::hash(ScoresData& data) const
{
ostringstream buf;
buf << HIGHSCORE_HEADER << data.md5 << md5Props() << data.variation;
for(uInt32 r = 0; r < NUM_RANKS && data.scores[r].score; ++r)
{
buf << data.scores[r].score
<< data.scores[r].special
<< data.scores[r].name
<< data.scores[r].date;
}
return MD5::hash(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::saveHighScores(ScoresData& data) const void HighScoresManager::saveHighScores(ScoresData& data) const
{ {
@ -571,14 +589,13 @@ void HighScoresManager::saveHighScores(ScoresData& data) const
{ {
json hsObject = json::object(); json hsObject = json::object();
json hsData = json::object(); json hsData = json::object();
json jScores = json::array();
// Add header so that if the high score format changes in the future, // Add header so that if the high score format changes in the future,
// we'll know right away, without having to parse the rest of the data // we'll know right away, without having to parse the rest of the data
hsData[VERSION] = HIGHSCORE_HEADER; hsObject[VERSION] = HIGHSCORE_HEADER;
hsData[MD5] = data.md5; hsObject[MD5] = data.md5;
hsData[VARIATION] = data.variation; hsObject[PROPCHECK] = md5Props();
json jScores = json::array();
for(uInt32 r = 0; r < NUM_RANKS && data.scores[r].score; ++r) for(uInt32 r = 0; r < NUM_RANKS && data.scores[r].score; ++r)
{ {
@ -592,10 +609,10 @@ void HighScoresManager::saveHighScores(ScoresData& data) const
jScores.push_back(jScore); jScores.push_back(jScore);
} }
hsData[SCORES] = jScores; hsData[SCORES] = jScores;
hsData[PROPCHECK] = md5Props(); hsData[VARIATION] = data.variation;
hsObject[DATA] = hsData; hsObject[DATA] = hsData;
hsObject[CHECKSUM] = MD5::hash(hsData.dump()); hsObject[CHECKSUM] = hash(data);
myHighscoreRepository->save(data.md5, to_string(data.variation), hsObject.dump(2)); myHighscoreRepository->save(data.md5, to_string(data.variation), hsObject.dump(2));
} }
@ -608,11 +625,11 @@ void HighScoresManager::saveHighScores(ScoresData& data) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::loadHighScores(ScoresData& data) void HighScoresManager::loadHighScores(ScoresData& data)
{ {
bool invalid = false;
ostringstream buf; ostringstream buf;
clearHighScores(data); clearHighScores(data);
bool invalid = false;
try { try {
Variant serializedHighscore; Variant serializedHighscore;
@ -620,27 +637,27 @@ void HighScoresManager::loadHighScores(ScoresData& data)
{ {
const json hsObject = json::parse(serializedHighscore.toString()); const json hsObject = json::parse(serializedHighscore.toString());
if(hsObject.contains(DATA)) // First test if we have a valid header
// If so, do a complete high score data load
if(!hsObject.contains(VERSION) || hsObject.at(VERSION) != HIGHSCORE_HEADER)
buf << "Error: Incompatible high scores data for variation " << data.variation << ".";
else if(hsObject.contains(DATA))
{ {
const json hsData = hsObject.at(DATA); const json hsData = hsObject.at(DATA);
// First test if we have a valid header if(!load(hsData, data)
// If so, do a complete high score data load || !hsObject.contains(MD5) || hsObject.at(MD5) != data.md5
if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER) || !hsObject.contains(PROPCHECK) || hsObject.at(PROPCHECK) != md5Props()
buf << "Error: Incompatible high scores data for variation " << data.variation << "."; || !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != hash(data))
invalid = true;
else else
{ return; // scores loaded OK
if(!load(hsData, data)
|| !hsData.contains(PROPCHECK) || hsData.at(PROPCHECK) != md5Props()
|| !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != MD5::hash(hsData.dump()))
invalid = true;
else
return;
}
} }
else else
invalid = true; invalid = true;
} }
else
return; // no scores for variation found
} }
catch(...) { invalid = true; } catch(...) { invalid = true; }
@ -655,8 +672,7 @@ void HighScoresManager::loadHighScores(ScoresData& data)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::load(const json& hsData, ScoresData& data) bool HighScoresManager::load(const json& hsData, ScoresData& data)
{ {
if(!hsData.contains(MD5) || hsData.at(MD5) != data.md5 if(!hsData.contains(VARIATION) || hsData.at(VARIATION) != data.variation
|| !hsData.contains(VARIATION) || hsData.at(VARIATION) != data.variation
|| !hsData.contains(SCORES)) || !hsData.contains(SCORES))
return false; return false;

View File

@ -18,7 +18,7 @@
#ifndef HIGHSCORES_MANAGER_HXX #ifndef HIGHSCORES_MANAGER_HXX
#define HIGHSCORES_MANAGER_HXX #define HIGHSCORES_MANAGER_HXX
#define HIGHSCORE_HEADER "06010000highscores" #define HIGHSCORE_HEADER "06050000highscores"
class OSystem; class OSystem;
@ -232,6 +232,7 @@ class HighScoresManager
uInt16 fromHexStr(const string& addr) const; uInt16 fromHexStr(const string& addr) const;
Int32 fromBCD(uInt8 bcd) const; Int32 fromBCD(uInt8 bcd) const;
string hash(HSM::ScoresData& data) const;
/** /**
Loads the current high scores for this game and variation from the given JSON object. Loads the current high scores for this game and variation from the given JSON object.

View File

@ -204,6 +204,8 @@ HighScoresDialog::HighScoresDialog(OSystem& osystem, DialogContainer& parent,
addDefaultsOKCancelBGroup(wid, _font, "Save", "Cancel", " Reset "); addDefaultsOKCancelBGroup(wid, _font, "Save", "Cancel", " Reset ");
_defaultWidget->setToolTip("Click to reset all high scores of this variation."); _defaultWidget->setToolTip("Click to reset all high scores of this variation.");
addToFocusList(wid); addToFocusList(wid);
_focusedWidget = _okWidget; // start with focus on 'Save' button
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -