mirror of
https://github.com/xenia-project/xenia.git
synced 2025-12-06 07:12:03 +01:00
[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 "xenia/kernel/xam/content_manager.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
|
|
@ -26,6 +27,7 @@ namespace xam {
|
||||||
static const char* kThumbnailFileName = "__thumbnail.png";
|
static const char* kThumbnailFileName = "__thumbnail.png";
|
||||||
|
|
||||||
static const char* kGameUserContentDirName = "profile";
|
static const char* kGameUserContentDirName = "profile";
|
||||||
|
static const char* kGameContentHeaderDirName = "Headers";
|
||||||
|
|
||||||
static int content_device_id_ = 0;
|
static int content_device_id_ = 0;
|
||||||
|
|
||||||
|
|
@ -95,7 +97,13 @@ std::vector<XCONTENT_AGGREGATE_DATA> ContentManager::ListContent(
|
||||||
// Directories only.
|
// Directories only.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
XCONTENT_AGGREGATE_DATA 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.device_id = device_id;
|
||||||
content_data.content_type = content_type;
|
content_data.content_type = content_type;
|
||||||
content_data.set_display_name(xe::path_to_utf16(file_info.name));
|
content_data.set_display_name(xe::path_to_utf16(file_info.name));
|
||||||
|
|
@ -103,7 +111,7 @@ std::vector<XCONTENT_AGGREGATE_DATA> ContentManager::ListContent(
|
||||||
content_data.title_id = title_id;
|
content_data.title_id = title_id;
|
||||||
result.emplace_back(std::move(content_data));
|
result.emplace_back(std::move(content_data));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,6 +134,64 @@ bool ContentManager::ContentExists(const XCONTENT_AGGREGATE_DATA& data) {
|
||||||
return std::filesystem::exists(path);
|
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,
|
X_RESULT ContentManager::CreateContent(const std::string_view root_name,
|
||||||
const XCONTENT_AGGREGATE_DATA& data) {
|
const XCONTENT_AGGREGATE_DATA& data) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,10 @@ class ContentManager {
|
||||||
const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data);
|
const std::string_view root_name, const XCONTENT_AGGREGATE_DATA& data);
|
||||||
|
|
||||||
bool ContentExists(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,
|
X_RESULT CreateContent(const std::string_view root_name,
|
||||||
const XCONTENT_AGGREGATE_DATA& data);
|
const XCONTENT_AGGREGATE_DATA& data);
|
||||||
X_RESULT OpenContent(const std::string_view root_name,
|
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) {
|
if (create) {
|
||||||
result = content_manager->CreateContent(root_name, content_data);
|
result = content_manager->CreateContent(root_name, content_data);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
content_manager->WriteContentHeaderFile(&content_data);
|
||||||
|
}
|
||||||
} else if (open) {
|
} else if (open) {
|
||||||
result = content_manager->OpenContent(root_name, content_data);
|
result = content_manager->OpenContent(root_name, content_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue