[Emulator] Install Content: Create header for installed packages
This fixes support for certain DLCs
This commit is contained in:
parent
469d062a50
commit
010b59e81c
|
@ -370,6 +370,10 @@ X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) {
|
||||||
content_root() / fmt::format("{:08X}", device->title_id()) /
|
content_root() / fmt::format("{:08X}", device->title_id()) /
|
||||||
fmt::format("{:08X}", device->content_type()) / path.filename();
|
fmt::format("{:08X}", device->content_type()) / path.filename();
|
||||||
|
|
||||||
|
std::filesystem::path header_path =
|
||||||
|
content_root() / fmt::format("{:08X}", device->title_id()) / "Headers" /
|
||||||
|
fmt::format("{:08X}", device->content_type()) / path.filename();
|
||||||
|
|
||||||
if (std::filesystem::exists(installation_path)) {
|
if (std::filesystem::exists(installation_path)) {
|
||||||
// TODO(Gliniak): Popup
|
// TODO(Gliniak): Popup
|
||||||
// Do you want to overwrite already existing data?
|
// Do you want to overwrite already existing data?
|
||||||
|
@ -380,7 +384,11 @@ X_STATUS Emulator::InstallContentPackage(const std::filesystem::path& path) {
|
||||||
return error_code.value();
|
return error_code.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vfs::VirtualFileSystem::ExtractFiles(device.get(), installation_path);
|
|
||||||
|
vfs::VirtualFileSystem::ExtractContentHeader(device.get(), header_path);
|
||||||
|
|
||||||
|
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(),
|
||||||
|
installation_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::Pause() {
|
void Emulator::Pause() {
|
||||||
|
|
|
@ -144,7 +144,7 @@ bool ContentManager::ContentExists(const XCONTENT_AGGREGATE_DATA& data) {
|
||||||
|
|
||||||
X_RESULT ContentManager::WriteContentHeaderFile(
|
X_RESULT ContentManager::WriteContentHeaderFile(
|
||||||
const XCONTENT_AGGREGATE_DATA* data) {
|
const XCONTENT_AGGREGATE_DATA* data) {
|
||||||
auto title_id = fmt::format("{:8X}", kernel_state_->title_id());
|
auto title_id = fmt::format("{:08X}", kernel_state_->title_id());
|
||||||
auto content_type =
|
auto content_type =
|
||||||
fmt::format("{:08X}", load_and_swap<uint32_t>(&data->content_type));
|
fmt::format("{:08X}", load_and_swap<uint32_t>(&data->content_type));
|
||||||
auto header_path =
|
auto header_path =
|
||||||
|
|
|
@ -856,5 +856,31 @@ bool StfsContainerDevice::ResolveFromFolder(const std::filesystem::path& path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kernel::xam::XCONTENT_AGGREGATE_DATA StfsContainerDevice::content_header() const {
|
||||||
|
kernel::xam::XCONTENT_AGGREGATE_DATA data;
|
||||||
|
|
||||||
|
std::memset(&data, 0, sizeof(kernel::xam::XCONTENT_AGGREGATE_DATA));
|
||||||
|
|
||||||
|
data.device_id = 1;
|
||||||
|
data.title_id = header_.metadata.execution_info.title_id;
|
||||||
|
data.content_type = header_.metadata.content_type;
|
||||||
|
|
||||||
|
auto name = header_.metadata.display_name(XLanguage::kEnglish);
|
||||||
|
if (name.empty()) {
|
||||||
|
// Find first filled language and use it. It might be incorrect, but meh
|
||||||
|
// until stfs support is done.
|
||||||
|
for (uint8_t i = 0; i < header_.metadata.kNumLanguagesV2; i++) {
|
||||||
|
name = header_.metadata.display_name((XLanguage)i);
|
||||||
|
if (!name.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.set_display_name(name);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/base/string_util.h"
|
#include "xenia/base/string_util.h"
|
||||||
#include "xenia/kernel/util/xex2_info.h"
|
#include "xenia/kernel/util/xex2_info.h"
|
||||||
|
#include "xenia/kernel/xam/content_manager.h"
|
||||||
#include "xenia/vfs/device.h"
|
#include "xenia/vfs/device.h"
|
||||||
#include "xenia/vfs/devices/stfs_xbox.h"
|
#include "xenia/vfs/devices/stfs_xbox.h"
|
||||||
|
|
||||||
|
@ -86,6 +87,8 @@ class StfsContainerDevice : public Device {
|
||||||
uint32_t title_id() const { return header_.metadata.execution_info.title_id; }
|
uint32_t title_id() const { return header_.metadata.execution_info.title_id; }
|
||||||
XContentType content_type() const { return header_.metadata.content_type; }
|
XContentType content_type() const { return header_.metadata.content_type; }
|
||||||
|
|
||||||
|
kernel::xam::XCONTENT_AGGREGATE_DATA content_header() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint32_t kBlocksPerHashLevel[3] = {170, 28900, 4913000};
|
const uint32_t kBlocksPerHashLevel[3] = {170, 28900, 4913000};
|
||||||
const uint32_t kEndOfChain = 0xFFFFFF;
|
const uint32_t kEndOfChain = 0xFFFFFF;
|
||||||
|
|
|
@ -45,7 +45,7 @@ int vfs_dump_main(const std::vector<std::string>& args) {
|
||||||
XELOGE("Failed to initialize device");
|
XELOGE("Failed to initialize device");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return VirtualFileSystem::ExtractFiles(device.get(), base_path);
|
return VirtualFileSystem::ExtractContentFiles(device.get(), base_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xenia/vfs/virtual_file_system.h"
|
#include "xenia/vfs/virtual_file_system.h"
|
||||||
|
#include "xenia/kernel/xam/content_manager.h"
|
||||||
|
#include "xenia/vfs/devices/stfs_container_device.h"
|
||||||
|
|
||||||
#include "xenia/base/literals.h"
|
#include "xenia/base/literals.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
@ -310,8 +312,8 @@ X_STATUS VirtualFileSystem::OpenFile(Entry* root_entry,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS VirtualFileSystem::ExtractFiles(Device* device,
|
X_STATUS VirtualFileSystem::ExtractContentFiles(
|
||||||
std::filesystem::path base_path) {
|
Device* device, std::filesystem::path base_path) {
|
||||||
// Run through all the files, breadth-first style.
|
// Run through all the files, breadth-first style.
|
||||||
std::queue<vfs::Entry*> queue;
|
std::queue<vfs::Entry*> queue;
|
||||||
auto root = device->ResolvePath("/");
|
auto root = device->ResolvePath("/");
|
||||||
|
@ -382,5 +384,28 @@ X_STATUS VirtualFileSystem::ExtractFiles(Device* device,
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualFileSystem::ExtractContentHeader(Device* device,
|
||||||
|
std::filesystem::path base_path) {
|
||||||
|
auto stfs_device = ((StfsContainerDevice*)device);
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(base_path.parent_path())) {
|
||||||
|
if (!std::filesystem::create_directories(base_path.parent_path())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto header_filename = base_path.filename().string() + ".header";
|
||||||
|
auto header_path = base_path.parent_path() / header_filename;
|
||||||
|
xe::filesystem::CreateEmptyFile(header_path);
|
||||||
|
|
||||||
|
if (std::filesystem::exists(header_path)) {
|
||||||
|
auto file = xe::filesystem::OpenFile(header_path, "wb");
|
||||||
|
kernel::xam::XCONTENT_AGGREGATE_DATA data = stfs_device->content_header();
|
||||||
|
data.set_file_name(base_path.filename().string());
|
||||||
|
fwrite(&data, 1, sizeof(kernel::xam::XCONTENT_AGGREGATE_DATA), file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -47,7 +47,11 @@ class VirtualFileSystem {
|
||||||
bool is_non_directory, File** out_file,
|
bool is_non_directory, File** out_file,
|
||||||
FileAction* out_action);
|
FileAction* out_action);
|
||||||
|
|
||||||
static X_STATUS ExtractFiles(Device* device, std::filesystem::path base_path);
|
static X_STATUS ExtractContentFiles(Device* device,
|
||||||
|
std::filesystem::path base_path);
|
||||||
|
static void ExtractContentHeader(Device* device,
|
||||||
|
std::filesystem::path base_path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xe::global_critical_region global_critical_region_;
|
xe::global_critical_region global_critical_region_;
|
||||||
std::vector<std::unique_ptr<Device>> devices_;
|
std::vector<std::unique_ptr<Device>> devices_;
|
||||||
|
|
Loading…
Reference in New Issue