String copy util method and fix Save Manager string copy overflows (#3274)

* add safe string copy method

* use string copy for save manager

* use string copy in spoiler log hint parsing

* remove intermediate string vars

* more string copy use in randomizer methods

* use string copy in gameplay stats

* add load char array method to remove string intermediate var

* try string.h import instead
This commit is contained in:
Adam Bird 2023-10-27 15:18:56 -04:00 committed by GitHub
parent 837072f80f
commit fd09a12fff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 105 additions and 134 deletions

View File

@ -7,6 +7,7 @@ extern "C" {
#include "functions.h"
#include "macros.h"
#include "../UIWidgets.hpp"
#include "soh/util.h"
#include <vector>
#include <string>
@ -286,10 +287,8 @@ extern "C" char* GameplayStats_GetCurrentTime() {
}
void LoadStatsVersion1() {
std::string buildVersion;
SaveManager::Instance->LoadData("buildVersion", buildVersion);
strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1);
gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0;
SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion,
ARRAY_COUNT(gSaveContext.sohStats.buildVersion));
SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor);
SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor);
SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch);
@ -683,8 +682,8 @@ void InitStats(bool isDebug) {
gSaveContext.sohStats.entrancesDiscovered[entrancesIdx] = 0;
}
strncpy(gSaveContext.sohStats.buildVersion, (const char*) gBuildVersion, sizeof(gSaveContext.sohStats.buildVersion) - 1);
gSaveContext.sohStats.buildVersion[sizeof(gSaveContext.sohStats.buildVersion) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.sohStats.buildVersion, std::string((char*)gBuildVersion),
ARRAY_COUNT(gSaveContext.sohStats.buildVersion));
gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor;
gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor;
gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch;

View File

