Add DLC support (#596)

* fs/core: Add DLC support

* fs/core: Fix extraction paths

* Fix DLC mounting

* gui: Add translations
This commit is contained in:
Dzmitry Dubrova 2024-08-29 12:55:40 +03:00 committed by GitHub
parent e1382b43c8
commit 8827c72a1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 544 additions and 92 deletions

View file

@ -7,14 +7,33 @@
#include <common/singleton.h>
#include <core/file_format/psf.h>
#include <core/file_sys/fs.h>
#include "app_content.h"
#include "common/io_file.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::AppContent {
int32_t addcont_count = 0;
struct AddContInfo {
char entitlementLabel[ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE];
OrbisAppContentAddcontDownloadStatus status;
OrbisAppContentGetEntitlementKey key;
};
std::array<AddContInfo, ORBIS_APP_CONTENT_INFO_LIST_MAX_SIZE> addcont_info = {{
{"0000000000000000",
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}},
}};
std::string title_id;
int PS4_SYSV_ABI _Z5dummyv() {
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
return ORBIS_OK;
@ -35,9 +54,31 @@ int PS4_SYSV_ABI sceAppContentAddcontEnqueueDownloadSp() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAppContentAddcontMount() {
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAppContentAddcontMount(u32 service_label,
const OrbisNpUnifiedEntitlementLabel* entitlement_label,
OrbisAppContentMountPoint* mount_point) {
LOG_INFO(Lib_AppContent, "called");
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) / title_id /
entitlement_label->data;
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
for (int i = 0; i < addcont_count; i++) {
if (strncmp(entitlement_label->data, addcont_info[i].entitlementLabel,
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
continue;
}
if (addcont_info[i].status != ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED) {
return ORBIS_APP_CONTENT_ERROR_NOT_FOUND;
}
snprintf(mount_point->data, ORBIS_APP_CONTENT_MOUNTPOINT_DATA_MAXSIZE, "/addcont%d", i);
mnt->Mount(mount_dir, mount_point->data);
return ORBIS_OK;
}
return ORBIS_APP_CONTENT_ERROR_NOT_FOUND;
}
int PS4_SYSV_ABI sceAppContentAddcontShrink() {
@ -124,22 +165,80 @@ int PS4_SYSV_ABI sceAppContentGetAddcontDownloadProgress() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAppContentGetAddcontInfo() {
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
const OrbisNpUnifiedEntitlementLabel* entitlementLabel,
OrbisAppContentAddcontInfo* info) {
LOG_INFO(Lib_AppContent, "called");
if (entitlementLabel == nullptr || info == nullptr) {
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
}
for (auto i = 0; i < addcont_count; i++) {
if (strncmp(entitlementLabel->data, addcont_info[i].entitlementLabel,
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
continue;
}
LOG_INFO(Lib_AppContent, "found DLC {}", entitlementLabel->data);
strncpy(info->entitlement_label.data, addcont_info[i].entitlementLabel,
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE);
info->status = addcont_info[i].status;
return ORBIS_OK;
}
return ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT;
}
int PS4_SYSV_ABI sceAppContentGetAddcontInfoList(u32 service_label,
OrbisAppContentAddcontInfo* list, u32 list_num,
u32* hit_num) {
*hit_num = 0;
LOG_ERROR(Lib_AppContent, "(DUMMY) called");
LOG_INFO(Lib_AppContent, "called");
if (list_num == 0 || list == nullptr) {
if (hit_num == nullptr) {
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
}
*hit_num = addcont_count;
return ORBIS_OK;
}
int dlcs_to_list = addcont_count < list_num ? addcont_count : list_num;
for (int i = 0; i < dlcs_to_list; i++) {
strncpy(list[i].entitlement_label.data, addcont_info[i].entitlementLabel,
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE);
list[i].status = addcont_info[i].status;
}
if (hit_num != nullptr) {
*hit_num = dlcs_to_list;
}
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAppContentGetEntitlementKey() {
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAppContentGetEntitlementKey(
u32 service_label, const OrbisNpUnifiedEntitlementLabel* entitlement_label,
OrbisAppContentGetEntitlementKey* key) {
LOG_ERROR(Lib_AppContent, "called");
if (entitlement_label == nullptr || key == nullptr) {
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
}
for (int i = 0; i < addcont_count; i++) {
if (strncmp(entitlement_label->data, addcont_info[i].entitlementLabel,
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
continue;
}
memcpy(key->data, addcont_info[i].key.data, ORBIS_APP_CONTENT_ENTITLEMENT_KEY_SIZE);
return ORBIS_OK;
}
return ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT;
}
int PS4_SYSV_ABI sceAppContentGetRegion() {
@ -150,7 +249,25 @@ int PS4_SYSV_ABI sceAppContentGetRegion() {
int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initParam,
OrbisAppContentBootParam* bootParam) {
LOG_ERROR(Lib_AppContent, "(DUMMY) called");
bootParam->attr = 0; // always 0
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");
auto addon_path = addons_dir / title_id;
if (std::filesystem::exists(addon_path)) {
for (const auto& entry : std::filesystem::directory_iterator(addon_path)) {
if (entry.is_directory()) {
auto entitlement_label = entry.path().filename().string();
AddContInfo info{};
info.status = ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED;
strcpy(info.entitlementLabel, entitlement_label.c_str());
addcont_info[addcont_count++] = info;
}
}
}
return ORBIS_OK;
}
@ -324,4 +441,4 @@ void RegisterlibSceAppContent(Core::Loader::SymbolsResolver* sym) {
sceAppContentGetDownloadedStoreCountry);
};
} // namespace Libraries::AppContent
} // namespace Libraries::AppContent

View file

@ -41,6 +41,16 @@ struct OrbisAppContentMountPoint {
constexpr int ORBIS_APP_CONTENT_TEMPORARY_DATA_OPTION_NONE = 0;
constexpr int ORBIS_APP_CONTENT_TEMPORARY_DATA_OPTION_FORMAT = (1 << 0);
constexpr int ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE = 17;
constexpr int ORBIS_APP_CONTENT_ENTITLEMENT_KEY_SIZE = 16;
constexpr int ORBIS_APP_CONTENT_INFO_LIST_MAX_SIZE = 2500;
enum OrbisAppContentAddcontDownloadStatus : u32 {
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_NO_EXTRA_DATA = 0,
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_NO_IN_QUEUE = 1,
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_DOWNLOADING = 2,
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_DOWNLOAD_SUSPENDED = 3,
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED = 4
};
struct OrbisNpUnifiedEntitlementLabel {
char data[ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE];
@ -54,11 +64,17 @@ struct OrbisAppContentAddcontInfo {
u32 status;
};
struct OrbisAppContentGetEntitlementKey {
char data[ORBIS_APP_CONTENT_ENTITLEMENT_KEY_SIZE];
};
int PS4_SYSV_ABI _Z5dummyv();
int PS4_SYSV_ABI sceAppContentAddcontDelete();
int PS4_SYSV_ABI sceAppContentAddcontEnqueueDownload();
int PS4_SYSV_ABI sceAppContentAddcontEnqueueDownloadSp();
int PS4_SYSV_ABI sceAppContentAddcontMount();
int PS4_SYSV_ABI sceAppContentAddcontMount(u32 service_label,
const OrbisNpUnifiedEntitlementLabel* entitlement_label,
OrbisAppContentMountPoint* mount_point);
int PS4_SYSV_ABI sceAppContentAddcontShrink();
int PS4_SYSV_ABI sceAppContentAddcontUnmount();
int PS4_SYSV_ABI sceAppContentAppParamGetInt(OrbisAppContentAppParamId paramId, s32* value);
@ -70,11 +86,15 @@ int PS4_SYSV_ABI sceAppContentDownload1Shrink();
int PS4_SYSV_ABI sceAppContentDownloadDataFormat();
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb();
int PS4_SYSV_ABI sceAppContentGetAddcontDownloadProgress();
int PS4_SYSV_ABI sceAppContentGetAddcontInfo();
int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
const OrbisNpUnifiedEntitlementLabel* entitlementLabel,
OrbisAppContentAddcontInfo* info);
int PS4_SYSV_ABI sceAppContentGetAddcontInfoList(u32 service_label,
OrbisAppContentAddcontInfo* list, u32 list_num,
u32* hit_num);
int PS4_SYSV_ABI sceAppContentGetEntitlementKey();
int PS4_SYSV_ABI sceAppContentGetEntitlementKey(
u32 service_label, const OrbisNpUnifiedEntitlementLabel* entitlement_label,
OrbisAppContentGetEntitlementKey* key);
int PS4_SYSV_ABI sceAppContentGetRegion();
int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initParam,
OrbisAppContentBootParam* bootParam);

View file

@ -460,4 +460,6 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_AES_ENCRY = 0x806A00B5;
constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF;
// AppContent library
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;