Use fs::path::native whenever possible, avoid unnecessary fs->string conversions in GUI code (#1064)

* Use filesystem::path whenever possible, remove fs::path::string

* My hatred for Windows grows with every passing day

* More Qt stuff

* custom u8string formatter for fmt library

* Use u8string for imgui

* Fix toml errors hopefully

* Fix not printing issue

* Oh and on SDL

* I hate Windows even more today

* fix toml reading utf-8 paths

also small fix for fmt::UTF

* Formatting

* Fix QT path to run games

* Fix path logging in save data

* Fix trophy path handling

* Update game_list_frame.cpp

fixed snd0path

* Update main_window.cpp

fix snd0path

* Update main_window.cpp

* paths finally fixed

* git info in WIP versions title

---------

Co-authored-by: Vinicius Rangel <me@viniciusrangel.dev>
Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
Paris Oplopoios 2024-09-26 11:41:59 +03:00 committed by GitHub
parent 54e2179337
commit 6295d6c416
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 271 additions and 125 deletions

View file

@ -4,9 +4,25 @@
#include <fstream>
#include <string>
#include <fmt/core.h>
#include <fmt/xchar.h> // for wstring support
#include <toml.hpp>
#include "common/logging/formatter.h"
#include "config.h"
namespace toml {
template <typename TC, typename K>
std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
std::filesystem::path opt) {
try {
auto str = find<std::string>(v, ky);
std::u8string u8str{(char8_t*)&str.front(), (char8_t*)&str.back() + 1};
return std::filesystem::path{u8str};
} catch (...) {
return opt;
}
}
} // namespace toml
namespace Config {
static bool isNeo = false;
@ -37,7 +53,7 @@ static bool vkMarkers = false;
static bool vkCrashDiagnostic = false;
// Gui
std::string settings_install_dir = "";
std::filesystem::path settings_install_dir = {};
u32 main_window_geometry_x = 400;
u32 main_window_geometry_y = 400;
u32 main_window_geometry_w = 1280;
@ -267,7 +283,7 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_w = w;
main_window_geometry_h = h;
}
void setGameInstallDir(const std::string& dir) {
void setGameInstallDir(const std::filesystem::path& dir) {
settings_install_dir = dir;
}
void setMainWindowTheme(u32 theme) {
@ -323,7 +339,7 @@ u32 getMainWindowGeometryW() {
u32 getMainWindowGeometryH() {
return main_window_geometry_h;
}
std::string getGameInstallDir() {
std::filesystem::path getGameInstallDir() {
return settings_install_dir;
}
u32 getMainWindowTheme() {
@ -378,7 +394,10 @@ void load(const std::filesystem::path& path) {
toml::value data;
try {
data = toml::parse(path);
std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ifs.open(path, std::ios_base::binary);
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
} catch (std::exception& ex) {
fmt::print("Got exception trying to load config file. Exception: {}\n", ex.what());
return;
@ -444,7 +463,7 @@ void load(const std::filesystem::path& path) {
mw_themes = toml::find_or<int>(gui, "theme", 0);
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
settings_install_dir = toml::find_or<std::string>(gui, "installDir", "");
settings_install_dir = toml::find_fs_path_or(gui, "installDir", {});
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
@ -468,17 +487,19 @@ void save(const std::filesystem::path& path) {
std::error_code error;
if (std::filesystem::exists(path, error)) {
try {
data = toml::parse(path);
std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ifs.open(path, std::ios_base::binary);
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
} catch (const std::exception& ex) {
fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
return;
}
} else {
if (error) {
fmt::print("Filesystem error accessing {} (error: {})\n", path.string(),
error.message().c_str());
fmt::print("Filesystem error: {}\n", error.message());
}
fmt::print("Saving new configuration file {}\n", path.string());
fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
}
data["General"]["isPS4Pro"] = isNeo;
@ -515,7 +536,7 @@ void save(const std::filesystem::path& path) {
data["GUI"]["gameTableMode"] = m_table_mode;
data["GUI"]["mw_width"] = m_window_size_W;
data["GUI"]["mw_height"] = m_window_size_H;
data["GUI"]["installDir"] = settings_install_dir;
data["GUI"]["installDir"] = std::string{fmt::UTF(settings_install_dir.u8string()).data};
data["GUI"]["geometry_x"] = main_window_geometry_x;
data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w;

View file

@ -72,7 +72,7 @@ bool vkCrashDiagnosticEnabled();
// Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
void setGameInstallDir(const std::string& dir);
void setGameInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme);
void setIconSize(u32 size);
void setIconSizeGrid(u32 size);
@ -90,7 +90,7 @@ u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH();
std::string getGameInstallDir();
std::filesystem::path getGameInstallDir();
u32 getMainWindowTheme();
u32 getIconSize();
u32 getIconSizeGrid();

View file

@ -19,3 +19,24 @@ struct fmt::formatter<T, std::enable_if_t<std::is_enum_v<T>, char>>
}
};
#endif
namespace fmt {
template <typename T = std::string_view>
struct UTF {
T data;
explicit UTF(const std::u8string_view view) {
data = T{(const char*)&view.front(), (const char*)&view.back() + 1};
}
explicit UTF(const std::u8string& str) : UTF(std::u8string_view{str}) {}
};
} // namespace fmt
template <>
struct fmt::formatter<fmt::UTF<std::string_view>, char> : formatter<std::string_view> {
template <typename FormatContext>
auto format(const UTF<std::string_view>& wrapper, FormatContext& ctx) const {
return formatter<std::string_view>::format(wrapper.data, ctx);
}
};

View file

@ -119,9 +119,9 @@ std::string convertValueToHex(const std::string type, const std::string valueStr
void OnGameLoaded() {
if (!patchFile.empty()) {
std::string patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string();
std::filesystem::path patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
std::string filePath = patchDir + "/" + patchFile;
auto filePath = (patchDir / patchFile).native();
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filePath.c_str());
@ -187,8 +187,8 @@ void OnGameLoaded() {
#ifdef ENABLE_QT_GUI
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
QString patchDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
QString patchDir;
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QString repositories[] = {"GoldHEN", "shadPS4"};
for (const QString& repository : repositories) {

View file

@ -22,6 +22,10 @@
#endif
#endif
#ifdef ENABLE_QT_GUI
#include <QString>
#endif
namespace Common::FS {
namespace fs = std::filesystem;
@ -165,4 +169,22 @@ void SetUserPath(PathType shad_path, const fs::path& new_path) {
UserPaths.insert_or_assign(shad_path, new_path);
}
#ifdef ENABLE_QT_GUI
void PathToQString(QString& result, const std::filesystem::path& path) {
#ifdef _WIN32
result = QString::fromStdWString(path.wstring());
#else
result = QString::fromStdString(path.string());
#endif
}
std::filesystem::path PathFromQString(const QString& path) {
#ifdef _WIN32
return std::filesystem::path(path.toStdWString());
#else
return std::filesystem::path(path.toStdString());
#endif
}
#endif
} // namespace Common::FS

View file

@ -6,6 +6,10 @@
#include <filesystem>
#include <vector>
#ifdef ENABLE_QT_GUI
class QString; // to avoid including <QString> in this header
#endif
namespace Common::FS {
enum class PathType {
@ -96,4 +100,23 @@ constexpr auto LOG_FILE = "shad_log.txt";
*/
void SetUserPath(PathType user_path, const std::filesystem::path& new_path);
#ifdef ENABLE_QT_GUI
/**
* Converts an std::filesystem::path to a QString.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param result The resulting QString
* @param path The path to convert
*/
void PathToQString(QString& result, const std::filesystem::path& path);
/**
* Converts a QString to an std::filesystem::path.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param path The path to convert
*/
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
#endif
} // namespace Common::FS

View file

@ -371,8 +371,7 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::
if (table.type == PFS_CURRENT_DIR) {
current_dir = extractPaths[table.inode];
}
extractPaths[table.inode] =
current_dir.string() / std::filesystem::path(table.name);
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
if (table.type == PFS_FILE || table.type == PFS_DIR) {
if (table.type == PFS_DIR) { // Create dirs.
@ -402,7 +401,7 @@ void PKG::ExtractFiles(const int index) {
int bsize = iNodeBuf[inode_number].Size;
Common::FS::IOFile inflated;
inflated.Open(extractPaths[inode_number].string(), Common::FS::FileAccessMode::Write);
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);

View file

@ -12,8 +12,8 @@
#define STBI_NO_STDIO
#include "externals/stb_image.h"
bool Splash::Open(const std::string& filepath) {
ASSERT_MSG(filepath.ends_with(".png"), "Unexpected file format passed");
bool Splash::Open(const std::filesystem::path& filepath) {
ASSERT_MSG(filepath.stem().string() != "png", "Unexpected file format passed");
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {

View file

@ -3,6 +3,7 @@
#pragma once
#include <filesystem>
#include <string>
#include <vector>
#include "common/types.h"
@ -22,7 +23,7 @@ public:
Splash() = default;
~Splash() = default;
bool Open(const std::string& filepath);
bool Open(const std::filesystem::path& filepath);
[[nodiscard]] bool IsLoaded() const {
return img_data.size();
}

View file

@ -29,7 +29,7 @@ static void removePadding(std::vector<u8>& vec) {
}
bool TRP::Extract(const std::filesystem::path& trophyPath) {
std::string title = trophyPath.filename().string();
std::filesystem::path title = trophyPath.filename();
std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/";
if (!std::filesystem::exists(gameSysDir)) {
return false;

View file

@ -557,10 +557,10 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
const auto trophyDir =
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles";
auto trophy_file = trophyDir / "trophy00" / "Xml" / "TROP.XML";
pugi::xml_document doc;
pugi::xml_parse_result result =
doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str());
pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str());
int numTrophies = 0;

View file

@ -107,14 +107,16 @@ static void BackupThreadBody() {
}
g_backup_status = WorkerStatus::Running;
LOG_INFO(Lib_SaveData, "Backing up the following directory: {}", req.save_path.string());
LOG_INFO(Lib_SaveData, "Backing up the following directory: {}",
fmt::UTF(req.save_path.u8string()));
try {
backup(req.save_path);
} catch (const std::filesystem::filesystem_error& err) {
LOG_ERROR(Lib_SaveData, "Failed to backup {}: {}", req.save_path.string(), err.what());
LOG_ERROR(Lib_SaveData, "Failed to backup {}: {}", fmt::UTF(req.save_path.u8string()),
err.what());
}
LOG_DEBUG(Lib_SaveData, "Backing up the following directory: {} finished",
req.save_path.string());
fmt::UTF(req.save_path.u8string()));
{
std::scoped_lock lk{g_backup_queue_mutex};
g_backup_queue.front().done = true;
@ -160,7 +162,7 @@ bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
if (g_backup_status != WorkerStatus::Waiting && g_backup_status != WorkerStatus::Running) {
LOG_ERROR(Lib_SaveData, "Called backup while status is {}. Backup request to {} ignored",
magic_enum::enum_name(g_backup_status.load()), save_path.string());
magic_enum::enum_name(g_backup_status.load()), fmt::UTF(save_path.u8string()));
return false;
}
{
@ -184,7 +186,7 @@ bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
}
bool Restore(const std::filesystem::path& save_path) {
LOG_INFO(Lib_SaveData, "Restoring backup for {}", save_path.string());
LOG_INFO(Lib_SaveData, "Restoring backup for {}", fmt::UTF(save_path.u8string()));
std::unique_lock lk{g_backup_running_mutex};
if (!fs::exists(save_path) || !fs::exists(save_path / backup_dir)) {
return false;

View file

@ -77,7 +77,7 @@ static void SaveFileSafe(void* buf, size_t count, const std::filesystem::path& p
g_saving_memory = true;
std::scoped_lock lk{g_saving_memory_mutex};
try {
LOG_DEBUG(Lib_SaveData, "Saving save data memory {}", g_save_path.string());
LOG_DEBUG(Lib_SaveData, "Saving save data memory {}", fmt::UTF(g_save_path.u8string()));
if (g_memory_dirty) {
g_memory_dirty = false;
@ -163,7 +163,8 @@ size_t CreateSaveMemory(size_t memory_size) {
bool ok = g_param_sfo.Open(g_param_sfo_path);
if (!ok) {
LOG_ERROR(Lib_SaveData, "Failed to open SFO at {}", g_param_sfo_path.string());
LOG_ERROR(Lib_SaveData, "Failed to open SFO at {}",
fmt::UTF(g_param_sfo_path.u8string()));
throw std::filesystem::filesystem_error(
"failed to open SFO", g_param_sfo_path,
std::make_error_code(std::errc::illegal_byte_sequence));

View file

@ -607,7 +607,7 @@ Error PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData
if (check->param != nullptr) {
PSF sfo;
if (!sfo.Open(backup_path / "sce_sys" / "param.sfo")) {
LOG_ERROR(Lib_SaveData, "Failed to read SFO at {}", backup_path.string());
LOG_ERROR(Lib_SaveData, "Failed to read SFO at {}", fmt::UTF(backup_path.u8string()));
return Error::INTERNAL;
}
check->param->FromSFO(sfo);
@ -818,7 +818,7 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
const auto sfo_path = SaveInstance::GetParamSFOPath(dir_path);
PSF sfo;
if (!sfo.Open(sfo_path)) {
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", sfo_path.string());
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", fmt::UTF(sfo_path.u8string()));
ASSERT_MSG(false, "Failed to read SFO");
}
map_dir_sfo.emplace(dir_name, std::move(sfo));

View file

@ -139,7 +139,7 @@ void Emulator::Run(const std::filesystem::path& file) {
if (splash->IsLoaded()) {
continue;
}
if (!splash->Open(entry.path().string())) {
if (!splash->Open(entry.path())) {
LOG_ERROR(Loader, "Game splash: unable to open file");
}
}
@ -189,7 +189,7 @@ void Emulator::Run(const std::filesystem::path& file) {
if (!std::filesystem::exists(mount_captures_dir)) {
std::filesystem::create_directory(mount_captures_dir);
}
VideoCore::SetOutputDir(mount_captures_dir.generic_string(), id);
VideoCore::SetOutputDir(mount_captures_dir, id);
// Initialize kernel and library facilities.
Libraries::Kernel::init_pthreads();
@ -205,7 +205,7 @@ void Emulator::Run(const std::filesystem::path& file) {
std::filesystem::path sce_module_folder = file.parent_path() / "sce_module";
if (std::filesystem::is_directory(sce_module_folder)) {
for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) {
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
LOG_INFO(Loader, "Loading {}", fmt::UTF(entry.path().u8string()));
linker->LoadModule(entry.path());
}
}

View file

@ -51,8 +51,16 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.DisplaySize = ImVec2((float)window.getWidth(), (float)window.getHeight());
io.IniFilename = SDL_strdup(config_path.string().c_str());
io.LogFilename = SDL_strdup(log_path.string().c_str());
auto path = config_path.u8string();
char* config_file_buf = new char[path.size() + 1]();
std::memcpy(config_file_buf, path.c_str(), path.size());
io.IniFilename = config_file_buf;
path = log_path.u8string();
char* log_file_buf = new char[path.size() + 1]();
std::memcpy(log_file_buf, path.c_str(), path.size());
io.LogFilename = log_file_buf;
ImFontGlyphRangesBuilder rb{};
rb.AddRanges(io.Fonts->GetGlyphRangesDefault());
@ -114,8 +122,8 @@ void Shutdown(const vk::Device& device) {
Sdl::Shutdown();
DestroyContext();
SDL_free(ini_filename);
SDL_free(log_filename);
delete[] (char*)ini_filename;
delete[] (char*)log_filename;
}
bool ProcessEvent(SDL_Event* event) {

View file

@ -5,7 +5,15 @@
#include "common/memory_patcher.h"
#include "emulator.h"
#ifdef _WIN32
#include <windows.h>
#endif
int main(int argc, char* argv[]) {
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
if (argc == 1) {
fmt::print("Usage: {} <elf or eboot.bin path>\n", argv[0]);
return -1;

View file

@ -50,8 +50,9 @@ void CheatsPatches::setupUI() {
defaultTextEdit = tr("defaultTextEdit_MSG");
defaultTextEdit.replace("\\n", "\n");
QString CHEATS_DIR_QString =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string());
QString CHEATS_DIR_QString;
Common::FS::PathToQString(CHEATS_DIR_QString,
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
QString NameCheatJson = m_gameSerial + "_" + m_gameVersion + ".json";
m_cheatFilePath = CHEATS_DIR_QString + "/" + NameCheatJson;
@ -275,9 +276,9 @@ void CheatsPatches::onSaveButtonClicked() {
int separatorIndex = selectedPatchName.indexOf(" | ");
selectedPatchName = selectedPatchName.mid(separatorIndex + 3);
QString patchDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string()) +
"/" + selectedPatchName;
QString patchDir;
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
patchDir += "/" + selectedPatchName;
QString filesJsonPath = patchDir + "/files.json";
QFile jsonFile(filesJsonPath);
@ -555,10 +556,10 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer
if (dotIndex != -1) {
baseFileName.insert(dotIndex, "_wolf2022");
}
QString filePath =
QString::fromStdString(
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string()) +
"/" + baseFileName;
QString filePath;
Common::FS::PathToQString(filePath,
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
filePath += "/" + baseFileName;
if (QFile::exists(filePath) && showMessageBox) {
QMessageBox::StandardButton reply2;
reply2 =
@ -612,8 +613,9 @@ void CheatsPatches::populateFileListPatches() {
}
m_patchInfos.clear();
QString patchesDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
QString patchesDir;
Common::FS::PathToQString(patchesDir,
Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QDir dir(patchesDir);
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
@ -906,8 +908,8 @@ void CheatsPatches::addCheatsToLayout(const QJsonArray& modsArray, const QJsonAr
}
void CheatsPatches::populateFileListCheats() {
QString cheatsDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string());
QString cheatsDir;
Common::FS::PathToQString(cheatsDir, Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
QString pattern = m_gameSerial + "_" + m_gameVersion + "*.json";
QDir dir(cheatsDir);
@ -932,8 +934,9 @@ void CheatsPatches::populateFileListCheats() {
if (!selectedIndexes.isEmpty()) {
QString selectedFileName = selectedIndexes.first().data().toString();
QString cheatsDir = QString::fromStdString(
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string());
QString cheatsDir;
Common::FS::PathToQString(
cheatsDir, Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
QFile file(cheatsDir + "/" + selectedFileName);
if (file.open(QIODevice::ReadOnly)) {

View file

@ -44,7 +44,8 @@ void GameGridFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
BackgroundMusicPlayer::getInstance().stopMusic();
return;
}
const auto snd0path = QString::fromStdString(m_game_info->m_games[item->row()].snd0_path);
QString snd0path;
Common::FS::PathToQString(snd0path, m_game_info->m_games[item->row()].snd0_path);
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
}
@ -122,14 +123,12 @@ void GameGridFrame::SetGridBackgroundImage(int row, int column) {
int itemID = (row * this->columnCount()) + column;
QWidget* item = this->cellWidget(row, column);
if (item) {
QString pic1Path = QString::fromStdString((*m_games_shared)[itemID].pic_path);
QString pic1Path;
Common::FS::PathToQString(pic1Path, (*m_games_shared)[itemID].pic_path);
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
(*m_games_shared)[itemID].serial / "pic1.png";
#ifdef _WIN32
const auto blurredPic1PathQt = QString::fromStdWString(blurredPic1Path.wstring());
#else
const auto blurredPic1PathQt = QString::fromStdString(blurredPic1Path.string());
#endif
QString blurredPic1PathQt;
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
backgroundImage = QImage(blurredPic1PathQt);
if (backgroundImage.isNull()) {

View file

@ -3,13 +3,15 @@
#include <QProgressDialog>
#include "common/path_util.h"
#include "game_info.h"
GameInfoClass::GameInfoClass() = default;
GameInfoClass::~GameInfoClass() = default;
void GameInfoClass::GetGameInfo(QWidget* parent) {
QString installDir = QString::fromStdString(Config::getGameInstallDir());
QString installDir;
Common::FS::PathToQString(installDir, Config::getGameInstallDir());
QStringList filePaths;
QDir parentFolder(installDir);
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
@ -19,7 +21,7 @@ void GameInfoClass::GetGameInfo(QWidget* parent) {
}
}
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
return readGameInfo(path.toStdString());
return readGameInfo(Common::FS::PathFromQString(path));
}).results();
// Progress bar, please be patient :)

View file

@ -22,17 +22,19 @@ public:
return a.name < b.name;
}
static GameInfo readGameInfo(const std::string& filePath) {
static GameInfo readGameInfo(const std::filesystem::path& filePath) {
GameInfo game;
game.path = filePath;
PSF psf;
if (psf.Open(std::filesystem::path(game.path) / "sce_sys" / "param.sfo")) {
game.icon_path = game.path + "/sce_sys/icon0.png";
QString iconpath = QString::fromStdString(game.icon_path);
if (psf.Open(game.path / "sce_sys" / "param.sfo")) {
game.icon_path = game.path / "sce_sys" / "icon0.png";
QString iconpath;
Common::FS::PathToQString(iconpath, game.icon_path);
game.icon = QImage(iconpath);
game.pic_path = game.path + "/sce_sys/pic1.png";
game.snd0_path = game.path + "/sce_sys/snd0.at9";
game.pic_path = game.path / "sce_sys" / "pic1.png";
game.snd0_path = game.path / "sce_sys" / "snd0.at9";
if (const auto title = psf.GetString("TITLE"); title.has_value()) {
game.name = *title;
}

View file

@ -41,7 +41,9 @@ QWidget* GameInstallDialog::SetupGamesDirectory() {
// Input.
m_gamesDirectory = new QLineEdit();
m_gamesDirectory->setText(QString::fromStdString(Config::getGameInstallDir()));
QString install_dir;
Common::FS::PathToQString(install_dir, Config::getGameInstallDir());
m_gamesDirectory->setText(install_dir);
m_gamesDirectory->setMinimumWidth(400);
layout->addWidget(m_gamesDirectory);
@ -76,7 +78,7 @@ void GameInstallDialog::Save() {
return;
}
Config::setGameInstallDir(gamesDirectory.toStdString());
Config::setGameInstallDir(Common::FS::PathFromQString(gamesDirectory));
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::save(config_dir / "config.toml");
accept();

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/path_util.h"
#include "common/string_util.h"
#include "game_list_frame.h"
GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent)
@ -73,7 +74,8 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
BackgroundMusicPlayer::getInstance().stopMusic();
return;
}
const auto snd0path = QString::fromStdString(m_game_info->m_games[item->row()].snd0_path);
QString snd0path;
Common::FS::PathToQString(snd0path, m_game_info->m_games[item->row()].snd0_path);
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
}
@ -88,7 +90,9 @@ void GameListFrame::PopulateGameList() {
SetTableItem(i, 4, QString::fromStdString(m_game_info->m_games[i].fw));
SetTableItem(i, 5, QString::fromStdString(m_game_info->m_games[i].size));
SetTableItem(i, 6, QString::fromStdString(m_game_info->m_games[i].version));
SetTableItem(i, 7, QString::fromStdString(m_game_info->m_games[i].path));
QString path;
Common::FS::PathToQString(path, m_game_info->m_games[i].path);
SetTableItem(i, 7, path);
}
}
@ -98,14 +102,12 @@ void GameListFrame::SetListBackgroundImage(QTableWidgetItem* item) {
return;
}
QString pic1Path = QString::fromStdString(m_game_info->m_games[item->row()].pic_path);
QString pic1Path;
Common::FS::PathToQString(pic1Path, m_game_info->m_games[item->row()].pic_path);
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
m_game_info->m_games[item->row()].serial / "pic1.png";
#ifdef _WIN32
const auto blurredPic1PathQt = QString::fromStdWString(blurredPic1Path.wstring());
#else
const auto blurredPic1PathQt = QString::fromStdString(blurredPic1Path.string());
#endif
QString blurredPic1PathQt;
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
backgroundImage = QImage(blurredPic1PathQt);
if (backgroundImage.isNull()) {

View file

@ -3,11 +3,14 @@
#pragma once
#include "common/path_util.h"
struct GameInfo {
std::string path; // root path of game directory (normally directory that contains eboot.bin)
std::string icon_path; // path of icon0.png
std::string pic_path; // path of pic1.png
std::string snd0_path; // path of snd0.at9
std::filesystem::path path; // root path of game directory
// (normally directory that contains eboot.bin)
std::filesystem::path icon_path; // path of icon0.png
std::filesystem::path pic_path; // path of pic1.png
std::filesystem::path snd0_path; // path of snd0.at9
QImage icon;
std::string size;
// variables extracted from param.sfo
@ -44,7 +47,9 @@ public:
}
static void GetFolderSize(GameInfo& game) {
QDir dir(QString::fromStdString(game.path));
QString dirPath;
Common::FS::PathToQString(dirPath, game.path);
QDir dir(dirPath);
QDirIterator it(dir.absolutePath(), QDirIterator::Subdirectories);
qint64 total = 0;
while (it.hasNext()) {

View file

@ -75,7 +75,8 @@ public:
}
if (selected == &openFolder) {
QString folderPath = QString::fromStdString(m_games[itemID].path);
QString folderPath;
Common::FS::PathToQString(folderPath, m_games[itemID].path);
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
}
@ -158,7 +159,9 @@ public:
QString gameSerial = QString::fromStdString(m_games[itemID].serial);
QString gameVersion = QString::fromStdString(m_games[itemID].version);
QString gameSize = QString::fromStdString(m_games[itemID].size);
QPixmap gameImage(QString::fromStdString(m_games[itemID].icon_path));
QString iconPath;
Common::FS::PathToQString(iconPath, m_games[itemID].icon_path);
QPixmap gameImage(iconPath);
CheatsPatches* cheatsPatches =
new CheatsPatches(gameName, gameSerial, gameVersion, gameSize, gameImage);
cheatsPatches->show();
@ -167,8 +170,9 @@ public:
}
if (selected == &openTrophyViewer) {
QString trophyPath = QString::fromStdString(m_games[itemID].serial);
QString gameTrpPath = QString::fromStdString(m_games[itemID].path);
QString trophyPath, gameTrpPath;
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
Common::FS::PathToQString(gameTrpPath, m_games[itemID].path);
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
trophyViewer->show();
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
@ -176,11 +180,13 @@ public:
}
if (selected == &createShortcut) {
QString targetPath = QString::fromStdString(m_games[itemID].path);
QString targetPath;
Common::FS::PathToQString(targetPath, m_games[itemID].path);
QString ebootPath = targetPath + "/eboot.bin";
// Get the full path to the icon
QString iconPath = QString::fromStdString(m_games[itemID].icon_path);
QString iconPath;
Common::FS::PathToQString(iconPath, m_games[itemID].icon_path);
QFileInfo iconFileInfo(iconPath);
QString icoPath = iconFileInfo.absolutePath() + "/" + iconFileInfo.baseName() + ".ico";

View file

@ -8,10 +8,18 @@
#include "game_install_dialog.h"
#include "main_window.h"
#ifdef _WIN32
#include <windows.h>
#endif
// Custom message handler to ignore Qt logs
void customMessageHandler(QtMsgType, const QMessageLogContext&, const QString&) {}
int main(int argc, char* argv[]) {
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
QApplication a(argc, argv);
// Load configurations and initialize Qt application
@ -22,7 +30,7 @@ int main(int argc, char* argv[]) {
bool has_command_line_argument = argc > 1;
// Check if the game install directory is set
if (Config::getGameInstallDir() == "" && !has_command_line_argument) {
if (Config::getGameInstallDir().empty() && !has_command_line_argument) {
GameInstallDialog dlg;
dlg.exec();
}

View file

@ -4,10 +4,12 @@
#include <QDockWidget>
#include <QProgressDialog>
#include <common/scm_rev.h>
#include "about_dialog.h"
#include "cheats_patches.h"
#include "check_update.h"
#include "common/io_file.h"
#include "common/path_util.h"
#include "common/string_util.h"
#include "common/version.h"
#include "core/file_format/pkg.h"
@ -43,7 +45,14 @@ bool MainWindow::Init() {
GetPhysicalDevices();
// show ui
setMinimumSize(350, minimumSizeHint().height());
setWindowTitle(QString::fromStdString("shadPS4 v" + std::string(Common::VERSION)));
std::string window_title = "";
if (Common::isRelease) {
window_title = fmt::format("shadPS4 v{}", Common::VERSION);
} else {
window_title = fmt::format("shadPS4 v{} {} {}", Common::VERSION, Common::g_scm_branch,
Common::g_scm_desc);
}
setWindowTitle(QString::fromStdString(window_title));
this->show();
// load game list
LoadGameLists();
@ -433,12 +442,14 @@ void MainWindow::CreateConnects() {
.arg(" APP VERSION", -11)
.arg(" Path");
for (const GameInfo& game : m_game_info->m_games) {
QString game_path;
Common::FS::PathToQString(game_path, game.path);
out << QString("%1 %2 %3 %4 %5\n")
.arg(QString::fromStdString(game.name), -50)
.arg(QString::fromStdString(game.serial), -10)
.arg(QString::fromStdString(game.fw), -4)
.arg(QString::fromStdString(game.version), -11)
.arg(QString::fromStdString(game.path));
.arg(game_path);
}
});
@ -517,7 +528,8 @@ void MainWindow::PlayBackgroundMusic() {
: m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt +
m_game_grid_frame->crtColumn;
const auto snd0path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path);
QString snd0path;
Common::FS::PathToQString(snd0path, m_game_info->m_games[itemID].snd0_path);
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
}
@ -529,28 +541,29 @@ void MainWindow::StartGame() {
if (table_mode == 0) {
if (m_game_list_frame->currentItem()) {
int itemID = m_game_list_frame->currentItem()->row();
gamePath = QString::fromStdString(m_game_info->m_games[itemID].path + "/eboot.bin");
Common::FS::PathToQString(gamePath, m_game_info->m_games[itemID].path / "eboot.bin");
}
} else if (table_mode == 1) {
if (m_game_grid_frame->cellClicked) {
int itemID = (m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt) +
m_game_grid_frame->crtColumn;
gamePath = QString::fromStdString(m_game_info->m_games[itemID].path + "/eboot.bin");
Common::FS::PathToQString(gamePath, m_game_info->m_games[itemID].path / "eboot.bin");
}
} else {
if (m_elf_viewer->currentItem()) {
int itemID = m_elf_viewer->currentItem()->row();
gamePath = QString::fromStdString(m_elf_viewer->m_elf_list[itemID].toStdString());
gamePath = m_elf_viewer->m_elf_list[itemID];
}
}
if (gamePath != "") {
AddRecentFiles(gamePath);
Core::Emulator emulator;
if (!std::filesystem::exists(gamePath.toUtf8().constData())) {
const auto path = Common::FS::PathFromQString(gamePath);
if (!std::filesystem::exists(path)) {
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
return;
}
emulator.Run(gamePath.toUtf8().constData());
emulator.Run(path);
}
}
@ -666,9 +679,11 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
pkg = PKG();
pkg.Open(file);
std::string failreason;
auto extract_path = std::filesystem::path(Config::getGameInstallDir()) / pkg.GetTitleID();
auto extract_path = Config::getGameInstallDir() / pkg.GetTitleID();
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
QDir game_dir(QString::fromStdString(extract_path.string()));
QString gameDirPath;
Common::FS::PathToQString(gameDirPath, extract_path);
QDir game_dir(gameDirPath);
if (game_dir.exists()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("PKG Extraction"));
@ -690,7 +705,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
auto addon_extract_path = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) /
pkg.GetTitleID() / entitlement_label;
QDir addon_dir(QString::fromStdString(addon_extract_path.string()));
QString addonDirPath;
Common::FS::PathToQString(addonDirPath, addon_extract_path);
QDir addon_dir(addonDirPath);
auto category = psf.GetString("CATEGORY");
if (pkgType.contains("PATCH")) {
@ -755,8 +772,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
return;
}
} else {
msgBox.setText(QString(tr("DLC already installed:") + "\n" +
QString::fromStdString(addon_extract_path.string()) +
msgBox.setText(QString(tr("DLC already installed:") + "\n" + addonDirPath +
"\n\n" + tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
@ -768,8 +784,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
}
}
} else {
msgBox.setText(QString(tr("Game already installed") + "\n" +
QString::fromStdString(extract_path.string()) + "\n" +
msgBox.setText(QString(tr("Game already installed") + "\n" + addonDirPath + "\n" +
tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
@ -812,7 +827,8 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
QFutureWatcher<void> futureWatcher;
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
if (pkgNum == nPkg) {
QString path = QString::fromStdString(Config::getGameInstallDir());
QString path;
Common::FS::PathToQString(path, Config::getGameInstallDir());
QMessageBox extractMsgBox(this);
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
extractMsgBox.setText(
@ -984,14 +1000,14 @@ void MainWindow::CreateRecentGameActions() {
}
connect(m_recent_files_group, &QActionGroup::triggered, this, [this](QAction* action) {
QString gamePath = action->text();
AddRecentFiles(gamePath); // Update the list.
auto gamePath = Common::FS::PathFromQString(action->text());
AddRecentFiles(action->text()); // Update the list.
Core::Emulator emulator;
if (!std::filesystem::exists(gamePath.toUtf8().constData())) {
if (!std::filesystem::exists(gamePath)) {
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
return;
}
emulator.Run(gamePath.toUtf8().constData());
emulator.Run(gamePath);
});
}

View file

@ -21,15 +21,10 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo
}
void TrophyViewer::PopulateTrophyWidget(QString title) {
#ifdef _WIN32
const auto trophyDir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
title.toStdWString() / "TrophyFiles";
const auto trophyDirQt = QString::fromStdWString(trophyDir.wstring());
#else
const auto trophyDir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
title.toStdString() / "TrophyFiles";
const auto trophyDirQt = QString::fromStdString(trophyDir.string());
#endif
Common::FS::PathFromQString(title) / "TrophyFiles";
QString trophyDirQt;
Common::FS::PathToQString(trophyDirQt, trophyDir);
QDir dir(trophyDirQt);
if (!dir.exists()) {

View file

@ -110,11 +110,11 @@ void TriggerCapture() {
}
}
void SetOutputDir(const std::string& path, const std::string& prefix) {
void SetOutputDir(const std::filesystem::path& path, const std::string& prefix) {
if (!rdoc_api) {
return;
}
rdoc_api->SetCaptureFilePathTemplate((path + '\\' + prefix).c_str());
rdoc_api->SetCaptureFilePathTemplate(fmt::UTF((path / prefix).u8string()).data.data());
}
} // namespace VideoCore

View file

@ -20,6 +20,6 @@ void EndCapture();
void TriggerCapture();
/// Sets output directory for captures
void SetOutputDir(const std::string& path, const std::string& prefix);
void SetOutputDir(const std::filesystem::path& path, const std::string& prefix);
} // namespace VideoCore