diff --git a/src/xenia/kernel/xam/content_manager.cc b/src/xenia/kernel/xam/content_manager.cc index 304d241ac..1c32bd66f 100644 --- a/src/xenia/kernel/xam/content_manager.cc +++ b/src/xenia/kernel/xam/content_manager.cc @@ -53,6 +53,26 @@ ContentPackage::~ContentPackage() { fs->UnregisterDevice(device_path_); } +void ContentPackage::LoadPackageLicenseMask( + const std::filesystem::path header_path) { + license_ = 0; + + if (!std::filesystem::exists(header_path)) { + return; + } + + auto file = xe::filesystem::OpenFile(header_path, "rb"); + auto file_size = std::filesystem::file_size(header_path); + if (file_size < sizeof(XCONTENT_AGGREGATE_DATA) + sizeof(license_)) { + fclose(file); + return; + } + + fseek(file, sizeof(XCONTENT_AGGREGATE_DATA), SEEK_SET); + size_t result = fread(&license_, 1, sizeof(license_), file); + fclose(file); +} + ContentManager::ContentManager(KernelState* kernel_state, const std::filesystem::path& root_path) : kernel_state_(kernel_state), root_path_(root_path) {} @@ -267,16 +287,17 @@ X_RESULT ContentManager::ReadContentHeaderFile( 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)) { + if (file_size < header_size) { fclose(file); return X_STATUS_END_OF_FILE; } - size_t result = fread(buffer.data(), 1, file_size, file); - if (result != file_size) { + size_t result = fread(buffer.data(), 1, header_size, file); + if (result != header_size) { fclose(file); return X_STATUS_END_OF_FILE; } + fclose(file); std::memcpy(&data, buffer.data(), buffer.size()); // It only reads basic info, however importing savefiles @@ -321,6 +342,7 @@ X_RESULT ContentManager::CreateContent(const std::string_view root_name, X_RESULT ContentManager::OpenContent(const std::string_view root_name, const uint64_t xuid, const XCONTENT_AGGREGATE_DATA& data, + uint32_t& content_license, const uint32_t disc_number) { auto global_lock = global_critical_region_.Acquire(); @@ -339,6 +361,11 @@ X_RESULT ContentManager::OpenContent(const std::string_view root_name, auto package = ResolvePackage(root_name, xuid, data, disc_number); assert_not_null(package); + package->LoadPackageLicenseMask(ResolvePackageHeaderPath( + data.file_name(), xuid, kernel_state_->title_id(), data.content_type)); + + content_license = package->GetPackageLicense(); + open_packages_.insert({string_key::create(root_name), package.release()}); return X_ERROR_SUCCESS; diff --git a/src/xenia/kernel/xam/content_manager.h b/src/xenia/kernel/xam/content_manager.h index f7d104eda..49cb8bd93 100644 --- a/src/xenia/kernel/xam/content_manager.h +++ b/src/xenia/kernel/xam/content_manager.h @@ -125,15 +125,21 @@ class ContentPackage { const std::filesystem::path& package_path); ~ContentPackage(); + void LoadPackageLicenseMask(const std::filesystem::path header_path); + const XCONTENT_AGGREGATE_DATA& GetPackageContentData() const { return content_data_; } + const uint32_t GetPackageLicense() const { return license_; } + private: KernelState* kernel_state_; std::string root_name_; std::string device_path_; XCONTENT_AGGREGATE_DATA content_data_; + uint32_t license_; + ; }; class ContentManager { @@ -161,6 +167,7 @@ class ContentManager { const XCONTENT_AGGREGATE_DATA& data); X_RESULT OpenContent(const std::string_view root_name, const uint64_t xuid, const XCONTENT_AGGREGATE_DATA& data, + uint32_t& content_license, const uint32_t disc_number = -1); X_RESULT CloseContent(const std::string_view root_name); X_RESULT GetContentThumbnail(const uint64_t xuid, diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 76b5c8536..d92a178cd 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -251,23 +251,19 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name, break; } + uint32_t content_license = 0; if (disposition == kDispositionState::Create) { result = content_manager->CreateContent(root_name, xuid, content_data); if (XSUCCEEDED(result)) { content_manager->WriteContentHeaderFile(xuid, &content_data); } } else if (disposition == kDispositionState::Open) { - result = content_manager->OpenContent(root_name, xuid, content_data); + result = content_manager->OpenContent(root_name, xuid, content_data, + content_license); } if (license_mask_ptr && XSUCCEEDED(result)) { - *license_mask_ptr = 0; // Stub! - - // Set license only for DLCs and XBLA titles - if (content_data.content_type == xe::XContentType::kMarketplaceContent || - content_data.content_type == xe::XContentType::kArcadeTitle) { - *license_mask_ptr = static_cast<uint32_t>(cvars::license_mask); - } + *license_mask_ptr = content_license; } extended_error = X_HRESULT_FROM_WIN32(result); diff --git a/src/xenia/vfs/devices/xcontent_container_device.h b/src/xenia/vfs/devices/xcontent_container_device.h index 928364693..26c074fe9 100644 --- a/src/xenia/vfs/devices/xcontent_container_device.h +++ b/src/xenia/vfs/devices/xcontent_container_device.h @@ -64,6 +64,9 @@ class XContentContainerDevice : public Device { } kernel::xam::XCONTENT_AGGREGATE_DATA content_header() const; + uint32_t license_mask() const { + return header_->content_header.licenses[0].license_bits; + } protected: XContentContainerDevice(const std::string_view mount_path, diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index 077dc1e61..c1f9cfc58 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -437,8 +437,11 @@ void VirtualFileSystem::ExtractContentHeader(Device* device, auto file = xe::filesystem::OpenFile(header_path, "wb"); kernel::xam::XCONTENT_AGGREGATE_DATA data = xcontent_device->content_header(); + uint32_t license_mask = xcontent_device->license_mask(); + data.set_file_name(base_path.filename().string()); fwrite(&data, 1, sizeof(kernel::xam::XCONTENT_AGGREGATE_DATA), file); + fwrite(&license_mask, 1, sizeof(license_mask), file); fclose(file); } return;