[XAM/Content] Implemented Custom CON Header Handling
This commit is contained in:
parent
009f709ad4
commit
6ad5c39fac
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue