[qt] fix various crashes due to invalid/corrupted/outdated settings (#4070)

lots of "out of index" errors :)

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4070
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
lizzie 2026-06-14 20:48:24 +02:00 committed by crueter
parent 1071353291
commit 60e1032771
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
13 changed files with 149 additions and 71 deletions

View file

@ -336,7 +336,7 @@ struct Values {
RendererBackend::Vulkan, RendererBackend::Vulkan,
#endif #endif
"backend", Category::Renderer}; "backend", Category::Renderer};
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList}; SwitchableSetting<u32> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList};
// Graphics Settings // Graphics Settings
ResolutionScalingInfo resolution_info{}; ResolutionScalingInfo resolution_info{};
@ -661,8 +661,8 @@ struct Values {
false, true, &custom_rtc_enabled}; false, true, &custom_rtc_enabled};
SwitchableSetting<s64, true> custom_rtc_offset{linkage, SwitchableSetting<s64, true> custom_rtc_offset{linkage,
0, 0,
(std::numeric_limits<int>::min)(), (std::numeric_limits<s64>::min)(),
(std::numeric_limits<int>::max)(), (std::numeric_limits<s64>::max)(),
"custom_rtc_offset", "custom_rtc_offset",
Category::System, Category::System,
Specialization::Countable, Specialization::Countable,
@ -751,7 +751,7 @@ struct Values {
Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850", Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
"touch_device", Category::Controls}; "touch_device", Category::Controls};
Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map", Setting<u32> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
Category::Controls}; Category::Controls};
std::vector<TouchFromButtonMap> touch_from_button_maps; std::vector<TouchFromButtonMap> touch_from_button_maps;

View file

@ -145,8 +145,8 @@ ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
ENUM(FullscreenMode, Borderless, Exclusive); ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu); ENUM(NvdecEmulation, Off, Cpu, Gpu);
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res5_4X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X); ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res5_4X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, Sgsr, SgsrEdge, MaxEnum); ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, Sgsr, SgsrEdge);
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum); ENUM(AntiAliasing, None, Fxaa, Smaa);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked); ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE); ENUM(AppletMode, HLE, LLE);

View file

