diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index fe9ea504d5..803f4f68bb 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -5,7 +5,7 @@ LOG_CHANNEL(psf_log, "PSF"); -template<> +template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto fmt) @@ -21,7 +21,7 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -template<> +template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto fmt) @@ -38,6 +38,47 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + const psf::registry& psf = get_object(arg); + + for (const auto& entry : psf) + { + if (entry.second.type() == psf::format::array) + { + // Format them last + continue; + } + + fmt::append(out, "%s: ", entry.first); + + const psf::entry& data = entry.second; + + if (data.type() == psf::format::integer) + { + fmt::append(out, "0x%x", data.as_integer()); + } + else + { + fmt::append(out, "\"%s\"", data.as_string()); + } + + out += '\n'; + } + + for (const auto& entry : psf) + { + if (entry.second.type() != psf::format::array) + { + // Formatted before + continue; + } + + fmt::append(out, "%s: %s\n", entry.first, std::basic_string_view(reinterpret_cast(entry.second.as_string().data()), entry.second.size())); + } +} + namespace psf { struct header_t diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 368510ff84..b8872bbe71 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -52,6 +52,7 @@ #include "Loader/PUP.h" #include "Loader/TAR.h" +#include "Loader/PSF.h" #include "Loader/mself.hpp" #include "Utilities/Thread.h" @@ -2796,6 +2797,15 @@ main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList drop_type = drop_type::drop_pup; } + else if (info.fileName().toLower() == "param.sfo") + { + if (drop_type != drop_type::drop_psf && drop_type != drop_type::drop_error) + { + return drop_type::drop_error; + } + + drop_type = drop_type::drop_psf; + } else if (info.suffix().toLower() == "pkg") { if (drop_type != drop_type::drop_pkg && drop_type != drop_type::drop_error) @@ -2885,6 +2895,23 @@ void main_window::dropEvent(QDropEvent* event) } break; } + case drop_type::drop_psf: // Display PARAM.SFO content + { + for (const auto& psf : drop_paths) + { + const std::string psf_path = sstr(psf); + std::string info = fmt::format("Dropped PARAM.SFO '%s':\n\n%s", psf_path, psf::load(psf_path).sfo); + + gui_log.success("%s", info); + info.erase(info.begin(), info.begin() + info.find_first_of('\'')); + + QMessageBox mb(QMessageBox::Information, tr("PARAM.SFO Information"), qstr(info), QMessageBox::Ok, this); + mb.setTextInteractionFlags(Qt::TextSelectableByMouse); + mb.exec(); + } + + break; + } case drop_type::drop_dir: // import valid games to gamelist (games.yaml) { if (!m_gui_settings->GetBootConfirmation(this)) diff --git a/rpcs3/rpcs3qt/main_window.h b/rpcs3/rpcs3qt/main_window.h index f0d73b6735..2babe2297c 100644 --- a/rpcs3/rpcs3qt/main_window.h +++ b/rpcs3/rpcs3qt/main_window.h @@ -74,6 +74,7 @@ class main_window : public QMainWindow drop_pkg, drop_pup, drop_rap, + drop_psf, drop_dir, drop_game, drop_rrc