diff --git a/scripts/file_formats/sfo.hexpat b/scripts/file_formats/sfo.hexpat new file mode 100644 index 000000000..cfc1f8789 --- /dev/null +++ b/scripts/file_formats/sfo.hexpat @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +import std.io; +import std.sys; + +struct Header { + u32 magic; + u32 version; + u32 key_table_offset; + u32 data_table_offset; + u32 index_table_entries; +}; + +struct KeyEntry { + char name[]; +} [[inline]]; + +struct DataEntry { + if (fmt == 0x0404) { + u32 int_value; + } else if(fmt == 0x0004) { + char bin_value[size]; + } else if(fmt == 0x0204) { + char str_value[size]; + } else { + std::warning("unknown fmt type"); + } +} [[inline]]; + +struct IndexEntry { + u16 key_offset; + u16 param_fmt; + u32 param_len; + u32 param_max_len; + u32 data_offset; +}; + +struct Entry { + u64 begin = $; + IndexEntry index; + KeyEntry key @ KeyTableOffset + index.key_offset; + DataEntry data @ DataTableOffset + index.data_offset; + u8 data_empty[index.param_max_len - index.param_len] @ DataTableOffset + index.data_offset + index.param_len; + $ = begin + sizeof(IndexEntry); +}; + +Header header @ 0; +std::assert(header.magic == 0x46535000, "Miss match magic"); +std::assert(header.version == 0x00000101, "Miss match version"); + +Entry list[header.index_table_entries] @ 0x14; \ No newline at end of file diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 29e6aeb4f..8a97517f2 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -14,9 +14,10 @@ namespace Common { -std::string ToLower(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); +std::string ToLower(std::string_view input) { + std::string str; + str.resize(input.size()); + std::ranges::transform(input, str.begin(), tolower); return str; } diff --git a/src/common/string_util.h b/src/common/string_util.h index 8dae6c75b..b3c4729d2 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -10,7 +10,7 @@ namespace Common { /// Make a string lowercase -[[nodiscard]] std::string ToLower(std::string str); +[[nodiscard]] std::string ToLower(std::string_view str); std::vector SplitString(const std::string& str, char delimiter); diff --git a/src/core/file_format/psf.cpp b/src/core/file_format/psf.cpp index 3d076acdc..f37461ae0 100644 --- a/src/core/file_format/psf.cpp +++ b/src/core/file_format/psf.cpp @@ -2,61 +2,297 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include + +#include "common/assert.h" #include "common/io_file.h" +#include "common/logging/log.h" #include "core/file_format/psf.h" +static const std::unordered_map psf_known_max_sizes = { + {"ACCOUNT_ID", 8}, {"CATEGORY", 4}, {"DETAIL", 1024}, {"FORMAT", 4}, + {"MAINTITLE", 128}, {"PARAMS", 1024}, {"SAVEDATA_BLOCKS", 8}, {"SAVEDATA_DIRECTORY", 32}, + {"SUBTITLE", 128}, {"TITLE_ID", 12}, +}; +static inline u32 get_max_size(std::string_view key, u32 default_value) { + if (const auto& v = psf_known_max_sizes.find(key); v != psf_known_max_sizes.end()) { + return v->second; + } + return default_value; +} + PSF::PSF() = default; PSF::~PSF() = default; -bool PSF::open(const std::string& filepath, const std::vector& psfBuffer) { - if (!psfBuffer.empty()) { - psf.resize(psfBuffer.size()); - psf = psfBuffer; - } else { - Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); - if (!file.IsOpen()) { - return false; - } +PSF::PSF(const PSF& other) = default; - const u64 psfSize = file.GetSize(); - psf.resize(psfSize); - file.Seek(0); - file.Read(psf); - file.Close(); +PSF::PSF(PSF&& other) noexcept + : entry_list{std::move(other.entry_list)}, map_binaries{std::move(other.map_binaries)}, + map_strings{std::move(other.map_strings)}, map_integers{std::move(other.map_integers)} {} + +PSF& PSF::operator=(const PSF& other) { + if (this == &other) + return *this; + entry_list = other.entry_list; + map_binaries = other.map_binaries; + map_strings = other.map_strings; + map_integers = other.map_integers; + return *this; +} + +PSF& PSF::operator=(PSF&& other) noexcept { + if (this == &other) + return *this; + entry_list = std::move(other.entry_list); + map_binaries = std::move(other.map_binaries); + map_strings = std::move(other.map_strings); + map_integers = std::move(other.map_integers); + return *this; +} + +bool PSF::Open(const std::filesystem::path& filepath) { + Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); + if (!file.IsOpen()) { + return false; } - // Parse file contents - PSFHeader header; - std::memcpy(&header, psf.data(), sizeof(header)); - for (u32 i = 0; i < header.index_table_entries; i++) { - PSFEntry entry; - std::memcpy(&entry, &psf[sizeof(PSFHeader) + i * sizeof(PSFEntry)], sizeof(entry)); + const u64 psfSize = file.GetSize(); + std::vector psf(psfSize); + file.Seek(0); + file.Read(psf); + file.Close(); + return Open(psf); +} - const std::string key = (char*)&psf[header.key_table_offset + entry.key_offset]; - if (entry.param_fmt == PSFEntry::Fmt::TextRaw || - entry.param_fmt == PSFEntry::Fmt::TextNormal) { - map_strings[key] = (char*)&psf[header.data_table_offset + entry.data_offset]; - } - if (entry.param_fmt == PSFEntry::Fmt::Integer) { - u32 value; - std::memcpy(&value, &psf[header.data_table_offset + entry.data_offset], sizeof(value)); - map_integers[key] = value; +bool PSF::Open(const std::vector& psf_buffer) { + const u8* psf_data = psf_buffer.data(); + + entry_list.clear(); + map_binaries.clear(); + map_strings.clear(); + map_integers.clear(); + + // Parse file contents + PSFHeader header{}; + std::memcpy(&header, psf_data, sizeof(header)); + + if (header.magic != PSF_MAGIC) { + LOG_ERROR(Core, "Invalid PSF magic number"); + return false; + } + if (header.version != PSF_VERSION_1_1 && header.version != PSF_VERSION_1_0) { + LOG_ERROR(Core, "Unsupported PSF version: 0x{:08x}", header.version); + return false; + } + + for (u32 i = 0; i < header.index_table_entries; i++) { + PSFRawEntry raw_entry{}; + std::memcpy(&raw_entry, psf_data + sizeof(PSFHeader) + i * sizeof(PSFRawEntry), + sizeof(raw_entry)); + + Entry& entry = entry_list.emplace_back(); + entry.key = std::string{(char*)(psf_data + header.key_table_offset + raw_entry.key_offset)}; + entry.param_fmt = static_cast(raw_entry.param_fmt.Raw()); + entry.max_len = raw_entry.param_max_len; + + const u8* data = psf_data + header.data_table_offset + raw_entry.data_offset; + + switch (entry.param_fmt) { + case Binary: { + std::vector value(raw_entry.param_len); + std::memcpy(value.data(), data, raw_entry.param_len); + map_binaries.emplace(i, std::move(value)); + } break; + case Text: { + std::string c_str{reinterpret_cast(data)}; + map_strings.emplace(i, std::move(c_str)); + } break; + case Integer: { + ASSERT_MSG(raw_entry.param_len == sizeof(s32), "PSF integer entry size mismatch"); + s32 integer = *(s32*)data; + map_integers.emplace(i, integer); + } break; + default: + UNREACHABLE_MSG("Unknown PSF entry format"); } } return true; } -std::string PSF::GetString(const std::string& key) { - if (map_strings.find(key) != map_strings.end()) { - return map_strings.at(key); +bool PSF::Encode(const std::filesystem::path& filepath) const { + Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Write); + if (!file.IsOpen()) { + return false; } - return ""; + + const auto psf_buffer = Encode(); + return file.Write(psf_buffer) == psf_buffer.size(); } -u32 PSF::GetInteger(const std::string& key) { - if (map_integers.find(key) != map_integers.end()) { - return map_integers.at(key); +std::vector PSF::Encode() const { + std::vector psf_buffer; + + psf_buffer.resize(sizeof(PSFHeader) + sizeof(PSFRawEntry) * entry_list.size()); + + { + auto& header = *(PSFHeader*)psf_buffer.data(); + header.magic = PSF_MAGIC; + header.version = PSF_VERSION_1_1; + header.index_table_entries = entry_list.size(); } - return -1; + + const size_t key_table_offset = psf_buffer.size(); + ((PSFHeader*)psf_buffer.data())->key_table_offset = key_table_offset; + for (size_t i = 0; i < entry_list.size(); i++) { + auto& raw_entry = ((PSFRawEntry*)(psf_buffer.data() + sizeof(PSFHeader)))[i]; + const Entry& entry = entry_list[i]; + raw_entry.key_offset = psf_buffer.size() - key_table_offset; + raw_entry.param_fmt.FromRaw(entry.param_fmt); + raw_entry.param_max_len = entry.max_len; + std::ranges::copy(entry.key, std::back_inserter(psf_buffer)); + psf_buffer.push_back(0); // NULL terminator + } + + const size_t data_table_offset = psf_buffer.size(); + ((PSFHeader*)psf_buffer.data())->data_table_offset = data_table_offset; + for (size_t i = 0; i < entry_list.size(); i++) { + if (psf_buffer.size() % 4 != 0) { + std::ranges::fill_n(std::back_inserter(psf_buffer), 4 - psf_buffer.size() % 4, 0); + } + auto& raw_entry = ((PSFRawEntry*)(psf_buffer.data() + sizeof(PSFHeader)))[i]; + const Entry& entry = entry_list[i]; + raw_entry.data_offset = psf_buffer.size() - data_table_offset; + + s32 additional_padding = s32(raw_entry.param_max_len); + + switch (entry.param_fmt) { + case Binary: { + const auto& value = map_binaries.at(i); + raw_entry.param_len = value.size(); + additional_padding -= s32(raw_entry.param_len); + std::ranges::copy(value, std::back_inserter(psf_buffer)); + } break; + case Text: { + const auto& value = map_strings.at(i); + raw_entry.param_len = value.size() + 1; + additional_padding -= s32(raw_entry.param_len); + std::ranges::copy(value, std::back_inserter(psf_buffer)); + psf_buffer.push_back(0); // NULL terminator + } break; + case Integer: { + const auto& value = map_integers.at(i); + raw_entry.param_len = sizeof(s32); + additional_padding -= s32(raw_entry.param_len); + const auto value_bytes = reinterpret_cast(&value); + std::ranges::copy(value_bytes, value_bytes + sizeof(s32), + std::back_inserter(psf_buffer)); + } break; + default: + UNREACHABLE_MSG("Unknown PSF entry format"); + } + ASSERT_MSG(additional_padding >= 0, "PSF entry max size mismatch"); + std::ranges::fill_n(std::back_inserter(psf_buffer), additional_padding, 0); + } + + return psf_buffer; +} + +std::optional> PSF::GetBinary(std::string_view key) const { + const auto& [it, index] = FindEntry(key); + if (it == entry_list.end()) { + return {}; + } + ASSERT(it->param_fmt == Binary); + return std::span{map_binaries.at(index)}; +} + +std::optional PSF::GetString(std::string_view key) const { + const auto& [it, index] = FindEntry(key); + if (it == entry_list.end()) { + return {}; + } + ASSERT(it->param_fmt == Text); + return std::string_view{map_strings.at(index)}; +} + +std::optional PSF::GetInteger(std::string_view key) const { + const auto& [it, index] = FindEntry(key); + if (it == entry_list.end()) { + return {}; + } + ASSERT(it->param_fmt == Integer); + return map_integers.at(index); +} + +void PSF::AddBinary(std::string key, std::vector value, bool update) { + auto [it, index] = FindEntry(key); + bool exist = it != entry_list.end(); + if (exist && !update) { + LOG_ERROR(Core, "PSF: Tried to add binary key that already exists: {}", key); + return; + } + if (exist) { + ASSERT_MSG(it->param_fmt == Binary, "PSF: Change format is not supported"); + it->max_len = get_max_size(key, value.size()); + map_binaries.at(index) = std::move(value); + return; + } + Entry& entry = entry_list.emplace_back(); + entry.max_len = get_max_size(key, value.size()); + entry.key = std::move(key); + entry.param_fmt = Binary; + map_binaries.emplace(entry_list.size() - 1, std::move(value)); +} + +void PSF::AddString(std::string key, std::string value, bool update) { + auto [it, index] = FindEntry(key); + bool exist = it != entry_list.end(); + if (exist && !update) { + LOG_ERROR(Core, "PSF: Tried to add string key that already exists: {}", key); + return; + } + if (exist) { + ASSERT_MSG(it->param_fmt == Text, "PSF: Change format is not supported"); + it->max_len = get_max_size(key, value.size() + 1); + map_strings.at(index) = std::move(value); + return; + } + Entry& entry = entry_list.emplace_back(); + entry.max_len = get_max_size(key, value.size() + 1); + entry.key = std::move(key); + entry.param_fmt = Text; + map_strings.emplace(entry_list.size() - 1, std::move(value)); +} + +void PSF::AddInteger(std::string key, s32 value, bool update) { + auto [it, index] = FindEntry(key); + bool exist = it != entry_list.end(); + if (exist && !update) { + LOG_ERROR(Core, "PSF: Tried to add integer key that already exists: {}", key); + return; + } + if (exist) { + ASSERT_MSG(it->param_fmt == Integer, "PSF: Change format is not supported"); + it->max_len = sizeof(s32); + map_integers.at(index) = value; + return; + } + Entry& entry = entry_list.emplace_back(); + entry.key = std::move(key); + entry.param_fmt = Integer; + entry.max_len = sizeof(s32); + map_integers.emplace(entry_list.size() - 1, value); +} + +std::pair::iterator, size_t> PSF::FindEntry(std::string_view key) { + auto entry = + std::ranges::find_if(entry_list, [&](const auto& entry) { return entry.key == key; }); + return {entry, std::distance(entry_list.begin(), entry)}; +} + +std::pair::const_iterator, size_t> PSF::FindEntry( + std::string_view key) const { + auto entry = + std::ranges::find_if(entry_list, [&](const auto& entry) { return entry.key == key; }); + return {entry, std::distance(entry_list.begin(), entry)}; } diff --git a/src/core/file_format/psf.h b/src/core/file_format/psf.h index 9a162b1d5..017fe87da 100644 --- a/src/core/file_format/psf.h +++ b/src/core/file_format/psf.h @@ -3,11 +3,18 @@ #pragma once +#include +#include #include +#include #include #include #include "common/endian.h" +constexpr u32 PSF_MAGIC = 0x00505346; +constexpr u32 PSF_VERSION_1_1 = 0x00000101; +constexpr u32 PSF_VERSION_1_0 = 0x00000100; + struct PSFHeader { u32_be magic; u32_le version; @@ -15,34 +22,66 @@ struct PSFHeader { u32_le data_table_offset; u32_le index_table_entries; }; +static_assert(sizeof(PSFHeader) == 0x14); -struct PSFEntry { - enum Fmt : u16 { - TextRaw = 0x0400, // String in UTF-8 format and not NULL terminated - TextNormal = 0x0402, // String in UTF-8 format and NULL terminated - Integer = 0x0404, // Unsigned 32-bit integer - }; - +struct PSFRawEntry { u16_le key_offset; u16_be param_fmt; u32_le param_len; u32_le param_max_len; u32_le data_offset; }; +static_assert(sizeof(PSFRawEntry) == 0x10); + +enum PSFEntryFmt : u16 { + Binary = 0x0004, // Binary data + Text = 0x0204, // String in UTF-8 format and NULL terminated + Integer = 0x0404, // Signed 32-bit integer +}; class PSF { + struct Entry { + std::string key; + PSFEntryFmt param_fmt; + u32 max_len; + }; + public: PSF(); ~PSF(); - bool open(const std::string& filepath, const std::vector& psfBuffer); + PSF(const PSF& other); + PSF(PSF&& other) noexcept; - std::string GetString(const std::string& key); - u32 GetInteger(const std::string& key); + PSF& operator=(const PSF& other); + PSF& operator=(PSF&& other) noexcept; - std::unordered_map map_strings; - std::unordered_map map_integers; + bool Open(const std::filesystem::path& filepath); + bool Open(const std::vector& psf_buffer); + + [[nodiscard]] std::vector Encode() const; + bool Encode(const std::filesystem::path& filepath) const; + + std::optional> GetBinary(std::string_view key) const; + std::optional GetString(std::string_view key) const; + std::optional GetInteger(std::string_view key) const; + + void AddBinary(std::string key, std::vector value, bool update = false); + void AddString(std::string key, std::string value, bool update = false); + void AddInteger(std::string key, s32 value, bool update = false); + + [[nodiscard]] const std::vector& GetEntries() const { + return entry_list; + } private: - std::vector psf; + std::vector entry_list; + + std::unordered_map> map_binaries; + std::unordered_map map_strings; + std::unordered_map map_integers; + + [[nodiscard]] std::pair::iterator, size_t> FindEntry(std::string_view key); + [[nodiscard]] std::pair::const_iterator, size_t> FindEntry( + std::string_view key) const; }; diff --git a/src/core/libraries/app_content/app_content.cpp b/src/core/libraries/app_content/app_content.cpp index 125d19684..d9df9d869 100644 --- a/src/core/libraries/app_content/app_content.cpp +++ b/src/core/libraries/app_content/app_content.cpp @@ -90,37 +90,39 @@ int PS4_SYSV_ABI sceAppContentAddcontUnmount() { return ORBIS_OK; } -int PS4_SYSV_ABI sceAppContentAppParamGetInt(OrbisAppContentAppParamId paramId, s32* value) { - if (value == nullptr) +int PS4_SYSV_ABI sceAppContentAppParamGetInt(OrbisAppContentAppParamId paramId, s32* out_value) { + if (out_value == nullptr) return ORBIS_APP_CONTENT_ERROR_PARAMETER; auto* param_sfo = Common::Singleton::Instance(); + std::optional value; switch (paramId) { case ORBIS_APP_CONTENT_APPPARAM_ID_SKU_FLAG: - *value = ORBIS_APP_CONTENT_APPPARAM_SKU_FLAG_FULL; + value = ORBIS_APP_CONTENT_APPPARAM_SKU_FLAG_FULL; break; case ORBIS_APP_CONTENT_APPPARAM_ID_USER_DEFINED_PARAM_1: - *value = param_sfo->GetInteger("USER_DEFINED_PARAM_1"); + value = param_sfo->GetInteger("USER_DEFINED_PARAM_1"); break; case ORBIS_APP_CONTENT_APPPARAM_ID_USER_DEFINED_PARAM_2: - *value = param_sfo->GetInteger("USER_DEFINED_PARAM_2"); + value = param_sfo->GetInteger("USER_DEFINED_PARAM_2"); break; case ORBIS_APP_CONTENT_APPPARAM_ID_USER_DEFINED_PARAM_3: - *value = param_sfo->GetInteger("USER_DEFINED_PARAM_3"); + value = param_sfo->GetInteger("USER_DEFINED_PARAM_3"); break; case ORBIS_APP_CONTENT_APPPARAM_ID_USER_DEFINED_PARAM_4: - *value = param_sfo->GetInteger("USER_DEFINED_PARAM_4"); + value = param_sfo->GetInteger("USER_DEFINED_PARAM_4"); break; default: LOG_ERROR(Lib_AppContent, " paramId = {}, value = {} paramId is not valid", paramId, *value); return ORBIS_APP_CONTENT_ERROR_PARAMETER; } - if (*value == -1) { + if (!value.has_value()) { LOG_ERROR(Lib_AppContent, " paramId = {}, value = {} value is not valid can't read param.sfo?", paramId, *value); return ORBIS_APP_CONTENT_ERROR_PARAMETER; } + *out_value = *value; return ORBIS_OK; } @@ -251,7 +253,7 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar auto* param_sfo = Common::Singleton::Instance(); const auto addons_dir = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir); - title_id = param_sfo->GetString("TITLE_ID"); + title_id = *param_sfo->GetString("TITLE_ID"); auto addon_path = addons_dir / title_id; if (std::filesystem::exists(addon_path)) { for (const auto& entry : std::filesystem::directory_iterator(addon_path)) { diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index d56f4dc41..318d864ba 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -244,7 +244,7 @@ int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver) { auto* param_sfo = Common::Singleton::Instance(); - int version = param_sfo->GetInteger("SYSTEM_VER"); + int version = *param_sfo->GetInteger("SYSTEM_VER"); LOG_INFO(Kernel, "returned system version = {:#x}", version); *ver = version; return (version > 0) ? ORBIS_OK : ORBIS_KERNEL_ERROR_EINVAL; diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index 10a89f669..037029b18 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -477,21 +477,21 @@ int PS4_SYSV_ABI sceSaveDataGetUpdatedDataCount() { int PS4_SYSV_ABI sceSaveDataInitialize() { LOG_INFO(Lib_SaveData, "called"); static auto* param_sfo = Common::Singleton::Instance(); - game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); + game_serial = std::string(*param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } int PS4_SYSV_ABI sceSaveDataInitialize2() { LOG_INFO(Lib_SaveData, "called"); static auto* param_sfo = Common::Singleton::Instance(); - game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); + game_serial = std::string(*param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } int PS4_SYSV_ABI sceSaveDataInitialize3() { LOG_INFO(Lib_SaveData, "called"); static auto* param_sfo = Common::Singleton::Instance(); - game_serial = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); + game_serial = std::string(*param_sfo->GetString("CONTENT_ID"), 7, 9); return ORBIS_OK; } diff --git a/src/emulator.cpp b/src/emulator.cpp index 2d3460a74..cfcdcb66a 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -10,6 +10,7 @@ #ifdef ENABLE_QT_GUI #include "common/memory_patcher.h" #endif +#include "common/assert.h" #include "common/ntapi.h" #include "common/path_util.h" #include "common/polyfill_thread.h" @@ -98,8 +99,9 @@ void Emulator::Run(const std::filesystem::path& file) { for (const auto& entry : std::filesystem::directory_iterator(sce_sys_folder)) { if (entry.path().filename() == "param.sfo") { auto* param_sfo = Common::Singleton::Instance(); - param_sfo->open(sce_sys_folder.string() + "/param.sfo", {}); - id = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); + const bool success = param_sfo->Open(sce_sys_folder / "param.sfo"); + ASSERT_MSG(success, "Failed to open param.sfo"); + id = std::string(*param_sfo->GetString("CONTENT_ID"), 7, 9); Libraries::NpTrophy::game_serial = id; const auto trophyDir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles"; @@ -112,10 +114,10 @@ void Emulator::Run(const std::filesystem::path& file) { #ifdef ENABLE_QT_GUI MemoryPatcher::g_game_serial = id; #endif - title = param_sfo->GetString("TITLE"); + title = *param_sfo->GetString("TITLE"); LOG_INFO(Loader, "Game id: {} Title: {}", id, title); - u32 fw_version = param_sfo->GetInteger("SYSTEM_VER"); - app_version = param_sfo->GetString("APP_VER"); + u32 fw_version = *param_sfo->GetInteger("SYSTEM_VER"); + app_version = *param_sfo->GetString("APP_VER"); LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version); } else if (entry.path().filename() == "playgo-chunk.dat") { auto* playgo = Common::Singleton::Instance(); diff --git a/src/qt_gui/game_info.h b/src/qt_gui/game_info.h index 6032e1c3a..2d08bc085 100644 --- a/src/qt_gui/game_info.h +++ b/src/qt_gui/game_info.h @@ -27,20 +27,21 @@ public: game.path = filePath; PSF psf; - if (psf.open(game.path + "/sce_sys/param.sfo", {})) { + 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); game.icon = QImage(iconpath); game.pic_path = game.path + "/sce_sys/pic1.png"; - game.name = psf.GetString("TITLE"); - game.serial = psf.GetString("TITLE_ID"); - game.region = GameListUtils::GetRegion(psf.GetString("CONTENT_ID").at(0)).toStdString(); - u32 fw_int = psf.GetInteger("SYSTEM_VER"); + game.name = *psf.GetString("TITLE"); + game.serial = *psf.GetString("TITLE_ID"); + game.region = + GameListUtils::GetRegion(psf.GetString("CONTENT_ID")->at(0)).toStdString(); + u32 fw_int = *psf.GetInteger("SYSTEM_VER"); QString fw = QString::number(fw_int, 16); QString fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.') : fw.left(3).insert(1, '.'); game.fw = (fw_int == 0) ? "0.00" : fw_.toStdString(); - game.version = psf.GetString("APP_VER"); + game.version = *psf.GetString("APP_VER"); } return game; } diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index fb1994bb0..24565981b 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -80,8 +80,8 @@ public: if (selected == &openSfoViewer) { PSF psf; - if (psf.open(m_games[itemID].path + "/sce_sys/param.sfo", {})) { - int rows = psf.map_strings.size() + psf.map_integers.size(); + if (psf.Open(std::filesystem::path(m_games[itemID].path) / "sce_sys" / "param.sfo")) { + int rows = psf.GetEntries().size(); QTableWidget* tableWidget = new QTableWidget(rows, 2); tableWidget->setAttribute(Qt::WA_DeleteOnClose); connect(widget->parent(), &QWidget::destroyed, tableWidget, @@ -90,23 +90,33 @@ public: tableWidget->verticalHeader()->setVisible(false); // Hide vertical header int row = 0; - for (const auto& pair : psf.map_strings) { + for (const auto& entry : psf.GetEntries()) { QTableWidgetItem* keyItem = - new QTableWidgetItem(QString::fromStdString(pair.first)); - QTableWidgetItem* valueItem = - new QTableWidgetItem(QString::fromStdString(pair.second)); + new QTableWidgetItem(QString::fromStdString(entry.key)); + QTableWidgetItem* valueItem; + switch (entry.param_fmt) { + case Binary: { - tableWidget->setItem(row, 0, keyItem); - tableWidget->setItem(row, 1, valueItem); - keyItem->setFlags(keyItem->flags() & ~Qt::ItemIsEditable); - valueItem->setFlags(valueItem->flags() & ~Qt::ItemIsEditable); - row++; - } - for (const auto& pair : psf.map_integers) { - QTableWidgetItem* keyItem = - new QTableWidgetItem(QString::fromStdString(pair.first)); - QTableWidgetItem* valueItem = new QTableWidgetItem( - QString("0x").append(QString::number(pair.second, 16))); + const auto bin = *psf.GetBinary(entry.key); + std::string text; + text.reserve(bin.size() * 2); + for (const auto& c : bin) { + static constexpr char hex[] = "0123456789ABCDEF"; + text.push_back(hex[c >> 4 & 0xF]); + text.push_back(hex[c & 0xF]); + } + valueItem = new QTableWidgetItem(QString::fromStdString(text)); + } break; + case Text: { + auto text = *psf.GetString(entry.key); + valueItem = new QTableWidgetItem(QString::fromStdString(std::string{text})); + } break; + case Integer: { + auto integer = *psf.GetInteger(entry.key); + valueItem = + new QTableWidgetItem(QString("0x") + QString::number(integer, 16)); + } break; + } tableWidget->setItem(row, 0, keyItem); tableWidget->setItem(row, 1, valueItem); diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 1945db7f9..cb0129c8e 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -636,9 +636,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int QMessageBox msgBox; msgBox.setWindowTitle(tr("PKG Extraction")); - psf.open("", pkg.sfo); + psf.Open(pkg.sfo); - std::string content_id = psf.GetString("CONTENT_ID"); + std::string content_id{*psf.GetString("CONTENT_ID")}; std::string entitlement_label = Common::SplitString(content_id, '-')[2]; auto addon_extract_path = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) / @@ -647,9 +647,11 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int auto category = psf.GetString("CATEGORY"); if (pkgType.contains("PATCH")) { - QString pkg_app_version = QString::fromStdString(psf.GetString("APP_VER")); - psf.open(extract_path.string() + "/sce_sys/param.sfo", {}); - QString game_app_version = QString::fromStdString(psf.GetString("APP_VER")); + QString pkg_app_version = + QString::fromStdString(std::string{*psf.GetString("APP_VER")}); + psf.Open(extract_path / "sce_sys" / "param.sfo"); + QString game_app_version = + QString::fromStdString(std::string{*psf.GetString("APP_VER")}); double appD = game_app_version.toDouble(); double pkgD = pkg_app_version.toDouble(); if (pkgD == appD) { diff --git a/src/qt_gui/pkg_viewer.cpp b/src/qt_gui/pkg_viewer.cpp index 49005c720..d41d37dbe 100644 --- a/src/qt_gui/pkg_viewer.cpp +++ b/src/qt_gui/pkg_viewer.cpp @@ -109,12 +109,12 @@ void PKGViewer::ProcessPKGInfo() { path = std::filesystem::path(m_pkg_list[i].toStdWString()); #endif package.Open(path); - psf.open("", package.sfo); - QString title_name = QString::fromStdString(psf.GetString("TITLE")); - QString title_id = QString::fromStdString(psf.GetString("TITLE_ID")); - QString app_type = game_list_util.GetAppType(psf.GetInteger("APP_TYPE")); - QString app_version = QString::fromStdString(psf.GetString("APP_VER")); - QString title_category = QString::fromStdString(psf.GetString("CATEGORY")); + psf.Open(package.sfo); + QString title_name = QString::fromStdString(std::string{*psf.GetString("TITLE")}); + QString title_id = QString::fromStdString(std::string{*psf.GetString("TITLE_ID")}); + QString app_type = game_list_util.GetAppType(*psf.GetInteger("APP_TYPE")); + QString app_version = QString::fromStdString(std::string{*psf.GetString("APP_VER")}); + QString title_category = QString::fromStdString(std::string{*psf.GetString("CATEGORY")}); QString pkg_size = game_list_util.FormatSize(package.GetPkgHeader().pkg_size); pkg_content_flag = package.GetPkgHeader().pkg_content_flags; QString flagss = ""; @@ -126,7 +126,7 @@ void PKGViewer::ProcessPKGInfo() { } } - u32 fw_int = psf.GetInteger("SYSTEM_VER"); + u32 fw_int = *psf.GetInteger("SYSTEM_VER"); QString fw = QString::number(fw_int, 16); QString fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.') : fw.left(3).insert(1, '.'); diff --git a/src/qt_gui/pkg_viewer.h b/src/qt_gui/pkg_viewer.h index 9598328a0..265a03b92 100644 --- a/src/qt_gui/pkg_viewer.h +++ b/src/qt_gui/pkg_viewer.h @@ -33,7 +33,6 @@ private: PKGHeader pkgheader; PKGEntry entry; PSFHeader header; - PSFEntry psfentry; char pkgTitleID[9]; std::vector pkg; u64 pkgSize = 0;