@ -11,6 +11,7 @@
#include <optional> #include <optional>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <type_traits>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
#include <fmt/core.h> #include <fmt/core.h>
@ -101,7 +102,15 @@ public:
* @param val The desired value * @param val The desired value
*/ */
virtual void SetValue(const Type& val) { virtual void SetValue(const Type& val) {
Type temp{ranged ? std::clamp(val, minimum, maximum) : val}; // Enums have a maximal range which they're allowed
Type temp{};
if constexpr (std::is_enum_v<Type>) {
auto const r_min = std::underlying_type_t<Type>(0);
auto const r_max = std::underlying_type_t<Type>(EnumMetadata<Type>::GetLast());
temp = Type(std::clamp(std::underlying_type_t<Type>(val), r_min, r_max));
} else {
temp = ranged ? std::clamp(val, this->minimum, this->maximum) : val;
}
std::swap(value, temp); std::swap(value, temp);
} }
@ -129,7 +138,7 @@ protected:
} else if constexpr (std::is_floating_point_v<Type>) { } else if constexpr (std::is_floating_point_v<Type>) {
return fmt::format("{:f}", value_); return fmt::format("{:f}", value_);
} else if constexpr (std::is_enum_v<Type>) { } else if constexpr (std::is_enum_v<Type>) {
return std::to_string(u32(value_)); return std::to_string(std::underlying_type_t<Type>(value_));
} else { } else {
return std::to_string(value_); return std::to_string(value_);
} }
@ -371,7 +380,15 @@ public:
* @param val The new value * @param val The new value
*/ */
void SetValue(const Type& val) override final { void SetValue(const Type& val) override final {
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val}; // Enums have a maximal range which they're allowed
Type temp{};
if constexpr (std::is_enum_v<Type>) {
auto const r_min = std::underlying_type_t<Type>(0);
auto const r_max = std::underlying_type_t<Type>(EnumMetadata<Type>::GetLast());
temp = Type(std::clamp(std::underlying_type_t<Type>(val), r_min, r_max));
} else {
temp = ranged ? std::clamp(val, this->minimum, this->maximum) : val;
}
if (use_global) { if (use_global) {
std::swap(this->value, temp); std::swap(this->value, temp);
} else { } else {

View file

@ -238,33 +238,27 @@ void Config::ReadControlValues() {
void Config::ReadMotionTouchValues() { void Config::ReadMotionTouchValues() {
Settings::values.touch_from_button_maps.clear(); Settings::values.touch_from_button_maps.clear();
int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps")); int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps"));
if (num_touch_from_button_maps > 0) { if (num_touch_from_button_maps > 0) {
for (int i = 0; i < num_touch_from_button_maps; ++i) { for (int i = 0; i < num_touch_from_button_maps; ++i) {
SetArrayIndex(i); SetArrayIndex(i);
Settings::TouchFromButtonMap map; Settings::TouchFromButtonMap map;
map.name = ReadStringSetting(std::string("name"), std::string("default")); map.name = ReadStringSetting(std::string("name"), std::string("default"));
int const num_touch_maps = BeginArray(std::string("entries"));
const int num_touch_maps = BeginArray(std::string("entries")); map.buttons.resize(num_touch_maps);
map.buttons.reserve(num_touch_maps);
for (int j = 0; j < num_touch_maps; j++) { for (int j = 0; j < num_touch_maps; j++) {
SetArrayIndex(j); SetArrayIndex(j);
std::string touch_mapping = ReadStringSetting(std::string("bind")); map.buttons[j] = ReadStringSetting(std::string("bind"));
map.buttons.emplace_back(std::move(touch_mapping));
} }
EndArray(); // entries EndArray(); // entries
Settings::values.touch_from_button_maps.emplace_back(std::move(map)); Settings::values.touch_from_button_maps.emplace_back(std::move(map));
} }
} else { } else {
Settings::values.touch_from_button_maps.emplace_back( Settings::values.touch_from_button_maps.emplace_back(Settings::TouchFromButtonMap{"default", {}});
Settings::TouchFromButtonMap{"default", {}});
num_touch_from_button_maps = 1; num_touch_from_button_maps = 1;
} }
EndArray(); // touch_from_button_maps EndArray(); // touch_from_button_maps
Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index = (std::min)(Settings::values.touch_from_button_map_index.GetValue(), u32(num_touch_from_button_maps - 1));
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
} }
void Config::ReadCoreValues() { void Config::ReadCoreValues() {
@ -501,15 +495,12 @@ void Config::SaveMotionTouchValues() {
BeginArray(std::string("touch_from_button_maps")); BeginArray(std::string("touch_from_button_maps"));
for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
SetArrayIndex(int(p)); SetArrayIndex(int(p));
WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, std::make_optional(std::string("default")));
std::make_optional(std::string("default")));
BeginArray(std::string("entries")); BeginArray(std::string("entries"));
for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
++q) { ++q) {
SetArrayIndex(int(q)); SetArrayIndex(int(q));
WriteStringSetting(std::string("bind"), WriteStringSetting(std::string("bind"), Settings::values.touch_from_button_maps[p].buttons[q]);
Settings::values.touch_from_button_maps[p].buttons[q]);
} }
EndArray(); // entries EndArray(); // entries
} }
@ -638,8 +629,7 @@ void Config::SaveDisabledAddOnValues() {
BeginArray(std::string("disabled")); BeginArray(std::string("disabled"));
for (std::size_t j = 0; j < elem.second.size(); ++j) { for (std::size_t j = 0; j < elem.second.size(); ++j) {
SetArrayIndex(int(j)); SetArrayIndex(int(j));
WriteStringSetting(std::string("d"), elem.second[j], WriteStringSetting(std::string("d"), elem.second[j], std::make_optional(std::string("")));
std::make_optional(std::string("")));
} }
EndArray(); // disabled EndArray(); // disabled
++i; ++i;
@ -733,21 +723,18 @@ s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64>
std::string full_key = GetFullKey(key, false); std::string full_key = GetFullKey(key, false);
if (!default_value.has_value()) { if (!default_value.has_value()) {
try { try {
return std::stoll( return std::stoll(std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
} catch (...) { } catch (...) {
return 0; return 0;
} }
} }
s64 result = 0; s64 result = 0;
if (config->GetBoolValue(GetSection().c_str(), if (config->GetBoolValue(GetSection().c_str(), std::string(full_key).append("\\default").c_str(), true)) {
std::string(full_key).append("\\default").c_str(), true)) {
result = default_value.value(); result = default_value.value();
} else { } else {
try { try {
result = std::stoll(std::string(config->GetValue( result = std::stoll(std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
} catch (...) { } catch (...) {
result = default_value.value(); result = default_value.value();
} }
@ -919,14 +906,12 @@ void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
bool use_global = true; bool use_global = true;
if (setting->Switchable() && !global) { if (setting->Switchable() && !global) {
use_global = use_global = ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
setting->SetGlobal(use_global); setting->SetGlobal(use_global);
} }
if (global || !use_global) { if (global || !use_global) {
const bool is_default = const bool is_default = ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
if (!is_default) { if (!is_default) {
setting->LoadString(ReadStringSetting(key, default_value)); setting->LoadString(ReadStringSetting(key, default_value));
} else { } else {
@ -1050,10 +1035,9 @@ std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) {
int Config::BeginArray(const std::string& array) { int Config::BeginArray(const std::string& array) {
array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0}); array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0});
const int size = config->GetLongValue(GetSection().c_str(), const int size = config->GetLongValue(GetSection().c_str(), GetFullKey(std::string("size"), true).c_str(), 0);
GetFullKey(std::string("size"), true).c_str(), 0); array_stack.back().size = (std::max)(0, size);
array_stack.back().size = size; return array_stack.back().size;
return size;
} }
void Config::EndArray() { void Config::EndArray() {
@ -1071,7 +1055,7 @@ void Config::EndArray() {
// Edge-case where the first array created doesn't have a name // Edge-case where the first array created doesn't have a name
config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str()); config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str());
} else { } else {
const auto key = GetFullKey(std::string("size"), true); auto const key = GetFullKey(std::string("size"), true);
config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str()); config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str());
} }

View file

@ -31,8 +31,10 @@ public:
using clock = std::chrono::system_clock; using clock = std::chrono::system_clock;
explicit Socket(const std::string& host, u16 port, SocketCallback callback_) explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
: callback(std::move(callback_)), timer(io_context), : callback(std::move(callback_)), timer(io_context)
socket(io_context, udp::endpoint(udp::v4(), 0)), client_id(Common::Random::Random32(0)) { , socket(io_context, udp::endpoint(udp::v4(), 0))
, client_id(Common::Random::Random32(0))
{
boost::system::error_code ec{}; boost::system::error_code ec{};
auto ipv4 = boost::asio::ip::make_address_v4(host, ec); auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
if (ec.value() != boost::system::errc::success) { if (ec.value() != boost::system::errc::success) {
@ -353,8 +355,13 @@ PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const {
} }
Common::UUID UDPClient::GetHostUUID(const std::string& host) const { Common::UUID UDPClient::GetHostUUID(const std::string& host) const {
const auto ip = boost::asio::ip::make_address_v4(host); boost::system::error_code ec{};
const auto hex_host = fmt::format("00000000-0000-0000-0000-0000{:06x}", ip.to_uint()); auto ip = boost::asio::ip::make_address_v4(host, ec);
if (ec.value() != boost::system::errc::success) {
LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided", host);
ip = boost::asio::ip::address_v4{};
}
auto const hex_host = fmt::format("00000000-0000-0000-0000-0000{:06x}", ip.to_uint());
return Common::UUID{hex_host}; return Common::UUID{hex_host};
} }

View file

@ -207,12 +207,11 @@ struct Values {
// Game List // Game List
Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList}; Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList}; Setting<u32, true> game_icon_size{linkage, 64, 8, 512, "game_icon_size", Category::UiGameList};
Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList}; Setting<u32, true> folder_icon_size{linkage, 48, 8, 512, "folder_icon_size", Category::UiGameList};
Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList}; Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList}; Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
Setting<Settings::GameListMode> game_list_mode{linkage, Settings::GameListMode::TreeView, Setting<Settings::GameListMode> game_list_mode{linkage, Settings::GameListMode::TreeView, "game_list_mode", Category::UiGameList};
"game_list_mode", Category::UiGameList};
Setting<bool> show_game_name{linkage, true, "show_game_name", Category::UiGameList}; Setting<bool> show_game_name{linkage, true, "show_game_name", Category::UiGameList};
std::atomic_bool is_game_list_reload_pending{false}; std::atomic_bool is_game_list_reload_pending{false};

View file

@ -89,11 +89,10 @@ std::string BuildCommaSeparatedExtensions(
} // Anonymous namespace } // Anonymous namespace
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, VkSurfaceKHR surface) {
VkSurfaceKHR surface) {
const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices(); const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
const s32 device_index = Settings::values.vulkan_device.GetValue(); const u32 device_index = Settings::values.vulkan_device.GetValue();
if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) { if (device_index >= u32(devices.size())) {
LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
} }

View file

@ -94,11 +94,10 @@ void ConfigureMotionTouch::SetConfiguration() {
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
touch_from_button_maps = Settings::values.touch_from_button_maps; touch_from_button_maps = Settings::values.touch_from_button_maps;
for (const auto& touch_map : touch_from_button_maps) { for (const auto& touch_map : touch_from_button_maps)
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
} if (auto const index = Settings::values.touch_from_button_map_index.GetValue(); int(index) < ui->touch_from_button_map->count())
ui->touch_from_button_map->setCurrentIndex( ui->touch_from_button_map->setCurrentIndex(index);
Settings::values.touch_from_button_map_index.GetValue());
min_x = touch_param.Get("min_x", 100); min_x = touch_param.Get("min_x", 100);
min_y = touch_param.Get("min_y", 50); min_y = touch_param.Get("min_y", 50);

View file

@ -183,7 +183,7 @@ void GameList::ResetViewMode() {
tree_view->setVisible(false); tree_view->setVisible(false);
break; break;
default: default:
break; UNREACHABLE();
} }
auto view = m_currentView->viewport(); auto view = m_currentView->viewport();
@ -196,10 +196,8 @@ void GameList::ResetViewMode() {
auto scroller = QScroller::scroller(view); auto scroller = QScroller::scroller(view);
QScrollerProperties props; QScrollerProperties props;
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
QScrollerProperties::OvershootAlwaysOff); props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy,
QScrollerProperties::OvershootAlwaysOff);
scroller->setScrollerProperties(props); scroller->setScrollerProperties(props);
if (m_isTreeMode != newTreeMode) { if (m_isTreeMode != newTreeMode) {

View file

@ -1088,10 +1088,9 @@ void MainWindow::InitializeWidgets() {
aa_status_button->setFocusPolicy(Qt::NoFocus); aa_status_button->setFocusPolicy(Qt::NoFocus);
connect(aa_status_button, &QPushButton::clicked, [&] { connect(aa_status_button, &QPushButton::clicked, [&] {
auto aa_mode = Settings::values.anti_aliasing.GetValue(); auto aa_mode = Settings::values.anti_aliasing.GetValue();
aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1); aa_mode = Settings::AntiAliasing(u32(aa_mode) + 1);
if (aa_mode == Settings::AntiAliasing::MaxEnum) { if (u32(aa_mode) > u32(Settings::EnumMetadata<Settings::AntiAliasing>::GetLast()))
aa_mode = Settings::AntiAliasing::None; aa_mode = Settings::EnumMetadata<Settings::AntiAliasing>::GetFirst();
}
Settings::values.anti_aliasing.SetValue(aa_mode); Settings::values.anti_aliasing.SetValue(aa_mode);
aa_status_button->setChecked(true); aa_status_button->setChecked(true);
UpdateAAText(); UpdateAAText();
@ -3623,10 +3622,9 @@ void MainWindow::OnIncreaseVolume() {
void MainWindow::OnToggleAdaptingFilter() { void MainWindow::OnToggleAdaptingFilter() {
auto filter = Settings::values.scaling_filter.GetValue(); auto filter = Settings::values.scaling_filter.GetValue();
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1); filter = Settings::ScalingFilter(u32(filter) + 1);
if (filter == Settings::ScalingFilter::MaxEnum) { if (u32(filter) > u32(Settings::EnumMetadata<Settings::ScalingFilter>::GetLast()))
filter = Settings::ScalingFilter::NearestNeighbor; filter = Settings::EnumMetadata<Settings::ScalingFilter>::GetFirst();
}
Settings::values.scaling_filter.SetValue(filter); Settings::values.scaling_filter.SetValue(filter);
filter_status_button->setChecked(true); filter_status_button->setChecked(true);
UpdateFilterText(); UpdateFilterText();

View file

@ -28,6 +28,8 @@ Tools for Eden and other subprojects. When adding new scripts please use `#!/bin
- `clang-format.sh`: Runs `clang-format` on the entire codebase. - `clang-format.sh`: Runs `clang-format` on the entire codebase.
* Requires: clang * Requires: clang
- `find-unused-strings.sh`: Find any unused strings in the Android app (XML -> Kotlin). - `find-unused-strings.sh`: Find any unused strings in the Android app (XML -> Kotlin).
- `cpp-lint.sh`: Homemade dumb C++ linter.
- `fuzzsettings.cpp`: Fuzz settings files.
## Android ## Android
It's recommended to run these scritps after almost any Android change, as they are relatively fast and important both for APK bloat and CI. It's recommended to run these scritps after almost any Android change, as they are relatively fast and important both for APK bloat and CI.

63
tools/fuzzsettings.cpp Normal file
View file

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <ctime>
#include <string>
#include <string_view>
int main(int argc, char *argv[]) {
std::srand(unsigned(std::time(nullptr)));
FILE *fp = std::fopen(argv[1], "rt");
if (fp) {
char line[BUFSIZ];
while (std::fgets(line, sizeof(line), fp)) {
if (line[0] == '[') {
std::printf("%s", line);
} else if (std::isspace(line[0])) {
std::printf("%s", line);
} else {
char *p = std::strchr(line, '=');
if (std::strstr(line, "\\default") == nullptr) {
// not default
*p = '\0';
std::string new_line{line};
std::string value{p + 1};
if (value == "true" || value == "false") {
new_line += std::string{} + "=TreufLAlse857874FJJakshjryiu475" + '\n';
} else if (std::isdigit(value[0])) {
if (new_line == "size"
|| std::strstr(new_line.c_str(), "entries\\size") != nullptr
|| std::strstr(new_line.c_str(), "\\size")) {
new_line += "=-1\n";
} else {
new_line += '=' + std::to_string(int(std::rand())) + '\n';
}
} else {
std::string_view const cset{"03832///1/1/.1/1./1./1./1.1/.1194573290uwmgjouidyhiomHMNIODASJK,POF MSHDVLJPOIuksdtpsunmghns"};
std::string rst{"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
for (size_t i = 0; i < rst.size(); ++i)
rst[i] = cset[std::rand() % cset.size()];
//new_line += "=\"" + rst + "\"";
new_line += "=" + value;
}
std::printf("%s", new_line.c_str());
} else {
// yes default
*p = '\0';
std::string new_line{line};
std::string value{p + 1};
new_line += "=false\n";
std::printf("%s", new_line.c_str());
}
}
}
std::fclose(fp);
}
return 0;
}

12
tools/fuzzsettings.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh -ex
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
ROOTDIR=$(CDPATH='' cd -- "$(dirname -- "$0")/" && pwd)
touch "$2"
c++ "$ROOTDIR/fuzzsettings.cpp" -o fuzzsettings
./fuzzsettings "$1" >"$2"
rm fuzzsettings