[XAM/Content] Implemented Custom CON Header Handling

This commit is contained in:
Gliniak 2021-01-19 23:04:18 +01:00
parent 009f709ad4
commit 6ad5c39fac
3 changed files with 81 additions and 8 deletions

View File

@ -9,6 +9,7 @@
#include "xenia/kernel/xam/content_manager.h"
#include <array>
#include <string>
#include "third_party/fmt/include/fmt/format.h"
@ -26,6 +27,7 @@ namespace xam {
static const char* kThumbnailFileName = "__thumbnail.png";
static const char* kGameUserContentDirName = "profile";
static const char* kGameContentHeaderDirName = "Headers";
static int content_device_id_ = 0;
@ -95,15 +97,21 @@ std::vector<XCONTENT_AGGREGATE_DATA> ContentManager::ListContent(
// Directories only.
continue;
}
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(file_info.name));
content_data.set_file_name(xe::path_to_utf8(file_info.name));
content_data.title_id = title_id;
result.emplace_back(std::move(content_data));
}
XCONTENT_AGGREGATE_DATA content_data;
if (XSUCCEEDED(
ReadContentHeaderFile(xe::path_to_utf8(file_info.name) + ".header",
content_type, content_data))) {
result.emplace_back(std::move(content_data));
} else {
content_data.device_id = device_id;
content_data.content_type = content_type;
content_data.set_display_name(xe::path_to_utf16(file_info.name));
content_data.set_file_name(xe::path_to_utf8(file_info.name));
content_data.title_id = title_id;
result.emplace_back(std::move(content_data));
}
}
return result;
}
@ -126,6 +134,64 @@ bool ContentManager::ContentExists(const XCONTENT_AGGREGATE_DATA& data) {
return std::filesystem::exists(path);
}
X_RESULT ContentManager::WriteContentHeaderFile(
const XCONTENT_AGGREGATE_DATA* data) {
auto title_id = fmt::format("{:8X}", kernel_state_->title_id());
auto content_type =
fmt::format("{:08X}", load_and_swap<uint32_t>(&data->content_type));
auto header_path =
root_path_ / title_id / kGameContentHeaderDirName / content_type;
if (!std::filesystem::exists(header_path)) {
if (!std::filesystem::create_directories(header_path)) {
return X_STATUS_ACCESS_DENIED;
}
}
auto header_filename = data->file_name() + ".header";
xe::filesystem::CreateEmptyFile(header_path / header_filename);
if (std::filesystem::exists(header_path / header_filename)) {
auto file = xe::filesystem::OpenFile(header_path / header_filename, "wb");
fwrite(data, 1, sizeof(XCONTENT_AGGREGATE_DATA), file);
fclose(file);
return X_STATUS_SUCCESS;
}
return X_STATUS_NO_SUCH_FILE;
}
X_RESULT ContentManager::ReadContentHeaderFile(const std::string_view file_name,
XContentType content_type,
XCONTENT_AGGREGATE_DATA& data) {
auto title_id = fmt::format("{:8X}", kernel_state_->title_id());
auto content_type_directory = fmt::format("{:08X}", content_type);
auto header_file_path = root_path_ / title_id / kGameContentHeaderDirName /
content_type_directory / file_name;
constexpr uint32_t header_size = sizeof(XCONTENT_AGGREGATE_DATA);
if (std::filesystem::exists(header_file_path)) {
auto file = xe::filesystem::OpenFile(header_file_path, "rb");
std::array<uint8_t, header_size> buffer;
auto file_size = std::filesystem::file_size(header_file_path);
if (file_size != header_size && file_size != sizeof(XCONTENT_DATA)) {
fclose(file);
return X_STATUS_END_OF_FILE;
}
size_t result = fread(buffer.data(), 1, file_size, file);
if (result != file_size) {
fclose(file);
return X_STATUS_END_OF_FILE;
}
fclose(file);
std::memcpy(&data, buffer.data(), buffer.size());
return X_STATUS_SUCCESS;
}
return X_STATUS_NO_SUCH_FILE;
}
X_RESULT ContentManager::CreateContent(const std::string_view root_name,
const XCONTENT_AGGREGATE_DATA& data) {
auto global_lock = global_critical_region_.Acquire();

View File

@ -149,6 +149,10 @@ class ContentManager {
const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data);
bool ContentExists(const XCONTENT_AGGREGATE_DATA& data);
X_RESULT WriteContentHeaderFile(const XCONTENT_AGGREGATE_DATA* data_raw);
X_RESULT ReadContentHeaderFile(const std::string_view file_name,
XContentType content_type,
XCONTENT_AGGREGATE_DATA& data);
X_RESULT CreateContent(const std::string_view root_name,
const XCONTENT_AGGREGATE_DATA& data);
X_RESULT OpenContent(const std::string_view root_name,

View File

@ -204,6 +204,9 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
if (create) {
result = content_manager->CreateContent(root_name, content_data);
if (XSUCCEEDED(result)) {
content_manager->WriteContentHeaderFile(&content_data);
}
} else if (open) {
result = content_manager->OpenContent(root_name, content_data);
}