diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp index 037a08545111..1a10a2b517b5 100644 --- a/Utilities/bin_patch.cpp +++ b/Utilities/bin_patch.cpp @@ -219,18 +219,18 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st // Go through each main key in the file for (auto pair : root) { - const auto& main_key = pair.first.Scalar(); + const std::string& main_key = pair.first.Scalar(); - if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map) + if (main_key.empty()) { - append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error); + append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.first), path), &patch_log.error); is_valid = false; continue; } - if (main_key.empty()) + if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map) { - append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.second), path), &patch_log.error); + append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error); is_valid = false; continue; } @@ -242,7 +242,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st } // Find or create an entry matching the key/hash in our map - auto& container = patches_map[main_key]; + patch_container& container = patches_map[main_key]; container.hash = main_key; container.version = version; @@ -252,6 +252,13 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st // Each key in "Patches" is also the patch description const std::string& description = patches_entry.first.Scalar(); + if (description.empty()) + { + append_log_message(log_messages, fmt::format("Error: Empty patch name (key: %s, location: %s, file: %s)", main_key, get_yaml_node_location(patches_entry.first), path), &patch_log.error); + is_valid = false; + continue; + } + // Compile patch information if (const auto yml_type = patches_entry.second.Type(); yml_type != YAML::NodeType::Map) @@ -330,7 +337,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st continue; } - patch_engine::patch_app_versions app_versions; + patch_app_versions app_versions; for (const auto version : serial_node.second) { @@ -579,6 +586,14 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st { if (!read_patch_node(info, patch_node, root, log_messages)) { + for (const auto& it : patches_entry.second) + { + if (it.first.Scalar() == patch_key::patch) + { + append_log_message(log_messages, fmt::format("Skipping invalid patch node %s: (key: %s, location: %s)", info.description, main_key, get_yaml_node_location(it.first)), &patch_log.error); + break; + } + } is_valid = false; } } @@ -703,6 +718,33 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie std::string error_message; + // Validate offset + switch (p_data.type) + { + case patch_type::move_file: + case patch_type::hide_file: + break; + default: + { + const u32 offset = get_yaml_node_value(addr_node, error_message); + if (!error_message.empty()) + { + error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid patch offset '%s' (not a valid u32 or overflow)", + p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.original_offset); + append_log_message(log_messages, error_message, &patch_log.error); + return false; + } + if ((0xFFFFFFFF - modifier) < p_data.offset) + { + error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid combination of patch offset 0x%.8x and modifier 0x%.8x (overflow)", + p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.offset, modifier); + append_log_message(log_messages, error_message, &patch_log.error); + return false; + } + break; + } + } + switch (p_data.type) { case patch_type::utf8: @@ -1338,9 +1380,9 @@ std::basic_string patch_engine::apply(const std::string& name, std::functio } std::basic_string applied_total; - const auto& container = ::at32(m_map, name); - const auto& serial = Emu.GetTitleID(); - const auto& app_version = Emu.GetAppVersion(); + const patch_container& container = ::at32(m_map, name); + const std::string& serial = Emu.GetTitleID(); + const std::string& app_version = Emu.GetAppVersion(); // Different containers in order to separate the patches std::vector> patches_for_this_serial_and_this_version; @@ -1374,7 +1416,7 @@ std::basic_string patch_engine::apply(const std::string& name, std::functio continue; } - const auto& app_versions = ::at32(serials, found_serial); + const patch_app_versions& app_versions = ::at32(serials, found_serial); std::string found_app_version; if (app_versions.contains(app_version)) @@ -1492,11 +1534,11 @@ void patch_engine::unload(const std::string& name) return; } - const auto& container = ::at32(m_map, name); + const patch_container& container = ::at32(m_map, name); for (const auto& [description, patch] : container.patch_info_map) { - for (auto& entry : patch.data_list) + for (const patch_data& entry : patch.data_list) { // Deallocate used memory if (u32 addr = std::exchange(entry.alloc_addr, 0)) @@ -1624,7 +1666,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc continue; } - auto& container = existing_patches[hash]; + patch_engine::patch_container& container = existing_patches[hash]; for (const auto& [description, new_info] : new_container.patch_info_map) { @@ -1635,7 +1677,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc continue; } - auto& info = container.patch_info_map[description]; + patch_engine::patch_info& info = container.patch_info_map[description]; bool ok; const bool version_is_bigger = utils::compare_versions(new_info.patch_version, info.patch_version, ok) > 0; @@ -1798,7 +1840,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages) { - patch_engine::patch_map existing_patches; + patch_map existing_patches; if (load(existing_patches, path, "", true, log_messages)) { @@ -1811,13 +1853,13 @@ bool patch_engine::import_patches(const patch_engine::patch_map& patches, const bool patch_engine::remove_patch(const patch_info& info) { - patch_engine::patch_map patches; + patch_map patches; if (load(patches, info.source_path)) { if (patches.contains(info.hash)) { - auto& container = patches[info.hash]; + patch_container& container = patches[info.hash]; if (container.patch_info_map.contains(info.description)) { diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 4769c99f18c8..b529e38359f9 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -435,7 +435,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) dlg.set_input_font(mono, false); dlg.set_clear_button_enabled(false); dlg.set_button_enabled(QDialogButtonBox::StandardButton::Ok, false); - dlg.set_validator(new QRegularExpressionValidator(QRegularExpression("^[1-9][0-9]*$"))); + dlg.set_validator(new QRegularExpressionValidator(QRegularExpression("^[1-9][0-9]*$"), &dlg)); u32 max = 0; @@ -1188,11 +1188,11 @@ void debugger_frame::ShowGotoAddressDialog() if (const auto thread = get_cpu(); !thread || thread->id_type() != 2) { - expression_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); + expression_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"), this)); } else { - expression_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,5}$"))); + expression_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,5}$"), this)); } // Ok/Cancel diff --git a/rpcs3/rpcs3qt/elf_memory_dumping_dialog.cpp b/rpcs3/rpcs3qt/elf_memory_dumping_dialog.cpp index 7bbcc53689d2..0eb7f4184420 100644 --- a/rpcs3/rpcs3qt/elf_memory_dumping_dialog.cpp +++ b/rpcs3/rpcs3qt/elf_memory_dumping_dialog.cpp @@ -34,13 +34,13 @@ elf_memory_dumping_dialog::elf_memory_dumping_dialog(u32 ppu_debugger_addr, std: m_seg_list->setMinimumWidth(gui::utils::get_label_width(tr("PPU Address: 0x00000000, LS Address: 0x00000, Segment Size: 0x00000, Flags: 0x0"))); // Address expression input - auto make_hex_edit = [mono](u32 max_digits) + auto make_hex_edit = [this, mono](u32 max_digits) { QLineEdit* le = new QLineEdit(); le->setFont(mono); le->setMaxLength(max_digits + 2); le->setPlaceholderText("0x" + QStringLiteral("0").repeated(max_digits)); - le->setValidator(new QRegularExpressionValidator(QRegularExpression(QStringLiteral("^(0[xX])?0*[a-fA-F0-9]{0,%1}$").arg(max_digits)))); + le->setValidator(new QRegularExpressionValidator(QRegularExpression(QStringLiteral("^(0[xX])?0*[a-fA-F0-9]{0,%1}$").arg(max_digits)), this)); return le; }; diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index 0c831f6125dc..d32de0f26c09 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -679,7 +679,7 @@ void log_frame::UpdateUI() const auto font_start_tag = [](const QColor& color) -> const QString { return QStringLiteral(""); }; const QString font_start_tag_stack = ""; - const QString font_end_tag = QStringLiteral(""); + static const QString font_end_tag = QStringLiteral(""); static constexpr auto escaped = [](const QString& text) { diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 50fa5c81b64f..d8f9e15f8ce5 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1633,7 +1633,7 @@ void main_window::DecryptSPRXLibraries() dlg->set_input_font(mono, true, '0'); dlg->set_clear_button_enabled(false); dlg->set_button_enabled(QDialogButtonBox::StandardButton::Ok, false); - dlg->set_validator(new QRegularExpressionValidator(QRegularExpression("^((((((K?L)?I)?C)?=)?0)?x)?[a-fA-F0-9]{0,32}$"))); // HEX only (with additional KLIC=0x prefix for convenience) + dlg->set_validator(new QRegularExpressionValidator(QRegularExpression("^((((((K?L)?I)?C)?=)?0)?x)?[a-fA-F0-9]{0,32}$"), this)); // HEX only (with additional KLIC=0x prefix for convenience) dlg->setAttribute(Qt::WA_DeleteOnClose); connect(dlg, &input_dialog::text_changed, dlg, [dlg](const QString& text) diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.cpp b/rpcs3/rpcs3qt/memory_viewer_panel.cpp index 07a7ff9bd20d..f8ee6fcebe31 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.cpp +++ b/rpcs3/rpcs3qt/memory_viewer_panel.cpp @@ -92,7 +92,7 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptrsetMaxLength(18); m_addr_line->setFixedWidth(75); m_addr_line->setFocus(); - m_addr_line->setValidator(new QRegularExpressionValidator(QRegularExpression(m_type == thread_type::spu ? "^(0[xX])?0*[a-fA-F0-9]{0,5}$" : "^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); + m_addr_line->setValidator(new QRegularExpressionValidator(QRegularExpression(m_type == thread_type::spu ? "^(0[xX])?0*[a-fA-F0-9]{0,5}$" : "^(0[xX])?0*[a-fA-F0-9]{0,8}$"), this)); hbox_tools_mem_addr->addWidget(m_addr_line); tools_mem_addr->setLayout(hbox_tools_mem_addr); diff --git a/rpcs3/rpcs3qt/patch_creator_dialog.cpp b/rpcs3/rpcs3qt/patch_creator_dialog.cpp index ed4cd0450a27..c87312535002 100644 --- a/rpcs3/rpcs3qt/patch_creator_dialog.cpp +++ b/rpcs3/rpcs3qt/patch_creator_dialog.cpp @@ -10,6 +10,9 @@ #include #include #include +#include + +#include LOG_CHANNEL(patch_log, "PAT"); @@ -31,11 +34,16 @@ patch_creator_dialog::patch_creator_dialog(QWidget* parent) , mMonoFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)) , mValidColor(gui::utils::get_label_color("log_level_success")) , mInvalidColor(gui::utils::get_label_color("log_level_error")) + , m_offset_validator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?[a-fA-F0-9]{0,8}$"), this)) { ui->setupUi(this); ui->patchEdit->setFont(mMonoFont); + ui->patchEdit->setAcceptRichText(true); ui->addPatchOffsetEdit->setFont(mMonoFont); + ui->addPatchOffsetEdit->setClearButtonEnabled(true); ui->addPatchValueEdit->setFont(mMonoFont); + ui->addPatchValueEdit->setClearButtonEnabled(true); + ui->addPatchCommentEdit->setClearButtonEnabled(true); ui->instructionTable->setFont(mMonoFont); ui->instructionTable->setItemDelegate(new table_item_delegate(this, false)); ui->instructionTable->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Fixed); @@ -66,6 +74,8 @@ patch_creator_dialog::patch_creator_dialog(QWidget* parent) connect(ui->addPatchButton, &QAbstractButton::clicked, this, [this]() { add_instruction(ui->instructionTable->rowCount()); }); init_patch_type_bombo_box(ui->addPatchTypeComboBox, patch_type::be32, false); + connect(ui->addPatchTypeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index){ update_validator(index, ui->addPatchTypeComboBox, ui->addPatchOffsetEdit); }); + update_validator(ui->addPatchTypeComboBox->currentIndex(), ui->addPatchTypeComboBox, ui->addPatchOffsetEdit); generate_yml(); } @@ -198,6 +208,25 @@ void patch_creator_dialog::show_table_menu(const QPoint& pos) menu.exec(ui->instructionTable->viewport()->mapToGlobal(pos)); } +void patch_creator_dialog::update_validator(int index, QComboBox* combo_box, QLineEdit* line_edit) +{ + if (index < 0 || !combo_box || !line_edit || !combo_box->itemData(index).canConvert()) + { + return; + } + + switch (combo_box->itemData(index).value()) + { + case patch_type::move_file: + case patch_type::hide_file: + line_edit->setValidator(nullptr); + break; + default: + line_edit->setValidator(m_offset_validator); + break; + } +} + void patch_creator_dialog::add_instruction(int row) { const QString type = ui->addPatchTypeComboBox->currentText(); @@ -206,6 +235,25 @@ void patch_creator_dialog::add_instruction(int row) const QString comment = ui->addPatchCommentEdit->text(); const patch_type t = patch_engine::get_patch_type(type.toStdString()); + + switch (t) + { + case patch_type::move_file: + case patch_type::hide_file: + break; + default: + { + int pos = 0; + QString text_to_validate = offset; + if (m_offset_validator->validate(text_to_validate, pos) == QValidator::Invalid) + { + QMessageBox::information(this, tr("Offset invalid!"), tr("The patch offset is invalid.\nThe offset has to be a hexadecimal number with 8 digits at most.")); + return; + } + break; + } + } + QComboBox* combo_box = create_patch_type_bombo_box(t); ui->instructionTable->insertRow(std::max(0, std::min(row, ui->instructionTable->rowCount()))); @@ -330,11 +378,12 @@ bool patch_creator_dialog::can_move_instructions(QModelIndexList& selection, mov return selection.last().row() < ui->instructionTable->rowCount() - 1; } -void patch_creator_dialog::validate() +void patch_creator_dialog::validate(const QString& patch) { patch_engine::patch_map patches; - const std::string content = ui->patchEdit->toPlainText().toStdString(); - const bool is_valid = patch_engine::load(patches, "From Patch Creator", content, true); + const std::string content = patch.toStdString(); + std::stringstream messages; + const bool is_valid = patch_engine::load(patches, "From Patch Creator", content, true, &messages); if (is_valid != m_valid) { @@ -356,6 +405,50 @@ void patch_creator_dialog::validate() ui->validLabel->setPalette(palette); m_valid = is_valid; } + + if (is_valid) + { + ui->patchEdit->setText(patch); + return; + } + + // Search for erronous yml node locations in log message + static const std::regex r("(line )(\\d+)(, column )(\\d+)"); + std::smatch sm; + std::set faulty_lines; + + for (std::string err = messages.str(); !err.empty() && std::regex_search(err, sm, r) && sm.size() == 5; err = sm.suffix()) + { + if (s64 row{}; try_to_int64(&row, sm[2].str(), 0, u32{umax})) + { + faulty_lines.insert(row); + } + } + + // Create html and colorize offending lines + const QString font_start_tag = QStringLiteral("");; + static const QString font_end_tag = QStringLiteral(""); + static const QString line_break_tag = QStringLiteral("
"); + + QStringList lines = patch.split("\n"); + QString new_text; + + for (int i = 0; i < lines.size(); i++) + { + // Escape each line and replace raw whitespace + const QString line = lines[i].toHtmlEscaped().replace(" ", " "); + + if (faulty_lines.empty() || faulty_lines.contains(i)) + { + new_text += font_start_tag + line + font_end_tag + line_break_tag; + } + else + { + new_text += line + line_break_tag; + } + } + + ui->patchEdit->setHtml(new_text); } void patch_creator_dialog::export_patch() @@ -421,8 +514,7 @@ void patch_creator_dialog::generate_yml(const QString& /*text*/) patch.append(QString(" - [ %0, %1, %2 ]%3\n").arg(type).arg(offset).arg(value).arg(comment.isEmpty() ? QStringLiteral("") : QString(" # %0").arg(comment))); } - ui->patchEdit->setText(patch); - validate(); + validate(patch); } bool patch_creator_dialog::eventFilter(QObject* object, QEvent* event) diff --git a/rpcs3/rpcs3qt/patch_creator_dialog.h b/rpcs3/rpcs3qt/patch_creator_dialog.h index 435fd734547c..a59063e31d7a 100644 --- a/rpcs3/rpcs3qt/patch_creator_dialog.h +++ b/rpcs3/rpcs3qt/patch_creator_dialog.h @@ -25,6 +25,7 @@ class patch_creator_dialog : public QDialog QColor mValidColor; QColor mInvalidColor; bool m_valid = true; // Will be invalidated immediately + QRegularExpressionValidator* m_offset_validator = nullptr; enum class move_direction { @@ -40,9 +41,11 @@ class patch_creator_dialog : public QDialog static void init_patch_type_bombo_box(QComboBox* combo_box, patch_type set_type, bool searchable); QComboBox* create_patch_type_bombo_box(patch_type set_type); + void update_validator(int index, QComboBox* combo_box, QLineEdit* line_edit); + private Q_SLOTS: void show_table_menu(const QPoint& pos); - void validate(); + void validate(const QString& patch); void generate_yml(const QString& text = {}); void export_patch(); diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 5e962a8bc311..5d269d2761aa 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -166,7 +166,7 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* tex_idx_line->setMaxLength(18); tex_idx_line->setFixedWidth(75); tex_idx_line->setFocus(); - tex_idx_line->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); + tex_idx_line->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"), this)); QLineEdit* tex_fmt_override_line = new QLineEdit(this); tex_fmt_override_line->setPlaceholderText("00"); @@ -174,7 +174,7 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* tex_fmt_override_line->setMaxLength(18); tex_fmt_override_line->setFixedWidth(75); tex_fmt_override_line->setFocus(); - tex_fmt_override_line->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,2}$"))); + tex_fmt_override_line->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,2}$"), this)); hbox_idx_line->addWidget(tex_idx_line); hbox_idx_line->addWidget(tex_fmt_override_line); diff --git a/rpcs3/rpcs3qt/system_cmd_dialog.cpp b/rpcs3/rpcs3qt/system_cmd_dialog.cpp index 45dfbdb0e043..fb2b19a8385b 100644 --- a/rpcs3/rpcs3qt/system_cmd_dialog.cpp +++ b/rpcs3/rpcs3qt/system_cmd_dialog.cpp @@ -33,13 +33,13 @@ system_cmd_dialog::system_cmd_dialog(QWidget* parent) m_value_input = new QLineEdit(); m_value_input->setFont(mono); m_value_input->setMaxLength(18); - m_value_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); + m_value_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"), this)); m_value_input->setPlaceholderText(QString("0x%1").arg(0, 16, 16, QChar('0'))); m_custom_command_input = new QLineEdit(); m_custom_command_input->setFont(mono); m_custom_command_input->setMaxLength(18); - m_custom_command_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); + m_custom_command_input->setValidator(new QRegularExpressionValidator(QRegularExpression("^(0[xX])?0*[a-fA-F0-9]{0,8}$"), this)); m_custom_command_input->setPlaceholderText(QString("0x%1").arg(0, 16, 16, QChar('0'))); m_command_box = new QComboBox(); diff --git a/rpcs3/rpcs3qt/vfs_dialog_usb_input.cpp b/rpcs3/rpcs3qt/vfs_dialog_usb_input.cpp index 7015fab09097..b39a89c0119b 100644 --- a/rpcs3/rpcs3qt/vfs_dialog_usb_input.cpp +++ b/rpcs3/rpcs3qt/vfs_dialog_usb_input.cpp @@ -58,12 +58,12 @@ vfs_dialog_usb_input::vfs_dialog_usb_input(const QString& name, const cfg::devic m_vid_edit = new QLineEdit; m_vid_edit->setMaxLength(4); - m_vid_edit->setValidator(new QRegularExpressionValidator(QRegularExpression("^[a-fA-F0-9]*$"))); // HEX only + m_vid_edit->setValidator(new QRegularExpressionValidator(QRegularExpression("^[a-fA-F0-9]*$"), this)); // HEX only m_vid_edit->setText(QString::fromStdString(info->vid)); m_pid_edit = new QLineEdit; m_pid_edit->setMaxLength(4); - m_pid_edit->setValidator(new QRegularExpressionValidator(QRegularExpression("^[a-fA-F0-9]*$"))); // HEX only + m_pid_edit->setValidator(new QRegularExpressionValidator(QRegularExpression("^[a-fA-F0-9]*$"), this)); // HEX only m_pid_edit->setText(QString::fromStdString(info->pid)); m_serial_edit = new QLineEdit; diff --git a/rpcs3/util/yaml.cpp b/rpcs3/util/yaml.cpp index dd3a47b6fe8b..52bf7ba89d3d 100644 --- a/rpcs3/util/yaml.cpp +++ b/rpcs3/util/yaml.cpp @@ -76,6 +76,11 @@ std::string get_yaml_node_location(YAML::Node node) } } +std::string get_yaml_node_location(const YAML::detail::iterator_value& it) +{ + return get_yaml_node_location(it.first); +} + template u32 get_yaml_node_value(YAML::Node, std::string&); template u64 get_yaml_node_value(YAML::Node, std::string&); template s64 get_yaml_node_value(YAML::Node, std::string&); diff --git a/rpcs3/util/yaml.hpp b/rpcs3/util/yaml.hpp index 98c43a33afce..51a577c741bd 100644 --- a/rpcs3/util/yaml.hpp +++ b/rpcs3/util/yaml.hpp @@ -28,3 +28,4 @@ T get_yaml_node_value(YAML::Node node, std::string& error_message); // Get the location of the node in the document std::string get_yaml_node_location(YAML::Node node); +std::string get_yaml_node_location(const YAML::detail::iterator_value& it);