mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-22 04:24:44 +00:00
core: Rewrite PSF parser & add encoder
add .sfo hex pattern to /scripts
This commit is contained in:
parent
048b8aef58
commit
820382a3e7
14 changed files with 452 additions and 108 deletions
52
scripts/file_formats/sfo.hexpat
Normal file
52
scripts/file_formats/sfo.hexpat
Normal file
|
@ -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<auto fmt, auto size> {
|
||||
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<auto KeyTableOffset, auto DataTableOffset> {
|
||||
u64 begin = $;
|
||||
IndexEntry index;
|
||||
KeyEntry key @ KeyTableOffset + index.key_offset;
|
||||
DataEntry<index.param_fmt, index.param_len> 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<header.key_table_offset, header.data_table_offset> list[header.index_table_entries] @ 0x14;
|
|
@ -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<char>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::string> SplitString(const std::string& str, char delimiter);
|
||||
|
||||
|
|
|
@ -2,61 +2,297 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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<std::string_view, u32> 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<u8>& 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<u8> 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<u8>& 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<PSFEntryFmt>(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<u8> 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<const char*>(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<u8> PSF::Encode() const {
|
||||
std::vector<u8> 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<const u8*>(&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<std::span<const u8>> 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<std::string_view> 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<s32> 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<u8> 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<std::vector<PSF::Entry>::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<std::vector<PSF::Entry>::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)};
|
||||
}
|
||||
|
|
|
@ -3,11 +3,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#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<u8>& 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<std::string, std::string> map_strings;
|
||||
std::unordered_map<std::string, u32> map_integers;
|
||||
bool Open(const std::filesystem::path& filepath);
|
||||
bool Open(const std::vector<u8>& psf_buffer);
|
||||
|
||||
[[nodiscard]] std::vector<u8> Encode() const;
|
||||
bool Encode(const std::filesystem::path& filepath) const;
|
||||
|
||||
std::optional<std::span<const u8>> GetBinary(std::string_view key) const;
|
||||
std::optional<std::string_view> GetString(std::string_view key) const;
|
||||
std::optional<s32> GetInteger(std::string_view key) const;
|
||||
|
||||
void AddBinary(std::string key, std::vector<u8> 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<Entry>& GetEntries() const {
|
||||
return entry_list;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8> psf;
|
||||
std::vector<Entry> entry_list;
|
||||
|
||||
std::unordered_map<size_t, std::vector<u8>> map_binaries;
|
||||
std::unordered_map<size_t, std::string> map_strings;
|
||||
std::unordered_map<size_t, s32> map_integers;
|
||||
|
||||
[[nodiscard]] std::pair<std::vector<Entry>::iterator, size_t> FindEntry(std::string_view key);
|
||||
[[nodiscard]] std::pair<std::vector<Entry>::const_iterator, size_t> FindEntry(
|
||||
std::string_view key) const;
|
||||
};
|
||||
|
|
|
@ -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<PSF>::Instance();
|
||||
std::optional<s32> 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<PSF>::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)) {
|
||||
|
|
|
@ -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<PSF>::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;
|
||||
|
|
|
@ -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<PSF>::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<PSF>::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<PSF>::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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<PSF>::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<PlaygoFile>::Instance();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, '.');
|
||||
|
|
|
@ -33,7 +33,6 @@ private:
|
|||
PKGHeader pkgheader;
|
||||
PKGEntry entry;
|
||||
PSFHeader header;
|
||||
PSFEntry psfentry;
|
||||
char pkgTitleID[9];
|
||||
std::vector<u8> pkg;
|
||||
u64 pkgSize = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue