mirror of
https://github.com/libretro/parallel-ps2.git
synced 2026-11-13 04:41:40 -10:00
Pcsx2Config's strings do not terminate in Pcsx2Config.cpp. They run
through two abstract interfaces:
FilenameOptions::Bios (std::string)
-> SettingsWrapper::Entry(..., std::string&) 2 impls
-> SettingsInterface::GetStringValue(std::string*) 2 impls
So the conversion starts at the bottom, as it had to in IopBios:
SettingsInterface gains GetStringValueBuf and SettingsWrapper gains
EntryBuf, both implemented in both of their subclasses
(MemorySettingsInterface / LayeredSettingsInterface, load / save).
With those in place the Config fields become mechanical.
GetStringValueBuf reports out_len -- the length the value actually had
-- so a caller can tell truncation from a short value. That is the
failure this whole area risks: a path cut at a buffer boundary is
silent, and nothing downstream can distinguish it from the user having
typed something short.
FilenameOptions::Bios is the first field converted. Its constructor
now zeroes the buffer explicitly, because a char array has no default
constructor and std::string did -- an uninitialised settings field
would read as garbage rather than as empty.
Verified with the round trip added in the previous commit: 14 cases, 0
failing, matching the pre-change baseline, including paths of exactly
64, 128, 255, 256, 511, 512 and 1024 bytes. Then the usual: BIOS still
found and identified at boot, Tekken from .cue, .cso and .chd at 1150
frame hashes each identical to baseline, savestate replay matching at
head[554], audio hash identical, gates 36/36. Both build systems, both
configurations.
The remaining Config fields -- Adapter, EthDevice, HddFile,
GzipIsoIndexTemplate, CurrentIRX, CurrentGameArgs, Mcd[].Filename --
are the same change repeated, each gated by the same round trip.
215 lines
5.6 KiB
C++
215 lines
5.6 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <compat/strl.h>
|
|
#include <utility>
|
|
|
|
#include "MemorySettingsInterface.h"
|
|
#include "StringUtil.h"
|
|
|
|
MemorySettingsInterface::MemorySettingsInterface() = default;
|
|
|
|
MemorySettingsInterface::~MemorySettingsInterface() = default;
|
|
|
|
bool MemorySettingsInterface::GetIntValue(const char* section, const char* key, s32* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
std::optional<s32> parsed = StringUtil::FromChars<s32>(iter->second, 10);
|
|
if (!parsed.has_value())
|
|
return false;
|
|
|
|
*value = parsed.value();
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetUIntValue(const char* section, const char* key, u32* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
std::optional<u32> parsed = StringUtil::FromChars<u32>(iter->second, 10);
|
|
if (!parsed.has_value())
|
|
return false;
|
|
|
|
*value = parsed.value();
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
std::optional<float> parsed = StringUtil::FromChars<float>(iter->second);
|
|
if (!parsed.has_value())
|
|
return false;
|
|
|
|
*value = parsed.value();
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
std::optional<double> parsed = StringUtil::FromChars<double>(iter->second);
|
|
if (!parsed.has_value())
|
|
return false;
|
|
|
|
*value = parsed.value();
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
std::optional<bool> parsed = StringUtil::FromChars<bool>(iter->second);
|
|
if (!parsed.has_value())
|
|
return false;
|
|
|
|
*value = parsed.value();
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
|
|
{
|
|
const auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return false;
|
|
|
|
const auto iter = sit->second.find(key);
|
|
if (iter == sit->second.end())
|
|
return false;
|
|
|
|
*value = iter->second;
|
|
return true;
|
|
}
|
|
|
|
bool MemorySettingsInterface::GetStringValueBuf(const char* section, const char* key,
|
|
char* value, size_t value_size, size_t* out_len) const
|
|
{
|
|
std::string tmp;
|
|
|
|
if (value_size)
|
|
value[0] = '\0';
|
|
if (out_len)
|
|
*out_len = 0;
|
|
|
|
if (!GetStringValue(section, key, &tmp))
|
|
return false;
|
|
|
|
if (out_len)
|
|
*out_len = tmp.size();
|
|
if (value_size)
|
|
strlcpy(value, tmp.c_str(), value_size);
|
|
return true;
|
|
}
|
|
|
|
void MemorySettingsInterface::SetIntValue(const char* section, const char* key, s32 value)
|
|
{
|
|
SetValue(section, key, std::to_string(value));
|
|
}
|
|
|
|
void MemorySettingsInterface::SetUIntValue(const char* section, const char* key, u32 value)
|
|
{
|
|
SetValue(section, key, std::to_string(value));
|
|
}
|
|
|
|
void MemorySettingsInterface::SetFloatValue(const char* section, const char* key, float value)
|
|
{
|
|
SetValue(section, key, std::to_string(value));
|
|
}
|
|
|
|
void MemorySettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
|
|
{
|
|
SetValue(section, key, std::to_string(value));
|
|
}
|
|
|
|
void MemorySettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
|
|
{
|
|
SetValue(section, key, std::to_string(value));
|
|
}
|
|
|
|
void MemorySettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
|
|
{
|
|
SetValue(section, key, value);
|
|
}
|
|
|
|
void MemorySettingsInterface::SetValue(const char* section, const char* key, std::string value)
|
|
{
|
|
auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
sit = m_sections.emplace(std::make_pair(std::string(section), KeyMap())).first;
|
|
|
|
const auto range = sit->second.equal_range(key);
|
|
if (range.first == sit->second.end())
|
|
{
|
|
sit->second.emplace(std::string(key), std::move(value));
|
|
return;
|
|
}
|
|
|
|
auto iter = range.first;
|
|
iter->second = std::move(value);
|
|
++iter;
|
|
|
|
// remove other values
|
|
while (iter != range.second)
|
|
{
|
|
auto remove = iter++;
|
|
sit->second.erase(remove);
|
|
}
|
|
}
|
|
|
|
void MemorySettingsInterface::DeleteValue(const char* section, const char* key)
|
|
{
|
|
auto sit = m_sections.find(section);
|
|
if (sit == m_sections.end())
|
|
return;
|
|
|
|
const auto range = sit->second.equal_range(key);
|
|
for (auto iter = range.first; iter != range.second;)
|
|
sit->second.erase(iter++);
|
|
}
|