[XAM] Partial implementation of: XamContentResolve and Listing of ODD content packages

It's not perfect as it doesn't take internal package name or data, but it should be good enough for most titles
This commit is contained in:
Gliniak 2024-11-03 12:09:53 +01:00 committed by Radosław Gliński
parent 418de9b7f2
commit b8296a9bc9
3 changed files with 95 additions and 10 deletions

View File

@ -243,6 +243,42 @@ std::vector<XCONTENT_AGGREGATE_DATA> ContentManager::ListContent(
return result;
}
std::vector<XCONTENT_AGGREGATE_DATA> ContentManager::ListContentODD(
const uint32_t device_id, const uint64_t xuid, const uint32_t title_id,
const XContentType content_type) const {
std::vector<XCONTENT_AGGREGATE_DATA> result;
auto xuid_str = fmt::format("{:016X}", xuid);
auto title_id_str = fmt::format("{:08X}", title_id);
auto content_type_str =
fmt::format("{:08X}", static_cast<uint32_t>(content_type));
const std::filesystem::path game_content_path =
std::filesystem::path("GAME:") / "content" / xuid_str / title_id_str /
content_type_str;
auto entry = kernel_state_->file_system()->ResolvePath(
xe::path_to_utf8(game_content_path));
if (!entry) {
return {};
}
for (const auto& child : entry->children()) {
XCONTENT_AGGREGATE_DATA content_data;
content_data.device_id = device_id;
content_data.content_type = content_type;
content_data.set_display_name(xe::path_to_utf16(child->name()));
content_data.set_file_name(xe::path_to_utf8(child->name()));
content_data.title_id = title_id;
content_data.xuid = xuid;
result.emplace_back(std::move(content_data));
}
return result;
}
std::unique_ptr<ContentPackage> ContentManager::ResolvePackage(
const std::string_view root_name, const uint64_t xuid,
const XCONTENT_AGGREGATE_DATA& data, const uint32_t disc_number) {

View File

@ -151,6 +151,10 @@ class ContentManager {
const uint32_t device_id, const uint64_t xuid, const uint32_t title_id,
const XContentType content_type) const;
std::vector<XCONTENT_AGGREGATE_DATA> ListContentODD(
const uint32_t device_id, const uint64_t xuid, const uint32_t title_id,
const XContentType content_type) const;
std::unique_ptr<ContentPackage> ResolvePackage(
const std::string_view root_name, const uint64_t xuid,
const XCONTENT_AGGREGATE_DATA& data, const uint32_t disc_number = -1);

View File

@ -76,18 +76,54 @@ DECLARE_XAM_EXPORT2(XamContentGetLicenseMask, kContent, kStub, kHighFrequency);
dword_result_t XamContentResolve_entry(dword_t user_index,
lpvoid_t content_data_ptr,
lpvoid_t buffer_ptr, dword_t buffer_size,
dword_t unk1, dword_t unk2,
dword_t unk3) {
dword_t unk1, lpdword_t root_name_ptr,
lpvoid_t overlapped_ptr) {
auto content_data = content_data_ptr.as<XCONTENT_DATA*>();
uint64_t xuid = 0;
const auto profile =
kernel_state()->xam_state()->profile_manager()->GetProfile(
static_cast<uint8_t>(user_index));
if (profile && content_data->content_type == XContentType::kSavedGame) {
xuid = profile->xuid();
}
std::string root_device_path = "";
if (root_name_ptr) {
// Check if root_name is valid.
// root_device_path = std::string(root_name_ptr);
// Unsupported for now.
return X_ERROR_INVALID_PARAMETER;
} else {
if (content_data->device_id == static_cast<uint32_t>(DummyDeviceId::HDD)) {
root_device_path = "\\Device\\Harddisk0\\Partition1\\Content\\";
} else if (content_data->device_id ==
static_cast<uint32_t>(DummyDeviceId::ODD)) {
// Or GAME, but D: usually means DVD drive meanwhile GAME always pinpoints
// to game, even if it is running from HDD
root_device_path = "D:\\content\\";
} else {
return X_ERROR_INVALID_PARAMETER;
}
}
const std::string relative_path = fmt::format(
"{:016X}\\{:08X}\\{:08X}\\{}", xuid, kernel_state()->title_id(),
static_cast<uint32_t>(content_data->content_type.get()),
content_data->file_name());
char* buffer =
kernel_memory()->TranslateVirtual<char*>(buffer_ptr.guest_address());
string_util::copy_truncating(buffer, root_device_path + relative_path,
buffer_size);
// Check if it exists and try to mount that package
// Result of buffer_ptr is sent to RtlInitAnsiString.
// buffer_size is usually 260 (max path).
// Games expect zero if resolve was successful.
assert_always();
XELOGW("XamContentResolve unimplemented!");
return X_ERROR_NOT_FOUND;
return X_ERROR_SUCCESS;
}
DECLARE_XAM_EXPORT1(XamContentResolve, kContent, kStub);
DECLARE_XAM_EXPORT1(XamContentResolve, kContent, kSketchy);
// https://github.com/MrColdbird/gameservice/blob/master/ContentManager.cpp
// https://github.com/LestaD/SourceEngine2007/blob/master/se2007/engine/xboxsystem.cpp#L499
@ -136,7 +172,8 @@ dword_result_t XamContentCreateEnumerator_entry(
auto user_enumerated_data =
kernel_state()->content_manager()->ListContent(
static_cast<uint32_t>(DummyDeviceId::HDD), xuid,
kernel_state()->title_id(), XContentType(uint32_t(content_type)));
kernel_state()->title_id(),
static_cast<XContentType>(content_type.value()));
enumerated_content.insert(enumerated_content.end(),
user_enumerated_data.cbegin(),
@ -147,7 +184,8 @@ dword_result_t XamContentCreateEnumerator_entry(
auto common_enumerated_data =
kernel_state()->content_manager()->ListContent(
static_cast<uint32_t>(DummyDeviceId::HDD), 0,
kernel_state()->title_id(), XContentType(uint32_t(content_type)));
kernel_state()->title_id(),
static_cast<XContentType>(content_type.value()));
enumerated_content.insert(enumerated_content.end(),
common_enumerated_data.cbegin(),
@ -161,7 +199,14 @@ dword_result_t XamContentCreateEnumerator_entry(
}
if (!device_info || device_info->device_id == DummyDeviceId::ODD) {
// TODO(gibbed): disc drive content
auto disc_enumerated_data =
kernel_state()->content_manager()->ListContentODD(
static_cast<uint32_t>(DummyDeviceId::ODD), 0,
kernel_state()->title_id(), XContentType(uint32_t(content_type)));
enumerated_content.insert(enumerated_content.end(),
disc_enumerated_data.cbegin(),
disc_enumerated_data.cend());
}
for (const auto& content_data : enumerated_content) {