@ -30,6 +30,7 @@
#include <boost_custom/container_hash/hash_32.hpp>
#include "randomizer_settings_window.h"
#include "savefile.h"
#include "soh/util.h"
extern "C" uint32_t ResourceMgr_IsGameMasterQuest();
extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
@ -1298,24 +1299,20 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
bool success = false;
// Have all these use strncpy so that the null terminator is copied
// and also set the last index to null for safety
try {
json spoilerFileJson;
spoilerFileStream >> spoilerFileJson;
std::string childAltarJsonText = spoilerFileJson["childAltar"]["hintText"].get<std::string>();
std::string formattedChildAltarText = FormatJsonHintText(childAltarJsonText);
strncpy(gSaveContext.childAltarText, formattedChildAltarText.c_str(), sizeof(gSaveContext.childAltarText) - 1);
gSaveContext.childAltarText[sizeof(gSaveContext.childAltarText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.childAltarText,
FormatJsonHintText(spoilerFileJson["childAltar"]["hintText"]),
ARRAY_COUNT(gSaveContext.childAltarText));
gSaveContext.rewardCheck[0] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["emeraldLoc"]];
gSaveContext.rewardCheck[1] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["rubyLoc"]];
gSaveContext.rewardCheck[2] = SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["sapphireLoc"]];
std::string adultAltarJsonText = spoilerFileJson["adultAltar"]["hintText"].get<std::string>();
std::string formattedAdultAltarText = FormatJsonHintText(adultAltarJsonText);
strncpy(gSaveContext.adultAltarText, formattedAdultAltarText.c_str(), sizeof(gSaveContext.adultAltarText) - 1);
gSaveContext.adultAltarText[sizeof(gSaveContext.adultAltarText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.adultAltarText,
FormatJsonHintText(spoilerFileJson["adultAltar"]["hintText"]),
ARRAY_COUNT(gSaveContext.adultAltarText));
gSaveContext.rewardCheck[3] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["forestMedallionLoc"]];
gSaveContext.rewardCheck[4] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["fireMedallionLoc"]];
gSaveContext.rewardCheck[5] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["waterMedallionLoc"]];
@ -1323,65 +1320,42 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
gSaveContext.rewardCheck[7] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"]];
gSaveContext.rewardCheck[8] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"]];
std::string ganonHintJsonText = spoilerFileJson["ganonHintText"].get<std::string>();
std::string formattedGanonHintJsonText = FormatJsonHintText(ganonHintJsonText);
strncpy(gSaveContext.ganonHintText, formattedGanonHintJsonText.c_str(), sizeof(gSaveContext.ganonHintText) - 1);
gSaveContext.ganonHintText[sizeof(gSaveContext.ganonHintText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.ganonHintText, spoilerFileJson["ganonHintText"],
ARRAY_COUNT(gSaveContext.ganonHintText));
gSaveContext.masterSwordHintCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["masterSwordHintLoc"]];
std::string ganonJsonText = spoilerFileJson["ganonText"].get<std::string>();
std::string formattedGanonJsonText = FormatJsonHintText(ganonJsonText);
strncpy(gSaveContext.ganonText, formattedGanonJsonText.c_str(), sizeof(gSaveContext.ganonText) - 1);
gSaveContext.ganonText[sizeof(gSaveContext.ganonText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.ganonText, spoilerFileJson["ganonText"],
ARRAY_COUNT(gSaveContext.ganonText));
std::string dampeJsonText = spoilerFileJson["dampeText"].get<std::string>();
std::string formattedDampeJsonText = FormatJsonHintText(dampeJsonText);
strncpy(gSaveContext.dampeText, formattedDampeJsonText.c_str(), sizeof(gSaveContext.dampeText) - 1);
gSaveContext.dampeText[sizeof(gSaveContext.dampeText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.dampeText, spoilerFileJson["dampeText"],
ARRAY_COUNT(gSaveContext.dampeText));
gSaveContext.dampeCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"]];
std::string gregJsonText = spoilerFileJson["gregText"].get<std::string>();
std::string formattedGregJsonText = FormatJsonHintText(gregJsonText);
strncpy(gSaveContext.gregHintText, formattedGregJsonText.c_str(), sizeof(gSaveContext.gregHintText) - 1);
gSaveContext.gregHintText[sizeof(gSaveContext.gregHintText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.gregHintText, spoilerFileJson["gregText"],
ARRAY_COUNT(gSaveContext.gregHintText));
gSaveContext.gregCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"]];
std::string sheikJsonText = spoilerFileJson["sheikText"].get<std::string>();
std::string formattedSheikJsonText = FormatJsonHintText(sheikJsonText);
strncpy(gSaveContext.sheikText, formattedSheikJsonText.c_str(), sizeof(gSaveContext.sheikText) - 1);
gSaveContext.sheikText[sizeof(gSaveContext.sheikText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.sheikText, spoilerFileJson["sheikText"],
ARRAY_COUNT(gSaveContext.sheikText));
gSaveContext.lightArrowHintCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"]];
std::string sariaJsonText = spoilerFileJson["sariaText"].get<std::string>();
std::string formattedSariaJsonText = FormatJsonHintText(sariaJsonText);
strncpy(gSaveContext.sariaText, formattedSariaJsonText.c_str(), sizeof(gSaveContext.sariaText) - 1);
gSaveContext.sariaText[sizeof(gSaveContext.sariaText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.sariaText, spoilerFileJson["sariaText"],
ARRAY_COUNT(gSaveContext.sariaText));
gSaveContext.sariaCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["sariaHintLoc"]];
std::string warpMinuetJsonText = spoilerFileJson["warpMinuetText"].get<std::string>();
strncpy(gSaveContext.warpMinuetText, warpMinuetJsonText.c_str(), sizeof(gSaveContext.warpMinuetText) - 1);
gSaveContext.warpMinuetText[sizeof(gSaveContext.warpMinuetText) - 1] = 0;
std::string warpBoleroJsonText = spoilerFileJson["warpBoleroText"].get<std::string>();
strncpy(gSaveContext.warpBoleroText, warpBoleroJsonText.c_str(), sizeof(gSaveContext.warpBoleroText) - 1);
gSaveContext.warpBoleroText[sizeof(gSaveContext.warpBoleroText) - 1] = 0;
std::string warpSerenadeJsonText = spoilerFileJson["warpSerenadeText"].get<std::string>();
strncpy(gSaveContext.warpSerenadeText, warpSerenadeJsonText.c_str(), sizeof(gSaveContext.warpSerenadeText) - 1);
gSaveContext.warpSerenadeText[sizeof(gSaveContext.warpSerenadeText) - 1] = 0;
std::string warpRequiemJsonText = spoilerFileJson["warpRequiemText"].get<std::string>();
strncpy(gSaveContext.warpRequiemText, warpRequiemJsonText.c_str(), sizeof(gSaveContext.warpRequiemText) - 1);
gSaveContext.warpRequiemText[sizeof(gSaveContext.warpRequiemText) - 1] = 0;
std::string warpNocturneJsonText = spoilerFileJson["warpNocturneText"].get<std::string>();
strncpy(gSaveContext.warpNocturneText, warpNocturneJsonText.c_str(), sizeof(gSaveContext.warpNocturneText) - 1);
gSaveContext.warpNocturneText[sizeof(gSaveContext.warpNocturneText) - 1] = 0;
std::string warpPreludeJsonText = spoilerFileJson["warpPreludeText"].get<std::string>();
strncpy(gSaveContext.warpPreludeText, warpPreludeJsonText.c_str(), sizeof(gSaveContext.warpPreludeText) - 1);
gSaveContext.warpPreludeText[sizeof(gSaveContext.warpPreludeText) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.warpMinuetText, spoilerFileJson["warpMinuetText"],
ARRAY_COUNT(gSaveContext.warpMinuetText));
SohUtils::CopyStringToCharArray(gSaveContext.warpBoleroText, spoilerFileJson["warpBoleroText"],
ARRAY_COUNT(gSaveContext.warpBoleroText));
SohUtils::CopyStringToCharArray(gSaveContext.warpSerenadeText, spoilerFileJson["warpSerenadeText"],
ARRAY_COUNT(gSaveContext.warpSerenadeText));
SohUtils::CopyStringToCharArray(gSaveContext.warpRequiemText, spoilerFileJson["warpRequiemText"],
ARRAY_COUNT(gSaveContext.warpRequiemText));
SohUtils::CopyStringToCharArray(gSaveContext.warpNocturneText, spoilerFileJson["warpNocturneText"],
ARRAY_COUNT(gSaveContext.warpNocturneText));
SohUtils::CopyStringToCharArray(gSaveContext.warpPreludeText, spoilerFileJson["warpPreludeText"],
ARRAY_COUNT(gSaveContext.warpPreludeText));
json hintsJson = spoilerFileJson["hints"];
int index = 0;
@ -1408,10 +1382,7 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
gSaveContext.hintLocations[index].area = SpoilerfileAreaNameToEnum[hintInfo["area"]];
}
std::string hintMessage = FormatJsonHintText(hintInfo["hint"]);
size_t maxHintTextSize = sizeof(gSaveContext.hintLocations[index].hintText);
strncpy(gSaveContext.hintLocations[index].hintText, hintMessage.c_str(), maxHintTextSize - 1);
gSaveContext.hintLocations[index].hintText[maxHintTextSize - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.hintLocations[index].hintText, hintInfo["hint"], ARRAY_COUNT(gSaveContext.hintLocations[index].hintText));
index++;
}
@ -1542,9 +1513,8 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent
index++;
}
std::string inputSeed = spoilerFileJson["seed"].get<std::string>();
strncpy(gSaveContext.inputSeed, inputSeed.c_str(), sizeof(gSaveContext.inputSeed) - 1);
gSaveContext.inputSeed[sizeof(gSaveContext.inputSeed) - 1] = 0;
SohUtils::CopyStringToCharArray(gSaveContext.inputSeed, spoilerFileJson["seed"],
ARRAY_COUNT(gSaveContext.inputSeed));
gSaveContext.finalSeed = spoilerFileJson["finalSeed"].get<uint32_t>();
@ -1562,8 +1532,8 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent
gSaveContext.itemLocations[randomizerCheck].get.fakeRgID =
SpoilerfileGetNameToEnum[itemit.value()];
} else if (itemit.key() == "trickName") {
strncpy(gSaveContext.itemLocations[randomizerCheck].get.trickName,
std::string(itemit.value()).c_str(), MAX_TRICK_NAME_SIZE);
SohUtils::CopyStringToCharArray(gSaveContext.itemLocations[randomizerCheck].get.trickName,
itemit.value(), MAX_TRICK_NAME_SIZE);
}
}
} else {
@ -3186,7 +3156,7 @@ void RandomizerSettingsWindow::DrawElement() {
);
ImGui::SameLine();
if (ImGui::Button("New Seed")) {
strncpy(seedString, std::to_string(rand() & 0xFFFFFFFF).c_str(), MAX_SEED_STRING_SIZE);
SohUtils::CopyStringToCharArray(seedString, std::to_string(rand() & 0xFFFFFFFF), MAX_SEED_STRING_SIZE);
}
UIWidgets::Tooltip("Creates a new random seed value to be used when generating a randomizer");
ImGui::SameLine();

View File

@ -1,6 +1,7 @@
#include "SaveManager.h"
#include "OTRGlobals.h"
#include "Enhancements/game-interactor/GameInteractor.h"
#include "soh/util.h"
#include "z64.h"
#include "functions.h"
@ -95,9 +96,8 @@ void SaveManager::LoadRandomizerVersion1() {
SaveManager::Instance->LoadStruct("get" + std::to_string(i), [&]() {
SaveManager::Instance->LoadData("rgID", gSaveContext.itemLocations[i].get.rgID);
SaveManager::Instance->LoadData("fakeRgID", gSaveContext.itemLocations[i].get.fakeRgID);
std::string trickName;
SaveManager::Instance->LoadData("trickName", trickName);
strncpy(gSaveContext.itemLocations[i].get.trickName, trickName.c_str(), MAX_TRICK_NAME_SIZE);
SaveManager::Instance->LoadCharArray("trickName", gSaveContext.itemLocations[i].get.trickName,
MAX_TRICK_NAME_SIZE);
});
SaveManager::Instance->LoadData("check" + std::to_string(i), gSaveContext.itemLocations[i].check);
}
@ -168,9 +168,8 @@ void SaveManager::LoadRandomizerVersion2() {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("rgID", gSaveContext.itemLocations[i].get.rgID);
SaveManager::Instance->LoadData("fakeRgID", gSaveContext.itemLocations[i].get.fakeRgID);
std::string trickName;
SaveManager::Instance->LoadData("trickName", trickName);
strncpy(gSaveContext.itemLocations[i].get.trickName, trickName.c_str(), MAX_TRICK_NAME_SIZE);
SaveManager::Instance->LoadCharArray("trickName", gSaveContext.itemLocations[i].get.trickName,
MAX_TRICK_NAME_SIZE);
});
});
@ -189,8 +188,7 @@ void SaveManager::LoadRandomizerVersion2() {
});
std::string inputSeed;
SaveManager::Instance->LoadData("inputSeed", inputSeed);
memcpy(gSaveContext.inputSeed, inputSeed.c_str(), inputSeed.length() + 1);
SaveManager::Instance->LoadCharArray("inputSeed", gSaveContext.inputSeed, ARRAY_COUNT(gSaveContext.inputSeed));
SaveManager::Instance->LoadData("finalSeed", gSaveContext.finalSeed);
@ -202,54 +200,41 @@ void SaveManager::LoadRandomizerVersion2() {
SaveManager::Instance->LoadArray("hintLocations", ARRAY_COUNT(gSaveContext.hintLocations), [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("check", gSaveContext.hintLocations[i].check);
std::string hintText;
SaveManager::Instance->LoadData("hintText", hintText);
memcpy(gSaveContext.hintLocations[i].hintText, hintText.c_str(), hintText.length());
SaveManager::Instance->LoadCharArray("hintText", gSaveContext.hintLocations[i].hintText,
ARRAY_COUNT(gSaveContext.hintLocations[i].hintText));
});
});
std::string childAltarText;
SaveManager::Instance->LoadData("childAltarText", childAltarText);
memcpy(gSaveContext.childAltarText, childAltarText.c_str(), childAltarText.length());
std::string adultAltarText;
SaveManager::Instance->LoadData("adultAltarText", adultAltarText);
memcpy(gSaveContext.adultAltarText, adultAltarText.c_str(), adultAltarText.length());
std::string ganonHintText;
SaveManager::Instance->LoadData("ganonHintText", ganonHintText);
memcpy(gSaveContext.ganonHintText, ganonHintText.c_str(), ganonHintText.length());
std::string ganonText;
SaveManager::Instance->LoadData("ganonText", ganonText);
memcpy(gSaveContext.ganonText, ganonText.c_str(), ganonText.length());
std::string dampeText;
SaveManager::Instance->LoadData("dampeText", dampeText);
memcpy(gSaveContext.dampeText, dampeText.c_str(), dampeText.length());
std::string gregHintText;
SaveManager::Instance->LoadData("gregHintText", gregHintText);
memcpy(gSaveContext.gregHintText, gregHintText.c_str(), gregHintText.length());
std::string sheikText;
SaveManager::Instance->LoadData("sheikText", sheikText);
memcpy(gSaveContext.sheikText, sheikText.c_str(), sheikText.length() + 1);
std::string sariaText;
SaveManager::Instance->LoadData("sariaText", sariaText);
memcpy(gSaveContext.sariaText, sariaText.c_str(), sariaText.length() + 1);
std::string warpMinuetText;
SaveManager::Instance->LoadData("warpMinuetText", warpMinuetText);
memcpy(gSaveContext.warpMinuetText, warpMinuetText.c_str(), warpMinuetText.length());
std::string warpBoleroText;
SaveManager::Instance->LoadData("warpBoleroText", warpBoleroText);
memcpy(gSaveContext.warpBoleroText, warpBoleroText.c_str(), warpBoleroText.length());
std::string warpSerenadeText;
SaveManager::Instance->LoadData("warpSerenadeText", warpSerenadeText);
memcpy(gSaveContext.warpSerenadeText, warpSerenadeText.c_str(), warpSerenadeText.length());
std::string warpRequiemText;
SaveManager::Instance->LoadData("warpRequiemText", warpRequiemText);
memcpy(gSaveContext.warpRequiemText, warpRequiemText.c_str(), warpRequiemText.length());
std::string warpNocturneText;
SaveManager::Instance->LoadData("warpNocturneText", warpNocturneText);
memcpy(gSaveContext.warpNocturneText, warpNocturneText.c_str(), warpNocturneText.length());
std::string warpPreludeText;
SaveManager::Instance->LoadData("warpPreludeText", warpPreludeText);
memcpy(gSaveContext.warpPreludeText, warpPreludeText.c_str(), warpPreludeText.length());
SaveManager::Instance->LoadCharArray("childAltarText", gSaveContext.childAltarText,
ARRAY_COUNT(gSaveContext.childAltarText));
SaveManager::Instance->LoadCharArray("adultAltarText", gSaveContext.adultAltarText,
ARRAY_COUNT(gSaveContext.adultAltarText));
SaveManager::Instance->LoadCharArray("ganonHintText", gSaveContext.ganonHintText,
ARRAY_COUNT(gSaveContext.ganonHintText));
SaveManager::Instance->LoadCharArray("ganonText", gSaveContext.ganonText, ARRAY_COUNT(gSaveContext.ganonText));
SaveManager::Instance->LoadCharArray("dampeText", gSaveContext.dampeText, ARRAY_COUNT(gSaveContext.dampeText));
SaveManager::Instance->LoadCharArray("gregHintText", gSaveContext.gregHintText,
ARRAY_COUNT(gSaveContext.gregHintText));
SaveManager::Instance->LoadCharArray("sheikText", gSaveContext.sheikText, ARRAY_COUNT(gSaveContext.sheikText));
SaveManager::Instance->LoadCharArray("sariaText", gSaveContext.sariaText, ARRAY_COUNT(gSaveContext.sariaText));
SaveManager::Instance->LoadCharArray("warpMinuetText", gSaveContext.warpMinuetText,
ARRAY_COUNT(gSaveContext.warpMinuetText));
SaveManager::Instance->LoadCharArray("warpBoleroText", gSaveContext.warpBoleroText,
ARRAY_COUNT(gSaveContext.warpBoleroText));
SaveManager::Instance->LoadCharArray("warpSerenadeText", gSaveContext.warpSerenadeText,
ARRAY_COUNT(gSaveContext.warpSerenadeText));
SaveManager::Instance->LoadCharArray("warpRequiemText", gSaveContext.warpRequiemText,
ARRAY_COUNT(gSaveContext.warpRequiemText));
SaveManager::Instance->LoadCharArray("warpNocturneText", gSaveContext.warpNocturneText,
ARRAY_COUNT(gSaveContext.warpNocturneText));
SaveManager::Instance->LoadCharArray("warpPreludeText", gSaveContext.warpPreludeText,
ARRAY_COUNT(gSaveContext.warpPreludeText));
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
@ -466,8 +451,8 @@ void SaveManager::InitMeta(int fileNum) {
fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor;
fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor;
fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.sohStats.buildVersionPatch;
strncpy(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, sizeof(fileMetaInfo[fileNum].buildVersion) - 1);
fileMetaInfo[fileNum].buildVersion[sizeof(fileMetaInfo[fileNum].buildVersion) - 1] = 0;
SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion,
ARRAY_COUNT(fileMetaInfo[fileNum].buildVersion));
}
void SaveManager::InitFile(bool isDebug) {
@ -1555,10 +1540,8 @@ void SaveManager::LoadBaseVersion3() {
SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens);
});
SaveManager::Instance->LoadStruct("sohStats", []() {
std::string buildVersion;
SaveManager::Instance->LoadData("buildVersion", buildVersion);
strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1);
gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0;
SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion,
ARRAY_COUNT(gSaveContext.sohStats.buildVersion));
SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor);
SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor);
SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch);
@ -2046,6 +2029,13 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav
SaveManager::Instance->SaveData("dogParams", saveContext->dogParams);
}
// Load a string into a char array based on size and ensuring it is null terminated when overflowed
void SaveManager::LoadCharArray(const std::string& name, char* destination, size_t size) {
std::string temp;
SaveManager::Instance->LoadData(name, temp);
SohUtils::CopyStringToCharArray(destination, temp, size);
}
void SaveManager::SaveArray(const std::string& name, const size_t size, SaveArrayFunc func) {
// Create an empty array and set it as the current save context, then call the function that saves an array entry.
nlohmann::json* saveJsonContext = currentJsonContext;
@ -2169,8 +2159,8 @@ void SaveManager::CopyZeldaFile(int from, int to) {
fileMetaInfo[to].buildVersionMajor = fileMetaInfo[from].buildVersionMajor;
fileMetaInfo[to].buildVersionMinor = fileMetaInfo[from].buildVersionMinor;
fileMetaInfo[to].buildVersionPatch = fileMetaInfo[from].buildVersionPatch;
strncpy(fileMetaInfo[to].buildVersion, fileMetaInfo[from].buildVersion, sizeof(fileMetaInfo[to].buildVersion) - 1);
fileMetaInfo[to].buildVersion[sizeof(fileMetaInfo[to].buildVersion) - 1] = 0;
SohUtils::CopyStringToCharArray(fileMetaInfo[to].buildVersion, fileMetaInfo[from].buildVersion,
ARRAY_COUNT(fileMetaInfo[to].buildVersion));
}
void SaveManager::DeleteZeldaFile(int fileNum) {

View File

@ -128,6 +128,8 @@ class SaveManager {
}
}
void LoadCharArray(const std::string& name, char* destination, size_t size);
// In the LoadArrayFunc func, the name must be "" to load from the array.
using LoadArrayFunc = std::function<void(size_t)>;
void LoadArray(const std::string& name, const size_t size, LoadArrayFunc func);

View File

@ -1,5 +1,6 @@
#include "util.h"
#include <string.h>
#include <vector>
std::vector<std::string> sceneNames = {
@ -312,3 +313,8 @@ const std::string& SohUtils::GetItemName(int32_t item) {
const std::string& SohUtils::GetQuestItemName(int32_t item) {
return questItemNames[item];
}
void SohUtils::CopyStringToCharArray(char* destination, std::string source, size_t size) {
strncpy(destination, source.c_str(), size - 1);
destination[size - 1] = '\0';
}

View File

@ -8,4 +8,8 @@ namespace SohUtils {
const std::string& GetItemName(int32_t item);
const std::string& GetQuestItemName(int32_t item);
// Copies a string and ensures the destination is null terminated if the source string is larger than size
// Only up to size-1 characters are copied from the source string
void CopyStringToCharArray(char* destination, std::string source, size_t size);
} // namespace SohUtils