feat(libkernel): add app metadata reading module
This commit is contained in:
parent
282257fd98
commit
cf1953058b
|
|
@ -28,6 +28,7 @@
|
|||
*.out
|
||||
*.app
|
||||
|
||||
_SaveData/
|
||||
build/
|
||||
b/
|
||||
Build/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "prx/libSceVideoOut/include/DisplayWindow.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/AspectFit.hpp"
|
||||
#include "prx/libkernel/AppMetadata/include/AppMetadata.hpp"
|
||||
#include "SDL_vulkan.h"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
|
@ -42,7 +43,8 @@ void DisplayWindow::create(std::uint32_t sourceWidth, std::uint32_t sourceHeight
|
|||
initialWidth = fitted.width;
|
||||
initialHeight = fitted.height;
|
||||
}
|
||||
window = SDL_CreateWindow("PS5", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, static_cast<int>(initialWidth), static_cast<int>(initialHeight), SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
const auto title = GetAppTitle_nid_postfix();
|
||||
window = SDL_CreateWindow(title.value, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, static_cast<int>(initialWidth), static_cast<int>(initialHeight), SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
require(window != nullptr, SDL_GetError());
|
||||
SDL_SetWindowMinimumSize(window, static_cast<int>(DisplayWindowMinimumWidth), static_cast<int>(DisplayWindowMinimumHeight));
|
||||
installSubclass();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef CORE_LIBS_PRX_LIBKERNEL_APPMETADATA_INCLUDE_APPMETADATA_HPP
|
||||
#define CORE_LIBS_PRX_LIBKERNEL_APPMETADATA_INCLUDE_APPMETADATA_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct AppTitle {
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct AppTitleId {
|
||||
char value[12];
|
||||
};
|
||||
|
||||
struct AppIconData {
|
||||
const std::uint8_t* bytes;
|
||||
std::uint64_t size;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
AppTitle GetAppTitle_nid_postfix();
|
||||
AppTitleId GetAppTitleId_nid_postfix();
|
||||
bool HasAppIcon_nid_postfix();
|
||||
AppIconData GetAppIconData_nid_postfix();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
#include "prx/libkernel/AppMetadata/include/AppMetadata.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
bool g_titleLoaded = false;
|
||||
bool g_iconAttempted = false;
|
||||
bool g_iconLoaded = false;
|
||||
char g_title[128] = {};
|
||||
char g_titleId[12] = {};
|
||||
std::vector<std::uint8_t> g_iconBytes;
|
||||
|
||||
constexpr const char* AppMetadataParamJsonGuestPath = "/app0/sce_sys/param.json";
|
||||
constexpr const char* AppMetadataIconGuestPath = "/app0/sce_sys/icon0.png";
|
||||
|
||||
struct ParsedParamJson {
|
||||
std::string title;
|
||||
std::string titleId;
|
||||
};
|
||||
|
||||
ParsedParamJson parseParamJson(const std::filesystem::path& paramJsonPath) {
|
||||
static_cast<void>(paramJsonPath);
|
||||
throw std::runtime_error("param.json parsing is not implemented");
|
||||
}
|
||||
|
||||
void copyToFixedBuffer(char* destination, std::size_t destinationSize, const std::string& source) {
|
||||
if (source.empty()) throw std::runtime_error("source string is empty");
|
||||
if (source.size() + 1 > destinationSize) throw std::length_error("source string does not fit into destination buffer");
|
||||
std::memcpy(destination, source.c_str(), source.size() + 1);
|
||||
}
|
||||
|
||||
void ensureTitleLoaded() {
|
||||
if (g_titleLoaded) return;
|
||||
const auto resolvedPath = ResolvePath_nid_no_patch(AppMetadataParamJsonGuestPath);
|
||||
if (!std::filesystem::exists(resolvedPath)) throw std::runtime_error("param.json not found");
|
||||
const auto parsed = parseParamJson(resolvedPath);
|
||||
copyToFixedBuffer(g_title, sizeof(g_title), parsed.title);
|
||||
copyToFixedBuffer(g_titleId, sizeof(g_titleId), parsed.titleId);
|
||||
g_titleLoaded = true;
|
||||
}
|
||||
|
||||
void ensureIconLoaded() {
|
||||
if (g_iconAttempted) return;
|
||||
g_iconAttempted = true;
|
||||
const auto resolvedPath = ResolvePath_nid_no_patch(AppMetadataIconGuestPath);
|
||||
if (!std::filesystem::exists(resolvedPath)) return;
|
||||
std::ifstream file(resolvedPath, std::ios::binary);
|
||||
if (!file.is_open()) throw std::runtime_error("failed to open icon0.png");
|
||||
file.seekg(0, std::ios::end);
|
||||
const auto fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<std::uint8_t> bytes(static_cast<std::size_t>(fileSize));
|
||||
if (!bytes.empty()) file.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
|
||||
if (bytes.empty()) throw std::runtime_error("icon0.png is empty");
|
||||
constexpr std::uint8_t PngSignature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
if (bytes.size() < 8 || std::memcmp(bytes.data(), PngSignature, sizeof(PngSignature)) != 0) throw std::runtime_error("icon0.png is not a valid PNG file");
|
||||
g_iconBytes = std::move(bytes);
|
||||
g_iconLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
AppTitle GetAppTitle_nid_postfix() {
|
||||
ensureTitleLoaded();
|
||||
AppTitle result{};
|
||||
std::memcpy(result.value, g_title, sizeof(result.value));
|
||||
return result;
|
||||
}
|
||||
|
||||
AppTitleId GetAppTitleId_nid_postfix() {
|
||||
ensureTitleLoaded();
|
||||
AppTitleId result{};
|
||||
std::memcpy(result.value, g_titleId, sizeof(result.value));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HasAppIcon_nid_postfix() {
|
||||
ensureIconLoaded();
|
||||
return g_iconLoaded;
|
||||
}
|
||||
|
||||
AppIconData GetAppIconData_nid_postfix() {
|
||||
ensureIconLoaded();
|
||||
if (!g_iconLoaded) throw std::runtime_error("icon not available");
|
||||
return AppIconData{ g_iconBytes.data(), g_iconBytes.size() };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Rtld.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Process.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Time/Time.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AppMetadata/src/AppMetadata.cpp
|
||||
)
|
||||
|
||||
target_include_directories(libkernel PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
|
|
|
|||
Loading…
Reference in New Issue